[PATCH 1/6] path: use openat()

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Ruediger Meier <ruediger.meier@xxxxxxxxxxx>

path_vcreate_with_prefix() is going to be removed.

Signed-off-by: Ruediger Meier <ruediger.meier@xxxxxxxxxxx>
---
 lib/path.c | 111 ++++++++++++++++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 96 insertions(+), 15 deletions(-)

diff --git a/lib/path.c b/lib/path.c
index 79c1e7a..94181fe 100644
--- a/lib/path.c
+++ b/lib/path.c
@@ -26,18 +26,60 @@
 #include <stdio.h>
 #include <inttypes.h>
 #include <errno.h>
+#include <sys/stat.h>
 
 #include "all-io.h"
 #include "path.h"
 #include "nls.h"
 #include "c.h"
 
+static int rootfd = -1;
 static size_t prefixlen;
+static char pathbuf_prefix[PATH_MAX];
 static char pathbuf[PATH_MAX];
 
+/* It's a programming error if they try us to use with relative paths. */
+#define PATH_REQUIRE_ABSOLUTE(path) \
+	assert( !path || *path == '/' )
+
+static inline const char *
+path_relative_if_sysroot(const char *p)
+{
+	/* Convert to relative path if we have a prefix (sysroot). Otherwise
+	 * openat() functions would ignore the dirfd. */
+	if(p && rootfd >= 0)
+		while(*p && *p == '/') ++p;
+	return p;
+}
+
 static const char *
 path_vcreate(const char *path, va_list ap)
 {
+	const char * p = pathbuf;
+	int rc = vsnprintf(
+		pathbuf, sizeof(pathbuf), path, ap);
+
+	if (rc < 0)
+		goto err;
+	if ((size_t)rc >= sizeof(pathbuf)) {
+		errno = ENAMETOOLONG;
+		goto err;
+	}
+
+	PATH_REQUIRE_ABSOLUTE(p);
+	p = path_relative_if_sysroot(p);
+
+	return p;
+err:
+	/* Only for error messages when we could not construct a path. */
+	strcpy(pathbuf, "path");
+	return NULL;
+}
+
+static const char *
+path_vcreate_with_prefix(const char *path, va_list ap)
+{
+	strcpy(pathbuf, pathbuf_prefix);
 	int rc = vsnprintf(
 		pathbuf + prefixlen, sizeof(pathbuf) - prefixlen, path, ap);
 
@@ -55,30 +97,60 @@ path_get(const char *path, ...)
 {
 	const char *p;
 	va_list ap;
+	static char userbuf[sizeof(pathbuf)];
 
 	va_start(ap, path);
-	p = path_vcreate(path, ap);
+	p = path_vcreate_with_prefix(path, ap);
 	va_end(ap);
 
+	if (p) {
+		/* do not hand out our global buffer to the user to avoid overlapping
+		 * problems in case we get this string back from the user */
+		p = strcpy(userbuf, p);
+	}
+
 	return p;
 }
 
+/* Get the last used path. Only for error messages. */
+static const char *
+path_last_path(void)
+{
+	if (rootfd < 0) {
+		return pathbuf;
+	} else {
+		char prfx[] = "[sysroot]/"; /* we could also add the real prefix */
+		size_t n = sizeof(prfx) - 1 ;
+		memmove(pathbuf+n, pathbuf, sizeof(pathbuf)-n);
+		pathbuf[sizeof(pathbuf)-1] = '\0';
+		strncpy(pathbuf, prfx, n);
+		return pathbuf;
+	}
+}
+
 static FILE *
 path_vfopen(const char *mode, int exit_on_error, const char *path, va_list ap)
 {
+	int fd;
 	FILE *f;
 	const char *p = path_vcreate(path, ap);
 	if (!p)
 		goto err;
 
-	f = fopen(p, mode);
-	if (!f)
+	fd = openat(rootfd, p, O_RDONLY);
+	if (fd == -1)
+		goto err;
+
+	f = fdopen(fd, mode);
+	if (!f) {
+		close(fd);
 		goto err;
+	}
 
 	return f;
 err:
 	if (exit_on_error)
-		err(EXIT_FAILURE, _("cannot open %s"), p ? p : "path");
+		err(EXIT_FAILURE, _("cannot open %s"), path_last_path());
 	return NULL;
 }
 
@@ -90,13 +162,13 @@ path_vopen(int flags, const char *path, va_list ap)
 	if (!p)
 		goto err;
 
-	fd = open(p, flags);
+	fd = openat(rootfd, p, flags);
 	if (fd == -1)
 		goto err;
 
 	return fd;
 err:
-	err(EXIT_FAILURE, _("cannot open %s"), p ? p : "path");
+	err(EXIT_FAILURE, _("cannot open %s"), path_last_path());
 }
 
 FILE *
@@ -123,7 +195,7 @@ path_read_str(char *result, size_t len, const char *path, ...)
 	va_end(ap);
 
 	if (!fgets(result, len, fd))
-		err(EXIT_FAILURE, _("cannot read %s"), pathbuf);
+		err(EXIT_FAILURE, _("cannot read %s"), path_last_path());
 	fclose(fd);
 
 	len = strlen(result);
@@ -144,9 +216,9 @@ path_read_s32(const char *path, ...)
 
 	if (fscanf(fd, "%d", &result) != 1) {
 		if (ferror(fd))
-			err(EXIT_FAILURE, _("cannot read %s"), pathbuf);
+			err(EXIT_FAILURE, _("cannot read %s"), path_last_path());
 		else
-			errx(EXIT_FAILURE, _("parse error: %s"), pathbuf);
+			errx(EXIT_FAILURE, _("parse error: %s"), path_last_path());
 	}
 	fclose(fd);
 	return result;
@@ -165,9 +237,9 @@ path_read_u64(const char *path, ...)
 
 	if (fscanf(fd, "%"SCNu64, &result) != 1) {
 		if (ferror(fd))
-			err(EXIT_FAILURE, _("cannot read %s"), pathbuf);
+			err(EXIT_FAILURE, _("cannot read %s"), path_last_path());
 		else
-			errx(EXIT_FAILURE, _("parse error: %s"), pathbuf);
+			errx(EXIT_FAILURE, _("parse error: %s"), path_last_path());
 	}
 	fclose(fd);
 	return result;
@@ -197,7 +269,7 @@ path_exist(const char *path, ...)
 	p = path_vcreate(path, ap);
 	va_end(ap);
 
-	return p && access(p, F_OK) == 0;
+	return p && faccessat(rootfd, p, F_OK, 0) == 0;
 }
 
 #ifdef HAVE_CPU_SET_T
@@ -213,7 +285,7 @@ path_cpuparse(int maxcpus, int islist, const char *path, va_list ap)
 	fd = path_vfopen("r" UL_CLOEXECSTR, 1, path, ap);
 
 	if (!fgets(buf, len, fd))
-		err(EXIT_FAILURE, _("cannot read %s"), pathbuf);
+		err(EXIT_FAILURE, _("cannot read %s"), path_last_path());
 	fclose(fd);
 
 	len = strlen(buf);
@@ -265,12 +337,21 @@ path_set_prefix(const char *prefix)
 {
 	size_t len = strlen(prefix);
 
-	if (len >= sizeof(pathbuf) - 1) {
+	/* ignore trivial prefix */
+	if (len == 0)
+		return 0;
+
+	if (len >= sizeof(pathbuf_prefix) - 1) {
 		errno = ENAMETOOLONG;
 		return -1;
 	}
+
+	rootfd = open(prefix, O_RDONLY|O_DIRECTORY|O_CLOEXEC);
+	if (rootfd < 0)
+		return -1;
+
 	prefixlen = len;
-	strcpy(pathbuf, prefix);
+	strcpy(pathbuf_prefix, prefix);
 	return 0;
 }
 
-- 
1.8.5.6

--
To unsubscribe from this list: send the line "unsubscribe util-linux" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Netdev]     [Ethernet Bridging]     [Linux Wireless]     [Kernel Newbies]     [Security]     [Linux for Hams]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux Admin]     [Samba]

  Powered by Linux