1 /* $NetBSD: t_ptrace_core_wait.h,v 1.10 2025/05/02 02:24:32 riastradh Exp $ */ 2 3 /*- 4 * Copyright (c) 2016, 2017, 2018, 2019, 2020 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 /* 30 * Parse the core file and find the requested note. If the reading or parsing 31 * fails, the test is failed. If the note is found, it is read onto buf, up to 32 * buf_len. The actual length of the note is returned (which can be greater 33 * than buf_len, indicating that it has been truncated). If the note is not 34 * found, -1 is returned. 35 * 36 * If the note_name ends in '*', then we find the first note that matches 37 * the note_name prefix up to the '*' character, e.g.: 38 * 39 * NetBSD-CORE@* 40 * 41 * finds the first note whose name prefix matches "NetBSD-CORE@". 42 */ 43 static ssize_t core_find_note(const char *core_path, 44 const char *note_name, uint64_t note_type, void *buf, size_t buf_len) 45 { 46 int core_fd; 47 Elf *core_elf; 48 size_t core_numhdr, i; 49 ssize_t ret = -1; 50 size_t name_len = strlen(note_name); 51 bool prefix_match = false; 52 53 if (note_name[name_len - 1] == '*') { 54 prefix_match = true; 55 name_len--; 56 } else { 57 /* note: we assume note name will be null-terminated */ 58 name_len++; 59 } 60 61 SYSCALL_REQUIRE((core_fd = open(core_path, O_RDONLY)) != -1); 62 SYSCALL_REQUIRE(elf_version(EV_CURRENT) != EV_NONE); 63 SYSCALL_REQUIRE((core_elf = elf_begin(core_fd, ELF_C_READ, NULL))); 64 65 SYSCALL_REQUIRE(elf_getphnum(core_elf, &core_numhdr) != 0); 66 for (i = 0; i < core_numhdr && ret == -1; i++) { 67 GElf_Phdr core_hdr; 68 size_t offset; 69 SYSCALL_REQUIRE(gelf_getphdr(core_elf, i, &core_hdr)); 70 if (core_hdr.p_type != PT_NOTE) 71 continue; 72 73 for (offset = core_hdr.p_offset; 74 offset < core_hdr.p_offset + core_hdr.p_filesz;) { 75 Elf64_Nhdr note_hdr; 76 char name_buf[64]; 77 78 switch (gelf_getclass(core_elf)) { 79 case ELFCLASS64: 80 SYSCALL_REQUIRE(pread(core_fd, ¬e_hdr, 81 sizeof(note_hdr), offset) 82 == sizeof(note_hdr)); 83 offset += sizeof(note_hdr); 84 break; 85 case ELFCLASS32: 86 { 87 Elf32_Nhdr tmp_hdr; 88 SYSCALL_REQUIRE(pread(core_fd, &tmp_hdr, 89 sizeof(tmp_hdr), offset) 90 == sizeof(tmp_hdr)); 91 offset += sizeof(tmp_hdr); 92 note_hdr.n_namesz = tmp_hdr.n_namesz; 93 note_hdr.n_descsz = tmp_hdr.n_descsz; 94 note_hdr.n_type = tmp_hdr.n_type; 95 } 96 break; 97 } 98 99 /* indicates end of notes */ 100 if (note_hdr.n_namesz == 0 || note_hdr.n_descsz == 0) 101 break; 102 if (((prefix_match && 103 note_hdr.n_namesz > name_len) || 104 (!prefix_match && 105 note_hdr.n_namesz == name_len)) && 106 note_hdr.n_namesz <= sizeof(name_buf)) { 107 SYSCALL_REQUIRE(pread(core_fd, name_buf, 108 note_hdr.n_namesz, offset) 109 == (ssize_t)(size_t)note_hdr.n_namesz); 110 111 if (!strncmp(note_name, name_buf, name_len) && 112 note_hdr.n_type == note_type) 113 ret = note_hdr.n_descsz; 114 } 115 116 offset += note_hdr.n_namesz; 117 /* fix to alignment */ 118 offset = roundup(offset, core_hdr.p_align); 119 120 /* if name & type matched above */ 121 if (ret != -1) { 122 ssize_t read_len = MIN(buf_len, 123 note_hdr.n_descsz); 124 SYSCALL_REQUIRE(pread(core_fd, buf, 125 read_len, offset) == read_len); 126 break; 127 } 128 129 offset += note_hdr.n_descsz; 130 /* fix to alignment */ 131 offset = roundup(offset, core_hdr.p_align); 132 } 133 } 134 135 elf_end(core_elf); 136 close(core_fd); 137 138 return ret; 139 } 140 141 ATF_TC(core_dump_procinfo); 142 ATF_TC_HEAD(core_dump_procinfo, tc) 143 { 144 atf_tc_set_md_var(tc, "descr", 145 "Trigger a core dump and verify its contents."); 146 } 147 148 ATF_TC_BODY(core_dump_procinfo, tc) 149 { 150 const int exitval = 5; 151 pid_t child, wpid; 152 #if defined(TWAIT_HAVE_STATUS) 153 const int sigval = SIGTRAP; 154 int status; 155 #endif 156 char core_path[] = "/tmp/core.XXXXXX"; 157 int core_fd; 158 struct netbsd_elfcore_procinfo procinfo; 159 160 DPRINTF("Before forking process PID=%d\n", getpid()); 161 SYSCALL_REQUIRE((child = fork()) != -1); 162 if (child == 0) { 163 DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid()); 164 FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1); 165 166 DPRINTF("Before triggering SIGTRAP\n"); 167 trigger_trap(); 168 169 DPRINTF("Before exiting of the child process\n"); 170 _exit(exitval); 171 } 172 DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child); 173 174 DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME); 175 TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child); 176 177 validate_status_stopped(status, sigval); 178 179 SYSCALL_REQUIRE((core_fd = mkstemp(core_path)) != -1); 180 close(core_fd); 181 182 DPRINTF("Call DUMPCORE for the child process\n"); 183 SYSCALL_REQUIRE(ptrace(PT_DUMPCORE, child, core_path, strlen(core_path)) 184 != -1); 185 186 DPRINTF("Read core file\n"); 187 ATF_REQUIRE_EQ(core_find_note(core_path, "NetBSD-CORE", 188 ELF_NOTE_NETBSD_CORE_PROCINFO, &procinfo, sizeof(procinfo)), 189 sizeof(procinfo)); 190 191 ATF_CHECK_EQ(procinfo.cpi_version, 1); 192 ATF_CHECK_EQ(procinfo.cpi_cpisize, sizeof(procinfo)); 193 ATF_CHECK_EQ(procinfo.cpi_signo, SIGTRAP); 194 ATF_CHECK_EQ(procinfo.cpi_pid, child); 195 ATF_CHECK_EQ(procinfo.cpi_ppid, getpid()); 196 ATF_CHECK_EQ(procinfo.cpi_pgrp, getpgid(child)); 197 ATF_CHECK_EQ(procinfo.cpi_sid, getsid(child)); 198 ATF_CHECK_EQ(procinfo.cpi_ruid, getuid()); 199 ATF_CHECK_EQ(procinfo.cpi_euid, geteuid()); 200 ATF_CHECK_EQ(procinfo.cpi_rgid, getgid()); 201 ATF_CHECK_EQ(procinfo.cpi_egid, getegid()); 202 ATF_CHECK_EQ(procinfo.cpi_nlwps, 1); 203 ATF_CHECK(procinfo.cpi_siglwp > 0); 204 205 unlink(core_path); 206 207 DPRINTF("Before resuming the child process where it left off and " 208 "without signal to be sent\n"); 209 210 #if defined(__aarch64__) || defined(__arm__) || defined(__hppa__) || \ 211 defined(__powerpc__) || defined(__riscv__) || defined(__sh3__) || \ 212 defined(sparc) || defined(__vax__) 213 /* 214 * For these archs, program counter is not automatically incremented 215 * by a trap instruction. We cannot increment PC in the trap handler, 216 * which breaks applications depending on this behavior, e.g., GDB. 217 * Therefore, we need to pass PC++ instead of (void *)1 (== PC) to 218 * PT_CONTINUE here. 219 */ 220 struct reg r; 221 222 SYSCALL_REQUIRE(ptrace(PT_GETREGS, child, &r, 0) != -1); 223 SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, 224 (void *)(PTRACE_REG_PC(&r) + PTRACE_BREAKPOINT_SIZE), 0) != -1); 225 #else 226 SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1); 227 #endif 228 229 DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME); 230 TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child); 231 232 validate_status_exited(status, exitval); 233 234 DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME); 235 TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0)); 236 } 237 238 #define ATF_TP_ADD_TCS_PTRACE_WAIT_CORE() \ 239 ATF_TP_ADD_TC(tp, core_dump_procinfo); 240