Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Anway shmget syscall #310

Merged
merged 14 commits into from
Jul 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 55 additions & 7 deletions src/safeposix/syscalls/fs_calls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4979,27 +4979,69 @@ impl Cage {
None
}

//------------------SHMGET SYSCALL------------------

pub fn shmget_syscall(&self, key: i32, size: usize, shmflg: i32) -> i32 {
/// ### Description
///
/// `shmget_syscall` returns the shared memory segment identifier associated with a particular `key`
/// If a key doesn't exist, shmget creates a new memory segment and attaches it to the key.
/// Traditionally if the value of the key equals `IPC_PRIVATE`, we also create a new memory segment which
/// is not associated with a key during this syscall,
/// but for our implementaion, we return an error and only create a new memory
/// segment when the IPC_CREAT flag is specified in the`shmflag` argument.
///
/// ### Returns
///
/// An 32 bit integer which represens the identifier of the memory segment associated with the key
///
/// ### Arguments
///
/// `key` : An i32 value that references a memory segment
/// `size` : Size of the memory segment to be created if key doesn't exist
/// `shmflag` : mode flags which indicate whether to create a new key or not
/// The `shmflag` is composed of the following
/// * IPC_CREAT - specify that the system call creates a new segment
/// * IPC_EXCL - this flag is used with IPC_CREAT to cause this function to fail when IPC_CREAT is also used
/// and the key passed has a memory segment associated with it.
///
/// ### Errors
///
/// * ENOENT : the key equals the `IPC_PRIVATE` constant
/// * EEXIST : key exists and yet either `IPC_CREAT` or `IPC_EXCL` are passed as flags
/// * ENOENT : key did not exist and the `IPC_CREAT` flag was not passed
/// * EINVAL : the size passed was less than the minimum size of segment or greater than the maximum possible size
///
/// ### Panics
///
/// There are no cases where the function directly panics
///
pub fn shmget_syscall(&self, key: i32, size: usize, shmflg: i32) -> i32 {
//Check if the key passed equals the IPC_PRIVATE flag
if key == IPC_PRIVATE {
// Return error since this is not suppported currently
return syscall_error(Errno::ENOENT, "shmget", "IPC_PRIVATE not implemented");
}
// Variable to store shmid
let shmid: i32;
// data of the shm table
let metadata = &SHM_METADATA;

// Check if there exists a memory segment associated with the key passed as argument
match metadata.shmkeyidtable.entry(key) {
// If there exists a memory segment at that key
interface::RustHashEntry::Occupied(occupied) => {
// Produce an error if invalid flags are used with a valid key
if (IPC_CREAT | IPC_EXCL) == (shmflg & (IPC_CREAT | IPC_EXCL)) {
return syscall_error(
Errno::EEXIST,
"shmget",
"key already exists and IPC_CREAT and IPC_EXCL were used",
);
}
// Get the id of the occupied memory segment
shmid = *occupied.get();
}
// If the memory segment doesn't exist
interface::RustHashEntry::Vacant(vacant) => {
// Return an error if IPC_CREAT was not specified
if 0 == (shmflg & IPC_CREAT) {
return syscall_error(
Errno::ENOENT,
Expand All @@ -5008,6 +5050,8 @@ impl Cage {
);
}

// If memory segment doesn't exist and IPC_CREAT was specified - we create a new memory segment
// Check if the size passed is a valid value
if (size as u32) < SHMMIN || (size as u32) > SHMMAX {
return syscall_error(
Errno::EINVAL,
Expand All @@ -5016,11 +5060,13 @@ impl Cage {
);
}

// Generate a new id for the new memory segment
shmid = metadata.new_keyid();
// Insert new id in the hash table entry pointed by the key
vacant.insert(shmid);
let mode = (shmflg & 0x1FF) as u16; // mode is 9 least signficant bits of shmflag, even if we dont really do
// anything with them

// Mode of the new segment is the 9 least significant bits of the shmflag
let mode = (shmflg & 0x1FF) as u16;
// Create a new segment with the key, size, cageid of the calling process
let segment = new_shm_segment(
key,
size,
Expand All @@ -5029,10 +5075,12 @@ impl Cage {
DEFAULT_GID,
mode,
);
// Insert the newly created segment in the SHM table with its key
metadata.shmtable.insert(shmid, segment);
}
};
shmid // return the shmid
// Return the shmid
shmid
}

//------------------SHMAT SYSCALL------------------
Expand Down
30 changes: 30 additions & 0 deletions src/tests/fs_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4034,6 +4034,36 @@ pub mod fs_tests {

assert_eq!(cage.close_syscall(fd), 0);
assert_eq!(cage.exit_syscall(EXIT_SUCCESS), EXIT_SUCCESS);

lindrustfinalize();
}

pub fn ut_lind_fs_shmget_syscall(){
// acquire locks and start env cleanup
let _thelock = setup::lock_and_init();
let cage = interface::cagetable_getref(1);

let key = 33123;
// Get shmid of a memory segment / create a new one if it doesn't exist
let shmid = cage.shmget_syscall(33123, 1024, IPC_CREAT);
assert_eq!(shmid,4);

// Check error upon asking for a valid key and passing the IPC_CREAT and IPC_EXCL flag
assert_eq!(cage.shmget_syscall(key, 1024, IPC_CREAT | IPC_EXCL),-(Errno::EEXIST as i32 ));

// Check error when passing IPC_CREAT flag as the key
assert_eq!(cage.shmget_syscall(IPC_PRIVATE,1024,IPC_PRIVATE),-(Errno::ENOENT as i32));

// Check if the function returns a correct shmid upon asking with a key that we know exists
assert_eq!(cage.shmget_syscall(key, 1024,0666),shmid);

// Check if the function returns the correct error when we don't pass IPC_CREAT for a key that doesn't exist
assert_eq!(cage.shmget_syscall(123456, 1024, 0),-(Errno::ENOENT as i32));

// Check if the size error is returned correctly
assert_eq!(cage.shmget_syscall(123456, (SHMMAX + 10 )as usize, IPC_CREAT),-(Errno::EINVAL as i32));
assert_eq!(cage.shmget_syscall(123456, 0 as usize, IPC_CREAT),-(Errno::EINVAL as i32));

lindrustfinalize();
}
}