cgroup: additional validity checks for cgroup attribute names

This commit is contained in:
Lennart Poettering 2013-01-19 00:59:19 +01:00
parent adf36dd0ae
commit e884315e3d
5 changed files with 89 additions and 34 deletions

View File

@ -2156,26 +2156,27 @@ int unit_add_cgroup_attribute(
_cleanup_free_ char *c = NULL;
CGroupAttribute *a;
int r;
assert(u);
assert(name);
assert(value);
if (!controller) {
const char *dot;
dot = strchr(name, '.');
if (!dot)
r = cg_controller_from_attr(name, &c);
if (r < 0)
return -EINVAL;
c = strndup(name, dot - name);
if (!c)
return -ENOMEM;
controller = c;
} else {
if (!filename_is_safe(name))
return -EINVAL;
if (!filename_is_safe(controller))
return -EINVAL;
}
if (streq(controller, SYSTEMD_CGROUP_CONTROLLER))
if (!controller || streq(controller, SYSTEMD_CGROUP_CONTROLLER))
return -EINVAL;
a = cgroup_attribute_find_list(u->cgroup_attributes, controller, name);

View File

@ -990,6 +990,8 @@ int cg_split_spec(const char *spec, char **controller, char **path) {
assert(spec);
if (*spec == '/') {
if (!path_is_safe(spec))
return -EINVAL;
if (path) {
t = strdup(spec);
@ -1007,7 +1009,7 @@ int cg_split_spec(const char *spec, char **controller, char **path) {
e = strchr(spec, ':');
if (!e) {
if (strchr(spec, '/') || spec[0] == 0)
if (!filename_is_safe(spec))
return -EINVAL;
if (controller) {
@ -1024,29 +1026,34 @@ int cg_split_spec(const char *spec, char **controller, char **path) {
return 0;
}
if (e[1] != '/' || e == spec || memchr(spec, '/', e-spec))
t = strndup(spec, e-spec);
if (!t)
return -ENOMEM;
if (!filename_is_safe(t)) {
free(t);
return -EINVAL;
if (controller) {
t = strndup(spec, e-spec);
if (!t)
return -ENOMEM;
}
if (path) {
u = strdup(e+1);
if (!u) {
free(t);
return -ENOMEM;
}
u = strdup(e+1);
if (!u) {
free(t);
return -ENOMEM;
}
if (!path_is_safe(u)) {
free(t);
free(u);
return -EINVAL;
}
if (controller)
*controller = t;
else
free(t);
if (path)
*path = u;
else
free(u);
return 0;
}
@ -1290,3 +1297,32 @@ int cg_pid_get_unit(pid_t pid, char **unit) {
int cg_pid_get_user_unit(pid_t pid, char **unit) {
return cg_pid_get("/user/", pid, unit);
}
int cg_controller_from_attr(const char *attr, char **controller) {
const char *dot;
char *c;
assert(attr);
assert(controller);
if (!filename_is_safe(attr))
return -EINVAL;
dot = strchr(attr, '.');
if (!dot) {
*controller = NULL;
return 0;
}
c = strndup(attr, dot - attr);
if (!c)
return -ENOMEM;
if (!filename_is_safe(c)) {
free(c);
return -EINVAL;
}
*controller = c;
return 1;
}

View File

@ -76,3 +76,5 @@ int cg_pid_get_user_unit(pid_t pid, char **unit);
int cgroup_to_unit(char *cgroup, char **unit);
char **cg_shorten_controllers(char **controllers);
int cg_controller_from_attr(const char *attr, char **controller);

View File

@ -561,9 +561,9 @@ int fchmod_umask(int fd, mode_t m) {
}
int write_one_line_file_atomic(const char *fn, const char *line) {
FILE *f;
_cleanup_fclose_ FILE *f = NULL;
_cleanup_free_ char *p = NULL;
int r;
char *p;
assert(fn);
assert(line);
@ -585,12 +585,9 @@ int write_one_line_file_atomic(const char *fn, const char *line) {
fflush(f);
if (ferror(f)) {
if (errno != 0)
r = -errno;
else
r = -EIO;
} else {
if (ferror(f))
r = errno ? -errno : -EIO;
else {
if (rename(p, fn) < 0)
r = -errno;
else
@ -601,9 +598,6 @@ finish:
if (r < 0)
unlink(p);
fclose(f);
free(p);
return r;
}
@ -5613,6 +5607,27 @@ bool string_is_safe(const char *p) {
return true;
}
bool path_is_safe(const char *p) {
if (isempty(p))
return false;
if (streq(p, "..") || startswith(p, "../") || endswith(p, "/..") || strstr(p, "/../"))
return false;
if (strlen(p) > PATH_MAX)
return false;
/* The following two checks are not really dangerous, but hey, they still are confusing */
if (streq(p, ".") || startswith(p, "./") || endswith(p, "/.") || strstr(p, "/./"))
return false;
if (strstr(p, "//"))
return false;
return true;
}
/* hey glibc, APIs with callbacks without a user pointer are so useless */
void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size,
int (*compar) (const void *, const void *, void *), void *arg) {

View File

@ -543,6 +543,7 @@ _malloc_ static inline void *memdup_multiply(const void *p, size_t a, size_t b)
}
bool filename_is_safe(const char *p);
bool path_is_safe(const char *p);
bool string_is_safe(const char *p);
void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size,