From 4aae71eea65dbdff608f8029f71677e7d69909a2 Mon Sep 17 00:00:00 2001 From: borysp Date: Fri, 25 Sep 2020 19:12:39 +0200 Subject: [PATCH] [LibOS] Make list of supplementary group ids dynamically allocated --- LibOS/shim/src/sys/shim_exec.c | 1 + LibOS/shim/src/sys/shim_fork.c | 1 + LibOS/shim/src/sys/shim_getpid.c | 81 +++++++++++++++++------- LibOS/shim/test/regression/.gitignore | 1 + LibOS/shim/test/regression/Makefile | 1 + LibOS/shim/test/regression/groups.c | 62 ++++++++++++++++++ LibOS/shim/test/regression/test_libos.py | 6 ++ 7 files changed, 130 insertions(+), 23 deletions(-) create mode 100644 LibOS/shim/test/regression/groups.c diff --git a/LibOS/shim/src/sys/shim_exec.c b/LibOS/shim/src/sys/shim_exec.c index c2a641c6..7057e097 100644 --- a/LibOS/shim/src/sys/shim_exec.c +++ b/LibOS/shim/src/sys/shim_exec.c @@ -166,6 +166,7 @@ static BEGIN_MIGRATION_DEF(execve, struct shim_thread* thread, struct shim_proce DEFINE_MIGRATE(migratable, NULL, 0); DEFINE_MIGRATE(arguments, argv, 0); DEFINE_MIGRATE(environ, envp, 0); + DEFINE_MIGRATE(groups_info, NULL, 0); } END_MIGRATION_DEF(execve) diff --git a/LibOS/shim/src/sys/shim_fork.c b/LibOS/shim/src/sys/shim_fork.c index fffa0d00..45215950 100644 --- a/LibOS/shim/src/sys/shim_fork.c +++ b/LibOS/shim/src/sys/shim_fork.c @@ -33,6 +33,7 @@ static BEGIN_MIGRATION_DEF(fork, struct shim_thread* thread, struct shim_process #ifdef DEBUG DEFINE_MIGRATE(gdb_map, NULL, 0); #endif + DEFINE_MIGRATE(groups_info, NULL, 0); } END_MIGRATION_DEF(fork) diff --git a/LibOS/shim/src/sys/shim_getpid.c b/LibOS/shim/src/sys/shim_getpid.c index 52724794..36d85393 100644 --- a/LibOS/shim/src/sys/shim_getpid.c +++ b/LibOS/shim/src/sys/shim_getpid.c @@ -70,60 +70,95 @@ int shim_do_setgid(gid_t gid) { #define NGROUPS_MAX 65536 /* # of supplemental group IDs; has to be same as host OS */ static struct groups_info_t { - int size; - gid_t spl_gid[NGROUPS_MAX]; -} g_groups_info __attribute_migratable = {.size = -1}; + size_t count; + gid_t* groups; +} g_groups_info = { .count = 0, .groups = NULL }; int shim_do_setgroups(int gidsetsize, gid_t* grouplist) { - if ((unsigned)gidsetsize > NGROUPS_MAX) + if (gidsetsize < 0 || (unsigned int)gidsetsize > NGROUPS_MAX) return -EINVAL; - if (gidsetsize && test_user_memory(grouplist, gidsetsize * sizeof(gid_t), true)) + if (gidsetsize && test_user_memory(grouplist, gidsetsize * sizeof(gid_t), /*write=*/false)) return -EFAULT; - lock(&cur_process.lock); - g_groups_info.size = gidsetsize; - for (int i = 0; i < gidsetsize; i++) { - g_groups_info.spl_gid[i] = grouplist[i]; + size_t groups_len = (size_t)gidsetsize; + gid_t* groups = (gid_t*)malloc(groups_len * sizeof(*groups)); + if (!groups) { + return -ENOMEM; } + for (size_t i = 0; i < groups_len; i++) { + groups[i] = grouplist[i]; + } + + void* old_groups = NULL; + lock(&cur_process.lock); + g_groups_info.count = groups_len; + old_groups = g_groups_info.groups; + g_groups_info.groups = groups; unlock(&cur_process.lock); + free(old_groups); + return 0; } int shim_do_getgroups(int gidsetsize, gid_t* grouplist) { - int cur_groups_size; - if (gidsetsize < 0) return -EINVAL; - if (gidsetsize && test_user_memory(grouplist, gidsetsize * sizeof(gid_t), true)) + if (gidsetsize && test_user_memory(grouplist, gidsetsize * sizeof(gid_t), /*write=*/true)) return -EFAULT; lock(&cur_process.lock); + size_t ret_size = g_groups_info.count; - if (g_groups_info.size == -1) { - /* initialize with getgid() */ - g_groups_info.size = 1; - g_groups_info.spl_gid[0] = shim_do_getgid(); - } - - cur_groups_size = g_groups_info.size; if (gidsetsize) { - if (cur_groups_size > gidsetsize) { + if (ret_size > (size_t)gidsetsize) { unlock(&cur_process.lock); return -EINVAL; } - for (int i = 0; i < cur_groups_size; i++) { - grouplist[i] = g_groups_info.spl_gid[i]; + for (size_t i = 0; i < g_groups_info.count; i++) { + grouplist[i] = g_groups_info.groups[i]; } } unlock(&cur_process.lock); - return cur_groups_size; + + return (int)ret_size; } +BEGIN_CP_FUNC(groups_info) { + __UNUSED(size); + __UNUSED(objp); + __UNUSED(obj); + + lock(&cur_process.lock); + + size_t copy_size = g_groups_info.count * sizeof(*g_groups_info.groups); + + size_t off = ADD_CP_OFFSET(sizeof(size_t) + copy_size); + + *(size_t*)((char*)base + off) = g_groups_info.count; + gid_t* new_groups = (gid_t*)((char*)base + off + sizeof(size_t)); + + memcpy(new_groups, g_groups_info.groups, copy_size); + + unlock(&cur_process.lock); + + ADD_CP_FUNC_ENTRY(off); +} +END_CP_FUNC(groups_info) + +BEGIN_RS_FUNC(groups_info) { + __UNUSED(offset); + __UNUSED(rebase); + size_t off = GET_CP_FUNC_ENTRY(); + g_groups_info.count = *(size_t*)((char*)base + off); + g_groups_info.groups = (gid_t*)((char*)base + off + sizeof(size_t)); +} +END_RS_FUNC(groups_info) + uid_t shim_do_geteuid(void) { struct shim_thread* cur = get_cur_thread(); return cur ? cur->euid : 0; diff --git a/LibOS/shim/test/regression/.gitignore b/LibOS/shim/test/regression/.gitignore index 254539a0..0168ee98 100644 --- a/LibOS/shim/test/regression/.gitignore +++ b/LibOS/shim/test/regression/.gitignore @@ -39,6 +39,7 @@ /getdents /getsockname /getsockopt +/groups /host_root_fs /init_fail /large_dir_read diff --git a/LibOS/shim/test/regression/Makefile b/LibOS/shim/test/regression/Makefile index e90ee776..cc4060d0 100644 --- a/LibOS/shim/test/regression/Makefile +++ b/LibOS/shim/test/regression/Makefile @@ -35,6 +35,7 @@ c_executables = \ getdents \ getsockname \ getsockopt \ + groups \ host_root_fs \ init_fail \ large_mmap \ diff --git a/LibOS/shim/test/regression/groups.c b/LibOS/shim/test/regression/groups.c new file mode 100644 index 00000000..a96e8e27 --- /dev/null +++ b/LibOS/shim/test/regression/groups.c @@ -0,0 +1,62 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include + +#define ARRAY_LEN(x) (sizeof(x) / sizeof(x[0])) + +static gid_t test_groups[] = { 0, 1337, 1337, 0 }; + +int main(void) { + setbuf(stdout, NULL); + setbuf(stderr, NULL); + + int x = getgroups(0, NULL); + if (x < 0) { + err(1, "getgroups"); + } + + gid_t groups[ARRAY_LEN(test_groups)]; + memcpy(groups, test_groups, sizeof(groups)); + + x = setgroups(ARRAY_LEN(groups), groups); + if (x != 0) { + err(1, "setgroups"); + } + + memset(groups, 0, sizeof(groups)); + + pid_t pid = fork(); + if (pid < 0) { + err(1, "fork"); + } else if (pid > 0) { + int status = 0; + if (waitpid(pid, &status, 0) < 0) { + err(1, "waitpid"); + } + if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { + errx(1, "invalid child return status: %d", status); + } + } + + x = getgroups(ARRAY_LEN(groups), groups); + if (x < 0) { + err(1, "getgroups"); + } else if (x != ARRAY_LEN(groups)) { + errx(1, "getgroups returned invalid length: %d (expected: %zu)", x, ARRAY_LEN(groups)); + } + + for (size_t i = 0; i < ARRAY_LEN(groups); i++) { + if (groups[i] != test_groups[i]) { + errx(1, "invalid group: %d (expected: %d)", groups[i], test_groups[i]); + } + } + + printf("%s OK\n", pid == 0 ? "child" : "parent"); + return 0; +} + diff --git a/LibOS/shim/test/regression/test_libos.py b/LibOS/shim/test/regression/test_libos.py index 942d78d3..f26a576d 100644 --- a/LibOS/shim/test/regression/test_libos.py +++ b/LibOS/shim/test/regression/test_libos.py @@ -492,6 +492,12 @@ class TC_30_Syscall(RegressionTestCase): stdout, _ = self.run_binary(['signal_multithread']) self.assertIn('TEST OK', stdout) + def test_100_get_set_groups(self): + stdout, _ = self.run_binary(['groups']) + self.assertIn('child OK', stdout); + self.assertIn('parent OK', stdout); + + @unittest.skipUnless(HAS_SGX, 'This test is only meaningful on SGX PAL because only SGX catches raw ' 'syscalls and redirects to Graphene\'s LibOS. If we will add seccomp to '