From: Lennart Poettering Date: Wed, 29 Apr 2015 19:40:54 +0000 (+0200) Subject: sd-bus: properly handle creds that are known but undefined for a process X-Git-Tag: v226.4~1^2~415 X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=commitdiff_plain;h=011da473952eb8c7be67e8238f381fc87d50eb58 sd-bus: properly handle creds that are known but undefined for a process A number of fields do not apply to all processes, including: there a processes without a controlling tty, without parent process, without service, user services or session. To distuingish these cases from the case where we simply don't have the data, always return ENXIO for them, while returning ENODATA for the case where we really lack the information. Also update the credentials dumping code to show this properly. Fields that are known but do not apply are now shown as "n/a". Note that this also changes some of the calls in process-util.c and cgroup-util.c to return ENXIO for these cases. --- diff --git a/src/libelogind/sd-bus/bus-control.c b/src/libelogind/sd-bus/bus-control.c index ca31807f7..fa4c28174 100644 --- a/src/libelogind/sd-bus/bus-control.c +++ b/src/libelogind/sd-bus/bus-control.c @@ -423,9 +423,24 @@ static int bus_populate_creds_from_items( c->mask |= SD_BUS_CREDS_TID; } - if (mask & SD_BUS_CREDS_PPID && item->pids.ppid > 0) { - c->ppid = (pid_t) item->pids.ppid; - c->mask |= SD_BUS_CREDS_PPID; + if (mask & SD_BUS_CREDS_PPID) { + if (item->pids.ppid > 0) { + c->ppid = (pid_t) item->pids.ppid; + c->mask |= SD_BUS_CREDS_PPID; + } else if (item->pids.pid == 1) { + /* The structure doesn't + * really distuingish the case + * where a process has no + * parent and where we don't + * know it because it could + * not be translated due to + * namespaces. However, we + * know that PID 1 has no + * parent process, hence let's + * patch that in, manually. */ + c->ppid = 0; + c->mask |= SD_BUS_CREDS_PPID; + } } break; @@ -565,12 +580,12 @@ static int bus_populate_creds_from_items( break; case KDBUS_ITEM_AUDIT: - if (mask & SD_BUS_CREDS_AUDIT_SESSION_ID && (uint32_t) item->audit.sessionid != (uint32_t) -1) { + if (mask & SD_BUS_CREDS_AUDIT_SESSION_ID) { c->audit_session_id = (uint32_t) item->audit.sessionid; c->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID; } - if (mask & SD_BUS_CREDS_AUDIT_LOGIN_UID && (uid_t) item->audit.loginuid != UID_INVALID) { + if (mask & SD_BUS_CREDS_AUDIT_LOGIN_UID) { c->audit_login_uid = (uid_t) item->audit.loginuid; c->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID; } diff --git a/src/libelogind/sd-bus/bus-creds.c b/src/libelogind/sd-bus/bus-creds.c index 1ac12a7bf..44fad0be0 100644 --- a/src/libelogind/sd-bus/bus-creds.c +++ b/src/libelogind/sd-bus/bus-creds.c @@ -302,6 +302,12 @@ _public_ int sd_bus_creds_get_ppid(sd_bus_creds *c, pid_t *ppid) { if (!(c->mask & SD_BUS_CREDS_PPID)) return -ENODATA; + /* PID 1 has no parent process. Let's distuingish the case of + * not knowing and not having a parent process by the returned + * error code. */ + if (c->ppid == 0) + return -ENXIO; + *ppid = c->ppid; return 0; } @@ -360,7 +366,9 @@ _public_ int sd_bus_creds_get_exe(sd_bus_creds *c, const char **ret) { if (!(c->mask & SD_BUS_CREDS_EXE)) return -ENODATA; - assert(c->exe); + if (!c->exe) + return -ENXIO; + *ret = c->exe; return 0; } @@ -477,8 +485,8 @@ _public_ int sd_bus_creds_get_cmdline(sd_bus_creds *c, char ***cmdline) { if (!(c->mask & SD_BUS_CREDS_CMDLINE)) return -ENODATA; - assert_return(c->cmdline, -ESRCH); - assert(c->cmdline); + if (!c->cmdline) + return -ENXIO; if (!c->cmdline_array) { c->cmdline_array = strv_parse_nulstr(c->cmdline, c->cmdline_size); @@ -497,6 +505,9 @@ _public_ int sd_bus_creds_get_audit_session_id(sd_bus_creds *c, uint32_t *sessio if (!(c->mask & SD_BUS_CREDS_AUDIT_SESSION_ID)) return -ENODATA; + if (c->audit_session_id == AUDIT_SESSION_INVALID) + return -ENXIO; + *sessionid = c->audit_session_id; return 0; } @@ -508,6 +519,9 @@ _public_ int sd_bus_creds_get_audit_login_uid(sd_bus_creds *c, uid_t *uid) { if (!(c->mask & SD_BUS_CREDS_AUDIT_LOGIN_UID)) return -ENODATA; + if (c->audit_login_uid == UID_INVALID) + return -ENXIO; + *uid = c->audit_login_uid; return 0; } @@ -519,6 +533,9 @@ _public_ int sd_bus_creds_get_tty(sd_bus_creds *c, const char **ret) { if (!(c->mask & SD_BUS_CREDS_TTY)) return -ENODATA; + if (!c->tty) + return -ENXIO; + *ret = c->tty; return 0; } @@ -754,8 +771,10 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) { if (r < 0) return r; - c->mask |= SD_BUS_CREDS_PPID; - } + } else + c->ppid = 0; + + c->mask |= SD_BUS_CREDS_PPID; continue; } } @@ -908,7 +927,17 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) { if (missing & SD_BUS_CREDS_EXE) { r = get_process_exe(pid, &c->exe); - if (r < 0) { + if (r == -ESRCH) { + /* Unfortunately we cannot really distuingish + * the case here where the process does not + * exist, and /proc/$PID/exe being unreadable + * because $PID is a kernel thread. Hence, + * assume it is a kernel thread, and rely on + * that this case is caught with a later + * call. */ + c->exe = NULL; + c->mask |= SD_BUS_CREDS_EXE; + } else if (r < 0) { if (r != -EPERM && r != -EACCES) return r; } else @@ -920,17 +949,18 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) { p = procfs_file_alloca(pid, "cmdline"); r = read_full_file(p, &c->cmdline, &c->cmdline_size); + if (r == -ENOENT) + return -ESRCH; if (r < 0) { - if (r == -ENOENT) - return -ESRCH; if (r != -EPERM && r != -EACCES) return r; } else { if (c->cmdline_size == 0) { free(c->cmdline); c->cmdline = NULL; - } else - c->mask |= SD_BUS_CREDS_CMDLINE; + } + + c->mask |= SD_BUS_CREDS_CMDLINE; } } @@ -941,9 +971,9 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) { return -ENOMEM; r = read_one_line_file(p, &c->tid_comm); + if (r == -ENOENT) + return -ESRCH; if (r < 0) { - if (r == -ENOENT) - return -ESRCH; if (r != -EPERM && r != -EACCES) return r; } else @@ -972,8 +1002,12 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) { if (missing & SD_BUS_CREDS_AUDIT_SESSION_ID) { r = audit_session_from_pid(pid, &c->audit_session_id); - if (r < 0) { - if (r != -EOPNOTSUPP && r != -ENXIO && r != -ENOENT && r != -EPERM && r != -EACCES) + if (r == -ENXIO) { + /* ENXIO means: no audit session id assigned */ + c->audit_session_id = AUDIT_SESSION_INVALID; + c->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID; + } else if (r < 0) { + if (r != -EOPNOTSUPP && r != -ENOENT && r != -EPERM && r != -EACCES) return r; } else c->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID; @@ -981,8 +1015,12 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) { if (missing & SD_BUS_CREDS_AUDIT_LOGIN_UID) { r = audit_loginuid_from_pid(pid, &c->audit_login_uid); - if (r < 0) { - if (r != -EOPNOTSUPP && r != -ENXIO && r != -ENOENT && r != -EPERM && r != -EACCES) + if (r == -ENXIO) { + /* ENXIO means: no audit login uid assigned */ + c->audit_login_uid = UID_INVALID; + c->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID; + } else if (r < 0) { + if (r != -EOPNOTSUPP && r != -ENOENT && r != -EPERM && r != -EACCES) return r; } else c->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID; @@ -990,13 +1028,28 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) { if (missing & SD_BUS_CREDS_TTY) { r = get_ctty(pid, NULL, &c->tty); - if (r < 0) { + if (r == -ENXIO) { + /* ENXIO means: process has no controlling TTY */ + c->tty = NULL; + c->mask |= SD_BUS_CREDS_TTY; + } else if (r < 0) { if (r != -EPERM && r != -EACCES && r != -ENOENT) return r; } else c->mask |= SD_BUS_CREDS_TTY; } + /* In case only the exe path was to be read we cannot + * distuingish the case where the exe path was unreadable + * because the process was a kernel thread, or when the + * process didn't exist at all. Hence, let's do a final check, + * to be sure. */ + if (!pid_is_alive(pid)) + return -ESRCH; + + if (tid > 0 && tid != pid && !pid_is_unwaited(tid)) + return -ESRCH; + c->augmented = missing & c->mask; return 0; @@ -1079,14 +1132,22 @@ int bus_creds_extend_by_pid(sd_bus_creds *c, uint64_t mask, sd_bus_creds **ret) } if (c->mask & mask & SD_BUS_CREDS_SUPPLEMENTARY_GIDS) { - n->supplementary_gids = newdup(gid_t, c->supplementary_gids, c->n_supplementary_gids); - if (!n->supplementary_gids) - return -ENOMEM; - n->n_supplementary_gids = c->n_supplementary_gids; + if (c->supplementary_gids) { + n->supplementary_gids = newdup(gid_t, c->supplementary_gids, c->n_supplementary_gids); + if (!n->supplementary_gids) + return -ENOMEM; + n->n_supplementary_gids = c->n_supplementary_gids; + } else { + n->supplementary_gids = NULL; + n->n_supplementary_gids = 0; + } + n->mask |= SD_BUS_CREDS_SUPPLEMENTARY_GIDS; } if (c->mask & mask & SD_BUS_CREDS_COMM) { + assert(c->comm); + n->comm = strdup(c->comm); if (!n->comm) return -ENOMEM; @@ -1095,6 +1156,8 @@ int bus_creds_extend_by_pid(sd_bus_creds *c, uint64_t mask, sd_bus_creds **ret) } if (c->mask & mask & SD_BUS_CREDS_TID_COMM) { + assert(c->tid_comm); + n->tid_comm = strdup(c->tid_comm); if (!n->tid_comm) return -ENOMEM; @@ -1103,23 +1166,34 @@ int bus_creds_extend_by_pid(sd_bus_creds *c, uint64_t mask, sd_bus_creds **ret) } if (c->mask & mask & SD_BUS_CREDS_EXE) { - n->exe = strdup(c->exe); - if (!n->exe) - return -ENOMEM; + if (c->exe) { + n->exe = strdup(c->exe); + if (!n->exe) + return -ENOMEM; + } else + n->exe = NULL; n->mask |= SD_BUS_CREDS_EXE; } if (c->mask & mask & SD_BUS_CREDS_CMDLINE) { - n->cmdline = memdup(c->cmdline, c->cmdline_size); - if (!n->cmdline) - return -ENOMEM; + if (c->cmdline) { + n->cmdline = memdup(c->cmdline, c->cmdline_size); + if (!n->cmdline) + return -ENOMEM; + + n->cmdline_size = c->cmdline_size; + } else { + n->cmdline = NULL; + n->cmdline_size = 0; + } - n->cmdline_size = c->cmdline_size; n->mask |= SD_BUS_CREDS_CMDLINE; } if (c->mask & mask & (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_OWNER_UID)) { + assert(c->cgroup); + n->cgroup = strdup(c->cgroup); if (!n->cgroup) return -ENOMEM; @@ -1132,6 +1206,8 @@ int bus_creds_extend_by_pid(sd_bus_creds *c, uint64_t mask, sd_bus_creds **ret) } if (c->mask & mask & (SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS)) { + assert(c->capability); + n->capability = memdup(c->capability, DIV_ROUND_UP(cap_last_cap(), 32U) * 4 * 4); if (!n->capability) return -ENOMEM; @@ -1140,6 +1216,8 @@ int bus_creds_extend_by_pid(sd_bus_creds *c, uint64_t mask, sd_bus_creds **ret) } if (c->mask & mask & SD_BUS_CREDS_SELINUX_CONTEXT) { + assert(c->label); + n->label = strdup(c->label); if (!n->label) return -ENOMEM; @@ -1166,6 +1244,8 @@ int bus_creds_extend_by_pid(sd_bus_creds *c, uint64_t mask, sd_bus_creds **ret) } if (c->mask & mask & SD_BUS_CREDS_UNIQUE_NAME) { + assert(c->unique_name); + n->unique_name = strdup(c->unique_name); if (!n->unique_name) return -ENOMEM; @@ -1173,15 +1253,20 @@ int bus_creds_extend_by_pid(sd_bus_creds *c, uint64_t mask, sd_bus_creds **ret) } if (c->mask & mask & SD_BUS_CREDS_WELL_KNOWN_NAMES) { - n->well_known_names = strv_copy(c->well_known_names); - if (!n->well_known_names) - return -ENOMEM; + if (strv_isempty(c->well_known_names)) + n->well_known_names = NULL; + else { + n->well_known_names = strv_copy(c->well_known_names); + if (!n->well_known_names) + return -ENOMEM; + } n->well_known_names_driver = c->well_known_names_driver; n->well_known_names_local = c->well_known_names_local; n->mask |= SD_BUS_CREDS_WELL_KNOWN_NAMES; } if (c->mask & mask & SD_BUS_CREDS_DESCRIPTION) { + assert(c->description); n->description = strdup(c->description); if (!n->description) return -ENOMEM; diff --git a/src/libelogind/sd-bus/bus-dump.c b/src/libelogind/sd-bus/bus-dump.c index 396bf36f8..47a5c6b3a 100644 --- a/src/libelogind/sd-bus/bus-dump.c +++ b/src/libelogind/sd-bus/bus-dump.c @@ -331,13 +331,11 @@ static void dump_capabilities( } int bus_creds_dump(sd_bus_creds *c, FILE *f, bool terse) { - bool audit_sessionid_is_set = false, audit_loginuid_is_set = false; - const char *u = NULL, *uu = NULL, *s = NULL, *sl = NULL; uid_t owner, audit_loginuid; uint32_t audit_sessionid; char **cmdline = NULL, **well_known = NULL; - const char *prefix, *color, *suffix; - int r; + const char *prefix, *color, *suffix, *s; + int r, q, v, w; assert(c); @@ -362,8 +360,12 @@ int bus_creds_dump(sd_bus_creds *c, FILE *f, bool terse) { fprintf(f, "%sPID=%s"PID_FMT"%s", prefix, color, c->pid, suffix); if (c->mask & SD_BUS_CREDS_TID) fprintf(f, "%sTID=%s"PID_FMT"%s", prefix, color, c->tid, suffix); - if (c->mask & SD_BUS_CREDS_PPID) - fprintf(f, "%sPPID=%s"PID_FMT"%s", prefix, color, c->ppid, suffix); + if (c->mask & SD_BUS_CREDS_PPID) { + if (c->ppid == 0) + fprintf(f, "%sPPID=%sn/a%s", prefix, color, suffix); + else + fprintf(f, "%sPPID=%s"PID_FMT"%s", prefix, color, c->ppid, suffix); + } if (c->mask & SD_BUS_CREDS_TTY) fprintf(f, "%sTTY=%s%s%s", prefix, color, strna(c->tty), suffix); @@ -409,12 +411,13 @@ int bus_creds_dump(sd_bus_creds *c, FILE *f, bool terse) { if (c->mask & SD_BUS_CREDS_TID_COMM) fprintf(f, "%sTIDComm=%s%s%s", prefix, color, c->tid_comm, suffix); if (c->mask & SD_BUS_CREDS_EXE) - fprintf(f, "%sExe=%s%s%s", prefix, color, c->exe, suffix); + fprintf(f, "%sExe=%s%s%s", prefix, color, strna(c->exe), suffix); if (terse && (c->mask & (SD_BUS_CREDS_EXE|SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM))) fputs("\n", f); - if (sd_bus_creds_get_cmdline(c, &cmdline) >= 0) { + r = sd_bus_creds_get_cmdline(c, &cmdline); + if (r >= 0) { char **i; fprintf(f, "%sCommandLine=%s", prefix, color); @@ -426,7 +429,8 @@ int bus_creds_dump(sd_bus_creds *c, FILE *f, bool terse) { } fprintf(f, "%s", suffix); - } + } else if (r != -ENODATA) + fprintf(f, "%sCommandLine=%sn/a%s", prefix, color, suffix); if (c->mask & SD_BUS_CREDS_SELINUX_CONTEXT) fprintf(f, "%sLabel=%s%s%s", prefix, color, c->label, suffix); @@ -438,32 +442,38 @@ int bus_creds_dump(sd_bus_creds *c, FILE *f, bool terse) { if (c->mask & SD_BUS_CREDS_CGROUP) fprintf(f, "%sCGroup=%s%s%s", prefix, color, c->cgroup, suffix); - (void) sd_bus_creds_get_unit(c, &u); - if (u) - fprintf(f, "%sUnit=%s%s%s", prefix, color, u, suffix); - (void) sd_bus_creds_get_user_unit(c, &uu); - if (uu) - fprintf(f, "%sUserUnit=%s%s%s", prefix, color, uu, suffix); - (void) sd_bus_creds_get_slice(c, &sl); - if (sl) - fprintf(f, "%sSlice=%s%s%s", prefix, color, sl, suffix); - (void) sd_bus_creds_get_session(c, &s); - if (s) - fprintf(f, "%sSession=%s%s%s", prefix, color, s, suffix); - - if (terse && ((c->mask & SD_BUS_CREDS_CGROUP) || u || uu || sl || s)) + s = NULL; + r = sd_bus_creds_get_unit(c, &s); + if (r != -ENODATA) + fprintf(f, "%sUnit=%s%s%s", prefix, color, strna(s), suffix); + s = NULL; + q = sd_bus_creds_get_user_unit(c, &s); + if (q != -ENODATA) + fprintf(f, "%sUserUnit=%s%s%s", prefix, color, strna(s), suffix); + s = NULL; + v = sd_bus_creds_get_slice(c, &s); + if (v != -ENODATA) + fprintf(f, "%sSlice=%s%s%s", prefix, color, strna(s), suffix); + s = NULL; + w = sd_bus_creds_get_session(c, &s); + if (w != -ENODATA) + fprintf(f, "%sSession=%s%s%s", prefix, color, strna(s), suffix); + + if (terse && ((c->mask & SD_BUS_CREDS_CGROUP) || r != -ENODATA || q != -ENODATA || v != -ENODATA || w != -ENODATA)) fputs("\n", f); - if (sd_bus_creds_get_audit_login_uid(c, &audit_loginuid) >= 0) { - audit_loginuid_is_set = true; + r = sd_bus_creds_get_audit_login_uid(c, &audit_loginuid); + if (r >= 0) fprintf(f, "%sAuditLoginUID=%s"UID_FMT"%s", prefix, color, audit_loginuid, suffix); - } - if (sd_bus_creds_get_audit_session_id(c, &audit_sessionid) >= 0) { - audit_sessionid_is_set = true; + else if (r != -ENODATA) + fprintf(f, "%sAuditLoginUID=%sn/a%s", prefix, color, suffix); + q = sd_bus_creds_get_audit_session_id(c, &audit_sessionid); + if (q >= 0) fprintf(f, "%sAuditSessionID=%s%"PRIu32"%s", prefix, color, audit_sessionid, suffix); - } + else if (q != -ENODATA) + fprintf(f, "%sAuditSessionID=%sn/a%s", prefix, color, suffix); - if (terse && (audit_loginuid_is_set || audit_sessionid_is_set)) + if (terse && (r != -ENODATA || q != -ENODATA)) fputs("\n", f); if (c->mask & SD_BUS_CREDS_UNIQUE_NAME) diff --git a/src/libelogind/sd-bus/bus-kernel.c b/src/libelogind/sd-bus/bus-kernel.c index a8c04b98a..556b5eb70 100644 --- a/src/libelogind/sd-bus/bus-kernel.c +++ b/src/libelogind/sd-bus/bus-kernel.c @@ -598,6 +598,9 @@ static int bus_kernel_make_message(sd_bus *bus, struct kdbus_msg *k) { if (d->pids.ppid > 0) { m->creds.ppid = (pid_t) d->pids.ppid; m->creds.mask |= SD_BUS_CREDS_PPID & bus->creds_mask; + } else if (d->pids.pid == 1) { + m->creds.ppid = 0; + m->creds.mask |= SD_BUS_CREDS_PPID & bus->creds_mask; } break; @@ -686,15 +689,11 @@ static int bus_kernel_make_message(sd_bus *bus, struct kdbus_msg *k) { break; case KDBUS_ITEM_AUDIT: - if ((uint32_t) d->audit.sessionid != (uint32_t) -1) { - m->creds.audit_session_id = (uint32_t) d->audit.sessionid; - m->creds.mask |= SD_BUS_CREDS_AUDIT_SESSION_ID & bus->creds_mask; - } + m->creds.audit_session_id = (uint32_t) d->audit.sessionid; + m->creds.mask |= SD_BUS_CREDS_AUDIT_SESSION_ID & bus->creds_mask; - if ((uid_t) d->audit.loginuid != UID_INVALID) { - m->creds.audit_login_uid = (uid_t) d->audit.loginuid; - m->creds.mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID & bus->creds_mask; - } + m->creds.audit_login_uid = (uid_t) d->audit.loginuid; + m->creds.mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID & bus->creds_mask; break; case KDBUS_ITEM_CAPS: diff --git a/src/shared/audit.c b/src/shared/audit.c index 84181d332..54148fcf1 100644 --- a/src/shared/audit.c +++ b/src/shared/audit.c @@ -46,7 +46,7 @@ int audit_session_from_pid(pid_t pid, uint32_t *id) { if (r < 0) return r; - if (u == (uint32_t) -1 || u <= 0) + if (u == AUDIT_SESSION_INVALID || u <= 0) return -ENXIO; *id = u; diff --git a/src/shared/audit.h b/src/shared/audit.h index fb5f1b513..6de331c73 100644 --- a/src/shared/audit.h +++ b/src/shared/audit.h @@ -21,12 +21,13 @@ along with systemd; If not, see . ***/ -#include "sd-bus.h" -#include "job.h" +#include +#include +#include -extern const sd_bus_vtable bus_job_vtable[]; +#define AUDIT_SESSION_INVALID ((uint32_t) -1) -int bus_job_method_cancel(sd_bus_message *message, void *job, sd_bus_error *error); +int audit_session_from_pid(pid_t pid, uint32_t *id); +int audit_loginuid_from_pid(pid_t pid, uid_t *uid); -void bus_job_send_change_signal(Job *j); -void bus_job_send_removed_signal(Job *j); +bool use_audit(void); diff --git a/src/shared/cgroup-util.c b/src/shared/cgroup-util.c index c746d606d..5c031a052 100644 --- a/src/shared/cgroup-util.c +++ b/src/shared/cgroup-util.c @@ -35,6 +35,7 @@ #include "util.h" #include "formats-util.h" #include "path-util.h" +#include "unit-name.h" #include "fileio.h" #include "special.h" #include "mkdir.h" @@ -439,7 +440,7 @@ static const char *normalize_controller(const char *controller) { assert(controller); if (streq(controller, SYSTEMD_CGROUP_CONTROLLER)) - return "elogind"; + return "systemd"; else if (startswith(controller, "name=")) return controller + 5; else @@ -1060,9 +1061,21 @@ int cg_mangle_path(const char *path, char **result) { } int cg_get_root_path(char **path) { + char *p, *e; + int r; + assert(path); - return cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, 1, path); + r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, 1, &p); + if (r < 0) + return r; + + e = endswith(p, "/" SPECIAL_SYSTEM_SLICE); + if (e) + *e = 0; + + *path = p; + return 0; } int cg_shift_path(const char *cgroup, const char *root, const char **shifted) { @@ -1125,30 +1138,201 @@ int cg_pid_get_path_shifted(pid_t pid, const char *root, char **cgroup) { return 0; } -int cg_path_get_session(const char *path, char **session) { - const char *e, *n, *s; +int cg_path_decode_unit(const char *cgroup, char **unit){ + char *e, *c, *s; + + assert(cgroup); + assert(unit); + + e = strchrnul(cgroup, '/'); + c = strndupa(cgroup, e - cgroup); + c = cg_unescape(c); + + if (!unit_name_is_valid(c, TEMPLATE_INVALID)) + return -ENXIO; + + s = strdup(c); + if (!s) + return -ENOMEM; + + *unit = s; + return 0; +} + +static const char *skip_slices(const char *p) { + /* Skips over all slice assignments */ + + for (;;) { + size_t n; + + p += strspn(p, "/"); + + n = strcspn(p, "/"); + if (n <= 6 || memcmp(p + n - 6, ".slice", 6) != 0) + return p; + + p += n; + } +} + +int cg_path_get_unit(const char *path, char **unit) { + const char *e; + + assert(path); + assert(unit); + + e = skip_slices(path); + + return cg_path_decode_unit(e, unit); +} + +int cg_pid_get_unit(pid_t pid, char **unit) { + _cleanup_free_ char *cgroup = NULL; + int r; + + assert(unit); + + r = cg_pid_get_path_shifted(pid, NULL, &cgroup); + if (r < 0) + return r; + + return cg_path_get_unit(cgroup, unit); +} + +/** + * Skip session-*.scope, but require it to be there. + */ +static const char *skip_session(const char *p) { + size_t n; + + assert(p); + + p += strspn(p, "/"); + + n = strcspn(p, "/"); + if (n < strlen("session-x.scope") || memcmp(p, "session-", 8) != 0 || memcmp(p + n - 6, ".scope", 6) != 0) + return NULL; + + p += n; + p += strspn(p, "/"); + + return p; +} + +/** + * Skip user@*.service, but require it to be there. + */ +static const char *skip_user_manager(const char *p) { + size_t n; + + assert(p); + + p += strspn(p, "/"); + + n = strcspn(p, "/"); + if (n < strlen("user@x.service") || memcmp(p, "user@", 5) != 0 || memcmp(p + n - 8, ".service", 8) != 0) + return NULL; + + p += n; + p += strspn(p, "/"); + + return p; +} + +int cg_path_get_user_unit(const char *path, char **unit) { + const char *e, *t; + + assert(path); + assert(unit); + + /* We always have to parse the path from the beginning as unit + * cgroups might have arbitrary child cgroups and we shouldn't get + * confused by those */ + + /* Skip slices, if there are any */ + e = skip_slices(path); + + /* Skip the session scope or user manager... */ + t = skip_session(e); + if (!t) + t = skip_user_manager(e); + if (!t) + return -ENXIO; + + /* ... and skip more slices if there are any */ + e = skip_slices(t); + + return cg_path_decode_unit(e, unit); +} + +int cg_pid_get_user_unit(pid_t pid, char **unit) { + _cleanup_free_ char *cgroup = NULL; + int r; + + assert(unit); + + r = cg_pid_get_path_shifted(pid, NULL, &cgroup); + if (r < 0) + return r; + + return cg_path_get_user_unit(cgroup, unit); +} + +int cg_path_get_machine_name(const char *path, char **machine) { + _cleanup_free_ char *u = NULL, *sl = NULL; + int r; + + r = cg_path_get_unit(path, &u); + if (r < 0) + return r; + + sl = strjoin("/run/systemd/machines/unit:", u, NULL); + if (!sl) + return -ENOMEM; + + return readlink_malloc(sl, machine); +} - /* Elogind uses a flat hierarchy, just "/SESSION". The only - wrinkle is that SESSION might be escaped. */ +int cg_pid_get_machine_name(pid_t pid, char **machine) { + _cleanup_free_ char *cgroup = NULL; + int r; + + assert(machine); + + r = cg_pid_get_path_shifted(pid, NULL, &cgroup); + if (r < 0) + return r; + + return cg_path_get_machine_name(cgroup, machine); +} + +int cg_path_get_session(const char *path, char **session) { + const char *e, *n, *x, *y; + char *s; assert(path); - assert(path[0] == '/'); - e = path + 1; + /* Skip slices, if there are any */ + e = skip_slices(path); + n = strchrnul(e, '/'); if (e == n) - return -ENOENT; + return -ENXIO; s = strndupa(e, n - e); s = cg_unescape(s); - if (!s[0]) - return -ENOENT; + x = startswith(s, "session-"); + if (!x) + return -ENXIO; + y = endswith(x, ".scope"); + if (!y || x == y) + return -ENXIO; if (session) { char *r; - r = strdup(s); + r = strndup(x, y - x); if (!r) return -ENOMEM; @@ -1169,6 +1353,97 @@ int cg_pid_get_session(pid_t pid, char **session) { return cg_path_get_session(cgroup, session); } +int cg_path_get_owner_uid(const char *path, uid_t *uid) { + _cleanup_free_ char *slice = NULL; + const char *start, *end; + char *s; + uid_t u; + int r; + + assert(path); + + r = cg_path_get_slice(path, &slice); + if (r < 0) + return r; + + start = startswith(slice, "user-"); + if (!start) + return -ENXIO; + end = endswith(slice, ".slice"); + if (!end) + return -ENXIO; + + s = strndupa(start, end - start); + if (!s) + return -ENXIO; + + if (parse_uid(s, &u) < 0) + return -ENXIO; + + if (uid) + *uid = u; + + return 0; +} + +int cg_pid_get_owner_uid(pid_t pid, uid_t *uid) { + _cleanup_free_ char *cgroup = NULL; + int r; + + r = cg_pid_get_path_shifted(pid, NULL, &cgroup); + if (r < 0) + return r; + + return cg_path_get_owner_uid(cgroup, uid); +} + +int cg_path_get_slice(const char *p, char **slice) { + const char *e = NULL; + size_t m = 0; + + assert(p); + assert(slice); + + for (;;) { + size_t n; + + p += strspn(p, "/"); + + n = strcspn(p, "/"); + if (n <= 6 || memcmp(p + n - 6, ".slice", 6) != 0) { + char *s; + + if (!e) + return -ENXIO; + + s = strndup(e, m); + if (!s) + return -ENOMEM; + + *slice = s; + return 0; + } + + e = p; + m = n; + + p += n; + } +} + +int cg_pid_get_slice(pid_t pid, char **slice) { + _cleanup_free_ char *cgroup = NULL; + int r; + + assert(slice); + + r = cg_pid_get_path_shifted(pid, NULL, &cgroup); + if (r < 0) + return r; + + return cg_path_get_slice(cgroup, slice); +} + char *cg_escape(const char *p) { bool need_prefix = false; @@ -1255,6 +1530,56 @@ bool cg_controller_is_valid(const char *p, bool allow_named) { return true; } +int cg_slice_to_path(const char *unit, char **ret) { + _cleanup_free_ char *p = NULL, *s = NULL, *e = NULL; + const char *dash; + + assert(unit); + assert(ret); + + if (!unit_name_is_valid(unit, TEMPLATE_INVALID)) + return -EINVAL; + + if (!endswith(unit, ".slice")) + return -EINVAL; + + p = unit_name_to_prefix(unit); + if (!p) + return -ENOMEM; + + dash = strchr(p, '-'); + while (dash) { + _cleanup_free_ char *escaped = NULL; + char n[dash - p + sizeof(".slice")]; + + strcpy(stpncpy(n, p, dash - p), ".slice"); + + if (!unit_name_is_valid(n, TEMPLATE_INVALID)) + return -EINVAL; + + escaped = cg_escape(n); + if (!escaped) + return -ENOMEM; + + if (!strextend(&s, escaped, "/", NULL)) + return -ENOMEM; + + dash = strchr(dash+1, '-'); + } + + e = cg_escape(unit); + if (!e) + return -ENOMEM; + + if (!strextend(&s, e, NULL)) + return -ENOMEM; + + *ret = s; + s = NULL; + + return 0; +} + int cg_set_attribute(const char *controller, const char *path, const char *attribute, const char *value) { _cleanup_free_ char *p = NULL; int r; diff --git a/src/shared/terminal-util.c b/src/shared/terminal-util.c index f5b659099..042b88f22 100644 --- a/src/shared/terminal-util.c +++ b/src/shared/terminal-util.c @@ -1009,7 +1009,7 @@ int get_ctty_devnr(pid_t pid, dev_t *d) { return -EIO; if (major(ttynr) == 0 && minor(ttynr) == 0) - return -ENOENT; + return -ENXIO; if (d) *d = (dev_t) ttynr; diff --git a/src/test/test-process-util.c b/src/test/test-process-util.c index 1de100cda..e4e2efecd 100644 --- a/src/test/test-process-util.c +++ b/src/test/test-process-util.c @@ -44,9 +44,8 @@ static void test_get_process_comm(void) { if (stat("/proc/1/comm", &st) == 0) { assert_se(get_process_comm(1, &a) >= 0); log_info("pid1 comm: '%s'", a); - } else { + } else log_warning("/proc/1/comm does not exist."); - } assert_se(get_process_cmdline(1, 0, true, &c) >= 0); log_info("pid1 cmdline: '%s'", c); @@ -87,7 +86,7 @@ static void test_get_process_comm(void) { log_info("self strlen(environ): '%zu'", strlen(env)); if (!detect_container(NULL)) - assert_se(get_ctty_devnr(1, &h) == -ENOENT); + assert_se(get_ctty_devnr(1, &h) == -ENXIO); getenv_for_pid(1, "PATH", &i); log_info("pid1 $PATH: '%s'", strna(i));