1 /* 2 * Copyright (c) Huawei Technologies Co., Ltd., 2015 3 * This program is free software; you can redistribute it and/or modify 4 * it under the terms of the GNU General Public License as published by 5 * the Free Software Foundation; either version 2 of the License, or 6 * (at your option) any later version. 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 11 * the GNU General Public License for more details. 12 */ 13 14 /* 15 * Verify that: 16 * The kernel imposes a limit of at least 32 nested levels on user namespaces. 17 */ 18 19 #define _GNU_SOURCE 20 #include <sys/wait.h> 21 #include <assert.h> 22 #include <stdio.h> 23 #include <stdlib.h> 24 #include <unistd.h> 25 #include <string.h> 26 #include <errno.h> 27 #include "userns_helper.h" 28 #include "test.h" 29 30 #define MAXNEST 32 31 32 char *TCID = "userns07"; 33 int TST_TOTAL = 1; 34 35 static void setup(void) 36 { 37 check_newuser(); 38 tst_tmpdir(); 39 TST_CHECKPOINT_INIT(NULL); 40 } 41 42 static void cleanup(void) 43 { 44 tst_rmdir(); 45 } 46 47 static int child_fn1(void *arg) 48 { 49 pid_t cpid1; 50 long level = (long)arg; 51 int status; 52 int parentuid; 53 int parentgid; 54 55 TST_SAFE_CHECKPOINT_WAIT(NULL, 0); 56 57 if (level == MAXNEST) 58 return 0; 59 cpid1 = ltp_clone_quick(CLONE_NEWUSER | SIGCHLD, 60 (void *)child_fn1, (void *)(level + 1)); 61 if (cpid1 < 0) { 62 printf("level %ld:unexpected error: (%d) %s\n", 63 level, errno, strerror(errno)); 64 return 1; 65 } 66 67 parentuid = geteuid(); 68 parentgid = getegid(); 69 70 updatemap(cpid1, UID_MAP, 0, parentuid, NULL); 71 updatemap(cpid1, GID_MAP, 0, parentgid, NULL); 72 73 TST_SAFE_CHECKPOINT_WAKE(cleanup, 0); 74 75 if (waitpid(cpid1, &status, 0) == -1) 76 return 1; 77 78 if (WIFEXITED(status) && WEXITSTATUS(status) != 0) { 79 printf("child exited abnormally\n"); 80 return 1; 81 } else if (WIFSIGNALED(status)) { 82 printf("child was killed with signal = %d", WTERMSIG(status)); 83 return 1; 84 } 85 return 0; 86 } 87 88 static void test_max_nest(void) 89 { 90 pid_t cpid1; 91 int parentuid; 92 int parentgid; 93 int fd; 94 char path[BUFSIZ]; 95 96 cpid1 = ltp_clone_quick(CLONE_NEWUSER | SIGCHLD, 97 (void *)child_fn1, (void *)0); 98 if (cpid1 < 0) 99 tst_brkm(TBROK | TERRNO, cleanup, "clone failed"); 100 101 parentuid = geteuid(); 102 parentgid = getegid(); 103 104 if (access("/proc/self/setgroups", F_OK) == 0) { 105 sprintf(path, "/proc/%d/setgroups", cpid1); 106 fd = SAFE_OPEN(cleanup, path, O_WRONLY, 0644); 107 SAFE_WRITE(cleanup, 1, fd, "deny", 4); 108 SAFE_CLOSE(cleanup, fd); 109 } 110 111 updatemap(cpid1, UID_MAP, 0, parentuid, cleanup); 112 updatemap(cpid1, GID_MAP, 0, parentgid, cleanup); 113 114 TST_SAFE_CHECKPOINT_WAKE(cleanup, 0); 115 tst_record_childstatus(cleanup, cpid1); 116 } 117 118 int main(int argc, char *argv[]) 119 { 120 int lc; 121 122 setup(); 123 tst_parse_opts(argc, argv, NULL, NULL); 124 125 for (lc = 0; TEST_LOOPING(lc); lc++) { 126 tst_count = 0; 127 test_max_nest(); 128 } 129 130 cleanup(); 131 tst_exit(); 132 } 133 134