Module Name: src Committed By: kamil Date: Mon Nov 14 04:55:57 UTC 2016
Modified Files: src/tests/kernel: t_ptrace_wait.c Log Message: Add new tests attach6 and attach7 in t_wait_proc{4,6,id,pid} attach6: Assert that tracer sees its parent when attached to tracer (check sysctl(7) and struct kinfo_proc2) attach7: Assert that tracer sees its parent when attached to tracer (check /proc/curproc/status 3rd column). Currently these tests fail as getppid() and parent id obtained in these alternative ways differ. Sponsored by <The NetBSD Foundation> To generate a diff of this commit: cvs rdiff -u -r1.12 -r1.13 src/tests/kernel/t_ptrace_wait.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/tests/kernel/t_ptrace_wait.c diff -u src/tests/kernel/t_ptrace_wait.c:1.12 src/tests/kernel/t_ptrace_wait.c:1.13 --- src/tests/kernel/t_ptrace_wait.c:1.12 Mon Nov 14 00:18:33 2016 +++ src/tests/kernel/t_ptrace_wait.c Mon Nov 14 04:55:57 2016 @@ -1,4 +1,4 @@ -/* $NetBSD: t_ptrace_wait.c,v 1.12 2016/11/14 00:18:33 kamil Exp $ */ +/* $NetBSD: t_ptrace_wait.c,v 1.13 2016/11/14 04:55:57 kamil Exp $ */ /*- * Copyright (c) 2016 The NetBSD Foundation, Inc. @@ -27,12 +27,13 @@ */ #include <sys/cdefs.h> -__RCSID("$NetBSD: t_ptrace_wait.c,v 1.12 2016/11/14 00:18:33 kamil Exp $"); +__RCSID("$NetBSD: t_ptrace_wait.c,v 1.13 2016/11/14 04:55:57 kamil Exp $"); #include <sys/param.h> #include <sys/types.h> #include <sys/ptrace.h> #include <sys/resource.h> +#include <sys/stat.h> #include <sys/sysctl.h> #include <sys/wait.h> #include <err.h> @@ -1008,7 +1009,8 @@ ATF_TC(attach5); ATF_TC_HEAD(attach5, tc) { atf_tc_set_md_var(tc, "descr", - "Assert that tracer sees its parent when attached to tracer"); + "Assert that tracer sees its parent when attached to tracer " + "(check getppid(2))"); } ATF_TC_BODY(attach5, tc) @@ -1024,10 +1026,335 @@ ATF_TC_BODY(attach5, tc) int status; #endif + printf("Spawn tracee\n"); + ATF_REQUIRE(pipe(fds_totracee) == 0); + ATF_REQUIRE(pipe(fds_fromtracee) == 0); + tracee = atf_utils_fork(); + if (tracee == 0) { + FORKEE_ASSERT(close(fds_totracee[1]) == 0); + FORKEE_ASSERT(close(fds_fromtracee[0]) == 0); + + parent = getppid(); + + /* Emit message to the parent */ + rv = write(fds_fromtracee[1], &msg, sizeof(msg)); + FORKEE_ASSERT(rv == sizeof(msg)); + rv = read(fds_totracee[0], &msg, sizeof(msg)); + FORKEE_ASSERT(rv == sizeof(msg)); + rv = write(fds_fromtracee[1], &msg, sizeof(msg)); + FORKEE_ASSERT(rv == sizeof(msg)); + + /* Wait for message from the parent */ + rv = read(fds_totracee[0], &msg, sizeof(msg)); + FORKEE_ASSERT(rv == sizeof(msg)); + + FORKEE_ASSERT_EQ(parent, getppid()); + + _exit(exitval_tracee); + } + ATF_REQUIRE(close(fds_totracee[0]) == 0); + ATF_REQUIRE(close(fds_fromtracee[1]) == 0); + + printf("Wait for child to record its parent identifier (pid)\n"); + rv = read(fds_fromtracee[0], &msg, sizeof(msg)); + FORKEE_ASSERT(rv == sizeof(msg)); + rv = write(fds_totracee[1], &msg, sizeof(msg)); + FORKEE_ASSERT(rv == sizeof(msg)); + rv = read(fds_fromtracee[0], &msg, sizeof(msg)); + FORKEE_ASSERT(rv == sizeof(msg)); + + printf("Spawn debugger\n"); + ATF_REQUIRE(pipe(fds_totracer) == 0); + ATF_REQUIRE(pipe(fds_fromtracer) == 0); + tracer = atf_utils_fork(); + if (tracer == 0) { + /* No IPC to communicate with the child */ + FORKEE_ASSERT(close(fds_totracee[1]) == 0); + FORKEE_ASSERT(close(fds_fromtracee[0]) == 0); + + FORKEE_ASSERT(close(fds_totracer[1]) == 0); + FORKEE_ASSERT(close(fds_fromtracer[0]) == 0); + + printf("Before calling PT_ATTACH from tracee %d\n", getpid()); + FORKEE_ASSERT(ptrace(PT_ATTACH, tracee, NULL, 0) != -1); + + /* Wait for tracee and assert that it was stopped w/ SIGSTOP */ + FORKEE_REQUIRE_SUCCESS( + wpid = TWAIT_GENERIC(tracee, &status, 0), tracee); + + forkee_status_stopped(status, SIGSTOP); + + /* Resume tracee with PT_CONTINUE */ + FORKEE_ASSERT(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1); + + /* Inform parent that tracer has attached to tracee */ + rv = write(fds_fromtracer[1], &msg, sizeof(msg)); + FORKEE_ASSERT(rv == sizeof(msg)); + + /* Wait for parent */ + rv = read(fds_totracer[0], &msg, sizeof(msg)); + FORKEE_ASSERT(rv == sizeof(msg)); + + /* Wait for tracee and assert that it exited */ + FORKEE_REQUIRE_SUCCESS( + wpid = TWAIT_GENERIC(tracee, &status, 0), tracee); + + forkee_status_exited(status, exitval_tracee); + + printf("Before exiting of the tracer process\n"); + _exit(exitval_tracer); + } + ATF_REQUIRE(close(fds_totracer[0]) == 0); + ATF_REQUIRE(close(fds_fromtracer[1]) == 0); + + printf("Wait for the tracer to attach to the tracee\n"); + rv = read(fds_fromtracer[0], &msg, sizeof(msg)); + ATF_REQUIRE(rv == sizeof(msg)); + + printf("Resume the tracee and let it exit\n"); + rv = write(fds_totracee[1], &msg, sizeof(msg)); + ATF_REQUIRE(rv == sizeof(msg)); + + printf("fds_totracee is no longer needed - close it\n"); + ATF_REQUIRE(close(fds_totracee[1]) == 0); + + printf("fds_fromtracee is no longer needed - close it\n"); + ATF_REQUIRE(close(fds_fromtracee[0]) == 0); + + printf("Detect that tracee is zombie\n"); + await_zombie(tracee); + + printf("Assert that there is no status about tracee - " + "Tracer must detect zombie first - calling %s()\n", TWAIT_FNAME); + TWAIT_REQUIRE_SUCCESS( + wpid = TWAIT_GENERIC(tracee, &status, WNOHANG), 0); + + printf("Resume the tracer and let it detect exited tracee\n"); + rv = write(fds_totracer[1], &msg, sizeof(msg)); + ATF_REQUIRE(rv == sizeof(msg)); + + printf("Wait for tracer to finish its job and exit - calling %s()\n", + TWAIT_FNAME); + TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracer, &status, 0), + tracer); + + validate_status_exited(status, exitval_tracer); + + printf("Wait for tracee to finish its job and exit - calling %s()\n", + TWAIT_FNAME); + TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracee, &status, WNOHANG), + tracee); + + validate_status_exited(status, exitval_tracee); + + printf("fds_fromtracer is no longer needed - close it\n"); + ATF_REQUIRE(close(fds_fromtracer[0]) == 0); + + printf("fds_totracer is no longer needed - close it\n"); + ATF_REQUIRE(close(fds_totracer[1]) == 0); +} +#endif + +#if defined(TWAIT_HAVE_PID) +ATF_TC(attach6); +ATF_TC_HEAD(attach6, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Assert that tracer sees its parent when attached to tracer " + "(check sysctl(7) and struct kinfo_proc2)"); +} + +ATF_TC_BODY(attach6, tc) +{ + int fds_totracee[2], fds_fromtracee[2]; + int fds_totracer[2], fds_fromtracer[2]; + int rv; + const int exitval_tracee = 5; + const int exitval_tracer = 10; + pid_t parent, tracee, tracer, wpid; + uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */ +#if defined(TWAIT_HAVE_STATUS) + int status; +#endif + int name[CTL_MAXNAME]; + struct kinfo_proc2 kp; + size_t len = sizeof(kp); + unsigned int namelen; + + printf("Spawn tracee\n"); + ATF_REQUIRE(pipe(fds_totracee) == 0); + ATF_REQUIRE(pipe(fds_fromtracee) == 0); + tracee = atf_utils_fork(); + if (tracee == 0) { + FORKEE_ASSERT(close(fds_totracee[1]) == 0); + FORKEE_ASSERT(close(fds_fromtracee[0]) == 0); + + parent = getppid(); + + /* Emit message to the parent */ + rv = write(fds_fromtracee[1], &msg, sizeof(msg)); + FORKEE_ASSERT(rv == sizeof(msg)); + rv = read(fds_totracee[0], &msg, sizeof(msg)); + FORKEE_ASSERT(rv == sizeof(msg)); + rv = write(fds_fromtracee[1], &msg, sizeof(msg)); + FORKEE_ASSERT(rv == sizeof(msg)); + + /* Wait for message from the parent */ + rv = read(fds_totracee[0], &msg, sizeof(msg)); + FORKEE_ASSERT(rv == sizeof(msg)); + + namelen = 0; + name[namelen++] = CTL_KERN; + name[namelen++] = KERN_PROC2; + name[namelen++] = KERN_PROC_PID; + name[namelen++] = getpid(); + name[namelen++] = len; + name[namelen++] = 1; + + FORKEE_ASSERT(sysctl(name, namelen, &kp, &len, NULL, 0) == 0); + FORKEE_ASSERT_EQ(parent, kp.p_ppid); + + _exit(exitval_tracee); + } + ATF_REQUIRE(close(fds_totracee[0]) == 0); + ATF_REQUIRE(close(fds_fromtracee[1]) == 0); + + printf("Wait for child to record its parent identifier (pid)\n"); + rv = read(fds_fromtracee[0], &msg, sizeof(msg)); + FORKEE_ASSERT(rv == sizeof(msg)); + rv = write(fds_totracee[1], &msg, sizeof(msg)); + FORKEE_ASSERT(rv == sizeof(msg)); + rv = read(fds_fromtracee[0], &msg, sizeof(msg)); + FORKEE_ASSERT(rv == sizeof(msg)); + + printf("Spawn debugger\n"); + ATF_REQUIRE(pipe(fds_totracer) == 0); + ATF_REQUIRE(pipe(fds_fromtracer) == 0); + tracer = atf_utils_fork(); + if (tracer == 0) { + /* No IPC to communicate with the child */ + FORKEE_ASSERT(close(fds_totracee[1]) == 0); + FORKEE_ASSERT(close(fds_fromtracee[0]) == 0); + + FORKEE_ASSERT(close(fds_totracer[1]) == 0); + FORKEE_ASSERT(close(fds_fromtracer[0]) == 0); + + printf("Before calling PT_ATTACH from tracee %d\n", getpid()); + FORKEE_ASSERT(ptrace(PT_ATTACH, tracee, NULL, 0) != -1); + + /* Wait for tracee and assert that it was stopped w/ SIGSTOP */ + FORKEE_REQUIRE_SUCCESS( + wpid = TWAIT_GENERIC(tracee, &status, 0), tracee); + + forkee_status_stopped(status, SIGSTOP); + + /* Resume tracee with PT_CONTINUE */ + FORKEE_ASSERT(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1); + + /* Inform parent that tracer has attached to tracee */ + rv = write(fds_fromtracer[1], &msg, sizeof(msg)); + FORKEE_ASSERT(rv == sizeof(msg)); + + /* Wait for parent */ + rv = read(fds_totracer[0], &msg, sizeof(msg)); + FORKEE_ASSERT(rv == sizeof(msg)); + + /* Wait for tracee and assert that it exited */ + FORKEE_REQUIRE_SUCCESS( + wpid = TWAIT_GENERIC(tracee, &status, 0), tracee); + + forkee_status_exited(status, exitval_tracee); + + printf("Before exiting of the tracer process\n"); + _exit(exitval_tracer); + } + ATF_REQUIRE(close(fds_totracer[0]) == 0); + ATF_REQUIRE(close(fds_fromtracer[1]) == 0); + + printf("Wait for the tracer to attach to the tracee\n"); + rv = read(fds_fromtracer[0], &msg, sizeof(msg)); + ATF_REQUIRE(rv == sizeof(msg)); + + printf("Resume the tracee and let it exit\n"); + rv = write(fds_totracee[1], &msg, sizeof(msg)); + ATF_REQUIRE(rv == sizeof(msg)); + + printf("fds_totracee is no longer needed - close it\n"); + ATF_REQUIRE(close(fds_totracee[1]) == 0); + + printf("fds_fromtracee is no longer needed - close it\n"); + ATF_REQUIRE(close(fds_fromtracee[0]) == 0); + + printf("Detect that tracee is zombie\n"); + await_zombie(tracee); + + printf("Assert that there is no status about tracee - " + "Tracer must detect zombie first - calling %s()\n", TWAIT_FNAME); + TWAIT_REQUIRE_SUCCESS( + wpid = TWAIT_GENERIC(tracee, &status, WNOHANG), 0); + + printf("Resume the tracer and let it detect exited tracee\n"); + rv = write(fds_totracer[1], &msg, sizeof(msg)); + ATF_REQUIRE(rv == sizeof(msg)); + + printf("Wait for tracer to finish its job and exit - calling %s()\n", + TWAIT_FNAME); + TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracer, &status, 0), + tracer); + + validate_status_exited(status, exitval_tracer); + + printf("Wait for tracee to finish its job and exit - calling %s()\n", + TWAIT_FNAME); + TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracee, &status, WNOHANG), + tracee); + + validate_status_exited(status, exitval_tracee); + + printf("fds_fromtracer is no longer needed - close it\n"); + ATF_REQUIRE(close(fds_fromtracer[0]) == 0); + + printf("fds_totracer is no longer needed - close it\n"); + ATF_REQUIRE(close(fds_totracer[1]) == 0); +} +#endif + +#if defined(TWAIT_HAVE_PID) +ATF_TC(attach7); +ATF_TC_HEAD(attach7, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Assert that tracer sees its parent when attached to tracer " + "(check /proc/curproc/status 3rd column)"); +} + +ATF_TC_BODY(attach7, tc) +{ + int fds_totracee[2], fds_fromtracee[2]; + int fds_totracer[2], fds_fromtracer[2]; + int rv; + const int exitval_tracee = 5; + const int exitval_tracer = 10; + pid_t parent, tracee, tracer, wpid; + uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */ +#if defined(TWAIT_HAVE_STATUS) + int status; +#endif + FILE *fp; + struct stat st; + const char *fname = "/proc/curproc/status"; + char s_executable[MAXPATHLEN]; + int s_pid, s_ppid; /* - * Tracee process cannot see its appropriate parent when debugged by a - * tracer + * Format: + * EXECUTABLE PID PPID ... */ + + ATF_REQUIRE((rv = stat(fname, &st)) == 0 || (errno == ENOENT)); + if (rv != 0) { + atf_tc_skip("/proc/curproc/stat not found"); + } + printf("Spawn tracee\n"); ATF_REQUIRE(pipe(fds_totracee) == 0); ATF_REQUIRE(pipe(fds_fromtracee) == 0); @@ -1050,7 +1377,10 @@ ATF_TC_BODY(attach5, tc) rv = read(fds_totracee[0], &msg, sizeof(msg)); FORKEE_ASSERT(rv == sizeof(msg)); - FORKEE_ASSERT_EQ(parent, getppid()); + FORKEE_ASSERT((fp = fopen(fname, "r")) != NULL); + fscanf(fp, "%s %d %d", s_executable, &s_pid, &s_ppid); + FORKEE_ASSERT(fclose(fp) == 0); + FORKEE_ASSERT_EQ(parent, s_ppid); _exit(exitval_tracee); } @@ -1177,6 +1507,8 @@ ATF_TP_ADD_TCS(tp) ATF_TP_ADD_TC(tp, attach3); ATF_TP_ADD_TC(tp, attach4); ATF_TP_ADD_TC_HAVE_PID(tp, attach5); + ATF_TP_ADD_TC_HAVE_PID(tp, attach6); + ATF_TP_ADD_TC_HAVE_PID(tp, attach7); return atf_no_error(); }