Skip to content

Commit 0f70595

Browse files
author
Al Viro
committed
link_path_walk(): sample parent's i_uid and i_mode for the last component
Signed-off-by: Al Viro <[email protected]>
1 parent 60ef60c commit 0f70595

File tree

1 file changed

+7
-10
lines changed

1 file changed

+7
-10
lines changed

fs/namei.c

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -505,6 +505,8 @@ struct nameidata {
505505
struct nameidata *saved;
506506
unsigned root_seq;
507507
int dfd;
508+
kuid_t dir_uid;
509+
umode_t dir_mode;
508510
} __randomize_layout;
509511

510512
static void set_nameidata(struct nameidata *p, int dfd, struct filename *name)
@@ -938,9 +940,6 @@ int sysctl_protected_regular __read_mostly;
938940
*/
939941
static inline int may_follow_link(struct nameidata *nd, const struct inode *inode)
940942
{
941-
const struct inode *parent;
942-
kuid_t puid;
943-
944943
if (!sysctl_protected_symlinks)
945944
return 0;
946945

@@ -949,13 +948,11 @@ static inline int may_follow_link(struct nameidata *nd, const struct inode *inod
949948
return 0;
950949

951950
/* Allowed if parent directory not sticky and world-writable. */
952-
parent = nd->inode;
953-
if ((parent->i_mode & (S_ISVTX|S_IWOTH)) != (S_ISVTX|S_IWOTH))
951+
if ((nd->dir_mode & (S_ISVTX|S_IWOTH)) != (S_ISVTX|S_IWOTH))
954952
return 0;
955953

956954
/* Allowed if parent directory and link owner match. */
957-
puid = parent->i_uid;
958-
if (uid_valid(puid) && uid_eq(puid, inode->i_uid))
955+
if (uid_valid(nd->dir_uid) && uid_eq(nd->dir_uid, inode->i_uid))
959956
return 0;
960957

961958
if (nd->flags & LOOKUP_RCU)
@@ -2159,6 +2156,8 @@ static int link_path_walk(const char *name, struct nameidata *nd)
21592156
OK:
21602157
/* pathname or trailing symlink, done */
21612158
if (!depth) {
2159+
nd->dir_uid = nd->inode->i_uid;
2160+
nd->dir_mode = nd->inode->i_mode;
21622161
nd->flags &= ~LOOKUP_PARENT;
21632162
return 0;
21642163
}
@@ -3224,8 +3223,6 @@ static const char *open_last_lookups(struct nameidata *nd,
32243223
static const char *do_last(struct nameidata *nd,
32253224
struct file *file, const struct open_flags *op)
32263225
{
3227-
kuid_t dir_uid = nd->inode->i_uid;
3228-
umode_t dir_mode = nd->inode->i_mode;
32293226
int open_flag = op->open_flag;
32303227
bool do_truncate;
32313228
int acc_mode;
@@ -3241,7 +3238,7 @@ static const char *do_last(struct nameidata *nd,
32413238
if (open_flag & O_CREAT) {
32423239
if (d_is_dir(nd->path.dentry))
32433240
return ERR_PTR(-EISDIR);
3244-
error = may_create_in_sticky(dir_mode, dir_uid,
3241+
error = may_create_in_sticky(nd->dir_mode, nd->dir_uid,
32453242
d_backing_inode(nd->path.dentry));
32463243
if (unlikely(error))
32473244
return ERR_PTR(error);

0 commit comments

Comments
 (0)