diff --git a/src/libos/src/vm/shm_manager.rs b/src/libos/src/vm/shm_manager.rs index c461f0f6..5e0bb723 100644 --- a/src/libos/src/vm/shm_manager.rs +++ b/src/libos/src/vm/shm_manager.rs @@ -170,6 +170,11 @@ impl ShmManager { if !vma.is_shared() { return_errno!(EINVAL, "not a shared chunk"); } + if let Some((file_ref, _)) = vma.writeback_file() { + if !file_ref.access_mode().unwrap().writable() && new_perms.can_write() { + return_errno!(EACCES, "file is not writable"); + } + } Self::apply_new_perms_if_higher(&mut vma, new_perms); Ok(()) } diff --git a/src/libos/src/vm/vm_chunk_manager.rs b/src/libos/src/vm/vm_chunk_manager.rs index 355c487f..c8a32024 100644 --- a/src/libos/src/vm/vm_chunk_manager.rs +++ b/src/libos/src/vm/vm_chunk_manager.rs @@ -284,6 +284,12 @@ impl ChunkManager { Some(intersection_vma) => intersection_vma, }; + if let Some((file_ref, _)) = intersection_vma.writeback_file() { + if !file_ref.access_mode().unwrap().writable() && new_perms.can_write() { + return_errno!(EACCES, "file is not writable"); + } + } + if intersection_vma.range() == containing_vma.range() { // The whole containing_vma is mprotected containing_vma.set_perms(new_perms); diff --git a/src/libos/src/vm/vm_manager.rs b/src/libos/src/vm/vm_manager.rs index 418fa493..8342a50e 100644 --- a/src/libos/src/vm/vm_manager.rs +++ b/src/libos/src/vm/vm_manager.rs @@ -89,6 +89,8 @@ impl VMManager { } pub fn mmap(&self, options: &VMMapOptions) -> Result { + mmap_file_check_permissions(options)?; + if LIBOS_CONFIG.feature.enable_posix_shm && options.is_shared() { let res = self.internal().mmap_shared_chunk(options); match res { @@ -911,6 +913,12 @@ impl InternalVMManager { return Ok(()); } + if let Some((file_ref, _)) = containing_vma.writeback_file() { + if !file_ref.access_mode().unwrap().writable() && new_perms.can_write() { + return_errno!(EACCES, "file is not writable"); + } + } + let current_pid = current!().process().pid(); let same_start = protect_range.start() == containing_vma.start(); let same_end = protect_range.end() == containing_vma.end(); @@ -1219,3 +1227,30 @@ impl VMRemapParser for InternalVMManager { self.free_manager.is_free_range(request_range) } } + +// Based on the mmap man page: +// A file descriptor refers to a non-regular file. Or a file +// mapping was requested, but fd is not open for reading. Or +// MAP_SHARED was requested and PROT_WRITE is set, but fd is +// not open in read/write (O_RDWR) mode. Or PROT_WRITE is +// set, but the file is append-only. +fn mmap_file_check_permissions(mmap_options: &VMMapOptions) -> Result<()> { + match mmap_options.initializer() { + VMInitializer::FileBacked { file } => { + let (file_ref, _) = file.backed_file(); + if !file_ref.access_mode().unwrap().readable() { + return_errno!(EACCES, "mmap file is not readable"); + } + + let perms = mmap_options.perms(); + if let Some((file_ref, _)) = file.writeback_file() { + if !file_ref.access_mode().unwrap().writable() && perms.can_write() { + return_errno!(EACCES, "mmap file is not writable"); + } + } + + return Ok(()); + } + _ => return Ok(()), + } +} diff --git a/test/mmap/main.c b/test/mmap/main.c index f51fe697..fce338f6 100644 --- a/test/mmap/main.c +++ b/test/mmap/main.c @@ -1608,6 +1608,38 @@ int test_shared_file_mmap_small_file() { return 0; } +int test_shared_file_mmap_permissions() { + const char *file_path = "/root/mmap_file.data"; + int fd = open(file_path, O_CREAT | O_TRUNC | O_RDONLY, 0644); + if (fd < 0) { + THROW_ERROR("file creation failed"); + } + + char *buf = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (buf != MAP_FAILED || errno != EACCES) { + THROW_ERROR("permission violation not detected"); + } + + close(fd); + fd = open(file_path, O_CREAT | O_TRUNC | O_RDONLY, 0644); + if (fd < 0) { + THROW_ERROR("file creation failed"); + } + + buf = mmap(NULL, PAGE_SIZE, PROT_READ, MAP_SHARED, fd, 0); + if (buf == MAP_FAILED) { + THROW_ERROR("mmap failed"); + } + + int ret = mprotect(buf, PAGE_SIZE, PROT_READ | PROT_WRITE); + if (ret != -1 || errno != EACCES) { + printf("ret = %d, errno = %d\n", ret, errno); + THROW_ERROR("permission violation not detected"); + } + + return 0; +} + // ============================================================================ // Test suite main // ============================================================================ @@ -1628,6 +1660,7 @@ static test_case_t test_cases[] = { TEST_CASE(test_shared_file_mmap_flushing_with_fdatasync), TEST_CASE(test_shared_file_mmap_flushing_with_fsync), TEST_CASE(test_shared_file_mmap_small_file), + TEST_CASE(test_shared_file_mmap_permissions), TEST_CASE(test_fixed_mmap_that_does_not_override_any_mmaping), TEST_CASE(test_fixed_mmap_that_overrides_existing_mmaping), TEST_CASE(test_fixed_mmap_with_non_page_aligned_addr),