Skip to content

Commit c2d5464

Browse files
ve1nardlind
andcommitted
mmap_syscall() and munmap_syscall() updates (#300)
* finished mmap and munmap * removed whitespace * formatted * fixed the conditional * fixed the test * fixed according to the review * fixed the typo --------- Co-authored-by: lind <lind@nyu.edu>
1 parent ea2f68a commit c2d5464

File tree

2 files changed

+466
-28
lines changed

2 files changed

+466
-28
lines changed

src/safeposix/syscalls/fs_calls.rs

Lines changed: 158 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -3504,7 +3504,70 @@ impl Cage {
35043504
}
35053505
}
35063506

3507-
//------------------------------------MMAP SYSCALL------------------------------------
3507+
/// ### Description
3508+
///
3509+
/// The `mmap_syscall()` function creates a new mapping in the
3510+
/// virtual address space of the calling process.
3511+
///
3512+
/// ### Arguments
3513+
///
3514+
/// The `mmap_syscall()` accepts six arguments:
3515+
/// * `addr` - the starting address for the new mapping. If `addr`
3516+
/// is NULL, then the kernel chooses the (page-aligned) address at
3517+
/// which to create the mapping. If addr is not NULL, then the
3518+
/// kernel takes it as a hint about where to place the mapping.
3519+
/// * `len` - specifies the length of the mapping (which must be
3520+
/// greater than 0).
3521+
/// * `prot` - describes the desired memory protection of the
3522+
/// mapping, which must not conflict with the open mode of the file.
3523+
/// It is either `PROT_NONE` or the bitwise OR of one or more of the
3524+
/// following flags: `PROT_EXEC` (Pages may be executed), `PROT_READ`
3525+
/// (Pages may be read), `PROT_WRITE` (Pages may be written), `PROT_NONE`
3526+
/// (Pages may not be accessed).
3527+
/// * `flags` - determines whether updates to the mapping are visible
3528+
/// to other processes mapping the same region, and whether updates are
3529+
/// carried through to the underlying file. This behavior is determined
3530+
/// by including exactly one of the following values in flags: `MAP_SHARED`
3531+
/// (Share this mapping. Updates to the mapping are visible to other
3532+
/// processes mapping the same region, and in the case of file-backed
3533+
/// mappings are carried through to the underlying file) or `MAP_PRIVATE`
3534+
/// (Create a private copy-on-write mapping. Updates to the mapping are
3535+
/// not visible to other processes mapping the same file, and are not
3536+
/// carried through to the underlying file). `MAP_SHARED_VALIDATE` and
3537+
/// other flags are not validated in the current implementation but
3538+
/// are supported by the underlying `libc_mmap()` syscall.
3539+
/// * `filedes` - a file descriptor specifying the file that shall be
3540+
/// mapped.
3541+
/// * `off` - designates the offset in the file from which the mapping
3542+
/// should start.
3543+
///
3544+
/// ### Returns
3545+
///
3546+
/// On success, `mmap_syscall()` returns a pointer to the mapped area.
3547+
/// In case of a failure, an error is returned, and `errno` is set depending
3548+
/// on the error, e.g. EINVAL, ERANGE, etc.
3549+
///
3550+
/// ### Errors
3551+
///
3552+
/// * `EINVAL` - the value of len is 0 or `flags` contained neither
3553+
/// `MAP_PRIVATE` nor `MAP_SHARED` or `flags` contained both
3554+
/// `MAP_PRIVATE` and `MAP_SHARED`.
3555+
/// * `EACCES` - `fildes` is not open for reading or `MAP_SHARED`
3556+
/// was requested and PROT_WRITE is set, but fd is not open in
3557+
/// read/write (`O_RDWR`) mode or `fildes` refers to a non-regular file.
3558+
/// * `ENXIO` - addresses in the range [`off`, `off`+`len`) are invalid
3559+
/// for the object specified by `fildes`.
3560+
/// * `EOPNOTSUPP` - Lind currently does not support mapping character
3561+
/// files.
3562+
/// * `EBADF` - invalid file descriptor.
3563+
/// Other errors, like `ENOMEM`, `EOVERFLOW`, etc. are not supported.
3564+
///
3565+
/// ### Panics
3566+
///
3567+
/// A panic occurs when a provided file descriptor is out of bounds.
3568+
///
3569+
/// To learn more about the syscall, flags, possible error values, etc., see
3570+
/// [mmap(2)](https://man7.org/linux/man-pages/man2/mmap.2.html)
35083571
35093572
pub fn mmap_syscall(
35103573
&self,
@@ -3516,57 +3579,78 @@ impl Cage {
35163579
off: i64,
35173580
) -> i32 {
35183581
if len == 0 {
3519-
syscall_error(Errno::EINVAL, "mmap", "the value of len is 0");
3582+
return syscall_error(Errno::EINVAL, "mmap", "the value of len is 0");
35203583
}
3521-
3522-
if 0 == flags & (MAP_PRIVATE | MAP_SHARED) {
3523-
syscall_error(
3584+
//Exactly one of the two flags (either `MAP_PRIVATE` or `MAP_SHARED`) must be
3585+
// set
3586+
if 0 == (flags & (MAP_PRIVATE | MAP_SHARED)) {
3587+
return syscall_error(
35243588
Errno::EINVAL,
35253589
"mmap",
35263590
"The value of flags is invalid (neither MAP_PRIVATE nor MAP_SHARED is set)",
35273591
);
35283592
}
3529-
3530-
if 0 != flags & MAP_ANONYMOUS {
3593+
if ((flags & MAP_PRIVATE) != 0) && ((flags & MAP_SHARED) != 0) {
3594+
return syscall_error(
3595+
Errno::EINVAL,
3596+
"mmap",
3597+
"The value of flags is invalid (MAP_PRIVATE and MAP_SHARED cannot be both set)",
3598+
);
3599+
}
3600+
//The `MAP_ANONYMOUS` flag specifies that the mapping
3601+
//is not backed by any file, so the `fildes` and `off`
3602+
//arguments should be ignored; however, some implementations
3603+
//require `fildes` to be -1, which we follow for the
3604+
//sake of portability.
3605+
if 0 != (flags & MAP_ANONYMOUS) {
35313606
return interface::libc_mmap(addr, len, prot, flags, -1, 0);
35323607
}
3533-
3608+
//BUG
3609+
//If the provided file descriptor is out of bounds, get_filedescriptor returns
3610+
//Err(), unwrapping on which produces a 'panic!'
3611+
//otherwise, file descriptor table entry is stored in 'checkedfd'
35343612
let checkedfd = self.get_filedescriptor(fildes).unwrap();
35353613
let mut unlocked_fd = checkedfd.write();
35363614
if let Some(filedesc_enum) = &mut *unlocked_fd {
3537-
//confirm fd type is mappable
3615+
//The current implementation supports only regular files
35383616
match filedesc_enum {
35393617
File(ref mut normalfile_filedesc_obj) => {
35403618
let inodeobj = FS_METADATA
35413619
.inodetable
35423620
.get(&normalfile_filedesc_obj.inode)
35433621
.unwrap();
3544-
3545-
//confirm inode type is mappable
3622+
//Confirm inode type is mappable
35463623
match &*inodeobj {
3624+
Inode::CharDev(_chardev_inode_obj) => {
3625+
syscall_error(Errno::EOPNOTSUPP, "mmap", "lind currently does not support mapping character files")
3626+
}
35473627
Inode::File(normalfile_inode_obj) => {
3548-
//if we want to write our changes back to the file the file needs to be open for reading and writing
3549-
if (flags & MAP_SHARED != 0) && (flags & PROT_WRITE != 0) && (normalfile_filedesc_obj.flags & O_RDWR != 0) {
3628+
//For any kind of memory mapping, the file should be
3629+
//opened for reading, so if it was opened for write
3630+
//only, the mapping should be denied
3631+
if (normalfile_filedesc_obj.flags & O_WRONLY) != 0 {
3632+
return syscall_error(Errno::EACCES, "mmap", "file descriptor is not open for reading");
3633+
}
3634+
//If we want to write our changes back to the file the file needs to be open for reading and writing
3635+
if (flags & MAP_SHARED) != 0 && (prot & PROT_WRITE) != 0 && (normalfile_filedesc_obj.flags & O_RDWR) != O_RDWR {
35503636
return syscall_error(Errno::EACCES, "mmap", "file descriptor is not open RDWR, but MAP_SHARED and PROT_WRITE are set");
35513637
}
35523638
let filesize = normalfile_inode_obj.size;
3639+
//The offset cannot be negative, and we cannot read past the end of the file
35533640
if off < 0 || off > filesize as i64 {
35543641
return syscall_error(Errno::ENXIO, "mmap", "Addresses in the range [off,off+len) are invalid for the object specified by fildes.");
35553642
}
3556-
//because of NaCl's internal workings we must allow mappings to extend past the end of a file
3643+
//Because of NaCl's internal workings we must allow mappings to extend past the end of the file
35573644
let fobj = FILEOBJECTTABLE.get(&normalfile_filedesc_obj.inode).unwrap();
3558-
//we cannot mmap a rust file in quite the right way so we retrieve the fd number from it
3559-
//this is the system fd number--the number of the lind.<inodenum> file in our host system
3645+
//The actual memory mapping is not emulated inside Lind, so the call to the kernel
3646+
//is required. To perform this call, the file descriptor of the actual file
3647+
//stored on the host machine is needed. Since Lind's emulated filesystem
3648+
//does not match the underlying host's filesystem, the file descriptor
3649+
//provided to the `mmap_syscall()` cannot be used and must be converted
3650+
//to the actual file descriptor stored in the host's filesystem.
35603651
let fobjfdno = fobj.as_fd_handle_raw_int();
3561-
3562-
35633652
interface::libc_mmap(addr, len, prot, flags, fobjfdno, off)
35643653
}
3565-
3566-
Inode::CharDev(_chardev_inode_obj) => {
3567-
syscall_error(Errno::EOPNOTSUPP, "mmap", "lind currently does not support mapping character files")
3568-
}
3569-
35703654
_ => {syscall_error(Errno::EACCES, "mmap", "the fildes argument refers to a file whose type is not supported by mmap")}
35713655
}
35723656
}
@@ -3581,15 +3665,61 @@ impl Cage {
35813665
}
35823666
}
35833667

3584-
//------------------------------------MUNMAP SYSCALL------------------------------------
3668+
/// ### Description
3669+
///
3670+
/// The `munmap_syscall()` function shall remove any mappings
3671+
/// containing any part of the address space of the process
3672+
/// starting at `addr` and continuing for `len` bytes.
3673+
/// Further references to these pages shall result in the
3674+
/// generation of a `SIGSEGV` signal to the process. If there
3675+
/// are no mappings in the specified address range, then
3676+
/// `munmap_syscall()` has no effect.
3677+
/// The current implementation of the syscall solely relies
3678+
/// on the inner implementation of NaCl (except for a simple
3679+
/// `len` argument check) by creating a new mapping in the
3680+
/// specified memory region by using `MAP_FIXED` with
3681+
/// `PROT_NONE` flag to deny any access to the unmapped
3682+
/// memory region.
3683+
///
3684+
/// ### Arguments
3685+
///
3686+
/// The `munmap_syscall()` accepts two arguments:
3687+
/// * `addr` - the address starting from which the mapping
3688+
/// shall be removed
3689+
/// * `len` - specifies the length of the mapping that
3690+
/// shall be removed.
3691+
///
3692+
/// ### Returns
3693+
///
3694+
/// On success, `munmap_syscall()` returns 0.
3695+
/// In case of a failure, an error is returned, and `errno`
3696+
/// is set to `EINVAL`.
3697+
///
3698+
/// ### Errors
3699+
///
3700+
/// * `EINVAL` - the value of len is 0
3701+
/// Other `EINVAL` errors are returned directly from the call to
3702+
/// `libc_mmap`
3703+
///
3704+
/// ### Panics
3705+
///
3706+
/// There are no cases where this function panics.
3707+
///
3708+
/// To learn more about the syscall, flags, possible error values, etc., see
3709+
/// [munmap(2)](https://linux.die.net/man/2/munmap)
35853710
35863711
pub fn munmap_syscall(&self, addr: *mut u8, len: usize) -> i32 {
35873712
if len == 0 {
3588-
syscall_error(Errno::EINVAL, "mmap", "the value of len is 0");
3713+
return syscall_error(Errno::EINVAL, "mmap", "the value of len is 0");
35893714
}
3590-
//NaCl's munmap implementation actually just writes over the previously mapped
3591-
// data with PROT_NONE This frees all of the resources except page table
3592-
// space, and is put inside safeposix for consistency
3715+
//NaCl's munmap implementation actually just writes
3716+
//over the previously mapped data with PROT_NONE.
3717+
//This frees all of the resources except page table
3718+
//space, and is put inside safeposix for consistency.
3719+
//`MAP_FIXED` is used to precisely unmap the specified
3720+
//memory region, and `MAP_ANONYMOUS` is used to deny
3721+
//any further access to the unmapped memory region
3722+
//thereby emulating the unmapping process.
35933723
interface::libc_mmap(
35943724
addr,
35953725
len,

0 commit comments

Comments
 (0)