@@ -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