#include "loopback-setup.h"
#include "path-util.h"
+#define IDLE_TIMEOUT_USEC (5*USEC_PER_SEC)
+
/* 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;
}
#endif
-static int do_capability_bounding_set_drop(uint64_t drop) {
- unsigned long i;
- cap_t old_cap = NULL, new_cap = NULL;
- cap_flag_value_t fv;
- int r;
-
- /* If we are run as PID 1 we will lack CAP_SETPCAP by default
- * in the effective set (yes, the kernel drops that when
- * executing init!), so get it back temporarily so that we can
- * call PR_CAPBSET_DROP. */
-
- old_cap = cap_get_proc();
- if (!old_cap)
- return -errno;
-
- if (cap_get_flag(old_cap, CAP_SETPCAP, CAP_EFFECTIVE, &fv) < 0) {
- r = -errno;
- goto finish;
- }
-
- if (fv != CAP_SET) {
- static const cap_value_t v = CAP_SETPCAP;
-
- new_cap = cap_dup(old_cap);
- if (!new_cap) {
- r = -errno;
- goto finish;
- }
-
- if (cap_set_flag(new_cap, CAP_EFFECTIVE, 1, &v, CAP_SET) < 0) {
- r = -errno;
- goto finish;
- }
-
- if (cap_set_proc(new_cap) < 0) {
- r = -errno;
- goto finish;
- }
- }
-
- for (i = 0; i <= cap_last_cap(); i++)
- if (drop & ((uint64_t) 1ULL << (uint64_t) i)) {
- if (prctl(PR_CAPBSET_DROP, i) < 0) {
- r = -errno;
- goto finish;
- }
- }
-
- r = 0;
-
-finish:
- if (new_cap)
- cap_free(new_cap);
-
- if (old_cap) {
- cap_set_proc(old_cap);
- cap_free(old_cap);
- }
-
- return r;
-}
-
static void rename_process_from_path(const char *path) {
char process_name[11];
const char *p;
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);
+ fd_wait_for_event(idle_pipe[0], POLLHUP, IDLE_TIMEOUT_USEC);
close_nointr_nofail(idle_pipe[0]);
}
}
goto fail_child;
}
- if (context->timer_slack_nsec_set)
+ if (context->timer_slack_nsec != (nsec_t) -1)
if (prctl(PR_SET_TIMERSLACK, context->timer_slack_nsec) < 0) {
err = -errno;
r = EXIT_TIMERSLACK;
#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->capability_bounding_set_drop) {
- err = do_capability_bounding_set_drop(context->capability_bounding_set_drop);
+ err = capability_bounding_set_drop(context->capability_bounding_set_drop, false);
if (err < 0) {
r = EXIT_CAPABILITIES;
goto fail_child;
c->send_sigkill = true;
c->control_group_persistent = -1;
c->ignore_sigpipe = true;
+ c->timer_slack_nsec = (nsec_t) -1;
}
void exec_context_done(ExecContext *c) {
fputs("\n", f);
}
- if (c->timer_slack_nsec_set)
+ if (c->timer_slack_nsec != (nsec_t) -1)
fprintf(f, "%sTimerSlackNSec: %lu\n", prefix, c->timer_slack_nsec);
fprintf(f,