cred_change_test.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814
  1. // SPDX-License-Identifier: GPL-2.0
  2. #define _GNU_SOURCE
  3. #include <errno.h>
  4. #include <fcntl.h>
  5. #include <limits.h>
  6. #include <sched.h>
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <string.h>
  10. #include <sys/capability.h>
  11. #include <sys/ioctl.h>
  12. #include <sys/stat.h>
  13. #include <sys/syscall.h>
  14. #include <sys/types.h>
  15. #include <sys/wait.h>
  16. #include <unistd.h>
  17. #include <linux/nsfs.h>
  18. #include "../kselftest_harness.h"
  19. #include "../filesystems/utils.h"
  20. #include "wrappers.h"
  21. /*
  22. * Test credential changes and their impact on namespace active references.
  23. */
  24. /*
  25. * Test setuid() in a user namespace properly swaps active references.
  26. * Create a user namespace with multiple UIDs mapped, then setuid() between them.
  27. * Verify that the user namespace remains active throughout.
  28. */
  29. TEST(setuid_preserves_active_refs)
  30. {
  31. pid_t pid;
  32. int status;
  33. __u64 userns_id;
  34. struct ns_id_req req = {
  35. .size = sizeof(req),
  36. .spare = 0,
  37. .ns_id = 0,
  38. .ns_type = CLONE_NEWUSER,
  39. .spare2 = 0,
  40. .user_ns_id = 0,
  41. };
  42. __u64 ns_ids[256];
  43. ssize_t ret;
  44. int i;
  45. bool found = false;
  46. int pipefd[2];
  47. ASSERT_EQ(pipe(pipefd), 0);
  48. pid = fork();
  49. ASSERT_GE(pid, 0);
  50. if (pid == 0) {
  51. /* Child process */
  52. int fd, userns_fd;
  53. __u64 child_userns_id;
  54. uid_t orig_uid = getuid();
  55. int setuid_count;
  56. close(pipefd[0]);
  57. /* Create new user namespace with multiple UIDs mapped (0-9) */
  58. userns_fd = get_userns_fd(0, orig_uid, 10);
  59. if (userns_fd < 0) {
  60. close(pipefd[1]);
  61. exit(1);
  62. }
  63. if (setns(userns_fd, CLONE_NEWUSER) < 0) {
  64. close(userns_fd);
  65. close(pipefd[1]);
  66. exit(1);
  67. }
  68. close(userns_fd);
  69. /* Get user namespace ID */
  70. fd = open("/proc/self/ns/user", O_RDONLY);
  71. if (fd < 0) {
  72. close(pipefd[1]);
  73. exit(1);
  74. }
  75. if (ioctl(fd, NS_GET_ID, &child_userns_id) < 0) {
  76. close(fd);
  77. close(pipefd[1]);
  78. exit(1);
  79. }
  80. close(fd);
  81. /* Send namespace ID to parent */
  82. write(pipefd[1], &child_userns_id, sizeof(child_userns_id));
  83. /*
  84. * Perform multiple setuid() calls.
  85. * Each setuid() triggers commit_creds() which should properly
  86. * swap active references via switch_cred_namespaces().
  87. */
  88. for (setuid_count = 0; setuid_count < 50; setuid_count++) {
  89. uid_t target_uid = (setuid_count % 10);
  90. if (setuid(target_uid) < 0) {
  91. if (errno != EPERM) {
  92. close(pipefd[1]);
  93. exit(1);
  94. }
  95. }
  96. }
  97. close(pipefd[1]);
  98. exit(0);
  99. }
  100. /* Parent process */
  101. close(pipefd[1]);
  102. if (read(pipefd[0], &userns_id, sizeof(userns_id)) != sizeof(userns_id)) {
  103. close(pipefd[0]);
  104. kill(pid, SIGKILL);
  105. waitpid(pid, NULL, 0);
  106. SKIP(return, "Failed to get namespace ID from child");
  107. }
  108. close(pipefd[0]);
  109. TH_LOG("Child user namespace ID: %llu", (unsigned long long)userns_id);
  110. /* Verify namespace is active while child is running */
  111. ret = sys_listns(&req, ns_ids, ARRAY_SIZE(ns_ids), 0);
  112. if (ret < 0) {
  113. kill(pid, SIGKILL);
  114. waitpid(pid, NULL, 0);
  115. if (errno == ENOSYS)
  116. SKIP(return, "listns() not supported");
  117. ASSERT_GE(ret, 0);
  118. }
  119. for (i = 0; i < ret; i++) {
  120. if (ns_ids[i] == userns_id) {
  121. found = true;
  122. break;
  123. }
  124. }
  125. ASSERT_TRUE(found);
  126. waitpid(pid, &status, 0);
  127. ASSERT_TRUE(WIFEXITED(status));
  128. ASSERT_EQ(WEXITSTATUS(status), 0);
  129. /* Verify namespace becomes inactive after child exits */
  130. ret = sys_listns(&req, ns_ids, ARRAY_SIZE(ns_ids), 0);
  131. ASSERT_GE(ret, 0);
  132. found = false;
  133. for (i = 0; i < ret; i++) {
  134. if (ns_ids[i] == userns_id) {
  135. found = true;
  136. break;
  137. }
  138. }
  139. ASSERT_FALSE(found);
  140. TH_LOG("setuid() correctly preserved active references (no leak)");
  141. }
  142. /*
  143. * Test setgid() in a user namespace properly handles active references.
  144. */
  145. TEST(setgid_preserves_active_refs)
  146. {
  147. pid_t pid;
  148. int status;
  149. __u64 userns_id;
  150. struct ns_id_req req = {
  151. .size = sizeof(req),
  152. .spare = 0,
  153. .ns_id = 0,
  154. .ns_type = CLONE_NEWUSER,
  155. .spare2 = 0,
  156. .user_ns_id = 0,
  157. };
  158. __u64 ns_ids[256];
  159. ssize_t ret;
  160. int i;
  161. bool found = false;
  162. int pipefd[2];
  163. ASSERT_EQ(pipe(pipefd), 0);
  164. pid = fork();
  165. ASSERT_GE(pid, 0);
  166. if (pid == 0) {
  167. /* Child process */
  168. int fd, userns_fd;
  169. __u64 child_userns_id;
  170. uid_t orig_uid = getuid();
  171. int setgid_count;
  172. close(pipefd[0]);
  173. /* Create new user namespace with multiple GIDs mapped */
  174. userns_fd = get_userns_fd(0, orig_uid, 10);
  175. if (userns_fd < 0) {
  176. close(pipefd[1]);
  177. exit(1);
  178. }
  179. if (setns(userns_fd, CLONE_NEWUSER) < 0) {
  180. close(userns_fd);
  181. close(pipefd[1]);
  182. exit(1);
  183. }
  184. close(userns_fd);
  185. /* Get user namespace ID */
  186. fd = open("/proc/self/ns/user", O_RDONLY);
  187. if (fd < 0) {
  188. close(pipefd[1]);
  189. exit(1);
  190. }
  191. if (ioctl(fd, NS_GET_ID, &child_userns_id) < 0) {
  192. close(fd);
  193. close(pipefd[1]);
  194. exit(1);
  195. }
  196. close(fd);
  197. write(pipefd[1], &child_userns_id, sizeof(child_userns_id));
  198. /* Perform multiple setgid() calls */
  199. for (setgid_count = 0; setgid_count < 50; setgid_count++) {
  200. gid_t target_gid = (setgid_count % 10);
  201. if (setgid(target_gid) < 0) {
  202. if (errno != EPERM) {
  203. close(pipefd[1]);
  204. exit(1);
  205. }
  206. }
  207. }
  208. close(pipefd[1]);
  209. exit(0);
  210. }
  211. /* Parent process */
  212. close(pipefd[1]);
  213. if (read(pipefd[0], &userns_id, sizeof(userns_id)) != sizeof(userns_id)) {
  214. close(pipefd[0]);
  215. kill(pid, SIGKILL);
  216. waitpid(pid, NULL, 0);
  217. SKIP(return, "Failed to get namespace ID from child");
  218. }
  219. close(pipefd[0]);
  220. waitpid(pid, &status, 0);
  221. ASSERT_TRUE(WIFEXITED(status));
  222. ASSERT_EQ(WEXITSTATUS(status), 0);
  223. /* Verify namespace becomes inactive */
  224. ret = sys_listns(&req, ns_ids, ARRAY_SIZE(ns_ids), 0);
  225. if (ret < 0) {
  226. if (errno == ENOSYS)
  227. SKIP(return, "listns() not supported");
  228. ASSERT_GE(ret, 0);
  229. }
  230. for (i = 0; i < ret; i++) {
  231. if (ns_ids[i] == userns_id) {
  232. found = true;
  233. break;
  234. }
  235. }
  236. ASSERT_FALSE(found);
  237. TH_LOG("setgid() correctly preserved active references (no leak)");
  238. }
  239. /*
  240. * Test setresuid() which changes real, effective, and saved UIDs.
  241. * This should properly swap active references via commit_creds().
  242. */
  243. TEST(setresuid_preserves_active_refs)
  244. {
  245. pid_t pid;
  246. int status;
  247. __u64 userns_id;
  248. struct ns_id_req req = {
  249. .size = sizeof(req),
  250. .spare = 0,
  251. .ns_id = 0,
  252. .ns_type = CLONE_NEWUSER,
  253. .spare2 = 0,
  254. .user_ns_id = 0,
  255. };
  256. __u64 ns_ids[256];
  257. ssize_t ret;
  258. int i;
  259. bool found = false;
  260. int pipefd[2];
  261. ASSERT_EQ(pipe(pipefd), 0);
  262. pid = fork();
  263. ASSERT_GE(pid, 0);
  264. if (pid == 0) {
  265. /* Child process */
  266. int fd, userns_fd;
  267. __u64 child_userns_id;
  268. uid_t orig_uid = getuid();
  269. int setres_count;
  270. close(pipefd[0]);
  271. /* Create new user namespace */
  272. userns_fd = get_userns_fd(0, orig_uid, 10);
  273. if (userns_fd < 0) {
  274. close(pipefd[1]);
  275. exit(1);
  276. }
  277. if (setns(userns_fd, CLONE_NEWUSER) < 0) {
  278. close(userns_fd);
  279. close(pipefd[1]);
  280. exit(1);
  281. }
  282. close(userns_fd);
  283. /* Get user namespace ID */
  284. fd = open("/proc/self/ns/user", O_RDONLY);
  285. if (fd < 0) {
  286. close(pipefd[1]);
  287. exit(1);
  288. }
  289. if (ioctl(fd, NS_GET_ID, &child_userns_id) < 0) {
  290. close(fd);
  291. close(pipefd[1]);
  292. exit(1);
  293. }
  294. close(fd);
  295. write(pipefd[1], &child_userns_id, sizeof(child_userns_id));
  296. /* Perform multiple setresuid() calls */
  297. for (setres_count = 0; setres_count < 30; setres_count++) {
  298. uid_t uid1 = (setres_count % 5);
  299. uid_t uid2 = ((setres_count + 1) % 5);
  300. uid_t uid3 = ((setres_count + 2) % 5);
  301. if (setresuid(uid1, uid2, uid3) < 0) {
  302. if (errno != EPERM) {
  303. close(pipefd[1]);
  304. exit(1);
  305. }
  306. }
  307. }
  308. close(pipefd[1]);
  309. exit(0);
  310. }
  311. /* Parent process */
  312. close(pipefd[1]);
  313. if (read(pipefd[0], &userns_id, sizeof(userns_id)) != sizeof(userns_id)) {
  314. close(pipefd[0]);
  315. kill(pid, SIGKILL);
  316. waitpid(pid, NULL, 0);
  317. SKIP(return, "Failed to get namespace ID from child");
  318. }
  319. close(pipefd[0]);
  320. waitpid(pid, &status, 0);
  321. ASSERT_TRUE(WIFEXITED(status));
  322. ASSERT_EQ(WEXITSTATUS(status), 0);
  323. /* Verify namespace becomes inactive */
  324. ret = sys_listns(&req, ns_ids, ARRAY_SIZE(ns_ids), 0);
  325. if (ret < 0) {
  326. if (errno == ENOSYS)
  327. SKIP(return, "listns() not supported");
  328. ASSERT_GE(ret, 0);
  329. }
  330. for (i = 0; i < ret; i++) {
  331. if (ns_ids[i] == userns_id) {
  332. found = true;
  333. break;
  334. }
  335. }
  336. ASSERT_FALSE(found);
  337. TH_LOG("setresuid() correctly preserved active references (no leak)");
  338. }
  339. /*
  340. * Test credential changes across multiple user namespaces.
  341. * Create nested user namespaces and verify active reference tracking.
  342. */
  343. TEST(cred_change_nested_userns)
  344. {
  345. pid_t pid;
  346. int status;
  347. __u64 parent_userns_id, child_userns_id;
  348. struct ns_id_req req = {
  349. .size = sizeof(req),
  350. .spare = 0,
  351. .ns_id = 0,
  352. .ns_type = CLONE_NEWUSER,
  353. .spare2 = 0,
  354. .user_ns_id = 0,
  355. };
  356. __u64 ns_ids[256];
  357. ssize_t ret;
  358. int i;
  359. bool found_parent = false, found_child = false;
  360. int pipefd[2];
  361. ASSERT_EQ(pipe(pipefd), 0);
  362. pid = fork();
  363. ASSERT_GE(pid, 0);
  364. if (pid == 0) {
  365. /* Child process */
  366. int fd, userns_fd;
  367. __u64 parent_id, child_id;
  368. uid_t orig_uid = getuid();
  369. close(pipefd[0]);
  370. /* Create first user namespace */
  371. userns_fd = get_userns_fd(0, orig_uid, 1);
  372. if (userns_fd < 0) {
  373. close(pipefd[1]);
  374. exit(1);
  375. }
  376. if (setns(userns_fd, CLONE_NEWUSER) < 0) {
  377. close(userns_fd);
  378. close(pipefd[1]);
  379. exit(1);
  380. }
  381. close(userns_fd);
  382. /* Get first namespace ID */
  383. fd = open("/proc/self/ns/user", O_RDONLY);
  384. if (fd < 0) {
  385. close(pipefd[1]);
  386. exit(1);
  387. }
  388. if (ioctl(fd, NS_GET_ID, &parent_id) < 0) {
  389. close(fd);
  390. close(pipefd[1]);
  391. exit(1);
  392. }
  393. close(fd);
  394. /* Create nested user namespace */
  395. userns_fd = get_userns_fd(0, 0, 1);
  396. if (userns_fd < 0) {
  397. close(pipefd[1]);
  398. exit(1);
  399. }
  400. if (setns(userns_fd, CLONE_NEWUSER) < 0) {
  401. close(userns_fd);
  402. close(pipefd[1]);
  403. exit(1);
  404. }
  405. close(userns_fd);
  406. /* Get nested namespace ID */
  407. fd = open("/proc/self/ns/user", O_RDONLY);
  408. if (fd < 0) {
  409. close(pipefd[1]);
  410. exit(1);
  411. }
  412. if (ioctl(fd, NS_GET_ID, &child_id) < 0) {
  413. close(fd);
  414. close(pipefd[1]);
  415. exit(1);
  416. }
  417. close(fd);
  418. /* Send both IDs to parent */
  419. write(pipefd[1], &parent_id, sizeof(parent_id));
  420. write(pipefd[1], &child_id, sizeof(child_id));
  421. /* Perform some credential changes in nested namespace */
  422. setuid(0);
  423. setgid(0);
  424. close(pipefd[1]);
  425. exit(0);
  426. }
  427. /* Parent process */
  428. close(pipefd[1]);
  429. /* Read both namespace IDs */
  430. if (read(pipefd[0], &parent_userns_id, sizeof(parent_userns_id)) != sizeof(parent_userns_id)) {
  431. close(pipefd[0]);
  432. kill(pid, SIGKILL);
  433. waitpid(pid, NULL, 0);
  434. SKIP(return, "Failed to get parent namespace ID");
  435. }
  436. if (read(pipefd[0], &child_userns_id, sizeof(child_userns_id)) != sizeof(child_userns_id)) {
  437. close(pipefd[0]);
  438. kill(pid, SIGKILL);
  439. waitpid(pid, NULL, 0);
  440. SKIP(return, "Failed to get child namespace ID");
  441. }
  442. close(pipefd[0]);
  443. TH_LOG("Parent userns: %llu, Child userns: %llu",
  444. (unsigned long long)parent_userns_id,
  445. (unsigned long long)child_userns_id);
  446. /* Verify both namespaces are active */
  447. ret = sys_listns(&req, ns_ids, ARRAY_SIZE(ns_ids), 0);
  448. if (ret < 0) {
  449. kill(pid, SIGKILL);
  450. waitpid(pid, NULL, 0);
  451. if (errno == ENOSYS)
  452. SKIP(return, "listns() not supported");
  453. ASSERT_GE(ret, 0);
  454. }
  455. for (i = 0; i < ret; i++) {
  456. if (ns_ids[i] == parent_userns_id)
  457. found_parent = true;
  458. if (ns_ids[i] == child_userns_id)
  459. found_child = true;
  460. }
  461. ASSERT_TRUE(found_parent);
  462. ASSERT_TRUE(found_child);
  463. /* Wait for child */
  464. waitpid(pid, &status, 0);
  465. ASSERT_TRUE(WIFEXITED(status));
  466. ASSERT_EQ(WEXITSTATUS(status), 0);
  467. /* Verify both namespaces become inactive */
  468. ret = sys_listns(&req, ns_ids, ARRAY_SIZE(ns_ids), 0);
  469. ASSERT_GE(ret, 0);
  470. found_parent = false;
  471. found_child = false;
  472. for (i = 0; i < ret; i++) {
  473. if (ns_ids[i] == parent_userns_id)
  474. found_parent = true;
  475. if (ns_ids[i] == child_userns_id)
  476. found_child = true;
  477. }
  478. ASSERT_FALSE(found_parent);
  479. ASSERT_FALSE(found_child);
  480. TH_LOG("Nested user namespace credential changes preserved active refs (no leak)");
  481. }
  482. /*
  483. * Test rapid credential changes don't cause refcount imbalances.
  484. * This stress-tests the switch_cred_namespaces() logic.
  485. */
  486. TEST(rapid_cred_changes_no_leak)
  487. {
  488. pid_t pid;
  489. int status;
  490. __u64 userns_id;
  491. struct ns_id_req req = {
  492. .size = sizeof(req),
  493. .spare = 0,
  494. .ns_id = 0,
  495. .ns_type = CLONE_NEWUSER,
  496. .spare2 = 0,
  497. .user_ns_id = 0,
  498. };
  499. __u64 ns_ids[256];
  500. ssize_t ret;
  501. int i;
  502. bool found = false;
  503. int pipefd[2];
  504. ASSERT_EQ(pipe(pipefd), 0);
  505. pid = fork();
  506. ASSERT_GE(pid, 0);
  507. if (pid == 0) {
  508. /* Child process */
  509. int fd, userns_fd;
  510. __u64 child_userns_id;
  511. uid_t orig_uid = getuid();
  512. int change_count;
  513. close(pipefd[0]);
  514. /* Create new user namespace with wider range of UIDs/GIDs */
  515. userns_fd = get_userns_fd(0, orig_uid, 100);
  516. if (userns_fd < 0) {
  517. close(pipefd[1]);
  518. exit(1);
  519. }
  520. if (setns(userns_fd, CLONE_NEWUSER) < 0) {
  521. close(userns_fd);
  522. close(pipefd[1]);
  523. exit(1);
  524. }
  525. close(userns_fd);
  526. /* Get user namespace ID */
  527. fd = open("/proc/self/ns/user", O_RDONLY);
  528. if (fd < 0) {
  529. close(pipefd[1]);
  530. exit(1);
  531. }
  532. if (ioctl(fd, NS_GET_ID, &child_userns_id) < 0) {
  533. close(fd);
  534. close(pipefd[1]);
  535. exit(1);
  536. }
  537. close(fd);
  538. write(pipefd[1], &child_userns_id, sizeof(child_userns_id));
  539. /*
  540. * Perform many rapid credential changes.
  541. * Mix setuid, setgid, setreuid, setregid, setresuid, setresgid.
  542. */
  543. for (change_count = 0; change_count < 200; change_count++) {
  544. switch (change_count % 6) {
  545. case 0:
  546. setuid(change_count % 50);
  547. break;
  548. case 1:
  549. setgid(change_count % 50);
  550. break;
  551. case 2:
  552. setreuid(change_count % 50, (change_count + 1) % 50);
  553. break;
  554. case 3:
  555. setregid(change_count % 50, (change_count + 1) % 50);
  556. break;
  557. case 4:
  558. setresuid(change_count % 50, (change_count + 1) % 50, (change_count + 2) % 50);
  559. break;
  560. case 5:
  561. setresgid(change_count % 50, (change_count + 1) % 50, (change_count + 2) % 50);
  562. break;
  563. }
  564. }
  565. close(pipefd[1]);
  566. exit(0);
  567. }
  568. /* Parent process */
  569. close(pipefd[1]);
  570. if (read(pipefd[0], &userns_id, sizeof(userns_id)) != sizeof(userns_id)) {
  571. close(pipefd[0]);
  572. kill(pid, SIGKILL);
  573. waitpid(pid, NULL, 0);
  574. SKIP(return, "Failed to get namespace ID from child");
  575. }
  576. close(pipefd[0]);
  577. TH_LOG("Testing with user namespace ID: %llu", (unsigned long long)userns_id);
  578. waitpid(pid, &status, 0);
  579. ASSERT_TRUE(WIFEXITED(status));
  580. ASSERT_EQ(WEXITSTATUS(status), 0);
  581. /* Verify namespace becomes inactive (no leaked active refs) */
  582. ret = sys_listns(&req, ns_ids, ARRAY_SIZE(ns_ids), 0);
  583. if (ret < 0) {
  584. if (errno == ENOSYS)
  585. SKIP(return, "listns() not supported");
  586. ASSERT_GE(ret, 0);
  587. }
  588. for (i = 0; i < ret; i++) {
  589. if (ns_ids[i] == userns_id) {
  590. found = true;
  591. break;
  592. }
  593. }
  594. ASSERT_FALSE(found);
  595. TH_LOG("200 rapid credential changes completed with no active ref leak");
  596. }
  597. /*
  598. * Test setfsuid/setfsgid which change filesystem UID/GID.
  599. * These also trigger credential changes but may have different code paths.
  600. */
  601. TEST(setfsuid_preserves_active_refs)
  602. {
  603. pid_t pid;
  604. int status;
  605. __u64 userns_id;
  606. struct ns_id_req req = {
  607. .size = sizeof(req),
  608. .spare = 0,
  609. .ns_id = 0,
  610. .ns_type = CLONE_NEWUSER,
  611. .spare2 = 0,
  612. .user_ns_id = 0,
  613. };
  614. __u64 ns_ids[256];
  615. ssize_t ret;
  616. int i;
  617. bool found = false;
  618. int pipefd[2];
  619. ASSERT_EQ(pipe(pipefd), 0);
  620. pid = fork();
  621. ASSERT_GE(pid, 0);
  622. if (pid == 0) {
  623. /* Child process */
  624. int fd, userns_fd;
  625. __u64 child_userns_id;
  626. uid_t orig_uid = getuid();
  627. int change_count;
  628. close(pipefd[0]);
  629. /* Create new user namespace */
  630. userns_fd = get_userns_fd(0, orig_uid, 10);
  631. if (userns_fd < 0) {
  632. close(pipefd[1]);
  633. exit(1);
  634. }
  635. if (setns(userns_fd, CLONE_NEWUSER) < 0) {
  636. close(userns_fd);
  637. close(pipefd[1]);
  638. exit(1);
  639. }
  640. close(userns_fd);
  641. /* Get user namespace ID */
  642. fd = open("/proc/self/ns/user", O_RDONLY);
  643. if (fd < 0) {
  644. close(pipefd[1]);
  645. exit(1);
  646. }
  647. if (ioctl(fd, NS_GET_ID, &child_userns_id) < 0) {
  648. close(fd);
  649. close(pipefd[1]);
  650. exit(1);
  651. }
  652. close(fd);
  653. write(pipefd[1], &child_userns_id, sizeof(child_userns_id));
  654. /* Perform multiple setfsuid/setfsgid calls */
  655. for (change_count = 0; change_count < 50; change_count++) {
  656. setfsuid(change_count % 10);
  657. setfsgid(change_count % 10);
  658. }
  659. close(pipefd[1]);
  660. exit(0);
  661. }
  662. /* Parent process */
  663. close(pipefd[1]);
  664. if (read(pipefd[0], &userns_id, sizeof(userns_id)) != sizeof(userns_id)) {
  665. close(pipefd[0]);
  666. kill(pid, SIGKILL);
  667. waitpid(pid, NULL, 0);
  668. SKIP(return, "Failed to get namespace ID from child");
  669. }
  670. close(pipefd[0]);
  671. waitpid(pid, &status, 0);
  672. ASSERT_TRUE(WIFEXITED(status));
  673. ASSERT_EQ(WEXITSTATUS(status), 0);
  674. /* Verify namespace becomes inactive */
  675. ret = sys_listns(&req, ns_ids, ARRAY_SIZE(ns_ids), 0);
  676. if (ret < 0) {
  677. if (errno == ENOSYS)
  678. SKIP(return, "listns() not supported");
  679. ASSERT_GE(ret, 0);
  680. }
  681. for (i = 0; i < ret; i++) {
  682. if (ns_ids[i] == userns_id) {
  683. found = true;
  684. break;
  685. }
  686. }
  687. ASSERT_FALSE(found);
  688. TH_LOG("setfsuid/setfsgid correctly preserved active references (no leak)");
  689. }
  690. TEST_HARNESS_MAIN