Home | History | Annotate | Download | only in userns
      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