Date: Fri, 16 Jul 2021 17:07:47 GMT From: David Chisnall <theraven@FreeBSD.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org Subject: git: cf98bc28d39d - main - Pass the syscall number to capsicum permission-denied signals Message-ID: <202107161707.16GH7lXA028965@gitrepo.freebsd.org>
next in thread | raw e-mail | index | archive | help
The branch main has been updated by theraven: URL: https://cgit.FreeBSD.org/src/commit/?id=cf98bc28d39d6df5386ac57375af1b60af5d6bb3 commit cf98bc28d39d6df5386ac57375af1b60af5d6bb3 Author: David Chisnall <theraven@FreeBSD.org> AuthorDate: 2021-07-10 16:19:52 +0000 Commit: David Chisnall <theraven@FreeBSD.org> CommitDate: 2021-07-16 17:06:44 +0000 Pass the syscall number to capsicum permission-denied signals The syscall number is stored in the same register as the syscall return on amd64 (and possibly other architectures) and so it is impossible to recover in the signal handler after the call has returned. This small tweak delivers it in the `si_value` field of the signal, which is sufficient to catch capability violations and emulate them with a call to a more-privileged process in the signal handler. This reapplies 3a522ba1bc852c3d4660a4fa32e4a94999d09a47 with a fix for the static assertion failure on i386. Approved by: markj (mentor) Reviewed by: kib, bcr (manpages) Differential Revision: https://reviews.freebsd.org/D29185 --- lib/libc/sys/procctl.2 | 10 ++++++++++ share/man/man3/siginfo.3 | 2 ++ sys/amd64/amd64/trap.c | 1 + sys/amd64/cloudabi32/cloudabi32_sysvec.c | 1 + sys/amd64/cloudabi64/cloudabi64_sysvec.c | 1 + sys/amd64/ia32/ia32_syscall.c | 1 + sys/amd64/include/proc.h | 1 + sys/amd64/linux/linux_sysvec.c | 1 + sys/amd64/linux32/linux32_sysvec.c | 1 + sys/arm/arm/syscall.c | 1 + sys/arm/cloudabi32/cloudabi32_sysvec.c | 1 + sys/arm/include/proc.h | 1 + sys/arm64/arm64/elf32_machdep.c | 1 + sys/arm64/arm64/trap.c | 1 + sys/arm64/cloudabi32/cloudabi32_sysvec.c | 1 + sys/arm64/cloudabi64/cloudabi64_sysvec.c | 1 + sys/arm64/include/proc.h | 1 + sys/arm64/linux/linux_sysvec.c | 1 + sys/i386/cloudabi32/cloudabi32_sysvec.c | 1 + sys/i386/i386/trap.c | 1 + sys/i386/include/proc.h | 1 + sys/i386/linux/linux_sysvec.c | 1 + sys/kern/kern_thread.c | 4 ++-- sys/kern/subr_syscall.c | 1 + sys/mips/include/proc.h | 1 + sys/mips/mips/trap.c | 1 + sys/powerpc/include/proc.h | 1 + sys/powerpc/powerpc/trap.c | 1 + sys/riscv/include/proc.h | 1 + sys/riscv/riscv/trap.c | 1 + sys/sys/signal.h | 7 +++++++ 31 files changed, 48 insertions(+), 2 deletions(-) diff --git a/lib/libc/sys/procctl.2 b/lib/libc/sys/procctl.2 index 432ed5919a81..ce7a2be5d5e4 100644 --- a/lib/libc/sys/procctl.2 +++ b/lib/libc/sys/procctl.2 @@ -454,6 +454,16 @@ and the .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 index acc8785b2f0d..7f8a809cdfa5 100644 --- a/share/man/man3/siginfo.3 +++ b/share/man/man3/siginfo.3 @@ -85,6 +85,8 @@ timer overrun count .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 index 55649687ce50..b08495f3f139 100644 --- a/sys/amd64/amd64/trap.c +++ b/sys/amd64/amd64/trap.c @@ -1059,6 +1059,7 @@ cpu_fetch_syscall_args(struct thread *td) sa = &td->td_sa; sa->code = frame->tf_rax; + sa->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 index 164f87e90e91..26924ed5a980 100644 --- a/sys/amd64/cloudabi32/cloudabi32_sysvec.c +++ b/sys/amd64/cloudabi32/cloudabi32_sysvec.c @@ -101,6 +101,7 @@ cloudabi32_fetch_syscall_args(struct thread *td) /* Obtain system call number. */ sa->code = frame->tf_rax; + sa->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 index d3893902b08e..c08d912e84d4 100644 --- a/sys/amd64/cloudabi64/cloudabi64_sysvec.c +++ b/sys/amd64/cloudabi64/cloudabi64_sysvec.c @@ -98,6 +98,7 @@ cloudabi64_fetch_syscall_args(struct thread *td) /* Obtain system call number. */ sa->code = frame->tf_rax; + sa->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 index 6c9399d1a52f..9294ef8ce741 100644 --- a/sys/amd64/ia32/ia32_syscall.c +++ b/sys/amd64/ia32/ia32_syscall.c @@ -150,6 +150,7 @@ ia32_fetch_syscall_args(struct thread *td) params = (caddr_t)frame->tf_rsp + sizeof(u_int32_t); sa->code = frame->tf_rax; + sa->original_code = sa->code; /* * Need to check if this is a 32 bit or 64 bit syscall. diff --git a/sys/amd64/include/proc.h b/sys/amd64/include/proc.h index 59796e729ac4..0f8cf50e326d 100644 --- a/sys/amd64/include/proc.h +++ b/sys/amd64/include/proc.h @@ -92,6 +92,7 @@ struct mdproc { struct syscall_args { u_int code; + u_int original_code; struct sysent *callp; register_t args[8]; }; diff --git a/sys/amd64/linux/linux_sysvec.c b/sys/amd64/linux/linux_sysvec.c index c5538932b1e3..566af6de29e7 100644 --- a/sys/amd64/linux/linux_sysvec.c +++ b/sys/amd64/linux/linux_sysvec.c @@ -191,6 +191,7 @@ linux_fetch_syscall_args(struct thread *td) sa->args[4] = frame->tf_r8; sa->args[5] = frame->tf_r9; sa->code = frame->tf_rax; + sa->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 index 504d57e418a5..7dfd57a74a1e 100644 --- a/sys/amd64/linux32/linux32_sysvec.c +++ b/sys/amd64/linux32/linux32_sysvec.c @@ -662,6 +662,7 @@ linux32_fetch_syscall_args(struct thread *td) sa->args[4] = frame->tf_rdi; sa->args[5] = frame->tf_rbp; /* Unconfirmed */ sa->code = frame->tf_rax; + sa->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 index a851db6e4556..a635de0ec716 100644 --- a/sys/arm/arm/syscall.c +++ b/sys/arm/arm/syscall.c @@ -108,6 +108,7 @@ cpu_fetch_syscall_args(struct thread *td) nap = 4; sa = &td->td_sa; sa->code = td->td_frame->tf_r7; + sa->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 index a8c5da47d265..4df57b22e13d 100644 --- a/sys/arm/cloudabi32/cloudabi32_sysvec.c +++ b/sys/arm/cloudabi32/cloudabi32_sysvec.c @@ -78,6 +78,7 @@ cloudabi32_fetch_syscall_args(struct thread *td) /* Obtain system call number. */ sa->code = frame->tf_r12; + sa->original_code = sa->code; if (sa->code >= CLOUDABI32_SYS_MAXSYSCALL) return (ENOSYS); sa->callp = &cloudabi32_sysent[sa->code]; diff --git a/sys/arm/include/proc.h b/sys/arm/include/proc.h index a37ccd8f621c..9566c264731e 100644 --- a/sys/arm/include/proc.h +++ b/sys/arm/include/proc.h @@ -75,6 +75,7 @@ struct mdproc { */ struct syscall_args { u_int code; + u_int original_code; struct sysent *callp; register_t args[MAXARGS]; } __aligned(8); diff --git a/sys/arm64/arm64/elf32_machdep.c b/sys/arm64/arm64/elf32_machdep.c index 206413b45172..7cedbffc4d43 100644 --- a/sys/arm64/arm64/elf32_machdep.c +++ b/sys/arm64/arm64/elf32_machdep.c @@ -175,6 +175,7 @@ freebsd32_fetch_syscall_args(struct thread *td) /* r7 is the syscall id */ sa->code = td->td_frame->tf_x[7]; + sa->original_code = sa->code; if (sa->code == SYS_syscall) { sa->code = *ap++; diff --git a/sys/arm64/arm64/trap.c b/sys/arm64/arm64/trap.c index e876fa5011c3..c6dd8c276414 100644 --- a/sys/arm64/arm64/trap.c +++ b/sys/arm64/arm64/trap.c @@ -130,6 +130,7 @@ cpu_fetch_syscall_args(struct thread *td) dst_ap = &sa->args[0]; sa->code = td->td_frame->tf_x[8]; + sa->original_code = sa->code; if (__predict_false(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 index 889393560ede..b7be5cc0e5e3 100644 --- a/sys/arm64/cloudabi32/cloudabi32_sysvec.c +++ b/sys/arm64/cloudabi32/cloudabi32_sysvec.c @@ -75,6 +75,7 @@ cloudabi32_fetch_syscall_args(struct thread *td) /* Obtain system call number. */ sa->code = frame->tf_x[0]; + sa->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 index bdbd828b7b62..624d86693457 100644 --- a/sys/arm64/cloudabi64/cloudabi64_sysvec.c +++ b/sys/arm64/cloudabi64/cloudabi64_sysvec.c @@ -78,6 +78,7 @@ cloudabi64_fetch_syscall_args(struct thread *td) /* Obtain system call number. */ sa->code = frame->tf_x[8]; + sa->original_code = sa->code; if (sa->code >= CLOUDABI64_SYS_MAXSYSCALL) return (ENOSYS); sa->callp = &cloudabi64_sysent[sa->code]; diff --git a/sys/arm64/include/proc.h b/sys/arm64/include/proc.h index bb933dc98241..3800798d79b7 100644 --- a/sys/arm64/include/proc.h +++ b/sys/arm64/include/proc.h @@ -49,6 +49,7 @@ struct mdproc { #define MAXARGS 8 struct syscall_args { u_int code; + u_int original_code; struct sysent *callp; register_t args[MAXARGS]; }; diff --git a/sys/arm64/linux/linux_sysvec.c b/sys/arm64/linux/linux_sysvec.c index 40f68a537985..e684fb604889 100644 --- a/sys/arm64/linux/linux_sysvec.c +++ b/sys/arm64/linux/linux_sysvec.c @@ -123,6 +123,7 @@ linux_fetch_syscall_args(struct thread *td) sa = &td->td_sa; sa->code = td->td_frame->tf_x[8]; + sa->original_code = sa->code; /* LINUXTODO: generic syscall? */ if (sa->code >= p->p_sysent->sv_size) sa->callp = &p->p_sysent->sv_table[0]; diff --git a/sys/i386/cloudabi32/cloudabi32_sysvec.c b/sys/i386/cloudabi32/cloudabi32_sysvec.c index 4f12d2b6cbce..e0a50f6697a9 100644 --- a/sys/i386/cloudabi32/cloudabi32_sysvec.c +++ b/sys/i386/cloudabi32/cloudabi32_sysvec.c @@ -96,6 +96,7 @@ cloudabi32_fetch_syscall_args(struct thread *td) /* Obtain system call number. */ sa->code = frame->tf_eax; + sa->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 index 045478149be5..07abac23c9da 100644 --- a/sys/i386/i386/trap.c +++ b/sys/i386/i386/trap.c @@ -1052,6 +1052,7 @@ cpu_fetch_syscall_args(struct thread *td) #endif sa->code = frame->tf_eax; + sa->original_code = sa->code; params = (caddr_t)frame->tf_esp + sizeof(uint32_t); /* diff --git a/sys/i386/include/proc.h b/sys/i386/include/proc.h index 2950946ff155..76e1ac611474 100644 --- a/sys/i386/include/proc.h +++ b/sys/i386/include/proc.h @@ -64,6 +64,7 @@ struct mdproc { struct syscall_args { u_int code; + u_int original_code; struct sysent *callp; register_t args[8]; }; diff --git a/sys/i386/linux/linux_sysvec.c b/sys/i386/linux/linux_sysvec.c index adb70fded6dc..a0959d55b585 100644 --- a/sys/i386/linux/linux_sysvec.c +++ b/sys/i386/linux/linux_sysvec.c @@ -756,6 +756,7 @@ linux_fetch_syscall_args(struct thread *td) sa = &td->td_sa; sa->code = frame->tf_eax; + sa->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_thread.c b/sys/kern/kern_thread.c index 7d971d295cba..328a69bc5f23 100644 --- a/sys/kern/kern_thread.c +++ b/sys/kern/kern_thread.c @@ -108,9 +108,9 @@ _Static_assert(offsetof(struct thread, td_flags) == 0x98, "struct thread KBI td_flags"); _Static_assert(offsetof(struct thread, td_pflags) == 0xa0, "struct thread KBI td_pflags"); -_Static_assert(offsetof(struct thread, td_frame) == 0x300, +_Static_assert(offsetof(struct thread, td_frame) == 0x304, "struct thread KBI td_frame"); -_Static_assert(offsetof(struct thread, td_emuldata) == 0x344, +_Static_assert(offsetof(struct thread, td_emuldata) == 0x348, "struct thread KBI td_emuldata"); _Static_assert(offsetof(struct proc, p_flag) == 0x6c, "struct proc KBI p_flag"); diff --git a/sys/kern/subr_syscall.c b/sys/kern/subr_syscall.c index 85a0814a2125..2304e3e7f3f9 100644 --- a/sys/kern/subr_syscall.c +++ b/sys/kern/subr_syscall.c @@ -230,6 +230,7 @@ syscallret(struct thread *td) ksi.ksi_signo = SIGTRAP; ksi.ksi_errno = td->td_errno; ksi.ksi_code = TRAP_CAP; + ksi.ksi_info.si_syscall = sa->original_code; trapsignal(td, &ksi); } } diff --git a/sys/mips/include/proc.h b/sys/mips/include/proc.h index 0cb1d433387c..29d832a162e6 100644 --- a/sys/mips/include/proc.h +++ b/sys/mips/include/proc.h @@ -84,6 +84,7 @@ struct mdproc { #define MAXARGS 8 struct syscall_args { u_int code; + u_int original_code; struct sysent *callp; register_t args[MAXARGS]; }; diff --git a/sys/mips/mips/trap.c b/sys/mips/mips/trap.c index 96a2de4ee817..9d7a07606373 100644 --- a/sys/mips/mips/trap.c +++ b/sys/mips/mips/trap.c @@ -355,6 +355,7 @@ cpu_fetch_syscall_args(struct thread *td) else locr0->pc += sizeof(int); sa->code = locr0->v0; + sa->original_code = sa->code; switch (sa->code) { case SYS___syscall: diff --git a/sys/powerpc/include/proc.h b/sys/powerpc/include/proc.h index d4df3ccfefef..aac4e66b39fc 100644 --- a/sys/powerpc/include/proc.h +++ b/sys/powerpc/include/proc.h @@ -62,6 +62,7 @@ struct mdproc { #define MAXARGS 8 struct syscall_args { u_int code; + u_int original_code; struct sysent *callp; register_t args[MAXARGS]; }; diff --git a/sys/powerpc/powerpc/trap.c b/sys/powerpc/powerpc/trap.c index 3a1bdf7cde07..ab5189a0f418 100644 --- a/sys/powerpc/powerpc/trap.c +++ b/sys/powerpc/powerpc/trap.c @@ -667,6 +667,7 @@ cpu_fetch_syscall_args(struct thread *td) sa = &td->td_sa; sa->code = frame->fixreg[0]; + sa->original_code = sa->code; params = (caddr_t)(frame->fixreg + FIRSTARG); n = NARGREG; diff --git a/sys/riscv/include/proc.h b/sys/riscv/include/proc.h index 4b5ae9ebe3ed..1c6c8d2919b5 100644 --- a/sys/riscv/include/proc.h +++ b/sys/riscv/include/proc.h @@ -48,6 +48,7 @@ struct mdproc { #define MAXARGS 8 struct syscall_args { u_int code; + u_int original_code; struct sysent *callp; register_t args[MAXARGS]; }; diff --git a/sys/riscv/riscv/trap.c b/sys/riscv/riscv/trap.c index 07d7f84a94e8..8844638c8204 100644 --- a/sys/riscv/riscv/trap.c +++ b/sys/riscv/riscv/trap.c @@ -103,6 +103,7 @@ cpu_fetch_syscall_args(struct thread *td) dst_ap = &sa->args[0]; sa->code = td->td_frame->tf_t[0]; + sa->original_code = sa->code; if (__predict_false(sa->code == SYS_syscall || sa->code == SYS___syscall)) { sa->code = *ap++; diff --git a/sys/sys/signal.h b/sys/sys/signal.h index 8b45a521c3ee..9dae3ce04745 100644 --- a/sys/sys/signal.h +++ b/sys/sys/signal.h @@ -255,6 +255,12 @@ typedef struct __siginfo { 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 @@ typedef struct __siginfo { #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 {
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202107161707.16GH7lXA028965>