seccomp: add SECCOMP_RET_ACK for non-fatal SIGSYS

Started by Kees Cook on Jan 29, 2016 · 4 messages from 3 authors · Last reply Jan 31, 2016

Subsystems (3)

Maintainers (3)

STALE3937d

open the first message on its own page

Message details and related content
Tracing processes for syscall usage can be done one step at a time with
SECCOMP_RET_TRAP, but this will block the syscall. Alternatively, using
a ptrace manager to handle SECCOMP_RET_TRACE returns can be used but is
heavy weight and depends on the ptrace infrastructure. A light-weight
method to learn syscalls is needed, which can reuse the existing delivery
of SIGSYS but without skipping the syscall. This is implemented as
SECCOMP_RET_ACK which is as permissive as SECCOMP_RET_ALLOW but delivers
SIGSYS after syscall completion, as long as the SECCOMP_RET_DATA is
non-zero. A signal handler can install a new rule for each syscall as
they are signaled with SECCOMP_RET_DATA set to 0 to disable reporting
for that syscall in the future (which is required for restarting syscalls
that are signal-sensitive like nanosleep).

Registers from the signal will reflect registers after the syscall returns
rather than before. Signal-sensitive syscalls will trigger EINTR, so they
must be whitelisted before they are resumed. Not allowing the sigreturn
syscall (and likely prctl to whitelist) will make using SECCOMP_RET_ACK
useless.

Signed-off-by: Kees Cook <redacted>
---
I don't like the name SECCOMP_RET_ACK, and SECCOMP_RET_ALLOW_SIGSYS
seems too long. SECCOMP_RET_RAISE? SECCOMP_RET_SIGSYS?
---
 Documentation/prctl/seccomp_filter.txt | 16 ++++++++++++++++
 include/uapi/linux/seccomp.h           |  1 +
 kernel/seccomp.c                       |  5 +++++
 3 files changed, 22 insertions(+)
diff --git a/Documentation/prctl/seccomp_filter.txt b/Documentation/prctl/seccomp_filter.txt
index 1e469ef75778..847da72d94f4 100644
--- a/Documentation/prctl/seccomp_filter.txt
+++ b/Documentation/prctl/seccomp_filter.txt
@@ -138,6 +138,22 @@ SECCOMP_RET_TRACE:
 	allow use of ptrace, even of other sandboxed processes, without
 	extreme care; ptracers can use this mechanism to escape.)
 
+SECCOMP_RET_ACK:
+	When the SECCOMP_RET_DATA portion is 0, this is the same
+	as SECCOMP_RET_ALLOW. When non-zero, this is the same as
+	SECCOMP_RET_TRAP except the syscall is executed normally
+	and register contents will show the state after the syscall.
+
+	For syscalls that are sensitive to pending signals, the
+	raised signal will interrupt the syscall. If these syscalls
+	are restarted immediately, they will loop forever. Users of
+	SECCOMP_RET_ACK need to add a new filter for each syscall
+	that sets a zero SECCOMP_RET_DATA to disable these kinds of
+	syscalls if they are not explicitly whitelisted to being with.
+
+	Whitelisting sigreturn (and likely prctl) is needed to use
+	SECCOMP_RET_ACK in a meaningful way.
+
 SECCOMP_RET_ALLOW:
 	Results in the system call being executed.
 
diff --git a/include/uapi/linux/seccomp.h b/include/uapi/linux/seccomp.h
index 0f238a43ff1e..285cd3a04052 100644
--- a/include/uapi/linux/seccomp.h
+++ b/include/uapi/linux/seccomp.h
@@ -29,6 +29,7 @@
 #define SECCOMP_RET_TRAP	0x00030000U /* disallow and force a SIGSYS */
 #define SECCOMP_RET_ERRNO	0x00050000U /* returns an errno */
 #define SECCOMP_RET_TRACE	0x7ff00000U /* pass to a tracer or disallow */
+#define SECCOMP_RET_ACK		0x7ffc0000U /* allow and send SIGSYS */
 #define SECCOMP_RET_ALLOW	0x7fff0000U /* allow */
 
 /* Masks for the return value sections. */
diff --git a/kernel/seccomp.c b/kernel/seccomp.c
index 580ac2d4024f..6eefbb2060d8 100644
--- a/kernel/seccomp.c
+++ b/kernel/seccomp.c
@@ -608,6 +608,11 @@ static u32 __seccomp_phase1_filter(int this_syscall, struct seccomp_data *sd)
 	case SECCOMP_RET_TRACE:
 		return filter_ret;  /* Save the rest for phase 2. */
 
+	case SECCOMP_RET_ACK:
+		/* Post SIGSYS on syscall return, with 16 bits of data. */
+		if (data)
+			seccomp_send_sigsys(this_syscall, data);
+		/* Fall through. */
 	case SECCOMP_RET_ALLOW:
 		return SECCOMP_PHASE1_OK;
 
-- 
2.6.3


-- 
Kees Cook
Chrome OS & Brillo Security
Message details and related content
On Thu, Jan 28, 2016 at 5:06 PM, Kees Cook [off-list ref] wrote:
Tracing processes for syscall usage can be done one step at a time with
SECCOMP_RET_TRAP, but this will block the syscall. Alternatively, using
a ptrace manager to handle SECCOMP_RET_TRACE returns can be used but is
heavy weight and depends on the ptrace infrastructure. A light-weight
method to learn syscalls is needed, which can reuse the existing delivery
of SIGSYS but without skipping the syscall. This is implemented as
SECCOMP_RET_ACK which is as permissive as SECCOMP_RET_ALLOW but delivers
SIGSYS after syscall completion, as long as the SECCOMP_RET_DATA is
non-zero. A signal handler can install a new rule for each syscall as
they are signaled with SECCOMP_RET_DATA set to 0 to disable reporting
for that syscall in the future (which is required for restarting syscalls
that are signal-sensitive like nanosleep).

Registers from the signal will reflect registers after the syscall returns
rather than before. Signal-sensitive syscalls will trigger EINTR, so they
must be whitelisted before they are resumed. Not allowing the sigreturn
syscall (and likely prctl to whitelist) will make using SECCOMP_RET_ACK
useless.

Signed-off-by: Kees Cook <redacted>
Could this use task_work to queue the signal on return to user mode
instead?  Would that solve the EINTR issues?

--Andy
Message details and related content
Thanks! This is just what I need.

What are the drawbacks to returning the sigsys before executing the
system call? Otherwise this loses the benefit of properly reporting
registers for argument inspection.

How about SECCOMP_RET_PERMISSIVE? Describes the application rather
than the implementation. Otherwise preference is for
SECCOMP_RET_ALLOW_SIGSYS.
Message details and related content
On Jan 28, 2016 6:33 PM, "Andy Lutomirski" [off-list ref] wrote:
On Thu, Jan 28, 2016 at 5:06 PM, Kees Cook [off-list ref] wrote:
quoted
Tracing processes for syscall usage can be done one step at a time with
SECCOMP_RET_TRAP, but this will block the syscall. Alternatively, using
a ptrace manager to handle SECCOMP_RET_TRACE returns can be used but is
heavy weight and depends on the ptrace infrastructure. A light-weight
method to learn syscalls is needed, which can reuse the existing delivery
of SIGSYS but without skipping the syscall. This is implemented as
SECCOMP_RET_ACK which is as permissive as SECCOMP_RET_ALLOW but delivers
SIGSYS after syscall completion, as long as the SECCOMP_RET_DATA is
non-zero. A signal handler can install a new rule for each syscall as
they are signaled with SECCOMP_RET_DATA set to 0 to disable reporting
for that syscall in the future (which is required for restarting syscalls
that are signal-sensitive like nanosleep).

Registers from the signal will reflect registers after the syscall returns
rather than before. Signal-sensitive syscalls will trigger EINTR, so they
must be whitelisted before they are resumed. Not allowing the sigreturn
syscall (and likely prctl to whitelist) will make using SECCOMP_RET_ACK
useless.

Signed-off-by: Kees Cook <redacted>
Could this use task_work to queue the signal on return to user mode
instead?  Would that solve the EINTR issues?
As another option, use the existing TRAP option but add a way for a
process to set a flag such that it can delete and re-add a filter.
Then you get SIGSYS, delete the old filter, add a new one that allows
the current syscall, and resume.  No funny business with EINTR or
clobbered regs.

--Andy
Keyboard shortcuts
hback out one level
jnext message in thread / next series-diff position
kprevious message in thread / previous series-diff position
ldrill in
Escclose help / fold thread tree
?toggle this help