xref: /haiku/src/tests/system/kernel/mmap_cut_tests.cpp (revision c0a12a6b7d697382511ff36e7815aad6a379b3a7)
19ed77019SAugustin Cavalier /*
29ed77019SAugustin Cavalier  * Copyright 2023, Haiku, Inc. All rights reserved.
39ed77019SAugustin Cavalier  * Distributed under the terms of the MIT License.
49ed77019SAugustin Cavalier  */
59ed77019SAugustin Cavalier 
69ed77019SAugustin Cavalier #include <stdio.h>
779572316STrung Nguyen #include <stdlib.h>
89ed77019SAugustin Cavalier #include <string.h>
99ed77019SAugustin Cavalier #include <fcntl.h>
109ed77019SAugustin Cavalier #include <sys/mman.h>
1179572316STrung Nguyen #include <unistd.h>
129ed77019SAugustin Cavalier #include <OS.h>
139ed77019SAugustin Cavalier 
149ed77019SAugustin Cavalier 
15bdcc293fSTrung Nguyen int gTestFd = -1;
169ed77019SAugustin Cavalier 
17bdcc293fSTrung Nguyen 
18bdcc293fSTrung Nguyen int
19bdcc293fSTrung Nguyen map_negative_offset_test()
20bdcc293fSTrung Nguyen {
219ed77019SAugustin Cavalier 	// should fail (negative offset)
22bdcc293fSTrung Nguyen 	void* ptr = mmap(NULL, B_PAGE_SIZE, PROT_READ, MAP_PRIVATE, gTestFd, -4096);
23bdcc293fSTrung Nguyen 	if (ptr != MAP_FAILED) {
249ed77019SAugustin Cavalier 		printf("map-negative-offset unexpectedly succeeded!\n");
259ed77019SAugustin Cavalier 		return -1;
269ed77019SAugustin Cavalier 	}
27bdcc293fSTrung Nguyen 	return 0;
28bdcc293fSTrung Nguyen }
299ed77019SAugustin Cavalier 
30bdcc293fSTrung Nguyen 
31bdcc293fSTrung Nguyen int
32bdcc293fSTrung Nguyen map_cut_compare_test()
33bdcc293fSTrung Nguyen {
34bdcc293fSTrung Nguyen 	uint8* ptr1 = (uint8*)mmap(NULL, 16 * B_PAGE_SIZE, PROT_READ, MAP_PRIVATE, gTestFd, 0);
359ed77019SAugustin Cavalier 	uint8 chunk[128];
369ed77019SAugustin Cavalier 	memcpy(chunk, &ptr1[3 * B_PAGE_SIZE], sizeof(chunk));
379ed77019SAugustin Cavalier 
389ed77019SAugustin Cavalier 	// now cut the area
399ed77019SAugustin Cavalier 	uint8* ptr2 = (uint8*)mmap(&ptr1[B_PAGE_SIZE], B_PAGE_SIZE,
409ed77019SAugustin Cavalier 		PROT_READ | PROT_WRITE, MAP_FIXED | MAP_PRIVATE | MAP_ANON, -1, 0);
419ed77019SAugustin Cavalier 
429ed77019SAugustin Cavalier 	// validate that the area after the cut still has the expected data
439ed77019SAugustin Cavalier 	int status = memcmp(&ptr1[3 * B_PAGE_SIZE], chunk, sizeof(chunk));
449ed77019SAugustin Cavalier 	if (status != 0) {
459ed77019SAugustin Cavalier 		printf("map-cut-compare test failed!\n");
469ed77019SAugustin Cavalier 		return status;
479ed77019SAugustin Cavalier 	}
48bdcc293fSTrung Nguyen 	return 0;
49bdcc293fSTrung Nguyen }
50bdcc293fSTrung Nguyen 
51bdcc293fSTrung Nguyen 
52bdcc293fSTrung Nguyen int
53bdcc293fSTrung Nguyen map_protect_cut_test()
54bdcc293fSTrung Nguyen {
55bdcc293fSTrung Nguyen 	uint8* ptr = (uint8*)mmap(NULL, B_PAGE_SIZE * 4, PROT_NONE,
56bdcc293fSTrung Nguyen 		MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
57bdcc293fSTrung Nguyen 
58bdcc293fSTrung Nguyen 	// make the tail accessible
59bdcc293fSTrung Nguyen 	mprotect(ptr + B_PAGE_SIZE * 3, B_PAGE_SIZE, PROT_READ | PROT_WRITE);
60bdcc293fSTrung Nguyen 
61bdcc293fSTrung Nguyen 	// store any value
62bdcc293fSTrung Nguyen 	ptr[B_PAGE_SIZE * 3] = 'a';
63bdcc293fSTrung Nguyen 
64bdcc293fSTrung Nguyen 	// cut the area in the middle, before the accessible tail
65bdcc293fSTrung Nguyen 	mmap(ptr + B_PAGE_SIZE, B_PAGE_SIZE, PROT_READ | PROT_WRITE,
66bdcc293fSTrung Nguyen 		MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
67bdcc293fSTrung Nguyen 
68bdcc293fSTrung Nguyen 	// validate that this does not crash
69bdcc293fSTrung Nguyen 	if (ptr[B_PAGE_SIZE * 3] != 'a') {
70bdcc293fSTrung Nguyen 		printf("map-protect-cut test failed!\n");
71bdcc293fSTrung Nguyen 		return -1;
72bdcc293fSTrung Nguyen 	}
73bdcc293fSTrung Nguyen 	return 0;
74bdcc293fSTrung Nguyen }
75bdcc293fSTrung Nguyen 
76bdcc293fSTrung Nguyen 
77bdcc293fSTrung Nguyen int
7879572316STrung Nguyen map_cut_fork_test()
7979572316STrung Nguyen {
8079572316STrung Nguyen 	char name[24];
8179572316STrung Nguyen 	sprintf(name, "/shm-mmap-cut-fork-test-%d", getpid());
8279572316STrung Nguyen 	name[sizeof(name) - 1] = '\0';
8379572316STrung Nguyen 	shm_unlink(name);
8479572316STrung Nguyen 	int fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW, 0600);
8579572316STrung Nguyen 	shm_unlink(name);
8679572316STrung Nguyen 
8779572316STrung Nguyen 	if (fd < 0) {
8879572316STrung Nguyen 		printf("failed to create temporary file!\n");
8979572316STrung Nguyen 		return fd;
9079572316STrung Nguyen 	}
9179572316STrung Nguyen 
9279572316STrung Nguyen 	ftruncate(fd, B_PAGE_SIZE * 4);
9379572316STrung Nguyen 
9479572316STrung Nguyen 	uint8* ptr = (uint8*)mmap(NULL, B_PAGE_SIZE * 4, PROT_NONE, MAP_PRIVATE,
9579572316STrung Nguyen 		fd, 0);
9679572316STrung Nguyen 
97*c0a12a6bSAugustin Cavalier 	// we can close the FD as mmap acquires another reference to the vnode
98*c0a12a6bSAugustin Cavalier 	close(fd);
99*c0a12a6bSAugustin Cavalier 
10079572316STrung Nguyen 	// make the head accessible and also force the kernel to allocate the
10179572316STrung Nguyen 	// page_protections array
10279572316STrung Nguyen 	mprotect(ptr, B_PAGE_SIZE, PROT_READ | PROT_WRITE);
10379572316STrung Nguyen 
10479572316STrung Nguyen 	// store any value
10579572316STrung Nguyen 	ptr[0] = 'a';
10679572316STrung Nguyen 
10779572316STrung Nguyen 	// cut the area in the middle
10879572316STrung Nguyen 	mmap(ptr + B_PAGE_SIZE, B_PAGE_SIZE, PROT_NONE,
10979572316STrung Nguyen 		MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
11079572316STrung Nguyen 
11179572316STrung Nguyen 	// validate that the fork does not crash the kernel
11279572316STrung Nguyen 	int pid = fork();
11379572316STrung Nguyen 
11479572316STrung Nguyen 	if (pid == 0)
11579572316STrung Nguyen 	{
11679572316STrung Nguyen 		exit(0);
11779572316STrung Nguyen 	}
11879572316STrung Nguyen 	else if (pid < 0)
11979572316STrung Nguyen 	{
12079572316STrung Nguyen 		printf("failed to fork the test process!\n");
12179572316STrung Nguyen 		return pid;
12279572316STrung Nguyen 	}
12379572316STrung Nguyen 
12479572316STrung Nguyen 	int status;
12579572316STrung Nguyen 	waitpid(pid, &status, 0);
12679572316STrung Nguyen 
12779572316STrung Nguyen 	// validate that this does not crash
12879572316STrung Nguyen 	if (ptr[0] != 'a') {
12979572316STrung Nguyen 		printf("map-cut-fork test failed!\n");
13079572316STrung Nguyen 		return -1;
13179572316STrung Nguyen 	}
13279572316STrung Nguyen 	return 0;
13379572316STrung Nguyen }
13479572316STrung Nguyen 
13579572316STrung Nguyen 
13679572316STrung Nguyen int
137bdcc293fSTrung Nguyen main()
138bdcc293fSTrung Nguyen {
139bdcc293fSTrung Nguyen 	gTestFd = open("/boot/system/lib/libroot.so", O_CLOEXEC | O_RDONLY);
140bdcc293fSTrung Nguyen 	if (gTestFd < 0)
141bdcc293fSTrung Nguyen 		return -1;
142bdcc293fSTrung Nguyen 
143bdcc293fSTrung Nguyen 	int status;
144bdcc293fSTrung Nguyen 
145bdcc293fSTrung Nguyen 	if ((status = map_negative_offset_test()) != 0)
146bdcc293fSTrung Nguyen 		return status;
147bdcc293fSTrung Nguyen 
148bdcc293fSTrung Nguyen 	if ((status = map_cut_compare_test()) != 0)
149bdcc293fSTrung Nguyen 		return status;
150bdcc293fSTrung Nguyen 
151bdcc293fSTrung Nguyen 	if ((status = map_protect_cut_test()) != 0)
152bdcc293fSTrung Nguyen 		return status;
1539ed77019SAugustin Cavalier 
15479572316STrung Nguyen 	if ((status = map_cut_fork_test()) != 0)
15579572316STrung Nguyen 		return status;
15679572316STrung Nguyen 
1579ed77019SAugustin Cavalier 	return 0;
1589ed77019SAugustin Cavalier }
159