mirror of
https://github.com/systemd/systemd.git
synced 2025-03-11 20:58:27 +03:00
cgroup: additional validity checks for cgroup attribute names
This commit is contained in:
parent
adf36dd0ae
commit
e884315e3d
@ -2156,26 +2156,27 @@ int unit_add_cgroup_attribute(
|
|||||||
|
|
||||||
_cleanup_free_ char *c = NULL;
|
_cleanup_free_ char *c = NULL;
|
||||||
CGroupAttribute *a;
|
CGroupAttribute *a;
|
||||||
|
int r;
|
||||||
|
|
||||||
assert(u);
|
assert(u);
|
||||||
assert(name);
|
assert(name);
|
||||||
assert(value);
|
assert(value);
|
||||||
|
|
||||||
if (!controller) {
|
if (!controller) {
|
||||||
const char *dot;
|
r = cg_controller_from_attr(name, &c);
|
||||||
|
if (r < 0)
|
||||||
dot = strchr(name, '.');
|
|
||||||
if (!dot)
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
c = strndup(name, dot - name);
|
|
||||||
if (!c)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
controller = c;
|
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;
|
return -EINVAL;
|
||||||
|
|
||||||
a = cgroup_attribute_find_list(u->cgroup_attributes, controller, name);
|
a = cgroup_attribute_find_list(u->cgroup_attributes, controller, name);
|
||||||
|
@ -990,6 +990,8 @@ int cg_split_spec(const char *spec, char **controller, char **path) {
|
|||||||
assert(spec);
|
assert(spec);
|
||||||
|
|
||||||
if (*spec == '/') {
|
if (*spec == '/') {
|
||||||
|
if (!path_is_safe(spec))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
if (path) {
|
if (path) {
|
||||||
t = strdup(spec);
|
t = strdup(spec);
|
||||||
@ -1007,7 +1009,7 @@ int cg_split_spec(const char *spec, char **controller, char **path) {
|
|||||||
|
|
||||||
e = strchr(spec, ':');
|
e = strchr(spec, ':');
|
||||||
if (!e) {
|
if (!e) {
|
||||||
if (strchr(spec, '/') || spec[0] == 0)
|
if (!filename_is_safe(spec))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (controller) {
|
if (controller) {
|
||||||
@ -1024,29 +1026,34 @@ int cg_split_spec(const char *spec, char **controller, char **path) {
|
|||||||
return 0;
|
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;
|
return -EINVAL;
|
||||||
|
|
||||||
if (controller) {
|
|
||||||
t = strndup(spec, e-spec);
|
|
||||||
if (!t)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (path) {
|
u = strdup(e+1);
|
||||||
u = strdup(e+1);
|
if (!u) {
|
||||||
if (!u) {
|
free(t);
|
||||||
free(t);
|
return -ENOMEM;
|
||||||
return -ENOMEM;
|
}
|
||||||
}
|
if (!path_is_safe(u)) {
|
||||||
|
free(t);
|
||||||
|
free(u);
|
||||||
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (controller)
|
if (controller)
|
||||||
*controller = t;
|
*controller = t;
|
||||||
|
else
|
||||||
|
free(t);
|
||||||
|
|
||||||
if (path)
|
if (path)
|
||||||
*path = u;
|
*path = u;
|
||||||
|
else
|
||||||
|
free(u);
|
||||||
|
|
||||||
return 0;
|
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) {
|
int cg_pid_get_user_unit(pid_t pid, char **unit) {
|
||||||
return cg_pid_get("/user/", pid, 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;
|
||||||
|
}
|
||||||
|
@ -76,3 +76,5 @@ int cg_pid_get_user_unit(pid_t pid, char **unit);
|
|||||||
int cgroup_to_unit(char *cgroup, char **unit);
|
int cgroup_to_unit(char *cgroup, char **unit);
|
||||||
|
|
||||||
char **cg_shorten_controllers(char **controllers);
|
char **cg_shorten_controllers(char **controllers);
|
||||||
|
|
||||||
|
int cg_controller_from_attr(const char *attr, char **controller);
|
||||||
|
@ -561,9 +561,9 @@ int fchmod_umask(int fd, mode_t m) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int write_one_line_file_atomic(const char *fn, const char *line) {
|
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;
|
int r;
|
||||||
char *p;
|
|
||||||
|
|
||||||
assert(fn);
|
assert(fn);
|
||||||
assert(line);
|
assert(line);
|
||||||
@ -585,12 +585,9 @@ int write_one_line_file_atomic(const char *fn, const char *line) {
|
|||||||
|
|
||||||
fflush(f);
|
fflush(f);
|
||||||
|
|
||||||
if (ferror(f)) {
|
if (ferror(f))
|
||||||
if (errno != 0)
|
r = errno ? -errno : -EIO;
|
||||||
r = -errno;
|
else {
|
||||||
else
|
|
||||||
r = -EIO;
|
|
||||||
} else {
|
|
||||||
if (rename(p, fn) < 0)
|
if (rename(p, fn) < 0)
|
||||||
r = -errno;
|
r = -errno;
|
||||||
else
|
else
|
||||||
@ -601,9 +598,6 @@ finish:
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
unlink(p);
|
unlink(p);
|
||||||
|
|
||||||
fclose(f);
|
|
||||||
free(p);
|
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5613,6 +5607,27 @@ bool string_is_safe(const char *p) {
|
|||||||
return true;
|
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 */
|
/* 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,
|
void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size,
|
||||||
int (*compar) (const void *, const void *, void *), void *arg) {
|
int (*compar) (const void *, const void *, void *), void *arg) {
|
||||||
|
@ -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 filename_is_safe(const char *p);
|
||||||
|
bool path_is_safe(const char *p);
|
||||||
bool string_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,
|
void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user