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: Tyler Hicks <tyhicks@canonical.com> Suggested-by: Andy Lutomirski <luto@amacapital.net> Signed-off-by: Kees Cook <keescook@chromium.org>
This commit is contained in:
		
							parent
							
								
									8e5f1ad116
								
							
						
					
					
						commit
						d612b1fd80
					
				| @ -11,8 +11,9 @@ | ||||
| #define SECCOMP_MODE_FILTER	2 /* uses user-supplied filter. */ | ||||
| 
 | ||||
| /* Valid operations for seccomp syscall. */ | ||||
| #define SECCOMP_SET_MODE_STRICT	0 | ||||
| #define SECCOMP_SET_MODE_FILTER	1 | ||||
| #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 | ||||
|  | ||||
| @ -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; | ||||
| 	} | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user