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@xxxxxxxxxxxxxx> --- 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