# HG changeset patch # User Taylor R Campbell # Date 1739897753 0 # Tue Feb 18 16:55:53 2025 +0000 # Branch trunk # Node ID bc3c70c24c866c9cf171734b393e50a42edb9637 # Parent 21a87af07c21c0dcfa6bf7753f80c7a2e37eaf2a # EXP-Topic riastradh-pr59085-execregleak Test whether exec/spawn will zero registers. Currently implemented only for a handful of architectures; should extend this to all the others, and extend as appropriate if we find more register content is worth testing (like maybe vector registers, but they are managed differently anyway and less likely to leak). VAX test contributed (and tested) by Kalvis Duckmanton, with some tweaks by me; the others written and tested by me. IA64 skipped, even though I suspect it _would_ leak if the kernel code ran as is, because I have no way to test it. PR kern/59084: exec/spawn leaks register content diff -r 21a87af07c21 -r bc3c70c24c86 distrib/sets/lists/debug/mi --- a/distrib/sets/lists/debug/mi Fri Feb 21 03:17:27 2025 +0000 +++ b/distrib/sets/lists/debug/mi Tue Feb 18 16:55:53 2025 +0000 @@ -1770,6 +1770,7 @@ ./usr/libdata/debug/usr/tests/kernel/arch/i386/t_ptrace_waitid.debug tests-obsolete obsolete,compattestfile ./usr/libdata/debug/usr/tests/kernel/arch/i386/t_ptrace_waitpid.debug tests-obsolete obsolete,compattestfile ./usr/libdata/debug/usr/tests/kernel/h_cloexec.debug tests-kernel-tests debug,atf,compattestfile +./usr/libdata/debug/usr/tests/kernel/h_execregs.debug tests-kernel-tests debug,atf,compattestfile ./usr/libdata/debug/usr/tests/kernel/h_fexecve.debug tests-kernel-tests debug,atf,compattestfile ./usr/libdata/debug/usr/tests/kernel/h_fpufork.debug tests-kernel-tests debug,atf,compattestfile ./usr/libdata/debug/usr/tests/kernel/h_getprocpath.debug tests-kernel-tests debug,atf,compattestfile @@ -1803,6 +1804,7 @@ ./usr/libdata/debug/usr/tests/kernel/posix_spawn/t_spawnattr.debug tests-obsolete obsolete,compattestfile ./usr/libdata/debug/usr/tests/kernel/t_cloexec.debug tests-kernel-tests debug,atf,compattestfile ./usr/libdata/debug/usr/tests/kernel/t_epoll.debug tests-obsolete obsolete,compattestfile +./usr/libdata/debug/usr/tests/kernel/t_execregs.debug tests-kernel-tests debug,atf,compattestfile ./usr/libdata/debug/usr/tests/kernel/t_extattrctl.debug tests-kernel-tests debug,atf,rump ./usr/libdata/debug/usr/tests/kernel/t_extent.debug tests-kernel-tests debug,atf,compattestfile ./usr/libdata/debug/usr/tests/kernel/t_fcntl.debug tests-kernel-tests debug,atf diff -r 21a87af07c21 -r bc3c70c24c86 distrib/sets/lists/tests/mi --- a/distrib/sets/lists/tests/mi Fri Feb 21 03:17:27 2025 +0000 +++ b/distrib/sets/lists/tests/mi Tue Feb 18 16:55:53 2025 +0000 @@ -2269,6 +2269,7 @@ ./usr/tests/kernel/arch/i386/t_ptrace_waitpid tests-obsolete obsolete ./usr/tests/kernel/arch/x86 tests-obsolete obsolete ./usr/tests/kernel/h_cloexec tests-kernel-tests compattestfile,atf +./usr/tests/kernel/h_execregs tests-kernel-tests compattestfile,atf ./usr/tests/kernel/h_fexecve tests-kernel-tests compattestfile,atf ./usr/tests/kernel/h_fpufork tests-kernel-tests compattestfile,atf ./usr/tests/kernel/h_getprocpath tests-kernel-tests compattestfile,atf @@ -2316,6 +2317,7 @@ ./usr/tests/kernel/posix_spawn/t_spawnattr tests-obsolete obsolete ./usr/tests/kernel/t_cloexec tests-kernel-tests compattestfile,atf ./usr/tests/kernel/t_epoll tests-obsolete obsolete +./usr/tests/kernel/t_execregs tests-kernel-tests compattestfile,atf ./usr/tests/kernel/t_extattrctl tests-kernel-tests atf,rump ./usr/tests/kernel/t_extent tests-kernel-tests compattestfile,atf ./usr/tests/kernel/t_fcntl tests-kernel-tests atf diff -r 21a87af07c21 -r bc3c70c24c86 tests/kernel/Makefile --- a/tests/kernel/Makefile Fri Feb 21 03:17:27 2025 +0000 +++ b/tests/kernel/Makefile Tue Feb 18 16:55:53 2025 +0000 @@ -9,6 +9,7 @@ TESTSDIR= ${TESTSBASE}/kernel TESTS_SUBDIRS+= kqueue TESTS_C+= t_cloexec #TESTS_C+= t_epoll +TESTS_C+= t_execregs TESTS_C+= t_fcntl .if ${MKRUMP} != "no" TESTS_C+= t_fdrestart @@ -51,6 +52,7 @@ TESTS_SH+= t_umount BINDIR= ${TESTSDIR} PROGS+= h_cloexec +PROGS+= h_execregs PROGS+= h_fexecve PROGS+= h_fpufork PROGS+= h_getprocpath @@ -132,4 +134,16 @@ CLEANFILES+= t_subr_prf.c LDADD.h_segv+= -lm +.if exists(arch/${MACHINE_ARCH}/execregs.h) +ARCHDIR:= ${.PARSEDIR}/arch/${MACHINE_ARCH} +.PATH: ${ARCHDIR} +CPPFLAGS.t_execregs.c+= -I${ARCHDIR} +CPPFLAGS.t_execregs.c+= -DHAVE_EXECREGS_TEST +SRCS.t_execregs+= t_execregs.c +SRCS.t_execregs+= execregs.c +LDFLAGS.h_execregs+= -static -Wl,-e,execregs_start +.else +SRCS.h_execregs= h_execregs_unimpl.c +.endif + .include diff -r 21a87af07c21 -r bc3c70c24c86 tests/kernel/arch/aarch64/execregs.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/kernel/arch/aarch64/execregs.c Tue Feb 18 16:55:53 2025 +0000 @@ -0,0 +1,226 @@ +/* $NetBSD$ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__RCSID("$NetBSD$"); + +#include "execregs.h" + +#include +#include +#include +#include + +extern char **environ; + +static unsigned long +nonnull(unsigned long x) +{ + + x |= x << 8; + x |= x << 16; + x |= x << 32; + return x; +} + +int +execregschild(char *path) +{ + /* x0: used to pass exec arg0, nonnull anyway (path) */ + /* x1: used to pass exec arg1, nonnull anyway (argv) */ + /* x2: used to pass exec arg2, nonnull anyway (environ) */ + register long x3 __asm("x3") = nonnull(3); + register long x4 __asm("x4") = nonnull(4); + register long x5 __asm("x5") = nonnull(5); + register long x6 __asm("x6") = nonnull(6); + register long x7 __asm("x7") = nonnull(7); + register long x8 __asm("x8") = nonnull(8); + register long x9 __asm("x9") = nonnull(9); + register long x10 __asm("x10") = nonnull(10); + register long x11 __asm("x11") = nonnull(11); + register long x12 __asm("x12") = nonnull(12); + register long x13 __asm("x13") = nonnull(13); + register long x14 __asm("x14") = nonnull(14); + register long x15 __asm("x15") = nonnull(15); + register long x16 __asm("x16") = nonnull(16); + register long x17 __asm("x17") = nonnull(17); + register long x18 __asm("x18") = nonnull(18); + register long x19 __asm("x19") = nonnull(19); + register long x20 __asm("x20") = nonnull(20); + register long x21 __asm("x21") = nonnull(21); + register long x22 __asm("x22") = nonnull(22); + register long x23 __asm("x23") = nonnull(23); + register long x24 __asm("x24") = nonnull(24); + register long x25 __asm("x25") = nonnull(25); + register long x26 __asm("x26") = nonnull(26); + register long x27 __asm("x27") = nonnull(27); + register long x28 __asm("x28") = nonnull(28); + /* x29: frame pointer, nonnull anyway */ + /* x30: link register, nonnull anyway */ + + char *argv[] = {path, NULL}; + char **envp = environ; + + /* + * Not perfect -- compiler might use some registers for + * stack/argument transfers, but all the arguments are nonnull + * so this is probably a good test anyway. + */ + __asm volatile("" : + "+r"(x3), + "+r"(x4), + "+r"(x5), + "+r"(x6), + "+r"(x7), + "+r"(x8), + "+r"(x9), + "+r"(x10), + "+r"(x11), + "+r"(x12), + "+r"(x13), + "+r"(x14), + "+r"(x15), + "+r"(x16), + "+r"(x17) + :: "memory"); + /* pacify gcc error: more than 30 operands in 'asm' */ + __asm volatile("" : + "+r"(x18), + "+r"(x19), + "+r"(x20), + "+r"(x21), + "+r"(x22), + "+r"(x23), + "+r"(x24), + "+r"(x25), + "+r"(x26), + "+r"(x27), + "+r"(x28) + :: "memory"); + + return execve(path, argv, envp); +} + +pid_t +spawnregschild(char *path, int fd) +{ + /* x0: used to pass posix_spawn arg0, nonnull anyway (&pid) */ + /* x1: used to pass posix_spawn arg1, nonnull anyway (path) */ + /* x2: used to pass posix_spawn arg2, nonnull anyway (&fileacts) */ + /* x3: used to pass posix_spawn arg3, nonnull anyway (&attr) */ + /* x4: used to pass posix_spawn arg3, nonnull anyway (argv) */ + /* x5: used to pass posix_spawn arg3, nonnull anyway (environ) */ + register long x6 __asm("x6") = nonnull(6); + register long x7 __asm("x7") = nonnull(7); + register long x8 __asm("x8") = nonnull(8); + register long x9 __asm("x9") = nonnull(9); + register long x10 __asm("x10") = nonnull(10); + register long x11 __asm("x11") = nonnull(11); + register long x12 __asm("x12") = nonnull(12); + register long x13 __asm("x13") = nonnull(13); + register long x14 __asm("x14") = nonnull(14); + register long x15 __asm("x15") = nonnull(15); + register long x16 __asm("x16") = nonnull(16); + register long x17 __asm("x17") = nonnull(17); + register long x18 __asm("x18") = nonnull(18); + register long x19 __asm("x19") = nonnull(19); + register long x20 __asm("x20") = nonnull(20); + register long x21 __asm("x21") = nonnull(21); + register long x22 __asm("x22") = nonnull(22); + register long x23 __asm("x23") = nonnull(23); + register long x24 __asm("x24") = nonnull(24); + register long x25 __asm("x25") = nonnull(25); + register long x26 __asm("x26") = nonnull(26); + register long x27 __asm("x27") = nonnull(27); + register long x28 __asm("x28") = nonnull(28); + /* x29: frame pointer, nonnull anyway */ + /* x30: link register, nonnull anyway */ + + char *argv[] = {path, NULL}; + char **envp = environ; + posix_spawn_file_actions_t fileacts; + posix_spawnattr_t attr; + pid_t pid; + int error; + + error = posix_spawn_file_actions_init(&fileacts); + if (error) + goto out; + error = posix_spawn_file_actions_adddup2(&fileacts, fd, STDOUT_FILENO); + if (error) + goto out; + error = posix_spawnattr_init(&attr); + if (error) + goto out; + + /* + * Not perfect -- compiler might use some registers for + * stack/argument transfers, but all the arguments are nonnull + * so this is probably a good test anyway. + */ + __asm volatile("" : + "+r"(x6), + "+r"(x7), + "+r"(x8), + "+r"(x9), + "+r"(x10), + "+r"(x11), + "+r"(x12), + "+r"(x13), + "+r"(x14), + "+r"(x15), + "+r"(x16), + "+r"(x17), + "+r"(x18), + "+r"(x19), + "+r"(x20) + :: "memory"); + /* pacify gcc error: more than 30 operands in 'asm' */ + __asm volatile("" : + "+r"(x21), + "+r"(x22), + "+r"(x23), + "+r"(x24), + "+r"(x25), + "+r"(x26), + "+r"(x27), + "+r"(x28) + :: "memory"); + + error = posix_spawn(&pid, path, &fileacts, &attr, argv, envp); + if (error) + goto out; + +out: posix_spawnattr_destroy(&attr); + posix_spawn_file_actions_destroy(&fileacts); + if (error) { + errno = error; + return -1; + } + return 0; +} diff -r 21a87af07c21 -r bc3c70c24c86 tests/kernel/arch/aarch64/execregs.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/kernel/arch/aarch64/execregs.h Tue Feb 18 16:55:53 2025 +0000 @@ -0,0 +1,86 @@ +/* $NetBSD$ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TESTS_KERNEL_ARCH_AARCH64_EXECREGS_H +#define TESTS_KERNEL_ARCH_AARCH64_EXECREGS_H + +#include + +#define NEXECREGS 31 + +#ifndef _LOCORE + +#include + +/* + * Ordered by struct reg in sys/arch/aarch64/include/reg.h for + * convenience of auditing. Must match h_execregs.S. + */ +static const char *const regname[] = { + "x0", + "x1", + /* x2: ps_strings */ + "x3", + "x4", + "x5", + "x6", + "x7", + "x8", + "x9", + "x10", + "x11", + "x12", + "x13", + "x14", + "x15", + "x16", + "x17", + "x18", + "x19", + "x20", + "x21", + "x22", + "x23", + "x24", + "x25", + "x26", + "x27", + "x28", + "x29", + "x30", + "tpidr", +}; + +__CTASSERT(NEXECREGS == __arraycount(regname)); + +int execregschild(char *); +pid_t spawnregschild(char *, int); + +#endif /* _LOCORE */ + +#endif /* TESTS_KERNEL_ARCH_AARCH64_EXECREGS_H */ diff -r 21a87af07c21 -r bc3c70c24c86 tests/kernel/arch/aarch64/h_execregs.S --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/kernel/arch/aarch64/h_execregs.S Tue Feb 18 16:55:53 2025 +0000 @@ -0,0 +1,84 @@ +/* $NetBSD$ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define _LOCORE + +#include + +#include + +#include "execregs.h" + +ENTRY(execregs_start) + /* create a stack frame with NEXECREGS*8 bytes */ + stp fp, lr, [sp, #-(16 + NEXECREGS*8)]! + + /* store registers to buffer on stack */ + stp x0, x1, [sp, #16] /* order matches execregs.h */ + /* x2: ps_strings */ + stp x3, x4, [sp, #(16 + 1*2*8)] + stp x5, x6, [sp, #(16 + 2*2*8)] + stp x7, x8, [sp, #(16 + 3*2*8)] + stp x9, x10, [sp, #(16 + 4*2*8)] + stp x11, x12, [sp, #(16 + 5*2*8)] + stp x13, x14, [sp, #(16 + 6*2*8)] + stp x15, x16, [sp, #(16 + 7*2*8)] + stp x17, x18, [sp, #(16 + 8*2*8)] + stp x19, x20, [sp, #(16 + 9*2*8)] + stp x21, x22, [sp, #(16 + 10*2*8)] + stp x23, x24, [sp, #(16 + 11*2*8)] + stp x25, x26, [sp, #(16 + 12*2*8)] + stp x27, x28, [sp, #(16 + 13*2*8)] + stp x29, x30, [sp, #(16 + 14*2*8)] + mrs x0, tpidr_el0 + str x0, [sp, #(16 + 15*2*8)] + + /* call write(STDOUT_FILENO, regs, sizeof(regs)) */ + mov x0, #1 /* arg0 := STDOUT_FILENO */ + add x1, sp, #16 /* arg1 := regs */ + mov x2, #(NEXECREGS*8) /* arg2 := sizeof(regs) */ + svc #SYS_write + + b.cs 2f /* bail if write failed */ + cmp x0, #(NEXECREGS*8) /* bail if wrote wrong # of bytes */ + b.ne 2f + + /* call exit(0) */ + mov x0, #0 /* arg0 := 0 */ +1: svc #SYS_exit + brk #0xffff /* paranoia */ + +2: /* call exit(127) */ + mov x0, #127 /* arg0 := 127 */ + b 1b +END(execregs_start) + +/* main stub to simplify linking */ +ENTRY(main) + brk #0xffff +END(main) diff -r 21a87af07c21 -r bc3c70c24c86 tests/kernel/arch/hppa/execregs.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/kernel/arch/hppa/execregs.c Tue Feb 18 16:55:53 2025 +0000 @@ -0,0 +1,281 @@ +/* $NetBSD$ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__RCSID("$NetBSD$"); + +#include "execregs.h" + +#include +#include +#include +#include + +extern char **environ; + +static unsigned long +nonnull(unsigned long x) +{ + + x |= x << 8; + x |= x << 16; + return x; +} + +int +execregschild(char *path) +{ + register long t1 __asm("r22") = nonnull(22); + register long t2 __asm("r21") = nonnull(21); + /* sp: stack pointer */ + register long t3 __asm("r20") = nonnull(20); + /* cr17/iisq_head: privileged */ + /* cr17/iisq_tail: privileged */ + /* cr18/iioq_head: privileged */ + /* cr18/iioq_tail: privileged */ + /* cr15/eiem: privileged */ + /* cr22/ipsw: privileged */ + /* sr3: privileged(?) */ + /* cr8/pidr1: privileged */ + /* cr20/isr: privileged */ + /* cr21/ior: privileged */ + /* cr19/iir: privileged */ + /* flags: N/A(?) */ + long sar = nonnull(0x8a); + /* r1: ADDIL (add immediate left) result, nonnull anyway */ + /* rp: return pointer, nonnull anyway */ + /* r3: frame pointer, nonnull anyway */ + register long r4 __asm("r4") = nonnull(4); + register long r5 __asm("r5") = nonnull(5); + register long r6 __asm("r6") = nonnull(6); + register long r7 __asm("r7") = nonnull(7); + register long r8 __asm("r8") = nonnull(8); + register long r9 __asm("r9") = nonnull(9); + register long r10 __asm("r10") = nonnull(10); + register long r11 __asm("r11") = nonnull(11); + register long r12 __asm("r12") = nonnull(12); + register long r13 __asm("r13") = nonnull(13); + register long r14 __asm("r14") = nonnull(14); + register long r15 __asm("r15") = nonnull(15); + register long r16 __asm("r16") = nonnull(16); + register long r17 __asm("r17") = nonnull(17); + register long r18 __asm("r18") = nonnull(18); + register long t4 __asm("r19") = nonnull(19); + register long arg3 __asm("r23") = nonnull(23); + /* arg2: envp, nonnull anyway */ + /* arg1: argv, nonnull anyway */ + /* arg0: path, nonnull anyway */ + /* r27/dp: data pointer, nonnull anyway */ + register long ret0 __asm("r28") = nonnull(28); + register long ret1 __asm("r29") = nonnull(29); + register long r31 __asm("r31") = nonnull(31); + /* sr0-sr7: space registers initialized by kernel */ + /* cr9/pidr2: privileged */ + /* cr12/pidr3: privileged */ + /* cr13/pidr4: privileged */ + /* cr0/rctr: privileged */ + /* cr10/ccr: privileged */ + /* cr23/eirr: privileged */ + /* cr24: privileged */ + /* cr25/vtop: privileged */ + /* cr27/tr3: _lwp_private, thread-local storage -- nonnull anyway */ + /* cr28: privileged */ + /* cr30/fpregs: privileged */ + /* cr31: privileged */ + + char *argv[] = {path, NULL}; + char **envp = environ; + + /* + * Not perfect -- compiler might use some registers for + * stack/argument transfers, but all the arguments are nonnull + * so this is probably a good test anyway. + */ + __asm volatile("mtctl %[sar], %%sar" + : /* outputs */ + : [sar] "r"(sar) + : "memory"); + __asm volatile("" : + "+r"(t1), + "+r"(t2), + "+r"(t3), + "+r"(r4), + "+r"(r5), + "+r"(r6), + "+r"(r7), + "+r"(r8), + "+r"(r9), + "+r"(r10), + "+r"(r11), + "+r"(r12) + :: "memory"); + /* pacify gcc error: more than 30 operands in 'asm' */ + __asm volatile("" : + "+r"(r13), + "+r"(r14), + "+r"(r15), + "+r"(r16), + "+r"(r17), + "+r"(r18), + "+r"(t4), + "+r"(arg3), + "+r"(ret0), + "+r"(ret1), + "+r"(r31) + :: "memory"); + + return execve(path, argv, envp); +} + +pid_t +spawnregschild(char *path, int fd) +{ + register long t1 __asm("r22") = nonnull(22); + register long t2 __asm("r21") = nonnull(21); + /* sp: stack pointer */ + register long t3 __asm("r20") = nonnull(20); + /* cr17/iisq_head: privileged */ + /* cr17/iisq_tail: privileged */ + /* cr18/iioq_head: privileged */ + /* cr18/iioq_tail: privileged */ + /* cr15/eiem: privileged */ + /* cr22/ipsw: privileged */ + /* sr3: privileged(?) */ + /* cr8/pidr1: privileged */ + /* cr20/isr: privileged */ + /* cr21/ior: privileged */ + /* cr19/iir: privileged */ + /* flags: N/A(?) */ + long sar = nonnull(0x8a); + /* r1: ADDIL (add immediate left) result, nonnull anyway */ + /* rp: return pointer, nonnull anyway */ + /* r3: frame pointer, nonnull anyway */ + register long r4 __asm("r4") = nonnull(4); + register long r5 __asm("r5") = nonnull(5); + register long r6 __asm("r6") = nonnull(6); + register long r7 __asm("r7") = nonnull(7); + register long r8 __asm("r8") = nonnull(8); + register long r9 __asm("r9") = nonnull(9); + register long r10 __asm("r10") = nonnull(10); + register long r11 __asm("r11") = nonnull(11); + register long r12 __asm("r12") = nonnull(12); + register long r13 __asm("r13") = nonnull(13); + register long r14 __asm("r14") = nonnull(14); + register long r15 __asm("r15") = nonnull(15); + register long r16 __asm("r16") = nonnull(16); + register long r17 __asm("r17") = nonnull(17); + register long r18 __asm("r18") = nonnull(18); + register long t4 __asm("r19") = nonnull(19); + /* arg3: attrp, nonnull anyway */ + /* arg2: fileactsp, nonnull anyway */ + /* arg1: path, nonnull anyway */ + /* arg0: pidp, nonnull anyway */ + /* r27/dp: data pointer, nonnull anyway */ + register long ret0 __asm("r28") = nonnull(28); + register long ret1 __asm("r29") = nonnull(29); + register long r31 __asm("r31") = nonnull(31); + /* sr0-sr7: space registers initialized by kernel */ + /* cr9/pidr2: privileged */ + /* cr12/pidr3: privileged */ + /* cr13/pidr4: privileged */ + /* cr0/rctr: privileged */ + /* cr10/ccr: privileged */ + /* cr23/eirr: privileged */ + /* cr24: privileged */ + /* cr25/vtop: privileged */ + /* cr27/tr3: _lwp_private, thread-local storage -- nonnull anyway */ + /* cr28: privileged */ + /* cr30/fpregs: privileged */ + /* cr31: privileged */ + + char *argv[] = {path, NULL}; + char **envp = environ; + posix_spawn_file_actions_t fileacts; + posix_spawnattr_t attr; + pid_t pid; + int error; + + error = posix_spawn_file_actions_init(&fileacts); + if (error) + goto out; + error = posix_spawn_file_actions_adddup2(&fileacts, fd, STDOUT_FILENO); + if (error) + goto out; + error = posix_spawnattr_init(&attr); + if (error) + goto out; + + /* + * Not perfect -- compiler might use some registers for + * stack/argument transfers, but all the arguments are nonnull + * so this is probably a good test anyway. + */ + __asm volatile("mtctl %[sar], %%sar" + : /* outputs */ + : [sar] "r"(sar) + : "memory"); + __asm volatile("" : + "+r"(t1), + "+r"(t2), + "+r"(t3), + "+r"(r4), + "+r"(r5), + "+r"(r6), + "+r"(r7), + "+r"(r8), + "+r"(r9), + "+r"(r10), + "+r"(r11), + "+r"(r12) + :: "memory"); + /* pacify gcc error: more than 30 operands in 'asm' */ + __asm volatile("" : + "+r"(r13), + "+r"(r14), + "+r"(r15), + "+r"(r16), + "+r"(r17), + "+r"(r18), + "+r"(t4), + "+r"(ret0), + "+r"(ret1), + "+r"(r31) + :: "memory"); + + error = posix_spawn(&pid, path, &fileacts, &attr, argv, envp); + if (error) + goto out; + +out: posix_spawnattr_destroy(&attr); + posix_spawn_file_actions_destroy(&fileacts); + if (error) { + errno = error; + return -1; + } + return 0; +} diff -r 21a87af07c21 -r bc3c70c24c86 tests/kernel/arch/hppa/execregs.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/kernel/arch/hppa/execregs.h Tue Feb 18 16:55:53 2025 +0000 @@ -0,0 +1,89 @@ +/* $NetBSD$ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TESTS_KERNEL_ARCH_HPPA_EXECREGS_H +#define TESTS_KERNEL_ARCH_HPPA_EXECREGS_H + +#include + +#define NEXECREGS 31 + +#ifndef _LOCORE + +#include + +/* + * Ordered by struct struct trapframe in sys/arch/hppa/include/frame.h + * for convenience of auditing. Must match h_execregs.S. + */ +static const char *const regname[] = { + "t1", + "t2", + /* sp: stack pointer */ + "t3", + /* various privileged stuff */ + "sar", + "r1", + "rp", + /* r3: frame pointer (set to initial stack pointer) */ + "r4", + "r5", + "r6", + "r70", + "r8", + "r9", + "r10", + "r11", + "r12", + "r13", + "r14", + "r15", + "r16", + "r17", + "r18", + "t4", + "arg3", + "arg2", + "arg1", + /* arg0: ps_strings */ + "dp", + "ret0", + "ret1", + "r31", + "cr27", + "cr28", +}; + +__CTASSERT(NEXECREGS == __arraycount(regname)); + +int execregschild(char *); +pid_t spawnregschild(char *, int); + +#endif /* _LOCORE */ + +#endif /* TESTS_KERNEL_ARCH_HPPA_EXECREGS_H */ diff -r 21a87af07c21 -r bc3c70c24c86 tests/kernel/arch/hppa/h_execregs.S --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/kernel/arch/hppa/h_execregs.S Tue Feb 18 16:55:53 2025 +0000 @@ -0,0 +1,129 @@ +/* $NetBSD$ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define _LOCORE + +#include + +#include +#include + +#include "execregs.h" + +_ENTRY(execregs_start) + .callinfo frame=(NEXECREGS*4), calls + .entry + + ldo (NEXECREGS*4)(%sp), %sp /* space for NEXECREGS */ + stw %t1, (4*(0 - NEXECREGS))(%sp) /* order matches execregs.h */ + stw %t2, (4*(1 - NEXECREGS))(%sp) + /* sp: stack pointer */ + stw %t3, (4*(2 - NEXECREGS))(%sp) + /* cr17/iisq_head: privileged */ + /* cr17/iisq_tail: privileged */ + /* cr18/iioq_head: privileged */ + /* cr18/iioq_tail: privileged */ + /* cr15/eiem: privileged */ + /* cr22/ipsw: privileged */ + /* sr3: privileged(?) */ + /* cr8/pidr1: privileged */ + /* cr20/isr: privileged */ + /* cr21/ior: privileged */ + /* cr19/iir: privileged */ + /* flags: N/A(?) */ + stw %sar, (4*(3 - NEXECREGS))(%sp) + stw %r1, (4*(4 - NEXECREGS))(%sp) + stw %rp, (4*(5 - NEXECREGS))(%sp) + /* r3: frame pointer (set to initial stack pointer) */ + stw %r4, (4*(6 - NEXECREGS))(%sp) + stw %r5, (4*(7 - NEXECREGS))(%sp) + stw %r6, (4*(8 - NEXECREGS))(%sp) + stw %r7, (4*(9 - NEXECREGS))(%sp) + stw %r8, (4*(10 - NEXECREGS))(%sp) + stw %r9, (4*(11 - NEXECREGS))(%sp) + stw %r10, (4*(12 - NEXECREGS))(%sp) + stw %r11, (4*(13 - NEXECREGS))(%sp) + stw %r12, (4*(14 - NEXECREGS))(%sp) + stw %r13, (4*(15 - NEXECREGS))(%sp) + stw %r14, (4*(16 - NEXECREGS))(%sp) + stw %r15, (4*(17 - NEXECREGS))(%sp) + stw %r16, (4*(18 - NEXECREGS))(%sp) + stw %r17, (4*(19 - NEXECREGS))(%sp) + stw %r18, (4*(20 - NEXECREGS))(%sp) + stw %t4, (4*(21 - NEXECREGS))(%sp) + stw %arg3, (4*(22 - NEXECREGS))(%sp) + stw %arg2, (4*(23 - NEXECREGS))(%sp) + stw %arg1, (4*(24 - NEXECREGS))(%sp) + /* arg0: ps_strings */ + stw %dp, (4*(25 - NEXECREGS))(%sp) + stw %ret0, (4*(26 - NEXECREGS))(%sp) + stw %ret1, (4*(27 - NEXECREGS))(%sp) + stw %r31, (4*(28 - NEXECREGS))(%sp) + /* sr0-sr7: space registers initialized by kernel */ + /* cr9/pidr2: privileged */ + /* cr12/pidr3: privileged */ + /* cr13/pidr4: privileged */ + /* cr0/rctr: privileged */ + /* cr10/ccr: privileged */ + /* cr23/eirr: privileged */ + /* cr24: privileged */ + /* cr25/vtop: privileged */ + /* cr26: ??? */ + stw %cr27, (4*(29 - NEXECREGS))(%sp) + stw %cr28, (4*(30 - NEXECREGS))(%sp) + /* cr30/fpregs: privileged */ + /* cr31: privileged */ + + /* call write(STDOUT_FILENO, regs, sizeof(regs)) */ + ldi 1, %arg0 /* arg0 := STDOUT_FILENO */ + ldo -(4*NEXECREGS)(%sp), %arg1 /* arg1 := regs */ + ldi (4*NEXECREGS), %arg2 /* arg2 := sizeof(regs) */ + ldil L%SYSCALLGATE, %r1 + ble 4(%sr2, %r1) + ldi SYS_write, %t1 + + comb,<>,n %r0, %t1, 2f /* bail if write failed */ + ldi (4*NEXECREGS), %t1 /* bail if wrong # bytes */ + comb,<>,n %ret0, %t1, 2f + + /* call exit(0) */ + ldi 0, %arg0 +1: ldil L%SYSCALLGATE, %r1 + ble 4(%sr2, %r1) + ldi SYS_exit, %t1 + break 0, 0 /* paranoia */ + +2: /* call exit(127) */ + b 1b + ldi 127, %arg0 +EXIT(execregs_start) + +/* main stub to simplify linking */ +LEAF_ENTRY(main) + break 0, 0 /* paranoia */ +EXIT(main) diff -r 21a87af07c21 -r bc3c70c24c86 tests/kernel/arch/i386/execregs.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/kernel/arch/i386/execregs.c Tue Feb 18 16:55:53 2025 +0000 @@ -0,0 +1,132 @@ +/* $NetBSD$ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__RCSID("$NetBSD$"); + +#include "execregs.h" + +#include +#include +#include +#include + +extern char **environ; + +static unsigned long +nonnull(unsigned long x) +{ + + x |= x << 8; + x |= x << 16; + return x; +} + +int +execregschild(char *path) +{ + register long edi __asm("edi") = nonnull('d'); + register long esi __asm("esi") = nonnull('s'); + /* ebp: frame pointer, can't touch that here, but it'll be nonnull */ + /* ebx: ps_strings, passed to child */ + register long edx __asm("edx") = nonnull('x'); + register long ecx __asm("ecx") = nonnull('c'); + register long eax __asm("eax") = nonnull('a'); + + char *argv[] = {path, NULL}; + char **envp = environ; + + /* + * Not perfect -- compiler might use some registers for + * stack/argument transfers, but all the arguments are nonnull + * so this is probably a good test anyway. + */ + __asm volatile("" : + "+r"(edi), + "+r"(esi), + "+r"(edx), + "+r"(ecx), + "+r"(eax) + :: "memory"); + + return execve(path, argv, envp); +} + +pid_t +spawnregschild(char *path, int fd) +{ + register long edi __asm("edi") = nonnull('d'); + register long esi __asm("esi") = nonnull('s'); + /* ebp: frame pointer, can't touch that here, but it'll be nonnull */ + /* ebx: ps_strings, passed to child */ + register long edx __asm("edx") = nonnull('x'); + register long ecx __asm("ecx") = nonnull('c'); + register long eax __asm("eax") = nonnull('a'); + + char *argv[] = {path, NULL}; + char **envp = environ; + posix_spawn_file_actions_t fileacts; + posix_spawnattr_t attr; + pid_t pid; + int error; + + error = posix_spawn_file_actions_init(&fileacts); + if (error) + goto out; + error = posix_spawn_file_actions_adddup2(&fileacts, fd, STDOUT_FILENO); + if (error) + goto out; + error = posix_spawnattr_init(&attr); + if (error) + goto out; + + /* + * Not perfect -- compiler might use some registers for + * stack/argument transfers, but all the arguments are nonnull + * so this is probably a good test anyway. + */ + __asm volatile("" : + "+r"(edi), + "+r"(esi), + "+r"(edx), + "+r"(ecx), + "+r"(eax) + :: "memory"); + + error = posix_spawn(&pid, path, &fileacts, &attr, argv, envp); + if (error) + goto out; + +out: posix_spawnattr_destroy(&attr); + posix_spawn_file_actions_destroy(&fileacts); + if (error) { + errno = error; + return -1; + } + return 0; +} diff -r 21a87af07c21 -r bc3c70c24c86 tests/kernel/arch/i386/execregs.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/kernel/arch/i386/execregs.h Tue Feb 18 16:55:53 2025 +0000 @@ -0,0 +1,69 @@ +/* $NetBSD$ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TESTS_KERNEL_ARCH_I386_EXECREGS_H +#define TESTS_KERNEL_ARCH_I386_EXECREGS_H + +#include + +#define NEXECREGS 6 + +#ifndef _LOCORE + +#include + +/* + * Ordered by struct trapframe in sys/arch/i386/include/frame.h for + * convenience of auditing. Must match h_execregs.S. + */ +static const char *const regname[] = { + /* gs/fs/es/ds: segment registers, not really registers */ + "edi", + "esi", + "ebp", + /* ebx: ps_strings */ + "edx", + "ecx", + "eax", + /* trapno: not a register */ + /* err: not a register */ + /* eip: instruction pointer */ + /* cs: segment register */ + /* eflags */ + /* esp: stack pointer */ + /* ss: stack selector */ +}; + +__CTASSERT(NEXECREGS == __arraycount(regname)); + +int execregschild(char *); +pid_t spawnregschild(char *, int); + +#endif /* _LOCORE */ + +#endif /* TESTS_KERNEL_ARCH_I386_EXECREGS_H */ diff -r 21a87af07c21 -r bc3c70c24c86 tests/kernel/arch/i386/h_execregs.S --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/kernel/arch/i386/h_execregs.S Tue Feb 18 16:55:53 2025 +0000 @@ -0,0 +1,85 @@ +/* $NetBSD$ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define _LOCORE + +#include + +#include + +#include "execregs.h" + +ENTRY(execregs_start) + andl $-0x4,%esp /* align stack to 4-byte boundary */ + + /* store registers to a buffer on stack */ + subl $(NEXECREGS*4),%esp /* space for NEXECREGS registers */ + movl %edi,0*4(%esp) /* order matches execregs.h */ + movl %esi,1*4(%esp) + movl %ebp,2*4(%esp) + movl %edx,3*4(%esp) + movl %ecx,4*4(%esp) + movl %eax,5*4(%esp) + + /* call write(STDOUT_FILENO, regs, sizeof(regs)) */ + movl %esp,%eax /* eax := regs */ + pushl $(NEXECREGS*4) /* arg2 := sizeof(regs) */ + pushl %eax /* arg1 := regs */ + pushl $0x1 /* arg0 := STDOUT_FILENO */ + call execregs_write + + jb 2f /* bail if write failed */ + cmpl $(NEXECREGS*4),%eax /* bail if wrote wrong # of bytes */ + jne 2f + + /* call exit(0) */ + pushl $0 /* arg0 := 0 */ +1: call execregs_exit + hlt /* paranoia */ + +2: /* call exit(127) */ + pushl $127 /* arg0 := 127 */ + jmp 1b +END(execregs_start) + +ENTRY(execregs_write) + movl $SYS_write,%eax /* syscall number */ + int $0x80 + retl +END(execregs_write) + +ENTRY(execregs_exit) + movl $SYS_exit,%eax /* syscall number */ + int $0x80 + hlt +END(execregs_exit) + +/* main stub to simplify linking */ +ENTRY(main) + hlt +END(main) diff -r 21a87af07c21 -r bc3c70c24c86 tests/kernel/arch/vax/execregs.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/kernel/arch/vax/execregs.c Tue Feb 18 16:55:53 2025 +0000 @@ -0,0 +1,166 @@ +/* $NetBSD$ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__RCSID("$NetBSD$"); + +#include "execregs.h" + +#include +#include +#include +#include + +extern char **environ; + +static unsigned long +nonnull(unsigned long x) +{ + + x |= x << 8; + x |= x << 16; + return x; +} + +int +execregschild(char *path) +{ + /* fp: frame pointer, nonnull */ + /* ap: argument pointer, on user stack, nonnull */ + /* sp: stack pointer, nonnull */ + register long r0 __asm("r0") = nonnull(0x10); + register long r1 __asm("r1") = nonnull(1); + register long r2 __asm("r2") = nonnull(2); + register long r3 __asm("r3") = nonnull(3); + register long r4 __asm("r4") = nonnull(4); + register long r5 __asm("r5") = nonnull(5); + register long r6 __asm("r6") = nonnull(6); + register long r7 __asm("r7") = nonnull(7); + register long r8 __asm("r8") = nonnull(8); + register long r9 __asm("r9") = nonnull(9); + register long r10 __asm("r10") = nonnull(10); + register long r11 __asm("r11") = nonnull(11); + /* pc: user PC, will be nonnull */ + /* psl: processor status longword, will be nonnull */ + + char *argv[] = {path, NULL}; + char **envp = environ; + + /* + * Not perfect -- compiler might use some registers for + * stack/argument transfers, but all the arguments are nonnull + * so this is probably a good test anyway. + */ + __asm volatile("" : + "+r"(r0), + "+r"(r1), + "+r"(r2), + "+r"(r3), + "+r"(r4), + "+r"(r5), + "+r"(r6), + "+r"(r7), + "+r"(r8), + "+r"(r9), + "+r"(r10), + "+r"(r11) + :: "memory"); + + return execve(path, argv, envp); +} + +pid_t +spawnregschild(char *path, int fd) +{ + /* fp: frame pointer, nonnull */ + /* ap: argument pointer, on user stack, nonnull */ + /* sp: stack pointer, nonnull */ + register long r0 __asm("r0") = nonnull(0x10); + register long r1 __asm("r1") = nonnull(1); + register long r2 __asm("r2") = nonnull(2); + register long r3 __asm("r3") = nonnull(3); + register long r4 __asm("r4") = nonnull(4); + register long r5 __asm("r5") = nonnull(5); + register long r6 __asm("r6") = nonnull(6); + register long r7 __asm("r7") = nonnull(7); + register long r8 __asm("r8") = nonnull(8); + register long r9 __asm("r9") = nonnull(9); + register long r10 __asm("r10") = nonnull(10); + register long r11 __asm("r11") = nonnull(11); + /* pc: user PC, will be nonnull */ + /* psl: processor status longword, will be nonnull */ + + char *argv[] = {path, NULL}; + char **envp = environ; + posix_spawn_file_actions_t fileacts; + posix_spawnattr_t attr; + pid_t pid; + int error; + + error = posix_spawn_file_actions_init(&fileacts); + if (error) + goto out; + error = posix_spawn_file_actions_adddup2(&fileacts, fd, STDOUT_FILENO); + if (error) + goto out; + error = posix_spawnattr_init(&attr); + if (error) + goto out; + + /* + * Not perfect -- compiler might use some registers for + * stack/argument transfers, but all the arguments are nonnull + * so this is probably a good test anyway. + */ + __asm volatile("" : + "+r"(r0), + "+r"(r1), + "+r"(r2), + "+r"(r3), + "+r"(r4), + "+r"(r5), + "+r"(r6), + "+r"(r7), + "+r"(r8), + "+r"(r9), + "+r"(r10), + "+r"(r11) + :: "memory"); + + error = posix_spawn(&pid, path, &fileacts, &attr, argv, envp); + if (error) + goto out; + +out: posix_spawnattr_destroy(&attr); + posix_spawn_file_actions_destroy(&fileacts); + if (error) { + errno = error; + return -1; + } + return 0; +} diff -r 21a87af07c21 -r bc3c70c24c86 tests/kernel/arch/vax/execregs.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/kernel/arch/vax/execregs.h Tue Feb 18 16:55:53 2025 +0000 @@ -0,0 +1,77 @@ +/* $NetBSD$ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TESTS_KERNEL_ARCH_VAX_EXECREGS_H +#define TESTS_KERNEL_ARCH_VAX_EXECREGS_H + +#include + +#define NEXECREGS 12 + +#ifndef _LOCORE + +#include + +/* + * The order matches that in struct trapframe in + * sys/arch/vax/include/trap.h + * + * Must match h_execregs.S. + * + * See also sys/arch/vax/vax/trap.c:setregs() + */ +static const char *const regname[] = { + "fp", /* Stack frame pointer */ + "ap", /* Argument pointer on user stack */ + /* sp: stack pointer */ + "r0", /* General registers saved upon trap/syscall */ + "r1", + "r2", + "r3", + "r4", + "r5", + /* r6: initial stack pointer */ + "r7", + "r8", + /* r9: ps_strings */ + "r10", + "r11", + /* trap: type of trap, not a register */ + /* code: trap specific code, not a register */ + /* pc: user PC */ + /* psl: processor status longword */ +}; + +__CTASSERT(NEXECREGS == __arraycount(regname)); + +int execregschild(char *); +pid_t spawnregschild(char *, int); + +#endif /* _LOCORE */ + +#endif /* TESTS_KERNEL_ARCH_VAX_EXECREGS_H */ diff -r 21a87af07c21 -r bc3c70c24c86 tests/kernel/arch/vax/h_execregs.S --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/kernel/arch/vax/h_execregs.S Tue Feb 18 16:55:53 2025 +0000 @@ -0,0 +1,87 @@ +/* $NetBSD$ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define _LOCORE + +#include + +#include + +#include "execregs.h" + +#define REGSIZE 4 +#define BUFSIZE (NEXECREGS * REGSIZE) +#define SLOT(n) (n)*REGSIZE(%sp) + +ENTRY(execregs_start, 0) + /* store registers to a buffer on stack */ + subl2 $BUFSIZE,%sp /* space for NEXECREGS registers */ + movl %fp,SLOT(0) /* order matches execregs.h */ + movl %ap,SLOT(1) + /* sp: stack pointer */ + movl %r0,SLOT(2) + movl %r1,SLOT(3) + movl %r2,SLOT(4) + movl %r3,SLOT(5) + movl %r4,SLOT(6) + movl %r5,SLOT(7) + /* r6: initial stack pointer */ + movl %r7,SLOT(8) + movl %r8,SLOT(9) + /* r9: ps_strings */ + movl %r10,SLOT(10) + movl %r11,SLOT(11) + + /* call write(STDOUT_FILENO, regs, sizeof(regs)) */ + pushl $BUFSIZE /* arg2 := sizeof(regs) */ + pushal 4(%sp) /* arg1 := regs */ + pushl $1 /* arg0 := STDOUT_FILENO */ + pushl $3 /* number of arguments */ + movl %sp,%ap /* argument pointer */ + chmk $SYS_write + + bcs 2f /* bail if write failed */ + cmpl $BUFSIZE,%r0 /* bail if wrote wrong # of bytes */ + bneq 2f + + /* call exit(0) */ + pushl $0 /* arg0 := 0 */ +1: pushl $1 /* number of arguments */ + movl %sp,%ap /* argument pointer */ + chmk $SYS_exit + .word 0xffff /* paranoia -- illegal opcode */ + +2: /* call exit(127) */ + pushl $127 /* arg0 := 127 */ + jmp 1b +END(execregs_start) + +/* main stub to simplify linking */ +ENTRY(main, 0) + .word 0xffff /* illegal opcode */ +END(main) diff -r 21a87af07c21 -r bc3c70c24c86 tests/kernel/arch/x86_64/execregs.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/kernel/arch/x86_64/execregs.c Tue Feb 18 16:55:53 2025 +0000 @@ -0,0 +1,156 @@ +/* $NetBSD$ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__RCSID("$NetBSD$"); + +#include "execregs.h" + +#include +#include +#include +#include + +extern char **environ; + +static unsigned long +nonnull(unsigned long x) +{ + + x |= x << 8; + x |= x << 16; + x |= x << 32; + return x; +} + +int +execregschild(char *path) +{ + /* rdi: used to pass exec arg0, nonnull anyway (path) */ + /* rsi: used to pass exec arg1, nonnull anyway (argv) */ + /* rdx: used to pass exec arg2, nonnull anyway (environ) */ + register long r10 __asm("r10") = nonnull(10); + register long r8 __asm("r8") = nonnull(8); + register long r9 __asm("r9") = nonnull(9); + register long rcx __asm("rcx") = nonnull('c'); + register long r11 __asm("r11") = nonnull(11); + register long r12 __asm("r12") = nonnull(12); + register long r13 __asm("r13") = nonnull(13); + register long r14 __asm("r14") = nonnull(14); + register long r15 __asm("r15") = nonnull(15); + /* rbp: frame pointer, can't touch that here, but it'll be nonnull */ + /* rbx: ps_strings, passed to child */ + register long rax __asm("rax") = nonnull('a'); + + char *argv[] = {path, NULL}; + char **envp = environ; + + /* + * Not perfect -- compiler might use some registers for + * stack/argument transfers, but all the arguments are nonnull + * so this is probably a good test anyway. + */ + __asm volatile("" : + "+r"(r10), + "+r"(r8), + "+r"(r9), + "+r"(rcx), + "+r"(r11), + "+r"(r12), + "+r"(r13), + "+r"(r14), + "+r"(r15), + "+r"(rax) + :: "memory"); + + return execve(path, argv, envp); +} + +pid_t +spawnregschild(char *path, int fd) +{ + /* rdi: used to pass posix_spawn arg0, nonnull anyway (&pid) */ + /* rsi: used to pass posix_spawn arg1, nonnull anyway (path) */ + /* rdx: used to pass posix_spawn arg2, nonnull anyway (&fileacts) */ + register long r10 __asm("r10") = nonnull(10); + /* r8: used to pass posix_spawn arg4, nonnull anyway (argv) */ + /* r9: used to pass posix_spawn arg5, nonnull anyway (environ) */ + /* rcx: used to pass posix_spawn arg3, nonnull anyway (&attr) */ + register long r11 __asm("r11") = nonnull(11); + register long r12 __asm("r12") = nonnull(12); + register long r13 __asm("r13") = nonnull(13); + register long r14 __asm("r14") = nonnull(14); + register long r15 __asm("r15") = nonnull(15); + /* rbp: frame pointer, can't touch that here, but it'll be nonnull */ + /* rbx: ps_strings, passed to child */ + register long rax __asm("rax") = nonnull('a'); + + char *argv[] = {path, NULL}; + char **envp = environ; + posix_spawn_file_actions_t fileacts; + posix_spawnattr_t attr; + pid_t pid; + int error; + + error = posix_spawn_file_actions_init(&fileacts); + if (error) + goto out; + error = posix_spawn_file_actions_adddup2(&fileacts, fd, STDOUT_FILENO); + if (error) + goto out; + error = posix_spawnattr_init(&attr); + if (error) + goto out; + + /* + * Not perfect -- compiler might use some registers for + * stack/argument transfers, but all the arguments are nonnull + * so this is probably a good test anyway. + */ + __asm volatile("" : + "+r"(r10), + "+r"(r11), + "+r"(r12), + "+r"(r13), + "+r"(r14), + "+r"(r15), + "+r"(rax) + :: "memory"); + + error = posix_spawn(&pid, path, &fileacts, &attr, argv, envp); + if (error) + goto out; + +out: posix_spawnattr_destroy(&attr); + posix_spawn_file_actions_destroy(&fileacts); + if (error) { + errno = error; + return -1; + } + return 0; +} diff -r 21a87af07c21 -r bc3c70c24c86 tests/kernel/arch/x86_64/execregs.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/kernel/arch/x86_64/execregs.h Tue Feb 18 16:55:53 2025 +0000 @@ -0,0 +1,81 @@ +/* $NetBSD$ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TESTS_KERNEL_ARCH_X86_64_EXECREGS_H +#define TESTS_KERNEL_ARCH_X86_64_EXECREGS_H + +#include + +#define NEXECREGS 14 + +#ifndef _LOCORE + +#include + +/* + * Ordered by _FRAME_REG in sys/arch/amd64/include/frame_regs.h for + * convenience of auditing. Must match h_execregs.S. + */ +static const char *const regname[] = { + "rdi", + "rsi", + "rdx", + "r10", + "r8", + "r9", + /* arg6: syscall arg from stack, not a real register */ + /* arg7: syscall arg from stack, not a real register */ + /* arg8: syscall arg from stack, not a real register */ + /* arg9: syscall arg from stack, not a real register */ + "rcx", + "r11", + "r12", + "r13", + "r14", + "r15", + "rbp", + /* rbx: ps_strings */ + "rax", + /* gs/fs/es/ds: segment registers, not really registers */ + /* trapno: not a register */ + /* err: not a register */ + /* rip: instruction pointer */ + /* cs: segment register */ + /* rflags */ + /* rsp: stack pointer */ + /* ss: stack selector */ +}; + +__CTASSERT(NEXECREGS == __arraycount(regname)); + +int execregschild(char *); +pid_t spawnregschild(char *, int); + +#endif /* _LOCORE */ + +#endif /* TESTS_KERNEL_ARCH_X86_64_EXECREGS_H */ diff -r 21a87af07c21 -r bc3c70c24c86 tests/kernel/arch/x86_64/h_execregs.S --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/kernel/arch/x86_64/h_execregs.S Tue Feb 18 16:55:53 2025 +0000 @@ -0,0 +1,82 @@ +/* $NetBSD$ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define _LOCORE + +#include + +#include + +#include "execregs.h" + +ENTRY(execregs_start) + andq $-0x10,%rsp /* align stack to 16-byte boundary */ + + /* store registers to a buffer on stack */ + subq $(NEXECREGS*8),%rsp /* space for NEXECREGS registers */ + movq %rdi,0*8(%rsp) /* order matches execregs.h */ + movq %rsi,1*8(%rsp) + movq %rdx,2*8(%rsp) + movq %r10,3*8(%rsp) + movq %r8,4*8(%rsp) + movq %r9,5*8(%rsp) + movq %rcx,6*8(%rsp) + movq %r11,7*8(%rsp) + movq %r12,8*8(%rsp) + movq %r13,9*8(%rsp) + movq %r14,10*8(%rsp) + movq %r15,11*8(%rsp) + movq %rbp,12*8(%rsp) + movq %rax,13*8(%rsp) + + /* call write(STDOUT_FILENO, regs, sizeof(regs)) */ + movl $0x1,%edi /* arg0 := STDOUT_FILENO */ + movq %rsp,%rsi /* arg1 := regs */ + movl $(NEXECREGS*8),%edx /* arg2 := sizeof(regs) */ + movl $SYS_write,%eax /* syscall number */ + syscall + + jb 2f /* bail if write failed */ + cmpq $(NEXECREGS*8),%rax /* bail if wrote wrong # of bytes */ + jne 2f + + /* call exit(0) */ + xorl %edi,%edi /* arg0 := 0 */ +1: movl $SYS_exit,%eax /* syscall number */ + syscall + hlt /* paranoia */ + +2: /* call exit(127) */ + movl $127,%edi /* arg0 := 127 */ + jmp 1b +END(execregs_start) + +/* main stub to simplify linking */ +ENTRY(main) + hlt +END(main) diff -r 21a87af07c21 -r bc3c70c24c86 tests/kernel/h_execregs_unimpl.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/kernel/h_execregs_unimpl.c Tue Feb 18 16:55:53 2025 +0000 @@ -0,0 +1,37 @@ +/* $NetBSD$ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__RCSID("$NetBSD$"); + +int +main(void) +{ + + return 127; +} diff -r 21a87af07c21 -r bc3c70c24c86 tests/kernel/t_execregs.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/kernel/t_execregs.c Tue Feb 18 16:55:53 2025 +0000 @@ -0,0 +1,185 @@ +/* $NetBSD$ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__RCSID("$NetBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_EXECREGS_TEST + +#include "execregs.h" +#include "h_macros.h" + +static void +readregs(int rfd, register_t regs[static NEXECREGS]) +{ + uint8_t *p; + size_t n; + ssize_t nread; + + p = (void *)regs; + n = NEXECREGS*sizeof(regs[0]); + while (n) { + RL(nread = read(rfd, p, n)); + ATF_CHECK_MSG((size_t)nread <= n, + "overlong read: %zu > %zu", (size_t)nread, n); + if (nread == 0) + break; + p += (size_t)nread; + n -= (size_t)nread; + } + ATF_REQUIRE_EQ_MSG(n, 0, + "truncated read, missing %zu bytes", n); +} + +static void +checkregs(const register_t regs[static NEXECREGS]) +{ + unsigned i; + +#if defined(__hppa__) || \ + defined(__ia64__) || \ + defined(__vax__) || \ + defined(__x86_64__) + atf_tc_expect_fail("PR kern/59084: exec/spawn leaks register content"); +#endif + + for (i = 0; i < NEXECREGS; i++) { + if (regs[i] != 0) { + for (i = 0; i < NEXECREGS; i++) { + fprintf(stderr, "[%s] %"PRIxREGISTER"\n", + regname[i], regs[i]); + } + fprintf(stderr, "\n"); + atf_tc_fail("registers not zeroed"); + } + } +} + +static void +testregs(int child, const int pipefd[static 2], + register_t regs[static NEXECREGS]) +{ + int status; + + RL(close(pipefd[1])); + + readregs(pipefd[0], regs); + + RL(waitpid(child, &status, 0)); + ATF_CHECK_EQ_MSG(status, 0, "status=0x%x", status); + + checkregs(regs); +} + +#endif + +ATF_TC(execregszero); +ATF_TC_HEAD(execregszero, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test execve(2) zeroes registers"); +} +ATF_TC_BODY(execregszero, tc) +{ +#ifdef HAVE_EXECREGS_TEST + char h_execregs[PATH_MAX]; + int pipefd[2]; + register_t regs[NEXECREGS]; + pid_t child; + + RL(snprintf(h_execregs, sizeof(h_execregs), "%s/h_execregs", + atf_tc_get_config_var(tc, "srcdir"))); + + RL(pipe(pipefd)); + memset(regs, 0x5a, sizeof(regs)); + + RL(child = fork()); + if (child == 0) { + if (dup2(pipefd[1], STDOUT_FILENO) == -1) + err(1, "dup2"); + if (closefrom(STDERR_FILENO + 1) == -1) + err(1, "closefrom"); + if (execregschild(h_execregs) == -1) + err(1, "execve"); + _exit(2); + } + + testregs(child, pipefd, regs); +#else + atf_tc_skip("missing test for PR kern/59084:" + " exec/spawn leaks register content"); +#endif +} + +ATF_TC(spawnregszero); +ATF_TC_HEAD(spawnregszero, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test posix_spawn(2) zeroes registers"); +} +ATF_TC_BODY(spawnregszero, tc) +{ +#ifdef HAVE_EXECREGS_TEST + char h_execregs[PATH_MAX]; + int pipefd[2]; + register_t regs[NEXECREGS]; + pid_t child; + + RL(snprintf(h_execregs, sizeof(h_execregs), "%s/h_execregs", + atf_tc_get_config_var(tc, "srcdir"))); + + RL(pipe(pipefd)); + memset(regs, 0x5a, sizeof(regs)); + + RL(child = spawnregschild(h_execregs, pipefd[1])); + + testregs(child, pipefd, regs); +#else + atf_tc_skip("missing test for PR kern/59084:" + " exec/spawn leaks register content"); +#endif +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, execregszero); + ATF_TP_ADD_TC(tp, spawnregszero); + + return atf_no_error(); +} # HG changeset patch # User Taylor R Campbell # Date 1740606281 0 # Wed Feb 26 21:44:41 2025 +0000 # Branch trunk # Node ID ea5c4f171dfa675d431d656cb1de9a2eec5530a2 # Parent bc3c70c24c866c9cf171734b393e50a42edb9637 # EXP-Topic riastradh-pr59085-execregleak Clear trapframe on exec. Do this for all architectures, even if the trapframe is fully initialized -- makes it easier to audit and be confident it's correct, and most likely (with the exception of sh3 which has an intermediate call to ufetch_int in the middle) the compiler can eliminate redundant stores in these routines. PR kern/59084: exec/spawn leaks register content diff -r bc3c70c24c86 -r ea5c4f171dfa sys/arch/alpha/alpha/machdep.c --- a/sys/arch/alpha/alpha/machdep.c Tue Feb 18 16:55:53 2025 +0000 +++ b/sys/arch/alpha/alpha/machdep.c Wed Feb 26 21:44:41 2025 +0000 @@ -1684,11 +1684,11 @@ setregs(register struct lwp *l, struct e panic("crash requested by boot flags"); #endif + memset(tfp, 0, sizeof(*tfp)); + #ifdef DEBUG for (i = 0; i < FRAME_SIZE; i++) tfp->tf_regs[i] = 0xbabefacedeadbeef; -#else - memset(tfp->tf_regs, 0, FRAME_SIZE * sizeof tfp->tf_regs[0]); #endif pcb = lwp_getpcb(l); memset(&pcb->pcb_fp, 0, sizeof(pcb->pcb_fp)); diff -r bc3c70c24c86 -r ea5c4f171dfa sys/arch/amd64/amd64/machdep.c --- a/sys/arch/amd64/amd64/machdep.c Tue Feb 18 16:55:53 2025 +0000 +++ b/sys/arch/amd64/amd64/machdep.c Wed Feb 26 21:44:41 2025 +0000 @@ -1388,6 +1388,8 @@ setregs(struct lwp *l, struct exec_packa kpreempt_enable(); tf = l->l_md.md_regs; + memset(tf, 0, sizeof(*tf)); + tf->tf_ds = GSEL(GUDATA_SEL, SEL_UPL); tf->tf_es = GSEL(GUDATA_SEL, SEL_UPL); tf->tf_rdi = 0; diff -r bc3c70c24c86 -r ea5c4f171dfa sys/arch/hppa/hppa/machdep.c --- a/sys/arch/hppa/hppa/machdep.c Tue Feb 18 16:55:53 2025 +0000 +++ b/sys/arch/hppa/hppa/machdep.c Wed Feb 26 21:44:41 2025 +0000 @@ -1889,6 +1889,8 @@ setregs(struct lwp *l, struct exec_packa struct trapframe *tf = l->l_md.md_regs; struct pcb *pcb = lwp_getpcb(l); + memset(tf, 0, sizeof(*tf)); + tf->tf_flags = TFF_SYS|TFF_LAST; tf->tf_iioq_tail = 4 + (tf->tf_iioq_head = pack->ep_entry | HPPA_PC_PRIV_USER); diff -r bc3c70c24c86 -r ea5c4f171dfa sys/arch/i386/i386/machdep.c --- a/sys/arch/i386/i386/machdep.c Tue Feb 18 16:55:53 2025 +0000 +++ b/sys/arch/i386/i386/machdep.c Wed Feb 26 21:44:41 2025 +0000 @@ -859,6 +859,8 @@ setregs(struct lwp *l, struct exec_packa x86_dbregs_clear(l); tf = l->l_md.md_regs; + memset(tf, 0, sizeof(*tf)); + tf->tf_gs = GSEL(GUGS_SEL, SEL_UPL); tf->tf_fs = GSEL(GUFS_SEL, SEL_UPL); tf->tf_es = LSEL(LUDATA_SEL, SEL_UPL); diff -r bc3c70c24c86 -r ea5c4f171dfa sys/arch/ia64/ia64/machdep.c --- a/sys/arch/ia64/ia64/machdep.c Tue Feb 18 16:55:53 2025 +0000 +++ b/sys/arch/ia64/ia64/machdep.c Wed Feb 26 21:44:41 2025 +0000 @@ -710,6 +710,8 @@ setregs(register struct lwp *l, struct e vaddr_t uv = uvm_lwp_getuarea(l); tf = l->l_md.md_tf; + memset(tf, 0, sizeof(*tf)); + regstkp = uv + sizeof(struct pcb); ksttop = diff -r bc3c70c24c86 -r ea5c4f171dfa sys/arch/m68k/m68k/m68k_machdep.c --- a/sys/arch/m68k/m68k/m68k_machdep.c Tue Feb 18 16:55:53 2025 +0000 +++ b/sys/arch/m68k/m68k/m68k_machdep.c Wed Feb 26 21:44:41 2025 +0000 @@ -93,6 +93,8 @@ setregs(struct lwp *l, struct exec_packa struct trapframe *tf = (struct trapframe *)l->l_md.md_regs; struct pcb *pcb = lwp_getpcb(l); + memset(tf, 0, sizeof(*tf)); + tf->tf_sr = PSL_USERSET; tf->tf_pc = pack->ep_entry & ~1; tf->tf_regs[D0] = 0; diff -r bc3c70c24c86 -r ea5c4f171dfa sys/arch/mips/mips/mips_machdep.c --- a/sys/arch/mips/mips/mips_machdep.c Tue Feb 18 16:55:53 2025 +0000 +++ b/sys/arch/mips/mips/mips_machdep.c Wed Feb 26 21:44:41 2025 +0000 @@ -1697,7 +1697,7 @@ setregs(struct lwp *l, struct exec_packa struct trapframe * const tf = l->l_md.md_utf; struct proc * const p = l->l_proc; - memset(tf, 0, sizeof(struct trapframe)); + memset(tf, 0, sizeof(*tf)); tf->tf_regs[_R_SP] = (intptr_t)stack; tf->tf_regs[_R_PC] = (intptr_t)pack->ep_entry & ~3; tf->tf_regs[_R_T9] = (intptr_t)pack->ep_entry & ~3; /* abicall requirement */ diff -r bc3c70c24c86 -r ea5c4f171dfa sys/arch/sh3/sh3/sh3_machdep.c --- a/sys/arch/sh3/sh3/sh3_machdep.c Tue Feb 18 16:55:53 2025 +0000 +++ b/sys/arch/sh3/sh3/sh3_machdep.c Wed Feb 26 21:44:41 2025 +0000 @@ -518,6 +518,7 @@ setregs(struct lwp *l, struct exec_packa l->l_md.md_flags &= ~(MDL_USEDFPU | MDL_SSTEP); tf = l->l_md.md_regs; + memset(tf, 0, sizeof(*tf)); tf->tf_ssr = PSL_USERSET; tf->tf_spc = pack->ep_entry; diff -r bc3c70c24c86 -r ea5c4f171dfa sys/arch/vax/vax/trap.c --- a/sys/arch/vax/vax/trap.c Tue Feb 18 16:55:53 2025 +0000 +++ b/sys/arch/vax/vax/trap.c Wed Feb 26 21:44:41 2025 +0000 @@ -371,6 +371,8 @@ setregs(struct lwp *l, struct exec_packa { struct trapframe * const tf = l->l_md.md_utf; + memset(tf, 0, sizeof(*tf)); + tf->tf_pc = pack->ep_entry + 2; tf->tf_sp = stack; tf->tf_r6 = stack; /* for ELF */ diff -r bc3c70c24c86 -r ea5c4f171dfa tests/kernel/t_execregs.c --- a/tests/kernel/t_execregs.c Tue Feb 18 16:55:53 2025 +0000 +++ b/tests/kernel/t_execregs.c Wed Feb 26 21:44:41 2025 +0000 @@ -71,13 +71,6 @@ checkregs(const register_t regs[static N { unsigned i; -#if defined(__hppa__) || \ - defined(__ia64__) || \ - defined(__vax__) || \ - defined(__x86_64__) - atf_tc_expect_fail("PR kern/59084: exec/spawn leaks register content"); -#endif - for (i = 0; i < NEXECREGS; i++) { if (regs[i] != 0) { for (i = 0; i < NEXECREGS; i++) {