]>
Commit | Line | Data |
---|---|---|
a39ff7e2 A |
1 | #define PRIVATE |
2 | #include <System/sys/kdebug.h> | |
5ba3f43e | 3 | #include <darwintest.h> |
a39ff7e2 A |
4 | #include <darwintest_utils.h> |
5 | #include <dispatch/dispatch.h> | |
6 | #include <fcntl.h> | |
5ba3f43e | 7 | #include <inttypes.h> |
a39ff7e2 | 8 | #include <libproc.h> |
cb323159 | 9 | #include <libgen.h> |
5ba3f43e | 10 | #include <limits.h> |
a39ff7e2 A |
11 | #include <mach/mach.h> |
12 | #include <mach/policy.h> | |
d9a64523 | 13 | #include <mach/vm_param.h> |
5ba3f43e A |
14 | #include <os/assumes.h> |
15 | #include <os/overflow.h> | |
a39ff7e2 | 16 | #include <pthread.h> |
d9a64523 | 17 | #include <pthread/qos_private.h> |
a39ff7e2 | 18 | #include <signal.h> |
5ba3f43e | 19 | #include <stdint.h> |
a39ff7e2 | 20 | #include <stdio.h> |
5ba3f43e A |
21 | #include <stdlib.h> |
22 | #include <string.h> | |
a39ff7e2 A |
23 | #include <sys/event.h> |
24 | #include <sys/mman.h> | |
25 | #include <sys/proc_info.h> | |
26 | #include <sys/stat.h> | |
5ba3f43e | 27 | #include <sys/sysctl.h> |
a39ff7e2 | 28 | #include <sys/vnode.h> |
5ba3f43e | 29 | #include <unistd.h> |
5ba3f43e A |
30 | #undef PRIVATE |
31 | ||
cb323159 A |
32 | T_GLOBAL_META(T_META_RUN_CONCURRENTLY(true)); |
33 | ||
a39ff7e2 A |
34 | #define ACT_CHANGE_UID 1 |
35 | #define ACT_CHANGE_RUID 2 | |
36 | #define ACT_EXIT 127 | |
37 | ||
38 | #define ACT_PHASE2 2 | |
39 | #define ACT_PHASE3 3 | |
40 | #define ACT_PHASE4 4 | |
41 | #define ACT_PHASE5 5 | |
42 | ||
43 | #define PIPE_IN 0 | |
44 | #define PIPE_OUT 1 | |
45 | ||
46 | #define CONF_THREAD_NAME "test_child_thread" | |
47 | #define CONF_CMD_NAME getprogname() | |
48 | #define CONF_PROC_COUNT 20 | |
49 | #define CONF_BLK_SIZE 4096 | |
50 | #define CONF_UID_VAL 999U | |
51 | #define CONF_RUID_VAL 998U | |
52 | #define CONF_GID_VAL 997U | |
53 | #define CONF_NICE_VAL 5 | |
54 | #define CONF_NUM_THREADS 2 | |
55 | ||
56 | #define BASEPRI_DEFAULT 31 | |
57 | #define MAXPRI_USER 63 | |
58 | ||
59 | #define CONF_OPN_FILE_COUNT 3 | |
d9a64523 | 60 | #define CONF_TMP_FILE_PFX "/tmp/xnu.tests.proc_info." |
0a7de745 A |
61 | static int |
62 | CONF_TMP_FILE_OPEN(char path[PATH_MAX]) | |
d9a64523 A |
63 | { |
64 | static char stmp_path[PATH_MAX] = {}; | |
65 | char *nm; | |
66 | if (path) { | |
67 | nm = path; | |
68 | } else { | |
69 | nm = stmp_path; | |
70 | } | |
71 | strlcpy(nm, CONF_TMP_FILE_PFX "XXXXXXXXXX", PATH_MAX); | |
72 | int fd = mkstemp(nm); | |
73 | T_QUIET; | |
74 | T_ASSERT_POSIX_SUCCESS(fd, "mkstemp(" CONF_TMP_FILE_PFX "XXXXXXXXXX)"); | |
75 | return fd; | |
76 | } | |
a39ff7e2 A |
77 | |
78 | uint32_t get_tty_dev(void); | |
79 | ||
80 | #define WAIT_FOR_CHILDREN(pipefd, action, child_count) \ | |
81 | do { \ | |
0a7de745 A |
82 | long ret; \ |
83 | if (child_count == 1) { \ | |
84 | int child_ret_action = 999; \ | |
85 | while (child_ret_action != action) { \ | |
86 | ret = read(pipefd, &child_ret_action, sizeof(child_ret_action)); \ | |
87 | } \ | |
88 | } else { \ | |
89 | int child_ready_count = child_count * (int)sizeof(action); \ | |
a39ff7e2 | 90 | \ |
0a7de745 A |
91 | action = 0; \ |
92 | while (child_ready_count) { \ | |
93 | ret = read(pipefd, &action, (int)sizeof(action)); \ | |
94 | if (ret != -1) { \ | |
95 | child_ready_count -= ret; \ | |
96 | } else { \ | |
97 | T_FAIL("ERROR: Could not read from pipe() : %d", errno); \ | |
98 | } \ | |
99 | if (action) { \ | |
100 | T_FAIL("ERROR: Child action failed with error %d", action); \ | |
101 | } \ | |
102 | } \ | |
103 | } \ | |
a39ff7e2 A |
104 | } while (0) |
105 | ||
106 | #define PROC_INFO_CALL(struct_name, pid, flavor, proc_arg) \ | |
107 | do { \ | |
0a7de745 A |
108 | struct struct_name * struct_var = malloc(sizeof(struct struct_name)); \ |
109 | T_QUIET; \ | |
110 | T_ASSERT_NOTNULL(struct_var, "malloc() for " #flavor); \ | |
111 | retval = __proc_info(PROC_INFO_CALL_PIDINFO, pid, flavor, (uint64_t)proc_arg, (user_addr_t)struct_var, \ | |
112 | (uint32_t)sizeof(struct struct_name)); \ | |
a39ff7e2 | 113 | \ |
0a7de745 A |
114 | T_QUIET; \ |
115 | T_EXPECT_POSIX_SUCCESS(retval, "__proc_info call for " #flavor); \ | |
116 | T_ASSERT_EQ_INT(retval, (int)sizeof(struct struct_name), "__proc_info call for " #flavor); \ | |
117 | ret_structs[i] = (void *)struct_var; \ | |
118 | i++; \ | |
a39ff7e2 A |
119 | } while (0) |
120 | ||
121 | uint32_t | |
122 | get_tty_dev() | |
123 | { | |
124 | struct stat buf; | |
125 | stat(ttyname(1), &buf); | |
0a7de745 | 126 | return (uint32_t)buf.st_rdev; |
a39ff7e2 A |
127 | } |
128 | ||
129 | /* | |
130 | * Defined in libsyscall/wrappers/libproc/libproc.c | |
131 | * For API test only. For normal use, please use the libproc API instead. | |
132 | * DO NOT COPY | |
133 | */ | |
134 | extern int __proc_info(int32_t callnum, int32_t pid, uint32_t flavor, uint64_t arg, user_addr_t buffer, int32_t buffersize); | |
135 | struct proc_config_s { | |
136 | int parent_pipe[2]; | |
137 | int child_count; | |
138 | pid_t proc_grp_id; | |
139 | int child_pipe[CONF_PROC_COUNT][2]; | |
140 | int child_pids[CONF_PROC_COUNT]; | |
141 | void * cow_map; /* memory for cow test */ | |
142 | }; | |
143 | typedef struct proc_config_s * proc_config_t; | |
144 | ||
145 | typedef void (^child_action_handler_t)(proc_config_t proc_config, int child_id); | |
146 | ||
147 | enum proc_info_opt { | |
148 | P_UNIQIDINFO = 0x01, | |
149 | C_UNIQIDINFO = 0x02, | |
150 | PBSD_OLD = 0x04, | |
151 | PBSD = 0x08, | |
152 | PBSD_SHORT = 0x10, | |
153 | PBSD_UNIQID = 0x20, | |
154 | P_TASK_INFO = 0x40, | |
155 | P_TASK_INFO_NEW = 0x80, | |
156 | PALL = 0x100, | |
157 | THREAD_ADDR = 0x200, | |
158 | PTHINFO_OLD = 0x400, | |
159 | PTHINFO = 0x800, | |
160 | PTHINFO_64 = 0x1000, | |
161 | PINFO_PATH = 0x2000, | |
162 | PAI = 0x4000, | |
163 | PREGINFO = 0x8000, | |
164 | PREGINFO_PATH = 0x10000, | |
165 | PREGINFO_PATH_2 = 0x20000, | |
166 | PREGINFO_PATH_3 = 0x40000, | |
167 | PVNINFO = 0x80000 | |
168 | }; | |
169 | ||
170 | static int tmp_fd = -1; | |
171 | ||
0a7de745 A |
172 | static child_action_handler_t proc_info_listpids_handler = ^void (proc_config_t proc_config, int child_id) { |
173 | close(proc_config->parent_pipe[PIPE_IN]); | |
174 | close(proc_config->child_pipe[child_id][PIPE_OUT]); | |
175 | long retval = 0; | |
176 | int child_action = 0; | |
177 | retval = write(proc_config->parent_pipe[PIPE_OUT], &child_action, sizeof(child_action)); | |
178 | if (retval != -1) { | |
179 | while (child_action != ACT_EXIT) { | |
180 | retval = read(proc_config->child_pipe[child_id][PIPE_IN], &child_action, sizeof(child_action)); | |
181 | if (retval == 0 || (retval == -1 && errno == EAGAIN)) { | |
182 | continue; | |
183 | } | |
184 | if (retval != -1) { | |
185 | switch (child_action) { | |
186 | case ACT_CHANGE_UID: | |
187 | /* | |
188 | * Change uid | |
189 | */ | |
190 | retval = setuid(CONF_UID_VAL); | |
191 | break; | |
192 | case ACT_CHANGE_RUID: | |
193 | /* | |
194 | * Change ruid | |
195 | */ | |
196 | retval = setreuid(CONF_RUID_VAL, (uid_t)-1); | |
197 | break; | |
198 | case ACT_EXIT: | |
199 | /* | |
200 | * Exit | |
201 | */ | |
202 | break; | |
203 | } | |
204 | } | |
205 | if (child_action != ACT_EXIT) { | |
206 | retval = write(proc_config->parent_pipe[PIPE_OUT], &retval, sizeof(retval)); | |
207 | if (retval == -1) { | |
208 | break; | |
209 | } | |
210 | } | |
211 | } | |
212 | } | |
213 | close(proc_config->parent_pipe[PIPE_OUT]); | |
214 | close(proc_config->child_pipe[child_id][PIPE_IN]); | |
215 | exit(0); | |
a39ff7e2 A |
216 | }; |
217 | ||
0a7de745 A |
218 | static child_action_handler_t proc_info_call_pidinfo_handler = ^void (proc_config_t proc_config, int child_id) { |
219 | close(proc_config->parent_pipe[PIPE_IN]); | |
220 | close(proc_config->child_pipe[child_id][PIPE_OUT]); | |
221 | int action = 0; | |
222 | long retval = 0; | |
223 | int i; | |
224 | void * tmp_map = NULL; | |
225 | dispatch_queue_t q = NULL; | |
226 | dispatch_semaphore_t sem = NULL; | |
227 | /* | |
228 | * PHASE 1: Child ready and waits for parent to send next action | |
229 | */ | |
230 | T_LOG("Child ready to accept action from parent"); | |
231 | retval = write(proc_config->parent_pipe[PIPE_OUT], &action, sizeof(action)); | |
232 | if (retval != -1) { | |
233 | while (action != ACT_EXIT) { | |
234 | retval = read(proc_config->child_pipe[child_id][PIPE_IN], &action, sizeof(action)); | |
235 | ||
236 | if (retval != -1) { | |
237 | retval = 0; | |
238 | switch (action) { | |
239 | case ACT_PHASE2: { | |
240 | /* | |
241 | * Change uid, euid, guid, rgid, nice value | |
242 | * Also change the svuid and svgid | |
243 | */ | |
244 | T_LOG("Child changing uid, euid, rguid, svuid, svgid and nice value"); | |
245 | retval = nice(CONF_NICE_VAL); | |
246 | if (retval == -1) { | |
247 | T_LOG("(child) ERROR: nice() failed"); | |
248 | break; | |
249 | } | |
250 | retval = setgid(CONF_GID_VAL); | |
251 | if (retval == -1) { | |
252 | T_LOG("(child) ERROR: setgid() failed"); | |
253 | break; | |
254 | } | |
255 | retval = setreuid((uid_t)-1, CONF_RUID_VAL); | |
256 | if (retval == -1) { | |
257 | T_LOG("(child) ERROR: setreuid() failed"); | |
258 | break; | |
259 | } | |
260 | break; | |
261 | } | |
262 | case ACT_PHASE3: { | |
263 | /* | |
264 | * Allocate a page of memory | |
265 | * Copy on write shared memory | |
eb6b6ca3 A |
266 | * |
267 | * WARNING | |
268 | * Don't add calls to T_LOG here as they can end up generating unwanted | |
269 | * calls to mach_msg_send(). If curtask->messages_sent gets incremented | |
270 | * at this point it will interfere with testing pti_messages_sent. | |
0a7de745 | 271 | */ |
0a7de745 A |
272 | retval = 0; |
273 | tmp_map = mmap(0, PAGE_SIZE, PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); | |
274 | if (tmp_map == MAP_FAILED) { | |
275 | T_LOG("(child) ERROR: mmap() failed"); | |
276 | retval = 1; | |
277 | break; | |
278 | } | |
279 | /* | |
280 | * Get the page allocated | |
281 | */ | |
282 | int * map_ptr = (int *)tmp_map; | |
283 | for (i = 0; i < (int)(PAGE_SIZE / sizeof(int)); i++) { | |
284 | *map_ptr++ = i; | |
285 | } | |
286 | /* | |
287 | * Cause copy on write to the page | |
288 | */ | |
289 | *((int *)(proc_config->cow_map)) = 20; | |
290 | ||
291 | break; | |
292 | } | |
293 | case ACT_PHASE4: { | |
294 | T_LOG("Child spending CPU cycles and changing thread name"); | |
295 | retval = 0; | |
296 | int number = 1000; | |
297 | unsigned long long factorial = 1; | |
298 | int j; | |
299 | for (j = 1; j <= number; j++) { | |
300 | factorial *= (unsigned long long)j; | |
301 | } | |
302 | sysctlbyname("kern.threadname", NULL, 0, CONF_THREAD_NAME, strlen(CONF_THREAD_NAME)); | |
303 | break; | |
304 | } | |
305 | case ACT_PHASE5: { | |
306 | /* | |
307 | * Dispatch for Workq test | |
308 | */ | |
309 | T_LOG("Child creating a dispatch queue, and dispatching blocks on it"); | |
310 | q = dispatch_queue_create("com.apple.test_proc_info.workqtest", | |
311 | DISPATCH_QUEUE_CONCURRENT); // dispatch_get_global_queue(0, 0); | |
312 | sem = dispatch_semaphore_create(0); | |
313 | ||
314 | for (i = 0; i < CONF_NUM_THREADS; i++) { | |
315 | dispatch_async(q, ^{ | |
316 | /* | |
317 | * Block the thread, do nothing | |
318 | */ | |
319 | dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER); | |
320 | }); | |
321 | } | |
322 | break; | |
323 | } | |
324 | case ACT_EXIT: { | |
325 | /* | |
326 | * Exit | |
327 | */ | |
328 | if (sem) { | |
329 | for (i = 0; i < CONF_NUM_THREADS; i++) { | |
330 | dispatch_semaphore_signal(sem); | |
331 | } | |
332 | } | |
333 | ||
334 | if (tmp_map) { | |
335 | munmap(tmp_map, PAGE_SIZE); | |
336 | } | |
337 | ||
338 | if (proc_config->cow_map) { | |
339 | munmap(proc_config->cow_map, PAGE_SIZE); | |
340 | } | |
341 | ||
342 | break; | |
343 | } | |
344 | } | |
345 | } | |
346 | if (action != ACT_EXIT) { | |
347 | retval = write(proc_config->parent_pipe[PIPE_OUT], &action, sizeof(action)); | |
348 | if (retval == -1) { | |
349 | break; | |
350 | } | |
351 | } | |
352 | } | |
353 | close(proc_config->parent_pipe[PIPE_OUT]); | |
354 | close(proc_config->child_pipe[child_id][PIPE_IN]); | |
355 | exit(0); | |
356 | } | |
a39ff7e2 A |
357 | }; |
358 | ||
359 | static void | |
360 | free_proc_config(proc_config_t proc_config) | |
361 | { | |
362 | free(proc_config); | |
363 | } | |
364 | ||
365 | static void | |
366 | send_action_to_child_processes(proc_config_t proc_config, int action) | |
367 | { | |
368 | long err; | |
369 | for (int i = 0; i < proc_config->child_count; i++) { | |
370 | err = write(proc_config->child_pipe[i][PIPE_OUT], &action, sizeof(action)); | |
371 | T_QUIET; | |
372 | T_ASSERT_POSIX_SUCCESS(err, "write() to child in send_action"); | |
373 | } | |
374 | if (action != ACT_EXIT) { | |
375 | WAIT_FOR_CHILDREN(proc_config->parent_pipe[PIPE_IN], action, proc_config->child_count); | |
376 | } | |
377 | } | |
378 | ||
379 | static void | |
380 | kill_child_processes(proc_config_t proc_config) | |
381 | { | |
382 | int ret = 0; | |
383 | T_LOG("Killing child processes"); | |
384 | send_action_to_child_processes(proc_config, ACT_EXIT); | |
385 | for (int child_id = 0; child_id < proc_config->child_count; child_id++) { | |
386 | close(proc_config->child_pipe[child_id][PIPE_OUT]); | |
387 | dt_waitpid(proc_config->child_pids[child_id], NULL, NULL, 5); | |
388 | T_QUIET; | |
389 | T_ASSERT_POSIX_SUCCESS(ret, "killed child %d", child_id); | |
390 | } | |
391 | close(proc_config->parent_pipe[PIPE_IN]); | |
392 | munmap(proc_config->cow_map, PAGE_SIZE); | |
393 | T_LOG("Killed child processes"); | |
394 | } | |
395 | ||
396 | static proc_config_t | |
397 | spawn_child_processes(int child_count, child_action_handler_t child_handler) | |
398 | { | |
399 | /* | |
400 | * Spawn procs for Tests 1.2 and 1.3 | |
401 | */ | |
402 | T_LOG("Spawning child processes..."); | |
403 | proc_config_t proc_config = malloc(sizeof(*proc_config)); | |
404 | int action = 0; | |
405 | int err; | |
406 | ||
407 | setpgid(0, 0); | |
408 | proc_config->proc_grp_id = getpgid(0); | |
409 | ||
410 | proc_config->child_count = child_count; | |
411 | ||
412 | err = pipe(proc_config->parent_pipe); | |
413 | T_QUIET; | |
414 | T_ASSERT_POSIX_SUCCESS(err, "pipe() call"); | |
415 | ||
416 | /* | |
417 | * Needed for ACT_PHASE3 tests | |
418 | */ | |
419 | proc_config->cow_map = mmap(0, PAGE_SIZE, PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); | |
420 | T_QUIET; | |
421 | T_ASSERT_NE_PTR(proc_config->cow_map, MAP_FAILED, "cow_map mmap()"); | |
422 | *((int *)(proc_config->cow_map)) = 10; | |
423 | ||
424 | pid_t child_pid; | |
425 | int i; | |
426 | int child_id; | |
427 | for (i = 0; i < child_count; i++) { | |
428 | err = pipe(proc_config->child_pipe[i]); | |
429 | T_QUIET; | |
430 | T_ASSERT_POSIX_SUCCESS(err, "pipe() call"); | |
431 | ||
432 | child_pid = fork(); | |
433 | child_id = i; | |
434 | T_QUIET; | |
435 | T_ASSERT_POSIX_SUCCESS(child_pid, "fork() in parent process for child %d", child_id); | |
436 | ||
437 | if (child_pid == 0) { | |
438 | child_handler(proc_config, child_id); | |
439 | } else { | |
440 | proc_config->child_pids[child_id] = child_pid; | |
441 | } | |
442 | close(proc_config->child_pipe[child_id][PIPE_IN]); | |
443 | } | |
444 | /* | |
445 | * Wait for the children processes to spawn | |
446 | */ | |
447 | close(proc_config->parent_pipe[PIPE_OUT]); | |
448 | WAIT_FOR_CHILDREN(proc_config->parent_pipe[PIPE_IN], action, child_count); | |
449 | ||
450 | return proc_config; | |
451 | } | |
452 | ||
453 | /* | |
454 | * All PROC_INFO_CALL_PIDINFO __proc_info calls fire from this function. | |
455 | * T_DECLs require different combinations of structs and different actions | |
456 | * must occur in the child to get the data. Instead of performing the setup | |
457 | * in each T_DECL, this function accepts a bitmap and performs the necessary setup | |
458 | * and cleanup work | |
459 | */ | |
460 | ||
461 | static void | |
462 | proc_info_caller(int proc_info_opts, void ** ret_structs, int * ret_child_pid) | |
463 | { | |
464 | int retval, i = 0; | |
465 | uint64_t * thread_addr = NULL; | |
466 | void * map_tmp = NULL; | |
0a7de745 | 467 | static char tmp_path[PATH_MAX] = {}; |
a39ff7e2 A |
468 | |
469 | proc_config_t proc_config = spawn_child_processes(1, proc_info_call_pidinfo_handler); | |
470 | int child_pid = proc_config->child_pids[0]; | |
471 | /* | |
472 | * These tests only require one child. | |
473 | * Some DECLs need to know the child pid, so we pass that back if applicable | |
474 | */ | |
475 | if (ret_child_pid != NULL) { | |
476 | *ret_child_pid = child_pid; | |
477 | } | |
478 | ||
479 | if (proc_info_opts & P_UNIQIDINFO) { | |
480 | PROC_INFO_CALL(proc_uniqidentifierinfo, getpid(), PROC_PIDUNIQIDENTIFIERINFO, 0); | |
481 | } | |
482 | if (proc_info_opts & C_UNIQIDINFO) { | |
483 | PROC_INFO_CALL(proc_uniqidentifierinfo, child_pid, PROC_PIDUNIQIDENTIFIERINFO, 0); | |
484 | } | |
485 | if (proc_info_opts & PBSD_OLD) { | |
486 | PROC_INFO_CALL(proc_bsdinfo, child_pid, PROC_PIDTBSDINFO, 0); | |
487 | } | |
488 | ||
489 | /* | |
490 | * Child Phase 2 Fires if opts require it | |
491 | * Small nap after call to give child time to receive and execute the action | |
492 | */ | |
493 | ||
494 | if (proc_info_opts >= PBSD) { | |
495 | send_action_to_child_processes(proc_config, ACT_PHASE2); | |
496 | } | |
497 | ||
498 | if (proc_info_opts & PBSD) { | |
499 | PROC_INFO_CALL(proc_bsdinfo, child_pid, PROC_PIDTBSDINFO, 0); | |
500 | } | |
501 | ||
502 | if (proc_info_opts & PBSD_SHORT) { | |
503 | PROC_INFO_CALL(proc_bsdshortinfo, child_pid, PROC_PIDT_SHORTBSDINFO, 0); | |
504 | } | |
505 | ||
506 | if (proc_info_opts & PBSD_UNIQID) { | |
507 | PROC_INFO_CALL(proc_bsdinfowithuniqid, child_pid, PROC_PIDT_BSDINFOWITHUNIQID, 0); | |
508 | } | |
509 | if (proc_info_opts & P_TASK_INFO) { | |
510 | PROC_INFO_CALL(proc_taskinfo, child_pid, PROC_PIDTASKINFO, 0); | |
511 | } | |
512 | ||
513 | /* | |
514 | * Child Phase 3 Fires | |
515 | */ | |
516 | if (proc_info_opts >= P_TASK_INFO_NEW) { | |
517 | send_action_to_child_processes(proc_config, ACT_PHASE3); | |
518 | } | |
519 | ||
520 | if (proc_info_opts & P_TASK_INFO_NEW) { | |
521 | PROC_INFO_CALL(proc_taskinfo, child_pid, PROC_PIDTASKINFO, 0); | |
522 | } | |
523 | ||
524 | if (proc_info_opts & PALL) { | |
525 | PROC_INFO_CALL(proc_taskallinfo, child_pid, PROC_PIDTASKALLINFO, 0); | |
526 | } | |
527 | /* | |
528 | * This case breaks the pattern in that its proc_info call requires PALL, | |
529 | * its value is required in some other proc_info calls | |
530 | * and we never put the retval into our ret_structs | |
531 | */ | |
532 | if (proc_info_opts & THREAD_ADDR || proc_info_opts & PTHINFO_OLD || proc_info_opts & PTHINFO || proc_info_opts & PINFO_PATH) { | |
533 | struct proc_taskallinfo * pall = malloc(sizeof(struct proc_taskallinfo)); | |
534 | T_QUIET; | |
535 | T_ASSERT_NOTNULL(pall, "malloc() for PROC_TASKALLINFO"); | |
536 | ||
537 | retval = __proc_info(PROC_INFO_CALL_PIDINFO, child_pid, PROC_PIDTASKALLINFO, (uint32_t)0, (user_addr_t)pall, | |
0a7de745 | 538 | (uint32_t)sizeof(struct proc_taskallinfo)); |
a39ff7e2 A |
539 | T_QUIET; |
540 | T_ASSERT_EQ_INT(retval, (int)sizeof(struct proc_taskallinfo), "__proc_info call for PROC_PIDTASKALLINFO in THREAD_ADDR"); | |
541 | ||
542 | thread_addr = malloc(sizeof(uint64_t) * (unsigned long)(pall->ptinfo.pti_threadnum + 1)); | |
543 | memset(thread_addr, 0, sizeof(uint64_t) * (unsigned long)(pall->ptinfo.pti_threadnum + 1)); | |
544 | T_QUIET; | |
545 | T_ASSERT_NOTNULL(thread_addr, "malloc() for PROC_PIDLISTTHREADS"); | |
546 | ||
547 | retval = __proc_info(PROC_INFO_CALL_PIDINFO, child_pid, PROC_PIDLISTTHREADS, (uint32_t)0, (user_addr_t)thread_addr, | |
0a7de745 | 548 | (int32_t)(sizeof(uint64_t) * (unsigned long)(pall->ptinfo.pti_threadnum + 1))); |
a39ff7e2 | 549 | T_LOG("(int)((unsigned long)retval / PROC_PIDLISTTHREADS_SIZE: %d", |
0a7de745 | 550 | (int)((unsigned long)retval / PROC_PIDLISTTHREADS_SIZE)); |
a39ff7e2 | 551 | T_ASSERT_GE_INT((int)((unsigned long)retval / PROC_PIDLISTTHREADS_SIZE), pall->ptinfo.pti_threadnum, |
0a7de745 | 552 | "__proc_info call for PROC_PIDLISTTHREADS"); |
a39ff7e2 A |
553 | |
554 | free(pall); | |
555 | } | |
556 | if (proc_info_opts & PTHINFO_OLD) { | |
557 | PROC_INFO_CALL(proc_threadinfo, child_pid, PROC_PIDTHREADINFO, thread_addr[0]); | |
558 | } | |
559 | ||
560 | /* | |
561 | * Child Phase 4 Fires | |
562 | */ | |
563 | if (proc_info_opts >= PTHINFO) { | |
564 | send_action_to_child_processes(proc_config, ACT_PHASE4); | |
565 | } | |
566 | ||
567 | if (proc_info_opts & PTHINFO) { | |
568 | PROC_INFO_CALL(proc_threadinfo, child_pid, PROC_PIDTHREADINFO, thread_addr[0]); | |
569 | } | |
570 | if (proc_info_opts & PTHINFO_64) { | |
571 | mach_port_name_t child_task = MACH_PORT_NULL; | |
572 | thread_array_t child_threads = NULL; | |
573 | mach_msg_type_number_t child_thread_count; | |
574 | thread_identifier_info_data_t child_thread_threadinfo; | |
575 | mach_msg_type_number_t thread_info_count = THREAD_IDENTIFIER_INFO_COUNT; | |
576 | struct proc_threadinfo * pthinfo_64 = malloc(sizeof(struct proc_threadinfo)); | |
577 | T_QUIET; | |
578 | T_ASSERT_NOTNULL(pthinfo_64, "malloc() for PROC_THREADINFO"); | |
579 | ||
580 | retval = task_for_pid(mach_task_self(), child_pid, &child_task); | |
581 | T_ASSERT_EQ_INT(retval, 0, "task_for_pid for PROC_PIDTHREADID64INFO"); | |
582 | ||
583 | retval = task_threads(child_task, &child_threads, &child_thread_count); | |
584 | T_ASSERT_MACH_SUCCESS(retval, "task_threads() call for PROC_PIDTHREADID64INFO"); | |
585 | ||
586 | retval = thread_info(child_threads[0], THREAD_IDENTIFIER_INFO, (thread_info_t)&child_thread_threadinfo, &thread_info_count); | |
587 | T_ASSERT_MACH_SUCCESS(retval, "thread_info call for PROC_PIDTHREADID64INFO"); | |
588 | ||
589 | retval = __proc_info(PROC_INFO_CALL_PIDINFO, child_pid, PROC_PIDTHREADID64INFO, (uint64_t)child_thread_threadinfo.thread_id, | |
0a7de745 | 590 | (user_addr_t)pthinfo_64, (uint32_t)sizeof(struct proc_threadinfo)); |
a39ff7e2 A |
591 | T_ASSERT_EQ_INT(retval, (int)sizeof(struct proc_threadinfo), "__proc_info call for PROC_PIDTHREADID64INFO"); |
592 | ||
593 | ret_structs[i] = (void *)pthinfo_64; | |
594 | i++; | |
595 | ||
596 | mach_port_deallocate(mach_task_self(), child_task); | |
597 | mach_port_deallocate(mach_task_self(), child_threads[0]); | |
598 | child_threads[0] = MACH_PORT_NULL; | |
599 | child_task = MACH_PORT_NULL; | |
600 | } | |
601 | if (proc_info_opts & PINFO_PATH) { | |
602 | PROC_INFO_CALL(proc_threadwithpathinfo, child_pid, PROC_PIDTHREADPATHINFO, thread_addr[0]); | |
603 | } | |
604 | ||
605 | if (proc_info_opts & PAI) { | |
606 | PROC_INFO_CALL(proc_archinfo, getpid(), PROC_PIDARCHINFO, 0); | |
607 | } | |
608 | ||
d9a64523 | 609 | vm_map_size_t map_tmp_sz = 0; |
a39ff7e2 A |
610 | if ((proc_info_opts & PREGINFO) | (proc_info_opts & PREGINFO_PATH) | (proc_info_opts & PREGINFO_PATH_2) | |
611 | (proc_info_opts & PREGINFO_PATH_3)) { | |
d9a64523 | 612 | tmp_fd = CONF_TMP_FILE_OPEN(tmp_path); |
a39ff7e2 | 613 | |
d9a64523 A |
614 | /* |
615 | * subsequent checks assume that this data does *not* stay | |
616 | * resident in the buffer cache, so set F_NOCACHE for direct | |
617 | * to storage writing. NOTE: this works if the writes are | |
618 | * page-aligned and > 2 pages in length. | |
619 | */ | |
620 | retval = fcntl(tmp_fd, F_NOCACHE, 1); | |
a39ff7e2 | 621 | T_QUIET; |
d9a64523 | 622 | T_ASSERT_POSIX_SUCCESS(retval, "fcntl(%d, F_NOCACHE) failed", tmp_fd); |
a39ff7e2 | 623 | |
d9a64523 A |
624 | int npages_to_write = 10; |
625 | map_tmp_sz = (vm_map_size_t)npages_to_write * (vm_map_size_t)PAGE_SIZE; | |
626 | ||
627 | /* | |
628 | * To make sure we don't go through the cached write paths in | |
629 | * the VM, we allocate a PAGE-aligned buffer that is > 2 | |
630 | * pages, and perform a write of the entire buffer (not in | |
631 | * small page-aligned chunks). | |
632 | */ | |
633 | char *buf = valloc((size_t)map_tmp_sz); | |
634 | T_QUIET; | |
635 | T_ASSERT_NOTNULL(buf, "valloc(%d) failed", (int)map_tmp_sz); | |
636 | ||
637 | memset(buf, 0x5, map_tmp_sz); | |
638 | ssize_t bw = write(tmp_fd, buf, (size_t)map_tmp_sz); | |
639 | T_QUIET; | |
640 | T_ASSERT_GT_INT((int)bw, 0, "write(%d, buf, %d) failed", tmp_fd, (int)map_tmp_sz); | |
641 | ||
642 | free(buf); | |
643 | ||
644 | map_tmp_sz -= PAGE_SIZE; | |
645 | map_tmp = mmap(0, (size_t)map_tmp_sz, PROT_WRITE, MAP_PRIVATE, tmp_fd, (off_t)PAGE_SIZE); | |
a39ff7e2 A |
646 | T_ASSERT_NE_PTR(map_tmp, MAP_FAILED, "mmap() for PROC_PIDREGIONINFO"); |
647 | ||
d9a64523 | 648 | T_LOG("file: %s is opened as fd %d and mapped at %llx with size %lu", tmp_path, tmp_fd, (uint64_t)map_tmp, |
0a7de745 | 649 | (unsigned long)PAGE_SIZE); |
d9a64523 A |
650 | |
651 | /* | |
652 | * unlink() the file to be nice, but do it _after_ we've | |
653 | * already flushed and mapped the file. This will ensure that | |
654 | * we don't end up writing to the buffer cache because the | |
655 | * file is unlinked. | |
656 | */ | |
657 | if (!(proc_info_opts & PREGINFO_PATH_3)) { | |
658 | retval = unlink(tmp_path); | |
659 | T_QUIET; | |
660 | T_ASSERT_POSIX_SUCCESS(retval, "unlink(%s) failed", tmp_path); | |
661 | } | |
a39ff7e2 A |
662 | } |
663 | ||
664 | if (proc_info_opts & PREGINFO) { | |
665 | PROC_INFO_CALL(proc_regioninfo, getpid(), PROC_PIDREGIONINFO, map_tmp); | |
666 | ret_structs[i] = map_tmp; | |
667 | i++; | |
d9a64523 A |
668 | ret_structs[i] = (void *)(uintptr_t)map_tmp_sz; |
669 | i++; | |
a39ff7e2 A |
670 | } |
671 | if (proc_info_opts & PREGINFO_PATH) { | |
672 | PROC_INFO_CALL(proc_regionwithpathinfo, getpid(), PROC_PIDREGIONPATHINFO, map_tmp); | |
673 | ret_structs[i] = map_tmp; | |
674 | i++; | |
d9a64523 A |
675 | ret_structs[i] = (void *)(uintptr_t)map_tmp_sz; |
676 | i++; | |
a39ff7e2 A |
677 | } |
678 | if (proc_info_opts & PREGINFO_PATH_2) { | |
679 | PROC_INFO_CALL(proc_regionwithpathinfo, getpid(), PROC_PIDREGIONPATHINFO2, map_tmp); | |
680 | ret_structs[i] = map_tmp; | |
681 | i++; | |
d9a64523 A |
682 | ret_structs[i] = (void *)(uintptr_t)map_tmp_sz; |
683 | i++; | |
a39ff7e2 A |
684 | } |
685 | ||
686 | if (proc_info_opts & PREGINFO_PATH_3) { | |
687 | struct proc_regionwithpathinfo * preginfo_path = malloc(sizeof(struct proc_regionwithpathinfo)); | |
688 | ||
689 | retval = __proc_info(PROC_INFO_CALL_PIDINFO, getpid(), PROC_PIDREGIONPATHINFO2, (uint64_t)map_tmp, | |
0a7de745 | 690 | (user_addr_t)preginfo_path, (uint32_t)sizeof(struct proc_regionwithpathinfo)); |
a39ff7e2 A |
691 | |
692 | T_ASSERT_EQ_INT(retval, (int)sizeof(struct proc_regionwithpathinfo), "__proc_info call for PROC_PIDREGIONPATHINFO2"); | |
693 | ||
694 | T_LOG("preginfo_path.prp_vip.vip_vi.vi_fsid.val 0: %d", preginfo_path->prp_vip.vip_vi.vi_fsid.val[0]); | |
695 | T_LOG("preginfo_path.prp_vip.vip_vi.vi_fsid.val 1: %d", preginfo_path->prp_vip.vip_vi.vi_fsid.val[1]); | |
0a7de745 A |
696 | ret_structs[3] = (void *)(uintptr_t)preginfo_path->prp_vip.vip_vi.vi_fsid.val[0]; |
697 | ret_structs[4] = (void *)(uintptr_t)preginfo_path->prp_vip.vip_vi.vi_fsid.val[1]; | |
a39ff7e2 A |
698 | |
699 | retval = __proc_info(PROC_INFO_CALL_PIDINFO, getpid(), PROC_PIDREGIONPATHINFO3, | |
0a7de745 A |
700 | (uint64_t)preginfo_path->prp_vip.vip_vi.vi_fsid.val[0] + |
701 | ((uint64_t)preginfo_path->prp_vip.vip_vi.vi_fsid.val[1] << 32), | |
702 | (user_addr_t)preginfo_path, | |
703 | (uint32_t)sizeof(struct proc_regionwithpathinfo)); | |
a39ff7e2 | 704 | T_ASSERT_EQ_INT(retval, (int)sizeof(struct proc_regionwithpathinfo), "__proc_info call for PROC_PIDREGIONPATHWITHINFO3"); |
0a7de745 A |
705 | ret_structs[0] = (void *)preginfo_path; |
706 | ret_structs[1] = (void *)map_tmp; | |
707 | ret_structs[2] = (void *)(uintptr_t)map_tmp_sz; | |
d9a64523 | 708 | |
0a7de745 | 709 | retval = unlink(tmp_path); |
d9a64523 A |
710 | T_QUIET; |
711 | T_ASSERT_POSIX_SUCCESS(retval, "unlink(%s) failed", preginfo_path->prp_vip.vip_path); | |
a39ff7e2 A |
712 | } |
713 | ||
714 | if (proc_info_opts & PVNINFO) { | |
715 | PROC_INFO_CALL(proc_vnodepathinfo, getpid(), PROC_PIDVNODEPATHINFO, 0); | |
716 | } | |
717 | ||
718 | kill_child_processes(proc_config); | |
719 | free_proc_config(proc_config); | |
720 | free(thread_addr); | |
721 | thread_addr = NULL; | |
722 | close(tmp_fd); | |
723 | tmp_fd = -1; | |
724 | } | |
725 | ||
726 | static void | |
727 | free_proc_info(void ** proc_info, int num) | |
728 | { | |
729 | for (int i = 0; i < num; i++) { | |
730 | free(proc_info[i]); | |
731 | } | |
732 | ||
733 | return; | |
734 | } | |
735 | ||
736 | /* | |
737 | * Start DECLs | |
738 | */ | |
739 | ||
740 | T_DECL(proc_info_listpids_all_pids, | |
0a7de745 | 741 | "proc_info API test to verify PROC_INFO_CALL_LISTPIDS", |
cb323159 | 742 | T_META_ASROOT(true)) |
a39ff7e2 A |
743 | { |
744 | /* | |
745 | * Get the value of nprocs with no buffer sent in | |
746 | */ | |
747 | int num_procs; | |
748 | num_procs = __proc_info(PROC_INFO_CALL_LISTPIDS, PROC_ALL_PIDS, (uint32_t)getpid(), (uint32_t)0, (user_addr_t)0, (uint32_t)0); | |
749 | T_ASSERT_GE_INT(num_procs, 1, "verify valid value for nprocs: %d", num_procs); | |
750 | ||
751 | proc_config_t proc_config = spawn_child_processes(CONF_PROC_COUNT, proc_info_listpids_handler); | |
752 | ||
753 | num_procs = __proc_info(PROC_INFO_CALL_LISTPIDS, PROC_ALL_PIDS, (uint32_t)getpid(), (uint32_t)0, (user_addr_t)0, (uint32_t)0); | |
754 | ||
755 | int proc_count = num_procs / (int)sizeof(pid_t); | |
756 | int proc_count_all = num_procs / (int)sizeof(pid_t); | |
757 | if (proc_count > (CONF_PROC_COUNT + 1)) { | |
758 | proc_count = CONF_PROC_COUNT + 1; | |
759 | } | |
760 | pid_t * proc_ids = malloc(sizeof(pid_t) * (unsigned long)proc_count); | |
761 | num_procs = __proc_info(PROC_INFO_CALL_LISTPIDS, PROC_ALL_PIDS, (uint32_t)getpid(), (uint32_t)0, (user_addr_t)proc_ids, | |
0a7de745 | 762 | (int32_t)(proc_count * (int)sizeof(pid_t))); |
a39ff7e2 A |
763 | num_procs = num_procs / (int)sizeof(pid_t); |
764 | T_ASSERT_GE_INT(num_procs, proc_count, "Valid number of pids obtained for PROC_ALL_PIDS."); | |
765 | ||
766 | free(proc_ids); | |
767 | ||
768 | /* | |
769 | * Grab list of all procs and make sure our spawned children are in the list. | |
770 | */ | |
771 | ||
772 | proc_ids = malloc(sizeof(pid_t) * (unsigned long)proc_count_all); | |
773 | num_procs = __proc_info(PROC_INFO_CALL_LISTPIDS, PROC_ALL_PIDS, (uint32_t)getpid(), (uint32_t)0, (user_addr_t)proc_ids, | |
0a7de745 | 774 | (int32_t)(proc_count_all * (int)sizeof(pid_t))); |
a39ff7e2 A |
775 | num_procs = num_procs / (int)sizeof(pid_t); |
776 | ||
777 | int pid_match = 1; | |
778 | ||
779 | for (int i = 0; i < (CONF_PROC_COUNT - 1); i++) { | |
780 | for (int j = 0; j < num_procs; j++) { | |
781 | if (proc_ids[j] == proc_config->child_pids[i]) { | |
782 | break; | |
783 | } else if (j == (num_procs - 1)) { | |
784 | pid_match = 0; | |
785 | break; | |
786 | } | |
787 | } | |
788 | ||
789 | if (!pid_match) { | |
790 | break; | |
791 | } | |
792 | } | |
793 | ||
794 | T_ASSERT_EQ(pid_match, 1, "PROC_INFO_CALL_LISTPIDS contains our spawned children's pids"); | |
795 | ||
796 | free(proc_ids); | |
797 | ||
798 | kill_child_processes(proc_config); | |
799 | free_proc_config(proc_config); | |
800 | ||
801 | errno = 0; | |
802 | num_procs = __proc_info(PROC_INFO_CALL_LISTPIDS, PROC_ALL_PIDS, (uint32_t)getpid(), (uint32_t)0, (user_addr_t)proc_ids, | |
0a7de745 | 803 | (uint32_t)(sizeof(pid_t) - 1)); |
a39ff7e2 A |
804 | T_EXPECT_POSIX_ERROR(errno, ENOMEM, "Valid proc_info behavior when bufsize < sizeof(pid_t)."); |
805 | } | |
806 | ||
807 | T_DECL(proc_info_listpids_pgrp_only, | |
0a7de745 | 808 | "proc_info API test to verify PROC_INFO_CALL_LISTPIDS", |
cb323159 | 809 | T_META_ASROOT(true)) |
a39ff7e2 A |
810 | { |
811 | proc_config_t proc_config = spawn_child_processes(CONF_PROC_COUNT, proc_info_listpids_handler); | |
812 | T_LOG("Test to verify PROC_PGRP_ONLY returns correct value"); | |
813 | /* | |
814 | * The number of obtained pids depends on size of buffer. | |
815 | * count = childCount + 1(parent) | |
816 | * So, we set it to one more than expected to capture any error. | |
817 | */ | |
818 | int proc_count = CONF_PROC_COUNT + 2; | |
819 | pid_t * proc_ids = malloc(sizeof(*proc_ids) * (unsigned long)proc_count); | |
820 | int num_procs = __proc_info(PROC_INFO_CALL_LISTPIDS, PROC_PGRP_ONLY, (uint32_t)proc_config->proc_grp_id, (uint32_t)0, | |
0a7de745 | 821 | (user_addr_t)proc_ids, (int32_t)(proc_count * (int)sizeof(*proc_ids))); |
a39ff7e2 A |
822 | num_procs = num_procs / (int)sizeof(pid_t); |
823 | T_ASSERT_EQ_INT(num_procs, CONF_PROC_COUNT + 1, "Valid number of pids obtained for PROC_PGRP_ONLY."); | |
824 | kill_child_processes(proc_config); | |
825 | free_proc_config(proc_config); | |
826 | free(proc_ids); | |
827 | } | |
828 | ||
829 | T_DECL(proc_info_listpids_ppid_only, | |
0a7de745 | 830 | "proc_info API test to verify PROC_INFO_CALL_LISTPIDS", |
cb323159 | 831 | T_META_ASROOT(true)) |
a39ff7e2 A |
832 | { |
833 | proc_config_t proc_config = spawn_child_processes(CONF_PROC_COUNT, proc_info_listpids_handler); | |
834 | T_LOG("Test to verify PROC_PPID_ONLY returns correct value"); | |
835 | /* | |
836 | * Pass in the same (bigger) buffer but expect only the pids where ppid is pid of current proc. | |
837 | */ | |
838 | int proc_count = CONF_PROC_COUNT + 2; | |
839 | pid_t * proc_ids = malloc(sizeof(*proc_ids) * (unsigned long)proc_count); | |
840 | int num_procs = __proc_info(PROC_INFO_CALL_LISTPIDS, PROC_PPID_ONLY, (uint32_t)getpid(), (uint32_t)0, (user_addr_t)proc_ids, | |
0a7de745 | 841 | (int32_t)(proc_count * (int)sizeof(*proc_ids))); |
a39ff7e2 A |
842 | num_procs = num_procs / (int)sizeof(pid_t); |
843 | T_ASSERT_EQ_INT(num_procs, CONF_PROC_COUNT, "Valid number of pids obtained for PROC_PPID_ONLY."); | |
844 | kill_child_processes(proc_config); | |
845 | free_proc_config(proc_config); | |
846 | free(proc_ids); | |
847 | } | |
848 | ||
849 | T_DECL(proc_info_listpids_uid_only, | |
0a7de745 | 850 | "proc_info API test to verify PROC_INFO_CALL_LISTPIDS", |
cb323159 | 851 | T_META_ASROOT(true)) |
a39ff7e2 A |
852 | { |
853 | proc_config_t proc_config = spawn_child_processes(CONF_PROC_COUNT, proc_info_listpids_handler); | |
854 | T_LOG("Test to verify PROC_UID_ONLY returns correct value"); | |
855 | int proc_count = CONF_PROC_COUNT + 2; | |
856 | pid_t * proc_ids = malloc(sizeof(*proc_ids) * (unsigned long)proc_count); | |
857 | send_action_to_child_processes(proc_config, ACT_CHANGE_UID); | |
858 | usleep(10000); | |
859 | int num_procs = __proc_info(PROC_INFO_CALL_LISTPIDS, PROC_UID_ONLY, CONF_UID_VAL, (uint32_t)0, (user_addr_t)proc_ids, | |
0a7de745 | 860 | (int32_t)(proc_count * (int)sizeof(*proc_ids))); |
a39ff7e2 | 861 | T_ASSERT_GE_ULONG((unsigned long)num_procs / sizeof(pid_t), (unsigned long)CONF_PROC_COUNT, |
0a7de745 | 862 | "Valid number of pids obtained for PROC_UID_ONLY."); |
a39ff7e2 A |
863 | kill_child_processes(proc_config); |
864 | free_proc_config(proc_config); | |
865 | free(proc_ids); | |
866 | } | |
867 | ||
868 | T_DECL(proc_info_listpids_ruid_only, | |
0a7de745 | 869 | "proc_info API test to verify PROC_INFO_CALL_LISTPIDS", |
cb323159 | 870 | T_META_ASROOT(true)) |
a39ff7e2 A |
871 | { |
872 | proc_config_t proc_config = spawn_child_processes(CONF_PROC_COUNT, proc_info_listpids_handler); | |
873 | T_LOG("Test to verify PROC_RUID_ONLY returns correct value"); | |
874 | int proc_count = CONF_PROC_COUNT + 2; | |
875 | pid_t * proc_ids = malloc(sizeof(*proc_ids) * (unsigned long)proc_count); | |
876 | send_action_to_child_processes(proc_config, ACT_CHANGE_RUID); | |
877 | usleep(10000); | |
878 | int num_procs = __proc_info(PROC_INFO_CALL_LISTPIDS, PROC_RUID_ONLY, CONF_RUID_VAL, (uint32_t)0, (user_addr_t)proc_ids, | |
0a7de745 | 879 | (int32_t)(proc_count * (int)sizeof(*proc_ids))); |
a39ff7e2 | 880 | T_ASSERT_GE_ULONG((unsigned long)num_procs / sizeof(pid_t), (unsigned long)CONF_PROC_COUNT, |
0a7de745 | 881 | "Valid number of pids obtained for PROC_RUID_ONLY."); |
a39ff7e2 A |
882 | kill_child_processes(proc_config); |
883 | free_proc_config(proc_config); | |
884 | free(proc_ids); | |
885 | } | |
886 | ||
887 | T_DECL(proc_info_listpids_tty_only, | |
0a7de745 | 888 | "proc_info API test to verify PROC_INFO_CALL_LISTPIDS", |
cb323159 | 889 | T_META_ASROOT(true)) |
a39ff7e2 A |
890 | { |
891 | int ret = isatty(STDOUT_FILENO); | |
892 | if (ret != 1) { | |
893 | T_SKIP("Not connected to tty...skipping test"); | |
894 | } | |
895 | ||
896 | proc_config_t proc_config = spawn_child_processes(CONF_PROC_COUNT, proc_info_listpids_handler); | |
897 | ||
898 | T_LOG("Test to verify PROC_TTY_ONLY returns correct value"); | |
899 | int proc_count = CONF_PROC_COUNT + 2; | |
900 | pid_t * proc_ids = malloc(sizeof(*proc_ids) * (unsigned long)proc_count); | |
901 | int num_procs = __proc_info(PROC_INFO_CALL_LISTPIDS, PROC_TTY_ONLY, get_tty_dev(), (uint32_t)0, (user_addr_t)proc_ids, | |
0a7de745 | 902 | (int32_t)(proc_count * (int)sizeof(*proc_ids))); |
a39ff7e2 A |
903 | num_procs = num_procs / (int)sizeof(pid_t); |
904 | T_ASSERT_GE_INT(num_procs, 0, "Valid number of pids returned by PROC_TTY_ONLY."); | |
905 | kill_child_processes(proc_config); | |
906 | free_proc_config(proc_config); | |
907 | free(proc_ids); | |
908 | } | |
909 | ||
910 | /* | |
911 | * Most of the following PROC_INFO_CALL_PIDINFO tests rely on a helper function (proc_info_caller) to make the necessary proc_info | |
912 | * calls on their behalf | |
913 | * In a previous iteration, these tests were all in one giant T_DECL and the helper function handles inter-DECL dependencies such as | |
914 | * a proc_info call relying on the results of a previous proc_info call or an assumed state that a child should be in. | |
915 | */ | |
916 | ||
917 | T_DECL(proc_info_pidinfo_proc_piduniqidentifierinfo, | |
0a7de745 | 918 | "Test to identify PROC_PIDUNIQIDENTIFIERINFO returns correct unique identifiers for process", |
cb323159 | 919 | T_META_ASROOT(true)) |
a39ff7e2 A |
920 | { |
921 | void * proc_info[2]; | |
922 | proc_info_caller(P_UNIQIDINFO | C_UNIQIDINFO, proc_info, NULL); | |
923 | struct proc_uniqidentifierinfo * p_uniqidinfo = (struct proc_uniqidentifierinfo *)proc_info[0]; | |
924 | struct proc_uniqidentifierinfo * c_uniqidinfo = (struct proc_uniqidentifierinfo *)proc_info[1]; | |
925 | ||
926 | T_EXPECT_NE_ULLONG(c_uniqidinfo->p_uniqueid, p_uniqidinfo->p_uniqueid, "p_uniqueid not unique for the process"); | |
927 | ||
928 | for (size_t i = 0; i < 16; i++) { | |
929 | T_EXPECT_EQ_UCHAR(c_uniqidinfo->p_uuid[i], p_uniqidinfo->p_uuid[i], "p_uuid should be the same unique id"); | |
930 | } | |
931 | T_EXPECT_EQ_ULLONG(c_uniqidinfo->p_puniqueid, p_uniqidinfo->p_uniqueid, | |
0a7de745 | 932 | "p_puniqueid of child should be same as p_uniqueid for parent"); |
a39ff7e2 A |
933 | |
934 | free_proc_info(proc_info, 2); | |
935 | } | |
936 | ||
937 | T_DECL(proc_info_pidinfo_proc_pidtbsdinfo, | |
0a7de745 | 938 | "Test to verify PROC_PIDTBSDINFO returns valid information about the process", |
cb323159 | 939 | T_META_ASROOT(true)) |
a39ff7e2 A |
940 | { |
941 | void * proc_info[2]; | |
942 | int child_pid = 0; | |
943 | proc_info_caller(PBSD_OLD | PBSD, proc_info, &child_pid); | |
944 | struct proc_bsdinfo * pbsd_old = (struct proc_bsdinfo *)proc_info[0]; | |
945 | struct proc_bsdinfo * pbsd = (struct proc_bsdinfo *)proc_info[1]; | |
946 | ||
947 | T_EXPECT_EQ_UINT((unsigned int)SRUN, pbsd->pbi_status, "PROC_PIDTBSDINFO shows Correct status"); | |
948 | T_EXPECT_EQ_UINT(0U, pbsd->pbi_xstatus, "PROC_PIDTBSDINFO show Correct xstatus (exit status)"); | |
949 | T_EXPECT_EQ_UINT(pbsd->pbi_pid, (unsigned int)child_pid, "PROC_PIDTBSDINFO returns valid pid"); | |
950 | T_EXPECT_EQ_UINT(pbsd->pbi_ppid, (unsigned int)getpid(), "PROC_PIDTBSDINFO returns valid ppid"); | |
951 | T_EXPECT_EQ_UINT(pbsd->pbi_uid, CONF_RUID_VAL, "PROC_PIDTBSDINFO returns valid uid"); | |
952 | T_EXPECT_EQ_UINT(pbsd->pbi_gid, CONF_GID_VAL, "PROC_PIDTBSDINFO returns valid gid"); | |
953 | T_EXPECT_EQ_UINT(pbsd->pbi_ruid, 0U, "PROC_PIDTBSDINFO returns valid ruid"); | |
954 | T_EXPECT_EQ_UINT(pbsd->pbi_rgid, CONF_GID_VAL, "PROC_PIDTBSDINFO returns valid rgid"); | |
955 | T_EXPECT_EQ_UINT(pbsd->pbi_svuid, CONF_RUID_VAL, "PROC_PIDTBSDINFO returns valid svuid"); | |
956 | T_EXPECT_EQ_UINT(pbsd->pbi_svgid, CONF_GID_VAL, "PROC_PIDTBSDINFO returns valid svgid"); | |
957 | T_EXPECT_EQ_UINT(pbsd->pbi_nice, CONF_NICE_VAL, "PROC_PIDTBSDINFO returns valid nice value"); | |
958 | T_EXPECT_EQ_STR(pbsd->pbi_comm, CONF_CMD_NAME, "PROC_PIDTBSDINFO returns valid p_comm name"); | |
959 | T_EXPECT_EQ_STR(pbsd->pbi_name, CONF_CMD_NAME, "PROC_PIDTBSDINFO returns valid p_name name"); | |
960 | T_EXPECT_EQ_UINT(pbsd->pbi_flags, (pbsd_old->pbi_flags | PROC_FLAG_PSUGID), "PROC_PIDTBSDINFO returns valid flags"); | |
961 | T_EXPECT_EQ_UINT(pbsd->pbi_nfiles, pbsd_old->pbi_nfiles, "PROC_PIDTBSDINFO returned valid pbi_nfiles"); | |
962 | T_EXPECT_EQ_UINT(pbsd->pbi_pgid, (uint32_t)getpgid(getpid()), "PROC_PIDTBSDINFO returned valid pbi_pgid"); | |
963 | T_EXPECT_EQ_UINT(pbsd->pbi_pjobc, pbsd->pbi_pjobc, "PROC_PIDTBSDINFO returned valid pbi_pjobc"); | |
964 | T_EXPECT_NE_UINT(pbsd->e_tdev, 0U, "PROC_PIDTBSDINFO returned valid e_tdev"); | |
965 | ||
966 | free_proc_info(proc_info, 2); | |
967 | } | |
968 | ||
969 | T_DECL(proc_info_pidt_shortbsdinfo, | |
0a7de745 | 970 | "Test to verify PROC_PIDT_SHORTBSDINFO returns valid information about the process", |
cb323159 | 971 | T_META_ASROOT(true)) |
a39ff7e2 A |
972 | { |
973 | void * proc_info[2]; | |
974 | int child_pid = 0; | |
975 | proc_info_caller(PBSD | PBSD_SHORT, proc_info, &child_pid); | |
976 | struct proc_bsdinfo * pbsd = (struct proc_bsdinfo *)proc_info[0]; | |
977 | struct proc_bsdshortinfo * pbsd_short = (struct proc_bsdshortinfo *)proc_info[1]; | |
978 | ||
979 | T_EXPECT_EQ_UINT(pbsd_short->pbsi_pid, (unsigned int)child_pid, "PROC_PIDT_SHORTBSDINFO returns valid pid"); | |
980 | T_EXPECT_EQ_UINT(pbsd_short->pbsi_ppid, (unsigned int)getpid(), "PROC_PIDT_SHORTBSDINFO returns valid ppid"); | |
981 | T_EXPECT_EQ_UINT(pbsd_short->pbsi_pgid, (uint32_t)getpgid(getpid()), "PROC_PIDT_SHORTBSDINFO returned valid pbi_pgid"); | |
982 | T_EXPECT_EQ_UINT((unsigned int)SRUN, pbsd_short->pbsi_status, "PROC_PIDT_SHORTBSDINFO shows Correct status"); | |
983 | T_EXPECT_EQ_STR(pbsd_short->pbsi_comm, CONF_CMD_NAME, "PROC_PIDT_SHORTBSDINFO returns valid p_comm name"); | |
984 | /* | |
985 | * The short variant returns all flags except session flags, hence ignoring them here. | |
986 | */ | |
987 | T_EXPECT_EQ_UINT(pbsd_short->pbsi_flags, (pbsd->pbi_flags & (unsigned int)(~PROC_FLAG_CTTY)), | |
0a7de745 | 988 | "PROC_PIDT_SHORTBSDINFO returns valid flags"); |
a39ff7e2 A |
989 | T_EXPECT_EQ_UINT(pbsd_short->pbsi_uid, CONF_RUID_VAL, "PROC_PIDT_SHORTBSDINFO returns valid uid"); |
990 | T_EXPECT_EQ_UINT(pbsd_short->pbsi_gid, CONF_GID_VAL, "PROC_PIDT_SHORTBSDINFO returns valid gid"); | |
991 | T_EXPECT_EQ_UINT(pbsd_short->pbsi_ruid, 0U, "PROC_PIDT_SHORTBSDINFO returns valid ruid"); | |
992 | T_EXPECT_EQ_UINT(pbsd_short->pbsi_svuid, CONF_RUID_VAL, "PROC_PIDT_SHORTBSDINFO returns valid svuid"); | |
993 | T_EXPECT_EQ_UINT(pbsd_short->pbsi_svgid, CONF_GID_VAL, "PROC_PIDT_SHORTBSDINFO returns valid svgid"); | |
994 | ||
995 | free_proc_info(proc_info, 2); | |
996 | } | |
997 | ||
998 | T_DECL(proc_info_pidt_bsdinfowithuniqid, | |
0a7de745 | 999 | "Test to verify PROC_PIDT_BSDINFOWITHUNIQID returns valid information about the process", |
cb323159 | 1000 | T_META_ASROOT(true)) |
a39ff7e2 A |
1001 | { |
1002 | void * proc_info[4]; | |
1003 | int child_pid = 0; | |
1004 | proc_info_caller(P_UNIQIDINFO | PBSD_OLD | PBSD | PBSD_UNIQID, proc_info, &child_pid); | |
1005 | struct proc_uniqidentifierinfo * p_uniqidinfo = (struct proc_uniqidentifierinfo *)proc_info[0]; | |
1006 | struct proc_bsdinfo * pbsd_old = (struct proc_bsdinfo *)proc_info[1]; | |
1007 | struct proc_bsdinfo * pbsd = (struct proc_bsdinfo *)proc_info[2]; | |
1008 | struct proc_bsdinfowithuniqid * pbsd_uniqid = (struct proc_bsdinfowithuniqid *)proc_info[3]; | |
1009 | ||
1010 | T_EXPECT_EQ_UINT((unsigned int)SRUN, pbsd->pbi_status, "PROC_PIDT_BSDINFOWITHUNIQID shows Correct status"); | |
1011 | T_EXPECT_EQ_UINT(0U, pbsd->pbi_xstatus, "PROC_PIDT_BSDINFOWITHUNIQID show Correct xstatus"); | |
1012 | T_EXPECT_EQ_UINT(pbsd_uniqid->pbsd.pbi_pid, (unsigned int)child_pid, "PROC_PIDT_BSDINFOWITHUNIQID returns valid pid"); | |
1013 | T_EXPECT_EQ_UINT(pbsd_uniqid->pbsd.pbi_ppid, (unsigned int)getpid(), "PROC_PIDT_BSDINFOWITHUNIQID returns valid ppid"); | |
1014 | T_EXPECT_EQ_UINT(pbsd_uniqid->pbsd.pbi_uid, CONF_RUID_VAL, "PROC_PIDT_BSDINFOWITHUNIQID returns valid uid"); | |
1015 | T_EXPECT_EQ_UINT(pbsd_uniqid->pbsd.pbi_gid, CONF_GID_VAL, "PROC_PIDT_BSDINFOWITHUNIQID returns valid gid"); | |
1016 | T_EXPECT_EQ_UINT(pbsd_uniqid->pbsd.pbi_ruid, 0U, "PROC_PIDT_BSDINFOWITHUNIQID returns valid ruid"); | |
1017 | T_EXPECT_EQ_UINT(pbsd_uniqid->pbsd.pbi_rgid, CONF_GID_VAL, "PROC_PIDT_BSDINFOWITHUNIQID returns valid rgid"); | |
1018 | T_EXPECT_EQ_UINT(pbsd_uniqid->pbsd.pbi_svuid, CONF_RUID_VAL, "PROC_PIDT_BSDINFOWITHUNIQID returns valid svuid"); | |
1019 | T_EXPECT_EQ_UINT(pbsd_uniqid->pbsd.pbi_svgid, CONF_GID_VAL, "PROC_PIDT_BSDINFOWITHUNIQID returns valid svgid"); | |
1020 | T_EXPECT_EQ_UINT(pbsd_uniqid->pbsd.pbi_nice, CONF_NICE_VAL, "PROC_PIDT_BSDINFOWITHUNIQID returns valid nice value"); | |
1021 | T_EXPECT_EQ_STR(pbsd_uniqid->pbsd.pbi_comm, CONF_CMD_NAME, "PROC_PIDT_BSDINFOWITHUNIQID returns valid p_comm name"); | |
1022 | T_EXPECT_EQ_STR(pbsd_uniqid->pbsd.pbi_name, CONF_CMD_NAME, "PROC_PIDT_BSDINFOWITHUNIQID returns valid p_name name"); | |
1023 | T_EXPECT_EQ_UINT(pbsd_uniqid->pbsd.pbi_flags, (pbsd_old->pbi_flags | PROC_FLAG_PSUGID), | |
0a7de745 | 1024 | "PROC_PIDT_BSDINFOWITHUNIQID returns valid flags"); |
a39ff7e2 A |
1025 | T_EXPECT_EQ_UINT(pbsd_uniqid->pbsd.pbi_nfiles, pbsd_old->pbi_nfiles, "PROC_PIDT_BSDINFOWITHUNIQID returned valid pbi_nfiles"); |
1026 | T_EXPECT_EQ_UINT(pbsd_uniqid->pbsd.pbi_pgid, (uint32_t)getpgid(getpid()), | |
0a7de745 | 1027 | "PROC_PIDT_BSDINFOWITHUNIQID returned valid pbi_pgid"); |
a39ff7e2 A |
1028 | T_EXPECT_EQ_UINT(pbsd_uniqid->pbsd.pbi_pjobc, pbsd->pbi_pjobc, "PROC_PIDT_BSDINFOWITHUNIQID returned valid pbi_pjobc"); |
1029 | T_EXPECT_NE_UINT(pbsd_uniqid->pbsd.e_tdev, 0U, "PROC_PIDT_BSDINFOWITHUNIQID returned valid e_tdev"); | |
1030 | T_EXPECT_NE_ULLONG(pbsd_uniqid->p_uniqidentifier.p_uniqueid, p_uniqidinfo->p_uniqueid, | |
0a7de745 | 1031 | "PROC_PIDT_BSDINFOWITHUNIQID returned valid p_uniqueid"); |
a39ff7e2 A |
1032 | for (int i = 0; i < 16; i++) { |
1033 | T_EXPECT_EQ_UCHAR(pbsd_uniqid->p_uniqidentifier.p_uuid[i], p_uniqidinfo->p_uuid[i], | |
0a7de745 | 1034 | "PROC_PIDT_BSDINFOWITHUNIQID reported valid p_uniqueid"); |
a39ff7e2 A |
1035 | } |
1036 | T_EXPECT_EQ_ULLONG(pbsd_uniqid->p_uniqidentifier.p_puniqueid, p_uniqidinfo->p_uniqueid, | |
0a7de745 | 1037 | "p_puniqueid of child should be same as p_uniqueid for parent"); |
a39ff7e2 A |
1038 | |
1039 | free_proc_info(proc_info, 4); | |
1040 | } | |
1041 | ||
1042 | T_DECL(proc_info_proc_pidtask_info, | |
0a7de745 | 1043 | "Test to verify PROC_PIDTASKINFO returns valid information about the process", |
cb323159 | 1044 | T_META_ASROOT(true)) |
a39ff7e2 A |
1045 | { |
1046 | void * proc_info[2]; | |
1047 | proc_info_caller(P_TASK_INFO | P_TASK_INFO_NEW, proc_info, NULL); | |
1048 | struct proc_taskinfo * p_task_info = (struct proc_taskinfo *)proc_info[0]; | |
1049 | struct proc_taskinfo * p_task_info_new = (struct proc_taskinfo *)proc_info[1]; | |
1050 | ||
1051 | T_EXPECT_GE_ULLONG((p_task_info_new->pti_virtual_size - p_task_info->pti_virtual_size), (unsigned long long)PAGE_SIZE, | |
0a7de745 | 1052 | "PROC_PIDTASKINFO returned valid value for pti_virtual_size"); |
a39ff7e2 | 1053 | T_EXPECT_GE_ULLONG((p_task_info_new->pti_resident_size - p_task_info->pti_resident_size), (unsigned long long)PAGE_SIZE, |
0a7de745 | 1054 | "PROC_PIDTASKINFO returned valid value for pti_virtual_size"); |
a39ff7e2 A |
1055 | T_EXPECT_EQ_INT(p_task_info_new->pti_policy, POLICY_TIMESHARE, "PROC_PIDTASKINFO returned valid value for pti_virtual_size"); |
1056 | T_EXPECT_GE_ULLONG(p_task_info->pti_threads_user, 1ULL, "PROC_PIDTASKINFO returned valid value for pti_threads_user"); | |
1057 | #if defined(__arm__) || defined(__arm64__) | |
1058 | T_EXPECT_GE_ULLONG(p_task_info->pti_threads_system, 0ULL, "PROC_PIDTASKINFO returned valid value for pti_threads_system"); | |
1059 | T_EXPECT_GE_ULLONG((p_task_info_new->pti_total_system - p_task_info->pti_total_system), 0ULL, | |
0a7de745 | 1060 | "PROC_PIDTASKINFO returned valid value for pti_total_system"); |
a39ff7e2 A |
1061 | #else |
1062 | T_EXPECT_GE_ULLONG(p_task_info->pti_threads_system, 1ULL, "PROC_PIDTASKINFO returned valid value for pti_threads_system"); | |
1063 | T_EXPECT_GT_ULLONG((p_task_info_new->pti_total_system - p_task_info->pti_total_system), 0ULL, | |
0a7de745 | 1064 | "PROC_PIDTASKINFO returned valid value for pti_total_system"); |
a39ff7e2 A |
1065 | #endif |
1066 | T_EXPECT_GT_ULLONG((p_task_info_new->pti_total_user - p_task_info->pti_total_user), 0ULL, | |
0a7de745 | 1067 | "PROC_PIDTASKINFO returned valid value for pti_total_user"); |
a39ff7e2 | 1068 | T_EXPECT_GE_INT((p_task_info_new->pti_faults - p_task_info->pti_faults), 1, |
0a7de745 | 1069 | "PROC_PIDTASKINFO returned valid value for pti_faults"); |
a39ff7e2 | 1070 | T_EXPECT_GE_INT((p_task_info_new->pti_cow_faults - p_task_info->pti_cow_faults), 1, |
0a7de745 | 1071 | "PROC_PIDTASKINFO returned valid value for pti_cow_faults"); |
a39ff7e2 | 1072 | T_EXPECT_GE_INT((p_task_info_new->pti_syscalls_mach - p_task_info->pti_syscalls_mach), 0, |
0a7de745 | 1073 | "PROC_PIDTASKINFO returned valid value for pti_syscalls_mach"); |
a39ff7e2 | 1074 | T_EXPECT_GE_INT((p_task_info_new->pti_syscalls_unix - p_task_info->pti_syscalls_unix), 2, |
0a7de745 | 1075 | "PROC_PIDTASKINFO returned valid value for pti_syscalls_unix"); |
a39ff7e2 | 1076 | T_EXPECT_EQ_INT((p_task_info_new->pti_messages_sent - p_task_info->pti_messages_sent), 0, |
0a7de745 | 1077 | "PROC_PIDTASKINFO returned valid value for pti_messages_sent"); |
a39ff7e2 | 1078 | T_EXPECT_EQ_INT((p_task_info_new->pti_messages_received - p_task_info->pti_messages_received), 0, |
0a7de745 | 1079 | "PROC_PIDTASKINFO returned valid value for pti_messages_received"); |
a39ff7e2 | 1080 | T_EXPECT_EQ_INT(p_task_info_new->pti_priority, p_task_info->pti_priority, |
0a7de745 | 1081 | "PROC_PIDTASKINFO returned valid value for pti_priority"); |
a39ff7e2 A |
1082 | T_EXPECT_GE_INT(p_task_info_new->pti_threadnum, 1, "PROC_PIDTASKINFO returned valid value for pti_threadnum"); |
1083 | ||
1084 | if (p_task_info_new->pti_threadnum > 1) { | |
1085 | T_LOG("WARN: PROC_PIDTASKINFO returned threadnum greater than 1"); | |
1086 | } | |
1087 | T_EXPECT_GE_INT(p_task_info_new->pti_numrunning, 0, "PROC_PIDTASKINFO returned valid value for pti_numrunning"); | |
1088 | T_EXPECT_GE_INT(p_task_info_new->pti_pageins, 0, "PROC_PIDTASKINFO returned valid value for pti_pageins"); | |
1089 | ||
1090 | if (p_task_info_new->pti_pageins > 0) { | |
1091 | T_LOG("WARN: PROC_PIDTASKINFO returned pageins greater than 0"); | |
1092 | } | |
1093 | ||
1094 | T_EXPECT_GE_INT(p_task_info_new->pti_csw, p_task_info->pti_csw, "PROC_PIDTASKINFO returned valid value for pti_csw"); | |
1095 | ||
1096 | free_proc_info(proc_info, 2); | |
1097 | } | |
1098 | ||
1099 | T_DECL(proc_info_proc_pidtaskallinfo, | |
0a7de745 | 1100 | "Test to verify PROC_PIDTASKALLINFO returns valid information about the process", |
cb323159 | 1101 | T_META_ASROOT(true)) |
a39ff7e2 A |
1102 | { |
1103 | void * proc_info[4]; | |
1104 | int child_pid = 0; | |
1105 | proc_info_caller(PBSD | PBSD_OLD | P_TASK_INFO | PALL, proc_info, &child_pid); | |
1106 | struct proc_bsdinfo * pbsd = (struct proc_bsdinfo *)proc_info[0]; | |
1107 | struct proc_bsdinfo * pbsd_old = (struct proc_bsdinfo *)proc_info[1]; | |
1108 | struct proc_taskinfo * p_task_info = (struct proc_taskinfo *)proc_info[2]; | |
1109 | struct proc_taskallinfo * pall = (struct proc_taskallinfo *)proc_info[3]; | |
1110 | ||
1111 | T_EXPECT_EQ_UINT((unsigned int)SRUN, pbsd->pbi_status, "PROC_PIDTASKALLINFO shows Correct status"); | |
1112 | T_EXPECT_EQ_UINT(0U, pbsd->pbi_xstatus, "PROC_PIDTASKALLINFO show Correct xstatus"); | |
1113 | T_EXPECT_EQ_UINT(pall->pbsd.pbi_pid, (unsigned int)child_pid, "PROC_PIDTASKALLINFO returns valid pid"); | |
1114 | T_EXPECT_EQ_UINT(pall->pbsd.pbi_ppid, (unsigned int)getpid(), "PROC_PIDTASKALLINFO returns valid ppid"); | |
1115 | T_EXPECT_EQ_UINT(pall->pbsd.pbi_uid, CONF_RUID_VAL, "PROC_PIDTASKALLINFO returns valid uid"); | |
1116 | T_EXPECT_EQ_UINT(pall->pbsd.pbi_gid, CONF_GID_VAL, "PROC_PIDTASKALLINFO returns valid gid"); | |
1117 | T_EXPECT_EQ_UINT(pall->pbsd.pbi_ruid, 0U, "PROC_PIDTASKALLINFO returns valid ruid"); | |
1118 | T_EXPECT_EQ_UINT(pall->pbsd.pbi_rgid, CONF_GID_VAL, "PROC_PIDTASKALLINFO returns valid rgid"); | |
1119 | T_EXPECT_EQ_UINT(pall->pbsd.pbi_svuid, CONF_RUID_VAL, "PROC_PIDTASKALLINFO returns valid svuid"); | |
1120 | T_EXPECT_EQ_UINT(pall->pbsd.pbi_svgid, CONF_GID_VAL, "PROC_PIDTASKALLINFO returns valid svgid"); | |
1121 | T_EXPECT_EQ_INT(pall->pbsd.pbi_nice, CONF_NICE_VAL, "PROC_PIDTASKALLINFO returns valid nice value"); | |
1122 | T_EXPECT_EQ_STR(pall->pbsd.pbi_comm, CONF_CMD_NAME, "PROC_PIDTASKALLINFO returns valid p_comm name"); | |
1123 | T_EXPECT_EQ_STR(pall->pbsd.pbi_name, CONF_CMD_NAME, "PROC_PIDTASKALLINFO returns valid p_name name"); | |
1124 | T_EXPECT_EQ_UINT(pall->pbsd.pbi_flags, (pbsd_old->pbi_flags | PROC_FLAG_PSUGID), "PROC_PIDTASKALLINFO returns valid flags"); | |
1125 | T_EXPECT_EQ_UINT(pall->pbsd.pbi_nfiles, pbsd_old->pbi_nfiles, "PROC_PIDTASKALLINFO returned valid pbi_nfiles"); | |
1126 | T_EXPECT_EQ_UINT(pall->pbsd.pbi_pgid, (uint32_t)getpgid(getpid()), "PROC_PIDTASKALLINFO returned valid pbi_pgid"); | |
1127 | T_EXPECT_EQ_UINT(pall->pbsd.pbi_pjobc, pbsd->pbi_pjobc, "PROC_PIDTASKALLINFO returned valid pbi_pjobc"); | |
1128 | T_EXPECT_NE_UINT(pall->pbsd.e_tdev, 0U, "PROC_PIDTASKALLINFO returned valid e_tdev"); | |
1129 | ||
1130 | #if defined(__arm__) || defined(__arm64__) | |
1131 | T_EXPECT_GE_ULLONG(pall->ptinfo.pti_threads_system, 0ULL, "PROC_PIDTASKALLINFO returned valid value for pti_threads_system"); | |
1132 | T_EXPECT_GE_ULLONG((pall->ptinfo.pti_total_system - p_task_info->pti_total_system), 0ULL, | |
0a7de745 | 1133 | "PROC_PIDTASKALLINFO returned valid value for pti_total_system"); |
a39ff7e2 A |
1134 | #else |
1135 | T_EXPECT_GE_ULLONG(pall->ptinfo.pti_threads_system, 1ULL, "PROC_PIDTASKALLINFO returned valid value for pti_threads_system"); | |
1136 | T_EXPECT_GT_ULLONG((pall->ptinfo.pti_total_system - p_task_info->pti_total_system), 0ULL, | |
0a7de745 | 1137 | "PROC_PIDTASKALLINFO returned valid value for pti_total_system"); |
a39ff7e2 A |
1138 | #endif /* ARM */ |
1139 | ||
1140 | T_EXPECT_GE_ULLONG((pall->ptinfo.pti_virtual_size - p_task_info->pti_virtual_size), (unsigned long long)PAGE_SIZE, | |
0a7de745 | 1141 | "PROC_PIDTASKALLINFO returned valid value for pti_virtual_size"); |
a39ff7e2 | 1142 | T_EXPECT_GE_ULLONG((pall->ptinfo.pti_resident_size - p_task_info->pti_resident_size), (unsigned long long)PAGE_SIZE, |
0a7de745 | 1143 | "PROC_PIDTASKALLINFO returned valid value for pti_virtual_size"); |
a39ff7e2 A |
1144 | T_EXPECT_EQ_INT(pall->ptinfo.pti_policy, POLICY_TIMESHARE, "PROC_PIDTASKALLINFO returned valid value for pti_virtual_size"); |
1145 | T_EXPECT_GE_ULLONG(pall->ptinfo.pti_threads_user, 1ULL, "PROC_PIDTASKALLINFO returned valid value for pti_threads_user "); | |
1146 | T_EXPECT_GT_ULLONG((pall->ptinfo.pti_total_user - p_task_info->pti_total_user), 0ULL, | |
0a7de745 | 1147 | "PROC_PIDTASKALLINFO returned valid value for pti_total_user"); |
a39ff7e2 | 1148 | T_EXPECT_GE_INT((pall->ptinfo.pti_faults - p_task_info->pti_faults), 1, |
0a7de745 | 1149 | "PROC_PIDTASKALLINFO returned valid value for pti_faults"); |
a39ff7e2 | 1150 | T_EXPECT_GE_INT((pall->ptinfo.pti_cow_faults - p_task_info->pti_cow_faults), 1, |
0a7de745 | 1151 | "PROC_PIDTASKALLINFO returned valid value for pti_cow_faults"); |
a39ff7e2 | 1152 | T_EXPECT_GE_INT((pall->ptinfo.pti_syscalls_mach - p_task_info->pti_syscalls_mach), 0, |
0a7de745 | 1153 | "PROC_PIDTASKALLINFO returned valid value for pti_syscalls_mach"); |
a39ff7e2 | 1154 | T_EXPECT_GE_INT((pall->ptinfo.pti_syscalls_unix - p_task_info->pti_syscalls_unix), 2, |
0a7de745 | 1155 | "PROC_PIDTASKALLINFO returned valid value for pti_syscalls_unix"); |
a39ff7e2 | 1156 | T_EXPECT_EQ_INT((pall->ptinfo.pti_messages_sent - p_task_info->pti_messages_sent), 0, |
0a7de745 | 1157 | "PROC_PIDTASKALLINFO returned valid value for pti_messages_sent"); |
a39ff7e2 | 1158 | T_EXPECT_EQ_INT((pall->ptinfo.pti_messages_received - p_task_info->pti_messages_received), 0, |
0a7de745 | 1159 | "PROC_PIDTASKALLINFO returned valid value for pti_messages_received"); |
a39ff7e2 | 1160 | T_EXPECT_EQ_INT(pall->ptinfo.pti_priority, p_task_info->pti_priority, |
0a7de745 | 1161 | "PROC_PIDTASKALLINFO returned valid value for pti_priority"); |
a39ff7e2 A |
1162 | T_EXPECT_GE_INT(pall->ptinfo.pti_threadnum, 1, "PROC_PIDTASKALLINFO returned valid value for pti_threadnum"); |
1163 | if (pall->ptinfo.pti_threadnum > 1) { | |
1164 | T_LOG("WARN: PROC_PIDTASKALLINFO returned threadnum greater than 1"); | |
1165 | } | |
1166 | T_EXPECT_GE_INT(pall->ptinfo.pti_numrunning, 0, "PROC_PIDTASKALLINFO returned valid value for pti_numrunning"); | |
1167 | T_EXPECT_GE_INT(pall->ptinfo.pti_pageins, 0, "PROC_PIDTASKALLINFO returned valid value for pti_pageins"); | |
1168 | if (pall->ptinfo.pti_pageins > 0) { | |
1169 | T_LOG("WARN: PROC_PIDTASKALLINFO returned pageins greater than 0"); | |
1170 | } | |
1171 | T_EXPECT_GE_INT(pall->ptinfo.pti_csw, p_task_info->pti_csw, "PROC_PIDTASKALLINFO returned valid value for pti_csw"); | |
1172 | ||
1173 | free_proc_info(proc_info, 4); | |
1174 | } | |
1175 | ||
1176 | T_DECL(proc_info_proc_pidlistthreads, | |
0a7de745 | 1177 | "Test to verify PROC_PIDLISTTHREADS returns valid information about process", |
cb323159 | 1178 | T_META_ASROOT(true)) |
a39ff7e2 A |
1179 | { |
1180 | void * proc_info[1]; | |
1181 | proc_info_caller(THREAD_ADDR, proc_info, NULL); | |
1182 | } | |
1183 | ||
1184 | T_DECL(proc_info_proc_pidthreadinfo, | |
0a7de745 | 1185 | "Test to verify PROC_PIDTHREADINFO returns valid information about the process", |
cb323159 | 1186 | T_META_ASROOT(true)) |
a39ff7e2 A |
1187 | { |
1188 | void * proc_info[2]; | |
1189 | int child_pid = 0; | |
1190 | proc_info_caller(PTHINFO_OLD | PTHINFO, proc_info, &child_pid); | |
1191 | struct proc_threadinfo * pthinfo_old = (struct proc_threadinfo *)proc_info[0]; | |
1192 | struct proc_threadinfo * pthinfo = (struct proc_threadinfo *)proc_info[1]; | |
1193 | ||
1194 | T_EXPECT_GT_ULLONG((pthinfo->pth_user_time - pthinfo_old->pth_user_time), 0ULL, | |
0a7de745 | 1195 | "PROC_PIDTHREADINFO returns valid value for pth_user_time"); |
a39ff7e2 | 1196 | T_EXPECT_GE_ULLONG((pthinfo->pth_system_time - pthinfo_old->pth_system_time), 0ULL, |
0a7de745 | 1197 | "PROC_PIDTHREADINFO returns valid value for pth_system_time"); |
a39ff7e2 A |
1198 | /* |
1199 | * This is the scaled cpu usage percentage, since we are not | |
1200 | * doing a really long CPU bound task, it is (nearly) zero | |
1201 | */ | |
1202 | T_EXPECT_GE_INT(pthinfo->pth_cpu_usage, 0, "PROC_PIDTHREADINFO returns valid value for pth_cpu_usage"); | |
1203 | T_EXPECT_EQ_INT(pthinfo->pth_policy, POLICY_TIMESHARE, "PROC_PIDTHREADINFO returns valid value for pth_policy"); | |
1204 | if (!(pthinfo->pth_run_state == TH_STATE_WAITING) && !(pthinfo->pth_run_state == TH_STATE_RUNNING)) { | |
1205 | T_EXPECT_EQ_INT(pthinfo->pth_run_state, -1, "PROC_PIDTHREADINFO returns valid value for pth_run_state"); | |
1206 | } | |
1207 | /* | |
1208 | * This value is hardcoded to 0 in the source, hence it will always | |
1209 | * unconditionally return 0 | |
1210 | */ | |
1211 | T_EXPECT_EQ_INT(pthinfo->pth_sleep_time, 0, "PROC_PIDTHREADINFO returns valid value for pth_sleep_time"); | |
1212 | T_EXPECT_LE_INT(pthinfo->pth_curpri, (BASEPRI_DEFAULT - CONF_NICE_VAL), | |
0a7de745 | 1213 | "PROC_PIDTHREADINFO returns valid value for pth_curpri"); |
a39ff7e2 | 1214 | T_EXPECT_EQ_INT(pthinfo->pth_priority, (BASEPRI_DEFAULT - CONF_NICE_VAL), |
0a7de745 | 1215 | "PROC_PIDTHREADINFO returns valid value for pth_priority"); |
a39ff7e2 A |
1216 | T_EXPECT_EQ_INT(pthinfo->pth_maxpriority, MAXPRI_USER, "PROC_PIDTHREADINFO returns valid value for pth_maxpriority"); |
1217 | T_EXPECT_EQ_STR(pthinfo->pth_name, CONF_THREAD_NAME, "PROC_PIDTHREADINFO returns valid value for pth_name"); | |
1218 | ||
1219 | free_proc_info(proc_info, 2); | |
1220 | } | |
1221 | ||
1222 | T_DECL(proc_info_proc_threadid64info, | |
0a7de745 | 1223 | "Test to verify PROC_PIDTHREADID64INFO returns valid information about the process", |
cb323159 | 1224 | T_META_ASROOT(true)) |
a39ff7e2 A |
1225 | { |
1226 | void * proc_info[2]; | |
1227 | proc_info_caller(PTHINFO | PTHINFO_64, proc_info, NULL); | |
1228 | struct proc_threadinfo pthinfo = *((struct proc_threadinfo *)proc_info[0]); | |
1229 | struct proc_threadinfo pthinfo_64 = *((struct proc_threadinfo *)proc_info[1]); | |
1230 | T_EXPECT_GE_ULLONG(pthinfo_64.pth_user_time, pthinfo.pth_user_time, | |
0a7de745 | 1231 | "PROC_PIDTHREADID64INFO returns valid value for pth_user_time"); |
a39ff7e2 | 1232 | T_EXPECT_GE_ULLONG(pthinfo_64.pth_system_time, pthinfo.pth_system_time, |
0a7de745 | 1233 | "PROC_PIDTHREADID64INFO returns valid value for pth_system_time"); |
a39ff7e2 | 1234 | T_EXPECT_GE_INT(pthinfo_64.pth_cpu_usage, pthinfo.pth_cpu_usage, |
0a7de745 | 1235 | "PROC_PIDTHREADID64INFO returns valid value for pth_cpu_usage"); |
a39ff7e2 A |
1236 | T_EXPECT_EQ_INT(pthinfo_64.pth_policy, POLICY_TIMESHARE, "PROC_PIDTHREADID64INFO returns valid value for pth_policy"); |
1237 | if (!(pthinfo_64.pth_run_state == TH_STATE_WAITING) && !(pthinfo_64.pth_run_state == TH_STATE_RUNNING)) { | |
1238 | T_EXPECT_EQ_INT(pthinfo_64.pth_run_state, -1, "PROC_PIDTHREADID64INFO returns valid value for pth_run_state"); | |
1239 | } | |
1240 | T_EXPECT_EQ_INT(pthinfo_64.pth_sleep_time, 0, "PROC_PIDTHREADID64INFO returns valid value for pth_sleep_time"); | |
1241 | T_EXPECT_EQ_INT(pthinfo_64.pth_curpri, pthinfo.pth_curpri, "PROC_PIDTHREADID64INFO returns valid value for pth_curpri"); | |
1242 | T_EXPECT_EQ_INT(pthinfo_64.pth_priority, pthinfo.pth_priority, "PROC_PIDTHREADID64INFO returns valid value for pth_priority"); | |
1243 | T_EXPECT_EQ_INT(pthinfo_64.pth_maxpriority, pthinfo.pth_maxpriority, | |
0a7de745 | 1244 | "PROC_PIDTHREADID64INFO returns valid value for pth_maxpriority"); |
a39ff7e2 A |
1245 | T_EXPECT_EQ_STR(pthinfo_64.pth_name, CONF_THREAD_NAME, "PROC_PIDTHREADID64INFO returns valid value for pth_name"); |
1246 | ||
1247 | free_proc_info(proc_info, 2); | |
1248 | } | |
1249 | ||
1250 | T_DECL(proc_info_proc_pidthreadpathinfo, | |
0a7de745 | 1251 | "Test to verify PROC_PIDTHREADPATHINFO returns valid information about the process", |
cb323159 | 1252 | T_META_ASROOT(true)) |
a39ff7e2 A |
1253 | { |
1254 | void * proc_info[2]; | |
1255 | proc_info_caller(PTHINFO | PINFO_PATH, proc_info, NULL); | |
1256 | struct proc_threadinfo pthinfo = *((struct proc_threadinfo *)proc_info[0]); | |
1257 | struct proc_threadwithpathinfo pinfo_path = *((struct proc_threadwithpathinfo *)proc_info[1]); | |
1258 | ||
1259 | T_EXPECT_GE_ULLONG(pinfo_path.pt.pth_user_time, pthinfo.pth_user_time, | |
0a7de745 | 1260 | "PROC_PIDTHREADPATHINFO returns valid value for pth_user_time"); |
a39ff7e2 | 1261 | T_EXPECT_GE_ULLONG(pinfo_path.pt.pth_system_time, pthinfo.pth_system_time, |
0a7de745 | 1262 | "PROC_PIDTHREADPATHINFO returns valid value for pth_system_time"); |
a39ff7e2 | 1263 | T_EXPECT_GE_INT(pinfo_path.pt.pth_cpu_usage, pthinfo.pth_cpu_usage, |
0a7de745 | 1264 | "PROC_PIDTHREADPATHINFO returns valid value for pth_cpu_usage"); |
a39ff7e2 A |
1265 | T_EXPECT_EQ_INT(pinfo_path.pt.pth_policy, POLICY_TIMESHARE, "PROC_PIDTHREADPATHINFO returns valid value for pth_policy"); |
1266 | if (!(pinfo_path.pt.pth_run_state == TH_STATE_WAITING) && !(pinfo_path.pt.pth_run_state == TH_STATE_RUNNING)) { | |
1267 | T_EXPECT_EQ_INT(pinfo_path.pt.pth_run_state, -1, "PROC_PIDTHREADPATHINFO returns valid value for pth_run_state"); | |
1268 | } | |
1269 | T_EXPECT_EQ_INT(pinfo_path.pt.pth_sleep_time, 0, "PROC_PIDTHREADPATHINFO returns valid value for pth_sleep_time"); | |
1270 | T_EXPECT_EQ_INT(pinfo_path.pt.pth_curpri, pthinfo.pth_curpri, "PROC_PIDTHREADPATHINFO returns valid value for pth_curpri"); | |
1271 | T_EXPECT_EQ_INT(pinfo_path.pt.pth_priority, pthinfo.pth_priority, | |
0a7de745 | 1272 | "PROC_PIDTHREADPATHINFO returns valid value for pth_priority"); |
a39ff7e2 | 1273 | T_EXPECT_EQ_INT(pinfo_path.pt.pth_maxpriority, pthinfo.pth_maxpriority, |
0a7de745 | 1274 | "PROC_PIDTHREADPATHINFO returns valid value for pth_maxpriority"); |
a39ff7e2 A |
1275 | T_EXPECT_EQ_STR(pinfo_path.pt.pth_name, CONF_THREAD_NAME, "PROC_PIDTHREADPATHINFO returns valid value for pth_name"); |
1276 | T_EXPECT_EQ_INT(pinfo_path.pvip.vip_vi.vi_type, VNON, "PROC_PIDTHREADPATHINFO valid vnode information"); | |
1277 | ||
1278 | free_proc_info(proc_info, 2); | |
1279 | } | |
1280 | ||
1281 | T_DECL(proc_info_proc_pidarchinfo, | |
0a7de745 | 1282 | "Test to verify PROC_PIDARCHINFO returns valid information about the process", |
cb323159 | 1283 | T_META_ASROOT(true)) |
a39ff7e2 A |
1284 | { |
1285 | void * proc_info[1]; | |
1286 | proc_info_caller(PAI, proc_info, NULL); | |
1287 | struct proc_archinfo pai = *((struct proc_archinfo *)proc_info[0]); | |
1288 | ||
1289 | #if defined(__arm__) || defined(__arm64__) | |
1290 | if (!((pai.p_cputype & CPU_TYPE_ARM) == CPU_TYPE_ARM) && !((pai.p_cputype & CPU_TYPE_ARM64) == CPU_TYPE_ARM64)) { | |
1291 | T_EXPECT_EQ_INT(pai.p_cputype, CPU_TYPE_ARM, "PROC_PIDARCHINFO returned valid value for p_cputype"); | |
1292 | } | |
1293 | T_EXPECT_EQ_INT((pai.p_cpusubtype & CPU_SUBTYPE_ARM_ALL), CPU_SUBTYPE_ARM_ALL, | |
0a7de745 | 1294 | "PROC_PIDARCHINFO returned valid value for p_cpusubtype"); |
a39ff7e2 A |
1295 | #else |
1296 | if (!((pai.p_cputype & CPU_TYPE_X86) == CPU_TYPE_X86) && !((pai.p_cputype & CPU_TYPE_X86_64) == CPU_TYPE_X86_64)) { | |
1297 | T_EXPECT_EQ_INT(pai.p_cputype, CPU_TYPE_X86, "PROC_PIDARCHINFO returned valid value for p_cputype"); | |
1298 | } | |
1299 | #endif | |
1300 | free_proc_info(proc_info, 1); | |
1301 | } | |
1302 | ||
1303 | T_DECL(proc_info_proc_pidregioninfo, | |
0a7de745 | 1304 | "Test to verify PROC_PIDREGIONINFO returns valid information about the process", |
cb323159 | 1305 | T_META_ASROOT(true)) |
a39ff7e2 | 1306 | { |
d9a64523 | 1307 | void * proc_info[3]; |
a39ff7e2 A |
1308 | proc_info_caller(PREGINFO, proc_info, NULL); |
1309 | ||
1310 | struct proc_regioninfo preginfo = *((struct proc_regioninfo *)proc_info[0]); | |
1311 | /* | |
1312 | * map_tmp isn't a struct like the rest of our ret_structs, but we sneak it back because we need it | |
1313 | */ | |
d9a64523 A |
1314 | void *map_tmp = proc_info[1]; |
1315 | vm_map_size_t map_tmp_sz = (vm_map_size_t)(uintptr_t)proc_info[2]; | |
a39ff7e2 A |
1316 | |
1317 | T_EXPECT_EQ_ULLONG(preginfo.pri_offset, (unsigned long long)PAGE_SIZE, "PROC_PIDREGIONINFO returns valid value for pri_offset"); | |
1318 | T_EXPECT_EQ_UINT((preginfo.pri_protection ^ (VM_PROT_READ | VM_PROT_WRITE)), 0U, | |
0a7de745 | 1319 | "PROC_PIDREGIONINFO returns valid value for pri_protection, expected read/write only"); |
a39ff7e2 | 1320 | T_EXPECT_EQ_UINT((preginfo.pri_max_protection & (VM_PROT_READ | VM_PROT_WRITE)), (unsigned int)(VM_PROT_READ | VM_PROT_WRITE), |
0a7de745 | 1321 | "PROC_PIDREGIONINFO returns valid value for pri_max_protection"); |
a39ff7e2 | 1322 | T_EXPECT_EQ_UINT((preginfo.pri_inheritance ^ VM_INHERIT_COPY), 0U, |
0a7de745 | 1323 | "PROC_PIDREGIONINFO returns valid value for pri_inheritance"); |
a39ff7e2 A |
1324 | T_EXPECT_EQ_UINT((preginfo.pri_behavior ^ VM_BEHAVIOR_DEFAULT), 0U, "PROC_PIDREGIONINFO returns valid value for pri_behavior"); |
1325 | T_EXPECT_EQ_UINT(preginfo.pri_user_wired_count, 0U, "PROC_PIDREGIONINFO returns valid value for pri_user_wired_count"); | |
1326 | T_EXPECT_EQ_UINT(preginfo.pri_user_tag, 0U, "PROC_PIDREGIONINFO returns valid value for pri_user_tag"); | |
1327 | T_EXPECT_NE_UINT((preginfo.pri_flags ^ (PROC_REGION_SUBMAP | PROC_REGION_SHARED)), 0U, | |
0a7de745 | 1328 | "PROC_PIDREGIONINFO returns valid value for pri_flags"); |
a39ff7e2 A |
1329 | T_EXPECT_EQ_UINT(preginfo.pri_pages_resident, 0U, "PROC_PIDREGIONINFO returns valid value for pri_pages_resident"); |
1330 | T_EXPECT_EQ_UINT(preginfo.pri_pages_shared_now_private, 0U, | |
0a7de745 | 1331 | "PROC_PIDREGIONINFO returns valid value for pri_pages_shared_now_private"); |
a39ff7e2 A |
1332 | T_EXPECT_EQ_UINT(preginfo.pri_pages_swapped_out, 0U, "PROC_PIDREGIONINFO returns valid value for pri_pages_swapped_out"); |
1333 | T_EXPECT_EQ_UINT(preginfo.pri_pages_dirtied, 0U, "PROC_PIDREGIONINFO returns valid value for pri_pages_dirtied"); | |
1334 | T_EXPECT_EQ_UINT(preginfo.pri_ref_count, 2U, "PROC_PIDREGIONINFO returns valid value for pri_ref_count"); | |
1335 | T_EXPECT_EQ_UINT(preginfo.pri_shadow_depth, 1U, "PROC_PIDREGIONINFO returns valid value for pri_shadow_depth"); | |
1336 | T_EXPECT_EQ_UINT(preginfo.pri_share_mode, (unsigned int)SM_COW, "PROC_PIDREGIONINFO returns valid value for pri_share_mode"); | |
1337 | T_EXPECT_EQ_UINT(preginfo.pri_private_pages_resident, 0U, | |
0a7de745 | 1338 | "PROC_PIDREGIONINFO returns valid value for pri_private_pages_resident"); |
d9a64523 | 1339 | T_EXPECT_GE_UINT(preginfo.pri_shared_pages_resident, 0U, |
0a7de745 | 1340 | "PROC_PIDREGIONINFO returns valid value for pri_shared_pages_resident"); |
a39ff7e2 A |
1341 | T_EXPECT_EQ_ULLONG(preginfo.pri_address, (uint64_t)map_tmp, "PROC_PIDREGIONINFO returns valid value for pri_addr"); |
1342 | T_EXPECT_NE_UINT(preginfo.pri_obj_id, 0U, "PROC_PIDREGIONINFO returns valid value for pri_obj_id"); | |
d9a64523 | 1343 | T_EXPECT_EQ_ULLONG(preginfo.pri_size, (unsigned long long)map_tmp_sz, "PROC_PIDREGIONINFO returns valid value for pri_size"); |
a39ff7e2 A |
1344 | T_EXPECT_EQ_UINT(preginfo.pri_depth, 0U, "PROC_PIDREGIONINFO returns valid value for pri_depth"); |
1345 | ||
1346 | int ret = 0; | |
d9a64523 | 1347 | ret = munmap(map_tmp, (size_t)map_tmp_sz); |
a39ff7e2 A |
1348 | T_QUIET; |
1349 | T_EXPECT_POSIX_SUCCESS(ret, "munmap of map_tmp"); | |
1350 | free_proc_info(proc_info, 1); | |
1351 | } | |
1352 | ||
1353 | T_DECL(proc_info_proc_pidregionpathinfo, | |
0a7de745 | 1354 | "Test to verify PROC_PIDREGIONPATHINFO returns valid information about the process", |
cb323159 | 1355 | T_META_ASROOT(true)) |
a39ff7e2 | 1356 | { |
d9a64523 | 1357 | void * proc_info[3]; |
a39ff7e2 A |
1358 | proc_info_caller(PREGINFO_PATH, proc_info, NULL); |
1359 | ||
1360 | struct proc_regionwithpathinfo preginfo_path = *((struct proc_regionwithpathinfo *)proc_info[0]); | |
1361 | /* | |
1362 | * map_tmp isn't a struct like the rest of our ret_structs, but we sneak it back because we need it | |
0a7de745 | 1363 | */ |
d9a64523 A |
1364 | void *map_tmp = proc_info[1]; |
1365 | vm_map_size_t map_tmp_sz = (vm_map_size_t)(uintptr_t)proc_info[2]; | |
a39ff7e2 A |
1366 | |
1367 | T_EXPECT_EQ_ULLONG(preginfo_path.prp_prinfo.pri_offset, (uint64_t)PAGE_SIZE, | |
0a7de745 | 1368 | "PROC_PIDREGIONPATHINFO returns valid value for pri_offset"); |
a39ff7e2 | 1369 | T_EXPECT_EQ_UINT((preginfo_path.prp_prinfo.pri_protection ^ (VM_PROT_READ | VM_PROT_WRITE)), 0U, |
0a7de745 | 1370 | "PROC_PIDREGIONPATHINFO returns valid value for pri_protection, expected read/write only"); |
a39ff7e2 | 1371 | T_EXPECT_EQ_UINT((preginfo_path.prp_prinfo.pri_max_protection & (VM_PROT_READ | VM_PROT_WRITE)), |
0a7de745 A |
1372 | (unsigned int)(VM_PROT_READ | VM_PROT_WRITE), |
1373 | "PROC_PIDREGIONPATHINFO returns valid value for pri_max_protection"); | |
a39ff7e2 | 1374 | T_EXPECT_EQ_UINT((preginfo_path.prp_prinfo.pri_inheritance ^ VM_INHERIT_COPY), 0U, |
0a7de745 | 1375 | "PROC_PIDREGIONPATHINFO returns valid value for pri_inheritance"); |
a39ff7e2 | 1376 | T_EXPECT_EQ_UINT((preginfo_path.prp_prinfo.pri_behavior ^ VM_BEHAVIOR_DEFAULT), 0U, |
0a7de745 | 1377 | "PROC_PIDREGIONPATHINFO returns valid value for pri_behavior"); |
a39ff7e2 | 1378 | T_EXPECT_EQ_UINT(preginfo_path.prp_prinfo.pri_user_wired_count, 0U, |
0a7de745 | 1379 | "PROC_PIDREGIONPATHINFO returns valid value for pri_user_wired_count"); |
a39ff7e2 A |
1380 | T_EXPECT_EQ_UINT(preginfo_path.prp_prinfo.pri_user_tag, 0U, "PROC_PIDREGIONPATHINFO returns valid value for pri_user_tag"); |
1381 | T_EXPECT_NE_UINT((preginfo_path.prp_prinfo.pri_flags ^ (PROC_REGION_SUBMAP | PROC_REGION_SHARED)), 0U, | |
0a7de745 | 1382 | "PROC_PIDREGIONPATHINFO returns valid value for pri_flags"); |
a39ff7e2 | 1383 | T_EXPECT_EQ_UINT(preginfo_path.prp_prinfo.pri_pages_resident, 0U, |
0a7de745 | 1384 | "PROC_PIDREGIONPATHINFO returns valid value for pri_pages_resident"); |
a39ff7e2 | 1385 | T_EXPECT_EQ_UINT(preginfo_path.prp_prinfo.pri_pages_shared_now_private, 0U, |
0a7de745 | 1386 | "PROC_PIDREGIONPATHINFO returns valid value for pri_pages_shared_now_private"); |
a39ff7e2 | 1387 | T_EXPECT_EQ_UINT(preginfo_path.prp_prinfo.pri_pages_swapped_out, 0U, |
0a7de745 | 1388 | "PROC_PIDREGIONPATHINFO returns valid value for pri_pages_swapped_out"); |
a39ff7e2 | 1389 | T_EXPECT_EQ_UINT(preginfo_path.prp_prinfo.pri_pages_dirtied, 0U, |
0a7de745 | 1390 | "PROC_PIDREGIONPATHINFO returns valid value for pri_pages_dirtied"); |
a39ff7e2 A |
1391 | T_EXPECT_EQ_UINT(preginfo_path.prp_prinfo.pri_ref_count, 2U, "PROC_PIDREGIONPATHINFO returns valid value for pri_ref_count"); |
1392 | T_EXPECT_EQ_UINT(preginfo_path.prp_prinfo.pri_shadow_depth, 1U, | |
0a7de745 | 1393 | "PROC_PIDREGIONPATHINFO returns valid value for pri_shadow_depth"); |
a39ff7e2 | 1394 | T_EXPECT_EQ_UINT(preginfo_path.prp_prinfo.pri_share_mode, (unsigned int)SM_COW, |
0a7de745 | 1395 | "PROC_PIDREGIONPATHINFO returns valid value for pri_share_mode"); |
a39ff7e2 | 1396 | T_EXPECT_EQ_UINT(preginfo_path.prp_prinfo.pri_private_pages_resident, 0U, |
0a7de745 | 1397 | "PROC_PIDREGIONPATHINFO returns valid value for pri_private_pages_resident"); |
d9a64523 | 1398 | T_EXPECT_GE_UINT(preginfo_path.prp_prinfo.pri_shared_pages_resident, 0U, |
0a7de745 | 1399 | "PROC_PIDREGIONPATHINFO returns valid value for pri_shared_pages_resident"); |
a39ff7e2 | 1400 | T_EXPECT_EQ_ULLONG(preginfo_path.prp_prinfo.pri_address, (uint64_t)map_tmp, |
0a7de745 | 1401 | "PROC_PIDREGIONPATHINFO returns valid value for pri_addr"); |
a39ff7e2 | 1402 | T_EXPECT_NE_UINT(preginfo_path.prp_prinfo.pri_obj_id, 0U, "PROC_PIDREGIONPATHINFO returns valid value for pri_obj_id"); |
d9a64523 | 1403 | T_EXPECT_EQ_ULLONG(preginfo_path.prp_prinfo.pri_size, (uint64_t)map_tmp_sz, |
0a7de745 | 1404 | "PROC_PIDREGIONPATHINFO returns valid value for pri_size"); |
a39ff7e2 A |
1405 | T_EXPECT_EQ_UINT(preginfo_path.prp_prinfo.pri_depth, 0U, "PROC_PIDREGIONPATHINFO returns valid value for pri_depth"); |
1406 | T_EXPECT_EQ_INT(preginfo_path.prp_vip.vip_vi.vi_type, VREG, "PROC_PIDREGIONPATHINFO returns valid value for vi_type"); | |
1407 | T_EXPECT_EQ_INT(preginfo_path.prp_vip.vip_vi.vi_pad, 0, "PROC_PIDREGIONPATHINFO returns valid value for vi_pad"); | |
1408 | T_EXPECT_NE_INT(preginfo_path.prp_vip.vip_vi.vi_fsid.val[0], 0, | |
0a7de745 | 1409 | "PROC_PIDREGIONPATHINFO returns valid value for vi_fsid.val[0]"); |
a39ff7e2 | 1410 | T_EXPECT_NE_INT(preginfo_path.prp_vip.vip_vi.vi_fsid.val[1], 0, |
0a7de745 | 1411 | "PROC_PIDREGIONPATHINFO returns valid value for vi_fsid.val[1]"); |
d9a64523 | 1412 | T_EXPECT_NE_PTR((void *)(strcasestr(preginfo_path.prp_vip.vip_path, CONF_TMP_FILE_PFX)), NULL, |
0a7de745 | 1413 | "PROC_PIDREGIONPATHINFO returns valid value for vi_path"); |
a39ff7e2 A |
1414 | /* |
1415 | * Basic sanity checks for vnode stat returned by the API | |
1416 | */ | |
1417 | T_EXPECT_NE_UINT(preginfo_path.prp_vip.vip_vi.vi_stat.vst_dev, 0U, "PROC_PIDREGIONPATHINFO returns valid value for vst_dev"); | |
1418 | T_EXPECT_EQ_INT(((preginfo_path.prp_vip.vip_vi.vi_stat.vst_mode & S_IFMT) ^ S_IFREG), 0, | |
0a7de745 | 1419 | "PROC_PIDREGIONPATHINFO returns valid value for vst_mode"); |
d9a64523 | 1420 | T_EXPECT_EQ_USHORT(preginfo_path.prp_vip.vip_vi.vi_stat.vst_nlink, (unsigned short)0, /* the file was unlink()'d! */ |
0a7de745 | 1421 | "PROC_PIDREGIONPATHINFO returns valid value for vst_nlink"); |
a39ff7e2 | 1422 | T_EXPECT_NE_ULLONG(preginfo_path.prp_vip.vip_vi.vi_stat.vst_ino, 0ULL, |
0a7de745 | 1423 | "PROC_PIDREGIONPATHINFO returns valid value for vst_ino"); |
a39ff7e2 A |
1424 | T_EXPECT_EQ_UINT(preginfo_path.prp_vip.vip_vi.vi_stat.vst_uid, 0U, "PROC_PIDREGIONPATHINFO returns valid value for vst_uid"); |
1425 | T_EXPECT_EQ_UINT(preginfo_path.prp_vip.vip_vi.vi_stat.vst_gid, 0U, "PROC_PIDREGIONPATHINFO returns valid value for vst_gid"); | |
1426 | T_EXPECT_GE_LLONG(preginfo_path.prp_vip.vip_vi.vi_stat.vst_size, (off_t)CONF_BLK_SIZE, | |
0a7de745 | 1427 | "PROC_PIDREGIONPATHINFO returns valid value for vst_size"); |
a39ff7e2 | 1428 | T_EXPECT_GE_LLONG(preginfo_path.prp_vip.vip_vi.vi_stat.vst_blocks, 1LL, |
0a7de745 | 1429 | "PROC_PIDREGIONPATHINFO returns valid value for vst_blocks"); |
a39ff7e2 | 1430 | T_EXPECT_GE_INT(preginfo_path.prp_vip.vip_vi.vi_stat.vst_blksize, CONF_BLK_SIZE, |
0a7de745 | 1431 | "PROC_PIDREGIONPATHINFO returns valid value for vst_blksize"); |
a39ff7e2 A |
1432 | |
1433 | int ret = 0; | |
d9a64523 | 1434 | ret = munmap(map_tmp, (size_t)map_tmp_sz); |
a39ff7e2 A |
1435 | T_QUIET; |
1436 | T_EXPECT_POSIX_SUCCESS(ret, "munmap of map_tmp"); | |
1437 | free_proc_info(proc_info, 1); | |
1438 | } | |
1439 | ||
1440 | T_DECL(proc_info_proc_pidregionpathinfo2, | |
0a7de745 | 1441 | "Test to verify PROC_PIDREGIONPATHINFO2 returns valid information about the process", |
cb323159 | 1442 | T_META_ASROOT(true)) |
a39ff7e2 | 1443 | { |
d9a64523 | 1444 | void * proc_info[3]; |
a39ff7e2 A |
1445 | proc_info_caller(PREGINFO_PATH_2, proc_info, NULL); |
1446 | ||
1447 | struct proc_regionwithpathinfo preginfo_path = *((struct proc_regionwithpathinfo *)proc_info[0]); | |
1448 | /* | |
1449 | * map_tmp isn't a struct like the rest of our ret_structs, but we sneak it back because we need it | |
0a7de745 | 1450 | */ |
d9a64523 A |
1451 | void *map_tmp = proc_info[1]; |
1452 | vm_map_size_t map_tmp_sz = (vm_map_size_t)(uintptr_t)proc_info[2]; | |
a39ff7e2 A |
1453 | |
1454 | T_EXPECT_EQ_ULLONG(preginfo_path.prp_prinfo.pri_offset, (uint64_t)PAGE_SIZE, | |
0a7de745 | 1455 | "PROC_PIDREGIONPATHINFO2 returns valid value for pri_offset"); |
a39ff7e2 | 1456 | T_EXPECT_EQ_UINT((preginfo_path.prp_prinfo.pri_protection ^ (VM_PROT_READ | VM_PROT_WRITE)), 0U, |
0a7de745 | 1457 | "PROC_PIDREGIONPATHINFO2 returns valid value for pri_protection, expected read/write only"); |
a39ff7e2 | 1458 | T_EXPECT_EQ_UINT((preginfo_path.prp_prinfo.pri_max_protection & (VM_PROT_READ | VM_PROT_WRITE)), |
0a7de745 A |
1459 | (unsigned int)(VM_PROT_READ | VM_PROT_WRITE), |
1460 | "PROC_PIDREGIONPATHINFO2 returns valid value for pri_max_protection"); | |
a39ff7e2 | 1461 | T_EXPECT_EQ_UINT((preginfo_path.prp_prinfo.pri_inheritance ^ VM_INHERIT_COPY), 0U, |
0a7de745 | 1462 | "PROC_PIDREGIONPATHINFO2 returns valid value for pri_inheritance"); |
a39ff7e2 | 1463 | T_EXPECT_EQ_UINT((preginfo_path.prp_prinfo.pri_behavior ^ VM_BEHAVIOR_DEFAULT), 0U, |
0a7de745 | 1464 | "PROC_PIDREGIONPATHINFO2 returns valid value for pri_behavior"); |
a39ff7e2 | 1465 | T_EXPECT_EQ_UINT(preginfo_path.prp_prinfo.pri_user_wired_count, 0U, |
0a7de745 | 1466 | "PROC_PIDREGIONPATHINFO2 returns valid value for pri_user_wired_count"); |
a39ff7e2 A |
1467 | T_EXPECT_EQ_UINT(preginfo_path.prp_prinfo.pri_user_tag, 0U, "PROC_PIDREGIONPATHINFO2 returns valid value for pri_user_tag"); |
1468 | T_EXPECT_NE_UINT((preginfo_path.prp_prinfo.pri_flags ^ (PROC_REGION_SUBMAP | PROC_REGION_SHARED)), 0U, | |
0a7de745 | 1469 | "PROC_PIDREGIONPATHINFO2 returns valid value for pri_flags"); |
a39ff7e2 A |
1470 | /* |
1471 | * Following values are hard-coded to be zero in source | |
1472 | */ | |
1473 | T_EXPECT_EQ_UINT(preginfo_path.prp_prinfo.pri_pages_resident, 0U, | |
0a7de745 | 1474 | "PROC_PIDREGIONPATHINFO2 returns valid value for pri_pages_resident"); |
a39ff7e2 | 1475 | T_EXPECT_EQ_UINT(preginfo_path.prp_prinfo.pri_pages_shared_now_private, 0U, |
0a7de745 | 1476 | "PROC_PIDREGIONPATHINFO2 returns valid value for pri_pages_shared_now_private"); |
a39ff7e2 | 1477 | T_EXPECT_EQ_UINT(preginfo_path.prp_prinfo.pri_pages_swapped_out, 0U, |
0a7de745 | 1478 | "PROC_PIDREGIONPATHINFO2 returns valid value for pri_pages_swapped_out"); |
a39ff7e2 | 1479 | T_EXPECT_EQ_UINT(preginfo_path.prp_prinfo.pri_pages_dirtied, 0U, |
0a7de745 | 1480 | "PROC_PIDREGIONPATHINFO2 returns valid value for pri_pages_dirtied"); |
a39ff7e2 A |
1481 | T_EXPECT_EQ_UINT(preginfo_path.prp_prinfo.pri_ref_count, 0U, "PROC_PIDREGIONPATHINFO2 returns valid value for pri_ref_count"); |
1482 | T_EXPECT_EQ_UINT(preginfo_path.prp_prinfo.pri_shadow_depth, 0U, | |
0a7de745 | 1483 | "PROC_PIDREGIONPATHINFO2 returns valid value for pri_shadow_depth"); |
a39ff7e2 A |
1484 | T_EXPECT_EQ_UINT(preginfo_path.prp_prinfo.pri_share_mode, 0U, "PROC_PIDREGIONPATHINFO2 returns valid value for pri_share_mode"); |
1485 | T_EXPECT_EQ_UINT(preginfo_path.prp_prinfo.pri_private_pages_resident, 0U, | |
0a7de745 | 1486 | "PROC_PIDREGIONPATHINFO2 returns valid value for pri_private_pages_resident"); |
a39ff7e2 | 1487 | T_EXPECT_EQ_UINT(preginfo_path.prp_prinfo.pri_shared_pages_resident, 0U, |
0a7de745 | 1488 | "PROC_PIDREGIONPATHINFO2 returns valid value for pri_shared_pages_resident"); |
a39ff7e2 | 1489 | T_EXPECT_EQ_ULLONG(preginfo_path.prp_prinfo.pri_address, (uint64_t)map_tmp, |
0a7de745 | 1490 | "PROC_PIDREGIONPATHINFO2 returns valid value for pri_addr"); |
a39ff7e2 | 1491 | T_EXPECT_EQ_UINT(preginfo_path.prp_prinfo.pri_obj_id, 0U, "PROC_PIDREGIONPATHINFO2 returns valid value for pri_obj_id"); |
d9a64523 | 1492 | T_EXPECT_EQ_ULLONG(preginfo_path.prp_prinfo.pri_size, (unsigned long long)map_tmp_sz, |
0a7de745 | 1493 | "PROC_PIDREGIONPATHINFO2 returns valid value for pri_size"); |
a39ff7e2 A |
1494 | T_EXPECT_EQ_UINT(preginfo_path.prp_prinfo.pri_depth, 0U, "PROC_PIDREGIONPATHINFO2 returns valid value for pri_depth"); |
1495 | ||
1496 | T_EXPECT_EQ_INT(preginfo_path.prp_vip.vip_vi.vi_type, VREG, "PROC_PIDREGIONPATHINFO2 returns valid value for vi_type"); | |
1497 | T_EXPECT_EQ_INT(preginfo_path.prp_vip.vip_vi.vi_pad, 0, "PROC_PIDREGIONPATHINFO2 returns valid value for vi_pad"); | |
1498 | T_EXPECT_NE_INT(preginfo_path.prp_vip.vip_vi.vi_fsid.val[0], 0, | |
0a7de745 A |
1499 | "PROC_PIDREGIONPATHINFO2 returns valid value for vi_fsid.val[0]:%d", |
1500 | preginfo_path.prp_vip.vip_vi.vi_fsid.val[0]); | |
a39ff7e2 | 1501 | T_EXPECT_NE_INT(preginfo_path.prp_vip.vip_vi.vi_fsid.val[1], 0, |
0a7de745 A |
1502 | "PROC_PIDREGIONPATHINFO2 returns valid value for vi_fsid.val[1]:%d", |
1503 | preginfo_path.prp_vip.vip_vi.vi_fsid.val[1]); | |
d9a64523 | 1504 | T_EXPECT_NE_PTR((void *)(strcasestr(preginfo_path.prp_vip.vip_path, CONF_TMP_FILE_PFX)), NULL, |
0a7de745 | 1505 | "PROC_PIDREGIONPATHINFO2 returns valid value for vi_path"); |
a39ff7e2 A |
1506 | /* |
1507 | * Basic sanity checks for vnode stat returned by the API | |
1508 | */ | |
1509 | T_EXPECT_NE_UINT(preginfo_path.prp_vip.vip_vi.vi_stat.vst_dev, 0U, "PROC_PIDREGIONPATHINFO2 returns valid value for vst_dev"); | |
1510 | T_EXPECT_EQ_UINT(((preginfo_path.prp_vip.vip_vi.vi_stat.vst_mode & S_IFMT) ^ S_IFREG), 0, | |
0a7de745 | 1511 | "PROC_PIDREGIONPATHINFO2 returns valid value for vst_mode"); |
d9a64523 | 1512 | T_EXPECT_EQ_USHORT(preginfo_path.prp_vip.vip_vi.vi_stat.vst_nlink, (unsigned short)0, /* the file was unlink()'d! */ |
0a7de745 | 1513 | "PROC_PIDREGIONPATHINFO2 returns valid value for vst_nlink"); |
a39ff7e2 | 1514 | T_EXPECT_NE_ULLONG(preginfo_path.prp_vip.vip_vi.vi_stat.vst_ino, 0ULL, |
0a7de745 | 1515 | "PROC_PIDREGIONPATHINFO2 returns valid value for vst_ino"); |
a39ff7e2 A |
1516 | T_EXPECT_EQ_UINT(preginfo_path.prp_vip.vip_vi.vi_stat.vst_uid, 0U, "PROC_PIDREGIONPATHINFO2 returns valid value for vst_uid"); |
1517 | T_EXPECT_EQ_UINT(preginfo_path.prp_vip.vip_vi.vi_stat.vst_gid, 0U, "PROC_PIDREGIONPATHINFO2 returns valid value for vst_gid"); | |
1518 | T_EXPECT_GE_LLONG(preginfo_path.prp_vip.vip_vi.vi_stat.vst_size, (off_t)CONF_BLK_SIZE, | |
0a7de745 | 1519 | "PROC_PIDREGIONPATHINFO2 returns valid value for vst_size"); |
a39ff7e2 | 1520 | T_EXPECT_GE_LLONG(preginfo_path.prp_vip.vip_vi.vi_stat.vst_blocks, 1LL, |
0a7de745 | 1521 | "PROC_PIDREGIONPATHINFO2 returns valid value for vst_blocks"); |
a39ff7e2 | 1522 | T_EXPECT_GE_UINT(preginfo_path.prp_vip.vip_vi.vi_stat.vst_blksize, CONF_BLK_SIZE, |
0a7de745 | 1523 | "PROC_PIDREGIONPATHINFO2 returns valid value for vst_blksize"); |
a39ff7e2 A |
1524 | |
1525 | int ret = 0; | |
d9a64523 | 1526 | ret = munmap(map_tmp, (size_t)map_tmp_sz); |
a39ff7e2 A |
1527 | T_QUIET; |
1528 | T_EXPECT_POSIX_SUCCESS(ret, "munmap of map_tmp"); | |
1529 | free_proc_info(proc_info, 1); | |
1530 | } | |
1531 | ||
1532 | T_DECL(proc_info_proc_pidregionpathinfo3, | |
0a7de745 | 1533 | "Test to verify PROC_PIDREGIONPATHINFO3 returns valid information about the process", |
cb323159 | 1534 | T_META_ASROOT(true)) |
a39ff7e2 | 1535 | { |
0a7de745 | 1536 | void * proc_info[5]; |
a39ff7e2 A |
1537 | proc_info_caller(PREGINFO_PATH_3, proc_info, NULL); |
1538 | ||
1539 | struct proc_regionwithpathinfo preginfo_path = *((struct proc_regionwithpathinfo *)proc_info[0]); | |
d9a64523 A |
1540 | void *map_tmp = proc_info[1]; |
1541 | vm_map_size_t map_tmp_sz = (vm_map_size_t)(uintptr_t)proc_info[2]; | |
a39ff7e2 | 1542 | |
0a7de745 A |
1543 | /* The *info3 version of this call returns any open file that lives on the same file system */ |
1544 | T_EXPECT_EQ_INT(preginfo_path.prp_vip.vip_vi.vi_fsid.val[0], (int)(uintptr_t)proc_info[3], | |
1545 | "PROC_PIDREGIONPATHINFO3 returns valid value for vi_fsid.val[0]"); | |
1546 | T_EXPECT_EQ_INT(preginfo_path.prp_vip.vip_vi.vi_fsid.val[1], (int)(uintptr_t)proc_info[4], | |
1547 | "PROC_PIDREGIONPATHINFO3 returns valid value for vi_fsid.val[1]"); | |
a39ff7e2 | 1548 | |
d9a64523 A |
1549 | int ret = 0; |
1550 | ret = munmap(map_tmp, (size_t)map_tmp_sz); | |
1551 | T_QUIET; | |
1552 | T_EXPECT_POSIX_SUCCESS(ret, "munmap of map_tmp"); | |
a39ff7e2 A |
1553 | free_proc_info(proc_info, 1); |
1554 | } | |
1555 | ||
1556 | T_DECL(proc_info_proc_pidvnodepathinfo, | |
0a7de745 | 1557 | "Test to verify PROC_PIDVNODEPATHINFO returns valid information about the process", |
cb323159 | 1558 | T_META_ASROOT(true)) |
a39ff7e2 A |
1559 | { |
1560 | void * proc_info[1]; | |
1561 | proc_info_caller(PVNINFO, proc_info, NULL); | |
1562 | struct proc_vnodepathinfo pvninfo = *((struct proc_vnodepathinfo *)proc_info[0]); | |
1563 | ||
1564 | T_EXPECT_EQ_INT(pvninfo.pvi_cdir.vip_vi.vi_type, VDIR, "PROC_PIDVNODEPATHINFO returns valid value for vi_type"); | |
1565 | T_EXPECT_EQ_INT(pvninfo.pvi_cdir.vip_vi.vi_pad, 0, "PROC_PIDVNODEPATHINFO returns valid value for vi_pad"); | |
1566 | T_EXPECT_NE_INT(pvninfo.pvi_cdir.vip_vi.vi_fsid.val[0], 0, "PROC_PIDVNODEPATHINFO returns valid value for vi_fsid.val[0]"); | |
1567 | T_EXPECT_NE_INT(pvninfo.pvi_cdir.vip_vi.vi_fsid.val[1], 0, "PROC_PIDVNODEPATHINFO returns valid value for vi_fsid.val[1]"); | |
1568 | /* | |
1569 | * Basic sanity checks for vnode stat returned by the API | |
1570 | */ | |
1571 | T_EXPECT_NE_UINT(pvninfo.pvi_cdir.vip_vi.vi_stat.vst_dev, 0U, "PROC_PIDVNODEPATHINFO returns valid value for vst_dev"); | |
1572 | T_EXPECT_EQ_INT(((pvninfo.pvi_cdir.vip_vi.vi_stat.vst_mode & S_IFMT) ^ S_IFDIR), 0, | |
0a7de745 | 1573 | "PROC_PIDVNODEPATHINFO returns valid value for vst_mode"); |
a39ff7e2 | 1574 | T_EXPECT_GE_USHORT(pvninfo.pvi_cdir.vip_vi.vi_stat.vst_nlink, (unsigned short)2, |
0a7de745 | 1575 | "PROC_PIDVNODEPATHINFO returns valid value for vst_nlink"); |
a39ff7e2 | 1576 | T_EXPECT_NE_ULLONG(pvninfo.pvi_cdir.vip_vi.vi_stat.vst_ino, 0ULL, "PROC_PIDVNODEPATHINFO returns valid value for vst_ino"); |
d9a64523 A |
1577 | T_EXPECT_GE_UINT(pvninfo.pvi_cdir.vip_vi.vi_stat.vst_uid, 0U, "PROC_PIDVNODEPATHINFO returns valid value for vst_uid"); |
1578 | T_EXPECT_GE_UINT(pvninfo.pvi_cdir.vip_vi.vi_stat.vst_gid, 0U, "PROC_PIDVNODEPATHINFO returns valid value for vst_gid"); | |
a39ff7e2 A |
1579 | T_EXPECT_GT_LLONG(pvninfo.pvi_cdir.vip_vi.vi_stat.vst_size, 0LL, "PROC_PIDVNODEPATHINFO returns valid value for vst_size"); |
1580 | T_EXPECT_GE_LLONG(pvninfo.pvi_cdir.vip_vi.vi_stat.vst_blocks, 0LL, "PROC_PIDVNODEPATHINFO returns valid value for vst_blocks"); | |
1581 | T_EXPECT_GE_UINT(pvninfo.pvi_cdir.vip_vi.vi_stat.vst_blksize, CONF_BLK_SIZE, | |
0a7de745 | 1582 | "PROC_PIDVNODEPATHINFO returns valid value for vst_blksize"); |
a39ff7e2 A |
1583 | |
1584 | free_proc_info(proc_info, 1); | |
1585 | } | |
1586 | /* | |
1587 | * The remaining tests break from the pattern of the other PROC_INFO_CALL_PIDINFO tests. | |
1588 | * We call proc_info directly as it's more efficient | |
1589 | */ | |
1590 | ||
1591 | T_DECL(proc_info_pidinfo_proc_pidlistfds, | |
0a7de745 | 1592 | "proc_info API tests to verify PROC_INFO_CALL_PIDINFO/PROC_PIDLISTFDS", |
cb323159 | 1593 | T_META_ASROOT(true)) |
a39ff7e2 A |
1594 | { |
1595 | int retval; | |
1596 | int orig_nfiles = 0; | |
1597 | struct proc_fdinfo * fd_info = NULL; | |
1598 | ||
1599 | T_LOG("Test to verify PROC_PIDLISTFDS returns sane number of open files"); | |
1600 | retval = __proc_info(PROC_INFO_CALL_PIDINFO, getpid(), PROC_PIDLISTFDS, (uint32_t)0, (user_addr_t)0, (uint32_t)0); | |
1601 | orig_nfiles = retval / (int)sizeof(struct proc_fdinfo); | |
1602 | T_EXPECT_GE_INT(orig_nfiles, CONF_OPN_FILE_COUNT, "The number of open files is lower than expected."); | |
1603 | ||
1604 | /* | |
0a7de745 A |
1605 | * Allocate a buffer of expected size + 1 to ensure that |
1606 | * the API still returns expected size | |
1607 | * i.e. 3 + 1 = 4 open fds | |
1608 | */ | |
a39ff7e2 A |
1609 | T_LOG("Test to verify PROC_PIDLISTFDS returns valid fd information"); |
1610 | fd_info = malloc(sizeof(*fd_info) * 5); | |
d9a64523 | 1611 | tmp_fd = CONF_TMP_FILE_OPEN(NULL); |
a39ff7e2 A |
1612 | T_LOG("tmp_fd val:%d", tmp_fd); |
1613 | T_QUIET; | |
1614 | T_EXPECT_POSIX_SUCCESS(tmp_fd, "open() for PROC_PIDLISTFDS"); | |
1615 | ||
1616 | retval = __proc_info(PROC_INFO_CALL_PIDINFO, getpid(), PROC_PIDLISTFDS, (uint32_t)0, (user_addr_t)fd_info, | |
0a7de745 | 1617 | (uint32_t)(sizeof(*fd_info) * 5)); |
a39ff7e2 A |
1618 | retval = retval / (int)sizeof(struct proc_fdinfo); |
1619 | ||
1620 | close(tmp_fd); | |
1621 | ||
1622 | for (int i = 0; i < retval; i++) { | |
1623 | /* | |
1624 | * Check only for the fd that we control. | |
1625 | */ | |
1626 | if (tmp_fd != fd_info[i].proc_fd) { | |
1627 | continue; | |
1628 | } | |
1629 | T_EXPECT_EQ_UINT(fd_info[i].proc_fdtype, (unsigned int)PROX_FDTYPE_VNODE, "Correct proc_fdtype for returned fd"); | |
1630 | } | |
1631 | ||
1632 | T_EXPECT_GE_INT(retval, 4, "Correct number of fds was returned."); | |
1633 | ||
1634 | tmp_fd = -1; | |
1635 | free(fd_info); | |
1636 | fd_info = NULL; | |
1637 | } | |
1638 | ||
1639 | T_DECL(proc_info_proc_pidpathinfo, | |
0a7de745 | 1640 | "Test to verify PROC_PIDPATHINFO returns valid information about the process", |
cb323159 | 1641 | T_META_ASROOT(true)) |
a39ff7e2 A |
1642 | { |
1643 | char * pid_path = NULL; | |
1644 | pid_path = malloc(sizeof(char) * PROC_PIDPATHINFO_MAXSIZE); | |
1645 | T_EXPECT_NOTNULL(pid_path, "malloc for PROC_PIDPATHINFO"); | |
1646 | int retval = __proc_info(PROC_INFO_CALL_PIDINFO, getpid(), PROC_PIDPATHINFO, (uint64_t)0, (user_addr_t)pid_path, | |
0a7de745 | 1647 | (uint32_t)PROC_PIDPATHINFO_MAXSIZE); |
a39ff7e2 A |
1648 | T_EXPECT_EQ_INT(retval, 0, "__proc_info call for PROC_PIDPATHINFO"); |
1649 | ||
1650 | T_EXPECT_NE_PTR((void *)(strcasestr(pid_path, CONF_CMD_NAME)), NULL, "PROC_PIDPATHINFOreturns valid value for pid_path"); | |
1651 | free(pid_path); | |
1652 | pid_path = NULL; | |
1653 | } | |
1654 | ||
1655 | T_DECL(proc_info_proc_pidlistfileports, | |
0a7de745 | 1656 | "Test to verify PROC_PIDLISTFILEPORTS returns valid information about the process", |
cb323159 | 1657 | T_META_ASROOT(true)) |
a39ff7e2 A |
1658 | { |
1659 | struct proc_fileportinfo * fileport_info = NULL; | |
1660 | mach_port_t tmp_file_port = MACH_PORT_NULL; | |
1661 | proc_config_t proc_config = spawn_child_processes(1, proc_info_call_pidinfo_handler); | |
1662 | int child_pid = proc_config->child_pids[0]; | |
1663 | ||
1664 | /* | |
1665 | * Create a file port | |
1666 | */ | |
d9a64523 | 1667 | tmp_fd = CONF_TMP_FILE_OPEN(NULL); |
a39ff7e2 A |
1668 | int retval = fileport_makeport(tmp_fd, &tmp_file_port); |
1669 | T_EXPECT_POSIX_SUCCESS(retval, "fileport_makeport() for PROC_PIDLISTFILEPORTS"); | |
1670 | ||
1671 | /* | |
1672 | * Like the other APIs, this returns the actual count + 20. Hence we expect it to be atleast 1 (that we created) | |
1673 | */ | |
1674 | retval = __proc_info(PROC_INFO_CALL_PIDINFO, getpid(), PROC_PIDLISTFILEPORTS, (uint64_t)0, (user_addr_t)0, (uint32_t)0); | |
1675 | T_EXPECT_GE_INT(retval / (int)sizeof(fileport_info), 1, | |
0a7de745 | 1676 | "__proc_info call for PROC_PIDLISTFILEPORTS to get total ports in parent"); |
a39ff7e2 A |
1677 | |
1678 | /* | |
1679 | * Child doesn't have any fileports, should return zero | |
1680 | */ | |
1681 | retval = __proc_info(PROC_INFO_CALL_PIDINFO, child_pid, PROC_PIDLISTFILEPORTS, (uint64_t)0, (user_addr_t)0, (uint32_t)0); | |
1682 | T_EXPECT_EQ_INT(retval / (int)sizeof(fileport_info), 0, | |
0a7de745 | 1683 | "__proc_info call for PROC_PIDLISTFILEPORTS to get total ports in child"); |
a39ff7e2 A |
1684 | |
1685 | fileport_info = malloc(sizeof(*fileport_info) * (size_t)retval); | |
1686 | retval = __proc_info(PROC_INFO_CALL_PIDINFO, getpid(), PROC_PIDLISTFILEPORTS, (uint64_t)0, (user_addr_t)fileport_info, | |
0a7de745 | 1687 | (uint32_t)sizeof(*fileport_info)); |
a39ff7e2 A |
1688 | T_EXPECT_EQ_INT(retval, (int)sizeof(*fileport_info), "__proc_info call for PROC_PIDLISTFILEPORTS"); |
1689 | ||
1690 | T_EXPECT_NE_UINT(fileport_info->proc_fileport, (uint32_t)0, "PROC_PIDLISTFILEPORTS returns valid value for proc_fileport"); | |
1691 | T_EXPECT_EQ_UINT(fileport_info->proc_fdtype, (uint32_t)PROX_FDTYPE_VNODE, | |
0a7de745 | 1692 | "PROC_PIDLISTFILEPORTS returns valid value for proc_fdtype"); |
a39ff7e2 A |
1693 | |
1694 | /* | |
1695 | * Cleanup for the fileport | |
1696 | */ | |
1697 | mach_port_deallocate(mach_task_self(), tmp_file_port); | |
1698 | tmp_file_port = MACH_PORT_NULL; | |
1699 | free(fileport_info); | |
1700 | fileport_info = NULL; | |
1701 | close(tmp_fd); | |
1702 | tmp_fd = -1; | |
1703 | free_proc_config(proc_config); | |
1704 | } | |
1705 | ||
1706 | T_DECL(proc_info_proc_pidcoalitioninfo, | |
0a7de745 | 1707 | "Test to verify PROC_PIDCOALITIONINFO returns valid information about the process", |
cb323159 | 1708 | T_META_ASROOT(true)) |
a39ff7e2 A |
1709 | { |
1710 | proc_config_t proc_config = spawn_child_processes(1, proc_info_call_pidinfo_handler); | |
1711 | int child_pid = proc_config->child_pids[0]; | |
1712 | ||
1713 | struct proc_pidcoalitioninfo pci_parent; | |
1714 | struct proc_pidcoalitioninfo pci_child; | |
1715 | int retval = __proc_info(PROC_INFO_CALL_PIDINFO, getpid(), PROC_PIDCOALITIONINFO, (uint64_t)0, (user_addr_t)&pci_parent, | |
0a7de745 | 1716 | (uint32_t)sizeof(pci_parent)); |
a39ff7e2 A |
1717 | T_EXPECT_EQ_INT(retval, (int)sizeof(pci_parent), "__proc_info call for PROC_PIDCOALITIONINFO (parent)"); |
1718 | retval = __proc_info(PROC_INFO_CALL_PIDINFO, child_pid, PROC_PIDCOALITIONINFO, (uint64_t)0, (user_addr_t)&pci_child, | |
0a7de745 | 1719 | (uint32_t)sizeof(pci_child)); |
a39ff7e2 A |
1720 | T_EXPECT_EQ_INT(retval, (int)sizeof(pci_child), "__proc_info call for PROC_PIDCOALITIONINFO (child)"); |
1721 | ||
1722 | /* | |
1723 | * Coalition IDs should match for child and parent | |
1724 | */ | |
1725 | for (int i = 0; i < COALITION_NUM_TYPES; i++) { | |
1726 | T_EXPECT_EQ_ULLONG(pci_parent.coalition_id[i], pci_child.coalition_id[i], | |
0a7de745 | 1727 | "PROC_PIDCOALITIONINFO returns valid value for coalition_id"); |
a39ff7e2 A |
1728 | } |
1729 | ||
1730 | free_proc_config(proc_config); | |
1731 | } | |
1732 | ||
1733 | T_DECL(proc_info_proc_pidworkqueueinfo, | |
0a7de745 | 1734 | "Test to verify PROC_PIDWORKQUEUEINFO returns valid information about the process", |
cb323159 | 1735 | T_META_ASROOT(true)) |
a39ff7e2 A |
1736 | { |
1737 | proc_config_t proc_config = spawn_child_processes(1, proc_info_call_pidinfo_handler); | |
1738 | int child_pid = proc_config->child_pids[0]; | |
1739 | send_action_to_child_processes(proc_config, ACT_PHASE5); | |
1740 | ||
1741 | struct proc_workqueueinfo pwqinfo; | |
1742 | usleep(10000); | |
1743 | int retval = __proc_info(PROC_INFO_CALL_PIDINFO, child_pid, PROC_PIDWORKQUEUEINFO, (uint64_t)0, (user_addr_t)&pwqinfo, | |
0a7de745 | 1744 | (uint32_t)sizeof(pwqinfo)); |
a39ff7e2 A |
1745 | T_EXPECT_EQ_INT(retval, (int)sizeof(pwqinfo), "__proc_info call for PROC_PIDWORKQUEUEINFO"); |
1746 | ||
1747 | int ncpu = 0; | |
1748 | size_t ncpu_size = sizeof(ncpu); | |
1749 | retval = sysctlbyname("hw.ncpu", (void *)&ncpu, &ncpu_size, NULL, 0); | |
1750 | T_EXPECT_EQ_INT(retval, 0, "sysctl() for PROC_PIDWORKQUEUEINFO"); | |
1751 | T_EXPECT_GE_UINT(pwqinfo.pwq_nthreads, (uint32_t)1, "PROC_PIDWORKQUEUEINFO returns valid value for pwq_nthreads"); | |
1752 | T_EXPECT_GE_UINT(pwqinfo.pwq_blockedthreads + pwqinfo.pwq_runthreads, (uint32_t)1, | |
0a7de745 | 1753 | "PROC_PIDWORKQUEUEINFO returns valid value for pwqinfo.pwq_runthreads/pwq_blockedthreads"); |
a39ff7e2 A |
1754 | T_EXPECT_EQ_UINT(pwqinfo.pwq_state, (uint32_t)0, "PROC_PIDWORKQUEUEINFO returns valid value for pwq_state"); |
1755 | ||
1756 | kill_child_processes(proc_config); | |
1757 | free_proc_config(proc_config); | |
1758 | } | |
1759 | T_DECL(proc_info_proc_pidnoteexit, | |
0a7de745 | 1760 | "Test to verify PROC_PIDNOTEEXIT returns valid information about the process", |
cb323159 | 1761 | T_META_ASROOT(true)) |
a39ff7e2 A |
1762 | { |
1763 | /* | |
1764 | * Ask the child to close pipe and quit, cleanup pipes for parent | |
1765 | */ | |
1766 | proc_config_t proc_config = spawn_child_processes(1, proc_info_call_pidinfo_handler); | |
1767 | int child_pid = proc_config->child_pids[0]; | |
1768 | send_action_to_child_processes(proc_config, ACT_EXIT); | |
1769 | ||
1770 | uint32_t exit_data = 0; | |
1771 | int retval = __proc_info(PROC_INFO_CALL_PIDINFO, child_pid, PROC_PIDNOTEEXIT, (uint64_t)(NOTE_EXITSTATUS | NOTE_EXIT_DETAIL), | |
0a7de745 | 1772 | (user_addr_t)&exit_data, (uint32_t)sizeof(exit_data)); |
a39ff7e2 A |
1773 | T_EXPECT_EQ_INT(retval, (int)sizeof(exit_data), "__proc_info call for PROC_PIDNOTEEXIT"); |
1774 | ||
1775 | T_EXPECT_EQ_UINT(exit_data, 0U, "PROC_PIDNOTEEXIT returned valid value for exit_data"); | |
1776 | ||
1777 | free_proc_config(proc_config); | |
1778 | } | |
1779 | ||
1780 | T_DECL(proc_info_negative_tests, | |
0a7de745 | 1781 | "Test to validate PROC_INFO_CALL_PIDINFO for invalid arguments", |
cb323159 | 1782 | T_META_ASROOT(true)) |
a39ff7e2 A |
1783 | { |
1784 | proc_config_t proc_config = spawn_child_processes(1, proc_info_call_pidinfo_handler); | |
1785 | int child_pid = proc_config->child_pids[0]; | |
1786 | uint32_t exit_data = 0; | |
1787 | ||
1788 | int retval = | |
1789 | __proc_info(PROC_INFO_CALL_PIDINFO, child_pid, PROC_PIDNOTEEXIT, (uint64_t)0, (user_addr_t)&exit_data, (uint32_t)0); | |
1790 | T_EXPECT_EQ_INT(errno, ENOMEM, "PROC_INFO_CALL_PIDINFO call should fail with ENOMEM if buffersize is zero"); | |
1791 | retval = __proc_info(PROC_INFO_CALL_PIDINFO, child_pid, PROC_PIDPATHINFO, (uint64_t)0, (user_addr_t)&exit_data, | |
0a7de745 | 1792 | (uint32_t)PROC_PIDPATHINFO_MAXSIZE + 1); |
a39ff7e2 | 1793 | T_EXPECT_EQ_INT(errno, EOVERFLOW, |
0a7de745 | 1794 | "PROC_INFO_CALL_PIDINFO call should fail with EOVERFLOW if buffersize is larger than PROC_PIDPATHINFO_MAXSIZE"); |
a39ff7e2 | 1795 | retval = __proc_info(PROC_INFO_CALL_PIDINFO, -1, PROC_PIDNOTEEXIT, (uint64_t)0, (user_addr_t)&exit_data, |
0a7de745 | 1796 | (uint32_t)sizeof(exit_data)); |
a39ff7e2 A |
1797 | T_EXPECT_EQ_INT(errno, ESRCH, "PROC_INFO_CALL_PIDINFO call should fail with ESRCH for invalid process id"); |
1798 | retval = __proc_info(PROC_INFO_CALL_PIDINFO, child_pid, -1U, (uint64_t)0, (user_addr_t)&exit_data, (uint32_t)sizeof(exit_data)); | |
1799 | T_EXPECT_EQ_INT(errno, EINVAL, "PROC_INFO_CALL_PIDINFO call should fail with EINVAL for invalid flavor"); | |
1800 | retval = __proc_info(PROC_INFO_CALL_PIDINFO, 0, PROC_PIDWORKQUEUEINFO, (uint64_t)0, (user_addr_t)0, (uint32_t)0); | |
1801 | T_EXPECT_EQ_INT(errno, EINVAL, | |
0a7de745 | 1802 | "PROC_INFO_CALL_PIDINFO call should fail with EINVAL if flavor is PROC_PIDWORKQUEUEINFO and pid=0"); |
a39ff7e2 A |
1803 | |
1804 | free_proc_config(proc_config); | |
1805 | } | |
1806 | ||
1807 | /* | |
1808 | * END PROC_INFO_CALL_PIDINFO DECLs | |
1809 | */ | |
5ba3f43e A |
1810 | |
1811 | #pragma mark proc_list_uptrs | |
1812 | ||
1813 | #define NUPTRS 4 | |
a39ff7e2 | 1814 | static uint64_t uptrs[NUPTRS] = {0x1122334455667788ULL, 0x99aabbccddeeff00ULL, 0xaabbaaddccaaffeeULL, 0xcc000011ccaa7755ULL}; |
5ba3f43e | 1815 | |
a39ff7e2 | 1816 | static const char * uptr_names[NUPTRS]; |
5ba3f43e A |
1817 | |
1818 | static void | |
a39ff7e2 | 1819 | print_uptrs(int argc, char * const * argv) |
5ba3f43e A |
1820 | { |
1821 | for (int i = 0; i < argc; i++) { | |
a39ff7e2 | 1822 | char * end; |
5ba3f43e A |
1823 | unsigned long pid = strtoul(argv[i], &end, 0); |
1824 | if (pid > INT_MAX) { | |
1825 | printf("error: pid '%lu' would overflow an integer\n", pid); | |
1826 | } | |
1827 | if (end == argv[i]) { | |
1828 | printf("error: could not parse '%s' as a pid\n", argv[i]); | |
1829 | continue; | |
1830 | } | |
1831 | int uptrs_count = proc_list_uptrs((int)pid, NULL, 0); | |
1832 | if (uptrs_count == 0) { | |
1833 | printf("no uptrs for process %d\n", (int)pid); | |
1834 | return; | |
1835 | } | |
1836 | ||
1837 | /* extra space */ | |
1838 | unsigned int uptrs_len = (unsigned int)uptrs_count + 32; | |
1839 | ||
a39ff7e2 | 1840 | uint64_t * uptrs_alloc = malloc(sizeof(uint64_t) * uptrs_len); |
5ba3f43e A |
1841 | os_assert(uptrs_alloc != NULL); |
1842 | ||
a39ff7e2 | 1843 | uptrs_count = proc_list_uptrs((int)pid, uptrs_alloc, (uint32_t)(sizeof(uint64_t) * uptrs_len)); |
5ba3f43e A |
1844 | printf("process %d has %d uptrs:\n", (int)pid, uptrs_count); |
1845 | if (uptrs_count > (int)uptrs_len) { | |
1846 | uptrs_count = (int)uptrs_len; | |
1847 | } | |
1848 | for (int j = 0; j < uptrs_count; j++) { | |
1849 | printf("%#17" PRIx64 "\n", uptrs_alloc[j]); | |
1850 | } | |
1851 | } | |
1852 | } | |
1853 | ||
f427ee49 | 1854 | T_DECL(proc_list_uptrs, "the kernel should return any up-pointers it knows about") |
5ba3f43e A |
1855 | { |
1856 | if (argc > 0) { | |
1857 | print_uptrs(argc, argv); | |
1858 | T_SKIP("command line invocation of tool, not test"); | |
1859 | } | |
1860 | ||
1861 | unsigned int cur_uptr = 0; | |
1862 | ||
1863 | int kq = kqueue(); | |
a39ff7e2 A |
1864 | T_QUIET; |
1865 | T_ASSERT_POSIX_SUCCESS(kq, "kqueue"); | |
5ba3f43e A |
1866 | |
1867 | /* | |
1868 | * Should find uptrs on file-type knotes and generic knotes (two | |
1869 | * different search locations, internally). | |
1870 | */ | |
1871 | struct kevent64_s events[2]; | |
1872 | memset(events, 0, sizeof(events)); | |
1873 | ||
1874 | uptr_names[cur_uptr] = "kqueue file-backed knote"; | |
a39ff7e2 A |
1875 | events[0].filter = EVFILT_WRITE; |
1876 | events[0].ident = STDOUT_FILENO; | |
1877 | events[0].flags = EV_ADD; | |
1878 | events[0].udata = uptrs[cur_uptr++]; | |
5ba3f43e A |
1879 | |
1880 | uptr_names[cur_uptr] = "kqueue non-file-backed knote"; | |
a39ff7e2 A |
1881 | events[1].filter = EVFILT_USER; |
1882 | events[1].ident = 1; | |
1883 | events[1].flags = EV_ADD; | |
1884 | events[1].udata = uptrs[cur_uptr++]; | |
5ba3f43e | 1885 | |
a39ff7e2 | 1886 | int kev_err = kevent64(kq, events, sizeof(events) / sizeof(events[0]), NULL, 0, KEVENT_FLAG_IMMEDIATE, NULL); |
5ba3f43e A |
1887 | T_ASSERT_POSIX_SUCCESS(kev_err, "register events with kevent64"); |
1888 | ||
1889 | /* | |
1890 | * Should find uptrs both on a kevent_id kqueue and in a workloop | |
1891 | * kqueue's knote's udata field. | |
1892 | */ | |
d9a64523 A |
1893 | uptr_names[cur_uptr] = "dynamic kqueue non-file-backed knote"; |
1894 | struct kevent_qos_s events_id[] = {{ | |
0a7de745 A |
1895 | .filter = EVFILT_USER, |
1896 | .ident = 1, | |
1897 | .flags = EV_ADD, | |
1898 | .qos = (int)_pthread_qos_class_encode(QOS_CLASS_DEFAULT, 0, 0), | |
1899 | .udata = uptrs[cur_uptr++] | |
1900 | }}; | |
5ba3f43e A |
1901 | |
1902 | uptr_names[cur_uptr] = "dynamic kqueue ID"; | |
a39ff7e2 | 1903 | kev_err = kevent_id(uptrs[cur_uptr++], events_id, 1, NULL, 0, NULL, NULL, KEVENT_FLAG_WORKLOOP | KEVENT_FLAG_IMMEDIATE); |
5ba3f43e A |
1904 | T_ASSERT_POSIX_SUCCESS(kev_err, "register event with kevent_id"); |
1905 | ||
a39ff7e2 | 1906 | errno = 0; |
5ba3f43e | 1907 | int uptrs_count = proc_list_uptrs(getpid(), NULL, 0); |
a39ff7e2 A |
1908 | T_QUIET; |
1909 | T_ASSERT_POSIX_SUCCESS(uptrs_count, "proc_list_uptrs"); | |
1910 | T_QUIET; | |
1911 | T_EXPECT_EQ(uptrs_count, NUPTRS, "should see correct number of up-pointers"); | |
5ba3f43e | 1912 | |
a39ff7e2 A |
1913 | uint64_t uptrs_obs[NUPTRS] = {0}; |
1914 | uptrs_count = proc_list_uptrs(getpid(), uptrs_obs, sizeof(uptrs_obs)); | |
1915 | T_QUIET; | |
1916 | T_ASSERT_POSIX_SUCCESS(uptrs_count, "proc_list_uptrs"); | |
5ba3f43e A |
1917 | |
1918 | for (int i = 0; i < uptrs_count; i++) { | |
1919 | int found = -1; | |
1920 | for (int j = 0; j < NUPTRS; j++) { | |
1921 | if (uptrs_obs[i] == uptrs[j]) { | |
1922 | found = j; | |
1923 | goto next; | |
1924 | } | |
1925 | } | |
1926 | T_FAIL("unexpected up-pointer found: %#" PRIx64, uptrs_obs[i]); | |
0a7de745 | 1927 | next: ; |
5ba3f43e A |
1928 | if (found != -1) { |
1929 | T_PASS("found up-pointer for %s", uptr_names[found]); | |
1930 | } | |
1931 | } | |
5c9f4661 A |
1932 | |
1933 | uint64_t up_overflow[2] = {0}; | |
0a7de745 A |
1934 | uptrs_count = proc_list_uptrs(getpid(), up_overflow, sizeof(uint64_t) + 1); |
1935 | T_ASSERT_EQ(up_overflow[1], (uint64_t)0, "overflow check"); | |
5ba3f43e A |
1936 | } |
1937 | ||
1938 | #pragma mark dynamic kqueue info | |
1939 | ||
a39ff7e2 | 1940 | #define EXPECTED_ID UINT64_C(0x1122334455667788) |
5ba3f43e A |
1941 | #define EXPECTED_UDATA UINT64_C(0x99aabbccddeeff00) |
1942 | #ifndef KQ_WORKLOOP | |
1943 | #define KQ_WORKLOOP 0x80 | |
1944 | #endif | |
1945 | ||
1946 | static void | |
1947 | setup_kevent_id(kqueue_id_t id) | |
1948 | { | |
d9a64523 | 1949 | struct kevent_qos_s events_id[] = {{ |
0a7de745 A |
1950 | .filter = EVFILT_USER, |
1951 | .ident = 1, | |
1952 | .flags = EV_ADD, | |
1953 | .qos = (int)_pthread_qos_class_encode(QOS_CLASS_DEFAULT, 0, 0), | |
1954 | .udata = EXPECTED_UDATA | |
1955 | }}; | |
5ba3f43e | 1956 | |
a39ff7e2 | 1957 | int err = kevent_id(id, events_id, 1, NULL, 0, NULL, NULL, KEVENT_FLAG_WORKLOOP | KEVENT_FLAG_IMMEDIATE); |
5ba3f43e A |
1958 | T_ASSERT_POSIX_SUCCESS(err, "register event with kevent_id"); |
1959 | } | |
1960 | ||
1961 | static kqueue_id_t * | |
a39ff7e2 | 1962 | list_kqids(pid_t pid, int * nkqids_out) |
5ba3f43e A |
1963 | { |
1964 | int kqids_len = 256; | |
1965 | int nkqids; | |
a39ff7e2 | 1966 | kqueue_id_t * kqids = NULL; |
5ba3f43e A |
1967 | uint32_t kqids_size; |
1968 | ||
1969 | retry: | |
1970 | if (os_mul_overflow(sizeof(kqueue_id_t), kqids_len, &kqids_size)) { | |
a39ff7e2 A |
1971 | T_QUIET; |
1972 | T_ASSERT_GT(kqids_len, PROC_PIDDYNKQUEUES_MAX, NULL); | |
5ba3f43e A |
1973 | kqids_len = PROC_PIDDYNKQUEUES_MAX; |
1974 | goto retry; | |
1975 | } | |
1976 | if (!kqids) { | |
1977 | kqids = malloc(kqids_size); | |
a39ff7e2 A |
1978 | T_QUIET; |
1979 | T_ASSERT_NOTNULL(kqids, "malloc(%" PRIu32 ")", kqids_size); | |
5ba3f43e A |
1980 | } |
1981 | ||
1982 | nkqids = proc_list_dynkqueueids(pid, kqids, kqids_size); | |
1983 | if (nkqids > kqids_len && kqids_len < PROC_PIDDYNKQUEUES_MAX) { | |
1984 | kqids_len *= 2; | |
1985 | if (kqids_len > PROC_PIDDYNKQUEUES_MAX) { | |
1986 | kqids_len = PROC_PIDDYNKQUEUES_MAX; | |
1987 | } | |
1988 | free(kqids); | |
1989 | kqids = NULL; | |
1990 | goto retry; | |
1991 | } | |
1992 | ||
1993 | *nkqids_out = nkqids; | |
1994 | return kqids; | |
1995 | } | |
1996 | ||
a39ff7e2 | 1997 | T_DECL(list_dynamic_kqueues, "the kernel should list IDs of dynamic kqueues", T_META_ALL_VALID_ARCHS(true)) |
5ba3f43e A |
1998 | { |
1999 | int nkqids; | |
2000 | bool found = false; | |
2001 | ||
2002 | setup_kevent_id(EXPECTED_ID); | |
a39ff7e2 | 2003 | kqueue_id_t * kqids = list_kqids(getpid(), &nkqids); |
5ba3f43e A |
2004 | T_ASSERT_GE(nkqids, 1, "at least one dynamic kqueue is listed"); |
2005 | for (int i = 0; i < nkqids; i++) { | |
2006 | if (kqids[i] == EXPECTED_ID) { | |
2007 | found = true; | |
2008 | T_PASS("found expected dynamic kqueue ID"); | |
2009 | } else { | |
2010 | T_LOG("found another dynamic kqueue with ID %#" PRIx64, kqids[i]); | |
2011 | } | |
2012 | } | |
2013 | ||
2014 | if (!found) { | |
2015 | T_FAIL("could not find dynamic ID of kqueue created"); | |
2016 | } | |
2017 | ||
2018 | free(kqids); | |
2019 | } | |
2020 | ||
a39ff7e2 | 2021 | T_DECL(dynamic_kqueue_basic_info, "the kernel should report valid basic dynamic kqueue info", T_META_ALL_VALID_ARCHS(true)) |
5ba3f43e A |
2022 | { |
2023 | struct kqueue_info kqinfo; | |
2024 | int ret; | |
2025 | ||
2026 | setup_kevent_id(EXPECTED_ID); | |
a39ff7e2 A |
2027 | ret = proc_piddynkqueueinfo(getpid(), PROC_PIDDYNKQUEUE_INFO, EXPECTED_ID, &kqinfo, sizeof(kqinfo)); |
2028 | T_ASSERT_POSIX_SUCCESS(ret, "proc_piddynkqueueinfo(... PROC_PIDDYNKQUEUE_INFO ...)"); | |
2029 | T_QUIET; | |
2030 | T_ASSERT_GE(ret, (int)sizeof(kqinfo), "PROC_PIDDYNKQUEUE_INFO should return the right size"); | |
5ba3f43e | 2031 | |
a39ff7e2 A |
2032 | T_EXPECT_NE(kqinfo.kq_state & KQ_WORKLOOP, 0U, "kqueue info should be for a workloop kqueue"); |
2033 | T_EXPECT_EQ(kqinfo.kq_stat.vst_ino, EXPECTED_ID, "inode field should be the kqueue's ID"); | |
5ba3f43e A |
2034 | } |
2035 | ||
a39ff7e2 | 2036 | T_DECL(dynamic_kqueue_extended_info, "the kernel should report valid extended dynamic kqueue info", T_META_ALL_VALID_ARCHS(true)) |
5ba3f43e A |
2037 | { |
2038 | struct kevent_extinfo kqextinfo[1]; | |
2039 | int ret; | |
2040 | ||
2041 | setup_kevent_id(EXPECTED_ID); | |
a39ff7e2 A |
2042 | ret = proc_piddynkqueueinfo(getpid(), PROC_PIDDYNKQUEUE_EXTINFO, EXPECTED_ID, kqextinfo, sizeof(kqextinfo)); |
2043 | T_ASSERT_POSIX_SUCCESS(ret, "proc_piddynkqueueinfo(... PROC_PIDDYNKQUEUE_EXTINFO ...)"); | |
2044 | T_QUIET; | |
2045 | T_ASSERT_EQ(ret, 1, "PROC_PIDDYNKQUEUE_EXTINFO should return a single knote"); | |
5ba3f43e | 2046 | |
a39ff7e2 A |
2047 | T_EXPECT_EQ(kqextinfo[0].kqext_kev.ident, 1ULL, "kevent identifier matches what was configured"); |
2048 | T_EXPECT_EQ(kqextinfo[0].kqext_kev.filter, (short)EVFILT_USER, "kevent filter matches what was configured"); | |
2049 | T_EXPECT_EQ(kqextinfo[0].kqext_kev.udata, EXPECTED_UDATA, "kevent udata matches what was configured"); | |
5ba3f43e A |
2050 | } |
2051 | ||
2052 | #pragma mark proc_listpids | |
2053 | ||
cb323159 A |
2054 | T_DECL(list_kdebug_pids, "the kernel should report processes that are filtered by kdebug", |
2055 | T_META_ASROOT(YES), T_META_RUN_CONCURRENTLY(false)) | |
5ba3f43e | 2056 | { |
a39ff7e2 | 2057 | int mib[4] = {CTL_KERN, KERN_KDEBUG}; |
5ba3f43e A |
2058 | int npids; |
2059 | int pids[1]; | |
2060 | int ret; | |
a39ff7e2 | 2061 | kd_regtype reg; |
5ba3f43e A |
2062 | size_t regsize = sizeof(reg); |
2063 | ||
2064 | mib[2] = KERN_KDREMOVE; | |
a39ff7e2 A |
2065 | ret = sysctl(mib, 3, NULL, NULL, NULL, 0); |
2066 | T_QUIET; | |
2067 | T_ASSERT_POSIX_SUCCESS(ret, "KERN_KDREMOVE sysctl"); | |
5ba3f43e | 2068 | |
a39ff7e2 A |
2069 | mib[2] = KERN_KDSETBUF; |
2070 | mib[3] = 100000; | |
2071 | ret = sysctl(mib, 4, NULL, NULL, NULL, 0); | |
2072 | T_QUIET; | |
2073 | T_ASSERT_POSIX_SUCCESS(ret, "KERN_KDSETBUF sysctl"); | |
5ba3f43e A |
2074 | |
2075 | mib[2] = KERN_KDSETUP; | |
a39ff7e2 A |
2076 | ret = sysctl(mib, 3, NULL, NULL, NULL, 0); |
2077 | T_QUIET; | |
2078 | T_ASSERT_POSIX_SUCCESS(ret, "KERN_KDSETUP sysctl"); | |
5ba3f43e A |
2079 | |
2080 | npids = proc_listpids(PROC_KDBG_ONLY, 0, pids, sizeof(pids)); | |
2081 | T_EXPECT_EQ(npids, 0, "no processes should be filtered initially"); | |
2082 | ||
a39ff7e2 A |
2083 | reg.type = KDBG_TYPENONE; |
2084 | reg.value1 = (unsigned int)getpid(); | |
5ba3f43e | 2085 | reg.value2 = 1; /* set the pid in the filter */ |
a39ff7e2 A |
2086 | mib[2] = KERN_KDPIDTR; |
2087 | ret = sysctl(mib, 3, ®, ®size, NULL, 0); | |
2088 | T_ASSERT_POSIX_SUCCESS(ret, "KERN_KDPIDTR sysctl to set a pid in the filter"); | |
5ba3f43e A |
2089 | |
2090 | npids = proc_listpids(PROC_KDBG_ONLY, 0, pids, sizeof(pids)); | |
2091 | npids /= 4; | |
2092 | T_EXPECT_EQ(npids, 1, "a process should be filtered"); | |
a39ff7e2 | 2093 | T_EXPECT_EQ(pids[0], getpid(), "process filtered should be the one that was set"); |
5ba3f43e A |
2094 | |
2095 | mib[2] = KERN_KDREMOVE; | |
a39ff7e2 A |
2096 | ret = sysctl(mib, 3, NULL, NULL, NULL, 0); |
2097 | T_QUIET; | |
2098 | T_ASSERT_POSIX_SUCCESS(ret, "KERN_KDREMOVE sysctl"); | |
5ba3f43e | 2099 | } |
cb323159 A |
2100 | |
2101 | #pragma mark misc | |
2102 | ||
2103 | static int prf_fd; | |
2104 | static char prf_path[PATH_MAX]; | |
2105 | static void | |
2106 | prf_end(void) | |
2107 | { | |
2108 | close(prf_fd); | |
2109 | unlink(prf_path); | |
2110 | } | |
2111 | ||
2112 | T_DECL(proc_regionfilename, "proc_regionfilename() should work") | |
2113 | { | |
2114 | static char expected[] = "'very rigorous maritime engineering standards' && the front fell off"; | |
2115 | static char real[sizeof(expected)]; | |
2116 | int rc; | |
2117 | void *addr; | |
2118 | ||
2119 | prf_fd = CONF_TMP_FILE_OPEN(prf_path); | |
2120 | T_ATEND(prf_end); | |
2121 | ||
2122 | rc = (int) write(prf_fd, expected, sizeof(expected)); | |
2123 | T_ASSERT_POSIX_SUCCESS(rc, "write to tmpfile"); | |
2124 | ||
2125 | addr = mmap(0, 0x1000, PROT_READ, MAP_PRIVATE, prf_fd, 0); | |
2126 | T_WITH_ERRNO; | |
2127 | T_ASSERT_NE_PTR(addr, MAP_FAILED, "mmap of tmpfile"); | |
2128 | ||
2129 | T_WITH_ERRNO; | |
2130 | T_ASSERT_GT(proc_regionfilename(getpid(), (uint64_t) addr, real, MAXPATHLEN), 0, "proc_regionfilename"); | |
2131 | T_EXPECT_EQ_STR(basename(prf_path), basename(real), "filename"); | |
2132 | } | |
2133 | ||
2134 | T_DECL(proc_regionpath, "PROC_PIDREGIONPATH should return addr, length and path") | |
2135 | { | |
2136 | int rc; | |
2137 | struct proc_regionpath path; | |
2138 | static char some_text[] = "'very rigorous maritime engineering standards' && the front fell off"; | |
2139 | unsigned long rounded_length = (sizeof(some_text) & (unsigned long) ~(PAGE_SIZE - 1)) + PAGE_SIZE; | |
2140 | void *addr; | |
2141 | ||
2142 | prf_fd = CONF_TMP_FILE_OPEN(prf_path); | |
2143 | T_ATEND(prf_end); | |
2144 | ||
2145 | rc = (int) write(prf_fd, some_text, sizeof(some_text)); | |
2146 | T_ASSERT_POSIX_SUCCESS(rc, "write to tmpfile"); | |
2147 | ||
2148 | addr = mmap(0, PAGE_SIZE, PROT_READ, MAP_PRIVATE, prf_fd, 0); | |
2149 | T_WITH_ERRNO; | |
2150 | T_ASSERT_NE_PTR(addr, MAP_FAILED, "mmap of tmpfile"); | |
2151 | ||
2152 | rc = proc_pidinfo(getpid(), PROC_PIDREGIONPATH, (uint64_t)addr, &path, sizeof(struct proc_regionpath)); | |
2153 | T_ASSERT_POSIX_SUCCESS(rc, "proc_pidinfo"); | |
2154 | ||
2155 | T_ASSERT_EQ((unsigned long) path.prpo_regionlength, rounded_length, "regionlength must match"); | |
2156 | T_ASSERT_EQ_PTR((void *) path.prpo_addr, addr, "addr must match"); | |
2157 | ||
2158 | rc = proc_pidinfo(getpid(), PROC_PIDREGIONPATH, (uint64_t)((char *) addr + 20), &path, sizeof(struct proc_regionpath)); | |
2159 | T_ASSERT_POSIX_SUCCESS(rc, "proc_pidinfo 20 bytes past the base address"); | |
2160 | ||
2161 | T_ASSERT_EQ((unsigned long) path.prpo_regionlength, rounded_length, "regionlength must match, even when 20 bytes past the base address"); | |
2162 | T_ASSERT_EQ_PTR((void *) path.prpo_addr, addr, "addr must match, even when 20 bytes past the base address"); | |
2163 | } |