diff --git a/lib/libc/sys/procctl.2 b/lib/libc/sys/procctl.2 --- a/lib/libc/sys/procctl.2 +++ b/lib/libc/sys/procctl.2 @@ -413,6 +413,16 @@ .Va si_code member is set to .Dv TRAP_CAP . +The system call number is stored in the +.Va si_syscall +field of the +.Fa siginfo +signal handler parameter. +The other system call parameters can be read from the +.Fa ucontext_t +but the system call number is typically stored in the register +that also contains the return value and so is unavailable in the +signal handler. .Pp See .Xr capsicum 4 diff --git a/share/man/man3/siginfo.3 b/share/man/man3/siginfo.3 --- a/share/man/man3/siginfo.3 +++ b/share/man/man3/siginfo.3 @@ -85,6 +85,8 @@ .It Vt int Ta Va si_mqd Ta .Tn POSIX message queue ID +.It Vt int Ta Va si_syscall Ta +system-call number for system calls blocked by Capsicum .El .Pp The diff --git a/sys/amd64/amd64/trap.c b/sys/amd64/amd64/trap.c --- a/sys/amd64/amd64/trap.c +++ b/sys/amd64/amd64/trap.c @@ -995,6 +995,7 @@ regcnt = NARGREGS; sa->code = frame->tf_rax; + td->original_code = sa->code; if (sa->code == SYS_syscall || sa->code == SYS___syscall) { sa->code = frame->tf_rdi; @@ -1040,6 +1041,7 @@ sa = &td->td_sa; sa->code = frame->tf_rax; + td->original_code = sa->code; if (__predict_false(sa->code == SYS_syscall || sa->code == SYS___syscall || diff --git a/sys/amd64/cloudabi32/cloudabi32_sysvec.c b/sys/amd64/cloudabi32/cloudabi32_sysvec.c --- a/sys/amd64/cloudabi32/cloudabi32_sysvec.c +++ b/sys/amd64/cloudabi32/cloudabi32_sysvec.c @@ -101,6 +101,7 @@ /* Obtain system call number. */ sa->code = frame->tf_rax; + td->original_code = sa->code; if (sa->code >= CLOUDABI32_SYS_MAXSYSCALL) return (ENOSYS); sa->callp = &cloudabi32_sysent[sa->code]; diff --git a/sys/amd64/cloudabi64/cloudabi64_sysvec.c b/sys/amd64/cloudabi64/cloudabi64_sysvec.c --- a/sys/amd64/cloudabi64/cloudabi64_sysvec.c +++ b/sys/amd64/cloudabi64/cloudabi64_sysvec.c @@ -97,6 +97,7 @@ /* Obtain system call number. */ sa->code = frame->tf_rax; + td->original_code = sa->code; if (sa->code >= CLOUDABI64_SYS_MAXSYSCALL) return (ENOSYS); sa->callp = &cloudabi64_sysent[sa->code]; diff --git a/sys/amd64/ia32/ia32_syscall.c b/sys/amd64/ia32/ia32_syscall.c --- a/sys/amd64/ia32/ia32_syscall.c +++ b/sys/amd64/ia32/ia32_syscall.c @@ -151,6 +151,7 @@ params = (caddr_t)frame->tf_rsp + sizeof(u_int32_t); sa->code = frame->tf_rax; + td->original_code = sa->code; /* * Need to check if this is a 32 bit or 64 bit syscall. diff --git a/sys/amd64/linux/linux_sysvec.c b/sys/amd64/linux/linux_sysvec.c --- a/sys/amd64/linux/linux_sysvec.c +++ b/sys/amd64/linux/linux_sysvec.c @@ -191,6 +191,7 @@ sa->args[4] = frame->tf_r8; sa->args[5] = frame->tf_r9; sa->code = frame->tf_rax; + td->original_code = sa->code; if (sa->code >= p->p_sysent->sv_size) /* nosys */ diff --git a/sys/amd64/linux32/linux32_sysvec.c b/sys/amd64/linux32/linux32_sysvec.c --- a/sys/amd64/linux32/linux32_sysvec.c +++ b/sys/amd64/linux32/linux32_sysvec.c @@ -657,6 +657,7 @@ sa->args[4] = frame->tf_rdi; sa->args[5] = frame->tf_rbp; /* Unconfirmed */ sa->code = frame->tf_rax; + td->original_code = sa->code; if (sa->code >= p->p_sysent->sv_size) /* nosys */ diff --git a/sys/arm/arm/syscall.c b/sys/arm/arm/syscall.c --- a/sys/arm/arm/syscall.c +++ b/sys/arm/arm/syscall.c @@ -108,6 +108,7 @@ sa = &td->td_sa; sa->code = td->td_frame->tf_r7; + td->original_code = sa->code; ap = &td->td_frame->tf_r0; if (sa->code == SYS_syscall) { sa->code = *ap++; diff --git a/sys/arm/cloudabi32/cloudabi32_sysvec.c b/sys/arm/cloudabi32/cloudabi32_sysvec.c --- a/sys/arm/cloudabi32/cloudabi32_sysvec.c +++ b/sys/arm/cloudabi32/cloudabi32_sysvec.c @@ -78,6 +78,7 @@ /* Obtain system call number. */ sa->code = frame->tf_r12; + td->original_code = sa->code; if (sa->code >= CLOUDABI32_SYS_MAXSYSCALL) return (ENOSYS); sa->callp = &cloudabi32_sysent[sa->code]; diff --git a/sys/arm64/arm64/trap.c b/sys/arm64/arm64/trap.c --- a/sys/arm64/arm64/trap.c +++ b/sys/arm64/arm64/trap.c @@ -109,6 +109,7 @@ sa = &td->td_sa; sa->code = td->td_frame->tf_x[8]; + td->original_code = sa->code; if (sa->code == SYS_syscall || sa->code == SYS___syscall) { sa->code = *ap++; diff --git a/sys/arm64/cloudabi32/cloudabi32_sysvec.c b/sys/arm64/cloudabi32/cloudabi32_sysvec.c --- a/sys/arm64/cloudabi32/cloudabi32_sysvec.c +++ b/sys/arm64/cloudabi32/cloudabi32_sysvec.c @@ -75,6 +75,7 @@ /* Obtain system call number. */ sa->code = frame->tf_x[0]; + td->original_code = sa->code; if (sa->code >= CLOUDABI32_SYS_MAXSYSCALL) return (ENOSYS); sa->callp = &cloudabi32_sysent[sa->code]; diff --git a/sys/arm64/cloudabi64/cloudabi64_sysvec.c b/sys/arm64/cloudabi64/cloudabi64_sysvec.c --- a/sys/arm64/cloudabi64/cloudabi64_sysvec.c +++ b/sys/arm64/cloudabi64/cloudabi64_sysvec.c @@ -78,6 +78,7 @@ /* Obtain system call number. */ sa->code = frame->tf_x[8]; + td->original_code = sa->code; if (sa->code >= CLOUDABI64_SYS_MAXSYSCALL) return (ENOSYS); sa->callp = &cloudabi64_sysent[sa->code]; diff --git a/sys/arm64/linux/linux_sysvec.c b/sys/arm64/linux/linux_sysvec.c --- a/sys/arm64/linux/linux_sysvec.c +++ b/sys/arm64/linux/linux_sysvec.c @@ -118,6 +118,7 @@ sa = &td->td_sa; sa->code = td->td_frame->tf_x[8]; + td->original_code = sa->code; /* LINUXTODO: generic syscall? */ if (p->p_sysent->sv_mask) sa->code &= p->p_sysent->sv_mask; diff --git a/sys/i386/cloudabi32/cloudabi32_sysvec.c b/sys/i386/cloudabi32/cloudabi32_sysvec.c --- a/sys/i386/cloudabi32/cloudabi32_sysvec.c +++ b/sys/i386/cloudabi32/cloudabi32_sysvec.c @@ -96,6 +96,7 @@ /* Obtain system call number. */ sa->code = frame->tf_eax; + td->original_code = sa->code; if (sa->code >= CLOUDABI32_SYS_MAXSYSCALL) return (ENOSYS); sa->callp = &cloudabi32_sysent[sa->code]; diff --git a/sys/i386/i386/trap.c b/sys/i386/i386/trap.c --- a/sys/i386/i386/trap.c +++ b/sys/i386/i386/trap.c @@ -1064,6 +1064,7 @@ #endif sa->code = frame->tf_eax; + td->original_code = sa->code; params = (caddr_t)frame->tf_esp + sizeof(uint32_t); /* diff --git a/sys/i386/linux/linux_sysvec.c b/sys/i386/linux/linux_sysvec.c --- a/sys/i386/linux/linux_sysvec.c +++ b/sys/i386/linux/linux_sysvec.c @@ -739,6 +739,7 @@ sa = &td->td_sa; sa->code = frame->tf_eax; + td->original_code = sa->code; sa->args[0] = frame->tf_ebx; sa->args[1] = frame->tf_ecx; sa->args[2] = frame->tf_edx; diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c --- a/sys/kern/kern_fork.c +++ b/sys/kern/kern_fork.c @@ -505,6 +505,19 @@ td2->td_vnet_lpush = NULL; #endif + /* + * Propagate the system call number to the new thread. This should never + * be needed because if a system call was not blocked by Capsicum then this + * field will not be read. We never deliver a signal in the child if a + * system call is blocked in the parent. + * + * This is set anyway so that a future use of this field will have the same + * behaviour in the stable back-port branches as in 14-CURRENT (where this + * value is part of the system-call arguments structure and not the thread + * structure). + */ + td2->original_code = td->original_code; + /* * Allow the scheduler to initialize the child. */ diff --git a/sys/kern/subr_syscall.c b/sys/kern/subr_syscall.c --- a/sys/kern/subr_syscall.c +++ b/sys/kern/subr_syscall.c @@ -199,6 +199,7 @@ ksi.ksi_signo = SIGTRAP; ksi.ksi_errno = td->td_errno; ksi.ksi_code = TRAP_CAP; + ksi.ksi_info.si_syscall = td->original_code; trapsignal(td, &ksi); } } diff --git a/sys/mips/mips/trap.c b/sys/mips/mips/trap.c --- a/sys/mips/mips/trap.c +++ b/sys/mips/mips/trap.c @@ -355,6 +355,7 @@ else locr0->pc += sizeof(int); sa->code = locr0->v0; + td->original_code = sa->code; switch (sa->code) { case SYS___syscall: diff --git a/sys/powerpc/powerpc/trap.c b/sys/powerpc/powerpc/trap.c --- a/sys/powerpc/powerpc/trap.c +++ b/sys/powerpc/powerpc/trap.c @@ -582,6 +582,7 @@ sa = &td->td_sa; sa->code = frame->fixreg[0]; + td->original_code = sa->code; params = (caddr_t)(frame->fixreg + FIRSTARG); n = NARGREG; diff --git a/sys/riscv/riscv/trap.c b/sys/riscv/riscv/trap.c --- a/sys/riscv/riscv/trap.c +++ b/sys/riscv/riscv/trap.c @@ -105,6 +105,7 @@ ap = &td->td_frame->tf_a[0]; sa->code = td->td_frame->tf_t[0]; + td->original_code = sa->code; if (sa->code == SYS_syscall || sa->code == SYS___syscall) { sa->code = *ap++; diff --git a/sys/sys/proc.h b/sys/sys/proc.h --- a/sys/sys/proc.h +++ b/sys/sys/proc.h @@ -372,6 +372,8 @@ struct mdthread td_md; /* (k) Any machine-dependent fields. */ #endif int td_pflags2; /* (k) Private thread (TDP2_*) flags. */ + int original_code; /* System call number. Undefined when + not in a syscall. */ }; struct thread0_storage { diff --git a/sys/sys/signal.h b/sys/sys/signal.h --- a/sys/sys/signal.h +++ b/sys/sys/signal.h @@ -255,6 +255,12 @@ struct { long _band; /* band event for SIGPOLL */ } _poll; /* was this ever used ? */ + struct { + int _syscall; /* Syscall number for signals + * delivered as a result of + * system calls denied by + * Capsicum. */ + } _capsicum; struct { long __spare1__; int __spare2__[7]; @@ -267,6 +273,7 @@ #define si_overrun _reason._timer._overrun #define si_mqd _reason._mesgq._mqd #define si_band _reason._poll._band +#define si_syscall _reason._capsicum._syscall #if defined(_WANT_LWPINFO32) || (defined(_KERNEL) && defined(__LP64__)) struct siginfo32 {