cgfsng: avoid tiny race window

Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
This commit is contained in:
Christian Brauner 2018-10-02 17:40:25 +02:00
parent ee455be41c
commit 17e5599174
No known key found for this signature in database
GPG Key ID: 8EB056D53EECB12D
2 changed files with 57 additions and 26 deletions

View File

@ -1257,13 +1257,50 @@ on_error:
return bret; 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) static bool monitor_create_path_for_hierarchy(struct hierarchy *h, char *cgname)
{ {
int ret; int ret;
h->monitor_full_path = must_make_path(h->mountpoint, h->container_base_path, cgname, NULL); h->monitor_full_path = must_make_path(h->mountpoint, h->container_base_path, cgname, NULL);
if (dir_exists(h->monitor_full_path)) { ret = mkdir_eexist_on_last(h->monitor_full_path, 0755);
ERROR("The cgroup \"%s\" already existed", h->monitor_full_path); if (ret < 0) {
ERROR("Failed to create cgroup \"%s\"", h->monitor_full_path);
return false; return false;
} }
@ -1272,12 +1309,6 @@ static bool monitor_create_path_for_hierarchy(struct hierarchy *h, char *cgname)
return false; 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); 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; int ret;
h->container_full_path = must_make_path(h->mountpoint, h->container_base_path, cgname, NULL); h->container_full_path = must_make_path(h->mountpoint, h->container_base_path, cgname, NULL);
if (dir_exists(h->container_full_path)) { ret = mkdir_eexist_on_last(h->container_full_path, 0755);
ERROR("The cgroup \"%s\" already existed", h->container_full_path); if (ret < 0) {
ERROR("Failed to create cgroup \"%s\"", h->container_full_path);
return false; return false;
} }
@ -1296,12 +1328,6 @@ static bool container_create_path_for_hierarchy(struct hierarchy *h, char *cgnam
return false; 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); return cg_unified_create_cgroup(h, cgname);
} }

View File

@ -221,26 +221,31 @@ extern int get_u16(unsigned short *val, const char *arg, int base)
return 0; 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 *tmp = dir;
const char *orig = dir; const char *orig = dir;
do {
int ret;
char *makeme; char *makeme;
do {
dir = tmp + strspn(tmp, "/"); dir = tmp + strspn(tmp, "/");
tmp = dir + strcspn(dir, "/"); tmp = dir + strcspn(dir, "/");
errno = ENOMEM;
makeme = strndup(orig, dir - orig); makeme = strndup(orig, dir - orig);
if (*makeme) { if (!makeme)
if (mkdir(makeme, mode) && errno != EEXIST) { return -1;
SYSERROR("failed to create directory '%s'", makeme);
ret = mkdir(makeme, mode);
if (ret < 0 && errno != EEXIST) {
SYSERROR("Failed to create directory \"%s\"", makeme);
free(makeme); free(makeme);
return -1; return -1;
} }
}
free(makeme); free(makeme);
} while(tmp != dir);
} while (tmp != dir);
return 0; return 0;
} }