github.com/stackdocker/rkt@v0.10.1-0.20151109095037-1aa827478248/stage1/enter/enter.c (about)

     1  // Copyright 2014 The rkt Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  #define _GNU_SOURCE
    16  #include <errno.h>
    17  #include <fcntl.h>
    18  #include <getopt.h>
    19  #include <limits.h>
    20  #include <sched.h>
    21  #include <signal.h>
    22  #include <stdio.h>
    23  #include <stdlib.h>
    24  #include <string.h>
    25  #include <sys/stat.h>
    26  #include <sys/types.h>
    27  #include <sys/wait.h>
    28  #include <unistd.h>
    29  
    30  #ifdef NO_SETNS_AVAILABLE
    31  
    32  #include <linux/unistd.h>
    33  
    34  static int setns(int fd, int nstype) {
    35  	return syscall(__NR_setns, fd, nstype);
    36  }
    37  
    38  #endif /* NO_SETNS_AVAILABLE */
    39  
    40  static int errornum;
    41  #define exit_if(_cond, _fmt, _args...)				\
    42  	errornum++;						\
    43  	if(_cond) {						\
    44  		fprintf(stderr, _fmt "\n", ##_args);		\
    45  		exit(errornum);					\
    46  	}
    47  #define pexit_if(_cond, _fmt, _args...)				\
    48  	exit_if(_cond, _fmt ": %s", ##_args, strerror(errno))
    49  
    50  static int openpidfd(int pid, char *which) {
    51  	char	path[PATH_MAX];
    52  	int	fd;
    53  	exit_if(snprintf(path, sizeof(path),
    54  			 "/proc/%i/%s", pid, which) == sizeof(path),
    55  		"Path overflow");
    56  	pexit_if((fd = open(path, O_RDONLY|O_CLOEXEC)) == -1,
    57  		"Unable to open \"%s\"", path);
    58  	return fd;
    59  }
    60  
    61  int main(int argc, char *argv[])
    62  {
    63  	int	fd;
    64  	int	pid = 0;
    65  	char *appname = NULL;
    66  	pid_t	child;
    67  	int	status;
    68  	int	root_fd;
    69  
    70  	int c;
    71  
    72  	/* The parameters list is specified in
    73  	 * Documentation/devel/stage1-implementors-guide.md */
    74  	while (1) {
    75  		int option_index = 0;
    76  		static struct option long_options[] = {
    77  		   {"pid",     required_argument, 0,  'p' },
    78  		   {"appname", required_argument, 0,  'a' },
    79  		   {0,         0,                 0,  0 }
    80  		};
    81  
    82  		c = getopt_long(argc, argv, "p:a:",
    83  				long_options, &option_index);
    84  		if (c == -1)
    85  			break;
    86  
    87  		switch (c) {
    88  		case 'p':
    89  			pid = atoi(optarg);
    90  			break;
    91  		case 'a':
    92  			appname = optarg;
    93  			break;
    94  		case 0:
    95  			break;
    96  		case ':':   /* missing option argument */
    97  		case '?':
    98  		default:
    99  			fprintf(stderr, "Usage: %s --pid=1234 "
   100  					"--appname=name -- cmd [args...]",
   101  					argv[0]);
   102  			exit(1);
   103  		}
   104  	}
   105  
   106  	root_fd = openpidfd(pid, "root");
   107  
   108  #define ns(_typ, _nam)							\
   109  	fd = openpidfd(pid, _nam);					\
   110  	pexit_if(setns(fd, _typ), "Unable to enter " _nam " namespace");
   111  
   112  #if 0
   113  	/* TODO(vc): Nspawn isn't employing CLONE_NEWUSER, disabled for now */
   114  	ns(CLONE_NEWUSER, "ns/user");
   115  #endif
   116  	ns(CLONE_NEWIPC,  "ns/ipc");
   117  	ns(CLONE_NEWUTS,  "ns/uts");
   118  	ns(CLONE_NEWNET,  "ns/net");
   119  	ns(CLONE_NEWPID,  "ns/pid");
   120  	ns(CLONE_NEWNS,	  "ns/mnt");
   121  
   122  	pexit_if(fchdir(root_fd) < 0,
   123  		"Unable to chdir to pod root");
   124  	pexit_if(chroot(".") < 0,
   125  		"Unable to chroot");
   126  	pexit_if(close(root_fd) == -1,
   127  		"Unable to close root_fd");
   128  
   129  	/* Fork is required to realize consequence of CLONE_NEWPID */
   130  	pexit_if(((child = fork()) == -1),
   131  		"Unable to fork");
   132  
   133  /* some stuff make the argv->args copy less cryptic */
   134  #define APPEXEC_ARGV_FWD_OFFSET	6
   135  
   136  	if(child == 0) {
   137  		char		root[PATH_MAX];
   138  		char		env[PATH_MAX];
   139  		char		*args[APPEXEC_ARGV_FWD_OFFSET + argc - optind + 1 /* NULL terminator */];
   140  		int		argsind;
   141  
   142  		/* Child goes on to execute /appexec */
   143  
   144  		exit_if(snprintf(root, sizeof(root),
   145  				 "/opt/stage2/%s/rootfs", appname) == sizeof(root),
   146  			"Root path overflow");
   147  
   148  		exit_if(snprintf(env, sizeof(env),
   149  				 "/rkt/env/%s", appname) == sizeof(env),
   150  			"Env path overflow");
   151  
   152  		args[0] = "/appexec";
   153  		args[1] = root;
   154  		args[2] = "/";	/* TODO(vc): plumb this into app.WorkingDirectory */
   155  		args[3] = env;
   156  		args[4] = "0"; /* uid */
   157  		args[5] = "0"; /* gid */
   158  		argsind = APPEXEC_ARGV_FWD_OFFSET;
   159  		while (optind < argc)
   160  			args[argsind++] = argv[optind++];
   161  
   162  		args[argsind] = NULL;
   163  
   164  		pexit_if(execv(args[0], args) == -1,
   165  			"Exec failed");
   166  	}
   167  
   168  	/* Wait for child, nsenter-like */
   169  	for(;;) {
   170  		if(waitpid(child, &status, WUNTRACED) == pid &&
   171  		   (WIFSTOPPED(status))) {
   172  			kill(getpid(), SIGSTOP);
   173  			/* the above stops us, upon receiving SIGCONT we'll
   174  			 * continue here and inform our child */
   175  			kill(child, SIGCONT);
   176  		} else {
   177  			break;
   178  		}
   179  	}
   180  
   181  	if(WIFEXITED(status)) {
   182  		exit(WEXITSTATUS(status));
   183  	} else if(WIFSIGNALED(status)) {
   184  		kill(getpid(), WTERMSIG(status));
   185  	}
   186  
   187  	return EXIT_FAILURE;
   188  }