1 // SPDX-License-Identifier: GPL-2.0 2 #define _GNU_SOURCE 3 #include <errno.h> 4 #include <sched.h> 5 #include <stdio.h> 6 #include <stdlib.h> 7 #include <sys/socket.h> 8 #include <sys/wait.h> 9 #include <unistd.h> 10 #include "../kselftest_harness.h" 11 #include "../filesystems/utils.h" 12 #include "wrappers.h" 13 14 /* 15 * Minimal test case to reproduce KASAN out-of-bounds in listns pagination. 16 * 17 * The bug occurs when: 18 * 1. Filtering by a specific namespace type (e.g., CLONE_NEWUSER) 19 * 2. Using pagination (req.ns_id != 0) 20 * 3. The lookup_ns_id_at() call in do_listns() passes ns_type=0 instead of 21 * the filtered type, causing it to search the unified tree and potentially 22 * return a namespace of the wrong type. 23 */ 24 TEST(pagination_with_type_filter) 25 { 26 struct ns_id_req req = { 27 .size = sizeof(req), 28 .spare = 0, 29 .ns_id = 0, 30 .ns_type = CLONE_NEWUSER, /* Filter by user namespace */ 31 .spare2 = 0, 32 .user_ns_id = 0, 33 }; 34 pid_t pids[10]; 35 int num_children = 10; 36 int i; 37 int sv[2]; 38 __u64 first_batch[3]; 39 ssize_t ret; 40 41 ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, sv), 0); 42 43 /* Create children with user namespaces */ 44 for (i = 0; i < num_children; i++) { 45 pids[i] = fork(); 46 ASSERT_GE(pids[i], 0); 47 48 if (pids[i] == 0) { 49 char c; 50 close(sv[0]); 51 52 if (setup_userns() < 0) { 53 close(sv[1]); 54 exit(1); 55 } 56 57 /* Signal parent we're ready */ 58 if (write(sv[1], &c, 1) != 1) { 59 close(sv[1]); 60 exit(1); 61 } 62 63 /* Wait for parent signal to exit */ 64 if (read(sv[1], &c, 1) != 1) { 65 close(sv[1]); 66 exit(1); 67 } 68 69 close(sv[1]); 70 exit(0); 71 } 72 } 73 74 close(sv[1]); 75 76 /* Wait for all children to signal ready */ 77 for (i = 0; i < num_children; i++) { 78 char c; 79 if (read(sv[0], &c, 1) != 1) { 80 close(sv[0]); 81 for (int j = 0; j < num_children; j++) 82 kill(pids[j], SIGKILL); 83 for (int j = 0; j < num_children; j++) 84 waitpid(pids[j], NULL, 0); 85 ASSERT_TRUE(false); 86 } 87 } 88 89 /* First batch - this should work */ 90 ret = sys_listns(&req, first_batch, 3, 0); 91 if (ret < 0) { 92 if (errno == ENOSYS) { 93 close(sv[0]); 94 for (i = 0; i < num_children; i++) 95 kill(pids[i], SIGKILL); 96 for (i = 0; i < num_children; i++) 97 waitpid(pids[i], NULL, 0); 98 SKIP(return, "listns() not supported"); 99 } 100 ASSERT_GE(ret, 0); 101 } 102 103 TH_LOG("First batch returned %zd entries", ret); 104 105 if (ret == 3) { 106 __u64 second_batch[3]; 107 108 /* Second batch - pagination triggers the bug */ 109 req.ns_id = first_batch[2]; /* Continue from last ID */ 110 ret = sys_listns(&req, second_batch, 3, 0); 111 112 TH_LOG("Second batch returned %zd entries", ret); 113 ASSERT_GE(ret, 0); 114 } 115 116 /* Signal all children to exit */ 117 for (i = 0; i < num_children; i++) { 118 char c = 'X'; 119 if (write(sv[0], &c, 1) != 1) { 120 close(sv[0]); 121 for (int j = i; j < num_children; j++) 122 kill(pids[j], SIGKILL); 123 for (int j = 0; j < num_children; j++) 124 waitpid(pids[j], NULL, 0); 125 ASSERT_TRUE(false); 126 } 127 } 128 129 close(sv[0]); 130 131 /* Cleanup */ 132 for (i = 0; i < num_children; i++) { 133 int status; 134 waitpid(pids[i], &status, 0); 135 } 136 } 137 138 TEST_HARNESS_MAIN 139