diff options
Diffstat (limited to 'shared/n-acd/src/test.h')
-rw-r--r-- | shared/n-acd/src/test.h | 121 |
1 files changed, 100 insertions, 21 deletions
diff --git a/shared/n-acd/src/test.h b/shared/n-acd/src/test.h index f2cb801aab..4c6ffebb6a 100644 --- a/shared/n-acd/src/test.h +++ b/shared/n-acd/src/test.h @@ -6,9 +6,12 @@ * includes net-namespace setups, veth setups, and more. */ +#undef NDEBUG #include <assert.h> +#include <c-stdaux.h> #include <endian.h> #include <errno.h> +#include <fcntl.h> #include <net/ethernet.h> #include <net/if.h> #include <sys/socket.h> @@ -21,6 +24,10 @@ #include <stdlib.h> #include <string.h> #include <sys/ioctl.h> +#include <sys/mount.h> +#include <sys/resource.h> +#include <sys/stat.h> +#include <sys/types.h> #include <unistd.h> #include "n-acd.h" @@ -29,10 +36,10 @@ static inline void test_add_child_ip(const struct in_addr *addr) { int r; r = asprintf(&p, "ip addr add dev veth1 %s/8", inet_ntoa(*addr)); - assert(r >= 0); + c_assert(r >= 0); r = system(p); - assert(r >= 0); + c_assert(r >= 0); free(p); } @@ -42,10 +49,10 @@ static inline void test_del_child_ip(const struct in_addr *addr) { int r; r = asprintf(&p, "ip addr del dev veth1 %s/8", inet_ntoa(*addr)); - assert(r >= 0); + c_assert(r >= 0); r = system(p); - assert(r >= 0); + c_assert(r >= 0); free(p); } @@ -56,20 +63,20 @@ static inline void test_if_query(const char *name, int *indexp, struct ether_add int r, s; l = strlen(name); - assert(l <= IF_NAMESIZE); + c_assert(l <= IF_NAMESIZE); if (indexp) { *indexp = if_nametoindex(name); - assert(*indexp > 0); + c_assert(*indexp > 0); } if (macp) { s = socket(AF_INET, SOCK_DGRAM, 0); - assert(s >= 0); + c_assert(s >= 0); strncpy(ifr.ifr_name, name, l + 1); r = ioctl(s, SIOCGIFHWADDR, &ifr); - assert(r >= 0); + c_assert(r >= 0); memcpy(macp->ether_addr_octet, ifr.ifr_hwaddr.sa_data, ETH_ALEN); @@ -82,14 +89,14 @@ static inline void test_veth_cmd(int ifindex, const char *cmd) { int r; p = if_indextoname(ifindex, name); - assert(p); + c_assert(p); r = asprintf(&p, "ip link set %s %s", name, cmd); - assert(r >= 0); + c_assert(r >= 0); /* Again: Ewwww... */ r = system(p); - assert(r == 0); + c_assert(r == 0); free(p); } @@ -102,11 +109,11 @@ static inline void test_veth_new(int *parent_indexp, /* Eww... but it works. */ r = system("ip link add type veth"); - assert(r == 0); + c_assert(r == 0); r = system("ip link set veth0 up"); - assert(r == 0); + c_assert(r == 0); r = system("ip link set veth1 up"); - assert(r == 0); + c_assert(r == 0); test_if_query("veth0", parent_indexp, parent_macp); test_if_query("veth1", child_indexp, child_macp); @@ -116,19 +123,91 @@ static inline void test_loopback_up(int *indexp, struct ether_addr *macp) { int r; r = system("ip link set lo up"); - assert(r == 0); + c_assert(r == 0); test_if_query("lo", indexp, macp); } -static inline int test_setup(void) { +static inline void test_raise_memlock(void) { + const size_t wanted = 64 * 1024 * 1024; + struct rlimit get, set; int r; - r = unshare(CLONE_NEWNET); - if (r < 0) { - assert(errno == EPERM); - return 77; + r = getrlimit(RLIMIT_MEMLOCK, &get); + c_assert(!r); + + /* try raising limit to @wanted */ + set.rlim_cur = wanted; + set.rlim_max = (wanted > get.rlim_max) ? wanted : get.rlim_max; + r = setrlimit(RLIMIT_MEMLOCK, &set); + if (r) { + c_assert(errno == EPERM); + + /* not privileged to raise limit, so maximize soft limit */ + set.rlim_cur = get.rlim_max; + set.rlim_max = get.rlim_max; + r = setrlimit(RLIMIT_MEMLOCK, &set); + c_assert(!r); } +} + +static inline void test_unshare_user_namespace(void) { + uid_t euid; + gid_t egid; + int r, fd; + + /* + * Enter a new user namespace as root:root. + */ + + euid = geteuid(); + egid = getegid(); + + r = unshare(CLONE_NEWUSER); + c_assert(r >= 0); + + fd = open("/proc/self/uid_map", O_WRONLY); + c_assert(fd >= 0); + r = dprintf(fd, "0 %d 1\n", euid); + c_assert(r >= 0); + close(fd); + + fd = open("/proc/self/setgroups", O_WRONLY); + c_assert(fd >= 0); + r = dprintf(fd, "deny"); + c_assert(r >= 0); + close(fd); + + fd = open("/proc/self/gid_map", O_WRONLY); + c_assert(fd >= 0); + r = dprintf(fd, "0 %d 1\n", egid); + c_assert(r >= 0); + close(fd); +} + +static inline void test_setup(void) { + int r; + + /* + * Move into a new network and mount namespace both associated + * with a new user namespace where the current eUID is mapped to + * 0. Then create a a private instance of /run/netns. This ensures + * that any network devices or network namespaces are private to + * the test process. + */ + + test_raise_memlock(); + test_unshare_user_namespace(); + + r = unshare(CLONE_NEWNET | CLONE_NEWNS); + c_assert(r >= 0); + + r = mount(NULL, "/", "", MS_PRIVATE | MS_REC, NULL); + c_assert(r >= 0); + + r = mount(NULL, "/run", "tmpfs", 0, NULL); + c_assert(r >= 0); - return 0; + r = mkdir("/run/netns", 0755); + c_assert(r >= 0); } |