diff options
author | Ahmad Fatoum <a.fatoum@pengutronix.de> | 2024-03-04 19:59:23 +0100 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2024-03-05 16:28:05 +0100 |
commit | b89cf57d484eacd2550e703d00ca1c9d479d2407 (patch) | |
tree | b34fe7126308c630ca9aa67d9464496a3a21c58a /fs | |
parent | 127f7b809e0c8079b4d8636e3f345d52eebd4875 (diff) | |
download | barebox-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.c | 19 |
1 files changed, 17 insertions, 2 deletions
@@ -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; |