[LinuxBIOS] PATCH: mkdirp() error on new directory outside given parent

Peter Stuge peter at stuge.se
Thu Jul 12 11:06:47 CEST 2007


Hey,

On Thu, Jul 12, 2007 at 10:24:03AM +0200, Patrick Georgi wrote:
> > +int mkdirp(const char *parent, const char *dirpath, mode_t mode)
> conflicts with: (where libgen is a compatibility dummy in solaris
> 10 at least, deferring that object to libc, so it always conflicts)
> 
>       int mkdirp(const char *path, mode_t mode);

Thanks!

New patch, rename mkdirp() to mkdirp_below(). :)

I just had a thought; parent and dirpath are currently treated as
either absolute or relative cwd but perhaps dirpath should always
be treated as absolute or relative parent instead?

mkdirp_below("subdir","x/y/z",077);

would create subdir/x/y/z. Feels much more intuitive, no?


//Peter
-------------- next part --------------
Replaces mkdirp() with mkdirp_below() that aborts directory creation and
returns an error if a part of dirpath is located outside the specified
parent directory. Use the parent "/" to allow new directories anywhere.

Signed-off-by: Peter Stuge <peter at stuge.se>

Index: util/lar/lib.c
===================================================================
--- util/lar/lib.c	(revision 447)
+++ util/lar/lib.c	(working copy)
@@ -24,6 +24,7 @@
 #include <strings.h>
 #include <unistd.h>
 #include <dirent.h>
+#include <errno.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 
@@ -33,42 +34,80 @@
 
 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 will fail.
+ *
+ * @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.
+ * @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 (!getcwd(cwd, MAX_PATH)) {
-		free(path);
-		fprintf(stderr, "Error getting cwd.\n");
-		return -1;
+	if (NULL == realpath(parent, rpar)) {
+		fprintf(stderr, "realpath(%s) failed: %s\n", parent,
+			strerror(errno));
+		goto done;
 	}
+	parlen = strlen(rpar);
 
-	do {
-		pos = index(currpath, '/');
-		if (pos)
-			*pos = 0;
+	for (subdir = path, dirsep = 0; subdir[dirsep]; subdir += dirsep) {
+		dirsep = strcspn(subdir, "/\\");
+		if (!dirsep) {
+			subdir++;
+			continue;
+		}
 
-		/* printf("cp=%s\n", currpath); */
-		mkdir(currpath, mode);
-		ret = chdir(currpath);
+		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;
 
-		if (pos)
-			currpath = pos + 1;
-	} while (pos && !ret && strlen(currpath));
-
-	chdir(cwd);
-	free(path);
-
+done:
+	if (path)
+		free(path);
 	return ret;
 }
 
Index: util/lar/extract.c
===================================================================
--- util/lar/extract.c	(revision 447)
+++ util/lar/extract.c	(working copy)
@@ -119,7 +119,7 @@
 		if (pos) {
 			pos[1] = 0;
 			/* printf("Pathname %s\n",pathname); */
-			mkdirp(pathname, 0755);
+			mkdirp_below(".", pathname, 0755);
 		}
 		free(pathname);
 
Index: util/lar/lib.h
===================================================================
--- util/lar/lib.h	(revision 447)
+++ util/lar/lib.h	(working copy)
@@ -41,7 +41,7 @@
 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);


More information about the coreboot mailing list