Module Name: src Committed By: mgorny Date: Sun Jun 30 21:20:04 UTC 2019
Modified Files: src/tests/lib/libc/sys: Makefile t_ptrace_wait.c Log Message: Add a test for verifying procinfo note inside coredumps. Add a first test for triggering a core dump in the debugged process (via PT_DUMPCORE) and verifying it. The test finds procinfo note and checks its contents. The core dump is processed through libelf. However, it only provides for finding all note segments (or sections?). I had to implement finding and processing individual notes myself. I've added a core_find_note() function that will be reused in future tests. Reviewed by kamil. To generate a diff of this commit: cvs rdiff -u -r1.56 -r1.57 src/tests/lib/libc/sys/Makefile cvs rdiff -u -r1.129 -r1.130 src/tests/lib/libc/sys/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/lib/libc/sys/Makefile diff -u src/tests/lib/libc/sys/Makefile:1.56 src/tests/lib/libc/sys/Makefile:1.57 --- src/tests/lib/libc/sys/Makefile:1.56 Fri Apr 26 20:41:10 2019 +++ src/tests/lib/libc/sys/Makefile Sun Jun 30 21:20:04 2019 @@ -1,4 +1,4 @@ -# $NetBSD: Makefile,v 1.56 2019/04/26 20:41:10 maya Exp $ +# $NetBSD: Makefile,v 1.57 2019/06/30 21:20:04 mgorny Exp $ MKMAN= no @@ -88,12 +88,12 @@ SRCS.t_mprotect= t_mprotect.c ${SRCS_EXE LDADD.t_getpid+= -lpthread -LDADD.t_ptrace_wait+= -pthread -lm -LDADD.t_ptrace_wait3+= -pthread -lm -LDADD.t_ptrace_wait4+= -pthread -lm -LDADD.t_ptrace_wait6+= -pthread -lm -LDADD.t_ptrace_waitid+= -pthread -lm -LDADD.t_ptrace_waitpid+= -pthread -lm +LDADD.t_ptrace_wait+= -pthread -lm -lelf +LDADD.t_ptrace_wait3+= -pthread -lm -lelf +LDADD.t_ptrace_wait4+= -pthread -lm -lelf +LDADD.t_ptrace_wait6+= -pthread -lm -lelf +LDADD.t_ptrace_waitid+= -pthread -lm -lelf +LDADD.t_ptrace_waitpid+= -pthread -lm -lelf .if (${MKRUMP} != "no") && !defined(BSD_MK_COMPAT_FILE) CPPFLAGS.t_posix_fadvise.c += -D_KERNTYPES Index: src/tests/lib/libc/sys/t_ptrace_wait.c diff -u src/tests/lib/libc/sys/t_ptrace_wait.c:1.129 src/tests/lib/libc/sys/t_ptrace_wait.c:1.130 --- src/tests/lib/libc/sys/t_ptrace_wait.c:1.129 Wed Jun 26 12:30:13 2019 +++ src/tests/lib/libc/sys/t_ptrace_wait.c Sun Jun 30 21:20:04 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: t_ptrace_wait.c,v 1.129 2019/06/26 12:30:13 mgorny Exp $ */ +/* $NetBSD: t_ptrace_wait.c,v 1.130 2019/06/30 21:20:04 mgorny Exp $ */ /*- * Copyright (c) 2016, 2017, 2018, 2019 The NetBSD Foundation, Inc. @@ -27,10 +27,11 @@ */ #include <sys/cdefs.h> -__RCSID("$NetBSD: t_ptrace_wait.c,v 1.129 2019/06/26 12:30:13 mgorny Exp $"); +__RCSID("$NetBSD: t_ptrace_wait.c,v 1.130 2019/06/30 21:20:04 mgorny Exp $"); #include <sys/param.h> #include <sys/types.h> +#include <sys/exec_elf.h> #include <sys/mman.h> #include <sys/ptrace.h> #include <sys/resource.h> @@ -43,6 +44,7 @@ __RCSID("$NetBSD: t_ptrace_wait.c,v 1.12 #include <elf.h> #include <err.h> #include <errno.h> +#include <fcntl.h> #include <lwp.h> #include <pthread.h> #include <sched.h> @@ -66,6 +68,9 @@ __RCSID("$NetBSD: t_ptrace_wait.c,v 1.12 #include <x86/specialreg.h> #endif +#include <libelf.h> +#include <gelf.h> + #include <atf-c.h> #include "h_macros.h" @@ -7639,6 +7644,180 @@ USER_VA0_DISABLE(user_va0_disable_pt_det /// ---------------------------------------------------------------------------- +/* + * Parse the core file and find the requested note. If the reading or parsing + * fails, the test is failed. If the note is found, it is read onto buf, up to + * buf_len. The actual length of the note is returned (which can be greater + * than buf_len, indicating that it has been truncated). If the note is not + * found, -1 is returned. + */ +static ssize_t core_find_note(const char *core_path, + const char *note_name, uint64_t note_type, void *buf, size_t buf_len) +{ + int core_fd; + Elf *core_elf; + size_t core_numhdr, i; + ssize_t ret = -1; + /* note: we assume note name will be null-terminated */ + size_t name_len = strlen(note_name) + 1; + + SYSCALL_REQUIRE((core_fd = open(core_path, O_RDONLY)) != -1); + SYSCALL_REQUIRE(elf_version(EV_CURRENT) != EV_NONE); + SYSCALL_REQUIRE((core_elf = elf_begin(core_fd, ELF_C_READ, NULL))); + + SYSCALL_REQUIRE(elf_getphnum(core_elf, &core_numhdr) != 0); + for (i = 0; i < core_numhdr && ret == -1; i++) { + GElf_Phdr core_hdr; + size_t offset; + SYSCALL_REQUIRE(gelf_getphdr(core_elf, i, &core_hdr)); + if (core_hdr.p_type != PT_NOTE) + continue; + + for (offset = core_hdr.p_offset; + offset < core_hdr.p_offset + core_hdr.p_filesz;) { + Elf64_Nhdr note_hdr; + char name_buf[64]; + + switch (gelf_getclass(core_elf)) { + case ELFCLASS64: + SYSCALL_REQUIRE(pread(core_fd, ¬e_hdr, + sizeof(note_hdr), offset) + == sizeof(note_hdr)); + offset += sizeof(note_hdr); + break; + case ELFCLASS32: + { + Elf32_Nhdr tmp_hdr; + SYSCALL_REQUIRE(pread(core_fd, &tmp_hdr, + sizeof(tmp_hdr), offset) + == sizeof(tmp_hdr)); + offset += sizeof(tmp_hdr); + note_hdr.n_namesz = tmp_hdr.n_namesz; + note_hdr.n_descsz = tmp_hdr.n_descsz; + note_hdr.n_type = tmp_hdr.n_type; + } + break; + } + + /* indicates end of notes */ + if (note_hdr.n_namesz == 0 || note_hdr.n_descsz == 0) + break; + if (note_hdr.n_namesz == name_len && + note_hdr.n_namesz <= sizeof(name_buf)) { + SYSCALL_REQUIRE(pread(core_fd, name_buf, + note_hdr.n_namesz, offset) + == note_hdr.n_namesz); + + if (!strncmp(note_name, name_buf, name_len) && + note_hdr.n_type == note_type) + ret = note_hdr.n_descsz; + } + + offset += note_hdr.n_namesz; + /* fix to alignment */ + offset = ((offset + core_hdr.p_align - 1) + / core_hdr.p_align) * core_hdr.p_align; + + /* if name & type matched above */ + if (ret != -1) { + ssize_t read_len = MIN(buf_len, + note_hdr.n_descsz); + SYSCALL_REQUIRE(pread(core_fd, buf, + read_len, offset) == read_len); + break; + } + + offset += note_hdr.n_descsz; + } + } + + elf_end(core_elf); + close(core_fd); + + return ret; +} + +ATF_TC(core_dump_procinfo); +ATF_TC_HEAD(core_dump_procinfo, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Trigger a core dump and verify its contents."); +} + +ATF_TC_BODY(core_dump_procinfo, tc) +{ + const int exitval = 5; + pid_t child, wpid; +#if defined(TWAIT_HAVE_STATUS) + const int sigval = SIGTRAP; + int status; +#endif + char core_path[] = "/tmp/core.XXXXXX"; + int core_fd; + struct netbsd_elfcore_procinfo procinfo; + + DPRINTF("Before forking process PID=%d\n", getpid()); + SYSCALL_REQUIRE((child = fork()) != -1); + if (child == 0) { + DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid()); + FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1); + + DPRINTF("Before triggering SIGTRAP\n"); + trigger_trap(); + + DPRINTF("Before exiting of the child process\n"); + _exit(exitval); + } + DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child); + + DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME); + TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child); + + validate_status_stopped(status, sigval); + + SYSCALL_REQUIRE((core_fd = mkstemp(core_path)) != -1); + close(core_fd); + + DPRINTF("Call DUMPCORE for the child process\n"); + SYSCALL_REQUIRE(ptrace(PT_DUMPCORE, child, core_path, strlen(core_path)) + != -1); + + DPRINTF("Read core file\n"); + ATF_REQUIRE_EQ(core_find_note(core_path, "NetBSD-CORE", + ELF_NOTE_NETBSD_CORE_PROCINFO, &procinfo, sizeof(procinfo)), + sizeof(procinfo)); + + ATF_CHECK_EQ(procinfo.cpi_version, 1); + ATF_CHECK_EQ(procinfo.cpi_cpisize, sizeof(procinfo)); + ATF_CHECK_EQ(procinfo.cpi_signo, SIGTRAP); + ATF_CHECK_EQ(procinfo.cpi_pid, child); + ATF_CHECK_EQ(procinfo.cpi_ppid, getpid()); + ATF_CHECK_EQ(procinfo.cpi_pgrp, getpgid(child)); + ATF_CHECK_EQ(procinfo.cpi_sid, getsid(child)); + ATF_CHECK_EQ(procinfo.cpi_ruid, getuid()); + ATF_CHECK_EQ(procinfo.cpi_euid, geteuid()); + ATF_CHECK_EQ(procinfo.cpi_rgid, getgid()); + ATF_CHECK_EQ(procinfo.cpi_egid, getegid()); + ATF_CHECK_EQ(procinfo.cpi_nlwps, 1); + ATF_CHECK_EQ(procinfo.cpi_siglwp, 1); + + unlink(core_path); + + DPRINTF("Before resuming the child process where it left off and " + "without signal to be sent\n"); + SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1); + + DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME); + TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child); + + validate_status_exited(status, exitval); + + DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME); + TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0)); +} + +/// ---------------------------------------------------------------------------- + #include "t_ptrace_amd64_wait.h" #include "t_ptrace_i386_wait.h" #include "t_ptrace_x86_wait.h" @@ -8130,6 +8309,8 @@ ATF_TP_ADD_TCS(tp) ATF_TP_ADD_TC(tp, user_va0_disable_pt_syscall); ATF_TP_ADD_TC(tp, user_va0_disable_pt_detach); + ATF_TP_ADD_TC(tp, core_dump_procinfo); + ATF_TP_ADD_TCS_PTRACE_WAIT_AMD64(); ATF_TP_ADD_TCS_PTRACE_WAIT_I386(); ATF_TP_ADD_TCS_PTRACE_WAIT_X86();