xref: /xnu-8020.121.3/tests/vm_test_code_signing_helper.c (revision fdd8201d7b966f0c3ea610489d29bd841d358941)
1 #include <TargetConditionals.h>
2 #include <errno.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <unistd.h>
7 
8 #if __has_include(<ptrauth.h>)
9 #include <ptrauth.h>
10 #endif
11 
12 #include <sys/mman.h>
13 #include <sys/syslimits.h>
14 
15 char *cmdname;
16 
17 int
main(int argc,char * argv[])18 main(
19 	int argc,
20 	char *argv[])
21 {
22 	uint32_t page_size;
23 	void *page;
24 	int ch;
25 	int opt_interactive;
26 
27 	cmdname = argv[0];
28 
29 	opt_interactive = 0;
30 	while ((ch = getopt(argc, argv, "i")) != -1) {
31 		switch (ch) {
32 		case 'i':
33 			opt_interactive = 1;
34 			break;
35 		case '?':
36 		default:
37 			fprintf(stdout,
38 			    "Usage: %s [-i]\n"
39 			    "\t-i: interactive\n",
40 			    cmdname);
41 			exit(1);
42 		}
43 	}
44 
45 	page_size = getpagesize();
46 	page = mmap(NULL, page_size, PROT_READ | PROT_EXEC, MAP_ANON | MAP_SHARED, -1, 0);
47 	if (!page) {
48 		fprintf(stderr, "%s:%d mmap() error %d (%s)\n",
49 		    cmdname, __LINE__,
50 		    errno, strerror(errno));
51 		exit(1);
52 	}
53 	if (opt_interactive) {
54 		fprintf(stdout, "allocated page at %p\n",
55 		    page);
56 	}
57 
58 	if (mprotect(page, page_size, PROT_READ | PROT_WRITE) != 0) {
59 		fprintf(stderr, "%s:%d mprotect(RW) error %d (%s)\n",
60 		    cmdname, __LINE__,
61 		    errno, strerror(errno));
62 		exit(1);
63 	}
64 
65 #if __arm64__
66 	// arm64 chdir() syscall
67 	char chdir_code[] =  {
68 		0x90, 0x01, 0x80, 0xd2, // movz   x16, #0xc
69 		0x01, 0x10, 0x00, 0xd4, // svc    #0x80
70 		0xc0, 0x03, 0x5f, 0xd6, // ret
71 	};
72 #elif __arm__
73 	// armv7 chdir() syscall
74 	char chdir_code[] = {
75 		0x0c, 0xc0, 0xa0, 0xe3, // mov    r12 #0xc
76 		0x80, 0x00, 0x00, 0xef, // svc    #0x80
77 		0x1e, 0xff, 0x2f, 0xe1, // bx lr
78 	};
79 #elif __x86_64__
80 	// x86_64 chdir() syscall
81 	char chdir_code[] = {
82 		0xb8, 0x0c, 0x00, 0x00, 0x02,   // movl   $0x200000c, %eax
83 		0x49, 0x89, 0xca,               // movq   %rcx, %r10
84 		0x0f, 0x05,                     // syscall
85 		0xc3,                           // retq
86 	};
87 #elif __i386__
88 	// i386 chdir() syscall
89 	char chdir_code[] = {
90 		0x90,   // nop
91 		0xc3,   // retq
92 	};
93 #endif
94 	memcpy(page, chdir_code, sizeof chdir_code);
95 
96 	if (opt_interactive) {
97 		fprintf(stdout,
98 		    "changed page protection to r/w and copied code at %p\n",
99 		    page);
100 		fprintf(stdout, "pausing...\n");
101 		fflush(stdout);
102 		getchar();
103 	}
104 
105 	if (mprotect(page, page_size, PROT_READ | PROT_EXEC) != 0) {
106 		fprintf(stderr, "%s:%d mprotect(RX) error %d (%s)\n",
107 		    cmdname, __LINE__,
108 		    errno, strerror(errno));
109 		exit(1);
110 	}
111 
112 	if (opt_interactive) {
113 		fprintf(stdout,
114 		    "changed page protection to r/x at %p\n",
115 		    page);
116 		fprintf(stdout, "pausing...\n");
117 		fflush(stdout);
118 		getchar();
119 	}
120 
121 	char origdir[PATH_MAX];
122 	getcwd(origdir, sizeof(origdir) - 1);
123 
124 	chdir("/");
125 	if (opt_interactive) {
126 		fprintf(stdout, "cwd before = %s\n", getwd(NULL));
127 	}
128 
129 	void (*mychdir)(char *) = page;
130 #if __has_feature(ptrauth_calls)
131 	mychdir = ptrauth_sign_unauthenticated(mychdir, ptrauth_key_function_pointer, 0);
132 #endif
133 	mychdir(getenv("HOME"));
134 	if (opt_interactive) {
135 		fprintf(stdout, "cwd after = %s\n", getwd(NULL));
136 		fprintf(stdout, "pausing...\n");
137 		fflush(stdout);
138 		getchar();
139 	}
140 
141 	fprintf(stdout, "%s: WARNING: unsigned code was executed\n",
142 	    cmdname);
143 
144 	/* fail: unsigned code was executed */
145 	fprintf(stdout, "%s: FAIL\n", cmdname);
146 	exit(1);
147 }
148