|
16 | 16 | #include "fd-util.h" |
17 | 17 | #include "log.h" |
18 | 18 | #include "macro.h" |
| 19 | +#include "path-util.h" |
19 | 20 | #include "process-util.h" |
20 | 21 | #include "resolved-dns-packet.h" |
21 | 22 | #include "resolved-dns-question.h" |
@@ -330,11 +331,36 @@ static void test_dns_stream(bool tls) { |
330 | 331 |
|
331 | 332 | static void try_isolate_network(void) { |
332 | 333 | _cleanup_close_ int socket_fd = -1; |
| 334 | + int r; |
333 | 335 |
|
334 | | - if (unshare(CLONE_NEWUSER | CLONE_NEWNET) < 0) { |
335 | | - log_warning("test-resolved-stream: Can't create user and network ns, running on host"); |
336 | | - return; |
| 336 | + /* First test if CLONE_NEWUSER/CLONE_NEWNET can actually work for us, i.e. we can open the namespaces |
| 337 | + * and then still access the build dir we are run from. We do that in a child process since it's |
| 338 | + * nasty if we have to go back from the namespace once we entered it and realized it cannot work. */ |
| 339 | + r = safe_fork("(usernstest)", FORK_DEATHSIG|FORK_LOG|FORK_WAIT, NULL); |
| 340 | + if (r == 0) { /* child */ |
| 341 | + _cleanup_free_ char *rt = NULL, *d = NULL; |
| 342 | + |
| 343 | + if (unshare(CLONE_NEWUSER | CLONE_NEWNET) < 0) { |
| 344 | + log_warning_errno(errno, "test-resolved-stream: Can't create user and network ns, running on host: %m"); |
| 345 | + _exit(EXIT_FAILURE); |
| 346 | + } |
| 347 | + |
| 348 | + assert_se(get_process_exe(0, &rt) >= 0); |
| 349 | + assert_se(path_extract_directory(rt, &d) >= 0); |
| 350 | + |
| 351 | + if (access(d, F_OK) < 0) { |
| 352 | + log_warning_errno(errno, "test-resolved-stream: Can't access /proc/self/exe from user/network ns, running on host: %m"); |
| 353 | + _exit(EXIT_FAILURE); |
| 354 | + } |
| 355 | + |
| 356 | + _exit(EXIT_SUCCESS); |
337 | 357 | } |
| 358 | + if (r == -EPROTO) /* EPROTO means nonzero exit code of child, i.e. the tests in the child failed */ |
| 359 | + return; |
| 360 | + assert_se(r > 0); |
| 361 | + |
| 362 | + /* Now that we know that the unshare() is safe, let's actually do it */ |
| 363 | + assert_se(unshare(CLONE_NEWUSER | CLONE_NEWNET) >= 0); |
338 | 364 |
|
339 | 365 | /* Bring up the loopback interfaceon the newly created network namespace */ |
340 | 366 | struct ifreq req = { .ifr_ifindex = 1 }; |
|
0 commit comments