diff options
Diffstat (limited to 'executor')
| -rw-r--r-- | executor/common.h | 2 | ||||
| -rw-r--r-- | executor/common_akaros.h | 1 | ||||
| -rw-r--r-- | executor/common_bsd.h | 1 | ||||
| -rw-r--r-- | executor/common_fuchsia.h | 1 | ||||
| -rw-r--r-- | executor/common_linux.h | 143 | ||||
| -rw-r--r-- | executor/common_test.h | 1 | ||||
| -rw-r--r-- | executor/common_windows.h | 1 | ||||
| -rw-r--r-- | executor/executor.cc | 13 |
8 files changed, 155 insertions, 8 deletions
diff --git a/executor/common.h b/executor/common.h index 15b279956..fdc35436c 100644 --- a/executor/common.h +++ b/executor/common.h @@ -628,7 +628,7 @@ static void loop(void) [[RESULTS]] -#if SYZ_THREADED || SYZ_REPEAT || SYZ_SANDBOX_NONE || SYZ_SANDBOX_SETUID || SYZ_SANDBOX_NAMESPACE +#if SYZ_THREADED || SYZ_REPEAT || SYZ_SANDBOX_NONE || SYZ_SANDBOX_SETUID || SYZ_SANDBOX_NAMESPACE || SYZ_SANDBOX_ANDROID_UNTRUSTED_APP #if SYZ_THREADED void execute_call(int call) #elif SYZ_REPEAT diff --git a/executor/common_akaros.h b/executor/common_akaros.h index a0e42088a..8d83749dc 100644 --- a/executor/common_akaros.h +++ b/executor/common_akaros.h @@ -37,4 +37,5 @@ void child() #if SYZ_EXECUTOR #define do_sandbox_setuid() 0 #define do_sandbox_namespace() 0 +#define do_sandbox_android_untrusted_app() 0 #endif diff --git a/executor/common_bsd.h b/executor/common_bsd.h index 004009861..49c6b36de 100644 --- a/executor/common_bsd.h +++ b/executor/common_bsd.h @@ -17,6 +17,7 @@ static int do_sandbox_none(void) #if SYZ_EXECUTOR #define do_sandbox_setuid() 0 #define do_sandbox_namespace() 0 +#define do_sandbox_android_untrusted_app() 0 #endif #if GOOS_openbsd diff --git a/executor/common_fuchsia.h b/executor/common_fuchsia.h index 219aee865..fb08aa2a0 100644 --- a/executor/common_fuchsia.h +++ b/executor/common_fuchsia.h @@ -244,6 +244,7 @@ static int do_sandbox_none(void) #if SYZ_EXECUTOR #define do_sandbox_setuid() 0 #define do_sandbox_namespace() 0 +#define do_sandbox_android_untrusted_app() 0 #endif // Ugly way to work around gcc's "error: function called through a non-compatible type". diff --git a/executor/common_linux.h b/executor/common_linux.h index 2f5692105..5ae770800 100644 --- a/executor/common_linux.h +++ b/executor/common_linux.h @@ -545,7 +545,7 @@ static long syz_open_pts(long a0, long a1) #endif #if SYZ_EXECUTOR || __NR_syz_init_net_socket -#if SYZ_EXECUTOR || SYZ_SANDBOX_NONE || SYZ_SANDBOX_SETUID || SYZ_SANDBOX_NAMESPACE +#if SYZ_EXECUTOR || SYZ_SANDBOX_NONE || SYZ_SANDBOX_SETUID || SYZ_SANDBOX_NAMESPACE || SYZ_SANDBOX_ANDROID_UNTRUSTED_APP #include <fcntl.h> #include <sched.h> #include <sys/stat.h> @@ -1438,7 +1438,7 @@ static void setup_binfmt_misc() } #endif -#if SYZ_EXECUTOR || SYZ_SANDBOX_NONE || SYZ_SANDBOX_SETUID || SYZ_SANDBOX_NAMESPACE +#if SYZ_EXECUTOR || SYZ_SANDBOX_NONE || SYZ_SANDBOX_SETUID || SYZ_SANDBOX_NAMESPACE || SYZ_SANDBOX_ANDROID_UNTRUSTED_APP #include <errno.h> #include <sys/mount.h> @@ -1452,9 +1452,7 @@ static void setup_common() setup_binfmt_misc(); #endif } -#endif -#if SYZ_EXECUTOR || SYZ_SANDBOX_NONE || SYZ_SANDBOX_SETUID || SYZ_SANDBOX_NAMESPACE #include <sched.h> #include <sys/prctl.h> #include <sys/resource.h> @@ -1738,6 +1736,143 @@ static int do_sandbox_namespace(void) } #endif +#if SYZ_EXECUTOR || SYZ_SANDBOX_ANDROID_UNTRUSTED_APP +#include <fcntl.h> // open(2) +#include <grp.h> // setgroups +#include <sys/xattr.h> // setxattr, getxattr + +#define AID_NET_BT_ADMIN 3001 +#define AID_NET_BT 3002 +#define AID_INET 3003 +#define AID_EVERYBODY 9997 +#define AID_APP 10000 + +#define UNTRUSTED_APP_UID AID_APP + 999 +#define UNTRUSTED_APP_GID AID_APP + 999 + +const char* SELINUX_CONTEXT_UNTRUSTED_APP = "u:r:untrusted_app:s0:c512,c768"; +const char* SELINUX_LABEL_APP_DATA_FILE = "u:object_r:app_data_file:s0:c512,c768"; +const char* SELINUX_CONTEXT_FILE = "/proc/thread-self/attr/current"; +const char* SELINUX_XATTR_NAME = "security.selinux"; + +const gid_t UNTRUSTED_APP_GROUPS[] = {UNTRUSTED_APP_GID, AID_NET_BT_ADMIN, AID_NET_BT, AID_INET, AID_EVERYBODY}; +const size_t UNTRUSTED_APP_NUM_GROUPS = sizeof(UNTRUSTED_APP_GROUPS) / sizeof(UNTRUSTED_APP_GROUPS[0]); + +// Similar to libselinux getcon(3), but: +// - No library dependency +// - No dynamic memory allocation +// - Uses fail() instead of returning an error code +static void syz_getcon(char* context, size_t context_size) +{ + int fd = open(SELINUX_CONTEXT_FILE, O_RDONLY); + + if (fd < 0) + fail("getcon: Couldn't open %s", SELINUX_CONTEXT_FILE); + + ssize_t nread = read(fd, context, context_size); + + close(fd); + + if (nread <= 0) + fail("getcon: Failed to read from %s", SELINUX_CONTEXT_FILE); + + // The contents of the context file MAY end with a newline + // and MAY not have a null terminator. Handle this here. + if (context[nread - 1] == '\n') + context[nread - 1] = '\0'; +} + +// Similar to libselinux setcon(3), but: +// - No library dependency +// - No dynamic memory allocation +// - Uses fail() instead of returning an error code +static void syz_setcon(const char* context) +{ + char new_context[512]; + + // Attempt to write the new context + int fd = open(SELINUX_CONTEXT_FILE, O_WRONLY); + + if (fd < 0) + fail("setcon: Could not open %s", SELINUX_CONTEXT_FILE); + + ssize_t bytes_written = write(fd, context, strlen(context)); + + // N.B.: We cannot reuse this file descriptor, since the target SELinux context + // may not be able to read from it. + close(fd); + + if (bytes_written != (ssize_t)strlen(context)) + fail("setcon: Could not write entire context. Wrote %zi, expected %zu", bytes_written, strlen(context)); + + // Validate the transition by checking the context + syz_getcon(new_context, sizeof(new_context)); + + if (strcmp(context, new_context) != 0) + fail("setcon: Failed to change to %s, context is %s", context, new_context); +} + +// Similar to libselinux getfilecon(3), but: +// - No library dependency +// - No dynamic memory allocation +// - Uses fail() instead of returning an error code +static int syz_getfilecon(const char* path, char* context, size_t context_size) +{ + int length = getxattr(path, SELINUX_XATTR_NAME, context, context_size); + + if (length == -1) + fail("getfilecon: getxattr failed"); + + return length; +} + +// Similar to libselinux setfilecon(3), but: +// - No library dependency +// - No dynamic memory allocation +// - Uses fail() instead of returning an error code +static void syz_setfilecon(const char* path, const char* context) +{ + char new_context[512]; + + if (setxattr(path, SELINUX_XATTR_NAME, context, strlen(context) + 1, 0) != 0) + fail("setfilecon: setxattr failed"); + + if (syz_getfilecon(path, new_context, sizeof(new_context)) != 0) + fail("setfilecon: getfilecon failed"); + + if (strcmp(context, new_context) != 0) + fail("setfilecon: could not set context to %s, currently %s", context, new_context); +} + +static int do_sandbox_android_untrusted_app(void) +{ + setup_common(); + sandbox_common(); + + if (setgroups(UNTRUSTED_APP_NUM_GROUPS, UNTRUSTED_APP_GROUPS) != 0) + fail("setgroups failed"); + + if (setresgid(UNTRUSTED_APP_GID, UNTRUSTED_APP_GID, UNTRUSTED_APP_GID) != 0) + fail("setresgid failed"); + + if (setresuid(UNTRUSTED_APP_UID, UNTRUSTED_APP_UID, UNTRUSTED_APP_UID) != 0) + fail("setresuid failed"); + + syz_setfilecon(".", SELINUX_LABEL_APP_DATA_FILE); + syz_setcon(SELINUX_CONTEXT_UNTRUSTED_APP); + +#if SYZ_EXECUTOR || SYZ_TUN_ENABLE + initialize_tun(); +#endif +#if SYZ_EXECUTOR || SYZ_ENABLE_NETDEV + initialize_netdevices(); +#endif + + loop(); + doexit(1); +} +#endif + #if SYZ_EXECUTOR || SYZ_REPEAT && SYZ_USE_TMP_DIR #include <dirent.h> #include <errno.h> diff --git a/executor/common_test.h b/executor/common_test.h index 75ec81721..dc162a833 100644 --- a/executor/common_test.h +++ b/executor/common_test.h @@ -60,4 +60,5 @@ static int do_sandbox_none(void) #if SYZ_EXECUTOR #define do_sandbox_setuid() 0 #define do_sandbox_namespace() 0 +#define do_sandbox_android_untrusted_app() 0 #endif diff --git a/executor/common_windows.h b/executor/common_windows.h index b5520197f..2a89ea469 100644 --- a/executor/common_windows.h +++ b/executor/common_windows.h @@ -115,4 +115,5 @@ static int do_sandbox_none(void) #if SYZ_EXECUTOR #define do_sandbox_setuid() 0 #define do_sandbox_namespace() 0 +#define do_sandbox_android_untrusted_app() 0 #endif diff --git a/executor/executor.cc b/executor/executor.cc index 22fe8d50e..2244cc797 100644 --- a/executor/executor.cc +++ b/executor/executor.cc @@ -101,6 +101,7 @@ enum sandbox_type { sandbox_none, sandbox_setuid, sandbox_namespace, + sandbox_android_untrusted_app }; bool flag_debug; @@ -369,6 +370,9 @@ int main(int argc, char** argv) case sandbox_namespace: status = do_sandbox_namespace(); break; + case sandbox_android_untrusted_app: + status = do_sandbox_android_untrusted_app(); + break; default: fail("unknown sandbox type"); } @@ -415,6 +419,7 @@ void setup_control_pipes() void parse_env_flags(uint64 flags) { + // Note: Values correspond to ordering in pkg/ipc/ipc.go, e.g. FlagSandboxNamespace flag_debug = flags & (1 << 0); flag_cover = flags & (1 << 1); flag_sandbox = sandbox_none; @@ -422,9 +427,11 @@ void parse_env_flags(uint64 flags) flag_sandbox = sandbox_setuid; else if (flags & (1 << 3)) flag_sandbox = sandbox_namespace; - flag_enable_tun = flags & (1 << 4); - flag_enable_net_dev = flags & (1 << 5); - flag_enable_fault_injection = flags & (1 << 6); + else if (flags & (1 << 4)) + flag_sandbox = sandbox_android_untrusted_app; + flag_enable_tun = flags & (1 << 5); + flag_enable_net_dev = flags & (1 << 6); + flag_enable_fault_injection = flags & (1 << 7); } #if SYZ_EXECUTOR_USES_FORK_SERVER |
