From 6c03089c32c251d823173bda4d809a9e643219f0 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 15 Apr 2013 14:05:00 +0200 Subject: bus: handle env vars safely Make sure that our library is safe for usage in SUID programs when it comes to env var handling --- src/shared/cgroup-util.c | 141 ++++++++++++++++++++++++++++++----------------- src/shared/cgroup-util.h | 6 +- 2 files changed, 94 insertions(+), 53 deletions(-) (limited to 'src/shared') diff --git a/src/shared/cgroup-util.c b/src/shared/cgroup-util.c index c17e1d4d1b..075260783c 100644 --- a/src/shared/cgroup-util.c +++ b/src/shared/cgroup-util.c @@ -1148,8 +1148,6 @@ int cg_get_user_path(char **path) { char **cg_shorten_controllers(char **controllers) { char **f, **t; - controllers = strv_uniq(controllers); - if (!controllers) return controllers; @@ -1175,11 +1173,11 @@ char **cg_shorten_controllers(char **controllers) { } *t = NULL; - return controllers; + return strv_uniq(controllers); } int cg_pid_get_cgroup(pid_t pid, char **root, char **cgroup) { - char *cg_process, *cg_init, *p; + char *cg_process, *cg_init, *p, *q; int r; assert(pid >= 0); @@ -1202,11 +1200,8 @@ int cg_pid_get_cgroup(pid_t pid, char **root, char **cgroup) { else if (streq(cg_init, "/")) cg_init[0] = 0; - if (startswith(cg_process, cg_init)) - p = cg_process + strlen(cg_init); - else - p = cg_process; - + q = startswith(cg_process, cg_init); + p = q ? q : cg_process; free(cg_init); if (cgroup) { @@ -1230,84 +1225,126 @@ int cg_pid_get_cgroup(pid_t pid, char **root, char **cgroup) { return 0; } -static int instance_unit_from_cgroup(char *cgroup){ - char *at; +/* non-static only for testing purposes */ +int cg_cgroup_to_unit(const char *cgroup, char **unit){ + char *p, *e, *c, *s, *k; assert(cgroup); + assert(unit); - at = strstr(cgroup, "@."); - if (at) { - /* This is a templated service */ + e = strchrnul(cgroup, '/'); + c = strndupa(cgroup, e - cgroup); - char *i; - char _cleanup_free_ *i2 = NULL, *s = NULL; + /* Could this be a valid unit name? */ + if (!unit_name_is_valid(c, true)) + return -EINVAL; - i = strchr(at, '/'); - if (!i || !i[1]) /* disallow empty instances */ + if (!unit_name_is_template(c)) + s = strdup(c); + else { + if (*e != '/') return -EINVAL; - s = strndup(at + 1, i - at - 1); - i2 = strdup(i + 1); - if (!s || !i2) - return -ENOMEM; + e += strspn(e, "/"); + p = strchrnul(e, '/'); - strcpy(at + 1, i2); - strcat(at + 1, s); + /* Don't allow empty instance strings */ + if (p == e) + return -EINVAL; + + k = strndupa(e, p - e); + + s = unit_name_replace_instance(c, k); } + if (!s) + return -ENOMEM; + + *unit = s; return 0; } -/* non-static only for testing purposes */ -int cgroup_to_unit(char *cgroup, char **unit){ +int cg_path_get_unit(const char *path, char **unit) { + const char *e; + + assert(path); + assert(unit); + + e = path_startswith(path, "/system/"); + if (!e) + return -ENOENT; + + return cg_cgroup_to_unit(e, unit); +} + +int cg_pid_get_unit(pid_t pid, char **unit) { + char _cleanup_free_ *cgroup = NULL; int r; - char *p; - assert(cgroup); assert(unit); - r = instance_unit_from_cgroup(cgroup); + r = cg_pid_get_cgroup(pid, NULL, &cgroup); if (r < 0) return r; - p = strrchr(cgroup, '/'); - assert(p); + return cg_path_get_unit(cgroup, unit); +} - r = unit_name_is_valid(p + 1, true); - if (!r) - return -EINVAL; +static const char *skip_label(const char *e) { + assert(e); - *unit = strdup(p + 1); - if (!*unit) - return -ENOMEM; + e += strspn(e, "/"); + e = strchr(e, '/'); + if (!e) + return NULL; - return 0; + e += strspn(e, "/"); + return e; } -static int cg_pid_get(const char *prefix, pid_t pid, char **unit) { - int r; - char _cleanup_free_ *cgroup = NULL; +int cg_path_get_user_unit(const char *path, char **unit) { + const char *e; - assert(pid >= 0); + assert(path); assert(unit); - r = cg_pid_get_cgroup(pid, NULL, &cgroup); - if (r < 0) - return r; + /* 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 */ - if (!startswith(cgroup, prefix)) + e = path_startswith(path, "/user/"); + if (!e) return -ENOENT; - r = cgroup_to_unit(cgroup, unit); - return r; -} + /* Skip the user name */ + e = skip_label(e); + if (!e) + return -ENOENT; -int cg_pid_get_unit(pid_t pid, char **unit) { - return cg_pid_get("/system/", pid, unit); + /* Skip the session ID */ + e = skip_label(e); + if (!e) + return -ENOENT; + + /* Skip the systemd cgroup */ + e = skip_label(e); + if (!e) + return -ENOENT; + + return cg_cgroup_to_unit(e, unit); } int cg_pid_get_user_unit(pid_t pid, char **unit) { - return cg_pid_get("/user/", pid, unit); + char _cleanup_free_ *cgroup = NULL; + int r; + + assert(unit); + + r = cg_pid_get_cgroup(pid, NULL, &cgroup); + if (r < 0) + return r; + + return cg_path_get_user_unit(cgroup, unit); } int cg_controller_from_attr(const char *attr, char **controller) { diff --git a/src/shared/cgroup-util.h b/src/shared/cgroup-util.h index 06c6bfb2e3..123f72c69f 100644 --- a/src/shared/cgroup-util.h +++ b/src/shared/cgroup-util.h @@ -69,11 +69,15 @@ int cg_is_empty_by_spec(const char *spec, bool ignore_self); int cg_is_empty_recursive(const char *controller, const char *path, bool ignore_self); int cg_get_user_path(char **path); + +int cg_path_get_unit(const char *path, char **unit); +int cg_path_get_user_unit(const char *path, char **unit); + int cg_pid_get_cgroup(pid_t pid, char **root, char **cgroup); int cg_pid_get_unit(pid_t pid, char **unit); int cg_pid_get_user_unit(pid_t pid, char **unit); -int cgroup_to_unit(char *cgroup, char **unit); +int cg_cgroup_to_unit(const char *cgroup, char **unit); char **cg_shorten_controllers(char **controllers); -- cgit v1.2.3-54-g00ecf