Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d612b1fd authored by Tyler Hicks's avatar Tyler Hicks Committed by Kees Cook
Browse files

seccomp: Operation for checking if an action is available



Userspace code that needs to check if the kernel supports a given action
may not be able to use the /proc/sys/kernel/seccomp/actions_avail
sysctl. The process may be running in a sandbox and, therefore,
sufficient filesystem access may not be available. This patch adds an
operation to the seccomp(2) syscall that allows userspace code to ask
the kernel if a given action is available.

If the action is supported by the kernel, 0 is returned. If the action
is not supported by the kernel, -1 is returned with errno set to
-EOPNOTSUPP. If this check is attempted on a kernel that doesn't support
this new operation, -1 is returned with errno set to -EINVAL meaning
that userspace code will have the ability to differentiate between the
two error cases.

Signed-off-by: default avatarTyler Hicks <tyhicks@canonical.com>
Suggested-by: default avatarAndy Lutomirski <luto@amacapital.net>
Signed-off-by: default avatarKees Cook <keescook@chromium.org>
parent 8e5f1ad1
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -13,6 +13,7 @@
/* Valid operations for seccomp syscall. */
#define SECCOMP_SET_MODE_STRICT		0
#define SECCOMP_SET_MODE_FILTER		1
#define SECCOMP_GET_ACTION_AVAIL	2

/* Valid flags for SECCOMP_SET_MODE_FILTER */
#define SECCOMP_FILTER_FLAG_TSYNC	1
+26 −0
Original line number Diff line number Diff line
@@ -808,6 +808,27 @@ static inline long seccomp_set_mode_filter(unsigned int flags,
}
#endif

static long seccomp_get_action_avail(const char __user *uaction)
{
	u32 action;

	if (copy_from_user(&action, uaction, sizeof(action)))
		return -EFAULT;

	switch (action) {
	case SECCOMP_RET_KILL:
	case SECCOMP_RET_TRAP:
	case SECCOMP_RET_ERRNO:
	case SECCOMP_RET_TRACE:
	case SECCOMP_RET_ALLOW:
		break;
	default:
		return -EOPNOTSUPP;
	}

	return 0;
}

/* Common entry point for both prctl and syscall. */
static long do_seccomp(unsigned int op, unsigned int flags,
		       const char __user *uargs)
@@ -819,6 +840,11 @@ static long do_seccomp(unsigned int op, unsigned int flags,
		return seccomp_set_mode_strict();
	case SECCOMP_SET_MODE_FILTER:
		return seccomp_set_mode_filter(flags, uargs);
	case SECCOMP_GET_ACTION_AVAIL:
		if (flags != 0)
			return -EINVAL;

		return seccomp_get_action_avail(uargs);
	default:
		return -EINVAL;
	}
+36 −0
Original line number Diff line number Diff line
@@ -1731,6 +1731,10 @@ TEST_F_SIGNAL(TRACE_syscall, kill_after_ptrace, SIGSYS)
#define SECCOMP_SET_MODE_FILTER 1
#endif

#ifndef SECCOMP_GET_ACTION_AVAIL
#define SECCOMP_GET_ACTION_AVAIL 2
#endif

#ifndef SECCOMP_FILTER_FLAG_TSYNC
#define SECCOMP_FILTER_FLAG_TSYNC 1
#endif
@@ -2469,6 +2473,38 @@ TEST(syscall_restart)
		_metadata->passed = 0;
}

TEST(get_action_avail)
{
	__u32 actions[] = { SECCOMP_RET_KILL,  SECCOMP_RET_TRAP,
			    SECCOMP_RET_ERRNO, SECCOMP_RET_TRACE,
			    SECCOMP_RET_ALLOW };
	__u32 unknown_action = 0x10000000U;
	int i;
	long ret;

	ret = seccomp(SECCOMP_GET_ACTION_AVAIL, 0, &actions[0]);
	ASSERT_NE(ENOSYS, errno) {
		TH_LOG("Kernel does not support seccomp syscall!");
	}
	ASSERT_NE(EINVAL, errno) {
		TH_LOG("Kernel does not support SECCOMP_GET_ACTION_AVAIL operation!");
	}
	EXPECT_EQ(ret, 0);

	for (i = 0; i < ARRAY_SIZE(actions); i++) {
		ret = seccomp(SECCOMP_GET_ACTION_AVAIL, 0, &actions[i]);
		EXPECT_EQ(ret, 0) {
			TH_LOG("Expected action (0x%X) not available!",
			       actions[i]);
		}
	}

	/* Check that an unknown action is handled properly (EOPNOTSUPP) */
	ret = seccomp(SECCOMP_GET_ACTION_AVAIL, 0, &unknown_action);
	EXPECT_EQ(ret, -1);
	EXPECT_EQ(errno, EOPNOTSUPP);
}

/*
 * TODO:
 * - add microbenchmarks