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 3a522ba1bc
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
This commit is contained in:
parent
4652422eb4
commit
cf98bc28d3
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 ||
|
||||
|
@ -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];
|
||||
|
@ -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];
|
||||
|
@ -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.
|
||||
|
@ -92,6 +92,7 @@ struct mdproc {
|
||||
|
||||
struct syscall_args {
|
||||
u_int code;
|
||||
u_int original_code;
|
||||
struct sysent *callp;
|
||||
register_t args[8];
|
||||
};
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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++;
|
||||
|
@ -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];
|
||||
|
@ -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);
|
||||
|
@ -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++;
|
||||
|
@ -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++;
|
||||
|
@ -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];
|
||||
|
@ -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];
|
||||
|
@ -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];
|
||||
};
|
||||
|
@ -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];
|
||||
|
@ -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];
|
||||
|
@ -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);
|
||||
|
||||
/*
|
||||
|
@ -64,6 +64,7 @@ struct mdproc {
|
||||
|
||||
struct syscall_args {
|
||||
u_int code;
|
||||
u_int original_code;
|
||||
struct sysent *callp;
|
||||
register_t args[8];
|
||||
};
|
||||
|
@ -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;
|
||||
|
@ -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");
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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];
|
||||
};
|
||||
|
@ -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:
|
||||
|
@ -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];
|
||||
};
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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];
|
||||
};
|
||||
|
@ -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++;
|
||||
|
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user