vshost-util-vserver

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

rpm-fake.c (18364B)


      1 // Copyright (C) 2003,2014 Enrico Scholz <enrico.scholz@ensc.de>
      2 //
      3 // This program is free software; you can redistribute it and/or modify
      4 // it under the terms of the GNU General Public License as published by
      5 // the Free Software Foundation; version 2 of the License.
      6 //
      7 // This program is distributed in the hope that it will be useful,
      8 // but WITHOUT ANY WARRANTY; without even the implied warranty of
      9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     10 // GNU General Public License for more details.
     11 //
     12 // You should have received a copy of the GNU General Public License
     13 // along with this program; if not, write to the Free Software
     14 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
     15 //
     16 
     17 #ifdef HAVE_CONFIG_H
     18 #  include <config.h>
     19 #endif
     20 
     21 #include "pathconfig.h"
     22 #include "util.h"
     23 
     24 #include <lib/vserver.h>
     25 #include <lib/internal.h>
     26 #include <lib_internal/sys_clone.h>
     27 
     28 #include <sys/socket.h>
     29 #include <dlfcn.h>
     30 #include <stdlib.h>
     31 #include <stdint.h>
     32 #include <stdio.h>
     33 #include <unistd.h>
     34 #include <asm/unistd.h>
     35 #include <string.h>
     36 #include <stdbool.h>
     37 #include <errno.h>
     38 #include <fcntl.h>
     39 #include <stdarg.h>
     40 #include <sys/mount.h>
     41 #ifdef HAVE_LINUX_TYPES_H
     42 #  include <linux/types.h>
     43 #endif
     44 #include <linux/fs.h>
     45 #include <sched.h>
     46 #include <signal.h>
     47 #include <sys/types.h>
     48 #include <sys/wait.h>
     49 #include <sys/un.h>
     50 #include <fcntl.h>
     51 #include <pwd.h>
     52 #include <grp.h>
     53 
     54 
     55   // from selinux.h
     56   // FIXME: add configure autodetection and include <selinux.h> directly
     57 int rpm_execcon(unsigned int verified,
     58 		const char *filename,
     59 		char *const argv[], char *const envp[]);
     60 
     61 
     62 #define ENSC_WRAPPERS_PREFIX	"rpm-fake.so: "
     63 #define ENSC_WRAPPERS_VSERVER	1
     64 #define ENSC_WRAPPERS_UNISTD	1
     65 #include <wrappers.h>
     66 
     67 #undef _POSIX_SOURCE
     68 #include "capability-compat.h"
     69 
     70 #define LIBNAME		"rpm-fake.so"
     71 #define PLATFORM_FILE	"/etc/rpm/platform"
     72 
     73 #define INIT(FILE,FUNC)	FUNC##_func = ((__typeof__(FUNC) *) (xdlsym(FILE, #FUNC)))
     74 #define DECLARE(FUNC)	static __typeof__(FUNC) *	FUNC##_func = 0
     75 
     76 #define DEBUG 1
     77 
     78 #define DBG_INIT	0x0001
     79 #define DBG_VARIABLES	0x0002
     80 #define DBG_RESOLVER	0x0004
     81 #define DBG_EXECV	0x0008
     82 #define DBG_ENV		0x0010
     83 #define DBG_VERBOSE0	0x8000
     84 #define DBG_VERBOSE1	(0x4000 | DBG_VERBOSE0)
     85 #define DBG_VERBOSE2	(0x2000 | DBG_VERBOSE1)
     86 
     87 int			wrapper_exit_code = 255;
     88 
     89 static xid_t		ctx   = VC_NOCTX;
     90 static uint32_t		caps  = ~0;
     91 static int		flags = 0;
     92 static char const *	mnts  = 0;
     93 static char const *	root  = 0;
     94 static int		pw_sock   = -1;
     95 static int		sync_sock = -1;
     96 static unsigned int	debug_level = 0;
     97 
     98 static bool		is_initialized = false;
     99 static bool		chroot_seen = false;
    100 
    101 static bool		ctx_created = false;
    102 
    103   //DECLARE(rpm_execcon);
    104 DECLARE(execve);
    105 DECLARE(getpwnam);
    106 DECLARE(getgrnam);
    107 DECLARE(endpwent);
    108 DECLARE(endgrent);
    109 DECLARE(chroot);
    110 
    111 static void		initRPMFake() __attribute__((__constructor__));
    112 static void		exitRPMFake() __attribute__((__destructor__));
    113 
    114 static inline bool
    115 isDbgLevel(unsigned int level)
    116 {
    117   return ((debug_level&level)==level);
    118 }
    119 
    120 static void *
    121 xdlsym(void *handle, const char *symbol)
    122 {
    123   void	*res = dlsym(handle, symbol);
    124   if (res==0) {
    125     char const	*error = dlerror();
    126     Vwrite(2, symbol, strlen(symbol));
    127     Vwrite(2, ": ", 2);
    128     Vwrite(2, error, strlen(error));
    129     Vwrite(2, "\n", 2);
    130 
    131     _exit(255);
    132   }
    133 
    134   return res;
    135 }
    136 
    137 static void
    138 showHelp()
    139 {
    140   WRITE_MSG(1,
    141 	    "Usage: LD_PRELOAD=" LIBNAME " <executable> <args>*\n\n"
    142 	    LIBNAME " unterstands the following environment variables:\n"
    143 	    "  $RPM_FAKE_RESOLVER     ...  program which does the NSS resolving (defaults\n"
    144 	    "                              to " RESOLVER_PROG ")\n"
    145 	    "  $RPM_FAKE_RESOLVER_UID ...  uid of the resolver program\n"
    146 	    "  $RPM_FAKE_RESOLVER_GID ...  gid of the resolver program\n"
    147 	    "  $RPM_FAKE_CTX          ...  vserver context which shall be used for resolver\n"
    148 	    "                              and scriptlets\n"
    149 	    "  $RPM_FAKE_CAP          ...  linux capability remove-mask for the context\n"
    150 	    "  $RPM_FAKE_FLAGS        ...  vserver flags of the context\n"
    151 	    "  $RPM_FAKE_CHROOT       ...  directory of the chroot environment\n"
    152 	    "  $RPM_FAKE_NAMESPACE_MOUNTS\n"
    153 	    "                          ... colon separated list of directories which will\n"
    154             "                              umounted before scriptlet execution\n\n"
    155 	    "  $RPM_FAKE_HELP          ... shows this message\n"
    156 	    "  $RPM_FAKE_VERSION       ... shows the version of this program\n\n"
    157 	    "  $RPM_FAKE_DEBUG         ... sets the debuglevel bitmask\n\n"
    158 	    "Please report bugs to " PACKAGE_BUGREPORT "\n");
    159   exit(0);
    160 }
    161 
    162 static void
    163 showVersion()
    164 {
    165   WRITE_MSG(1,
    166 	    LIBNAME " " VERSION " -- wrapper around rpm\n"
    167 	    "This program is part of " PACKAGE_STRING "\n\n"
    168 	    "Copyright (C) 2003 Enrico Scholz\n"
    169 	    VERSION_COPYRIGHT_DISCLAIMER);
    170   exit(0);
    171 }
    172 
    173 static void
    174 unsetPreloadEnv()
    175 {
    176   char			*env = getenv("LD_PRELOAD");
    177   char			*pos;
    178 
    179     // the const <-> non-const assignment is not an issue since the following
    180     // modifying operations will not be executed in the const-case
    181   env = env ? env : "";
    182   pos = strstr(env, LIBNAME);
    183 
    184   if (pos!=0) {
    185     char	*end_pos = pos + sizeof(LIBNAME);
    186     bool	is_end = (end_pos[-1]=='\0');
    187     char	*start_pos;
    188 
    189     end_pos[-1] = '\0';
    190     start_pos   = strrchr(env, ':');
    191     if (start_pos==0) start_pos = env;
    192     else if (!is_end) ++start_pos;
    193 
    194     if (is_end) *start_pos = '\0';
    195     else        memmove(start_pos, end_pos, strlen(end_pos)+1);
    196   }
    197 
    198 #ifdef DEBUG
    199   if (isDbgLevel(DBG_VERBOSE1|DBG_VARIABLES)) {
    200     WRITE_MSG(2, "env='");
    201     WRITE_STR(2, env);
    202     WRITE_MSG(2, "'\n");
    203   }
    204 #endif
    205 
    206   if (*env=='\0') unsetenv("LD_PRELOAD");
    207 }
    208 
    209 static void
    210 clearEnv()
    211 {
    212   if (isDbgLevel(DBG_ENV)) WRITE_MSG(2, "clearEnv()\n");
    213 
    214   unsetenv("RPM_FAKE_S_CONTEXT_REV");
    215   unsetenv("RPM_FAKE_S_CONTEXT_NR");
    216   unsetenv("RPM_FAKE_CTX");
    217   unsetenv("RPM_FAKE_FLAGS");
    218   unsetenv("RPM_FAKE_CHROOT");
    219   unsetenv("RPM_FAKE_NAMESPACE_MOUNTS");
    220 
    221   unsetenv("RPM_FAKE_RESOLVER_GID");
    222   unsetenv("RPM_FAKE_RESOLVER_UID");
    223   unsetenv("RPM_FAKE_RESOLVER");
    224   unsetenv("RPM_FAKE_PWSOCKET");
    225 
    226   unsetenv("RPM_FAKE_DEBUG");
    227 
    228   unsetPreloadEnv();
    229 }
    230 
    231 static int
    232 getDefaultEnv(char const *key, int dflt)
    233 {
    234   char		*env = getenv(key);
    235   int		res;
    236 
    237   if (env==0 || env[0]=='\0') res = dflt;
    238   else                        res = atoi(env);
    239 
    240   return res;
    241 }
    242 
    243   /// \returns true iff we are in ctx after leaving this function
    244 static bool
    245 setupContext(xid_t xid, char const **xid_str)
    246 {
    247   bool		res = false;
    248 
    249   if (vc_isSupported(vcFEATURE_MIGRATE)) {
    250     xid_t	rc=VC_NOCTX;
    251 
    252     if ((xid==VC_DYNAMIC_XID || !vc_is_dynamic_xid(xid)) &&
    253 	(rc=vc_ctx_create(xid, NULL))==VC_NOCTX &&
    254 	errno!=EEXIST) {
    255       perror(ENSC_WRAPPERS_PREFIX "vc_ctx_create()");
    256       exit(255);
    257     }
    258 
    259     if (rc!=VC_NOCTX) {
    260       char			buf[sizeof(xid_t)*3 + 128];
    261       size_t			l;
    262       struct vc_ctx_caps	caps;
    263       struct vc_ctx_flags	flags;
    264 
    265       strcpy(buf, "rpm-fake.so #");
    266       l = utilvserver_fmt_uint(buf+sizeof("rpm-fake.so #")-1, getppid());
    267       Evc_set_vhi_name(rc, vcVHI_CONTEXT, buf, sizeof("rpm-fake.so #")+l-1);
    268 
    269       caps.ccaps =  0ull;
    270       caps.cmask = ~0ull;
    271       caps.bcaps = ~vc_get_insecurebcaps();
    272       caps.bmask = ~0ull;
    273       Evc_set_ccaps(rc, &caps);
    274 
    275       flags.flagword = 0;
    276       flags.mask = VC_VXF_SC_HELPER;
    277       Evc_set_cflags(rc, &flags);
    278 
    279 	// context will be activated later...
    280 
    281       xid = rc;
    282       res = true;
    283       ctx_created = true;
    284     }
    285   }
    286 
    287   if (xid==VC_DYNAMIC_XID)
    288     *xid_str = 0;
    289   else {
    290     char		buf[sizeof(xid_t)*3 + 2];
    291     size_t		l;
    292 
    293     l        = utilvserver_fmt_uint(buf, xid); buf[l] = '\0';
    294     *xid_str = strdup(buf);
    295   }
    296 
    297   Ewrite(3, &xid, sizeof xid);
    298   return res;
    299 }
    300 
    301 #if 0
    302 static void
    303 initPwSocket()
    304 {
    305   char const *	sock_name = getenv("RPM_FAKE_PWSOCKET");
    306   if (sock_name!=0) {
    307     int flag;
    308     struct sockaddr_un	addr = {
    309       .sun_family = AF_UNIX,
    310     };
    311 
    312     strncpy(addr.sun_path, sock_name, sizeof(addr.sun_path)-1);
    313     addr.sun_path[sizeof(addr.sun_path)-1]='\0';
    314 
    315     if ((pw_sock=socket(AF_UNIX, SOCK_STREAM, 0))==-1 ||
    316 	connect(pw_sock, (struct sockaddr *)(&addr), sizeof addr)==-1 ||
    317 	(flag=fcntl(pw_sock, F_GETFD))==-1 ||
    318 	fcntl(pw_sock, F_SETFD, flag | FD_CLOEXEC)==-1) {
    319       perror(ENSC_WRAPPERS_PREFIX "error while initializing pw-socket");
    320       exit(255);
    321     }
    322   }
    323 }
    324 #else
    325 static void
    326 initPwSocket()
    327 {
    328   char const *	resolver = getenv("RPM_FAKE_RESOLVER");
    329   if (resolver==0) resolver=RESOLVER_PROG;
    330 
    331   if (resolver!=0 && *resolver!='\0') {
    332     int			res_sock[2];
    333     int			sync_pipe[2];
    334     pid_t		pid;
    335     char const *	uid=0;
    336     char const *	gid=0;
    337 
    338     uid=getenv("RPM_FAKE_RESOLVER_UID");
    339     gid=getenv("RPM_FAKE_RESOLVER_GID");
    340 
    341     if (socketpair(AF_UNIX, SOCK_STREAM, 0, res_sock)==-1 ||
    342 	pipe(sync_pipe)==-1 ||
    343 	fcntl(res_sock[0],  F_SETFD, FD_CLOEXEC)==-1 ||
    344 	fcntl(sync_pipe[0], F_SETFD, FD_CLOEXEC)==-1) {
    345       perror(ENSC_WRAPPERS_PREFIX "failed to create/initialize resolver-socket or pipe");
    346       exit(255);
    347     }
    348 
    349     pid = fork();
    350     if (pid==-1) {
    351       perror(ENSC_WRAPPERS_PREFIX "fork()");
    352       exit(255);
    353     }
    354 
    355     if (pid==0) {
    356       char const	*args[20];
    357       char const	**ptr  = args;
    358       char const 	*env[] = { "HOME=/", "PATH=/bin:/usr/bin", 0 };
    359       char const	*xid_str;
    360       char		flag_str[ sizeof(flags)*3 + 2];
    361       char		caps_str[ sizeof(caps)*3  + 2];
    362 
    363       clearEnv();
    364 
    365       setsid();
    366       dup2(res_sock[1],  0);
    367       dup2(res_sock[1],  1);
    368       if (sync_pipe[1]!=3) {
    369 	close(3);
    370 	dup2(sync_pipe[1], 3);
    371 	close(sync_pipe[1]);
    372       }
    373       close(res_sock[1]);
    374 	/* ... *socket[0] are marked as close-on-exec ...*/
    375 
    376       flag_str[utilvserver_fmt_uint(flag_str, flags)] = '\0';
    377       caps_str[utilvserver_fmt_uint(caps_str, caps)]  = '\0';
    378 
    379       *ptr++ = resolver;
    380       *ptr++ = "-F"; *ptr++ = flag_str;
    381       *ptr++ = "-C"; *ptr++ = caps_str;
    382       if (root)  { *ptr++ = "-r"; *ptr++ = ".";   }
    383       if (uid)   { *ptr++ = "-u"; *ptr++ = uid;   }
    384       if (gid)   { *ptr++ = "-g"; *ptr++ = gid;   }
    385 
    386       if (root) Echdir(root);
    387 
    388       if (setupContext(ctx, &xid_str)) { *ptr++ = "-s"; }
    389       else if (xid_str)                { *ptr++ = "-c"; *ptr++ = xid_str; }
    390 
    391       *ptr++ = 0;
    392       execve_func(resolver, (char **)args, (char **)env);
    393       perror(ENSC_WRAPPERS_PREFIX "failed to exec resolver");
    394       exit(255);
    395     }
    396     else {
    397       uint8_t		c;
    398 
    399       close(res_sock[1]);
    400       close(sync_pipe[1]);
    401       pw_sock   = res_sock[0];
    402       sync_sock = sync_pipe[0];
    403 
    404       if (read(sync_sock, &ctx, sizeof ctx)!=sizeof(ctx) ||
    405 	  read(sync_sock, &c, 1)!=1 ||
    406 	  write(pw_sock, ".", 1)!=1 ||
    407 	  read(pw_sock, &c,   1)!=1 ||
    408 	  c!='.') {
    409 	WRITE_MSG(2, ENSC_WRAPPERS_PREFIX "failed to initialize communication with resolver\n");
    410 	exit(255);
    411       }
    412 
    413       if (wait4(pid, 0, WNOHANG,0)==-1) {
    414 	WRITE_MSG(2, ENSC_WRAPPERS_PREFIX" unexpected initialization-error of resolver\n");
    415 	exit(255);
    416       }
    417     }
    418   }
    419 }
    420 #endif
    421 
    422 static void
    423 reduceCapabilities()
    424 {
    425   int retried = 0;
    426   struct __user_cap_header_struct header;
    427   struct __user_cap_data_struct user[2];
    428 
    429   header.version = _LINUX_CAPABILITY_VERSION_3;
    430   header.pid     = 0;
    431 
    432 retry:
    433   if (capget(&header, user)==-1) {
    434     if (!retried &&
    435 	header.version != _LINUX_CAPABILITY_VERSION_3) {
    436       header.version = _LINUX_CAPABILITY_VERSION_1;
    437       retried = 1;
    438       goto retry;
    439     }
    440     perror("capget()");
    441     exit(wrapper_exit_code);
    442   }
    443 
    444   user[0].effective   &= ~(1<<CAP_MKNOD);
    445   user[0].permitted   &= ~(1<<CAP_MKNOD);
    446   user[0].inheritable &= ~(1<<CAP_MKNOD);
    447 
    448   if (capset(&header, user)==-1) {
    449     perror("capset()");
    450     exit(wrapper_exit_code);
    451   }
    452 }
    453 
    454 static void
    455 initEnvironment()
    456 {
    457   int		syscall_rev;
    458   int		syscall_nr;
    459 
    460   if (is_initialized) return;
    461 
    462   syscall_rev = getDefaultEnv("RPM_FAKE_S_CONTEXT_REV", 0);
    463   syscall_nr  = getDefaultEnv("RPM_FAKE_S_CONTEXT_NR",  273);
    464 
    465 #ifdef VC_ENABLE_API_LEGACY
    466   {
    467     extern void vc_init_internal_legacy(int ctx_rev, int ctx_number,
    468 					int ipv4_rev, int ipv4_number);
    469 
    470     vc_init_internal_legacy(syscall_rev, syscall_nr, 3, 274);
    471   }
    472 #endif
    473 
    474   ctx       = getDefaultEnv("RPM_FAKE_CTX",  VC_DYNAMIC_XID);
    475   caps      = getDefaultEnv("RPM_FAKE_CAP",  ~0x3404040f);
    476   flags     = getDefaultEnv("RPM_FAKE_FLAGS", 0);
    477   root      = getenv("RPM_FAKE_CHROOT");
    478   mnts      = getenv("RPM_FAKE_NAMESPACE_MOUNTS");
    479   if (mnts && *mnts) mnts = strdup(mnts);
    480   else               mnts = 0;
    481 
    482 #if DEBUG
    483   if (isDbgLevel(DBG_VERBOSE1))
    484     dprintf(2, "ctx=%u, caps=%016x, flags=%016x,\nroot='%s',\nmnts='%s'\n",
    485 	    ctx, caps, flags, root, mnts);
    486 #endif
    487 
    488   is_initialized = true;
    489 }
    490 
    491 static void
    492 initSymbols()
    493 {
    494     //INIT(RTLD_NEXT, rpm_execcon);
    495   INIT(RTLD_NEXT, execve);
    496   INIT(RTLD_NEXT, getgrnam);
    497   INIT(RTLD_NEXT, getpwnam);
    498   INIT(RTLD_NEXT, endpwent);
    499   INIT(RTLD_NEXT, endgrent);
    500   INIT(RTLD_NEXT, chroot);
    501 }
    502 
    503 void
    504 initRPMFake()
    505 {
    506   if (getenv("RPM_FAKE_VERSION")) showVersion();
    507   if (getenv("RPM_FAKE_HELP"))    showHelp();
    508 
    509   debug_level = getDefaultEnv("RPM_FAKE_DEBUG", 0);
    510 
    511   if (isDbgLevel(DBG_INIT)) WRITE_MSG(2, ">>>>> initRPMFake <<<<<\n");
    512 
    513   reduceCapabilities();
    514   initSymbols();
    515   initEnvironment();
    516   initPwSocket();
    517 
    518 #if 0
    519   if (isDbgLevel(DBG_VARIABLES|DBG_VERBOSE2)) {
    520 
    521   }
    522 #endif
    523 }
    524 
    525 void
    526 exitRPMFake()
    527 {
    528   if (isDbgLevel(DBG_INIT)) WRITE_MSG(2, ">>>>> exitRPMFake <<<<<\n");
    529   if (pw_sock!=-1) {
    530     uint8_t	c;
    531     if (read(sync_sock, &c, 1)!=1) { /*...*/ }
    532     if (write(pw_sock, "Q", 1)!=1) { /*...*/ }
    533     if (ctx_created) {
    534       if (vc_isSupported(vcFEATURE_VWAIT)) {
    535 	if (vc_wait_exit(ctx)==-1) { /*...*/ }
    536       }
    537       else {
    538 	/* this can race */
    539 	if (read(sync_sock, &c, 1)!=0) { /*...*/}
    540       }
    541     }
    542   }
    543 }
    544 
    545 
    546   //============   the worker part   ===========
    547 
    548 
    549 static bool
    550 doPwStringRequest(uint32_t *result, char style, char const *name)
    551 {
    552   uint32_t	len = strlen(name);
    553   uint8_t	code;
    554   uint8_t	c;
    555 
    556   return (TEMP_FAILURE_RETRY(read (sync_sock, &c, 1))==1 &&
    557 	  TEMP_FAILURE_RETRY(write(pw_sock, &style, 1))==1 &&
    558 	  TEMP_FAILURE_RETRY(write(pw_sock, &len,   sizeof len))==sizeof(len) &&
    559 	  TEMP_FAILURE_RETRY(write(pw_sock, name,   len))==(ssize_t)(len) &&
    560 	  TEMP_FAILURE_RETRY(read (pw_sock, &code,  sizeof code))==sizeof(code) &&
    561 	  TEMP_FAILURE_RETRY(read (pw_sock, result, sizeof *result))==sizeof(*result) &&
    562 	  code!=0);
    563 }
    564 
    565 struct passwd *
    566 getpwnam(const char * name)
    567 {
    568   if (pw_sock==-1) return getpwnam_func(name);
    569   else {
    570     uint32_t			id;
    571     static struct passwd	res = {
    572       .pw_passwd = "*",
    573       .pw_gid    = -1,
    574       .pw_gecos  = "",
    575       .pw_dir    = "/",
    576       .pw_shell  = "/bin/false"
    577     };
    578 
    579     res.pw_name = (char *)(name);
    580     if (!doPwStringRequest(&id, 'P', name)) return 0;
    581     res.pw_uid = id;
    582 
    583     return &res;
    584   }
    585 }
    586 
    587 struct group *
    588 getgrnam(const char * name)
    589 {
    590   if (pw_sock==-1) return getgrnam_func(name);
    591   else {
    592     uint32_t			id;
    593     static struct group		res = {
    594       .gr_passwd = "*",
    595       .gr_mem    = 0
    596     };
    597 
    598     res.gr_name = (char *)(name);
    599     if (!doPwStringRequest(&id, 'G', name)) return 0;
    600     res.gr_gid = id;
    601 
    602     return &res;
    603   }
    604 }
    605 
    606 void
    607 endgrent()
    608 {
    609   if (pw_sock==-1) endgrent_func();
    610   TEMP_FAILURE_RETRY(write(pw_sock, "Cg", 2));
    611 }
    612 
    613 void
    614 endpwent()
    615 {
    616   if (pw_sock==-1) endpwent_func();
    617   TEMP_FAILURE_RETRY(write(pw_sock, "Cp", 2));
    618 }
    619 
    620 
    621 static int
    622 execvWorker(char const *path, char * const argv[], char * const envp[])
    623 {
    624   int		res = -1;
    625 
    626   if (vc_isSupported(vcFEATURE_MIGRATE))
    627     res = vc_ctx_migrate(ctx, 0);
    628   else {
    629 #ifdef VC_ENABLE_API_COMPAT
    630     res = vc_new_s_context(ctx,caps,flags);
    631 #else
    632     WRITE_MSG(2, ENSC_WRAPPERS_PREFIX "can not change context: migrate kernel feature missing and 'compat' API disabled\n");
    633 #endif
    634   }
    635 
    636   clearEnv();
    637 
    638   if (res!=-1)
    639     res=execve_func(path, argv, envp);
    640 
    641   return res;
    642 }
    643 
    644 struct ExecvParams
    645 {
    646     char const *	path;
    647     char * const *	argv;
    648     char * const *	envp;
    649     char const *	mnts;
    650 };
    651 
    652 static int
    653 removeNamespaceMountsChild(struct ExecvParams const *params)
    654 {
    655   char			buf[strlen(params->mnts)+1], *ptr;
    656 
    657   strcpy(buf, params->mnts);
    658   ptr = strtok(buf, ":");
    659   while (ptr) {
    660     if (umount2(ptr, 0)==-1) {
    661 	// FIXME: What is the semantic for CLONE_NEWNS? Is it ok that mounts in
    662 	// chroots are visible only, when chroot is on /dev/root?
    663 	//
    664 	// For now, ignore any errors, but future versions should handle them.
    665 
    666 	//return -1;
    667     }
    668     ptr = strtok(0, ":");
    669   }
    670 
    671   return execvWorker(params->path, params->argv, params->envp);
    672 }
    673 
    674 static int
    675 removeNamespaceMounts(char const *path,
    676 		      char * const argv[], char * const envp[])
    677 {
    678   if (mnts==0) return execvWorker(path, argv, envp);
    679 
    680   {
    681     int				status;
    682     pid_t			p, pid;
    683     struct ExecvParams		params;
    684 
    685     params.path = path;
    686     params.argv = argv;
    687     params.envp = envp;
    688     params.mnts = mnts;
    689 
    690       // the rpmlib signal-handler is still active; use the default one to
    691       // make wait4() working...
    692     signal(SIGCHLD, SIG_DFL);
    693 
    694 #ifdef NDEBUG
    695     pid = sys_clone(CLONE_NEWNS|SIGCHLD|CLONE_VFORK, 0);
    696 #else
    697     pid = sys_clone(CLONE_NEWNS|SIGCHLD, 0);
    698 #endif
    699 
    700     switch (pid) {
    701       case -1	:  return -1;
    702       case 0	:  _exit(removeNamespaceMountsChild(&params));
    703       default	:  break;
    704     }
    705 
    706     while ((p=wait4(pid, &status, 0,0))==-1 &&
    707 	   (errno==EINTR || errno==EAGAIN)) ;
    708 
    709     if (p==-1)   return -1;
    710 
    711     if (WIFEXITED(status))   _exit(WEXITSTATUS(status));
    712     if (WIFSIGNALED(status)) kill(getpid(), WTERMSIG(status));
    713 
    714     return -1;
    715   }
    716 }
    717 
    718 
    719 int
    720 execv(char const *path, char * const argv[])
    721 {
    722   extern char **environ;
    723 
    724   if (isDbgLevel(DBG_EXECV)) {
    725     WRITE_MSG(2, "execv('");
    726     WRITE_STR(2, path);
    727     WRITE_MSG(2, "', ...)\n");
    728   }
    729 
    730   if (!chroot_seen) {
    731     if (isDbgLevel(DBG_VERBOSE1|DBG_EXECV))
    732       WRITE_MSG(2, "chroot() not called yet; bypassing execve() wrapper\n");
    733     return execve_func(path, argv, environ);
    734   }
    735 
    736   return removeNamespaceMounts(path, argv, environ);
    737 }
    738 
    739 int
    740 rpm_execcon(unsigned int UNUSED verified,
    741 	    const char *filename,
    742 	    char *const argv[], char *const envp[])
    743 {
    744   if (isDbgLevel(DBG_EXECV)) {
    745     WRITE_MSG(2, "rpm_execcon(..., '");
    746     WRITE_STR(2, filename);
    747     WRITE_MSG(2, "', ...)\n");
    748   }
    749 
    750   return removeNamespaceMounts(filename, argv, envp);
    751 }
    752 
    753 int
    754 chroot(char const *path)
    755 {
    756   chroot_seen = true;
    757   return chroot_func(path);
    758 }
    759 
    760 int
    761 is_selinux_enabled()
    762 {
    763   return 0;
    764 }