Skip to content

Commit

Permalink
namei: allow set_root() to produce errors
Browse files Browse the repository at this point in the history
For LOOKUP_BENEATH and LOOKUP_IN_ROOT it is necessary to ensure that
set_root() is never called, and thus (for hardening purposes) it should
return an error rather than permit a breakout from the root. In
addition, move all of the repetitive set_root() calls to nd_jump_root().

Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
  • Loading branch information
Aleksa Sarai authored and Al Viro committed Dec 9, 2019
1 parent 1bc8207 commit 740a167
Showing 1 changed file with 24 additions and 11 deletions.
35 changes: 24 additions & 11 deletions fs/namei.c
Original file line number Diff line number Diff line change
Expand Up @@ -798,7 +798,7 @@ static int complete_walk(struct nameidata *nd)
return status;
}

static void set_root(struct nameidata *nd)
static int set_root(struct nameidata *nd)
{
struct fs_struct *fs = current->fs;

Expand All @@ -814,6 +814,7 @@ static void set_root(struct nameidata *nd)
get_fs_root(fs, &nd->root);
nd->flags |= LOOKUP_ROOT_GRABBED;
}
return 0;
}

static void path_put_conditional(struct path *path, struct nameidata *nd)
Expand All @@ -837,6 +838,11 @@ static inline void path_to_nameidata(const struct path *path,

static int nd_jump_root(struct nameidata *nd)
{
if (!nd->root.mnt) {
int error = set_root(nd);
if (error)
return error;
}
if (nd->flags & LOOKUP_RCU) {
struct dentry *d;
nd->path = nd->root;
Expand Down Expand Up @@ -1084,10 +1090,9 @@ const char *get_link(struct nameidata *nd)
return res;
}
if (*res == '/') {
if (!nd->root.mnt)
set_root(nd);
if (unlikely(nd_jump_root(nd)))
return ERR_PTR(-ECHILD);
error = nd_jump_root(nd);
if (unlikely(error))
return ERR_PTR(error);
while (unlikely(*++res == '/'))
;
}
Expand Down Expand Up @@ -1700,8 +1705,13 @@ static inline int may_lookup(struct nameidata *nd)
static inline int handle_dots(struct nameidata *nd, int type)
{
if (type == LAST_DOTDOT) {
if (!nd->root.mnt)
set_root(nd);
int error = 0;

if (!nd->root.mnt) {
error = set_root(nd);
if (error)
return error;
}
if (nd->flags & LOOKUP_RCU) {
return follow_dotdot_rcu(nd);
} else
Expand Down Expand Up @@ -2159,6 +2169,7 @@ static int link_path_walk(const char *name, struct nameidata *nd)
/* must be paired with terminate_walk() */
static const char *path_init(struct nameidata *nd, unsigned flags)
{
int error;
const char *s = nd->name->name;

if (!*s)
Expand Down Expand Up @@ -2191,11 +2202,13 @@ static const char *path_init(struct nameidata *nd, unsigned flags)
nd->path.dentry = NULL;

nd->m_seq = read_seqbegin(&mount_lock);

/* Figure out the starting path and root (if needed). */
if (*s == '/') {
set_root(nd);
if (likely(!nd_jump_root(nd)))
return s;
return ERR_PTR(-ECHILD);
error = nd_jump_root(nd);
if (unlikely(error))
return ERR_PTR(error);
return s;
} else if (nd->dfd == AT_FDCWD) {
if (flags & LOOKUP_RCU) {
struct fs_struct *fs = current->fs;
Expand Down

0 comments on commit 740a167

Please sign in to comment.