From 1662d08e218368a4f0318d7f8f889222c0d227cf Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Sun, 12 Jan 2025 10:54:59 +0100 Subject: [PATCH] test: skip tests when having no private netns Under valgrind in github CI we (currently) seem unable to create the netns. This worked previously, now it no longer does. Handle that by skipping the tests that require a netns. --- .github/workflows/ci.yml | 4 +-- tests/cksuite-all-netns.c | 13 ++++++++- tests/nl-test-util.c | 57 +++++++++++++++++++++++++++++++++++++-- tests/nl-test-util.h | 3 +++ 4 files changed, 72 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4962ae13..a54ded7c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -107,8 +107,8 @@ jobs: run: | set -x export NLTST_SEED_RAND= - CK_FORK=no libtool --mode=execute valgrind --error-exitcode=66 --leak-check=full -s --show-leak-kinds=all ./tests/check-direct - CK_FORK=no libtool --mode=execute valgrind --error-exitcode=66 --leak-check=full -s --show-leak-kinds=all ./tests/check-all + NLTST_IN_CI_VALGRIND=1 CK_FORK=no libtool --mode=execute valgrind --error-exitcode=66 --leak-check=full -s --show-leak-kinds=all ./tests/check-direct + NLTST_IN_CI_VALGRIND=1 CK_FORK=no libtool --mode=execute valgrind --error-exitcode=66 --leak-check=full -s --show-leak-kinds=all ./tests/check-all shell: bash - name: Install packages for Release diff --git a/tests/cksuite-all-netns.c b/tests/cksuite-all-netns.c index 1948c3e8..04e0f6df 100644 --- a/tests/cksuite-all-netns.c +++ b/tests/cksuite-all-netns.c @@ -73,6 +73,9 @@ START_TEST(cache_and_clone) size_t i; int r; + if (_nltst_skip_no_netns()) + return; + for (i = 0; i < _NL_N_ELEMENTS(links); i++) { if (links[i].add) _nltst_add_link(NULL, links[i].ifname, links[i].kind, @@ -132,11 +135,16 @@ START_TEST(test_create_iface) _nl_auto_rtnl_link struct rtnl_link *link2 = NULL; _nl_auto_rtnl_link struct rtnl_link *peer = NULL; _nltst_auto_delete_link const char *IFNAME_DUMMY = NULL; - _nltst_auto_delete_link const char *IFNAME = "ifname"; + _nltst_auto_delete_link const char *IFNAME = NULL; int ifindex_dummy; uint32_t u32; int r; + if (_nltst_skip_no_netns()) + return; + + IFNAME = "ifname"; + switch (TEST_IDX) { case 0: link = _nltst_assert(rtnl_link_bridge_alloc()); @@ -317,6 +325,9 @@ START_TEST(route_1) _nl_auto_nl_socket struct nl_sock *sk = NULL; _nl_auto_nl_cache struct nl_cache *cache = NULL; + if (_nltst_skip_no_netns()) + return; + if (_nltst_skip_no_iproute2("route_1")) return; diff --git a/tests/nl-test-util.c b/tests/nl-test-util.c index dc8dc5ad..64ccf46f 100644 --- a/tests/nl-test-util.c +++ b/tests/nl-test-util.c @@ -84,6 +84,7 @@ uint32_t _nltst_rand_u32(void) struct nltst_netns { int canary; + bool is_unshared; }; /*****************************************************************************/ @@ -114,6 +115,30 @@ void nltst_netns_fixture_teardown(void) _nl_clear_pointer(&_netns_fixture_global.nsdata, nltst_netns_leave); } +bool nltst_netns_fixture_is_unshared(void) +{ + _assert_nltst_netns(_netns_fixture_global.nsdata); + return _netns_fixture_global.nsdata->is_unshared; +} + +bool _nltst_skip_no_netns(void) +{ + if (nltst_netns_fixture_is_unshared()) + return false; + + if (_nltst_in_ci()) { + /* In CI, we exepect normal tests to have a netns, but under + * valgrind this might fail. */ + if (!_nl_streq0(getenv("NLTST_IN_CI_VALGRIND"), "1")) { + ck_abort_msg( + "Unable to create private netns under CI (NLTST_IN_CI=1) while not running valgind (NLTST_IN_CI_VALGRIND!=1)"); + } + } + + printf("skip test due to having no private netns\n"); + return true; +} + /*****************************************************************************/ static void unshare_user(void) @@ -125,6 +150,10 @@ static void unshare_user(void) /* Become a root in new user NS. */ r = unshare(CLONE_NEWUSER); + if (r != 0 && errno == EPERM) { + /* No permissions? Ignore. Will be handled later. */ + return; + } _nltst_assert_errno(r == 0); /* Since Linux 3.19 we have to disable setgroups() in order to map users. @@ -149,14 +178,28 @@ static void unshare_user(void) } r = fprintf(f, "0 %d 1", uid); _nltst_assert_errno(r > 0); - _nltst_fclose(f); + r = fclose(f); + if (r != 0 && errno == EPERM) { + /* Oddly, it seems close() can fail at this point. Ignore it, + * but we probably will be unable to unshare (which we handle + * later). + */ + } else + _nltst_assert_errno(r == 0); /* Map current GID to root in NS to be created. */ f = fopen("/proc/self/gid_map", "we"); _nltst_assert_errno(f); r = fprintf(f, "0 %d 1", gid); _nltst_assert_errno(r > 0); - _nltst_fclose(f); + r = fclose(f); + if (r != 0 && errno == EPERM) { + /* Oddly, it seems close() can fail at this point. Ignore it, but + * we probably will be unable to unshare (which we handle + * later). + */ + } else + _nltst_assert_errno(r == 0); } struct nltst_netns *nltst_netns_enter(void) @@ -172,6 +215,15 @@ struct nltst_netns *nltst_netns_enter(void) unshare_user(); r = unshare(CLONE_NEWNET | CLONE_NEWNS); + if (r != 0 && errno == EPERM) { + /* The system is probably sandboxed somehow and we are unable + * to create a private netns. That seems questionable, because + * a point of a private netns is to sandbox an application. + * Not having permissions to sandbox sounds bad. + * + * Anyway. We accept this and will later skip some tests. */ + return nsdata; + } _nltst_assert_errno(r == 0); /* We need a read-only /sys so that the platform knows there's no udev. */ @@ -179,6 +231,7 @@ struct nltst_netns *nltst_netns_enter(void) r = mount("sys", "/sys", "sysfs", MS_RDONLY, NULL); _nltst_assert_errno(r == 0); + nsdata->is_unshared = true; return nsdata; } diff --git a/tests/nl-test-util.h b/tests/nl-test-util.h index 981228b4..d840a4ab 100644 --- a/tests/nl-test-util.h +++ b/tests/nl-test-util.h @@ -429,6 +429,9 @@ char **_nltst_strtokv(const char *str); void nltst_netns_fixture_setup(void); void nltst_netns_fixture_teardown(void); +bool nltst_netns_fixture_is_unshared(void); + +bool _nltst_skip_no_netns(void); struct nltst_netns;