ns_active_ref_test.c 69 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672
  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 <linux/nsfs.h>
  11. #include <sys/mount.h>
  12. #include <sys/socket.h>
  13. #include <sys/stat.h>
  14. #include <sys/types.h>
  15. #include <sys/wait.h>
  16. #include <sys/syscall.h>
  17. #include <unistd.h>
  18. #include <pthread.h>
  19. #include "../kselftest_harness.h"
  20. #include "../filesystems/utils.h"
  21. #include "wrappers.h"
  22. #ifndef FD_NSFS_ROOT
  23. #define FD_NSFS_ROOT -10003 /* Root of the nsfs filesystem */
  24. #endif
  25. #ifndef FILEID_NSFS
  26. #define FILEID_NSFS 0xf1
  27. #endif
  28. /*
  29. * Test that initial namespaces can be reopened via file handle.
  30. * Initial namespaces should have active ref count of 1 from boot.
  31. */
  32. TEST(init_ns_always_active)
  33. {
  34. struct file_handle *handle;
  35. int mount_id;
  36. int ret;
  37. int fd1, fd2;
  38. struct stat st1, st2;
  39. handle = malloc(sizeof(*handle) + MAX_HANDLE_SZ);
  40. ASSERT_NE(handle, NULL);
  41. /* Open initial network namespace */
  42. fd1 = open("/proc/1/ns/net", O_RDONLY);
  43. ASSERT_GE(fd1, 0);
  44. /* Get file handle for initial namespace */
  45. handle->handle_bytes = MAX_HANDLE_SZ;
  46. ret = name_to_handle_at(fd1, "", handle, &mount_id, AT_EMPTY_PATH);
  47. if (ret < 0 && errno == EOPNOTSUPP) {
  48. SKIP(free(handle); close(fd1);
  49. return, "nsfs doesn't support file handles");
  50. }
  51. ASSERT_EQ(ret, 0);
  52. /* Close the namespace fd */
  53. close(fd1);
  54. /* Try to reopen via file handle - should succeed since init ns is always active */
  55. fd2 = open_by_handle_at(FD_NSFS_ROOT, handle, O_RDONLY);
  56. if (fd2 < 0 && (errno == EINVAL || errno == EOPNOTSUPP)) {
  57. SKIP(free(handle);
  58. return, "open_by_handle_at with FD_NSFS_ROOT not supported");
  59. }
  60. ASSERT_GE(fd2, 0);
  61. /* Verify we opened the same namespace */
  62. fd1 = open("/proc/1/ns/net", O_RDONLY);
  63. ASSERT_GE(fd1, 0);
  64. ASSERT_EQ(fstat(fd1, &st1), 0);
  65. ASSERT_EQ(fstat(fd2, &st2), 0);
  66. ASSERT_EQ(st1.st_ino, st2.st_ino);
  67. close(fd1);
  68. close(fd2);
  69. free(handle);
  70. }
  71. /*
  72. * Test namespace lifecycle: create a namespace in a child process,
  73. * get a file handle while it's active, then try to reopen after
  74. * the process exits (namespace becomes inactive).
  75. */
  76. TEST(ns_inactive_after_exit)
  77. {
  78. struct file_handle *handle;
  79. int mount_id;
  80. int ret;
  81. int fd;
  82. int pipefd[2];
  83. pid_t pid;
  84. int status;
  85. char buf[sizeof(*handle) + MAX_HANDLE_SZ];
  86. /* Create pipe for passing file handle from child */
  87. ASSERT_EQ(pipe(pipefd), 0);
  88. pid = fork();
  89. ASSERT_GE(pid, 0);
  90. if (pid == 0) {
  91. /* Child process */
  92. close(pipefd[0]);
  93. /* Create new network namespace */
  94. ret = unshare(CLONE_NEWNET);
  95. if (ret < 0) {
  96. close(pipefd[1]);
  97. exit(1);
  98. }
  99. /* Open our new namespace */
  100. fd = open("/proc/self/ns/net", O_RDONLY);
  101. if (fd < 0) {
  102. close(pipefd[1]);
  103. exit(1);
  104. }
  105. /* Get file handle for the namespace */
  106. handle = (struct file_handle *)buf;
  107. handle->handle_bytes = MAX_HANDLE_SZ;
  108. ret = name_to_handle_at(fd, "", handle, &mount_id, AT_EMPTY_PATH);
  109. close(fd);
  110. if (ret < 0) {
  111. close(pipefd[1]);
  112. exit(1);
  113. }
  114. /* Send handle to parent */
  115. write(pipefd[1], buf, sizeof(*handle) + handle->handle_bytes);
  116. close(pipefd[1]);
  117. /* Exit - namespace should become inactive */
  118. exit(0);
  119. }
  120. /* Parent process */
  121. close(pipefd[1]);
  122. /* Read file handle from child */
  123. ret = read(pipefd[0], buf, sizeof(buf));
  124. close(pipefd[0]);
  125. /* Wait for child to exit */
  126. waitpid(pid, &status, 0);
  127. ASSERT_TRUE(WIFEXITED(status));
  128. ASSERT_EQ(WEXITSTATUS(status), 0);
  129. ASSERT_GT(ret, 0);
  130. handle = (struct file_handle *)buf;
  131. /* Try to reopen namespace - should fail with ENOENT since it's inactive */
  132. fd = open_by_handle_at(FD_NSFS_ROOT, handle, O_RDONLY);
  133. ASSERT_LT(fd, 0);
  134. /* Should fail with ENOENT (namespace inactive) or ESTALE */
  135. ASSERT_TRUE(errno == ENOENT || errno == ESTALE);
  136. }
  137. /*
  138. * Test that a namespace remains active while a process is using it,
  139. * even after the creating process exits.
  140. */
  141. TEST(ns_active_with_multiple_processes)
  142. {
  143. struct file_handle *handle;
  144. int mount_id;
  145. int ret;
  146. int fd;
  147. int pipefd[2];
  148. int syncpipe[2];
  149. pid_t pid1, pid2;
  150. int status;
  151. char buf[sizeof(*handle) + MAX_HANDLE_SZ];
  152. char sync_byte;
  153. /* Create pipes for communication */
  154. ASSERT_EQ(pipe(pipefd), 0);
  155. ASSERT_EQ(pipe(syncpipe), 0);
  156. pid1 = fork();
  157. ASSERT_GE(pid1, 0);
  158. if (pid1 == 0) {
  159. /* First child - creates namespace */
  160. close(pipefd[0]);
  161. close(syncpipe[1]);
  162. /* Create new network namespace */
  163. ret = unshare(CLONE_NEWNET);
  164. if (ret < 0) {
  165. close(pipefd[1]);
  166. close(syncpipe[0]);
  167. exit(1);
  168. }
  169. /* Open and get handle */
  170. fd = open("/proc/self/ns/net", O_RDONLY);
  171. if (fd < 0) {
  172. close(pipefd[1]);
  173. close(syncpipe[0]);
  174. exit(1);
  175. }
  176. handle = (struct file_handle *)buf;
  177. handle->handle_bytes = MAX_HANDLE_SZ;
  178. ret = name_to_handle_at(fd, "", handle, &mount_id, AT_EMPTY_PATH);
  179. close(fd);
  180. if (ret < 0) {
  181. close(pipefd[1]);
  182. close(syncpipe[0]);
  183. exit(1);
  184. }
  185. /* Send handle to parent */
  186. write(pipefd[1], buf, sizeof(*handle) + handle->handle_bytes);
  187. close(pipefd[1]);
  188. /* Wait for signal before exiting */
  189. read(syncpipe[0], &sync_byte, 1);
  190. close(syncpipe[0]);
  191. exit(0);
  192. }
  193. /* Parent reads handle */
  194. close(pipefd[1]);
  195. ret = read(pipefd[0], buf, sizeof(buf));
  196. close(pipefd[0]);
  197. ASSERT_GT(ret, 0);
  198. handle = (struct file_handle *)buf;
  199. /* Create second child that will keep namespace active */
  200. pid2 = fork();
  201. ASSERT_GE(pid2, 0);
  202. if (pid2 == 0) {
  203. /* Second child - reopens the namespace */
  204. close(syncpipe[0]);
  205. close(syncpipe[1]);
  206. /* Open the namespace via handle */
  207. fd = open_by_handle_at(FD_NSFS_ROOT, handle, O_RDONLY);
  208. if (fd < 0) {
  209. exit(1);
  210. }
  211. /* Join the namespace */
  212. ret = setns(fd, CLONE_NEWNET);
  213. close(fd);
  214. if (ret < 0) {
  215. exit(1);
  216. }
  217. /* Sleep to keep namespace active */
  218. sleep(1);
  219. exit(0);
  220. }
  221. /* Let second child enter the namespace */
  222. usleep(100000); /* 100ms */
  223. /* Signal first child to exit */
  224. close(syncpipe[0]);
  225. sync_byte = 'X';
  226. write(syncpipe[1], &sync_byte, 1);
  227. close(syncpipe[1]);
  228. /* Wait for first child */
  229. waitpid(pid1, &status, 0);
  230. ASSERT_TRUE(WIFEXITED(status));
  231. /* Namespace should still be active because second child is using it */
  232. fd = open_by_handle_at(FD_NSFS_ROOT, handle, O_RDONLY);
  233. ASSERT_GE(fd, 0);
  234. close(fd);
  235. /* Wait for second child */
  236. waitpid(pid2, &status, 0);
  237. ASSERT_TRUE(WIFEXITED(status));
  238. }
  239. /*
  240. * Test user namespace active ref tracking via credential lifecycle
  241. */
  242. TEST(userns_active_ref_lifecycle)
  243. {
  244. struct file_handle *handle;
  245. int mount_id;
  246. int ret;
  247. int fd;
  248. int pipefd[2];
  249. pid_t pid;
  250. int status;
  251. char buf[sizeof(*handle) + MAX_HANDLE_SZ];
  252. ASSERT_EQ(pipe(pipefd), 0);
  253. pid = fork();
  254. ASSERT_GE(pid, 0);
  255. if (pid == 0) {
  256. /* Child process */
  257. close(pipefd[0]);
  258. /* Create new user namespace */
  259. ret = unshare(CLONE_NEWUSER);
  260. if (ret < 0) {
  261. close(pipefd[1]);
  262. exit(1);
  263. }
  264. /* Set up uid/gid mappings */
  265. int uid_map_fd = open("/proc/self/uid_map", O_WRONLY);
  266. int gid_map_fd = open("/proc/self/gid_map", O_WRONLY);
  267. int setgroups_fd = open("/proc/self/setgroups", O_WRONLY);
  268. if (uid_map_fd >= 0 && gid_map_fd >= 0 && setgroups_fd >= 0) {
  269. write(setgroups_fd, "deny", 4);
  270. close(setgroups_fd);
  271. char mapping[64];
  272. snprintf(mapping, sizeof(mapping), "0 %d 1", getuid());
  273. write(uid_map_fd, mapping, strlen(mapping));
  274. close(uid_map_fd);
  275. snprintf(mapping, sizeof(mapping), "0 %d 1", getgid());
  276. write(gid_map_fd, mapping, strlen(mapping));
  277. close(gid_map_fd);
  278. }
  279. /* Get file handle */
  280. fd = open("/proc/self/ns/user", O_RDONLY);
  281. if (fd < 0) {
  282. close(pipefd[1]);
  283. exit(1);
  284. }
  285. handle = (struct file_handle *)buf;
  286. handle->handle_bytes = MAX_HANDLE_SZ;
  287. ret = name_to_handle_at(fd, "", handle, &mount_id, AT_EMPTY_PATH);
  288. close(fd);
  289. if (ret < 0) {
  290. close(pipefd[1]);
  291. exit(1);
  292. }
  293. /* Send handle to parent */
  294. write(pipefd[1], buf, sizeof(*handle) + handle->handle_bytes);
  295. close(pipefd[1]);
  296. exit(0);
  297. }
  298. /* Parent */
  299. close(pipefd[1]);
  300. ret = read(pipefd[0], buf, sizeof(buf));
  301. close(pipefd[0]);
  302. waitpid(pid, &status, 0);
  303. ASSERT_TRUE(WIFEXITED(status));
  304. ASSERT_EQ(WEXITSTATUS(status), 0);
  305. ASSERT_GT(ret, 0);
  306. handle = (struct file_handle *)buf;
  307. /* Namespace should be inactive after all tasks exit */
  308. fd = open_by_handle_at(FD_NSFS_ROOT, handle, O_RDONLY);
  309. ASSERT_LT(fd, 0);
  310. ASSERT_TRUE(errno == ENOENT || errno == ESTALE);
  311. }
  312. /*
  313. * Test PID namespace active ref tracking
  314. */
  315. TEST(pidns_active_ref_lifecycle)
  316. {
  317. struct file_handle *handle;
  318. int mount_id;
  319. int ret;
  320. int fd;
  321. int pipefd[2];
  322. pid_t pid;
  323. int status;
  324. char buf[sizeof(*handle) + MAX_HANDLE_SZ];
  325. ASSERT_EQ(pipe(pipefd), 0);
  326. pid = fork();
  327. ASSERT_GE(pid, 0);
  328. if (pid == 0) {
  329. /* Child process */
  330. close(pipefd[0]);
  331. /* Create new PID namespace */
  332. ret = unshare(CLONE_NEWPID);
  333. if (ret < 0) {
  334. close(pipefd[1]);
  335. exit(1);
  336. }
  337. /* Fork to actually enter the PID namespace */
  338. pid_t child = fork();
  339. if (child < 0) {
  340. close(pipefd[1]);
  341. exit(1);
  342. }
  343. if (child == 0) {
  344. /* Grandchild - in new PID namespace */
  345. fd = open("/proc/self/ns/pid", O_RDONLY);
  346. if (fd < 0) {
  347. exit(1);
  348. }
  349. handle = (struct file_handle *)buf;
  350. handle->handle_bytes = MAX_HANDLE_SZ;
  351. ret = name_to_handle_at(fd, "", handle, &mount_id, AT_EMPTY_PATH);
  352. close(fd);
  353. if (ret < 0) {
  354. exit(1);
  355. }
  356. /* Send handle to grandparent */
  357. write(pipefd[1], buf, sizeof(*handle) + handle->handle_bytes);
  358. close(pipefd[1]);
  359. exit(0);
  360. }
  361. /* Wait for grandchild */
  362. waitpid(child, NULL, 0);
  363. exit(0);
  364. }
  365. /* Parent */
  366. close(pipefd[1]);
  367. ret = read(pipefd[0], buf, sizeof(buf));
  368. close(pipefd[0]);
  369. waitpid(pid, &status, 0);
  370. ASSERT_TRUE(WIFEXITED(status));
  371. ASSERT_EQ(WEXITSTATUS(status), 0);
  372. ASSERT_GT(ret, 0);
  373. handle = (struct file_handle *)buf;
  374. /* Namespace should be inactive after all processes exit */
  375. fd = open_by_handle_at(FD_NSFS_ROOT, handle, O_RDONLY);
  376. ASSERT_LT(fd, 0);
  377. ASSERT_TRUE(errno == ENOENT || errno == ESTALE);
  378. }
  379. /*
  380. * Test that an open file descriptor keeps a namespace active.
  381. * Even after the creating process exits, the namespace should remain
  382. * active as long as an fd is held open.
  383. */
  384. TEST(ns_fd_keeps_active)
  385. {
  386. struct file_handle *handle;
  387. int mount_id;
  388. int ret;
  389. int nsfd;
  390. int pipe_child_ready[2];
  391. int pipe_parent_ready[2];
  392. pid_t pid;
  393. int status;
  394. char buf[sizeof(*handle) + MAX_HANDLE_SZ];
  395. char sync_byte;
  396. char proc_path[64];
  397. ASSERT_EQ(pipe(pipe_child_ready), 0);
  398. ASSERT_EQ(pipe(pipe_parent_ready), 0);
  399. pid = fork();
  400. ASSERT_GE(pid, 0);
  401. if (pid == 0) {
  402. /* Child process */
  403. close(pipe_child_ready[0]);
  404. close(pipe_parent_ready[1]);
  405. TH_LOG("Child: creating new network namespace");
  406. /* Create new network namespace */
  407. ret = unshare(CLONE_NEWNET);
  408. if (ret < 0) {
  409. TH_LOG("Child: unshare(CLONE_NEWNET) failed: %s", strerror(errno));
  410. close(pipe_child_ready[1]);
  411. close(pipe_parent_ready[0]);
  412. exit(1);
  413. }
  414. TH_LOG("Child: network namespace created successfully");
  415. /* Get file handle for the namespace */
  416. nsfd = open("/proc/self/ns/net", O_RDONLY);
  417. if (nsfd < 0) {
  418. TH_LOG("Child: failed to open /proc/self/ns/net: %s", strerror(errno));
  419. close(pipe_child_ready[1]);
  420. close(pipe_parent_ready[0]);
  421. exit(1);
  422. }
  423. TH_LOG("Child: opened namespace fd %d", nsfd);
  424. handle = (struct file_handle *)buf;
  425. handle->handle_bytes = MAX_HANDLE_SZ;
  426. ret = name_to_handle_at(nsfd, "", handle, &mount_id, AT_EMPTY_PATH);
  427. close(nsfd);
  428. if (ret < 0) {
  429. TH_LOG("Child: name_to_handle_at failed: %s", strerror(errno));
  430. close(pipe_child_ready[1]);
  431. close(pipe_parent_ready[0]);
  432. exit(1);
  433. }
  434. TH_LOG("Child: got file handle (bytes=%u)", handle->handle_bytes);
  435. /* Send file handle to parent */
  436. ret = write(pipe_child_ready[1], buf, sizeof(*handle) + handle->handle_bytes);
  437. TH_LOG("Child: sent %d bytes of file handle to parent", ret);
  438. close(pipe_child_ready[1]);
  439. /* Wait for parent to open the fd */
  440. TH_LOG("Child: waiting for parent to open fd");
  441. ret = read(pipe_parent_ready[0], &sync_byte, 1);
  442. close(pipe_parent_ready[0]);
  443. TH_LOG("Child: parent signaled (read %d bytes), exiting now", ret);
  444. /* Exit - namespace should stay active because parent holds fd */
  445. exit(0);
  446. }
  447. /* Parent process */
  448. close(pipe_child_ready[1]);
  449. close(pipe_parent_ready[0]);
  450. TH_LOG("Parent: reading file handle from child");
  451. /* Read file handle from child */
  452. ret = read(pipe_child_ready[0], buf, sizeof(buf));
  453. close(pipe_child_ready[0]);
  454. ASSERT_GT(ret, 0);
  455. handle = (struct file_handle *)buf;
  456. TH_LOG("Parent: received %d bytes, handle size=%u", ret, handle->handle_bytes);
  457. /* Open the child's namespace while it's still alive */
  458. snprintf(proc_path, sizeof(proc_path), "/proc/%d/ns/net", pid);
  459. TH_LOG("Parent: opening child's namespace at %s", proc_path);
  460. nsfd = open(proc_path, O_RDONLY);
  461. if (nsfd < 0) {
  462. TH_LOG("Parent: failed to open %s: %s", proc_path, strerror(errno));
  463. close(pipe_parent_ready[1]);
  464. kill(pid, SIGKILL);
  465. waitpid(pid, NULL, 0);
  466. SKIP(return, "Failed to open child's namespace");
  467. }
  468. TH_LOG("Parent: opened child's namespace, got fd %d", nsfd);
  469. /* Signal child that we have the fd */
  470. sync_byte = 'G';
  471. write(pipe_parent_ready[1], &sync_byte, 1);
  472. close(pipe_parent_ready[1]);
  473. TH_LOG("Parent: signaled child that we have the fd");
  474. /* Wait for child to exit */
  475. waitpid(pid, &status, 0);
  476. ASSERT_TRUE(WIFEXITED(status));
  477. ASSERT_EQ(WEXITSTATUS(status), 0);
  478. TH_LOG("Child exited, parent holds fd %d to namespace", nsfd);
  479. /*
  480. * Namespace should still be ACTIVE because we hold an fd.
  481. * We should be able to reopen it via file handle.
  482. */
  483. TH_LOG("Attempting to reopen namespace via file handle (should succeed - fd held)");
  484. int fd2 = open_by_handle_at(FD_NSFS_ROOT, handle, O_RDONLY);
  485. ASSERT_GE(fd2, 0);
  486. TH_LOG("Successfully reopened namespace via file handle, got fd %d", fd2);
  487. /* Verify it's the same namespace */
  488. struct stat st1, st2;
  489. ASSERT_EQ(fstat(nsfd, &st1), 0);
  490. ASSERT_EQ(fstat(fd2, &st2), 0);
  491. TH_LOG("Namespace inodes: nsfd=%lu, fd2=%lu", st1.st_ino, st2.st_ino);
  492. ASSERT_EQ(st1.st_ino, st2.st_ino);
  493. close(fd2);
  494. /* Now close the fd - namespace should become inactive */
  495. TH_LOG("Closing fd %d - namespace should become inactive", nsfd);
  496. close(nsfd);
  497. /* Now reopening should fail - namespace is inactive */
  498. TH_LOG("Attempting to reopen namespace via file handle (should fail - inactive)");
  499. fd2 = open_by_handle_at(FD_NSFS_ROOT, handle, O_RDONLY);
  500. ASSERT_LT(fd2, 0);
  501. /* Should fail with ENOENT (inactive) or ESTALE (gone) */
  502. TH_LOG("Reopen failed as expected: %s (errno=%d)", strerror(errno), errno);
  503. ASSERT_TRUE(errno == ENOENT || errno == ESTALE);
  504. }
  505. /*
  506. * Test hierarchical active reference propagation.
  507. * When a child namespace is active, its owning user namespace should also
  508. * be active automatically due to hierarchical active reference propagation.
  509. * This ensures parents are always reachable when children are active.
  510. */
  511. TEST(ns_parent_always_reachable)
  512. {
  513. struct file_handle *parent_handle, *child_handle;
  514. int ret;
  515. int child_nsfd;
  516. int pipefd[2];
  517. pid_t pid;
  518. int status;
  519. __u64 parent_id, child_id;
  520. char parent_buf[sizeof(*parent_handle) + MAX_HANDLE_SZ];
  521. char child_buf[sizeof(*child_handle) + MAX_HANDLE_SZ];
  522. ASSERT_EQ(pipe(pipefd), 0);
  523. pid = fork();
  524. ASSERT_GE(pid, 0);
  525. if (pid == 0) {
  526. /* Child process */
  527. close(pipefd[0]);
  528. TH_LOG("Child: creating parent user namespace and setting up mappings");
  529. /* Create parent user namespace with mappings */
  530. ret = setup_userns();
  531. if (ret < 0) {
  532. TH_LOG("Child: setup_userns() for parent failed: %s", strerror(errno));
  533. close(pipefd[1]);
  534. exit(1);
  535. }
  536. TH_LOG("Child: parent user namespace created, now uid=%d gid=%d", getuid(), getgid());
  537. /* Get namespace ID for parent user namespace */
  538. int parent_fd = open("/proc/self/ns/user", O_RDONLY);
  539. if (parent_fd < 0) {
  540. TH_LOG("Child: failed to open parent /proc/self/ns/user: %s", strerror(errno));
  541. close(pipefd[1]);
  542. exit(1);
  543. }
  544. TH_LOG("Child: opened parent userns fd %d", parent_fd);
  545. if (ioctl(parent_fd, NS_GET_ID, &parent_id) < 0) {
  546. TH_LOG("Child: NS_GET_ID for parent failed: %s", strerror(errno));
  547. close(parent_fd);
  548. close(pipefd[1]);
  549. exit(1);
  550. }
  551. close(parent_fd);
  552. TH_LOG("Child: got parent namespace ID %llu", (unsigned long long)parent_id);
  553. /* Create child user namespace within parent */
  554. TH_LOG("Child: creating nested child user namespace");
  555. ret = setup_userns();
  556. if (ret < 0) {
  557. TH_LOG("Child: setup_userns() for child failed: %s", strerror(errno));
  558. close(pipefd[1]);
  559. exit(1);
  560. }
  561. TH_LOG("Child: nested child user namespace created, uid=%d gid=%d", getuid(), getgid());
  562. /* Get namespace ID for child user namespace */
  563. int child_fd = open("/proc/self/ns/user", O_RDONLY);
  564. if (child_fd < 0) {
  565. TH_LOG("Child: failed to open child /proc/self/ns/user: %s", strerror(errno));
  566. close(pipefd[1]);
  567. exit(1);
  568. }
  569. TH_LOG("Child: opened child userns fd %d", child_fd);
  570. if (ioctl(child_fd, NS_GET_ID, &child_id) < 0) {
  571. TH_LOG("Child: NS_GET_ID for child failed: %s", strerror(errno));
  572. close(child_fd);
  573. close(pipefd[1]);
  574. exit(1);
  575. }
  576. close(child_fd);
  577. TH_LOG("Child: got child namespace ID %llu", (unsigned long long)child_id);
  578. /* Send both namespace IDs to parent */
  579. TH_LOG("Child: sending both namespace IDs to parent");
  580. write(pipefd[1], &parent_id, sizeof(parent_id));
  581. write(pipefd[1], &child_id, sizeof(child_id));
  582. close(pipefd[1]);
  583. TH_LOG("Child: exiting - parent userns should become inactive");
  584. /* Exit - parent user namespace should become inactive */
  585. exit(0);
  586. }
  587. /* Parent process */
  588. close(pipefd[1]);
  589. TH_LOG("Parent: reading both namespace IDs from child");
  590. /* Read both namespace IDs - fixed size, no parsing needed */
  591. ret = read(pipefd[0], &parent_id, sizeof(parent_id));
  592. if (ret != sizeof(parent_id)) {
  593. close(pipefd[0]);
  594. waitpid(pid, NULL, 0);
  595. SKIP(return, "Failed to read parent namespace ID from child");
  596. }
  597. ret = read(pipefd[0], &child_id, sizeof(child_id));
  598. close(pipefd[0]);
  599. if (ret != sizeof(child_id)) {
  600. waitpid(pid, NULL, 0);
  601. SKIP(return, "Failed to read child namespace ID from child");
  602. }
  603. TH_LOG("Parent: received parent_id=%llu, child_id=%llu",
  604. (unsigned long long)parent_id, (unsigned long long)child_id);
  605. /* Construct file handles from namespace IDs */
  606. parent_handle = (struct file_handle *)parent_buf;
  607. parent_handle->handle_bytes = sizeof(struct nsfs_file_handle);
  608. parent_handle->handle_type = FILEID_NSFS;
  609. struct nsfs_file_handle *parent_fh = (struct nsfs_file_handle *)parent_handle->f_handle;
  610. parent_fh->ns_id = parent_id;
  611. parent_fh->ns_type = 0;
  612. parent_fh->ns_inum = 0;
  613. child_handle = (struct file_handle *)child_buf;
  614. child_handle->handle_bytes = sizeof(struct nsfs_file_handle);
  615. child_handle->handle_type = FILEID_NSFS;
  616. struct nsfs_file_handle *child_fh = (struct nsfs_file_handle *)child_handle->f_handle;
  617. child_fh->ns_id = child_id;
  618. child_fh->ns_type = 0;
  619. child_fh->ns_inum = 0;
  620. TH_LOG("Parent: opening child namespace BEFORE child exits");
  621. /* Open child namespace while child is still alive to keep it active */
  622. child_nsfd = open_by_handle_at(FD_NSFS_ROOT, child_handle, O_RDONLY);
  623. if (child_nsfd < 0) {
  624. TH_LOG("Failed to open child namespace: %s (errno=%d)", strerror(errno), errno);
  625. waitpid(pid, NULL, 0);
  626. SKIP(return, "Failed to open child namespace");
  627. }
  628. TH_LOG("Opened child namespace fd %d", child_nsfd);
  629. /* Now wait for child to exit */
  630. TH_LOG("Parent: waiting for child to exit");
  631. waitpid(pid, &status, 0);
  632. ASSERT_TRUE(WIFEXITED(status));
  633. ASSERT_EQ(WEXITSTATUS(status), 0);
  634. TH_LOG("Child process exited, parent holds fd to child namespace");
  635. /*
  636. * With hierarchical active reference propagation:
  637. * Since the child namespace is active (parent process holds fd),
  638. * the parent user namespace should ALSO be active automatically.
  639. * This is because when we took an active reference on the child,
  640. * it propagated up to the owning user namespace.
  641. */
  642. TH_LOG("Attempting to reopen parent namespace (should SUCCEED - hierarchical propagation)");
  643. int parent_fd = open_by_handle_at(FD_NSFS_ROOT, parent_handle, O_RDONLY);
  644. ASSERT_GE(parent_fd, 0);
  645. TH_LOG("SUCCESS: Parent namespace is active (fd=%d) due to active child", parent_fd);
  646. /* Verify we can also get parent via NS_GET_USERNS */
  647. TH_LOG("Verifying NS_GET_USERNS also works");
  648. int parent_fd2 = ioctl(child_nsfd, NS_GET_USERNS);
  649. if (parent_fd2 < 0) {
  650. close(parent_fd);
  651. close(child_nsfd);
  652. TH_LOG("NS_GET_USERNS failed: %s (errno=%d)", strerror(errno), errno);
  653. SKIP(return, "NS_GET_USERNS not supported or failed");
  654. }
  655. TH_LOG("NS_GET_USERNS succeeded, got parent fd %d", parent_fd2);
  656. /* Verify both methods give us the same namespace */
  657. struct stat st1, st2;
  658. ASSERT_EQ(fstat(parent_fd, &st1), 0);
  659. ASSERT_EQ(fstat(parent_fd2, &st2), 0);
  660. TH_LOG("Parent namespace inodes: parent_fd=%lu, parent_fd2=%lu", st1.st_ino, st2.st_ino);
  661. ASSERT_EQ(st1.st_ino, st2.st_ino);
  662. /*
  663. * Close child fd - parent should remain active because we still
  664. * hold direct references to it (parent_fd and parent_fd2).
  665. */
  666. TH_LOG("Closing child fd - parent should remain active (direct refs held)");
  667. close(child_nsfd);
  668. /* Parent should still be openable */
  669. TH_LOG("Verifying parent still active via file handle");
  670. int parent_fd3 = open_by_handle_at(FD_NSFS_ROOT, parent_handle, O_RDONLY);
  671. ASSERT_GE(parent_fd3, 0);
  672. close(parent_fd3);
  673. TH_LOG("Closing all fds to parent namespace");
  674. close(parent_fd);
  675. close(parent_fd2);
  676. /* Both should now be inactive */
  677. TH_LOG("Attempting to reopen parent (should fail - inactive, no refs)");
  678. parent_fd = open_by_handle_at(FD_NSFS_ROOT, parent_handle, O_RDONLY);
  679. ASSERT_LT(parent_fd, 0);
  680. TH_LOG("Parent inactive as expected: %s (errno=%d)", strerror(errno), errno);
  681. ASSERT_TRUE(errno == ENOENT || errno == ESTALE);
  682. }
  683. /*
  684. * Test that bind mounts keep namespaces in the tree even when inactive
  685. */
  686. TEST(ns_bind_mount_keeps_in_tree)
  687. {
  688. struct file_handle *handle;
  689. int mount_id;
  690. int ret;
  691. int fd;
  692. int pipefd[2];
  693. pid_t pid;
  694. int status;
  695. char buf[sizeof(*handle) + MAX_HANDLE_SZ];
  696. char tmpfile[] = "/tmp/ns-test-XXXXXX";
  697. int tmpfd;
  698. /* Create temporary file for bind mount */
  699. tmpfd = mkstemp(tmpfile);
  700. if (tmpfd < 0) {
  701. SKIP(return, "Cannot create temporary file");
  702. }
  703. close(tmpfd);
  704. ASSERT_EQ(pipe(pipefd), 0);
  705. pid = fork();
  706. ASSERT_GE(pid, 0);
  707. if (pid == 0) {
  708. /* Child process */
  709. close(pipefd[0]);
  710. /* Unshare mount namespace and make mounts private to avoid propagation */
  711. ret = unshare(CLONE_NEWNS);
  712. if (ret < 0) {
  713. close(pipefd[1]);
  714. unlink(tmpfile);
  715. exit(1);
  716. }
  717. ret = mount(NULL, "/", NULL, MS_PRIVATE | MS_REC, NULL);
  718. if (ret < 0) {
  719. close(pipefd[1]);
  720. unlink(tmpfile);
  721. exit(1);
  722. }
  723. /* Create new network namespace */
  724. ret = unshare(CLONE_NEWNET);
  725. if (ret < 0) {
  726. close(pipefd[1]);
  727. unlink(tmpfile);
  728. exit(1);
  729. }
  730. /* Bind mount the namespace */
  731. ret = mount("/proc/self/ns/net", tmpfile, NULL, MS_BIND, NULL);
  732. if (ret < 0) {
  733. close(pipefd[1]);
  734. unlink(tmpfile);
  735. exit(1);
  736. }
  737. /* Get file handle */
  738. fd = open("/proc/self/ns/net", O_RDONLY);
  739. if (fd < 0) {
  740. umount(tmpfile);
  741. close(pipefd[1]);
  742. unlink(tmpfile);
  743. exit(1);
  744. }
  745. handle = (struct file_handle *)buf;
  746. handle->handle_bytes = MAX_HANDLE_SZ;
  747. ret = name_to_handle_at(fd, "", handle, &mount_id, AT_EMPTY_PATH);
  748. close(fd);
  749. if (ret < 0) {
  750. umount(tmpfile);
  751. close(pipefd[1]);
  752. unlink(tmpfile);
  753. exit(1);
  754. }
  755. /* Send handle to parent */
  756. write(pipefd[1], buf, sizeof(*handle) + handle->handle_bytes);
  757. close(pipefd[1]);
  758. exit(0);
  759. }
  760. /* Parent */
  761. close(pipefd[1]);
  762. ret = read(pipefd[0], buf, sizeof(buf));
  763. close(pipefd[0]);
  764. waitpid(pid, &status, 0);
  765. ASSERT_TRUE(WIFEXITED(status));
  766. ASSERT_EQ(WEXITSTATUS(status), 0);
  767. ASSERT_GT(ret, 0);
  768. handle = (struct file_handle *)buf;
  769. /*
  770. * Namespace should be inactive but still in tree due to bind mount.
  771. * Reopening should fail with ENOENT (inactive) not ESTALE (not in tree).
  772. */
  773. fd = open_by_handle_at(FD_NSFS_ROOT, handle, O_RDONLY);
  774. ASSERT_LT(fd, 0);
  775. /* Should be ENOENT (inactive) since bind mount keeps it in tree */
  776. if (errno != ENOENT && errno != ESTALE) {
  777. TH_LOG("Unexpected error: %d", errno);
  778. }
  779. /* Cleanup */
  780. umount(tmpfile);
  781. unlink(tmpfile);
  782. }
  783. /*
  784. * Test multi-level hierarchy (3+ levels deep).
  785. * Grandparent → Parent → Child
  786. * When child is active, both parent AND grandparent should be active.
  787. */
  788. TEST(ns_multilevel_hierarchy)
  789. {
  790. struct file_handle *gp_handle, *p_handle, *c_handle;
  791. int ret, pipefd[2];
  792. pid_t pid;
  793. int status;
  794. __u64 gp_id, p_id, c_id;
  795. char gp_buf[sizeof(*gp_handle) + MAX_HANDLE_SZ];
  796. char p_buf[sizeof(*p_handle) + MAX_HANDLE_SZ];
  797. char c_buf[sizeof(*c_handle) + MAX_HANDLE_SZ];
  798. ASSERT_EQ(pipe(pipefd), 0);
  799. pid = fork();
  800. ASSERT_GE(pid, 0);
  801. if (pid == 0) {
  802. close(pipefd[0]);
  803. /* Create grandparent user namespace */
  804. if (setup_userns() < 0) {
  805. close(pipefd[1]);
  806. exit(1);
  807. }
  808. int gp_fd = open("/proc/self/ns/user", O_RDONLY);
  809. if (gp_fd < 0) {
  810. close(pipefd[1]);
  811. exit(1);
  812. }
  813. if (ioctl(gp_fd, NS_GET_ID, &gp_id) < 0) {
  814. close(gp_fd);
  815. close(pipefd[1]);
  816. exit(1);
  817. }
  818. close(gp_fd);
  819. /* Create parent user namespace */
  820. if (setup_userns() < 0) {
  821. close(pipefd[1]);
  822. exit(1);
  823. }
  824. int p_fd = open("/proc/self/ns/user", O_RDONLY);
  825. if (p_fd < 0) {
  826. close(pipefd[1]);
  827. exit(1);
  828. }
  829. if (ioctl(p_fd, NS_GET_ID, &p_id) < 0) {
  830. close(p_fd);
  831. close(pipefd[1]);
  832. exit(1);
  833. }
  834. close(p_fd);
  835. /* Create child user namespace */
  836. if (setup_userns() < 0) {
  837. close(pipefd[1]);
  838. exit(1);
  839. }
  840. int c_fd = open("/proc/self/ns/user", O_RDONLY);
  841. if (c_fd < 0) {
  842. close(pipefd[1]);
  843. exit(1);
  844. }
  845. if (ioctl(c_fd, NS_GET_ID, &c_id) < 0) {
  846. close(c_fd);
  847. close(pipefd[1]);
  848. exit(1);
  849. }
  850. close(c_fd);
  851. /* Send all three namespace IDs */
  852. write(pipefd[1], &gp_id, sizeof(gp_id));
  853. write(pipefd[1], &p_id, sizeof(p_id));
  854. write(pipefd[1], &c_id, sizeof(c_id));
  855. close(pipefd[1]);
  856. exit(0);
  857. }
  858. close(pipefd[1]);
  859. /* Read all three namespace IDs - fixed size, no parsing needed */
  860. ret = read(pipefd[0], &gp_id, sizeof(gp_id));
  861. if (ret != sizeof(gp_id)) {
  862. close(pipefd[0]);
  863. waitpid(pid, NULL, 0);
  864. SKIP(return, "Failed to read grandparent namespace ID from child");
  865. }
  866. ret = read(pipefd[0], &p_id, sizeof(p_id));
  867. if (ret != sizeof(p_id)) {
  868. close(pipefd[0]);
  869. waitpid(pid, NULL, 0);
  870. SKIP(return, "Failed to read parent namespace ID from child");
  871. }
  872. ret = read(pipefd[0], &c_id, sizeof(c_id));
  873. close(pipefd[0]);
  874. if (ret != sizeof(c_id)) {
  875. waitpid(pid, NULL, 0);
  876. SKIP(return, "Failed to read child namespace ID from child");
  877. }
  878. /* Construct file handles from namespace IDs */
  879. gp_handle = (struct file_handle *)gp_buf;
  880. gp_handle->handle_bytes = sizeof(struct nsfs_file_handle);
  881. gp_handle->handle_type = FILEID_NSFS;
  882. struct nsfs_file_handle *gp_fh = (struct nsfs_file_handle *)gp_handle->f_handle;
  883. gp_fh->ns_id = gp_id;
  884. gp_fh->ns_type = 0;
  885. gp_fh->ns_inum = 0;
  886. p_handle = (struct file_handle *)p_buf;
  887. p_handle->handle_bytes = sizeof(struct nsfs_file_handle);
  888. p_handle->handle_type = FILEID_NSFS;
  889. struct nsfs_file_handle *p_fh = (struct nsfs_file_handle *)p_handle->f_handle;
  890. p_fh->ns_id = p_id;
  891. p_fh->ns_type = 0;
  892. p_fh->ns_inum = 0;
  893. c_handle = (struct file_handle *)c_buf;
  894. c_handle->handle_bytes = sizeof(struct nsfs_file_handle);
  895. c_handle->handle_type = FILEID_NSFS;
  896. struct nsfs_file_handle *c_fh = (struct nsfs_file_handle *)c_handle->f_handle;
  897. c_fh->ns_id = c_id;
  898. c_fh->ns_type = 0;
  899. c_fh->ns_inum = 0;
  900. /* Open child before process exits */
  901. int c_fd = open_by_handle_at(FD_NSFS_ROOT, c_handle, O_RDONLY);
  902. if (c_fd < 0) {
  903. waitpid(pid, NULL, 0);
  904. SKIP(return, "Failed to open child namespace");
  905. }
  906. waitpid(pid, &status, 0);
  907. ASSERT_TRUE(WIFEXITED(status));
  908. ASSERT_EQ(WEXITSTATUS(status), 0);
  909. /*
  910. * With 3-level hierarchy and child active:
  911. * - Child is active (we hold fd)
  912. * - Parent should be active (propagated from child)
  913. * - Grandparent should be active (propagated from parent)
  914. */
  915. TH_LOG("Testing parent active when child is active");
  916. int p_fd = open_by_handle_at(FD_NSFS_ROOT, p_handle, O_RDONLY);
  917. ASSERT_GE(p_fd, 0);
  918. TH_LOG("Testing grandparent active when child is active");
  919. int gp_fd = open_by_handle_at(FD_NSFS_ROOT, gp_handle, O_RDONLY);
  920. ASSERT_GE(gp_fd, 0);
  921. close(c_fd);
  922. close(p_fd);
  923. close(gp_fd);
  924. }
  925. /*
  926. * Test multiple children sharing same parent.
  927. * Parent should stay active as long as ANY child is active.
  928. */
  929. TEST(ns_multiple_children_same_parent)
  930. {
  931. struct file_handle *p_handle, *c1_handle, *c2_handle;
  932. int ret, pipefd[2];
  933. pid_t pid;
  934. int status;
  935. __u64 p_id, c1_id, c2_id;
  936. char p_buf[sizeof(*p_handle) + MAX_HANDLE_SZ];
  937. char c1_buf[sizeof(*c1_handle) + MAX_HANDLE_SZ];
  938. char c2_buf[sizeof(*c2_handle) + MAX_HANDLE_SZ];
  939. ASSERT_EQ(pipe(pipefd), 0);
  940. pid = fork();
  941. ASSERT_GE(pid, 0);
  942. if (pid == 0) {
  943. close(pipefd[0]);
  944. /* Create parent user namespace */
  945. if (setup_userns() < 0) {
  946. close(pipefd[1]);
  947. exit(1);
  948. }
  949. int p_fd = open("/proc/self/ns/user", O_RDONLY);
  950. if (p_fd < 0) {
  951. close(pipefd[1]);
  952. exit(1);
  953. }
  954. if (ioctl(p_fd, NS_GET_ID, &p_id) < 0) {
  955. close(p_fd);
  956. close(pipefd[1]);
  957. exit(1);
  958. }
  959. close(p_fd);
  960. /* Create first child user namespace */
  961. if (setup_userns() < 0) {
  962. close(pipefd[1]);
  963. exit(1);
  964. }
  965. int c1_fd = open("/proc/self/ns/user", O_RDONLY);
  966. if (c1_fd < 0) {
  967. close(pipefd[1]);
  968. exit(1);
  969. }
  970. if (ioctl(c1_fd, NS_GET_ID, &c1_id) < 0) {
  971. close(c1_fd);
  972. close(pipefd[1]);
  973. exit(1);
  974. }
  975. close(c1_fd);
  976. /* Return to parent user namespace and create second child */
  977. /* We can't actually do this easily, so let's create a sibling namespace
  978. * by creating a network namespace instead */
  979. if (unshare(CLONE_NEWNET) < 0) {
  980. close(pipefd[1]);
  981. exit(1);
  982. }
  983. int c2_fd = open("/proc/self/ns/net", O_RDONLY);
  984. if (c2_fd < 0) {
  985. close(pipefd[1]);
  986. exit(1);
  987. }
  988. if (ioctl(c2_fd, NS_GET_ID, &c2_id) < 0) {
  989. close(c2_fd);
  990. close(pipefd[1]);
  991. exit(1);
  992. }
  993. close(c2_fd);
  994. /* Send all namespace IDs */
  995. write(pipefd[1], &p_id, sizeof(p_id));
  996. write(pipefd[1], &c1_id, sizeof(c1_id));
  997. write(pipefd[1], &c2_id, sizeof(c2_id));
  998. close(pipefd[1]);
  999. exit(0);
  1000. }
  1001. close(pipefd[1]);
  1002. /* Read all three namespace IDs - fixed size, no parsing needed */
  1003. ret = read(pipefd[0], &p_id, sizeof(p_id));
  1004. if (ret != sizeof(p_id)) {
  1005. close(pipefd[0]);
  1006. waitpid(pid, NULL, 0);
  1007. SKIP(return, "Failed to read parent namespace ID");
  1008. }
  1009. ret = read(pipefd[0], &c1_id, sizeof(c1_id));
  1010. if (ret != sizeof(c1_id)) {
  1011. close(pipefd[0]);
  1012. waitpid(pid, NULL, 0);
  1013. SKIP(return, "Failed to read first child namespace ID");
  1014. }
  1015. ret = read(pipefd[0], &c2_id, sizeof(c2_id));
  1016. close(pipefd[0]);
  1017. if (ret != sizeof(c2_id)) {
  1018. waitpid(pid, NULL, 0);
  1019. SKIP(return, "Failed to read second child namespace ID");
  1020. }
  1021. /* Construct file handles from namespace IDs */
  1022. p_handle = (struct file_handle *)p_buf;
  1023. p_handle->handle_bytes = sizeof(struct nsfs_file_handle);
  1024. p_handle->handle_type = FILEID_NSFS;
  1025. struct nsfs_file_handle *p_fh = (struct nsfs_file_handle *)p_handle->f_handle;
  1026. p_fh->ns_id = p_id;
  1027. p_fh->ns_type = 0;
  1028. p_fh->ns_inum = 0;
  1029. c1_handle = (struct file_handle *)c1_buf;
  1030. c1_handle->handle_bytes = sizeof(struct nsfs_file_handle);
  1031. c1_handle->handle_type = FILEID_NSFS;
  1032. struct nsfs_file_handle *c1_fh = (struct nsfs_file_handle *)c1_handle->f_handle;
  1033. c1_fh->ns_id = c1_id;
  1034. c1_fh->ns_type = 0;
  1035. c1_fh->ns_inum = 0;
  1036. c2_handle = (struct file_handle *)c2_buf;
  1037. c2_handle->handle_bytes = sizeof(struct nsfs_file_handle);
  1038. c2_handle->handle_type = FILEID_NSFS;
  1039. struct nsfs_file_handle *c2_fh = (struct nsfs_file_handle *)c2_handle->f_handle;
  1040. c2_fh->ns_id = c2_id;
  1041. c2_fh->ns_type = 0;
  1042. c2_fh->ns_inum = 0;
  1043. /* Open both children before process exits */
  1044. int c1_fd = open_by_handle_at(FD_NSFS_ROOT, c1_handle, O_RDONLY);
  1045. int c2_fd = open_by_handle_at(FD_NSFS_ROOT, c2_handle, O_RDONLY);
  1046. if (c1_fd < 0 || c2_fd < 0) {
  1047. if (c1_fd >= 0) close(c1_fd);
  1048. if (c2_fd >= 0) close(c2_fd);
  1049. waitpid(pid, NULL, 0);
  1050. SKIP(return, "Failed to open child namespaces");
  1051. }
  1052. waitpid(pid, &status, 0);
  1053. ASSERT_TRUE(WIFEXITED(status));
  1054. ASSERT_EQ(WEXITSTATUS(status), 0);
  1055. /* Parent should be active (both children active) */
  1056. TH_LOG("Both children active - parent should be active");
  1057. int p_fd = open_by_handle_at(FD_NSFS_ROOT, p_handle, O_RDONLY);
  1058. ASSERT_GE(p_fd, 0);
  1059. close(p_fd);
  1060. /* Close first child - parent should STILL be active */
  1061. TH_LOG("Closing first child - parent should still be active");
  1062. close(c1_fd);
  1063. p_fd = open_by_handle_at(FD_NSFS_ROOT, p_handle, O_RDONLY);
  1064. ASSERT_GE(p_fd, 0);
  1065. close(p_fd);
  1066. /* Close second child - NOW parent should become inactive */
  1067. TH_LOG("Closing second child - parent should become inactive");
  1068. close(c2_fd);
  1069. p_fd = open_by_handle_at(FD_NSFS_ROOT, p_handle, O_RDONLY);
  1070. ASSERT_LT(p_fd, 0);
  1071. }
  1072. /*
  1073. * Test that different namespace types with same owner all contribute
  1074. * active references to the owning user namespace.
  1075. */
  1076. TEST(ns_different_types_same_owner)
  1077. {
  1078. struct file_handle *u_handle, *n_handle, *ut_handle;
  1079. int ret, pipefd[2];
  1080. pid_t pid;
  1081. int status;
  1082. __u64 u_id, n_id, ut_id;
  1083. char u_buf[sizeof(*u_handle) + MAX_HANDLE_SZ];
  1084. char n_buf[sizeof(*n_handle) + MAX_HANDLE_SZ];
  1085. char ut_buf[sizeof(*ut_handle) + MAX_HANDLE_SZ];
  1086. ASSERT_EQ(pipe(pipefd), 0);
  1087. pid = fork();
  1088. ASSERT_GE(pid, 0);
  1089. if (pid == 0) {
  1090. close(pipefd[0]);
  1091. /* Create user namespace */
  1092. if (setup_userns() < 0) {
  1093. close(pipefd[1]);
  1094. exit(1);
  1095. }
  1096. int u_fd = open("/proc/self/ns/user", O_RDONLY);
  1097. if (u_fd < 0) {
  1098. close(pipefd[1]);
  1099. exit(1);
  1100. }
  1101. if (ioctl(u_fd, NS_GET_ID, &u_id) < 0) {
  1102. close(u_fd);
  1103. close(pipefd[1]);
  1104. exit(1);
  1105. }
  1106. close(u_fd);
  1107. /* Create network namespace (owned by user namespace) */
  1108. if (unshare(CLONE_NEWNET) < 0) {
  1109. close(pipefd[1]);
  1110. exit(1);
  1111. }
  1112. int n_fd = open("/proc/self/ns/net", O_RDONLY);
  1113. if (n_fd < 0) {
  1114. close(pipefd[1]);
  1115. exit(1);
  1116. }
  1117. if (ioctl(n_fd, NS_GET_ID, &n_id) < 0) {
  1118. close(n_fd);
  1119. close(pipefd[1]);
  1120. exit(1);
  1121. }
  1122. close(n_fd);
  1123. /* Create UTS namespace (also owned by user namespace) */
  1124. if (unshare(CLONE_NEWUTS) < 0) {
  1125. close(pipefd[1]);
  1126. exit(1);
  1127. }
  1128. int ut_fd = open("/proc/self/ns/uts", O_RDONLY);
  1129. if (ut_fd < 0) {
  1130. close(pipefd[1]);
  1131. exit(1);
  1132. }
  1133. if (ioctl(ut_fd, NS_GET_ID, &ut_id) < 0) {
  1134. close(ut_fd);
  1135. close(pipefd[1]);
  1136. exit(1);
  1137. }
  1138. close(ut_fd);
  1139. /* Send all namespace IDs */
  1140. write(pipefd[1], &u_id, sizeof(u_id));
  1141. write(pipefd[1], &n_id, sizeof(n_id));
  1142. write(pipefd[1], &ut_id, sizeof(ut_id));
  1143. close(pipefd[1]);
  1144. exit(0);
  1145. }
  1146. close(pipefd[1]);
  1147. /* Read all three namespace IDs - fixed size, no parsing needed */
  1148. ret = read(pipefd[0], &u_id, sizeof(u_id));
  1149. if (ret != sizeof(u_id)) {
  1150. close(pipefd[0]);
  1151. waitpid(pid, NULL, 0);
  1152. SKIP(return, "Failed to read user namespace ID");
  1153. }
  1154. ret = read(pipefd[0], &n_id, sizeof(n_id));
  1155. if (ret != sizeof(n_id)) {
  1156. close(pipefd[0]);
  1157. waitpid(pid, NULL, 0);
  1158. SKIP(return, "Failed to read network namespace ID");
  1159. }
  1160. ret = read(pipefd[0], &ut_id, sizeof(ut_id));
  1161. close(pipefd[0]);
  1162. if (ret != sizeof(ut_id)) {
  1163. waitpid(pid, NULL, 0);
  1164. SKIP(return, "Failed to read UTS namespace ID");
  1165. }
  1166. /* Construct file handles from namespace IDs */
  1167. u_handle = (struct file_handle *)u_buf;
  1168. u_handle->handle_bytes = sizeof(struct nsfs_file_handle);
  1169. u_handle->handle_type = FILEID_NSFS;
  1170. struct nsfs_file_handle *u_fh = (struct nsfs_file_handle *)u_handle->f_handle;
  1171. u_fh->ns_id = u_id;
  1172. u_fh->ns_type = 0;
  1173. u_fh->ns_inum = 0;
  1174. n_handle = (struct file_handle *)n_buf;
  1175. n_handle->handle_bytes = sizeof(struct nsfs_file_handle);
  1176. n_handle->handle_type = FILEID_NSFS;
  1177. struct nsfs_file_handle *n_fh = (struct nsfs_file_handle *)n_handle->f_handle;
  1178. n_fh->ns_id = n_id;
  1179. n_fh->ns_type = 0;
  1180. n_fh->ns_inum = 0;
  1181. ut_handle = (struct file_handle *)ut_buf;
  1182. ut_handle->handle_bytes = sizeof(struct nsfs_file_handle);
  1183. ut_handle->handle_type = FILEID_NSFS;
  1184. struct nsfs_file_handle *ut_fh = (struct nsfs_file_handle *)ut_handle->f_handle;
  1185. ut_fh->ns_id = ut_id;
  1186. ut_fh->ns_type = 0;
  1187. ut_fh->ns_inum = 0;
  1188. /* Open both non-user namespaces before process exits */
  1189. int n_fd = open_by_handle_at(FD_NSFS_ROOT, n_handle, O_RDONLY);
  1190. int ut_fd = open_by_handle_at(FD_NSFS_ROOT, ut_handle, O_RDONLY);
  1191. if (n_fd < 0 || ut_fd < 0) {
  1192. if (n_fd >= 0) close(n_fd);
  1193. if (ut_fd >= 0) close(ut_fd);
  1194. waitpid(pid, NULL, 0);
  1195. SKIP(return, "Failed to open namespaces");
  1196. }
  1197. waitpid(pid, &status, 0);
  1198. ASSERT_TRUE(WIFEXITED(status));
  1199. ASSERT_EQ(WEXITSTATUS(status), 0);
  1200. /*
  1201. * Both network and UTS namespaces are active.
  1202. * User namespace should be active (gets 2 active refs).
  1203. */
  1204. TH_LOG("Both net and uts active - user namespace should be active");
  1205. int u_fd = open_by_handle_at(FD_NSFS_ROOT, u_handle, O_RDONLY);
  1206. ASSERT_GE(u_fd, 0);
  1207. close(u_fd);
  1208. /* Close network namespace - user namespace should STILL be active */
  1209. TH_LOG("Closing network ns - user ns should still be active (uts still active)");
  1210. close(n_fd);
  1211. u_fd = open_by_handle_at(FD_NSFS_ROOT, u_handle, O_RDONLY);
  1212. ASSERT_GE(u_fd, 0);
  1213. close(u_fd);
  1214. /* Close UTS namespace - user namespace should become inactive */
  1215. TH_LOG("Closing uts ns - user ns should become inactive");
  1216. close(ut_fd);
  1217. u_fd = open_by_handle_at(FD_NSFS_ROOT, u_handle, O_RDONLY);
  1218. ASSERT_LT(u_fd, 0);
  1219. }
  1220. /*
  1221. * Test hierarchical propagation with deep namespace hierarchy.
  1222. * Create: init_user_ns -> user_A -> user_B -> net_ns
  1223. * When net_ns is active, both user_A and user_B should be active.
  1224. * This verifies the conditional recursion in __ns_ref_active_put() works.
  1225. */
  1226. TEST(ns_deep_hierarchy_propagation)
  1227. {
  1228. struct file_handle *ua_handle, *ub_handle, *net_handle;
  1229. int ret, pipefd[2];
  1230. pid_t pid;
  1231. int status;
  1232. __u64 ua_id, ub_id, net_id;
  1233. char ua_buf[sizeof(*ua_handle) + MAX_HANDLE_SZ];
  1234. char ub_buf[sizeof(*ub_handle) + MAX_HANDLE_SZ];
  1235. char net_buf[sizeof(*net_handle) + MAX_HANDLE_SZ];
  1236. ASSERT_EQ(pipe(pipefd), 0);
  1237. pid = fork();
  1238. ASSERT_GE(pid, 0);
  1239. if (pid == 0) {
  1240. close(pipefd[0]);
  1241. /* Create user_A -> user_B -> net hierarchy */
  1242. if (setup_userns() < 0) {
  1243. close(pipefd[1]);
  1244. exit(1);
  1245. }
  1246. int ua_fd = open("/proc/self/ns/user", O_RDONLY);
  1247. if (ua_fd < 0) {
  1248. close(pipefd[1]);
  1249. exit(1);
  1250. }
  1251. if (ioctl(ua_fd, NS_GET_ID, &ua_id) < 0) {
  1252. close(ua_fd);
  1253. close(pipefd[1]);
  1254. exit(1);
  1255. }
  1256. close(ua_fd);
  1257. if (setup_userns() < 0) {
  1258. close(pipefd[1]);
  1259. exit(1);
  1260. }
  1261. int ub_fd = open("/proc/self/ns/user", O_RDONLY);
  1262. if (ub_fd < 0) {
  1263. close(pipefd[1]);
  1264. exit(1);
  1265. }
  1266. if (ioctl(ub_fd, NS_GET_ID, &ub_id) < 0) {
  1267. close(ub_fd);
  1268. close(pipefd[1]);
  1269. exit(1);
  1270. }
  1271. close(ub_fd);
  1272. if (unshare(CLONE_NEWNET) < 0) {
  1273. close(pipefd[1]);
  1274. exit(1);
  1275. }
  1276. int net_fd = open("/proc/self/ns/net", O_RDONLY);
  1277. if (net_fd < 0) {
  1278. close(pipefd[1]);
  1279. exit(1);
  1280. }
  1281. if (ioctl(net_fd, NS_GET_ID, &net_id) < 0) {
  1282. close(net_fd);
  1283. close(pipefd[1]);
  1284. exit(1);
  1285. }
  1286. close(net_fd);
  1287. /* Send all three namespace IDs */
  1288. write(pipefd[1], &ua_id, sizeof(ua_id));
  1289. write(pipefd[1], &ub_id, sizeof(ub_id));
  1290. write(pipefd[1], &net_id, sizeof(net_id));
  1291. close(pipefd[1]);
  1292. exit(0);
  1293. }
  1294. close(pipefd[1]);
  1295. /* Read all three namespace IDs - fixed size, no parsing needed */
  1296. ret = read(pipefd[0], &ua_id, sizeof(ua_id));
  1297. if (ret != sizeof(ua_id)) {
  1298. close(pipefd[0]);
  1299. waitpid(pid, NULL, 0);
  1300. SKIP(return, "Failed to read user_A namespace ID");
  1301. }
  1302. ret = read(pipefd[0], &ub_id, sizeof(ub_id));
  1303. if (ret != sizeof(ub_id)) {
  1304. close(pipefd[0]);
  1305. waitpid(pid, NULL, 0);
  1306. SKIP(return, "Failed to read user_B namespace ID");
  1307. }
  1308. ret = read(pipefd[0], &net_id, sizeof(net_id));
  1309. close(pipefd[0]);
  1310. if (ret != sizeof(net_id)) {
  1311. waitpid(pid, NULL, 0);
  1312. SKIP(return, "Failed to read network namespace ID");
  1313. }
  1314. /* Construct file handles from namespace IDs */
  1315. ua_handle = (struct file_handle *)ua_buf;
  1316. ua_handle->handle_bytes = sizeof(struct nsfs_file_handle);
  1317. ua_handle->handle_type = FILEID_NSFS;
  1318. struct nsfs_file_handle *ua_fh = (struct nsfs_file_handle *)ua_handle->f_handle;
  1319. ua_fh->ns_id = ua_id;
  1320. ua_fh->ns_type = 0;
  1321. ua_fh->ns_inum = 0;
  1322. ub_handle = (struct file_handle *)ub_buf;
  1323. ub_handle->handle_bytes = sizeof(struct nsfs_file_handle);
  1324. ub_handle->handle_type = FILEID_NSFS;
  1325. struct nsfs_file_handle *ub_fh = (struct nsfs_file_handle *)ub_handle->f_handle;
  1326. ub_fh->ns_id = ub_id;
  1327. ub_fh->ns_type = 0;
  1328. ub_fh->ns_inum = 0;
  1329. net_handle = (struct file_handle *)net_buf;
  1330. net_handle->handle_bytes = sizeof(struct nsfs_file_handle);
  1331. net_handle->handle_type = FILEID_NSFS;
  1332. struct nsfs_file_handle *net_fh = (struct nsfs_file_handle *)net_handle->f_handle;
  1333. net_fh->ns_id = net_id;
  1334. net_fh->ns_type = 0;
  1335. net_fh->ns_inum = 0;
  1336. /* Open net_ns before child exits to keep it active */
  1337. int net_fd = open_by_handle_at(FD_NSFS_ROOT, net_handle, O_RDONLY);
  1338. if (net_fd < 0) {
  1339. waitpid(pid, NULL, 0);
  1340. SKIP(return, "Failed to open network namespace");
  1341. }
  1342. waitpid(pid, &status, 0);
  1343. ASSERT_TRUE(WIFEXITED(status));
  1344. ASSERT_EQ(WEXITSTATUS(status), 0);
  1345. /* With net_ns active, both user_A and user_B should be active */
  1346. TH_LOG("Testing user_B active (net_ns active causes propagation)");
  1347. int ub_fd = open_by_handle_at(FD_NSFS_ROOT, ub_handle, O_RDONLY);
  1348. ASSERT_GE(ub_fd, 0);
  1349. TH_LOG("Testing user_A active (propagated through user_B)");
  1350. int ua_fd = open_by_handle_at(FD_NSFS_ROOT, ua_handle, O_RDONLY);
  1351. ASSERT_GE(ua_fd, 0);
  1352. /* Close net_ns - user_B should stay active (we hold direct ref) */
  1353. TH_LOG("Closing net_ns, user_B should remain active (direct ref held)");
  1354. close(net_fd);
  1355. int ub_fd2 = open_by_handle_at(FD_NSFS_ROOT, ub_handle, O_RDONLY);
  1356. ASSERT_GE(ub_fd2, 0);
  1357. close(ub_fd2);
  1358. /* Close user_B - user_A should stay active (we hold direct ref) */
  1359. TH_LOG("Closing user_B, user_A should remain active (direct ref held)");
  1360. close(ub_fd);
  1361. int ua_fd2 = open_by_handle_at(FD_NSFS_ROOT, ua_handle, O_RDONLY);
  1362. ASSERT_GE(ua_fd2, 0);
  1363. close(ua_fd2);
  1364. /* Close user_A - everything should become inactive */
  1365. TH_LOG("Closing user_A, all should become inactive");
  1366. close(ua_fd);
  1367. /* All should now be inactive */
  1368. ua_fd = open_by_handle_at(FD_NSFS_ROOT, ua_handle, O_RDONLY);
  1369. ASSERT_LT(ua_fd, 0);
  1370. }
  1371. /*
  1372. * Test that parent stays active as long as ANY child is active.
  1373. * Create parent user namespace with two child net namespaces.
  1374. * Parent should remain active until BOTH children are inactive.
  1375. */
  1376. TEST(ns_parent_multiple_children_refcount)
  1377. {
  1378. struct file_handle *parent_handle, *net1_handle, *net2_handle;
  1379. int ret, pipefd[2], syncpipe[2];
  1380. pid_t pid;
  1381. int status;
  1382. __u64 p_id, n1_id, n2_id;
  1383. char p_buf[sizeof(*parent_handle) + MAX_HANDLE_SZ];
  1384. char n1_buf[sizeof(*net1_handle) + MAX_HANDLE_SZ];
  1385. char n2_buf[sizeof(*net2_handle) + MAX_HANDLE_SZ];
  1386. char sync_byte;
  1387. ASSERT_EQ(pipe(pipefd), 0);
  1388. ASSERT_EQ(pipe(syncpipe), 0);
  1389. pid = fork();
  1390. ASSERT_GE(pid, 0);
  1391. if (pid == 0) {
  1392. close(pipefd[0]);
  1393. close(syncpipe[1]);
  1394. /* Create parent user namespace */
  1395. if (setup_userns() < 0) {
  1396. close(pipefd[1]);
  1397. exit(1);
  1398. }
  1399. int p_fd = open("/proc/self/ns/user", O_RDONLY);
  1400. if (p_fd < 0) {
  1401. close(pipefd[1]);
  1402. exit(1);
  1403. }
  1404. if (ioctl(p_fd, NS_GET_ID, &p_id) < 0) {
  1405. close(p_fd);
  1406. close(pipefd[1]);
  1407. exit(1);
  1408. }
  1409. close(p_fd);
  1410. /* Create first network namespace */
  1411. if (unshare(CLONE_NEWNET) < 0) {
  1412. close(pipefd[1]);
  1413. close(syncpipe[0]);
  1414. exit(1);
  1415. }
  1416. int n1_fd = open("/proc/self/ns/net", O_RDONLY);
  1417. if (n1_fd < 0) {
  1418. close(pipefd[1]);
  1419. close(syncpipe[0]);
  1420. exit(1);
  1421. }
  1422. if (ioctl(n1_fd, NS_GET_ID, &n1_id) < 0) {
  1423. close(n1_fd);
  1424. close(pipefd[1]);
  1425. close(syncpipe[0]);
  1426. exit(1);
  1427. }
  1428. /* Keep n1_fd open so first namespace stays active */
  1429. /* Create second network namespace */
  1430. if (unshare(CLONE_NEWNET) < 0) {
  1431. close(n1_fd);
  1432. close(pipefd[1]);
  1433. close(syncpipe[0]);
  1434. exit(1);
  1435. }
  1436. int n2_fd = open("/proc/self/ns/net", O_RDONLY);
  1437. if (n2_fd < 0) {
  1438. close(n1_fd);
  1439. close(pipefd[1]);
  1440. close(syncpipe[0]);
  1441. exit(1);
  1442. }
  1443. if (ioctl(n2_fd, NS_GET_ID, &n2_id) < 0) {
  1444. close(n1_fd);
  1445. close(n2_fd);
  1446. close(pipefd[1]);
  1447. close(syncpipe[0]);
  1448. exit(1);
  1449. }
  1450. /* Keep both n1_fd and n2_fd open */
  1451. /* Send all namespace IDs */
  1452. write(pipefd[1], &p_id, sizeof(p_id));
  1453. write(pipefd[1], &n1_id, sizeof(n1_id));
  1454. write(pipefd[1], &n2_id, sizeof(n2_id));
  1455. close(pipefd[1]);
  1456. /* Wait for parent to signal before exiting */
  1457. read(syncpipe[0], &sync_byte, 1);
  1458. close(syncpipe[0]);
  1459. exit(0);
  1460. }
  1461. close(pipefd[1]);
  1462. close(syncpipe[0]);
  1463. /* Read all three namespace IDs - fixed size, no parsing needed */
  1464. ret = read(pipefd[0], &p_id, sizeof(p_id));
  1465. if (ret != sizeof(p_id)) {
  1466. close(pipefd[0]);
  1467. waitpid(pid, NULL, 0);
  1468. SKIP(return, "Failed to read parent namespace ID");
  1469. }
  1470. ret = read(pipefd[0], &n1_id, sizeof(n1_id));
  1471. if (ret != sizeof(n1_id)) {
  1472. close(pipefd[0]);
  1473. waitpid(pid, NULL, 0);
  1474. SKIP(return, "Failed to read first network namespace ID");
  1475. }
  1476. ret = read(pipefd[0], &n2_id, sizeof(n2_id));
  1477. close(pipefd[0]);
  1478. if (ret != sizeof(n2_id)) {
  1479. waitpid(pid, NULL, 0);
  1480. SKIP(return, "Failed to read second network namespace ID");
  1481. }
  1482. /* Construct file handles from namespace IDs */
  1483. parent_handle = (struct file_handle *)p_buf;
  1484. parent_handle->handle_bytes = sizeof(struct nsfs_file_handle);
  1485. parent_handle->handle_type = FILEID_NSFS;
  1486. struct nsfs_file_handle *p_fh = (struct nsfs_file_handle *)parent_handle->f_handle;
  1487. p_fh->ns_id = p_id;
  1488. p_fh->ns_type = 0;
  1489. p_fh->ns_inum = 0;
  1490. net1_handle = (struct file_handle *)n1_buf;
  1491. net1_handle->handle_bytes = sizeof(struct nsfs_file_handle);
  1492. net1_handle->handle_type = FILEID_NSFS;
  1493. struct nsfs_file_handle *n1_fh = (struct nsfs_file_handle *)net1_handle->f_handle;
  1494. n1_fh->ns_id = n1_id;
  1495. n1_fh->ns_type = 0;
  1496. n1_fh->ns_inum = 0;
  1497. net2_handle = (struct file_handle *)n2_buf;
  1498. net2_handle->handle_bytes = sizeof(struct nsfs_file_handle);
  1499. net2_handle->handle_type = FILEID_NSFS;
  1500. struct nsfs_file_handle *n2_fh = (struct nsfs_file_handle *)net2_handle->f_handle;
  1501. n2_fh->ns_id = n2_id;
  1502. n2_fh->ns_type = 0;
  1503. n2_fh->ns_inum = 0;
  1504. /* Open both net namespaces while child is still alive */
  1505. int n1_fd = open_by_handle_at(FD_NSFS_ROOT, net1_handle, O_RDONLY);
  1506. int n2_fd = open_by_handle_at(FD_NSFS_ROOT, net2_handle, O_RDONLY);
  1507. if (n1_fd < 0 || n2_fd < 0) {
  1508. if (n1_fd >= 0) close(n1_fd);
  1509. if (n2_fd >= 0) close(n2_fd);
  1510. sync_byte = 'G';
  1511. write(syncpipe[1], &sync_byte, 1);
  1512. close(syncpipe[1]);
  1513. waitpid(pid, NULL, 0);
  1514. SKIP(return, "Failed to open net namespaces");
  1515. }
  1516. /* Signal child that we have opened the namespaces */
  1517. sync_byte = 'G';
  1518. write(syncpipe[1], &sync_byte, 1);
  1519. close(syncpipe[1]);
  1520. /* Wait for child to exit */
  1521. waitpid(pid, &status, 0);
  1522. ASSERT_TRUE(WIFEXITED(status));
  1523. ASSERT_EQ(WEXITSTATUS(status), 0);
  1524. /* Parent should be active (has 2 active children) */
  1525. TH_LOG("Both net namespaces active - parent should be active");
  1526. int p_fd = open_by_handle_at(FD_NSFS_ROOT, parent_handle, O_RDONLY);
  1527. ASSERT_GE(p_fd, 0);
  1528. close(p_fd);
  1529. /* Close first net namespace - parent should STILL be active */
  1530. TH_LOG("Closing first net ns - parent should still be active");
  1531. close(n1_fd);
  1532. p_fd = open_by_handle_at(FD_NSFS_ROOT, parent_handle, O_RDONLY);
  1533. ASSERT_GE(p_fd, 0);
  1534. close(p_fd);
  1535. /* Close second net namespace - parent should become inactive */
  1536. TH_LOG("Closing second net ns - parent should become inactive");
  1537. close(n2_fd);
  1538. p_fd = open_by_handle_at(FD_NSFS_ROOT, parent_handle, O_RDONLY);
  1539. ASSERT_LT(p_fd, 0);
  1540. }
  1541. /*
  1542. * Test that user namespace as a child also propagates correctly.
  1543. * Create user_A -> user_B, verify when user_B is active that user_A
  1544. * is also active. This is different from non-user namespace children.
  1545. */
  1546. TEST(ns_userns_child_propagation)
  1547. {
  1548. struct file_handle *ua_handle, *ub_handle;
  1549. int ret, pipefd[2];
  1550. pid_t pid;
  1551. int status;
  1552. __u64 ua_id, ub_id;
  1553. char ua_buf[sizeof(*ua_handle) + MAX_HANDLE_SZ];
  1554. char ub_buf[sizeof(*ub_handle) + MAX_HANDLE_SZ];
  1555. ASSERT_EQ(pipe(pipefd), 0);
  1556. pid = fork();
  1557. ASSERT_GE(pid, 0);
  1558. if (pid == 0) {
  1559. close(pipefd[0]);
  1560. /* Create user_A */
  1561. if (setup_userns() < 0) {
  1562. close(pipefd[1]);
  1563. exit(1);
  1564. }
  1565. int ua_fd = open("/proc/self/ns/user", O_RDONLY);
  1566. if (ua_fd < 0) {
  1567. close(pipefd[1]);
  1568. exit(1);
  1569. }
  1570. if (ioctl(ua_fd, NS_GET_ID, &ua_id) < 0) {
  1571. close(ua_fd);
  1572. close(pipefd[1]);
  1573. exit(1);
  1574. }
  1575. close(ua_fd);
  1576. /* Create user_B (child of user_A) */
  1577. if (setup_userns() < 0) {
  1578. close(pipefd[1]);
  1579. exit(1);
  1580. }
  1581. int ub_fd = open("/proc/self/ns/user", O_RDONLY);
  1582. if (ub_fd < 0) {
  1583. close(pipefd[1]);
  1584. exit(1);
  1585. }
  1586. if (ioctl(ub_fd, NS_GET_ID, &ub_id) < 0) {
  1587. close(ub_fd);
  1588. close(pipefd[1]);
  1589. exit(1);
  1590. }
  1591. close(ub_fd);
  1592. /* Send both namespace IDs */
  1593. write(pipefd[1], &ua_id, sizeof(ua_id));
  1594. write(pipefd[1], &ub_id, sizeof(ub_id));
  1595. close(pipefd[1]);
  1596. exit(0);
  1597. }
  1598. close(pipefd[1]);
  1599. /* Read both namespace IDs - fixed size, no parsing needed */
  1600. ret = read(pipefd[0], &ua_id, sizeof(ua_id));
  1601. if (ret != sizeof(ua_id)) {
  1602. close(pipefd[0]);
  1603. waitpid(pid, NULL, 0);
  1604. SKIP(return, "Failed to read user_A namespace ID");
  1605. }
  1606. ret = read(pipefd[0], &ub_id, sizeof(ub_id));
  1607. close(pipefd[0]);
  1608. if (ret != sizeof(ub_id)) {
  1609. waitpid(pid, NULL, 0);
  1610. SKIP(return, "Failed to read user_B namespace ID");
  1611. }
  1612. /* Construct file handles from namespace IDs */
  1613. ua_handle = (struct file_handle *)ua_buf;
  1614. ua_handle->handle_bytes = sizeof(struct nsfs_file_handle);
  1615. ua_handle->handle_type = FILEID_NSFS;
  1616. struct nsfs_file_handle *ua_fh = (struct nsfs_file_handle *)ua_handle->f_handle;
  1617. ua_fh->ns_id = ua_id;
  1618. ua_fh->ns_type = 0;
  1619. ua_fh->ns_inum = 0;
  1620. ub_handle = (struct file_handle *)ub_buf;
  1621. ub_handle->handle_bytes = sizeof(struct nsfs_file_handle);
  1622. ub_handle->handle_type = FILEID_NSFS;
  1623. struct nsfs_file_handle *ub_fh = (struct nsfs_file_handle *)ub_handle->f_handle;
  1624. ub_fh->ns_id = ub_id;
  1625. ub_fh->ns_type = 0;
  1626. ub_fh->ns_inum = 0;
  1627. /* Open user_B before child exits */
  1628. int ub_fd = open_by_handle_at(FD_NSFS_ROOT, ub_handle, O_RDONLY);
  1629. if (ub_fd < 0) {
  1630. waitpid(pid, NULL, 0);
  1631. SKIP(return, "Failed to open user_B");
  1632. }
  1633. waitpid(pid, &status, 0);
  1634. ASSERT_TRUE(WIFEXITED(status));
  1635. ASSERT_EQ(WEXITSTATUS(status), 0);
  1636. /* With user_B active, user_A should also be active */
  1637. TH_LOG("Testing user_A active when child user_B is active");
  1638. int ua_fd = open_by_handle_at(FD_NSFS_ROOT, ua_handle, O_RDONLY);
  1639. ASSERT_GE(ua_fd, 0);
  1640. /* Close user_B */
  1641. TH_LOG("Closing user_B");
  1642. close(ub_fd);
  1643. /* user_A should remain active (we hold direct ref) */
  1644. int ua_fd2 = open_by_handle_at(FD_NSFS_ROOT, ua_handle, O_RDONLY);
  1645. ASSERT_GE(ua_fd2, 0);
  1646. close(ua_fd2);
  1647. /* Close user_A - should become inactive */
  1648. TH_LOG("Closing user_A - should become inactive");
  1649. close(ua_fd);
  1650. ua_fd = open_by_handle_at(FD_NSFS_ROOT, ua_handle, O_RDONLY);
  1651. ASSERT_LT(ua_fd, 0);
  1652. }
  1653. /*
  1654. * Test different namespace types (net, uts, ipc) all contributing
  1655. * active references to the same owning user namespace.
  1656. */
  1657. TEST(ns_mixed_types_same_owner)
  1658. {
  1659. struct file_handle *user_handle, *net_handle, *uts_handle;
  1660. int ret, pipefd[2];
  1661. pid_t pid;
  1662. int status;
  1663. __u64 u_id, n_id, ut_id;
  1664. char u_buf[sizeof(*user_handle) + MAX_HANDLE_SZ];
  1665. char n_buf[sizeof(*net_handle) + MAX_HANDLE_SZ];
  1666. char ut_buf[sizeof(*uts_handle) + MAX_HANDLE_SZ];
  1667. ASSERT_EQ(pipe(pipefd), 0);
  1668. pid = fork();
  1669. ASSERT_GE(pid, 0);
  1670. if (pid == 0) {
  1671. close(pipefd[0]);
  1672. if (setup_userns() < 0) {
  1673. close(pipefd[1]);
  1674. exit(1);
  1675. }
  1676. int u_fd = open("/proc/self/ns/user", O_RDONLY);
  1677. if (u_fd < 0) {
  1678. close(pipefd[1]);
  1679. exit(1);
  1680. }
  1681. if (ioctl(u_fd, NS_GET_ID, &u_id) < 0) {
  1682. close(u_fd);
  1683. close(pipefd[1]);
  1684. exit(1);
  1685. }
  1686. close(u_fd);
  1687. if (unshare(CLONE_NEWNET) < 0) {
  1688. close(pipefd[1]);
  1689. exit(1);
  1690. }
  1691. int n_fd = open("/proc/self/ns/net", O_RDONLY);
  1692. if (n_fd < 0) {
  1693. close(pipefd[1]);
  1694. exit(1);
  1695. }
  1696. if (ioctl(n_fd, NS_GET_ID, &n_id) < 0) {
  1697. close(n_fd);
  1698. close(pipefd[1]);
  1699. exit(1);
  1700. }
  1701. close(n_fd);
  1702. if (unshare(CLONE_NEWUTS) < 0) {
  1703. close(pipefd[1]);
  1704. exit(1);
  1705. }
  1706. int ut_fd = open("/proc/self/ns/uts", O_RDONLY);
  1707. if (ut_fd < 0) {
  1708. close(pipefd[1]);
  1709. exit(1);
  1710. }
  1711. if (ioctl(ut_fd, NS_GET_ID, &ut_id) < 0) {
  1712. close(ut_fd);
  1713. close(pipefd[1]);
  1714. exit(1);
  1715. }
  1716. close(ut_fd);
  1717. /* Send all namespace IDs */
  1718. write(pipefd[1], &u_id, sizeof(u_id));
  1719. write(pipefd[1], &n_id, sizeof(n_id));
  1720. write(pipefd[1], &ut_id, sizeof(ut_id));
  1721. close(pipefd[1]);
  1722. exit(0);
  1723. }
  1724. close(pipefd[1]);
  1725. /* Read all three namespace IDs - fixed size, no parsing needed */
  1726. ret = read(pipefd[0], &u_id, sizeof(u_id));
  1727. if (ret != sizeof(u_id)) {
  1728. close(pipefd[0]);
  1729. waitpid(pid, NULL, 0);
  1730. SKIP(return, "Failed to read user namespace ID");
  1731. }
  1732. ret = read(pipefd[0], &n_id, sizeof(n_id));
  1733. if (ret != sizeof(n_id)) {
  1734. close(pipefd[0]);
  1735. waitpid(pid, NULL, 0);
  1736. SKIP(return, "Failed to read network namespace ID");
  1737. }
  1738. ret = read(pipefd[0], &ut_id, sizeof(ut_id));
  1739. close(pipefd[0]);
  1740. if (ret != sizeof(ut_id)) {
  1741. waitpid(pid, NULL, 0);
  1742. SKIP(return, "Failed to read UTS namespace ID");
  1743. }
  1744. /* Construct file handles from namespace IDs */
  1745. user_handle = (struct file_handle *)u_buf;
  1746. user_handle->handle_bytes = sizeof(struct nsfs_file_handle);
  1747. user_handle->handle_type = FILEID_NSFS;
  1748. struct nsfs_file_handle *u_fh = (struct nsfs_file_handle *)user_handle->f_handle;
  1749. u_fh->ns_id = u_id;
  1750. u_fh->ns_type = 0;
  1751. u_fh->ns_inum = 0;
  1752. net_handle = (struct file_handle *)n_buf;
  1753. net_handle->handle_bytes = sizeof(struct nsfs_file_handle);
  1754. net_handle->handle_type = FILEID_NSFS;
  1755. struct nsfs_file_handle *n_fh = (struct nsfs_file_handle *)net_handle->f_handle;
  1756. n_fh->ns_id = n_id;
  1757. n_fh->ns_type = 0;
  1758. n_fh->ns_inum = 0;
  1759. uts_handle = (struct file_handle *)ut_buf;
  1760. uts_handle->handle_bytes = sizeof(struct nsfs_file_handle);
  1761. uts_handle->handle_type = FILEID_NSFS;
  1762. struct nsfs_file_handle *ut_fh = (struct nsfs_file_handle *)uts_handle->f_handle;
  1763. ut_fh->ns_id = ut_id;
  1764. ut_fh->ns_type = 0;
  1765. ut_fh->ns_inum = 0;
  1766. /* Open both non-user namespaces */
  1767. int n_fd = open_by_handle_at(FD_NSFS_ROOT, net_handle, O_RDONLY);
  1768. int ut_fd = open_by_handle_at(FD_NSFS_ROOT, uts_handle, O_RDONLY);
  1769. if (n_fd < 0 || ut_fd < 0) {
  1770. if (n_fd >= 0) close(n_fd);
  1771. if (ut_fd >= 0) close(ut_fd);
  1772. waitpid(pid, NULL, 0);
  1773. SKIP(return, "Failed to open namespaces");
  1774. }
  1775. waitpid(pid, &status, 0);
  1776. ASSERT_TRUE(WIFEXITED(status));
  1777. ASSERT_EQ(WEXITSTATUS(status), 0);
  1778. /* User namespace should be active (2 active children) */
  1779. TH_LOG("Both net and uts active - user ns should be active");
  1780. int u_fd = open_by_handle_at(FD_NSFS_ROOT, user_handle, O_RDONLY);
  1781. ASSERT_GE(u_fd, 0);
  1782. close(u_fd);
  1783. /* Close net - user ns should STILL be active (uts still active) */
  1784. TH_LOG("Closing net - user ns should still be active");
  1785. close(n_fd);
  1786. u_fd = open_by_handle_at(FD_NSFS_ROOT, user_handle, O_RDONLY);
  1787. ASSERT_GE(u_fd, 0);
  1788. close(u_fd);
  1789. /* Close uts - user ns should become inactive */
  1790. TH_LOG("Closing uts - user ns should become inactive");
  1791. close(ut_fd);
  1792. u_fd = open_by_handle_at(FD_NSFS_ROOT, user_handle, O_RDONLY);
  1793. ASSERT_LT(u_fd, 0);
  1794. }
  1795. /* Thread test helpers and structures */
  1796. struct thread_ns_info {
  1797. __u64 ns_id;
  1798. int pipefd;
  1799. int syncfd_read;
  1800. int syncfd_write;
  1801. int exit_code;
  1802. };
  1803. static void *thread_create_namespace(void *arg)
  1804. {
  1805. struct thread_ns_info *info = (struct thread_ns_info *)arg;
  1806. int ret;
  1807. /* Create new network namespace */
  1808. ret = unshare(CLONE_NEWNET);
  1809. if (ret < 0) {
  1810. info->exit_code = 1;
  1811. return NULL;
  1812. }
  1813. /* Get namespace ID */
  1814. int fd = open("/proc/thread-self/ns/net", O_RDONLY);
  1815. if (fd < 0) {
  1816. info->exit_code = 2;
  1817. return NULL;
  1818. }
  1819. ret = ioctl(fd, NS_GET_ID, &info->ns_id);
  1820. close(fd);
  1821. if (ret < 0) {
  1822. info->exit_code = 3;
  1823. return NULL;
  1824. }
  1825. /* Send namespace ID to main thread */
  1826. if (write(info->pipefd, &info->ns_id, sizeof(info->ns_id)) != sizeof(info->ns_id)) {
  1827. info->exit_code = 4;
  1828. return NULL;
  1829. }
  1830. /* Wait for signal to exit */
  1831. char sync_byte;
  1832. if (read(info->syncfd_read, &sync_byte, 1) != 1) {
  1833. info->exit_code = 5;
  1834. return NULL;
  1835. }
  1836. info->exit_code = 0;
  1837. return NULL;
  1838. }
  1839. /*
  1840. * Test that namespace becomes inactive after thread exits.
  1841. * This verifies active reference counting works with threads, not just processes.
  1842. */
  1843. TEST(thread_ns_inactive_after_exit)
  1844. {
  1845. pthread_t thread;
  1846. struct thread_ns_info info;
  1847. struct file_handle *handle;
  1848. int pipefd[2];
  1849. int syncpipe[2];
  1850. int ret;
  1851. char sync_byte;
  1852. char buf[sizeof(*handle) + MAX_HANDLE_SZ];
  1853. ASSERT_EQ(pipe(pipefd), 0);
  1854. ASSERT_EQ(pipe(syncpipe), 0);
  1855. info.pipefd = pipefd[1];
  1856. info.syncfd_read = syncpipe[0];
  1857. info.syncfd_write = -1;
  1858. info.exit_code = -1;
  1859. /* Create thread that will create a namespace */
  1860. ret = pthread_create(&thread, NULL, thread_create_namespace, &info);
  1861. ASSERT_EQ(ret, 0);
  1862. /* Read namespace ID from thread */
  1863. __u64 ns_id;
  1864. ret = read(pipefd[0], &ns_id, sizeof(ns_id));
  1865. if (ret != sizeof(ns_id)) {
  1866. sync_byte = 'X';
  1867. write(syncpipe[1], &sync_byte, 1);
  1868. pthread_join(thread, NULL);
  1869. close(pipefd[0]);
  1870. close(pipefd[1]);
  1871. close(syncpipe[0]);
  1872. close(syncpipe[1]);
  1873. SKIP(return, "Failed to read namespace ID from thread");
  1874. }
  1875. TH_LOG("Thread created namespace with ID %llu", (unsigned long long)ns_id);
  1876. /* Construct file handle */
  1877. handle = (struct file_handle *)buf;
  1878. handle->handle_bytes = sizeof(struct nsfs_file_handle);
  1879. handle->handle_type = FILEID_NSFS;
  1880. struct nsfs_file_handle *fh = (struct nsfs_file_handle *)handle->f_handle;
  1881. fh->ns_id = ns_id;
  1882. fh->ns_type = 0;
  1883. fh->ns_inum = 0;
  1884. /* Namespace should be active while thread is alive */
  1885. TH_LOG("Attempting to open namespace while thread is alive (should succeed)");
  1886. int nsfd = open_by_handle_at(FD_NSFS_ROOT, handle, O_RDONLY);
  1887. ASSERT_GE(nsfd, 0);
  1888. close(nsfd);
  1889. /* Signal thread to exit */
  1890. TH_LOG("Signaling thread to exit");
  1891. sync_byte = 'X';
  1892. ASSERT_EQ(write(syncpipe[1], &sync_byte, 1), 1);
  1893. close(syncpipe[1]);
  1894. /* Wait for thread to exit */
  1895. ASSERT_EQ(pthread_join(thread, NULL), 0);
  1896. close(pipefd[0]);
  1897. close(pipefd[1]);
  1898. close(syncpipe[0]);
  1899. if (info.exit_code != 0)
  1900. SKIP(return, "Thread failed to create namespace");
  1901. TH_LOG("Thread exited, namespace should be inactive");
  1902. /* Namespace should now be inactive */
  1903. nsfd = open_by_handle_at(FD_NSFS_ROOT, handle, O_RDONLY);
  1904. ASSERT_LT(nsfd, 0);
  1905. /* Should fail with ENOENT (inactive) or ESTALE (gone) */
  1906. TH_LOG("Namespace inactive as expected: %s (errno=%d)", strerror(errno), errno);
  1907. ASSERT_TRUE(errno == ENOENT || errno == ESTALE);
  1908. }
  1909. /*
  1910. * Test that a namespace remains active while a thread holds an fd to it.
  1911. * Even after the thread exits, the namespace should remain active as long as
  1912. * another thread holds a file descriptor to it.
  1913. */
  1914. TEST(thread_ns_fd_keeps_active)
  1915. {
  1916. pthread_t thread;
  1917. struct thread_ns_info info;
  1918. struct file_handle *handle;
  1919. int pipefd[2];
  1920. int syncpipe[2];
  1921. int ret;
  1922. char sync_byte;
  1923. char buf[sizeof(*handle) + MAX_HANDLE_SZ];
  1924. ASSERT_EQ(pipe(pipefd), 0);
  1925. ASSERT_EQ(pipe(syncpipe), 0);
  1926. info.pipefd = pipefd[1];
  1927. info.syncfd_read = syncpipe[0];
  1928. info.syncfd_write = -1;
  1929. info.exit_code = -1;
  1930. /* Create thread that will create a namespace */
  1931. ret = pthread_create(&thread, NULL, thread_create_namespace, &info);
  1932. ASSERT_EQ(ret, 0);
  1933. /* Read namespace ID from thread */
  1934. __u64 ns_id;
  1935. ret = read(pipefd[0], &ns_id, sizeof(ns_id));
  1936. if (ret != sizeof(ns_id)) {
  1937. sync_byte = 'X';
  1938. write(syncpipe[1], &sync_byte, 1);
  1939. pthread_join(thread, NULL);
  1940. close(pipefd[0]);
  1941. close(pipefd[1]);
  1942. close(syncpipe[0]);
  1943. close(syncpipe[1]);
  1944. SKIP(return, "Failed to read namespace ID from thread");
  1945. }
  1946. TH_LOG("Thread created namespace with ID %llu", (unsigned long long)ns_id);
  1947. /* Construct file handle */
  1948. handle = (struct file_handle *)buf;
  1949. handle->handle_bytes = sizeof(struct nsfs_file_handle);
  1950. handle->handle_type = FILEID_NSFS;
  1951. struct nsfs_file_handle *fh = (struct nsfs_file_handle *)handle->f_handle;
  1952. fh->ns_id = ns_id;
  1953. fh->ns_type = 0;
  1954. fh->ns_inum = 0;
  1955. /* Open namespace while thread is alive */
  1956. TH_LOG("Opening namespace while thread is alive");
  1957. int nsfd = open_by_handle_at(FD_NSFS_ROOT, handle, O_RDONLY);
  1958. ASSERT_GE(nsfd, 0);
  1959. /* Signal thread to exit */
  1960. TH_LOG("Signaling thread to exit");
  1961. sync_byte = 'X';
  1962. write(syncpipe[1], &sync_byte, 1);
  1963. close(syncpipe[1]);
  1964. /* Wait for thread to exit */
  1965. pthread_join(thread, NULL);
  1966. close(pipefd[0]);
  1967. close(pipefd[1]);
  1968. close(syncpipe[0]);
  1969. if (info.exit_code != 0) {
  1970. close(nsfd);
  1971. SKIP(return, "Thread failed to create namespace");
  1972. }
  1973. TH_LOG("Thread exited, but main thread holds fd - namespace should remain active");
  1974. /* Namespace should still be active because we hold an fd */
  1975. int nsfd2 = open_by_handle_at(FD_NSFS_ROOT, handle, O_RDONLY);
  1976. ASSERT_GE(nsfd2, 0);
  1977. /* Verify it's the same namespace */
  1978. struct stat st1, st2;
  1979. ASSERT_EQ(fstat(nsfd, &st1), 0);
  1980. ASSERT_EQ(fstat(nsfd2, &st2), 0);
  1981. ASSERT_EQ(st1.st_ino, st2.st_ino);
  1982. close(nsfd2);
  1983. TH_LOG("Closing fd - namespace should become inactive");
  1984. close(nsfd);
  1985. /* Now namespace should be inactive */
  1986. nsfd = open_by_handle_at(FD_NSFS_ROOT, handle, O_RDONLY);
  1987. ASSERT_LT(nsfd, 0);
  1988. /* Should fail with ENOENT (inactive) or ESTALE (gone) */
  1989. TH_LOG("Namespace inactive as expected: %s (errno=%d)", strerror(errno), errno);
  1990. ASSERT_TRUE(errno == ENOENT || errno == ESTALE);
  1991. }
  1992. /* Structure for thread data in subprocess */
  1993. struct thread_sleep_data {
  1994. int syncfd_read;
  1995. };
  1996. static void *thread_sleep_and_wait(void *arg)
  1997. {
  1998. struct thread_sleep_data *data = (struct thread_sleep_data *)arg;
  1999. char sync_byte;
  2000. /* Wait for signal to exit - read will unblock when pipe is closed */
  2001. (void)read(data->syncfd_read, &sync_byte, 1);
  2002. return NULL;
  2003. }
  2004. /*
  2005. * Test that namespaces become inactive after subprocess with multiple threads exits.
  2006. * Create a subprocess that unshares user and network namespaces, then creates two
  2007. * threads that share those namespaces. Verify that after all threads and subprocess
  2008. * exit, the namespaces are no longer listed by listns() and cannot be opened by
  2009. * open_by_handle_at().
  2010. */
  2011. TEST(thread_subprocess_ns_inactive_after_all_exit)
  2012. {
  2013. int pipefd[2];
  2014. int sv[2];
  2015. pid_t pid;
  2016. int status;
  2017. __u64 user_id, net_id;
  2018. struct file_handle *user_handle, *net_handle;
  2019. char user_buf[sizeof(*user_handle) + MAX_HANDLE_SZ];
  2020. char net_buf[sizeof(*net_handle) + MAX_HANDLE_SZ];
  2021. char sync_byte;
  2022. int ret;
  2023. ASSERT_EQ(pipe(pipefd), 0);
  2024. ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, sv), 0);
  2025. pid = fork();
  2026. ASSERT_GE(pid, 0);
  2027. if (pid == 0) {
  2028. /* Child process */
  2029. close(pipefd[0]);
  2030. close(sv[0]);
  2031. /* Create user namespace with mappings */
  2032. if (setup_userns() < 0) {
  2033. fprintf(stderr, "Child: setup_userns() failed: %s\n", strerror(errno));
  2034. close(pipefd[1]);
  2035. close(sv[1]);
  2036. exit(1);
  2037. }
  2038. fprintf(stderr, "Child: setup_userns() succeeded\n");
  2039. /* Get user namespace ID */
  2040. int user_fd = open("/proc/self/ns/user", O_RDONLY);
  2041. if (user_fd < 0) {
  2042. fprintf(stderr, "Child: open(/proc/self/ns/user) failed: %s\n", strerror(errno));
  2043. close(pipefd[1]);
  2044. close(sv[1]);
  2045. exit(1);
  2046. }
  2047. if (ioctl(user_fd, NS_GET_ID, &user_id) < 0) {
  2048. fprintf(stderr, "Child: ioctl(NS_GET_ID) for user ns failed: %s\n", strerror(errno));
  2049. close(user_fd);
  2050. close(pipefd[1]);
  2051. close(sv[1]);
  2052. exit(1);
  2053. }
  2054. close(user_fd);
  2055. fprintf(stderr, "Child: user ns ID = %llu\n", (unsigned long long)user_id);
  2056. /* Unshare network namespace */
  2057. if (unshare(CLONE_NEWNET) < 0) {
  2058. fprintf(stderr, "Child: unshare(CLONE_NEWNET) failed: %s\n", strerror(errno));
  2059. close(pipefd[1]);
  2060. close(sv[1]);
  2061. exit(1);
  2062. }
  2063. fprintf(stderr, "Child: unshare(CLONE_NEWNET) succeeded\n");
  2064. /* Get network namespace ID */
  2065. int net_fd = open("/proc/self/ns/net", O_RDONLY);
  2066. if (net_fd < 0) {
  2067. fprintf(stderr, "Child: open(/proc/self/ns/net) failed: %s\n", strerror(errno));
  2068. close(pipefd[1]);
  2069. close(sv[1]);
  2070. exit(1);
  2071. }
  2072. if (ioctl(net_fd, NS_GET_ID, &net_id) < 0) {
  2073. fprintf(stderr, "Child: ioctl(NS_GET_ID) for net ns failed: %s\n", strerror(errno));
  2074. close(net_fd);
  2075. close(pipefd[1]);
  2076. close(sv[1]);
  2077. exit(1);
  2078. }
  2079. close(net_fd);
  2080. fprintf(stderr, "Child: net ns ID = %llu\n", (unsigned long long)net_id);
  2081. /* Send namespace IDs to parent */
  2082. if (write(pipefd[1], &user_id, sizeof(user_id)) != sizeof(user_id)) {
  2083. fprintf(stderr, "Child: write(user_id) failed: %s\n", strerror(errno));
  2084. exit(1);
  2085. }
  2086. if (write(pipefd[1], &net_id, sizeof(net_id)) != sizeof(net_id)) {
  2087. fprintf(stderr, "Child: write(net_id) failed: %s\n", strerror(errno));
  2088. exit(1);
  2089. }
  2090. close(pipefd[1]);
  2091. fprintf(stderr, "Child: sent namespace IDs to parent\n");
  2092. /* Create two threads that share the namespaces */
  2093. pthread_t thread1, thread2;
  2094. struct thread_sleep_data data;
  2095. data.syncfd_read = sv[1];
  2096. int ret_thread = pthread_create(&thread1, NULL, thread_sleep_and_wait, &data);
  2097. if (ret_thread != 0) {
  2098. fprintf(stderr, "Child: pthread_create(thread1) failed: %s\n", strerror(ret_thread));
  2099. close(sv[1]);
  2100. exit(1);
  2101. }
  2102. fprintf(stderr, "Child: created thread1\n");
  2103. ret_thread = pthread_create(&thread2, NULL, thread_sleep_and_wait, &data);
  2104. if (ret_thread != 0) {
  2105. fprintf(stderr, "Child: pthread_create(thread2) failed: %s\n", strerror(ret_thread));
  2106. close(sv[1]);
  2107. pthread_cancel(thread1);
  2108. exit(1);
  2109. }
  2110. fprintf(stderr, "Child: created thread2\n");
  2111. /* Wait for threads to complete - they will unblock when parent writes */
  2112. fprintf(stderr, "Child: waiting for threads to exit\n");
  2113. pthread_join(thread1, NULL);
  2114. fprintf(stderr, "Child: thread1 exited\n");
  2115. pthread_join(thread2, NULL);
  2116. fprintf(stderr, "Child: thread2 exited\n");
  2117. close(sv[1]);
  2118. /* Exit - namespaces should become inactive */
  2119. fprintf(stderr, "Child: all threads joined, exiting with success\n");
  2120. exit(0);
  2121. }
  2122. /* Parent process */
  2123. close(pipefd[1]);
  2124. close(sv[1]);
  2125. TH_LOG("Parent: waiting to read namespace IDs from child");
  2126. /* Read namespace IDs from child */
  2127. ret = read(pipefd[0], &user_id, sizeof(user_id));
  2128. if (ret != sizeof(user_id)) {
  2129. TH_LOG("Parent: failed to read user_id, ret=%d, errno=%s", ret, strerror(errno));
  2130. close(pipefd[0]);
  2131. sync_byte = 'X';
  2132. (void)write(sv[0], &sync_byte, 1);
  2133. close(sv[0]);
  2134. waitpid(pid, NULL, 0);
  2135. SKIP(return, "Failed to read user namespace ID from child");
  2136. }
  2137. ret = read(pipefd[0], &net_id, sizeof(net_id));
  2138. close(pipefd[0]);
  2139. if (ret != sizeof(net_id)) {
  2140. TH_LOG("Parent: failed to read net_id, ret=%d, errno=%s", ret, strerror(errno));
  2141. sync_byte = 'X';
  2142. (void)write(sv[0], &sync_byte, 1);
  2143. close(sv[0]);
  2144. waitpid(pid, NULL, 0);
  2145. SKIP(return, "Failed to read network namespace ID from child");
  2146. }
  2147. TH_LOG("Child created user ns %llu and net ns %llu with 2 threads",
  2148. (unsigned long long)user_id, (unsigned long long)net_id);
  2149. /* Construct file handles */
  2150. user_handle = (struct file_handle *)user_buf;
  2151. user_handle->handle_bytes = sizeof(struct nsfs_file_handle);
  2152. user_handle->handle_type = FILEID_NSFS;
  2153. struct nsfs_file_handle *user_fh = (struct nsfs_file_handle *)user_handle->f_handle;
  2154. user_fh->ns_id = user_id;
  2155. user_fh->ns_type = 0;
  2156. user_fh->ns_inum = 0;
  2157. net_handle = (struct file_handle *)net_buf;
  2158. net_handle->handle_bytes = sizeof(struct nsfs_file_handle);
  2159. net_handle->handle_type = FILEID_NSFS;
  2160. struct nsfs_file_handle *net_fh = (struct nsfs_file_handle *)net_handle->f_handle;
  2161. net_fh->ns_id = net_id;
  2162. net_fh->ns_type = 0;
  2163. net_fh->ns_inum = 0;
  2164. /* Verify namespaces are active while subprocess and threads are alive */
  2165. TH_LOG("Verifying namespaces are active while subprocess with threads is running");
  2166. int user_fd = open_by_handle_at(FD_NSFS_ROOT, user_handle, O_RDONLY);
  2167. ASSERT_GE(user_fd, 0);
  2168. int net_fd = open_by_handle_at(FD_NSFS_ROOT, net_handle, O_RDONLY);
  2169. ASSERT_GE(net_fd, 0);
  2170. close(user_fd);
  2171. close(net_fd);
  2172. /* Also verify they appear in listns() */
  2173. TH_LOG("Verifying namespaces appear in listns() while active");
  2174. struct ns_id_req req = {
  2175. .size = sizeof(struct ns_id_req),
  2176. .spare = 0,
  2177. .ns_id = 0,
  2178. .ns_type = CLONE_NEWUSER,
  2179. .spare2 = 0,
  2180. .user_ns_id = 0,
  2181. };
  2182. __u64 ns_ids[256];
  2183. int nr_ids = sys_listns(&req, ns_ids, 256, 0);
  2184. if (nr_ids < 0) {
  2185. TH_LOG("listns() not available, skipping listns verification");
  2186. } else {
  2187. /* Check if user_id is in the list */
  2188. int found_user = 0;
  2189. for (int i = 0; i < nr_ids; i++) {
  2190. if (ns_ids[i] == user_id) {
  2191. found_user = 1;
  2192. break;
  2193. }
  2194. }
  2195. ASSERT_TRUE(found_user);
  2196. TH_LOG("User namespace found in listns() as expected");
  2197. /* Check network namespace */
  2198. req.ns_type = CLONE_NEWNET;
  2199. nr_ids = sys_listns(&req, ns_ids, 256, 0);
  2200. if (nr_ids >= 0) {
  2201. int found_net = 0;
  2202. for (int i = 0; i < nr_ids; i++) {
  2203. if (ns_ids[i] == net_id) {
  2204. found_net = 1;
  2205. break;
  2206. }
  2207. }
  2208. ASSERT_TRUE(found_net);
  2209. TH_LOG("Network namespace found in listns() as expected");
  2210. }
  2211. }
  2212. /* Signal threads to exit */
  2213. TH_LOG("Signaling threads to exit");
  2214. sync_byte = 'X';
  2215. /* Write two bytes - one for each thread */
  2216. ASSERT_EQ(write(sv[0], &sync_byte, 1), 1);
  2217. ASSERT_EQ(write(sv[0], &sync_byte, 1), 1);
  2218. close(sv[0]);
  2219. /* Wait for child process to exit */
  2220. waitpid(pid, &status, 0);
  2221. ASSERT_TRUE(WIFEXITED(status));
  2222. if (WEXITSTATUS(status) != 0) {
  2223. TH_LOG("Child process failed with exit code %d", WEXITSTATUS(status));
  2224. SKIP(return, "Child process failed");
  2225. }
  2226. TH_LOG("Subprocess and all threads have exited successfully");
  2227. /* Verify namespaces are now inactive - open_by_handle_at should fail */
  2228. TH_LOG("Verifying namespaces are inactive after subprocess and threads exit");
  2229. user_fd = open_by_handle_at(FD_NSFS_ROOT, user_handle, O_RDONLY);
  2230. ASSERT_LT(user_fd, 0);
  2231. TH_LOG("User namespace inactive as expected: %s (errno=%d)",
  2232. strerror(errno), errno);
  2233. ASSERT_TRUE(errno == ENOENT || errno == ESTALE);
  2234. net_fd = open_by_handle_at(FD_NSFS_ROOT, net_handle, O_RDONLY);
  2235. ASSERT_LT(net_fd, 0);
  2236. TH_LOG("Network namespace inactive as expected: %s (errno=%d)",
  2237. strerror(errno), errno);
  2238. ASSERT_TRUE(errno == ENOENT || errno == ESTALE);
  2239. /* Verify namespaces do NOT appear in listns() */
  2240. TH_LOG("Verifying namespaces do NOT appear in listns() when inactive");
  2241. memset(&req, 0, sizeof(req));
  2242. req.size = sizeof(struct ns_id_req);
  2243. req.ns_type = CLONE_NEWUSER;
  2244. nr_ids = sys_listns(&req, ns_ids, 256, 0);
  2245. if (nr_ids >= 0) {
  2246. int found_user = 0;
  2247. for (int i = 0; i < nr_ids; i++) {
  2248. if (ns_ids[i] == user_id) {
  2249. found_user = 1;
  2250. break;
  2251. }
  2252. }
  2253. ASSERT_FALSE(found_user);
  2254. TH_LOG("User namespace correctly not listed in listns()");
  2255. /* Check network namespace */
  2256. req.ns_type = CLONE_NEWNET;
  2257. nr_ids = sys_listns(&req, ns_ids, 256, 0);
  2258. if (nr_ids >= 0) {
  2259. int found_net = 0;
  2260. for (int i = 0; i < nr_ids; i++) {
  2261. if (ns_ids[i] == net_id) {
  2262. found_net = 1;
  2263. break;
  2264. }
  2265. }
  2266. ASSERT_FALSE(found_net);
  2267. TH_LOG("Network namespace correctly not listed in listns()");
  2268. }
  2269. }
  2270. }
  2271. TEST_HARNESS_MAIN