1 /* 2 * Copyright (c) Huawei Technologies Co., Ltd., 2015 3 * This program is free software; you can redistribute it and/or modify it 4 * under the terms of the GNU General Public License as published by the Free 5 * Software Foundation; either version 2 of the License, or (at your option) 6 * any later version. This program is distributed in the hope that it will be 7 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 8 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General 9 * Public License for more details. You should have received a copy of the GNU 10 * General Public License along with this program. 11 */ 12 13 /* 14 * Verify that: 15 * When a process with non-zero user IDs performs an execve(), the process's 16 * capability sets are cleared. 17 * When a process with zero user IDs performs an execve(), the process's 18 * capability sets are set. 19 * 20 */ 21 22 #define _GNU_SOURCE 23 #include <sys/wait.h> 24 #include <assert.h> 25 #include <stdio.h> 26 #include <stdlib.h> 27 #include <stdbool.h> 28 #include <unistd.h> 29 #include <string.h> 30 #include <errno.h> 31 #include "libclone.h" 32 #include "test.h" 33 #include "config.h" 34 #include "userns_helper.h" 35 36 #define CHILD1UID 0 37 #define CHILD1GID 0 38 #define CHILD2UID 200 39 #define CHILD2GID 200 40 41 char *TCID = "user_namespace6"; 42 int TST_TOTAL = 1; 43 44 static int cpid1, parentuid, parentgid; 45 46 /* 47 * child_fn1() - Inside a new user namespace 48 */ 49 static int child_fn1(void) 50 { 51 int exit_val = 0; 52 char *const args[] = { "userns06_capcheck", "privileged" }; 53 54 TST_SAFE_CHECKPOINT_WAIT(NULL, 0); 55 56 if (execve(args[0], args, NULL) == -1) { 57 printf("execvp unexpected error: (%d) %s\n", 58 errno, strerror(errno)); 59 exit_val = 1; 60 } 61 62 return exit_val; 63 } 64 65 /* 66 * child_fn2() - Inside a new user namespace 67 */ 68 static int child_fn2(void) 69 { 70 int exit_val = 0; 71 int uid, gid; 72 char *const args[] = { "userns06_capcheck", "unprivileged" }; 73 74 TST_SAFE_CHECKPOINT_WAIT(NULL, 1); 75 76 uid = geteuid(); 77 gid = getegid(); 78 79 if (uid != CHILD2UID || gid != CHILD2GID) { 80 printf("unexpected uid=%d gid=%d\n", uid, gid); 81 exit_val = 1; 82 } 83 84 if (execve(args[0], args, NULL) == -1) { 85 printf("execvp unexpected error: (%d) %s\n", 86 errno, strerror(errno)); 87 exit_val = 1; 88 } 89 90 return exit_val; 91 } 92 93 static void cleanup(void) 94 { 95 tst_rmdir(); 96 } 97 98 static void setup(void) 99 { 100 check_newuser(); 101 tst_tmpdir(); 102 TST_CHECKPOINT_INIT(NULL); 103 TST_RESOURCE_COPY(cleanup, "userns06_capcheck", NULL); 104 } 105 106 int main(int argc, char *argv[]) 107 { 108 pid_t cpid2; 109 char path[BUFSIZ]; 110 int lc; 111 int fd; 112 113 tst_parse_opts(argc, argv, NULL, NULL); 114 #ifndef HAVE_LIBCAP 115 tst_brkm(TCONF, NULL, "System is missing libcap."); 116 #endif 117 setup(); 118 119 for (lc = 0; TEST_LOOPING(lc); lc++) { 120 tst_count = 0; 121 122 parentuid = geteuid(); 123 parentgid = getegid(); 124 125 cpid1 = ltp_clone_quick(CLONE_NEWUSER | SIGCHLD, 126 (void *)child_fn1, NULL); 127 if (cpid1 < 0) 128 tst_brkm(TBROK | TERRNO, cleanup, 129 "cpid1 clone failed"); 130 131 cpid2 = ltp_clone_quick(CLONE_NEWUSER | SIGCHLD, 132 (void *)child_fn2, NULL); 133 if (cpid2 < 0) 134 tst_brkm(TBROK | TERRNO, cleanup, 135 "cpid2 clone failed"); 136 137 if (access("/proc/self/setgroups", F_OK) == 0) { 138 sprintf(path, "/proc/%d/setgroups", cpid1); 139 fd = SAFE_OPEN(cleanup, path, O_WRONLY, 0644); 140 SAFE_WRITE(cleanup, 1, fd, "deny", 4); 141 SAFE_CLOSE(cleanup, fd); 142 143 sprintf(path, "/proc/%d/setgroups", cpid2); 144 fd = SAFE_OPEN(cleanup, path, O_WRONLY, 0644); 145 SAFE_WRITE(cleanup, 1, fd, "deny", 4); 146 SAFE_CLOSE(cleanup, fd); 147 } 148 149 updatemap(cpid1, UID_MAP, CHILD1UID, parentuid, cleanup); 150 updatemap(cpid2, UID_MAP, CHILD2UID, parentuid, cleanup); 151 152 updatemap(cpid1, GID_MAP, CHILD1GID, parentgid, cleanup); 153 updatemap(cpid2, GID_MAP, CHILD2GID, parentgid, cleanup); 154 155 TST_SAFE_CHECKPOINT_WAKE(cleanup, 0); 156 TST_SAFE_CHECKPOINT_WAKE(cleanup, 1); 157 158 tst_record_childstatus(cleanup, cpid1); 159 tst_record_childstatus(cleanup, cpid2); 160 } 161 cleanup(); 162 tst_exit(); 163 } 164