#include "strv.h"
#include "tests.h"
#include "tmpfile-util.h"
+#include "uid-range.h"
char* setup_fake_runtime_dir(void) {
char t[] = "/tmp/fake-xdg-runtime-XXXXXX", *p;
assert_not_reached();
}
+bool userns_has_single_user(void) {
+ _cleanup_(uid_range_freep) UIDRange *uidrange = NULL, *gidrange = NULL;
+
+ /* Check if we're in a user namespace with only a single user mapped in. We special case this
+ * scenario in a few tests because it's the only kind of namespace that can be created unprivileged
+ * and as such happens more often than not, so we make sure to deal with it so that all tests pass
+ * in such environments. */
+
+ if (uid_range_load_userns(NULL, UID_RANGE_USERNS_INSIDE, &uidrange) < 0)
+ return false;
+
+ if (uid_range_load_userns(NULL, GID_RANGE_USERNS_INSIDE, &gidrange) < 0)
+ return false;
+
+ return uidrange->n_entries == 1 && uidrange->entries[0].nr == 1 &&
+ gidrange->n_entries == 1 && gidrange->entries[0].nr == 1;
+}
+
bool can_memlock(void) {
/* Let's see if we can mlock() a larger blob of memory. BPF programs are charged against
* RLIMIT_MEMLOCK, hence let's first make sure we can lock memory at all, and skip the test if we
int write_tmpfile(char *pattern, const char *contents);
bool have_namespaces(void);
+bool userns_has_single_user(void);
/* We use the small but non-trivial limit here */
#define CAN_MEMLOCK_SIZE (512 * 1024U)
cmd = strjoina("getfacl -p ", fn);
assert_se(system(cmd) == 0);
- if (getuid() == 0) {
+ if (getuid() == 0 && !userns_has_single_user()) {
const char *nobody = NOBODY_USER_NAME;
r = get_user_creds(&nobody, &uid, NULL, NULL, NULL, 0);
if (r < 0)
show_capabilities();
- test_drop_privileges();
+ if (!userns_has_single_user())
+ test_drop_privileges();
+
test_update_inherited_set();
- fork_test(test_have_effective_cap);
+ if (!userns_has_single_user())
+ fork_test(test_have_effective_cap);
if (run_ambient)
fork_test(test_apply_ambient_caps);
/* Paths underneath the "root" with different UIDs while using CHASE_SAFE */
- if (geteuid() == 0) {
+ if (geteuid() == 0 && !userns_has_single_user()) {
p = strjoina(temp, "/user");
ASSERT_OK(mkdir(p, 0755));
ASSERT_OK(chown(p, UID_NOBODY, GID_NOBODY));
r = chase(p, NULL, 0, &result, NULL);
assert_se(r == -ENOENT);
- if (geteuid() == 0) {
+ if (geteuid() == 0 && !userns_has_single_user()) {
p = strjoina(temp, "/priv1");
ASSERT_OK(mkdir(p, 0755));
}
static int intro(void) {
- if (geteuid() != 0)
- return log_tests_skipped("not running as root");
+ if (geteuid() != 0 || userns_has_single_user())
+ return log_tests_skipped("not running as root or in userns with single user");
return EXIT_SUCCESS;
}
condition_free(condition);
free(gid);
+ /* In an unprivileged user namespace with the current user mapped to root, all the auxiliary groups
+ * of the user will be mapped to the nobody group, which means the user in the user namespace is in
+ * both the root and the nobody group, meaning the next test can't work, so let's skip it in that
+ * case. */
+ if (in_group(NOBODY_GROUP_NAME) && in_group("root"))
+ return (void) log_tests_skipped("user is in both root and nobody group");
+
groupname = (char*)(getegid() == 0 ? NOBODY_GROUP_NAME : "root");
condition = condition_new(CONDITION_GROUP, groupname, false, false);
assert_se(condition);
struct stat st;
const char *p;
- if (geteuid() != 0)
- return;
+ if (geteuid() != 0 || userns_has_single_user())
+ return (void) log_tests_skipped("not running as root or in userns with single user");
BLOCK_WITH_UMASK(0000);
TEST(rm_rf_chmod) {
int r;
+ if (getuid() == 0 && userns_has_single_user())
+ return (void) log_tests_skipped("running as root or in userns with single user");
+
if (getuid() == 0) {
/* This test only works unpriv (as only then the access mask for the owning user matters),
* hence drop privs here */
struct ucred ucred;
int pair[2] = EBADF_PAIR;
- if (geteuid() == 0) {
+ if (geteuid() == 0 && !userns_has_single_user()) {
test_uid = 1;
test_gid = 2;
test_gids = (gid_t*) gids;