vshost-util-vserver

Build script and sources for util-vserver.
git clone https://ccx.te2000.cz/git/vshost-util-vserver
Log | Files | Refs

vcontext.c (15225B)


      1 // $Id$    --*- c -*--
      2 
      3 // Copyright (C) 2004-2006 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
      4 //
      5 // This program is free software; you can redistribute it and/or modify
      6 // it under the terms of the GNU General Public License as published by
      7 // the Free Software Foundation; version 2 of the License.
      8 //
      9 // This program is distributed in the hope that it will be useful,
     10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
     11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     12 // GNU General Public License for more details.
     13 //
     14 // You should have received a copy of the GNU General Public License
     15 // along with this program; if not, write to the Free Software
     16 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
     17 
     18 
     19 #ifdef HAVE_CONFIG_H
     20 #  include <config.h>
     21 #endif
     22 
     23 #include "util.h"
     24 #include "compat-pivot_root.h"
     25 #include "lib/internal.h"
     26 #include "lib_internal/jail.h"
     27 #include "lib_internal/sys_personality.h"
     28 #include "lib_internal/sys_unshare.h"
     29 
     30 #include <vserver.h>
     31 #include <getopt.h>
     32 #include <fcntl.h>
     33 #include <errno.h>
     34 #include <sys/socket.h>
     35 #include <sys/un.h>
     36 #include <assert.h>
     37 #include <signal.h>
     38 #include <sys/types.h>
     39 #include <pwd.h>
     40 #include <grp.h>
     41 #include <sys/mount.h>
     42 
     43 #include <linux/personality.h>
     44 
     45 #define ENSC_WRAPPERS_PREFIX	"vcontext: "
     46 #define ENSC_WRAPPERS_UNISTD	1
     47 #define ENSC_WRAPPERS_VSERVER	1
     48 #define ENSC_WRAPPERS_FCNTL	1
     49 #define ENSC_WRAPPERS_SOCKET	1
     50 #define ENSC_WRAPPERS_IOSOCK	1
     51 #include <wrappers.h>
     52 
     53 #define CMD_HELP		0x1000
     54 #define CMD_VERSION		0x1001
     55 #define CMD_XID			0x4000
     56 #define CMD_CREATE		0x4001
     57 #define CMD_MIGRATE		0x4003
     58 #define CMD_INITPID		0x4002
     59 #define CMD_DISCONNECT		0x4004
     60 #define CMD_UID			0x4005
     61 #define CMD_CHROOT		0x4006
     62 #define CMD_SILENT		0x4007
     63 #define CMD_SYNCSOCK		0x4008
     64 #define CMD_SYNCMSG		0x4009
     65 #define CMD_MIGRATESELF		0x400a
     66 #define CMD_ENDSETUP		0x400b
     67 #define CMD_SILENTEXIST		0x400c
     68 #define CMD_NAMESPACE		0x400d
     69 #define CMD_PERSTYPE		0x400e
     70 #define CMD_PERSFLAG		0x400f
     71 #define CMD_VLOGIN		0x4010
     72 #define CMD_PIVOT_ROOT		0x4011
     73 #define CMD_CLOSE_FD		0x4012
     74 
     75 
     76 #ifndef MNT_DETACH
     77 #define MNT_DETACH		0x0002
     78 #endif
     79 
     80 
     81 struct option const
     82 CMDLINE_OPTIONS[] = {
     83   { "help",       no_argument,       0, CMD_HELP },
     84   { "version",    no_argument,       0, CMD_VERSION },
     85   { "ctx",        required_argument, 0, CMD_XID },
     86   { "xid",        required_argument, 0, CMD_XID },
     87   { "create",     no_argument,       0, CMD_CREATE },
     88   { "migrate",    no_argument,       0, CMD_MIGRATE },
     89   { "migrate-self", no_argument,       	0, CMD_MIGRATESELF },
     90   { "initpid",      no_argument,       	0, CMD_INITPID },
     91   { "endsetup",     no_argument,        0, CMD_ENDSETUP },
     92   { "disconnect",   no_argument,	0, CMD_DISCONNECT },
     93   { "silent",       no_argument,       	0, CMD_SILENT },
     94   { "silentexist",  no_argument,       	0, CMD_SILENTEXIST },
     95   { "uid",          required_argument,  0, CMD_UID },
     96   { "chroot",       no_argument,       	0, CMD_CHROOT },
     97   { "namespace",    no_argument,       	0, CMD_NAMESPACE },
     98   { "syncsock",     required_argument, 	0, CMD_SYNCSOCK },
     99   { "syncmsg",      required_argument, 	0, CMD_SYNCMSG },
    100   { "personality-type",  required_argument, 0, CMD_PERSTYPE },
    101   { "personality-flags", required_argument, 0, CMD_PERSFLAG },
    102   { "vlogin",       no_argument,        0, CMD_VLOGIN },
    103   { "pivot-root",   no_argument,        0, CMD_PIVOT_ROOT },
    104   { "closefd",      no_argument,        0, CMD_CLOSE_FD },
    105 #if 1
    106   { "fakeinit",     no_argument,       	0, CMD_INITPID },	// compatibility
    107 #endif
    108   { 0,0,0,0 },
    109 };
    110 
    111 struct Arguments {
    112     bool		do_create;
    113     bool		do_migrate;
    114     bool		do_migrateself;
    115     bool		do_disconnect;
    116     bool		do_endsetup;
    117     bool		is_initpid;
    118     bool		is_silentexist;
    119     bool		set_namespace;
    120     bool		do_vlogin;
    121     uint_least32_t	personality_flags;
    122     uint_least32_t	personality_type;
    123     int			verbosity;
    124     bool		do_chroot;
    125     bool		do_pivot_root;
    126     bool		do_close_fd;
    127     char const *	uid;
    128     xid_t		xid;
    129     char const *	sync_sock;
    130     char const *	sync_msg;
    131 };
    132 
    133 int		wrapper_exit_code = 255;
    134 
    135 void do_vlogin(int argc, char *argv[], int ind);
    136 
    137 static void
    138 showHelp(int fd, char const *cmd, int res)
    139 {
    140   WRITE_MSG(fd, "Usage:\n    ");
    141   WRITE_STR(fd, cmd);
    142   WRITE_MSG(fd,
    143 	    " --create [--xid <xid>] <opts>* [--] <program> <args>*\n    ");
    144   WRITE_STR(fd, cmd);
    145   WRITE_MSG(fd,
    146 	    " [(--migrate --xid <xid>)|--migrate-self]  <opts>* [--] <program> <args>*\n"
    147 	    "\n"
    148 	    "<opts> can be:\n"
    149 	    "    --chroot	 ...  chroot into current directory\n"
    150 	    "    --namespace     ...  execute namespace management operations\n"
    151 	    "    --uid <uid>     ...  change uid\n"
    152 	    "    --initpid       ...  set current process as general process reaper\n"
    153 	    "                         for ctx (possible for --migrate only)\n"
    154 	    "    --endsetup      ...  clear the setup flag; usefully for migrate only\n"
    155 	    "    --disconnect    ...  start program in background\n"
    156 	    "    --personality-type <type>\n"
    157 	    "                    ...  execute <program> in the given execution domain\n"
    158 	    "    --personality-flags <flags>+\n"
    159 	    "                    ...  set special flags for the given execution domain\n"
    160 	    "    --silent        ...  be silent\n"
    161 	    "    --silentexist   ...  be silent when context exists already; usefully\n"
    162 	    "                         for '--create' only\n"
    163 	    "    --syncsock <file-name>\n"
    164 	    "                    ...  before executing the program, send a message\n"
    165 	    "                         to the socket and wait until it closes.\n"
    166 	    "                         <file-name> must be a SOCK_STREAM unix socket\n"
    167 	    "    --syncmsg <message>\n"
    168 	    "                    ...  use <message> as synchronization message; by\n"
    169 	    "                         default, 'ok' will be used\n"
    170 	    "    --vlogin        ...  enable terminal proxy\n"
    171 	    "    --closefd       ...  close all open file descriptors >2\n"
    172 	    "\n"
    173 	    "'vcontext --create' exits with code 254 iff the context exists already.\n"
    174 	    "\n"
    175 	    "Please report bugs to " PACKAGE_BUGREPORT "\n");
    176 
    177   exit(res);
    178 }
    179 
    180 static void
    181 showVersion()
    182 {
    183   WRITE_MSG(1,
    184 	    "vcontext " VERSION " -- manages the creation of security contexts\n"
    185 	    "This program is part of " PACKAGE_STRING "\n\n"
    186 	    "Copyright (C) 2004-2006 Enrico Scholz\n"
    187 	    VERSION_COPYRIGHT_DISCLAIMER);
    188   exit(0);
    189 }
    190 
    191 #include "context-sync.hc"
    192 
    193 static inline ALWAYSINLINE void
    194 tellContext(xid_t ctx, bool do_it)
    195 {
    196   char		buf[sizeof(xid_t)*3+2];
    197   size_t	l;
    198 
    199   if (!do_it) return;
    200 
    201   l = utilvserver_fmt_long(buf,ctx);
    202 
    203   WRITE_MSG(1, "New security context is ");
    204   Vwrite   (1, buf, l);
    205   WRITE_MSG(1, "\n");
    206 }
    207 
    208 static int
    209 connectExternalSync(char const *filename)
    210 {
    211   int			fd;
    212   struct sockaddr_un	addr;
    213 
    214   if (filename==0) return -1;
    215 
    216   ENSC_INIT_UNIX_SOCK(addr, filename);
    217 
    218   fd = Esocket(PF_UNIX, SOCK_STREAM, 0);
    219   Econnect(fd, &addr, sizeof(addr));
    220 
    221   return fd;
    222 }
    223 
    224 static void
    225 setFlags(struct Arguments const *args, xid_t xid)
    226 {
    227   struct vc_ctx_flags	flags = { 0,0 };
    228 
    229   if (args->is_initpid)
    230     flags.mask |=  VC_VXF_STATE_INIT;
    231 
    232   if (args->do_endsetup)
    233     flags.mask |=  VC_VXF_STATE_SETUP;
    234 
    235   if (flags.mask!=0) {
    236     DPRINTF("set_flags: mask=%08llx, flag=%08llx\n", flags.mask, flags.flagword);
    237     Evc_set_cflags(xid, &flags);
    238   }
    239 }
    240 
    241 static void
    242 doExternalSync(int fd, char const *msg)
    243 {
    244   char		c;
    245 
    246   if (fd==-1) return;
    247 
    248   if (msg) EsendAll(fd, msg, strlen(msg));
    249   Eshutdown(fd, SHUT_WR);
    250 
    251   if (TEMP_FAILURE_RETRY(recv(fd, &c, 1, MSG_NOSIGNAL))!=0) {
    252     WRITE_MSG(2, ENSC_WRAPPERS_PREFIX "unexpected external synchronization event\n");
    253     exit(wrapper_exit_code);
    254   }
    255 
    256   Eclose(fd);
    257 }
    258 
    259 static inline ALWAYSINLINE int
    260 doit(struct Arguments const *args, int argc, char *argv[])
    261 {
    262   int			p[2][2];
    263   pid_t			pid = initSync(p, args->do_disconnect);
    264 
    265   if (pid==0) {
    266     xid_t			xid;
    267     int				ext_sync_fd = connectExternalSync(args->sync_sock);
    268 
    269     doSyncStage0(p, args->do_disconnect);
    270 
    271     if (args->do_close_fd) {
    272       int fd;
    273       for (fd = 3; fd < sysconf(_SC_OPEN_MAX); fd++) {
    274 	if (fd == ext_sync_fd ||
    275             fd == p[0][0] ||
    276             fd == p[0][1] ||
    277             fd == p[1][0] ||
    278             fd == p[1][1])
    279 	  continue;
    280 	close(fd);
    281       }
    282     }
    283 
    284     if (args->do_create) {
    285       xid = vc_ctx_create(args->xid, NULL);
    286       if (xid==VC_NOCTX) {
    287 	switch (errno) {
    288 	  case EEXIST	:
    289 	    if (!args->is_silentexist)
    290 	      perror(ENSC_WRAPPERS_PREFIX "vc_ctx_create()");
    291 	    return 254;
    292 	  default	:
    293 	    perror(ENSC_WRAPPERS_PREFIX "vc_ctx_create()");
    294 	    return wrapper_exit_code;
    295 	}
    296       }
    297       tellContext(xid, args->verbosity>=1);
    298     }
    299     else
    300       xid = args->xid;
    301 
    302     if (args->do_chroot) {
    303       Echroot(".");
    304       if (args->set_namespace) {
    305 	if (args->do_migrateself)  Evc_set_namespace(xid, CLONE_NEWNS|CLONE_FS, 0);
    306 	else if (args->do_migrate) Evc_enter_namespace(xid, CLONE_NEWNS|CLONE_FS, 0);
    307       }
    308     }
    309     else if (args->do_pivot_root) {
    310       if (vc_enter_namespace(xid, CLONE_NEWNS | CLONE_FS, 1) == -1) {
    311 	bool existed = false;
    312 	if (sys_unshare(CLONE_NEWNS) == -1) {
    313 	  perror(ENSC_WRAPPERS_PREFIX "unshare(NEWNS)");
    314 	  return wrapper_exit_code;
    315 	}
    316 	if (mkdir("./.oldroot", 0700) == -1) {
    317 	  if (errno == EEXIST)
    318 	    existed = true;
    319 	  else {
    320 	    perror(ENSC_WRAPPERS_PREFIX "mkdir()");
    321 	    return wrapper_exit_code;
    322 	  }
    323 	}
    324 	if (pivot_root(".", "./.oldroot") == -1) {
    325 	  perror(ENSC_WRAPPERS_PREFIX "pivot_root()");
    326 	  return wrapper_exit_code;
    327 	}
    328 	if (umount2("/.oldroot", MNT_DETACH) == -1) {
    329 	  perror(ENSC_WRAPPERS_PREFIX "umount2()");
    330 	  return wrapper_exit_code;
    331 	}
    332 	if (!existed && rmdir("/.oldroot") == -1) {
    333 	  perror(ENSC_WRAPPERS_PREFIX "rmdir()");
    334 	  return wrapper_exit_code;
    335 	}
    336 	Evc_set_namespace(xid, CLONE_NEWNS | CLONE_FS, 1);
    337       }
    338     }
    339 
    340     setFlags(args, xid);
    341 
    342     if (args->do_migrate && !args->do_migrateself)
    343       Evc_ctx_migrate(xid, 0);
    344 
    345     if (args->uid != NULL) {
    346       uid_t uid = 0;
    347       unsigned long tmp;
    348 
    349       if (!isNumberUnsigned(args->uid, &tmp, false)) {
    350 #ifdef __dietlibc__
    351 	struct passwd *pw;
    352 	pw = getpwnam(args->uid);
    353 	if (pw == NULL) {
    354 	  WRITE_MSG(2, ENSC_WRAPPERS_PREFIX "Username '");
    355 	  WRITE_STR(2, args->uid);
    356 	  WRITE_MSG(2, "' does not exist\n");
    357 	  return wrapper_exit_code;
    358 	}
    359 	uid = pw->pw_uid;
    360 	Einitgroups(args->uid, pw->pw_gid);
    361 	Esetgid(pw->pw_gid);
    362 #else
    363 	WRITE_MSG(2, ENSC_WRAPPERS_PREFIX "Uid '");
    364 	WRITE_STR(2, args->uid);
    365 	WRITE_MSG(2, "' is not a number\n");
    366 	return wrapper_exit_code;
    367 #endif
    368       }
    369       else
    370 	uid = (uid_t) tmp;
    371 
    372       Esetuid((uid_t) uid);
    373       if (getuid()!=uid) {
    374 	WRITE_MSG(2, ENSC_WRAPPERS_PREFIX "Something went wrong while changing the UID\n");
    375 	exit(wrapper_exit_code);
    376       }
    377     }
    378 
    379     if (args->personality_type!=VC_BAD_PERSONALITY &&
    380 	sys_personality(args->personality_type | args->personality_flags)==-1) {
    381       perror(ENSC_WRAPPERS_PREFIX "personality()");
    382       exit(wrapper_exit_code);
    383     }
    384 
    385     doExternalSync(ext_sync_fd, args->sync_msg);
    386     doSyncStage1(p, args->do_disconnect);
    387     DPRINTF("doit: pid=%u, ppid=%u\n", getpid(), getppid());
    388 
    389     if (!args->do_vlogin)
    390       execvp (argv[optind],argv+optind);
    391     else
    392       do_vlogin(argc, argv, optind);
    393     doSyncStage2(p, args->do_disconnect);
    394 
    395     PERROR_Q(ENSC_WRAPPERS_PREFIX "execvp", argv[optind]);
    396     exit(wrapper_exit_code);
    397   }
    398 
    399   assert(args->do_disconnect);
    400 
    401   waitOnSync(pid, p, args->xid!=VC_DYNAMIC_XID && args->do_migrate);
    402   return EXIT_SUCCESS;
    403 }
    404 
    405 static uint_least32_t
    406 parsePersonalityType(char const *str)
    407 {
    408   uint_least32_t	res = vc_str2personalitytype(str, 0);
    409   if (res==VC_BAD_PERSONALITY) {
    410     WRITE_MSG(2, ENSC_WRAPPERS_PREFIX "bad personality type\n");
    411     exit(wrapper_exit_code);
    412   }
    413 
    414   return res;
    415 }
    416 
    417 static uint_least32_t
    418 parsePersonalityFlags(char const *str)
    419 {
    420   struct vc_err_listparser	err;
    421   uint_least32_t		res;
    422 
    423   if (vc_list2personalityflag(str, 0, &res, &err)==-1) {
    424     WRITE_MSG(2, ENSC_WRAPPERS_PREFIX "bad personality flag '");
    425     Vwrite(2, err.ptr, err.len);
    426     WRITE_MSG(2, "'\n");
    427     exit(wrapper_exit_code);
    428   }
    429 
    430   return res;
    431 }
    432 
    433 int main (int argc, char *argv[])
    434 {
    435   struct Arguments		args = {
    436     .do_create         = false,
    437     .do_migrate        = false,
    438     .do_migrateself    = false,
    439     .do_disconnect     = false,
    440     .do_endsetup       = false,
    441     .do_vlogin         = false,
    442     .do_close_fd       = false,
    443     .is_initpid        = false,
    444     .is_silentexist    = false,
    445     .set_namespace     = false,
    446     .verbosity         = 1,
    447     .uid               = NULL,
    448     .xid               = VC_DYNAMIC_XID,
    449     .personality_type  = VC_BAD_PERSONALITY,
    450     .personality_flags = 0,
    451     .sync_msg          = "ok",
    452   };
    453 
    454   while (1) {
    455     int		c = getopt_long(argc, argv, "+", CMDLINE_OPTIONS, 0);
    456     if (c==-1) break;
    457 
    458     switch (c) {
    459       case CMD_HELP		:  showHelp(1, argv[0], 0);
    460       case CMD_VERSION		:  showVersion();
    461       case CMD_CREATE		:  args.do_create      = true;   break;
    462       case CMD_MIGRATE		:  args.do_migrate     = true;   break;
    463       case CMD_DISCONNECT	:  args.do_disconnect  = true;   break;
    464       case CMD_ENDSETUP		:  args.do_endsetup    = true;   break;
    465       case CMD_VLOGIN		:  args.do_vlogin      = true;   break;
    466       case CMD_INITPID		:  args.is_initpid     = true;   break;
    467       case CMD_CHROOT		:  args.do_chroot      = true;   break;
    468       case CMD_PIVOT_ROOT	:  args.do_pivot_root  = true;   break;
    469       case CMD_NAMESPACE	:  args.set_namespace  = true;   break;
    470       case CMD_SILENTEXIST	:  args.is_silentexist = true;   break;
    471       case CMD_CLOSE_FD		:  args.do_close_fd    = true;   break;
    472       case CMD_SYNCSOCK		:  args.sync_sock      = optarg; break;
    473       case CMD_SYNCMSG		:  args.sync_msg       = optarg; break;
    474       case CMD_UID		:  args.uid            = optarg; break;
    475       case CMD_XID		:  args.xid = Evc_xidopt2xid(optarg,true); break;
    476       case CMD_SILENT		:  --args.verbosity; break;
    477       case CMD_PERSTYPE		:
    478 	args.personality_type   = parsePersonalityType(optarg);
    479 	break;
    480       case CMD_PERSFLAG		:
    481 	args.personality_flags |= parsePersonalityFlags(optarg);
    482 	break;
    483       case CMD_MIGRATESELF	:
    484 	args.do_migrate     = true;
    485 	args.do_migrateself = true;
    486 	break;
    487 
    488       default		:
    489 	WRITE_MSG(2, "Try '");
    490 	WRITE_STR(2, argv[0]);
    491 	WRITE_MSG(2, " --help' for more information.\n");
    492 	return wrapper_exit_code;
    493 	break;
    494     }
    495   }
    496 
    497   signal(SIGCHLD, SIG_DFL);
    498 
    499   if (args.do_migrateself)
    500     args.xid = Evc_get_task_xid(0);
    501 
    502   if (!args.do_create && !args.do_migrate)
    503     WRITE_MSG(2, "Neither '--create' nor '--migrate' specified; try '--help' for more information\n");
    504   else if (args.do_create  &&  args.do_migrate)
    505     WRITE_MSG(2, "Can not specify '--create' and '--migrate' at the same time; try '--help' for more information\n");
    506   else if (!args.do_migrate && args.is_initpid)
    507     WRITE_MSG(2, "'--initpid' is possible in combination with '--migrate' only\n");
    508   else if (!args.do_create && args.xid==VC_DYNAMIC_XID)
    509     WRITE_MSG(2, ENSC_WRAPPERS_PREFIX "Can not migrate to an unknown context\n");
    510   else if (optind>=argc)
    511     WRITE_MSG(2, "No command given; use '--help' for more information.\n");
    512   else
    513     return doit(&args, argc, argv);
    514 
    515   return wrapper_exit_code;
    516 }