[PATCH v2 038/113] fs: implement O_CHROOT

Ahmad Fatoum a.fatoum at pengutronix.de
Mon Mar 4 10:59:23 PST 2024


For use by EFI file system path resolution, implement an O_CHROOT
flag that will map / to the root of the file system the dirfd points
to instead of the VFS root. If the dirfd points to a mountpoint, it will
be followed to the file system inside. This is similar to Linux openat2
with RESOLVE_IN_ROOT.

Without this, the EFI protocol would have to do path sanitization itself
before passing paths to the barebox VFS implementation.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 fs/fs.c         | 19 +++++++++++++++++--
 include/fcntl.h |  1 +
 2 files changed, 18 insertions(+), 2 deletions(-)

diff --git a/fs/fs.c b/fs/fs.c
index 7aa8a5d69b25..9b876fe1f9be 100644
--- a/fs/fs.c
+++ b/fs/fs.c
@@ -2166,9 +2166,17 @@ static int link_path_walk(const char *name, struct nameidata *nd)
 	}
 }
 
+static bool file_has_flag(FILE *f, unsigned flag)
+{
+	if (IS_ERR_OR_NULL(f))
+		return false;
+	return (f->flags & flag) == flag;
+}
+
 static const char *path_init(int dirfd, struct nameidata *nd, unsigned flags)
 {
 	const char *s = nd->name->name;
+	bool chroot = false;
 	FILE *f = NULL;
 
 	nd->last_type = LAST_ROOT; /* if there are only slashes... */
@@ -2181,10 +2189,12 @@ static const char *path_init(int dirfd, struct nameidata *nd, unsigned flags)
 	/* We don't check for error here yet, as POSIX allows checking
 	 * whether paths are absolute with openat(-1, path, O_PATH)
 	 */
-	if (dirfd != AT_FDCWD)
+	if (dirfd != AT_FDCWD) {
 		f = fd_to_file(dirfd, true);
+		chroot = file_has_flag(f, O_CHROOT);
+	}
 
-	if (*s == '/') {
+	if (*s == '/' && !chroot) {
 		get_root(&nd->path);
 	} else if (dirfd == AT_FDCWD) {
 		get_pwd(&nd->path);
@@ -2195,6 +2205,11 @@ static const char *path_init(int dirfd, struct nameidata *nd, unsigned flags)
 		nd->path.mnt = &f->fsdev->vfsmount;
 		nd->path.dentry = f->dentry;
 		follow_mount(&nd->path);
+
+		if (*s == '/')
+			nd->path.dentry = nd->path.mnt->mnt_root;
+		if (chroot)
+			nd->d_root = nd->path.mnt->mnt_root;
 	}
 
 	return s;
diff --git a/include/fcntl.h b/include/fcntl.h
index a3f5d96cd0ac..532a3a0f6b1e 100644
--- a/include/fcntl.h
+++ b/include/fcntl.h
@@ -24,6 +24,7 @@
 #define O_DIRECTORY	00200000	/* must be a directory */
 #define O_NOFOLLOW	00400000	/* don't follow links */
 #define O_PATH		02000000	/* open as path */
+#define O_CHROOT	04000000	/* dirfd: stay within filesystem root */
 #define __O_TMPFILE	020000000
 
 #define O_TMPFILE       (__O_TMPFILE | O_DIRECTORY)
-- 
2.39.2




More information about the barebox mailing list