Something went wrong. Try again.
(I'm so sorry!) Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300// SPDX-License-Identifier: GPL-2.0#define _GNU_SOURCE#include <errno.h>#include <fcntl.h>#include <sched.h>#include <stdio.h>#include <string.h>#include <sys/wait.h>#include <unistd.h>#include "../kselftest_harness.h"
/* * The fields of a uid_map/gid_map line are stored in u32. Values that * do not fit, and negative values, must be rejected with EINVAL instead * of being silently truncated, and in-range values must still be * accepted. */
static int write_file(const char *path, const char *buf){ ssize_t len = strlen(buf); ssize_t ret; int fd;
fd = open(path, O_WRONLY | O_CLOEXEC); if (fd < 0) return -errno; ret = write(fd, buf, len); if (ret < 0) ret = -errno; close(fd); if (ret < 0) return ret; return ret == len ? 0 : -EIO;}
static ssize_t read_file(const char *path, char *buf, size_t size){ ssize_t ret; int fd;
fd = open(path, O_RDONLY | O_CLOEXEC); if (fd < 0) return -errno; ret = read(fd, buf, size - 1); if (ret < 0) ret = -errno; else buf[ret] = '\0'; close(fd); return ret;}
/* Enter a fresh user namespace, remembering the outer ids. */static int enter_userns(uid_t *uid, gid_t *gid){ *uid = geteuid(); *gid = getegid(); if (unshare(CLONE_NEWUSER) < 0) return -errno; /* Required before an unprivileged gid_map write. */ return write_file("/proc/self/setgroups", "deny");}
static void expect_rejected(struct __test_metadata *_metadata, const char *path, const char *line){ char buf[256];
TH_LOG("writing \"%s\" to %s", line, path); EXPECT_EQ(write_file(path, line), -EINVAL); /* Nothing may have been installed. */ EXPECT_EQ(read_file(path, buf, sizeof(buf)), 0) { TH_LOG("installed: %s", buf); }}
static void expect_accepted(struct __test_metadata *_metadata, const char *path, const char *line, unsigned int first, unsigned int lower_first, unsigned int count){ unsigned int f, l, c; char buf[256];
TH_LOG("writing \"%s\" to %s", line, path); ASSERT_EQ(write_file(path, line), 0);
ASSERT_GT(read_file(path, buf, sizeof(buf)), 0); ASSERT_EQ(sscanf(buf, "%u %u %u", &f, &l, &c), 3); EXPECT_EQ(f, first); EXPECT_EQ(l, lower_first); EXPECT_EQ(c, count); /* Exactly one extent. */ EXPECT_EQ(strchr(buf, '\n'), buf + strlen(buf) - 1);}
TEST(uid_map_first_above_u32){ char line[64]; uid_t uid; gid_t gid; int ret;
ret = enter_userns(&uid, &gid); if (ret) SKIP(return, "cannot set up user namespace: %s", strerror(-ret)); snprintf(line, sizeof(line), "4294967301 %u 1", uid); expect_rejected(_metadata, "/proc/self/uid_map", line);}
TEST(uid_map_lower_first_above_u32){ char line[64]; uid_t uid; gid_t gid; int ret;
ret = enter_userns(&uid, &gid); if (ret) SKIP(return, "cannot set up user namespace: %s", strerror(-ret)); snprintf(line, sizeof(line), "0 %llu 1", (1ULL << 32) + uid); expect_rejected(_metadata, "/proc/self/uid_map", line);}
TEST(uid_map_count_above_u32){ char line[64]; uid_t uid; gid_t gid; int ret;
ret = enter_userns(&uid, &gid); if (ret) SKIP(return, "cannot set up user namespace: %s", strerror(-ret)); snprintf(line, sizeof(line), "0 %u 4294967297", uid); expect_rejected(_metadata, "/proc/self/uid_map", line);}
TEST(gid_map_first_above_u32){ char line[64]; uid_t uid; gid_t gid; int ret;
ret = enter_userns(&uid, &gid); if (ret) SKIP(return, "cannot set up user namespace: %s", strerror(-ret)); snprintf(line, sizeof(line), "4294967301 %u 1", gid); expect_rejected(_metadata, "/proc/self/gid_map", line);}
TEST(uid_map_first_negative){ char line[64]; uid_t uid; gid_t gid; int ret;
ret = enter_userns(&uid, &gid); if (ret) SKIP(return, "cannot set up user namespace: %s", strerror(-ret)); snprintf(line, sizeof(line), "-1 %u 1", uid); expect_rejected(_metadata, "/proc/self/uid_map", line);}
TEST(uid_map_lower_first_negative){ uid_t uid; gid_t gid; int ret;
ret = enter_userns(&uid, &gid); if (ret) SKIP(return, "cannot set up user namespace: %s", strerror(-ret)); expect_rejected(_metadata, "/proc/self/uid_map", "0 -1 1");}
TEST(uid_map_count_negative){ char line[64]; uid_t uid; gid_t gid; int ret;
ret = enter_userns(&uid, &gid); if (ret) SKIP(return, "cannot set up user namespace: %s", strerror(-ret)); snprintf(line, sizeof(line), "0 %u -1", uid); expect_rejected(_metadata, "/proc/self/uid_map", line);}
TEST(uid_map_in_range){ char line[64]; uid_t uid; gid_t gid; int ret;
ret = enter_userns(&uid, &gid); if (ret) SKIP(return, "cannot set up user namespace: %s", strerror(-ret)); snprintf(line, sizeof(line), "5 %u 1", uid); expect_accepted(_metadata, "/proc/self/uid_map", line, 5, uid, 1);}
TEST(uid_map_zero){ char line[64]; uid_t uid; gid_t gid; int ret;
ret = enter_userns(&uid, &gid); if (ret) SKIP(return, "cannot set up user namespace: %s", strerror(-ret)); snprintf(line, sizeof(line), "0 %u 1", uid); expect_accepted(_metadata, "/proc/self/uid_map", line, 0, uid, 1);}
/* 4294967295 is (u32)-1, which map_write() refuses as a starting id. */TEST(uid_map_largest_first){ char line[64]; uid_t uid; gid_t gid; int ret;
ret = enter_userns(&uid, &gid); if (ret) SKIP(return, "cannot set up user namespace: %s", strerror(-ret)); snprintf(line, sizeof(line), "4294967294 %u 1", uid); expect_accepted(_metadata, "/proc/self/uid_map", line, 4294967294U, uid, 1);}
TEST(uid_map_extra_spaces){ char line[64]; uid_t uid; gid_t gid; int ret;
ret = enter_userns(&uid, &gid); if (ret) SKIP(return, "cannot set up user namespace: %s", strerror(-ret)); snprintf(line, sizeof(line), "0 %u 1", uid); expect_accepted(_metadata, "/proc/self/uid_map", line, 0, uid, 1);}
/* * An unprivileged writer may only map a single id, so the largest count * needs a privileged parent writing the map of a child namespace. With * first and lower_first 0, the no-wrap rule allows up to 4294967295. */TEST(uid_map_largest_count){ unsigned int first, lower_first, count; int to_child[2], from_child[2]; char path[64], buf[256]; pid_t pid; char c;
if (geteuid() != 0) SKIP(return, "needs root in the initial user namespace"); ASSERT_GT(read_file("/proc/self/uid_map", buf, sizeof(buf)), 0); ASSERT_EQ(sscanf(buf, "%u %u %u", &first, &lower_first, &count), 3); if (first != 0 || lower_first != 0 || count != 4294967295U) SKIP(return, "not in the initial user namespace");
ASSERT_EQ(pipe(to_child), 0); ASSERT_EQ(pipe(from_child), 0); pid = fork(); ASSERT_GE(pid, 0); if (pid == 0) { close(to_child[1]); close(from_child[0]); c = unshare(CLONE_NEWUSER) ? 'F' : 'K'; if (write(from_child[1], &c, 1) != 1) _exit(1); /* Stay alive until the parent is done with our uid_map. */ if (read(to_child[0], &c, 1) < 0) _exit(1); _exit(0); } close(to_child[0]); close(from_child[1]);
ASSERT_EQ(read(from_child[0], &c, 1), 1); ASSERT_EQ(c, 'K'); snprintf(path, sizeof(path), "/proc/%d/uid_map", pid); expect_accepted(_metadata, path, "0 0 4294967295", 0, 0, 4294967295U);
close(to_child[1]); EXPECT_EQ(waitpid(pid, NULL, 0), pid);}
TEST_HARNESS_MAIN