diff options
| author | Zach Riggle <zachriggle@users.noreply.github.com> | 2018-09-17 04:33:11 -0500 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2018-09-17 11:33:11 +0200 |
| commit | 0eca949a6c271b879d582e01c3d1d79dc704172c (patch) | |
| tree | ff6c780fbf4993aaa11036de414a74c28ac0fb5d /executor/common_linux.h | |
| parent | fd85ed48854729938fad986fc81e1c57a667fb36 (diff) | |
RFC: android: Add support for untrusted_app sandboxing (#697)
executor: add support for android_untrusted_app sandbox
This adds a new sandbox type, 'android_untrusted_app', which restricts
syz-executor to the privileges which are available to third-party applications,
e.g. those installed from the Google Play store.
In particular, this uses the UID space reserved for applications (instead of
the 'setuid' sandbox, which uses the traditional 'nobody' user / 65534)
as well as a set of groups which the Android-specific kernels are aware of,
and finally ensures that the SELinux context is set appropriately.
Dependencies on libselinux are avoided by manually implementing the few
functions that are needed to change the context of the current process,
and arbitrary files. The underlying mechanisms are relatively simple.
Fixes google/syzkaller#643
Test: make presubmit
Bug: http://b/112900774
Diffstat (limited to 'executor/common_linux.h')
| -rw-r--r-- | executor/common_linux.h | 143 |
1 files changed, 139 insertions, 4 deletions
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> |
