git: 3a522ba1bc85 - main - Pass the syscall number to capsicum permission-denied signals

David Chisnall theraven at FreeBSD.org
Sat Jul 10 16:20:11 UTC 2021


The branch main has been updated by theraven:

URL: https://cgit.FreeBSD.org/src/commit/?id=3a522ba1bc852c3d4660a4fa32e4a94999d09a47

commit 3a522ba1bc852c3d4660a4fa32e4a94999d09a47
Author:     David Chisnall <theraven at FreeBSD.org>
AuthorDate: 2021-07-10 16:19:52 +0000
Commit:     David Chisnall <theraven at FreeBSD.org>
CommitDate: 2021-07-10 16:19:52 +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.
    
    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/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 +++++++
 30 files changed, 46 insertions(+)

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 744b646b31c8..2b2d2e433efa 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 e1d3708b70e9..7749c1cd7fc8 100644
--- a/sys/arm64/linux/linux_sysvec.c
+++ b/sys/arm64/linux/linux_sysvec.c
@@ -125,6 +125,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/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 {


More information about the dev-commits-src-main mailing list