From 17e55991744576bca20e370a6d829da99c3fc801 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Tue, 2 Oct 2018 17:40:25 +0200 Subject: [PATCH] cgfsng: avoid tiny race window Signed-off-by: Christian Brauner --- src/lxc/cgroups/cgfsng.c | 58 +++++++++++++++++++++++++++++----------- src/lxc/utils.c | 25 ++++++++++------- 2 files changed, 57 insertions(+), 26 deletions(-) diff --git a/src/lxc/cgroups/cgfsng.c b/src/lxc/cgroups/cgfsng.c index 0fc9b11d2..ec4501c33 100644 --- a/src/lxc/cgroups/cgfsng.c +++ b/src/lxc/cgroups/cgfsng.c @@ -1257,13 +1257,50 @@ on_error: return bret; } +static int mkdir_eexist_on_last(const char *dir, mode_t mode) +{ + const char *tmp = dir; + const char *orig = dir; + size_t orig_len; + + orig_len = strlen(dir); + do { + int ret; + size_t cur_len; + char *makeme; + + dir = tmp + strspn(tmp, "/"); + tmp = dir + strcspn(dir, "/"); + + errno = ENOMEM; + cur_len = dir - orig; + makeme = strndup(orig, cur_len); + if (!makeme) + return -1; + + ret = mkdir(makeme, mode); + if (ret < 0) { + if ((errno != EEXIST) || (orig_len == cur_len)) { + SYSERROR("Failed to create directory \"%s\"", makeme); + free(makeme); + return -1; + } + } + free(makeme); + + } while (tmp != dir); + + return 0; +} + static bool monitor_create_path_for_hierarchy(struct hierarchy *h, char *cgname) { int ret; h->monitor_full_path = must_make_path(h->mountpoint, h->container_base_path, cgname, NULL); - if (dir_exists(h->monitor_full_path)) { - ERROR("The cgroup \"%s\" already existed", h->monitor_full_path); + ret = mkdir_eexist_on_last(h->monitor_full_path, 0755); + if (ret < 0) { + ERROR("Failed to create cgroup \"%s\"", h->monitor_full_path); return false; } @@ -1272,12 +1309,6 @@ static bool monitor_create_path_for_hierarchy(struct hierarchy *h, char *cgname) return false; } - ret = mkdir_p(h->monitor_full_path, 0755); - if (ret < 0) { - ERROR("Failed to create cgroup \"%s\"", h->monitor_full_path); - return false; - } - return cg_unified_create_cgroup(h, cgname); } @@ -1286,8 +1317,9 @@ static bool container_create_path_for_hierarchy(struct hierarchy *h, char *cgnam int ret; h->container_full_path = must_make_path(h->mountpoint, h->container_base_path, cgname, NULL); - if (dir_exists(h->container_full_path)) { - ERROR("The cgroup \"%s\" already existed", h->container_full_path); + ret = mkdir_eexist_on_last(h->container_full_path, 0755); + if (ret < 0) { + ERROR("Failed to create cgroup \"%s\"", h->container_full_path); return false; } @@ -1296,12 +1328,6 @@ static bool container_create_path_for_hierarchy(struct hierarchy *h, char *cgnam return false; } - ret = mkdir_p(h->container_full_path, 0755); - if (ret < 0) { - ERROR("Failed to create cgroup \"%s\"", h->container_full_path); - return false; - } - return cg_unified_create_cgroup(h, cgname); } diff --git a/src/lxc/utils.c b/src/lxc/utils.c index 27f4578ba..af0190fa3 100644 --- a/src/lxc/utils.c +++ b/src/lxc/utils.c @@ -221,26 +221,31 @@ extern int get_u16(unsigned short *val, const char *arg, int base) return 0; } -extern int mkdir_p(const char *dir, mode_t mode) +int mkdir_p(const char *dir, mode_t mode) { const char *tmp = dir; const char *orig = dir; - char *makeme; - do { + int ret; + char *makeme; + dir = tmp + strspn(tmp, "/"); tmp = dir + strcspn(dir, "/"); + errno = ENOMEM; makeme = strndup(orig, dir - orig); - if (*makeme) { - if (mkdir(makeme, mode) && errno != EEXIST) { - SYSERROR("failed to create directory '%s'", makeme); - free(makeme); - return -1; - } + if (!makeme) + return -1; + + ret = mkdir(makeme, mode); + if (ret < 0 && errno != EEXIST) { + SYSERROR("Failed to create directory \"%s\"", makeme); + free(makeme); + return -1; } free(makeme); - } while(tmp != dir); + + } while (tmp != dir); return 0; }