提交 53a5271b 编写于 作者: A Aleksa Sarai 提交者: Joseph Qi

namei: allow set_root() to produce errors

to #26323588

commit 740a16782750a5b6c7d1609a9c09641ce6753ea6 upstream.

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: NAleksa Sarai <cyphar@cyphar.com>
Signed-off-by: NAl Viro <viro@zeniv.linux.org.uk>
Signed-off-by: NJoseph Qi <joseph.qi@linux.alibaba.com>
Acked-by: NXiaoguang Wang <xiaoguang.wang@linux.alibaba.com>
上级 b63f56c4
...@@ -807,7 +807,7 @@ static int complete_walk(struct nameidata *nd) ...@@ -807,7 +807,7 @@ static int complete_walk(struct nameidata *nd)
return status; return status;
} }
static void set_root(struct nameidata *nd) static int set_root(struct nameidata *nd)
{ {
struct fs_struct *fs = current->fs; struct fs_struct *fs = current->fs;
...@@ -822,6 +822,7 @@ static void set_root(struct nameidata *nd) ...@@ -822,6 +822,7 @@ static void set_root(struct nameidata *nd)
} else { } else {
get_fs_root(fs, &nd->root); get_fs_root(fs, &nd->root);
} }
return 0;
} }
static void path_put_conditional(struct path *path, struct nameidata *nd) static void path_put_conditional(struct path *path, struct nameidata *nd)
...@@ -845,6 +846,11 @@ static inline void path_to_nameidata(const struct path *path, ...@@ -845,6 +846,11 @@ static inline void path_to_nameidata(const struct path *path,
static int nd_jump_root(struct nameidata *nd) 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) { if (nd->flags & LOOKUP_RCU) {
struct dentry *d; struct dentry *d;
nd->path = nd->root; nd->path = nd->root;
...@@ -1089,10 +1095,9 @@ const char *get_link(struct nameidata *nd) ...@@ -1089,10 +1095,9 @@ const char *get_link(struct nameidata *nd)
return res; return res;
} }
if (*res == '/') { if (*res == '/') {
if (!nd->root.mnt) error = nd_jump_root(nd);
set_root(nd); if (unlikely(error))
if (unlikely(nd_jump_root(nd))) return ERR_PTR(error);
return ERR_PTR(-ECHILD);
while (unlikely(*++res == '/')) while (unlikely(*++res == '/'))
; ;
} }
...@@ -1706,8 +1711,13 @@ static inline int may_lookup(struct nameidata *nd) ...@@ -1706,8 +1711,13 @@ static inline int may_lookup(struct nameidata *nd)
static inline int handle_dots(struct nameidata *nd, int type) static inline int handle_dots(struct nameidata *nd, int type)
{ {
if (type == LAST_DOTDOT) { if (type == LAST_DOTDOT) {
if (!nd->root.mnt) int error = 0;
set_root(nd);
if (!nd->root.mnt) {
error = set_root(nd);
if (error)
return error;
}
if (nd->flags & LOOKUP_RCU) { if (nd->flags & LOOKUP_RCU) {
return follow_dotdot_rcu(nd); return follow_dotdot_rcu(nd);
} else } else
...@@ -2167,6 +2177,7 @@ static int link_path_walk(const char *name, struct nameidata *nd) ...@@ -2167,6 +2177,7 @@ static int link_path_walk(const char *name, struct nameidata *nd)
/* must be paired with terminate_walk() */ /* must be paired with terminate_walk() */
static const char *path_init(struct nameidata *nd, unsigned flags) static const char *path_init(struct nameidata *nd, unsigned flags)
{ {
int error;
const char *s = nd->name->name; const char *s = nd->name->name;
if (!*s) if (!*s)
...@@ -2199,11 +2210,13 @@ static const char *path_init(struct nameidata *nd, unsigned flags) ...@@ -2199,11 +2210,13 @@ static const char *path_init(struct nameidata *nd, unsigned flags)
nd->path.dentry = NULL; nd->path.dentry = NULL;
nd->m_seq = read_seqbegin(&mount_lock); nd->m_seq = read_seqbegin(&mount_lock);
/* Figure out the starting path and root (if needed). */
if (*s == '/') { if (*s == '/') {
set_root(nd); error = nd_jump_root(nd);
if (likely(!nd_jump_root(nd))) if (unlikely(error))
return ERR_PTR(error);
return s; return s;
return ERR_PTR(-ECHILD);
} else if (nd->dfd == AT_FDCWD) { } else if (nd->dfd == AT_FDCWD) {
if (flags & LOOKUP_RCU) { if (flags & LOOKUP_RCU) {
struct fs_struct *fs = current->fs; struct fs_struct *fs = current->fs;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册