Path: blob/main/sys/contrib/openzfs/tests/zfs-tests/cmd/user_ns_exec.c
48529 views
// SPDX-License-Identifier: CDDL-1.01/*2* CDDL HEADER START3*4* The contents of this file are subject to the terms of the5* Common Development and Distribution License (the "License").6* You may not use this file except in compliance with the License.7*8* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE9* or https://opensource.org/licenses/CDDL-1.0.10* See the License for the specific language governing permissions11* and limitations under the License.12*13* When distributing Covered Code, include this CDDL HEADER in each14* file and include the License file at usr/src/OPENSOLARIS.LICENSE.15* If applicable, add the following below this CDDL HEADER, with the16* fields enclosed by brackets "[]" replaced with your own identifying17* information: Portions Copyright [yyyy] [name of copyright owner]18*19* CDDL HEADER END20*/2122#include <stdio.h>23#include <unistd.h>24#include <string.h>25#include <limits.h>26#include <sys/types.h>27#include <sys/types.h>28#include <sys/socket.h>29#include <sys/wait.h>30#include <fcntl.h>31#include <errno.h>32#include <signal.h>33#include <sched.h>3435#define EXECSHELL "/bin/sh"36#define UIDMAP "0 100000 65536"3738static int39child_main(int argc, char *argv[], int sync_pipe)40{41char sync_buf;42char cmds[BUFSIZ] = { 0 };43char sep[] = " ";44int i, len;4546if (unshare(CLONE_NEWUSER | CLONE_NEWNS) != 0) {47perror("unshare");48return (1);49}5051/* tell parent we entered the new namespace */52if (write(sync_pipe, "1", 1) != 1) {53perror("write");54return (1);55}5657/* wait for parent to setup the uid mapping */58if (read(sync_pipe, &sync_buf, 1) != 1) {59(void) fprintf(stderr, "user namespace setup failed\n");60return (1);61}6263close(sync_pipe);6465if (setuid(0) != 0) {66perror("setuid");67return (1);68}69if (setgid(0) != 0) {70perror("setgid");71return (1);72}7374len = 0;75for (i = 1; i < argc; i++) {76(void) snprintf(cmds+len, sizeof (cmds)-len,77"%s%s", argv[i], sep);78len += strlen(argv[i]) + strlen(sep);79}8081if (execl(EXECSHELL, "sh", "-c", cmds, (char *)NULL) != 0) {82perror("execl: " EXECSHELL);83return (1);84}8586return (0);87}8889static int90set_idmap(pid_t pid, const char *file)91{92int result = 0;93int mapfd;94char path[PATH_MAX];9596(void) snprintf(path, sizeof (path), "/proc/%d/%s", (int)pid, file);9798mapfd = open(path, O_WRONLY);99if (mapfd < 0) {100perror("open");101return (errno);102}103104if (write(mapfd, UIDMAP, sizeof (UIDMAP)-1) != sizeof (UIDMAP)-1) {105perror("write");106result = (errno);107}108109close(mapfd);110111return (result);112}113114int115main(int argc, char *argv[])116{117char sync_buf;118int result, wstatus;119int syncfd[2];120pid_t child;121122if (argc < 2 || strlen(argv[1]) == 0) {123(void) printf("\tUsage: %s <commands> ...\n", argv[0]);124return (1);125}126127if (socketpair(AF_UNIX, SOCK_STREAM, 0, syncfd) != 0) {128perror("socketpair");129return (1);130}131132child = fork();133if (child == (pid_t)-1) {134perror("fork");135return (1);136}137138if (child == 0) {139close(syncfd[0]);140return (child_main(argc, argv, syncfd[1]));141}142143close(syncfd[1]);144145result = 0;146/* wait for the child to have unshared its namespaces */147if (read(syncfd[0], &sync_buf, 1) != 1) {148perror("read");149kill(child, SIGKILL);150result = 1;151goto reap;152}153154/* write uid mapping */155if (set_idmap(child, "uid_map") != 0 ||156set_idmap(child, "gid_map") != 0) {157result = 1;158kill(child, SIGKILL);159goto reap;160}161162/* tell the child to proceed */163if (write(syncfd[0], "1", 1) != 1) {164perror("write");165kill(child, SIGKILL);166result = 1;167goto reap;168}169close(syncfd[0]);170171reap:172while (waitpid(child, &wstatus, 0) != child)173kill(child, SIGKILL);174if (result == 0)175result = WEXITSTATUS(wstatus);176177return (result);178}179180181