* Copyright 2023, Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#include <OS.h>
int gTestFd = -1;
int
map_cut_compare_test()
{
const size_t size = 16 * B_PAGE_SIZE;
uint8* ptr1 = (uint8*)mmap(NULL, size, PROT_READ, MAP_PRIVATE, gTestFd, 0);
uint8 chunk[128];
memcpy(chunk, &ptr1[3 * B_PAGE_SIZE], sizeof(chunk));
uint8* ptr2 = (uint8*)mmap(&ptr1[B_PAGE_SIZE], B_PAGE_SIZE,
PROT_READ | PROT_WRITE, MAP_FIXED | MAP_PRIVATE | MAP_ANON, -1, 0);
int status = memcmp(&ptr1[3 * B_PAGE_SIZE], chunk, sizeof(chunk));
if (status != 0) {
printf("map-cut-compare test failed!\n");
return status;
}
return munmap(ptr1, size);
}
int
map_protect_cut_test1()
{
const size_t size = B_PAGE_SIZE * 4;
uint8* ptr = (uint8*)mmap(NULL, B_PAGE_SIZE * 4, PROT_NONE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
mprotect(ptr + B_PAGE_SIZE * 3, B_PAGE_SIZE, PROT_READ | PROT_WRITE);
ptr[B_PAGE_SIZE * 3] = 'a';
if (mmap(ptr + B_PAGE_SIZE, B_PAGE_SIZE, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0) == NULL)
return -1;
if (ptr[B_PAGE_SIZE * 3] != 'a') {
printf("map-protect-cut test failed!\n");
return -1;
}
return munmap(ptr, size);
}
int
map_protect_cut_test2()
{
const size_t size = B_PAGE_SIZE * 4;
uint8* ptr = (uint8*)mmap(NULL, size, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
ptr[B_PAGE_SIZE * 3] = 'a';
if (mprotect(ptr + B_PAGE_SIZE * 3, B_PAGE_SIZE, PROT_NONE) != 0)
return -1;
if (mmap(ptr + B_PAGE_SIZE, B_PAGE_SIZE, PROT_NONE,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0) == NULL)
return -1;
if (mprotect(ptr + B_PAGE_SIZE * 3, B_PAGE_SIZE, PROT_READ | PROT_WRITE) != 0)
return -1;
if (ptr[B_PAGE_SIZE * 3] != 'a') {
printf("map-protect-cut test failed!\n");
return -1;
}
ptr[B_PAGE_SIZE * 3] = 'b';
if (mprotect(ptr + B_PAGE_SIZE * 3, B_PAGE_SIZE, PROT_NONE) != 0)
return -1;
set_area_protection(area_for(ptr + B_PAGE_SIZE * 3), B_READ_AREA | B_WRITE_AREA);
if (ptr[B_PAGE_SIZE * 3] != 'b') {
printf("map-protect-cut test failed!\n");
return -1;
}
return munmap(ptr, size);
}
int
map_cut_protect_test()
{
const size_t size = B_PAGE_SIZE * 4;
uint8* ptr = (uint8*)mmap(NULL, size, PROT_NONE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (mmap(ptr + B_PAGE_SIZE, B_PAGE_SIZE, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0) == NULL)
return -1;
mprotect(ptr + B_PAGE_SIZE * 3, B_PAGE_SIZE, PROT_READ | PROT_WRITE);
ptr[B_PAGE_SIZE * 3] = 'a';
return munmap(ptr, size);
}
int
map_cut_fork_test()
{
char name[24];
sprintf(name, "/shm-mmap-cut-fork-test-%d", getpid());
name[sizeof(name) - 1] = '\0';
shm_unlink(name);
int fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW, 0600);
shm_unlink(name);
if (fd < 0) {
printf("failed to create temporary file!\n");
return fd;
}
ftruncate(fd, B_PAGE_SIZE * 4);
uint8* ptr = (uint8*)mmap(NULL, B_PAGE_SIZE * 4, PROT_NONE, MAP_PRIVATE,
fd, 0);
close(fd);
mprotect(ptr, B_PAGE_SIZE, PROT_READ | PROT_WRITE);
ptr[0] = 'a';
mmap(ptr + B_PAGE_SIZE, B_PAGE_SIZE, PROT_NONE,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
int pid = fork();
if (pid == 0) {
exit(0);
} else if (pid < 0) {
printf("failed to fork the test process!\n");
return pid;
}
int status;
waitpid(pid, &status, 0);
if (ptr[0] != 'a') {
printf("map-cut-fork test failed!\n");
return -1;
}
return 0;
}
int
main()
{
gTestFd = open("/boot/system/lib/libroot.so", O_CLOEXEC | O_RDONLY);
if (gTestFd < 0)
return -1;
int status;
if ((status = map_cut_compare_test()) != 0)
return status;
if ((status = map_protect_cut_test1()) != 0)
return status;
if ((status = map_protect_cut_test2()) != 0)
return status;
if ((status = map_cut_protect_test()) != 0)
return status;
if ((status = map_cut_fork_test()) != 0)
return status;
return 0;
}