xref: /linux/tools/testing/selftests/prctl/set-anon-vma-name-test.c (revision 67f8bc848ee31831336bd478e57d2f993551902e)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * This test covers the anonymous VMA naming functionality through prctl calls
4  */
5 
6 #include <errno.h>
7 #include <fcntl.h>
8 #include <sys/prctl.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <sys/mman.h>
12 #include <string.h>
13 #include <unistd.h>
14 
15 #include "kselftest_harness.h"
16 
17 #define AREA_SIZE 1024
18 
19 #define GOOD_NAME "goodname"
20 #define BAD_NAME "badname\1"
21 
22 #ifndef PR_SET_VMA
23 #define PR_SET_VMA 0x53564d41
24 #define PR_SET_VMA_ANON_NAME 0
25 #endif
26 
27 
28 int rename_vma(unsigned long addr, unsigned long size, char *name)
29 {
30 	int res;
31 
32 	res = prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, addr, size, name);
33 	if (res < 0)
34 		return -errno;
35 	return res;
36 }
37 
38 int was_renaming_successful(char *target_name, unsigned long ptr)
39 {
40 	FILE *maps_file;
41 
42 	char line_buf[512], name[128], mode[8];
43 	unsigned long start_addr, end_addr, offset;
44 	unsigned int major_id, minor_id, node_id;
45 
46 	char target_buf[128];
47 	int res = 0, sscanf_res;
48 
49 	// The entry name in maps will be in format [anon:<target_name>]
50 	sprintf(target_buf, "[anon:%s]", target_name);
51 	maps_file = fopen("/proc/self/maps", "r");
52 	if (!maps_file) {
53 		printf("## /proc/self/maps file opening error\n");
54 		return 0;
55 	}
56 
57 	// Parse the maps file to find the entry we renamed
58 	while (fgets(line_buf, sizeof(line_buf), maps_file)) {
59 		sscanf_res = sscanf(line_buf, "%lx-%lx %7s %lx %u:%u %u %s", &start_addr,
60 					&end_addr, mode, &offset, &major_id,
61 					&minor_id, &node_id, name);
62 		if (sscanf_res == EOF) {
63 			res = 0;
64 			printf("## EOF while parsing the maps file\n");
65 			break;
66 		}
67 		if (!strcmp(name, target_buf) && start_addr == ptr) {
68 			res = 1;
69 			break;
70 		}
71 	}
72 	fclose(maps_file);
73 	return res;
74 }
75 
76 FIXTURE(vma) {
77 	void *ptr_anon, *ptr_not_anon;
78 	int fd_not_anon;
79 };
80 
81 FIXTURE_SETUP(vma) {
82 	char template[] = "./set-anon-vma-test-XXXXXX";
83 
84 	self->ptr_anon = mmap(NULL, AREA_SIZE, PROT_READ | PROT_WRITE,
85 					MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
86 	ASSERT_NE(self->ptr_anon, MAP_FAILED);
87 
88 	self->fd_not_anon = mkstemp(template);
89 	ASSERT_NE(self->fd_not_anon, -1);
90 	unlink(template);
91 	ASSERT_EQ(ftruncate(self->fd_not_anon, AREA_SIZE), 0);
92 	self->ptr_not_anon = mmap(NULL, AREA_SIZE, PROT_READ | PROT_WRITE,
93 					MAP_PRIVATE, self->fd_not_anon, 0);
94 	ASSERT_NE(self->ptr_not_anon, MAP_FAILED);
95 	close(self->fd_not_anon);
96 }
97 
98 FIXTURE_TEARDOWN(vma) {
99 	munmap(self->ptr_anon, AREA_SIZE);
100 	munmap(self->ptr_not_anon, AREA_SIZE);
101 }
102 
103 TEST_F(vma, renaming) {
104 	TH_LOG("Try to rename the VMA with correct parameters");
105 	EXPECT_GE(rename_vma((unsigned long)self->ptr_anon, AREA_SIZE, GOOD_NAME), 0);
106 	EXPECT_TRUE(was_renaming_successful(GOOD_NAME, (unsigned long)self->ptr_anon));
107 
108 	TH_LOG("Try to pass invalid name (with non-printable character \\1) to rename the VMA");
109 	EXPECT_EQ(rename_vma((unsigned long)self->ptr_anon, AREA_SIZE, BAD_NAME), -EINVAL);
110 
111 	TH_LOG("Try to rename non-anonymous VMA");
112 	EXPECT_EQ(rename_vma((unsigned long) self->ptr_not_anon, AREA_SIZE, GOOD_NAME), -EBADF);
113 }
114 
115 TEST_HARNESS_MAIN
116