diff --git a/exile.c b/exile.c index f9a8294..a8f029d 100644 --- a/exile.c +++ b/exile.c @@ -625,6 +625,8 @@ struct exile_policy *exile_init_policy() result->not_dumpable = 1; result->no_new_privs = 1; result->namespace_options = EXILE_UNSHARE_MOUNT | EXILE_UNSHARE_USER; + result->namespace_uid = 0; + result->namespace_gid = 0; return result; } @@ -938,7 +940,7 @@ void exile_free_policy(struct exile_policy *ctxt) } /* Enters the specified namespaces */ -static int enter_namespaces(int namespace_options) +static int enter_namespaces(int namespace_options, uid_t namespace_uid, gid_t namespace_gid) { if(namespace_options & EXILE_UNSHARE_USER) { @@ -975,7 +977,7 @@ static int enter_namespaces(int namespace_options) EXILE_LOG_ERROR("Failed to open /proc/self/uid_map for writing"); return -1; } - writesize = snprintf(buf, sizeof(buf), "0 %u 1\n", current_uid); + writesize = snprintf(buf, sizeof(buf), "%u %u 1\n", namespace_uid, current_uid); writeret = write(fd, buf, writesize); if(writeret < 0 || writeret < writesize) { @@ -991,7 +993,7 @@ static int enter_namespaces(int namespace_options) EXILE_LOG_ERROR("Failed to open /proc/self/gid_map for writing"); return -1; } - writesize = snprintf(buf, sizeof(buf), "0 %u 1\n", current_gid); + writesize = snprintf(buf, sizeof(buf), "%u %u 1\n", namespace_gid, current_gid); writeret = write(fd, buf, writesize); if(writeret < 0 || writeret < writesize) { @@ -1541,7 +1543,7 @@ int exile_enable_policy(struct exile_policy *policy) close_file_fds(); } - if(enter_namespaces(policy->namespace_options) < 0) + if(enter_namespaces(policy->namespace_options, policy->namespace_uid, policy->namespace_gid) < 0) { EXILE_LOG_ERROR("Error while trying to enter namespaces\n"); return -1; diff --git a/exile.h b/exile.h index 76d7248..7061fdd 100644 --- a/exile.h +++ b/exile.h @@ -375,6 +375,9 @@ struct exile_policy uint64_t vow_promises; + uid_t namespace_uid; + gid_t namespace_gid; + /* Do not manually add policies here, use exile_append_path_policies() */ struct exile_path_policy *path_policies; struct exile_path_policy **path_policies_tail; diff --git a/test.c b/test.c index 683a277..168c682 100644 --- a/test.c +++ b/test.c @@ -755,8 +755,50 @@ int test_unshare_user() } return 0; +} +int test_unshare_user_own_uid() +{ + uid_t uid = getuid(); + gid_t gid = getgid(); + char uidstr[64]; + snprintf(uidstr, sizeof(uidstr), "%u", uid); + + char gidstr[64]; + snprintf(gidstr, sizeof(gidstr), "%u", gid); + + struct exile_policy *policy = exile_init_policy(); + policy->namespace_options = EXILE_UNSHARE_USER; + policy->namespace_gid = gid; + policy->namespace_uid = uid; + xexile_enable_policy(policy); + + if(do_test_nsuidmap("/proc/self/uid_map", uidstr, uidstr, "1") != 0) + { + LOG("/proc/self/uid_map failed\n"); + return 1; + } + + if(do_test_nsuidmap("/proc/self/gid_map", gidstr, gidstr, "1") != 0) + { + LOG("/proc/self/gid_map failed\n"); + return 1; + } + + FILE *fp = fopen("/proc/self/setgroups", "r"); + + char buffer[4096] = { 0 }; + fread(buffer, sizeof(buffer), 1, fp); + fclose(fp); + + if(strcmp(buffer, "deny\n") != 0) + { + LOG("/proc/self/setgroups does not contain 'deny'\n"); + return 1; + } + + return 0; } struct dispatcher @@ -788,6 +830,8 @@ struct dispatcher dispatchers[] = { { "vow_from_str", &test_vows_from_str}, { "clone3_nosys", &test_clone3_nosys}, { "unshare-user", &test_unshare_user}, + { "unshare-user-own-uid", &test_unshare_user_own_uid}, + };