X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fexecute.c;h=250d53a424a07655929439929a62a56d6eec99c0;hp=1a5f09d324d6f12d47a7c08bfa1c2432bdfda079;hb=9f84624270432cdff35c4f499fbdb9e0f94fe705;hpb=0f1df8e1691f6a0397153860caf28fda38231833 diff --git a/src/execute.c b/src/execute.c index 1a5f09d32..250d53a42 100644 --- a/src/execute.c +++ b/src/execute.c @@ -56,6 +56,7 @@ #include "missing.h" #include "utmp-wtmp.h" #include "def.h" +#include "loopback-setup.h" /* This assumes there is a 'tty' group */ #define TTY_MODE 0620 @@ -187,9 +188,9 @@ static int connect_logger_as(const ExecContext *context, ExecOutput output, cons zero(sa); sa.sa.sa_family = AF_UNIX; - strncpy(sa.un.sun_path, LOGGER_SOCKET, sizeof(sa.un.sun_path)); + strncpy(sa.un.sun_path, STDOUT_SYSLOG_BRIDGE_SOCKET, sizeof(sa.un.sun_path)); - if (connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + sizeof(LOGGER_SOCKET) - 1) < 0) { + if (connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + sizeof(STDOUT_SYSLOG_BRIDGE_SOCKET) - 1) < 0) { close_nointr_nofail(fd); return -errno; } @@ -549,82 +550,6 @@ static int restore_confirm_stdio(const ExecContext *context, return 0; } -static int get_group_creds(const char *groupname, gid_t *gid) { - struct group *g; - unsigned long lu; - - assert(groupname); - assert(gid); - - /* We enforce some special rules for gid=0: in order to avoid - * NSS lookups for root we hardcode its data. */ - - if (streq(groupname, "root") || streq(groupname, "0")) { - *gid = 0; - return 0; - } - - if (safe_atolu(groupname, &lu) >= 0) { - errno = 0; - g = getgrgid((gid_t) lu); - } else { - errno = 0; - g = getgrnam(groupname); - } - - if (!g) - return errno != 0 ? -errno : -ESRCH; - - *gid = g->gr_gid; - return 0; -} - -static int get_user_creds(const char **username, uid_t *uid, gid_t *gid, const char **home) { - struct passwd *p; - unsigned long lu; - - assert(username); - assert(*username); - assert(uid); - assert(gid); - assert(home); - - /* We enforce some special rules for uid=0: in order to avoid - * NSS lookups for root we hardcode its data. */ - - if (streq(*username, "root") || streq(*username, "0")) { - *username = "root"; - *uid = 0; - *gid = 0; - *home = "/root"; - return 0; - } - - if (safe_atolu(*username, &lu) >= 0) { - errno = 0; - p = getpwuid((uid_t) lu); - - /* If there are multiple users with the same id, make - * sure to leave $USER to the configured value instead - * of the first occurrence in the database. However if - * the uid was configured by a numeric uid, then let's - * pick the real username from /etc/passwd. */ - if (*username && p) - *username = p->pw_name; - } else { - errno = 0; - p = getpwnam(*username); - } - - if (!p) - return errno != 0 ? -errno : -ESRCH; - - *uid = p->pw_uid; - *gid = p->pw_gid; - *home = p->pw_dir; - return 0; -} - static int enforce_groups(const ExecContext *context, const char *username, gid_t gid) { bool keep_groups = false; int r; @@ -636,9 +561,12 @@ static int enforce_groups(const ExecContext *context, const char *username, gid_ if (context->group || username) { - if (context->group) - if ((r = get_group_creds(context->group, &gid)) < 0) + if (context->group) { + const char *g = context->group; + + if ((r = get_group_creds(&g, &gid)) < 0) return r; + } /* First step, initialize groups from /etc/groups */ if (username && gid != 0) { @@ -673,13 +601,16 @@ static int enforce_groups(const ExecContext *context, const char *username, gid_ k = 0; STRV_FOREACH(i, context->supplementary_groups) { + const char *g; if (k >= ngroups_max) { free(gids); return -E2BIG; } - if ((r = get_group_creds(*i, gids+k)) < 0) { + g = *i; + r = get_group_creds(&g, gids+k); + if (r < 0) { free(gids); return r; } @@ -843,7 +774,7 @@ static int setup_pam( /* This string must fit in 10 chars (i.e. the length * of "/sbin/init") */ - rename_process("sd:pam"); + rename_process("sd(PAM)"); /* Make sure we don't keep open the passed fds in this child. We assume that otherwise only those fds are @@ -861,13 +792,20 @@ static int setup_pam( /* Check if our parent process might already have * died? */ if (getppid() == parent_pid) { - if (sigwait(&ss, &sig) < 0) - goto child_finish; + for (;;) { + if (sigwait(&ss, &sig) < 0) { + if (errno == EINTR) + continue; + + goto child_finish; + } - assert(sig == SIGTERM); + assert(sig == SIGTERM); + break; + } } - /* Only if our parent died we'll end the session */ + /* If our parent died we'll end the session */ if (getppid() != parent_pid) if ((pam_code = pam_close_session(handle, PAM_DATA_SILENT)) != PAM_SUCCESS) goto child_finish; @@ -891,6 +829,9 @@ static int setup_pam( * might have opened it, but we don't want this fd around. */ closelog(); + *pam_env = e; + e = NULL; + return 0; fail: @@ -954,12 +895,9 @@ static int do_capability_bounding_set_drop(uint64_t drop) { } } - for (i = 0; i <= MAX(63LU, (unsigned long) CAP_LAST_CAP); i++) + for (i = 0; i <= cap_last_cap(); i++) if (drop & ((uint64_t) 1ULL << (uint64_t) i)) { if (prctl(PR_CAPBSET_DROP, i) < 0) { - if (errno == EINVAL) - break; - r = -errno; goto finish; } @@ -989,6 +927,7 @@ int exec_spawn(ExecCommand *command, bool apply_tty_stdin, bool confirm_spawn, CGroupBonding *cgroup_bondings, + CGroupAttribute *cgroup_attributes, pid_t *ret) { pid_t pid; @@ -1032,9 +971,11 @@ int exec_spawn(ExecCommand *command, log_debug("About to execute: %s", line); free(line); - if (cgroup_bondings) - if ((r = cgroup_bonding_realize_list(cgroup_bondings))) - goto fail_parent; + r = cgroup_bonding_realize_list(cgroup_bondings); + if (r < 0) + goto fail_parent; + + cgroup_attribute_apply_list(cgroup_attributes, cgroup_bondings); if ((pid = fork()) < 0) { r = -errno; @@ -1056,7 +997,7 @@ int exec_spawn(ExecCommand *command, /* This string must fit in 10 chars (i.e. the length * of "/sbin/init") */ - rename_process("sd.exec"); + rename_process("sd(EXEC)"); /* We reset exactly these signals, since they are the * only ones we set to SIG_IGN in the main daemon. All @@ -1229,7 +1170,7 @@ int exec_spawn(ExecCommand *command, } if (context->utmp_id) - utmp_put_init_process(0, context->utmp_id, getpid(), getsid(0), context->tty_path); + utmp_put_init_process(context->utmp_id, getpid(), getsid(0), context->tty_path); if (context->user) { username = context->user; @@ -1253,7 +1194,7 @@ int exec_spawn(ExecCommand *command, } if (apply_permissions) - if (enforce_groups(context, username, uid) < 0) { + if (enforce_groups(context, username, gid) < 0) { r = EXIT_GROUP; goto fail_child; } @@ -1262,12 +1203,20 @@ int exec_spawn(ExecCommand *command, #ifdef HAVE_PAM if (context->pam_name && username) { - if (setup_pam(context->pam_name, username, context->tty_path, &pam_env, fds, n_fds) < 0) { + if (setup_pam(context->pam_name, username, context->tty_path, &pam_env, fds, n_fds) != 0) { r = EXIT_PAM; goto fail_child; } } #endif + if (context->private_network) { + if (unshare(CLONE_NEWNET) < 0) { + r = EXIT_NETWORK; + goto fail_child; + } + + loopback_setup(); + } if (strv_length(context->read_write_dirs) > 0 || strv_length(context->read_only_dirs) > 0 || @@ -1462,7 +1411,7 @@ fail_parent: void exec_context_init(ExecContext *c) { assert(c); - c->umask = 0002; + c->umask = 0022; c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, 0); c->cpu_sched_policy = SCHED_OTHER; c->syslog_priority = LOG_DAEMON|LOG_INFO; @@ -1654,13 +1603,15 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) { "%sRootDirectory: %s\n" "%sNonBlocking: %s\n" "%sPrivateTmp: %s\n" - "%sControlGroupModify: %s\n", + "%sControlGroupModify: %s\n" + "%sPrivateNetwork: %s\n", prefix, c->umask, prefix, c->working_directory ? c->working_directory : "/", prefix, c->root_directory ? c->root_directory : "/", prefix, yes_no(c->non_blocking), prefix, yes_no(c->private_tmp), - prefix, yes_no(c->control_group_modify)); + prefix, yes_no(c->control_group_modify), + prefix, yes_no(c->private_network)); STRV_FOREACH(e, c->environment) fprintf(f, "%sEnvironment: %s\n", prefix, *e); @@ -1766,7 +1717,7 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) { unsigned long l; fprintf(f, "%sCapabilityBoundingSet:", prefix); - for (l = 0; l <= (unsigned long) CAP_LAST_CAP; l++) + for (l = 0; l <= cap_last_cap(); l++) if (!(c->capability_bounding_set_drop & ((uint64_t) 1ULL << (uint64_t) l))) { char *t;