summaryrefslogtreecommitdiff
path: root/fs
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2020-03-05 11:34:48 -0500
committerAl Viro <viro@zeniv.linux.org.uk>2020-04-02 01:09:27 -0400
commit0f705953012a753068b20016f55dc12d1f7e17e5 (patch)
treea7a0082ab31848427122ae949f8fafab63c6666c /fs
parent60ef60c7d7291d7cdc43661363cd05a5102e69f6 (diff)
link_path_walk(): sample parent's i_uid and i_mode for the last component
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs')
-rw-r--r--fs/namei.c17
1 files changed, 7 insertions, 10 deletions
diff --git a/fs/namei.c b/fs/namei.c
index 7a95a3fcbf68..e737d884592d 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -505,6 +505,8 @@ struct nameidata {
struct nameidata *saved;
unsigned root_seq;
int dfd;
+ kuid_t dir_uid;
+ umode_t dir_mode;
} __randomize_layout;
static void set_nameidata(struct nameidata *p, int dfd, struct filename *name)
@@ -938,9 +940,6 @@ int sysctl_protected_regular __read_mostly;
*/
static inline int may_follow_link(struct nameidata *nd, const struct inode *inode)
{
- const struct inode *parent;
- kuid_t puid;
-
if (!sysctl_protected_symlinks)
return 0;
@@ -949,13 +948,11 @@ static inline int may_follow_link(struct nameidata *nd, const struct inode *inod
return 0;
/* Allowed if parent directory not sticky and world-writable. */
- parent = nd->inode;
- if ((parent->i_mode & (S_ISVTX|S_IWOTH)) != (S_ISVTX|S_IWOTH))
+ if ((nd->dir_mode & (S_ISVTX|S_IWOTH)) != (S_ISVTX|S_IWOTH))
return 0;
/* Allowed if parent directory and link owner match. */
- puid = parent->i_uid;
- if (uid_valid(puid) && uid_eq(puid, inode->i_uid))
+ if (uid_valid(nd->dir_uid) && uid_eq(nd->dir_uid, inode->i_uid))
return 0;
if (nd->flags & LOOKUP_RCU)
@@ -2159,6 +2156,8 @@ static int link_path_walk(const char *name, struct nameidata *nd)
OK:
/* pathname or trailing symlink, done */
if (!depth) {
+ nd->dir_uid = nd->inode->i_uid;
+ nd->dir_mode = nd->inode->i_mode;
nd->flags &= ~LOOKUP_PARENT;
return 0;
}
@@ -3224,8 +3223,6 @@ finish_lookup:
static const char *do_last(struct nameidata *nd,
struct file *file, const struct open_flags *op)
{
- kuid_t dir_uid = nd->inode->i_uid;
- umode_t dir_mode = nd->inode->i_mode;
int open_flag = op->open_flag;
bool do_truncate;
int acc_mode;
@@ -3241,7 +3238,7 @@ static const char *do_last(struct nameidata *nd,
if (open_flag & O_CREAT) {
if (d_is_dir(nd->path.dentry))
return ERR_PTR(-EISDIR);
- error = may_create_in_sticky(dir_mode, dir_uid,
+ error = may_create_in_sticky(nd->dir_mode, nd->dir_uid,
d_backing_inode(nd->path.dentry));
if (unlikely(error))
return ERR_PTR(error);