Fix false alarm on non-page-aligned size for mprotect

This commit is contained in:
Hui, Chunyang 2021-02-23 12:33:34 +00:00 committed by Zongmin.Gu
parent 58bddcb89d
commit c4c3315c06
2 changed files with 37 additions and 0 deletions

@ -373,6 +373,12 @@ impl ProcessVM {
} }
pub fn mprotect(&self, addr: usize, size: usize, perms: VMPerms) -> Result<()> { pub fn mprotect(&self, addr: usize, size: usize, perms: VMPerms) -> Result<()> {
let size = {
if size == 0 {
return Ok(());
}
align_up(size, PAGE_SIZE)
};
let protect_range = VMRange::new_with_size(addr, size)?; let protect_range = VMRange::new_with_size(addr, size)?;
if !self.process_range.range().is_superset_of(&protect_range) { if !self.process_range.range().is_superset_of(&protect_range) {
return_errno!(ENOMEM, "invalid range"); return_errno!(ENOMEM, "invalid range");

@ -9,6 +9,7 @@
#include <assert.h> #include <assert.h>
#include <string.h> #include <string.h>
#include <fcntl.h> #include <fcntl.h>
#include <sys/syscall.h>
#include "test.h" #include "test.h"
// ============================================================================ // ============================================================================
@ -1061,6 +1062,35 @@ int test_mprotect_with_invalid_prot() {
return 0; return 0;
} }
int test_mprotect_with_non_page_aligned_size() {
int flags = MAP_PRIVATE | MAP_ANONYMOUS;
void *buf = mmap(NULL, PAGE_SIZE * 2, PROT_NONE, flags, -1, 0);
if (buf == MAP_FAILED) {
THROW_ERROR("mmap failed");
}
// Use raw syscall interface becase libc wrapper will handle non-page-aligned address
// and will not cause failure.
// Raw mprotect syscall with non-page-aligned address should fail.
int ret = syscall(SYS_mprotect, buf + 10, PAGE_SIZE, PROT_WRITE);
if (ret == 0 || errno != EINVAL) {
THROW_ERROR("mprotect with non-page-aligned address should fail with EINVAL");
}
// According to man page of mprotect, this syscall require a page aligned start address, but the size could be any value.
// Raw mprotect syscall with non-page-aligned size should succeed.
ret = syscall(SYS_mprotect, buf, PAGE_SIZE + 100, PROT_WRITE);
if (ret < 0) {
THROW_ERROR("mprotect with non-page-aligned size failed");
}
// Mprotect succeeded and the pages are writable.
*(char *)buf = 1;
*(char *)(buf + PAGE_SIZE) = 1;
return 0;
}
// ============================================================================ // ============================================================================
// Test suite main // Test suite main
// ============================================================================ // ============================================================================
@ -1100,6 +1130,7 @@ static test_case_t test_cases[] = {
TEST_CASE(test_mprotect_with_zero_len), TEST_CASE(test_mprotect_with_zero_len),
TEST_CASE(test_mprotect_with_invalid_addr), TEST_CASE(test_mprotect_with_invalid_addr),
TEST_CASE(test_mprotect_with_invalid_prot), TEST_CASE(test_mprotect_with_invalid_prot),
TEST_CASE(test_mprotect_with_non_page_aligned_size),
}; };
int main() { int main() {