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(¶ms)); 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 }