From 7f49e38558bd7791a83a7fd9cedb2d87bf03d851 Mon Sep 17 00:00:00 2001 From: Peter Stuge Date: Fri, 13 Jul 2007 10:40:31 +0000 Subject: [PATCH] Replaces mkdirp() with mkdirp_below() that aborts directory creation and returns an error if any part of dirpath is located outside the specified parent directory. Use the parent "/" to allow new directories anywhere. Note that dirpath is relative to the working directory, not to parent. Signed-off-by: Peter Stuge Acked-by: Stefan Reinauer git-svn-id: svn://coreboot.org/repository/LinuxBIOSv3@453 f3766cd6-281f-0410-b1cd-43a5c92072e9 --- util/lar/extract.c | 2 +- util/lar/lib.c | 97 +++++++++++++++++++++++++++++++++------------- util/lar/lib.h | 2 +- 3 files changed, 71 insertions(+), 30 deletions(-) diff --git a/util/lar/extract.c b/util/lar/extract.c index 83dc0332ed..36ce347cc4 100644 --- a/util/lar/extract.c +++ b/util/lar/extract.c @@ -119,7 +119,7 @@ int extract_lar(const char *archivename, struct file *files) if (pos) { pos[1] = 0; /* printf("Pathname %s\n",pathname); */ - mkdirp(pathname, 0755); + mkdirp_below(".", pathname, 0755); } free(pathname); diff --git a/util/lar/lib.c b/util/lar/lib.c index 8475f747aa..c5bab43657 100644 --- a/util/lar/lib.c +++ b/util/lar/lib.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -33,42 +34,82 @@ static struct file *files = NULL; -int mkdirp(const char *dirpath, mode_t mode) +/** + * Create a new directory including any missing parent directories. + * + * NOTE: This function does not do complete path resolution as described in + * Linux path_resolution(2) and hence will fail for complex paths: + * + * e.g.: mkdirp_below("subdir", "subdir/../subdir/x", 0777); + * + * This call should create subdir/x, but since subdir/.. is outside subdir, + * the function returns an error. + * + * @param parent Return an error if a new directory would be created outside + * this directory. Pass "/" to allow new directories to be created anywhere. + * @param dirpath The new directory that should be created, the path can be + * either absolute or relative to the current working directory. (It is not + * relative to parent.) + * @param mode Permissions to use for newly created directories. + */ +int mkdirp_below(const char *parent, const char *dirpath, mode_t mode) { - char *pos, *currpath, *path; - char cwd[MAX_PATH]; - int ret = 0; + int ret = -1; + size_t dirsep, parlen, sublen; + char c, *r, *path = NULL, *subdir, rpar[PATH_MAX], rsub[PATH_MAX]; + + if (!dirpath) { + fprintf(stderr, "mkdirp_below: No new directory specified\n"); + goto done; + } path = strdup(dirpath); if (!path) { - fprintf(stderr, "Out of memory.\n"); - exit(1); + perror("Duplicate new directory failed:"); + goto done; } - currpath = path; + if (NULL == realpath(parent, rpar)) { + fprintf(stderr, "realpath(%s) failed: %s\n", parent, + strerror(errno)); + goto done; + } + parlen = strlen(rpar); - if (!getcwd(cwd, MAX_PATH)) { + for (subdir = path, dirsep = 0; subdir[dirsep]; subdir += dirsep) { + dirsep = strcspn(subdir, "/\\"); + if (!dirsep) { + subdir++; + continue; + } + + c = subdir[dirsep]; + subdir[dirsep] = 0; + r = realpath(path, rsub); + sublen = strlen(rsub); + if (NULL == r) { + if(ENOENT != errno) { + fprintf(stderr, "realpath(%s) failed: %s\n", + path, strerror(errno)); + goto done; + } + } else if (sublen < parlen || strncmp(rpar, rsub, parlen)) { + fprintf(stderr, "Abort: %s is outside %s\n", dirpath, + parent); + goto done; + } + if(-1 == mkdir(path, mode) && EEXIST != errno) { + fprintf(stderr, "mkdir(%s): %s\n", path, + strerror(errno)); + goto done; + } + subdir[dirsep] = c; + } + ret = 0; + +done: + if (path) free(path); - fprintf(stderr, "Error getting cwd.\n"); - return -1; - } - - do { - pos = index(currpath, '/'); - if (pos) - *pos = 0; - - /* printf("cp=%s\n", currpath); */ - mkdir(currpath, mode); - ret = chdir(currpath); - - if (pos) - currpath = pos + 1; - } while (pos && !ret && strlen(currpath)); - - chdir(cwd); - free(path); - return ret; } diff --git a/util/lar/lib.h b/util/lar/lib.h index 4d7bf51a49..02c4f396cb 100644 --- a/util/lar/lib.h +++ b/util/lar/lib.h @@ -41,7 +41,7 @@ long get_larsize(void); char *get_bootblock(void); /* prototypes for lib.c functions */ -int mkdirp(const char *dirpath, mode_t mode); +int mkdirp_below(const char *parent, const char *dirpath, mode_t mode); int add_files(const char *name); int add_file_or_directory(const char *name);