/* Execute LINE as a shell command, returning its status. */ static int do_system (const char *line) { int status, save; pid_t pid; struct sigaction sa; #ifndef _LIBC_REENTRANT struct sigaction intr, quit; #endif sigset_t omask; sa.sa_handler = SIG_IGN; sa.sa_flags = 0; __sigemptyset (&sa.sa_mask); DO_LOCK (); if (ADD_REF () == 0) { if (__sigaction (SIGINT, &sa, &intr) < 0) { SUB_REF (); goto out; } if (__sigaction (SIGQUIT, &sa, &quit) < 0) { save = errno; SUB_REF (); goto out_restore_sigint; } } DO_UNLOCK (); /* We reuse the bitmap in the 'sa' structure. */ __sigaddset (&sa.sa_mask, SIGCHLD); save = errno; if (__sigprocmask (SIG_BLOCK, &sa.sa_mask, &omask) < 0) { #ifndef _LIBC if (errno == ENOSYS) __set_errno (save); else #endif { DO_LOCK (); if (SUB_REF () == 0) { save = errno; (void) __sigaction (SIGQUIT, &quit, (struct sigaction *) NULL); out_restore_sigint: (void) __sigaction (SIGINT, &intr, (struct sigaction *) NULL); __set_errno (save); } out: DO_UNLOCK (); return -1; } } #ifdef CLEANUP_HANDLER CLEANUP_HANDLER; #endif #ifdef FORK pid = FORK (); #else pid = __fork (); #endif if (pid == (pid_t) 0) { /* Child side. */ const char *new_argv[4]; new_argv[0] = SHELL_NAME; new_argv[1] = "-c"; new_argv[2] = line; new_argv[3] = NULL; /* Restore the signals. */ (void) __sigaction (SIGINT, &intr, (struct sigaction *) NULL); (void) __sigaction (SIGQUIT, &quit, (struct sigaction *) NULL); (void) __sigprocmask (SIG_SETMASK, &omask, (sigset_t *) NULL); INIT_LOCK (); /* Exec the shell. */ (void) __execve (SHELL_PATH, (char *const *) new_argv, __environ); _exit (127); } else if (pid < (pid_t) 0) /* The fork failed. */ status = -1; else /* Parent side. */ { /* Note the system() is a cancellation point. But since we call waitpid() which itself is a cancellation point we do not have to do anything here. */ if (TEMP_FAILURE_RETRY (__waitpid (pid, &status, 0)) != pid) status = -1; } #ifdef CLEANUP_HANDLER CLEANUP_RESET; #endif save = errno; DO_LOCK (); if ((SUB_REF () == 0 && (__sigaction (SIGINT, &intr, (struct sigaction *) NULL) | __sigaction (SIGQUIT, &quit, (struct sigaction *) NULL)) != 0) || __sigprocmask (SIG_SETMASK, &omask, (sigset_t *) NULL) != 0) { #ifndef _LIBC /* glibc cannot be used on systems without waitpid. */ if (errno == ENOSYS) __set_errno (save); else #endif status = -1; } DO_UNLOCK (); return status; }
int kernel_execve(const char *filename, char *const argv[], char *const envp[]) { return __execve(filename, argv, envp, current); }
/* Execute PATH with arguments ARGV and environment from `environ'. */ int execv (const char *path, char *const argv[]) { return __execve (path, argv, __environ); }
int _private_execve(const char *filename, char *const argv [], char *const envp[]) { _gfs_hook_debug_v(fputs("Hooking execve\n", stderr)); return (__execve(filename, argv, envp)); }
/* Spawn a new process executing PATH with the attributes describes in *ATTRP. Before running the process perform the actions described in FILE-ACTIONS. */ int __spawni (pid_t *pid, const char *file, const posix_spawn_file_actions_t *file_actions, const posix_spawnattr_t *attrp, char *const argv[], char *const envp[], int xflags) { pid_t new_pid; char *path, *p, *name; size_t len; size_t pathlen; /* Do this once. */ short int flags = attrp == NULL ? 0 : attrp->__flags; /* Generate the new process. */ if ((flags & POSIX_SPAWN_USEVFORK) != 0 /* If no major work is done, allow using vfork. Note that we might perform the path searching. But this would be done by a call to execvp(), too, and such a call must be OK according to POSIX. */ || ((flags & (POSIX_SPAWN_SETSIGMASK | POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSCHEDPARAM | POSIX_SPAWN_SETSCHEDULER | POSIX_SPAWN_SETPGROUP | POSIX_SPAWN_RESETIDS)) == 0 && file_actions == NULL)) new_pid = __vfork (); else new_pid = __fork (); if (new_pid != 0) { if (new_pid < 0) return errno; /* The call was successful. Store the PID if necessary. */ if (pid != NULL) *pid = new_pid; return 0; } /* Set signal mask. */ if ((flags & POSIX_SPAWN_SETSIGMASK) != 0 && __sigprocmask (SIG_SETMASK, &attrp->__ss, NULL) != 0) _exit (SPAWN_ERROR); /* Set signal default action. */ if ((flags & POSIX_SPAWN_SETSIGDEF) != 0) { /* We have to iterate over all signals. This could possibly be done better but it requires system specific solutions since the sigset_t data type can be very different on different architectures. */ int sig; struct sigaction sa; memset (&sa, '\0', sizeof (sa)); sa.sa_handler = SIG_DFL; for (sig = 1; sig <= _NSIG; ++sig) if (__sigismember (&attrp->__sd, sig) != 0 && __sigaction (sig, &sa, NULL) != 0) _exit (SPAWN_ERROR); } #ifdef _POSIX_PRIORITY_SCHEDULING /* Set the scheduling algorithm and parameters. */ if ((flags & (POSIX_SPAWN_SETSCHEDPARAM | POSIX_SPAWN_SETSCHEDULER)) == POSIX_SPAWN_SETSCHEDPARAM) { if (__sched_setparam (0, &attrp->__sp) == -1) _exit (SPAWN_ERROR); } else if ((flags & POSIX_SPAWN_SETSCHEDULER) != 0) { if (__sched_setscheduler (0, attrp->__policy, &attrp->__sp) == -1) _exit (SPAWN_ERROR); } #endif /* Set the process group ID. */ if ((flags & POSIX_SPAWN_SETPGROUP) != 0 && __setpgid (0, attrp->__pgrp) != 0) _exit (SPAWN_ERROR); /* Set the effective user and group IDs. */ if ((flags & POSIX_SPAWN_RESETIDS) != 0 && (local_seteuid (__getuid ()) != 0 || local_setegid (__getgid ()) != 0)) _exit (SPAWN_ERROR); /* Execute the file actions. */ if (file_actions != NULL) { int cnt; struct rlimit64 fdlimit; bool have_fdlimit = false; for (cnt = 0; cnt < file_actions->__used; ++cnt) { struct __spawn_action *action = &file_actions->__actions[cnt]; switch (action->tag) { case spawn_do_close: if (close_not_cancel (action->action.close_action.fd) != 0) { if (! have_fdlimit) { __getrlimit64 (RLIMIT_NOFILE, &fdlimit); have_fdlimit = true; } /* Only signal errors for file descriptors out of range. */ if (action->action.close_action.fd < 0 || action->action.close_action.fd >= fdlimit.rlim_cur) /* Signal the error. */ _exit (SPAWN_ERROR); } break; case spawn_do_open: { int new_fd = open_not_cancel (action->action.open_action.path, action->action.open_action.oflag | O_LARGEFILE, action->action.open_action.mode); if (new_fd == -1) /* The `open' call failed. */ _exit (SPAWN_ERROR); /* Make sure the desired file descriptor is used. */ if (new_fd != action->action.open_action.fd) { if (__dup2 (new_fd, action->action.open_action.fd) != action->action.open_action.fd) /* The `dup2' call failed. */ _exit (SPAWN_ERROR); if (close_not_cancel (new_fd) != 0) /* The `close' call failed. */ _exit (SPAWN_ERROR); } } break; case spawn_do_dup2: if (__dup2 (action->action.dup2_action.fd, action->action.dup2_action.newfd) != action->action.dup2_action.newfd) /* The `dup2' call failed. */ _exit (SPAWN_ERROR); break; } } } if ((xflags & SPAWN_XFLAGS_USE_PATH) == 0 || strchr (file, '/') != NULL) { /* The FILE parameter is actually a path. */ __execve (file, argv, envp); maybe_script_execute (file, argv, envp, xflags); /* Oh, oh. `execve' returns. This is bad. */ _exit (SPAWN_ERROR); } /* We have to search for FILE on the path. */ path = getenv ("PATH"); if (path == NULL) { /* There is no `PATH' in the environment. The default search path is the current directory followed by the path `confstr' returns for `_CS_PATH'. */ len = confstr (_CS_PATH, (char *) NULL, 0); path = (char *) __alloca (1 + len); path[0] = ':'; (void) confstr (_CS_PATH, path + 1, len); } len = strlen (file) + 1; pathlen = strlen (path); name = __alloca (pathlen + len + 1); /* Copy the file name at the top. */ name = (char *) memcpy (name + pathlen + 1, file, len); /* And add the slash. */ *--name = '/'; p = path; do { char *startp; path = p; p = __strchrnul (path, ':'); if (p == path) /* Two adjacent colons, or a colon at the beginning or the end of `PATH' means to search the current directory. */ startp = name + 1; else startp = (char *) memcpy (name - (p - path), path, p - path); /* Try to execute this name. If it works, execv will not return. */ __execve (startp, argv, envp); maybe_script_execute (startp, argv, envp, xflags); switch (errno) { case EACCES: case ENOENT: case ESTALE: case ENOTDIR: /* Those errors indicate the file is missing or not executable by us, in which case we want to just try the next path directory. */ break; default: /* Some other error means we found an executable file, but something went wrong executing it; return the error to our caller. */ _exit (SPAWN_ERROR); } } while (*p++ != '\0'); /* Return with an error. */ _exit (SPAWN_ERROR); }