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