Skip to content

Commit 740a167

Browse files
cypharAl Viro
authored andcommitted
namei: allow set_root() to produce errors
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 <[email protected]> Signed-off-by: Al Viro <[email protected]>
1 parent 1bc8207 commit 740a167

File tree

1 file changed

+24
-11
lines changed

1 file changed

+24
-11
lines changed

fs/namei.c

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -798,7 +798,7 @@ static int complete_walk(struct nameidata *nd)
798798
return status;
799799
}
800800

801-
static void set_root(struct nameidata *nd)
801+
static int set_root(struct nameidata *nd)
802802
{
803803
struct fs_struct *fs = current->fs;
804804

@@ -814,6 +814,7 @@ static void set_root(struct nameidata *nd)
814814
get_fs_root(fs, &nd->root);
815815
nd->flags |= LOOKUP_ROOT_GRABBED;
816816
}
817+
return 0;
817818
}
818819

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

838839
static int nd_jump_root(struct nameidata *nd)
839840
{
841+
if (!nd->root.mnt) {
842+
int error = set_root(nd);
843+
if (error)
844+
return error;
845+
}
840846
if (nd->flags & LOOKUP_RCU) {
841847
struct dentry *d;
842848
nd->path = nd->root;
@@ -1084,10 +1090,9 @@ const char *get_link(struct nameidata *nd)
10841090
return res;
10851091
}
10861092
if (*res == '/') {
1087-
if (!nd->root.mnt)
1088-
set_root(nd);
1089-
if (unlikely(nd_jump_root(nd)))
1090-
return ERR_PTR(-ECHILD);
1093+
error = nd_jump_root(nd);
1094+
if (unlikely(error))
1095+
return ERR_PTR(error);
10911096
while (unlikely(*++res == '/'))
10921097
;
10931098
}
@@ -1700,8 +1705,13 @@ static inline int may_lookup(struct nameidata *nd)
17001705
static inline int handle_dots(struct nameidata *nd, int type)
17011706
{
17021707
if (type == LAST_DOTDOT) {
1703-
if (!nd->root.mnt)
1704-
set_root(nd);
1708+
int error = 0;
1709+
1710+
if (!nd->root.mnt) {
1711+
error = set_root(nd);
1712+
if (error)
1713+
return error;
1714+
}
17051715
if (nd->flags & LOOKUP_RCU) {
17061716
return follow_dotdot_rcu(nd);
17071717
} else
@@ -2159,6 +2169,7 @@ static int link_path_walk(const char *name, struct nameidata *nd)
21592169
/* must be paired with terminate_walk() */
21602170
static const char *path_init(struct nameidata *nd, unsigned flags)
21612171
{
2172+
int error;
21622173
const char *s = nd->name->name;
21632174

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

21932204
nd->m_seq = read_seqbegin(&mount_lock);
2205+
2206+
/* Figure out the starting path and root (if needed). */
21942207
if (*s == '/') {
2195-
set_root(nd);
2196-
if (likely(!nd_jump_root(nd)))
2197-
return s;
2198-
return ERR_PTR(-ECHILD);
2208+
error = nd_jump_root(nd);
2209+
if (unlikely(error))
2210+
return ERR_PTR(error);
2211+
return s;
21992212
} else if (nd->dfd == AT_FDCWD) {
22002213
if (flags & LOOKUP_RCU) {
22012214
struct fs_struct *fs = current->fs;

0 commit comments

Comments
 (0)