#include <sys/mount.h>
#include <linux/fs.h>
#include <linux/oom.h>
+#include <sys/poll.h>
#ifdef HAVE_PAM
#include <security/pam_appl.h>
#include "utmp-wtmp.h"
#include "def.h"
#include "loopback-setup.h"
+#include "path-util.h"
/* This assumes there is a 'tty' group */
#define TTY_MODE 0620
static int setup_pam(
const char *name,
const char *user,
+ uid_t uid,
const char *tty,
char ***pam_env,
int fds[], unsigned n_fds) {
open here that have been opened by PAM. */
close_many(fds, n_fds);
- /* Wait until our parent died. This will most likely
- * not work since the kernel does not allow
- * unprivileged parents kill their privileged children
- * this way. We rely on the control groups kill logic
+ /* Drop privileges - we don't need any to pam_close_session
+ * and this will make PR_SET_PDEATHSIG work in most cases.
+ * If this fails, ignore the error - but expect sd-pam threads
+ * to fail to exit normally */
+ if (setresuid(uid, uid, uid) < 0)
+ log_error("Error: Failed to setresuid() in sd-pam: %s", strerror(-r));
+
+ /* Wait until our parent died. This will only work if
+ * the above setresuid() succeeds, otherwise the kernel
+ * will not allow unprivileged parents kill their privileged
+ * children this way. We rely on the control groups kill logic
* to do the rest for us. */
if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0)
goto child_finish;
/* This resulting string must fit in 10 chars (i.e. the length
* of "/sbin/init") to look pretty in /bin/ps */
- p = file_name_from_path(path);
+ p = path_get_file_name(path);
if (isempty(p)) {
rename_process("(...)");
return;
bool confirm_spawn,
CGroupBonding *cgroup_bondings,
CGroupAttribute *cgroup_attributes,
+ const char *cgroup_suffix,
+ int idle_pipe[2],
pid_t *ret) {
pid_t pid;
goto fail_child;
}
+ if (idle_pipe) {
+ if (idle_pipe[1] >= 0)
+ close_nointr_nofail(idle_pipe[1]);
+ if (idle_pipe[0] >= 0) {
+ fd_wait_for_event(idle_pipe[0], POLLHUP, DEFAULT_TIMEOUT_USEC);
+ close_nointr_nofail(idle_pipe[0]);
+ }
+ }
+
/* Close sockets very early to make sure we don't
* block init reexecution because it cannot bind its
* sockets */
}
if (!keep_stdout) {
- err = setup_output(context, socket_fd, file_name_from_path(command->path), apply_tty_stdin);
+ err = setup_output(context, socket_fd, path_get_file_name(command->path), apply_tty_stdin);
if (err < 0) {
r = EXIT_STDOUT;
goto fail_child;
}
}
- err = setup_error(context, socket_fd, file_name_from_path(command->path), apply_tty_stdin);
+ err = setup_error(context, socket_fd, path_get_file_name(command->path), apply_tty_stdin);
if (err < 0) {
r = EXIT_STDERR;
goto fail_child;
}
if (cgroup_bondings) {
- err = cgroup_bonding_install_list(cgroup_bondings, 0);
+ err = cgroup_bonding_install_list(cgroup_bondings, 0, cgroup_suffix);
if (err < 0) {
r = EXIT_CGROUP;
goto fail_child;
#ifdef HAVE_PAM
if (context->pam_name && username) {
- err = setup_pam(context->pam_name, username, context->tty_path, &pam_env, fds, n_fds);
+ err = setup_pam(context->pam_name, username, uid, context->tty_path, &pam_env, fds, n_fds);
if (err < 0) {
r = EXIT_PAM;
goto fail_child;
if (!context->rlimit[i])
continue;
- if (setrlimit(i, context->rlimit[i]) < 0) {
+ if (setrlimit_closest(i, context->rlimit[i]) < 0) {
err = -errno;
r = EXIT_LIMITS;
goto fail_child;
* sure that when we kill the cgroup the process will be
* killed too). */
if (cgroup_bondings)
- cgroup_bonding_install_list(cgroup_bondings, pid);
+ cgroup_bonding_install_list(cgroup_bondings, pid, cgroup_suffix);
log_debug("Forked %s as %lu", command->path, (unsigned long) pid);