summaryrefslogtreecommitdiff
path: root/src/shared/cgroup-util.c
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2015-04-30 00:47:41 +0200
committerLennart Poettering <lennart@poettering.net>2015-04-30 00:49:41 +0200
commit8b0849e9710d721c5d0b775aaf0fd662eefa1449 (patch)
treec185b5676d440e4ca30d0a1226fdbf49683a009a /src/shared/cgroup-util.c
parent5cc0748e19490c4275aa66796679e3e67b649795 (diff)
core: rework cgroup path parse logic
Various cleanups, be stricter when parsing unit paths. Most importantly: return the root slice "-.slice" when asked for slice of paths that contain no slice component.
Diffstat (limited to 'src/shared/cgroup-util.c')
-rw-r--r--src/shared/cgroup-util.c212
1 files changed, 147 insertions, 65 deletions
diff --git a/src/shared/cgroup-util.c b/src/shared/cgroup-util.c
index 7521b8b5f9..67e6f70e8e 100644
--- a/src/shared/cgroup-util.c
+++ b/src/shared/cgroup-util.c
@@ -40,6 +40,7 @@
#include "fileio.h"
#include "special.h"
#include "mkdir.h"
+#include "login-shared.h"
int cg_enumerate_processes(const char *controller, const char *path, FILE **_f) {
_cleanup_free_ char *fs = NULL;
@@ -1140,13 +1141,17 @@ int cg_pid_get_path_shifted(pid_t pid, const char *root, char **cgroup) {
}
int cg_path_decode_unit(const char *cgroup, char **unit){
- char *e, *c, *s;
+ char *c, *s;
+ size_t n;
assert(cgroup);
assert(unit);
- e = strchrnul(cgroup, '/');
- c = strndupa(cgroup, e - cgroup);
+ n = strcspn(cgroup, "/");
+ if (n < 3)
+ return -ENXIO;
+
+ c = strndupa(cgroup, n);
c = cg_unescape(c);
if (!unit_name_is_valid(c, TEMPLATE_INVALID))
@@ -1160,7 +1165,31 @@ int cg_path_decode_unit(const char *cgroup, char **unit){
return 0;
}
+static bool valid_slice_name(const char *p, size_t n) {
+
+ if (!p)
+ return false;
+
+ if (n < strlen("x.slice"))
+ return false;
+
+ if (memcmp(p + n - 6, ".slice", 6) == 0) {
+ char buf[n+1], *c;
+
+ memcpy(buf, p, n);
+ buf[n] = 0;
+
+ c = cg_unescape(buf);
+
+ return unit_name_is_valid(c, TEMPLATE_INVALID);
+ }
+
+ return false;
+}
+
static const char *skip_slices(const char *p) {
+ assert(p);
+
/* Skips over all slice assignments */
for (;;) {
@@ -1169,22 +1198,35 @@ static const char *skip_slices(const char *p) {
p += strspn(p, "/");
n = strcspn(p, "/");
- if (n <= 6 || memcmp(p + n - 6, ".slice", 6) != 0)
+ if (!valid_slice_name(p, n))
return p;
p += n;
}
}
-int cg_path_get_unit(const char *path, char **unit) {
+int cg_path_get_unit(const char *path, char **ret) {
const char *e;
+ char *unit;
+ int r;
assert(path);
- assert(unit);
+ assert(ret);
e = skip_slices(path);
- return cg_path_decode_unit(e, unit);
+ r = cg_path_decode_unit(e, &unit);
+ if (r < 0)
+ return r;
+
+ /* We skipped over the slices, don't accept any now */
+ if (endswith(unit, ".slice")) {
+ free(unit);
+ return -ENXIO;
+ }
+
+ *ret = unit;
+ return 0;
}
int cg_pid_get_unit(pid_t pid, char **unit) {
@@ -1206,18 +1248,35 @@ int cg_pid_get_unit(pid_t pid, char **unit) {
static const char *skip_session(const char *p) {
size_t n;
- assert(p);
+ if (isempty(p))
+ return NULL;
p += strspn(p, "/");
n = strcspn(p, "/");
- if (n < strlen("session-x.scope") || memcmp(p, "session-", 8) != 0 || memcmp(p + n - 6, ".scope", 6) != 0)
+ if (n < strlen("session-x.scope"))
return NULL;
- p += n;
- p += strspn(p, "/");
+ if (memcmp(p, "session-", 8) == 0 && memcmp(p + n - 6, ".scope", 6) == 0) {
+ char buf[n - 8 - 6 + 1];
+
+ memcpy(buf, p + 8, n - 8 - 6);
+ buf[n - 8 - 6] = 0;
+
+ /* Note that session scopes never need unescaping,
+ * since they cannot conflict with the kernel's own
+ * names, hence we don't need to call cg_unescape()
+ * here. */
+
+ if (!session_id_valid(buf))
+ return false;
- return p;
+ p += n;
+ p += strspn(p, "/");
+ return p;
+ }
+
+ return NULL;
}
/**
@@ -1226,25 +1285,45 @@ static const char *skip_session(const char *p) {
static const char *skip_user_manager(const char *p) {
size_t n;
- assert(p);
+ if (isempty(p))
+ return NULL;
p += strspn(p, "/");
n = strcspn(p, "/");
- if (n < strlen("user@x.service") || memcmp(p, "user@", 5) != 0 || memcmp(p + n - 8, ".service", 8) != 0)
+ if (n < strlen("user@x.service"))
return NULL;
- p += n;
- p += strspn(p, "/");
+ if (memcmp(p, "user@", 5) == 0 && memcmp(p + n - 8, ".service", 8) == 0) {
+ char buf[n - 5 - 8 + 1];
+
+ memcpy(buf, p + 5, n - 5 - 8);
+ buf[n - 5 - 8] = 0;
+
+ /* Note that user manager services never need unescaping,
+ * since they cannot conflict with the kernel's own
+ * names, hence we don't need to call cg_unescape()
+ * here. */
+
+ if (parse_uid(buf, NULL) < 0)
+ return NULL;
+
+ p += n;
+ p += strspn(p, "/");
+
+ return p;
+ }
- return p;
+ return NULL;
}
-int cg_path_get_user_unit(const char *path, char **unit) {
+int cg_path_get_user_unit(const char *path, char **ret) {
const char *e, *t;
+ char *unit;
+ int r;
assert(path);
- assert(unit);
+ assert(ret);
/* We always have to parse the path from the beginning as unit
* cgroups might have arbitrary child cgroups and we shouldn't get
@@ -1253,17 +1332,30 @@ int cg_path_get_user_unit(const char *path, char **unit) {
/* Skip slices, if there are any */
e = skip_slices(path);
- /* Skip the session scope or user manager... */
- t = skip_session(e);
+ /* Skip the user manager... */
+ t = skip_user_manager(e);
+
+ /* Alternatively skip the user session... */
if (!t)
- t = skip_user_manager(e);
+ t = skip_session(e);
if (!t)
return -ENXIO;
/* ... and skip more slices if there are any */
e = skip_slices(t);
- return cg_path_decode_unit(e, unit);
+ r = cg_path_decode_unit(e, &unit);
+ if (r < 0)
+ return r;
+
+ /* We skipped over the slices, don't accept any now */
+ if (endswith(unit, ".slice")) {
+ free(unit);
+ return -ENXIO;
+ }
+
+ *ret = unit;
+ return 0;
}
int cg_pid_get_user_unit(pid_t pid, char **unit) {
@@ -1308,36 +1400,35 @@ int cg_pid_get_machine_name(pid_t pid, char **machine) {
}
int cg_path_get_session(const char *path, char **session) {
- const char *e, *n, *x, *y;
- char *s;
+ _cleanup_free_ char *unit = NULL;
+ char *start, *end;
+ int r;
assert(path);
- /* Skip slices, if there are any */
- e = skip_slices(path);
+ r = cg_path_get_unit(path, &unit);
+ if (r < 0)
+ return r;
- n = strchrnul(e, '/');
- if (e == n)
+ start = startswith(unit, "session-");
+ if (!start)
return -ENXIO;
-
- s = strndupa(e, n - e);
- s = cg_unescape(s);
-
- x = startswith(s, "session-");
- if (!x)
+ end = endswith(start, ".scope");
+ if (!end)
return -ENXIO;
- y = endswith(x, ".scope");
- if (!y || x == y)
+
+ *end = 0;
+ if (!session_id_valid(start))
return -ENXIO;
if (session) {
- char *r;
+ char *rr;
- r = strndup(x, y - x);
- if (!r)
+ rr = strdup(start);
+ if (!rr)
return -ENOMEM;
- *session = r;
+ *session = rr;
}
return 0;
@@ -1356,9 +1447,7 @@ int cg_pid_get_session(pid_t pid, char **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;
+ char *start, *end;
int r;
assert(path);
@@ -1370,20 +1459,14 @@ int cg_path_get_owner_uid(const char *path, uid_t *uid) {
start = startswith(slice, "user-");
if (!start)
return -ENXIO;
- end = endswith(slice, ".slice");
+ end = endswith(start, ".slice");
if (!end)
return -ENXIO;
- s = strndupa(start, end - start);
- if (!s)
+ *end = 0;
+ if (parse_uid(start, uid) < 0)
return -ENXIO;
- if (parse_uid(s, &u) < 0)
- return -ENXIO;
-
- if (uid)
- *uid = u;
-
return 0;
}
@@ -1400,7 +1483,6 @@ int cg_pid_get_owner_uid(pid_t pid, uid_t *uid) {
int cg_path_get_slice(const char *p, char **slice) {
const char *e = NULL;
- size_t m = 0;
assert(p);
assert(slice);
@@ -1411,23 +1493,23 @@ int cg_path_get_slice(const char *p, char **slice) {
p += strspn(p, "/");
n = strcspn(p, "/");
- if (n <= 6 || memcmp(p + n - 6, ".slice", 6) != 0) {
- char *s;
+ if (!valid_slice_name(p, n)) {
- if (!e)
- return -ENXIO;
+ if (!e) {
+ char *s;
- s = strndup(e, m);
- if (!s)
- return -ENOMEM;
+ s = strdup("-.slice");
+ if (!s)
+ return -ENOMEM;
- *slice = s;
- return 0;
+ *slice = s;
+ return 0;
+ }
+
+ return cg_path_decode_unit(e, slice);
}
e = p;
- m = n;
-
p += n;
}
}