summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/namei.c10
-rw-r--r--include/linux/namei.h3
2 files changed, 9 insertions, 4 deletions
diff --git a/fs/namei.c b/fs/namei.c
index eaf07f87cba5..53d815415810 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -2296,13 +2296,16 @@ static const char *path_init(struct nameidata *nd, unsigned flags)
nd->m_seq = read_seqbegin(&mount_lock);
- /* Figure out the starting path and root (if needed). */
- if (*s == '/') {
+ /* Absolute pathname -- fetch the root (LOOKUP_IN_ROOT uses nd->dfd). */
+ if (*s == '/' && !(flags & LOOKUP_IN_ROOT)) {
error = nd_jump_root(nd);
if (unlikely(error))
return ERR_PTR(error);
return s;
- } else if (nd->dfd == AT_FDCWD) {
+ }
+
+ /* Relative pathname -- get the starting-point it is relative to. */
+ if (nd->dfd == AT_FDCWD) {
if (flags & LOOKUP_RCU) {
struct fs_struct *fs = current->fs;
unsigned seq;
@@ -2342,6 +2345,7 @@ static const char *path_init(struct nameidata *nd, unsigned flags)
}
fdput(f);
}
+
/* For scoped-lookups we need to set the root to the dirfd as well. */
if (flags & LOOKUP_IS_SCOPED) {
nd->root = nd->path;
diff --git a/include/linux/namei.h b/include/linux/namei.h
index d2a98083be77..4e77068f7a1a 100644
--- a/include/linux/namei.h
+++ b/include/linux/namei.h
@@ -45,8 +45,9 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT, LAST_BIND};
#define LOOKUP_NO_MAGICLINKS 0x020000 /* No nd_jump_link() crossing. */
#define LOOKUP_NO_XDEV 0x040000 /* No mountpoint crossing. */
#define LOOKUP_BENEATH 0x080000 /* No escaping from starting point. */
+#define LOOKUP_IN_ROOT 0x100000 /* Treat dirfd as fs root. */
/* LOOKUP_* flags which do scope-related checks based on the dirfd. */
-#define LOOKUP_IS_SCOPED LOOKUP_BENEATH
+#define LOOKUP_IS_SCOPED (LOOKUP_BENEATH | LOOKUP_IN_ROOT)
extern int path_pts(struct path *path);