summaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorAhmad Fatoum <a.fatoum@pengutronix.de>2024-03-04 19:59:23 +0100
committerSascha Hauer <s.hauer@pengutronix.de>2024-03-05 16:28:05 +0100
commitb89cf57d484eacd2550e703d00ca1c9d479d2407 (patch)
treeb34fe7126308c630ca9aa67d9464496a3a21c58a /fs
parent127f7b809e0c8079b4d8636e3f345d52eebd4875 (diff)
downloadbarebox-b89cf57d484eacd2550e703d00ca1c9d479d2407.tar.gz
barebox-b89cf57d484eacd2550e703d00ca1c9d479d2407.tar.xz
fs: implement O_CHROOT
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@pengutronix.de> Link: https://lore.barebox.org/20240304190038.3486881-39-a.fatoum@pengutronix.de Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'fs')
-rw-r--r--fs/fs.c19
1 files changed, 17 insertions, 2 deletions
diff --git a/fs/fs.c b/fs/fs.c
index 7aa8a5d69b..9b876fe1f9 100644
--- a/fs/fs.c
+++ b/fs/fs.c
@@ -2166,9 +2166,17 @@ OK:
}
}
+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;