cgroups: fix memory leak and simplify code

Closes #3252. Reported-by: 's avatarLiFeng <lifeng68@huawei.com> Signed-off-by: 's avatarChristian Brauner <christian.brauner@ubuntu.com>
parent dab55f77
...@@ -54,19 +54,6 @@ ...@@ -54,19 +54,6 @@
lxc_log_define(cgfsng, cgroup); lxc_log_define(cgfsng, cgroup);
static void free_string_list(char **clist)
{
int i;
if (!clist)
return;
for (i = 0; clist[i]; i++)
free(clist[i]);
free(clist);
}
/* Given a pointer to a null-terminated array of pointers, realloc to add one /* Given a pointer to a null-terminated array of pointers, realloc to add one
* entry, and point the new entry to NULL. Do not fail. Return the index to the * entry, and point the new entry to NULL. Do not fail. Return the index to the
* second-to-last entry - that is, the one which is now available for use * second-to-last entry - that is, the one which is now available for use
...@@ -2940,12 +2927,11 @@ static void cg_unified_delegate(char ***delegate) ...@@ -2940,12 +2927,11 @@ static void cg_unified_delegate(char ***delegate)
*/ */
static int cg_hybrid_init(struct cgroup_ops *ops, bool relative, bool unprivileged) static int cg_hybrid_init(struct cgroup_ops *ops, bool relative, bool unprivileged)
{ {
__do_free char *basecginfo = NULL; __do_free char *basecginfo = NULL, *line = NULL;
__do_free char *line = NULL; __do_free_string_list char **klist = NULL, **nlist = NULL;
__do_fclose FILE *f = NULL; __do_fclose FILE *f = NULL;
int ret; int ret;
size_t len = 0; size_t len = 0;
char **klist = NULL, **nlist = NULL;
/* Root spawned containers escape the current cgroup, so use init's /* Root spawned containers escape the current cgroup, so use init's
* cgroups as our base in that case. * cgroups as our base in that case.
...@@ -2968,11 +2954,11 @@ static int cg_hybrid_init(struct cgroup_ops *ops, bool relative, bool unprivileg ...@@ -2968,11 +2954,11 @@ static int cg_hybrid_init(struct cgroup_ops *ops, bool relative, bool unprivileg
lxc_cgfsng_print_basecg_debuginfo(basecginfo, klist, nlist); lxc_cgfsng_print_basecg_debuginfo(basecginfo, klist, nlist);
while (getline(&line, &len, f) != -1) { while (getline(&line, &len, f) != -1) {
__do_free char *base_cgroup = NULL, *mountpoint = NULL;
__do_free_string_list char **controller_list = NULL;
int type; int type;
bool writeable; bool writeable;
struct hierarchy *new; struct hierarchy *new;
char *base_cgroup = NULL, *mountpoint = NULL;
char **controller_list = NULL;
type = get_cgroup_version(line); type = get_cgroup_version(line);
if (type == 0) if (type == 0)
...@@ -3000,18 +2986,18 @@ static int cg_hybrid_init(struct cgroup_ops *ops, bool relative, bool unprivileg ...@@ -3000,18 +2986,18 @@ static int cg_hybrid_init(struct cgroup_ops *ops, bool relative, bool unprivileg
if (type == CGROUP_SUPER_MAGIC) if (type == CGROUP_SUPER_MAGIC)
if (controller_list_is_dup(ops->hierarchies, controller_list)) if (controller_list_is_dup(ops->hierarchies, controller_list))
log_trace_errno(goto next, EEXIST, "Skipping duplicating controller"); log_trace_errno(continue, EEXIST, "Skipping duplicating controller");
mountpoint = cg_hybrid_get_mountpoint(line); mountpoint = cg_hybrid_get_mountpoint(line);
if (!mountpoint) if (!mountpoint)
log_error_errno(goto next, EINVAL, "Failed parsing mountpoint from \"%s\"", line); log_error_errno(continue, EINVAL, "Failed parsing mountpoint from \"%s\"", line);
if (type == CGROUP_SUPER_MAGIC) if (type == CGROUP_SUPER_MAGIC)
base_cgroup = cg_hybrid_get_current_cgroup(basecginfo, controller_list[0], CGROUP_SUPER_MAGIC); base_cgroup = cg_hybrid_get_current_cgroup(basecginfo, controller_list[0], CGROUP_SUPER_MAGIC);
else else
base_cgroup = cg_hybrid_get_current_cgroup(basecginfo, NULL, CGROUP2_SUPER_MAGIC); base_cgroup = cg_hybrid_get_current_cgroup(basecginfo, NULL, CGROUP2_SUPER_MAGIC);
if (!base_cgroup) if (!base_cgroup)
log_error_errno(goto next, EINVAL, "Failed to find current cgroup"); log_error_errno(continue, EINVAL, "Failed to find current cgroup");
trim(base_cgroup); trim(base_cgroup);
prune_init_scope(base_cgroup); prune_init_scope(base_cgroup);
...@@ -3020,7 +3006,7 @@ static int cg_hybrid_init(struct cgroup_ops *ops, bool relative, bool unprivileg ...@@ -3020,7 +3006,7 @@ static int cg_hybrid_init(struct cgroup_ops *ops, bool relative, bool unprivileg
else else
writeable = test_writeable_v1(mountpoint, base_cgroup); writeable = test_writeable_v1(mountpoint, base_cgroup);
if (!writeable) if (!writeable)
log_trace_errno(goto next, EROFS, "The %s group is not writeable", base_cgroup); log_trace_errno(continue, EROFS, "The %s group is not writeable", base_cgroup);
if (type == CGROUP2_SUPER_MAGIC) { if (type == CGROUP2_SUPER_MAGIC) {
char *cgv2_ctrl_path; char *cgv2_ctrl_path;
...@@ -3040,26 +3026,16 @@ static int cg_hybrid_init(struct cgroup_ops *ops, bool relative, bool unprivileg ...@@ -3040,26 +3026,16 @@ static int cg_hybrid_init(struct cgroup_ops *ops, bool relative, bool unprivileg
/* Exclude all controllers that cgroup use does not want. */ /* Exclude all controllers that cgroup use does not want. */
if (!cgroup_use_wants_controllers(ops, controller_list)) if (!cgroup_use_wants_controllers(ops, controller_list))
log_trace_errno(goto next, EINVAL, "Skipping controller"); log_trace_errno(continue, EINVAL, "Skipping controller");
new = add_hierarchy(&ops->hierarchies, controller_list, mountpoint, base_cgroup, type); new = add_hierarchy(&ops->hierarchies, move_ptr(controller_list), move_ptr(mountpoint), move_ptr(base_cgroup), type);
if (type == CGROUP2_SUPER_MAGIC && !ops->unified) { if (type == CGROUP2_SUPER_MAGIC && !ops->unified) {
if (unprivileged) if (unprivileged)
cg_unified_delegate(&new->cgroup2_chown); cg_unified_delegate(&new->cgroup2_chown);
ops->unified = new; ops->unified = new;
} }
continue;
next:
free_string_list(controller_list);
free(mountpoint);
free(base_cgroup);
} }
free_string_list(klist);
free_string_list(nlist);
TRACE("Writable cgroup hierarchies:"); TRACE("Writable cgroup hierarchies:");
lxc_cgfsng_print_hierarchies(ops); lxc_cgfsng_print_hierarchies(ops);
......
...@@ -13,11 +13,35 @@ ...@@ -13,11 +13,35 @@
#include "macro.h" #include "macro.h"
#define define_cleanup_attribute(type, func) \
static inline void func##_ptr(type *ptr) \
{ \
if (*ptr) \
func(*ptr); \
}
#define free_disarm(ptr) \
({ \
free(ptr); \
move_ptr(ptr); \
})
static inline void __auto_free__(void *p) static inline void __auto_free__(void *p)
{ {
free(*(void **)p); free(*(void **)p);
} }
static inline void free_string_list(char **list)
{
if (list) {
for (int i = 0; list[i]; i++)
free(list[i]);
free_disarm(list);
}
}
define_cleanup_attribute(char **, free_string_list);
#define __do_free_string_list __attribute__((__cleanup__(free_string_list_ptr)))
static inline void __auto_fclose__(FILE **f) static inline void __auto_fclose__(FILE **f)
{ {
if (*f) if (*f)
...@@ -38,12 +62,6 @@ static inline void __auto_closedir__(DIR **d) ...@@ -38,12 +62,6 @@ static inline void __auto_closedir__(DIR **d)
fd = -EBADF; \ fd = -EBADF; \
} }
#define free_disarm(ptr) \
({ \
free(ptr); \
move_ptr(ptr); \
})
static inline void __auto_close__(int *fd) static inline void __auto_close__(int *fd)
{ {
close_prot_errno_disarm(*fd); close_prot_errno_disarm(*fd);
......
...@@ -77,7 +77,6 @@ static inline void clear_bit(unsigned bit, uint32_t *bitarr) ...@@ -77,7 +77,6 @@ static inline void clear_bit(unsigned bit, uint32_t *bitarr)
bitarr[bit / NBITS] &= ~(1 << (bit % NBITS)); bitarr[bit / NBITS] &= ~(1 << (bit % NBITS));
} }
static char *copy_to_eol(char *s); static char *copy_to_eol(char *s);
static void free_string_list(char **list);
static char *get_mountpoint(char *line); static char *get_mountpoint(char *line);
static bool get_uid_gid(const char *user, uid_t *uid, gid_t *gid); static bool get_uid_gid(const char *user, uid_t *uid, gid_t *gid);
static int handle_login(const char *user, uid_t uid, gid_t gid); static int handle_login(const char *user, uid_t uid, gid_t gid);
...@@ -454,16 +453,6 @@ static size_t string_list_length(char **list) ...@@ -454,16 +453,6 @@ static size_t string_list_length(char **list)
return len; return len;
} }
/* Free null-terminated array of strings. */
static void free_string_list(char **list)
{
char **it;
for (it = list; it && *it; it++)
free(*it);
free(list);
}
/* Write single integer to file. */ /* Write single integer to file. */
static bool write_int(char *path, int v) static bool write_int(char *path, int v)
{ {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment