1
0
mirror of https://github.com/systemd/systemd.git synced 2025-01-20 18:04:03 +03:00

Merge pull request #34026 from DaanDeMeyer/tests

Handle unprivileged user namespaces gracefully in tests
This commit is contained in:
Daan De Meyer 2024-08-18 23:31:10 +02:00 committed by GitHub
commit c4e809b6ad
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 54 additions and 15 deletions

View File

@ -92,18 +92,24 @@ TEST(message_address) {
struct in_addr in_data;
struct ifa_cacheinfo cache;
const char *label;
int r;
assert_se(sd_netlink_open(&rtnl) >= 0);
ifindex = (int) if_nametoindex("lo");
assert_se(sd_rtnl_message_new_addr(rtnl, &message, RTM_GETADDR, ifindex, AF_INET) >= 0);
assert_se(sd_netlink_message_set_request_dump(message, true) >= 0);
assert_se(sd_netlink_call(rtnl, message, 0, &reply) == 1);
assert_se(sd_netlink_message_read_in_addr(reply, IFA_LOCAL, &in_data) >= 0);
assert_se(sd_netlink_message_read_in_addr(reply, IFA_ADDRESS, &in_data) >= 0);
assert_se(sd_netlink_message_read_string(reply, IFA_LABEL, &label) >= 0);
assert_se(sd_netlink_message_read_cache_info(reply, IFA_CACHEINFO, &cache) == 0);
r = sd_netlink_call(rtnl, message, 0, &reply);
assert_se(r >= 0);
/* If the loopback device is down we won't get any results. */
if (r > 0) {
assert_se(sd_netlink_message_read_in_addr(reply, IFA_LOCAL, &in_data) >= 0);
assert_se(sd_netlink_message_read_in_addr(reply, IFA_ADDRESS, &in_data) >= 0);
assert_se(sd_netlink_message_read_string(reply, IFA_LABEL, &label) >= 0);
assert_se(sd_netlink_message_read_cache_info(reply, IFA_CACHEINFO, &cache) == 0);
}
}
TEST(message_route) {

View File

@ -29,6 +29,7 @@
#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;
@ -166,6 +167,24 @@ bool have_namespaces(void) {
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

View File

@ -76,6 +76,7 @@ void test_setup_logging(int level);
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)

View File

@ -41,7 +41,7 @@ TEST_RET(add_acls_for_user) {
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)

View File

@ -318,10 +318,13 @@ int main(int argc, char *argv[]) {
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);

View File

@ -183,7 +183,7 @@ TEST(chase) {
/* 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));
@ -313,7 +313,7 @@ TEST(chase) {
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));

View File

@ -153,8 +153,8 @@ TEST(chown_recursive) {
}
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;
}

View File

@ -1003,6 +1003,13 @@ TEST(condition_test_group) {
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);

View File

@ -368,8 +368,8 @@ TEST(chmod_and_chown) {
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);

View File

@ -89,6 +89,9 @@ static void test_rm_rf_chmod_inner(void) {
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 */

View File

@ -170,7 +170,7 @@ TEST(getpeercred_getpeergroups) {
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;