Skip to content
This repository was archived by the owner on Feb 8, 2021. It is now read-only.

Commit 2175595

Browse files
authored
Merge pull request #271 from bergwolf/symlink_mkdir
create volume/fsmap mountpoints properly
2 parents be8536a + a368dae commit 2175595

File tree

3 files changed

+149
-3
lines changed

3 files changed

+149
-3
lines changed

src/container.c

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ static int container_setup_volume(struct hyper_container *container)
102102
for (i = 0; i < container->vols_num; i++) {
103103
char volume[512];
104104
char mountpoint[512];
105+
char *expath;
105106
char *options = NULL;
106107
const char *filevolume = NULL;
107108
vol = &container->vols[i];
@@ -144,9 +145,14 @@ static int container_setup_volume(struct hyper_container *container)
144145
return -1;
145146

146147
if (filevolume == NULL) {
147-
if (hyper_mkdir(mountpoint, 0755) < 0) {
148+
expath = hyper_mkdir_at(".", mountpoint, 0755);
149+
if (expath == NULL) {
148150
perror("create volume dir failed");
149151
return -1;
152+
} else {
153+
/* ensure mountpoint is reachable */
154+
sprintf(mountpoint, "%s", expath);
155+
free(expath);
150156
}
151157
if (vol->docker) {
152158
if (container->initialize &&
@@ -189,7 +195,7 @@ static int container_setup_volume(struct hyper_container *container)
189195

190196
for (i = 0; i < container->maps_num; i++) {
191197
struct stat st;
192-
char *src, path[512], volume[512];
198+
char *src, *expath, path[512], volume[512];
193199
struct fsmap *map = &container->maps[i];
194200
char mountpoint[512];
195201

@@ -201,9 +207,14 @@ static int container_setup_volume(struct hyper_container *container)
201207
stat(src, &st);
202208

203209
if (st.st_mode & S_IFDIR) {
204-
if (hyper_mkdir(mountpoint, 0755) < 0) {
210+
expath = hyper_mkdir_at(".", mountpoint, 0755);
211+
if (expath == NULL) {
205212
perror("create map dir failed");
206213
return -1;
214+
} else {
215+
/* ensure mountpoint is reachable */
216+
sprintf(mountpoint, "%s", expath);
217+
free(expath);
207218
}
208219
if (map->docker) {
209220
/* converted from volume */

src/util.c

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,140 @@ int hyper_create_file(const char *hyper_path)
301301
return 0;
302302
}
303303

304+
static char *hyper_resolve_link(char *path)
305+
{
306+
char buf[512];
307+
int len;
308+
309+
len = readlink(path, buf, sizeof(buf));
310+
if (len < 0) {
311+
perror("failed to read mkdir symlink");
312+
return NULL;
313+
} else if (len >= sizeof(buf)) {
314+
errno = ENAMETOOLONG;
315+
return NULL;
316+
}
317+
318+
buf[len] = '\0';
319+
fprintf(stdout, "follow link %s\n", buf);
320+
return strdup(buf);
321+
}
322+
323+
/**
324+
* hyper_mkdir_follow_link - create directories recurrsively while resolving symlinks
325+
* as if we were in a chroot jail.
326+
*
327+
* @root: chroot jail path.
328+
* @parent: what's already created to the target directory.
329+
* @path: target directory. It is always relative to @root even if it starts with /.
330+
* @mode: directory mode.
331+
* @link_max: max number of symlinks to follow.
332+
* @depth: number of components resolved.
333+
*
334+
* Upon success, @parent is changed to point to resolved path name.
335+
*/
336+
static int hyper_mkdir_follow_link(char *root, char *parent, char *path,
337+
mode_t mode, int *link_max, int *depth)
338+
{
339+
char *comp, *prev, *link, *dummy, *npath, *delim = "/";
340+
struct stat st;
341+
342+
npath = strdup(path);
343+
if (npath == NULL)
344+
goto out;
345+
346+
comp = strtok_r(npath, delim, &dummy);
347+
if (comp == NULL)
348+
goto out;
349+
350+
do {
351+
if (!strcmp(comp, "."))
352+
continue;
353+
354+
if (strlen(parent) + strlen(comp) + 1 >= 512) {
355+
errno = ENAMETOOLONG;
356+
goto out;
357+
}
358+
prev = &parent[strlen(parent)];
359+
strcat(parent, "/");
360+
strcat(parent, comp);
361+
if (!strcmp(comp, "..")) {
362+
if (--(*depth) <= 0) {
363+
/* points to root */
364+
sprintf(parent, "%s", root);
365+
*depth = 0;
366+
}
367+
/* no need to check parent directory */
368+
continue;
369+
} else {
370+
(*depth)++;
371+
}
372+
373+
if (lstat(parent, &st) >= 0) {
374+
if (S_ISDIR(st.st_mode)) {
375+
continue;
376+
} else if (S_ISLNK(st.st_mode)) {
377+
if (--(*link_max) <= 0) {
378+
errno = ELOOP;
379+
goto out;
380+
}
381+
link = hyper_resolve_link(parent);
382+
if (link == NULL)
383+
goto out;
384+
if (link[0] == '/') {
385+
sprintf(parent, "%s", root);
386+
*depth = 0;
387+
} else {
388+
*prev = '\0'; /* drop current comp */
389+
(*depth)--;
390+
}
391+
if (hyper_mkdir_follow_link(root, parent, link, mode, link_max, depth) < 0) {
392+
free(link);
393+
goto out;
394+
}
395+
free(link);
396+
continue;
397+
} else {
398+
errno = ENOTDIR;
399+
goto out;
400+
}
401+
}
402+
403+
fprintf(stdout, "create directory %s\n", parent);
404+
if (mkdir(parent, mode) < 0 && errno != EEXIST) {
405+
perror("failed to create directory");
406+
goto out;
407+
}
408+
} while((comp = strtok_r(NULL, delim, &dummy)) != NULL);
409+
410+
/* reset errno to mark success */
411+
errno = 0;
412+
out:
413+
free(npath);
414+
printf("parent is %s errno %d\n", parent, errno);
415+
return errno ? -1 : 0;
416+
}
417+
418+
/*
419+
* hyper_mkdir_at() is similar to hyper_mkdir() with the exception that
420+
* when there are symlinks in the path components, it acts as if we created
421+
* directories in a chroot jail. @path is always considered relative to root
422+
* even if it starts with a leading stash ('/').
423+
*
424+
* Upon success, return symlink expanded result.
425+
*/
426+
char *hyper_mkdir_at(char *root, char *path, mode_t mode)
427+
{
428+
char result[512];
429+
int depth = 0, max_link = 40;
430+
431+
sprintf(result, "%s", root);
432+
if (hyper_mkdir_follow_link(root, result, path, mode, &max_link, &depth) < 0)
433+
return NULL;
434+
435+
return strdup(result);
436+
}
437+
304438
int hyper_mkdir(char *path, mode_t mode)
305439
{
306440
struct stat st;

src/util.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ int hyper_cmd(char *cmd);
2929
int hyper_create_file(const char *hyper_path);
3030
void hyper_filize(char *hyper_path);
3131
int hyper_mkdir(char *path, mode_t mode);
32+
char *hyper_mkdir_at(char *root, char *path, mode_t mode);
3233
int hyper_write_file(const char *path, const char *value, size_t len);
3334
int hyper_open_channel(char *channel, int mode);
3435
int hyper_setfd_cloexec(int fd);

0 commit comments

Comments
 (0)