Skip to content

Commit 3e79d97

Browse files
committed
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull vfs fixes from Al Viro: "These four commits are obvious fixes (a couple of fdget_pos()-related ones from Eric Biggers, prepend_name() fix, missing checks for false negatives from __lookup_mnt() in fs/namei.c)" For now I'm pulling just the four obvious fixes, there's another four pending in Al's 'for-linus' branch wrt the mnt_hash list that were more involved. * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: rcuwalk: recheck mount_lock after mountpoint crossing attempts make prepend_name() work correctly when called with negative *buflen vfs: Don't let __fdget_pos() get FMODE_PATH files vfs: atomic f_pos access in llseek()
2 parents b098d67 + b37199e commit 3e79d97

File tree

4 files changed

+21
-35
lines changed

4 files changed

+21
-35
lines changed

fs/dcache.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2833,9 +2833,9 @@ static int prepend_name(char **buffer, int *buflen, struct qstr *name)
28332833
u32 dlen = ACCESS_ONCE(name->len);
28342834
char *p;
28352835

2836-
if (*buflen < dlen + 1)
2837-
return -ENAMETOOLONG;
28382836
*buflen -= dlen + 1;
2837+
if (*buflen < 0)
2838+
return -ENAMETOOLONG;
28392839
p = *buffer -= dlen + 1;
28402840
*p++ = '/';
28412841
while (dlen--) {

fs/file.c

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -713,27 +713,16 @@ unsigned long __fdget_raw(unsigned int fd)
713713

714714
unsigned long __fdget_pos(unsigned int fd)
715715
{
716-
struct files_struct *files = current->files;
717-
struct file *file;
718-
unsigned long v;
719-
720-
if (atomic_read(&files->count) == 1) {
721-
file = __fcheck_files(files, fd);
722-
v = 0;
723-
} else {
724-
file = __fget(fd, 0);
725-
v = FDPUT_FPUT;
726-
}
727-
if (!file)
728-
return 0;
716+
unsigned long v = __fdget(fd);
717+
struct file *file = (struct file *)(v & ~3);
729718

730-
if (file->f_mode & FMODE_ATOMIC_POS) {
719+
if (file && (file->f_mode & FMODE_ATOMIC_POS)) {
731720
if (file_count(file) > 1) {
732721
v |= FDPUT_POS_UNLOCK;
733722
mutex_lock(&file->f_pos_lock);
734723
}
735724
}
736-
return v | (unsigned long)file;
725+
return v;
737726
}
738727

739728
/*

fs/namei.c

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1109,7 +1109,7 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path,
11091109
return false;
11101110

11111111
if (!d_mountpoint(path->dentry))
1112-
break;
1112+
return true;
11131113

11141114
mounted = __lookup_mnt(path->mnt, path->dentry);
11151115
if (!mounted)
@@ -1125,20 +1125,7 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path,
11251125
*/
11261126
*inode = path->dentry->d_inode;
11271127
}
1128-
return true;
1129-
}
1130-
1131-
static void follow_mount_rcu(struct nameidata *nd)
1132-
{
1133-
while (d_mountpoint(nd->path.dentry)) {
1134-
struct mount *mounted;
1135-
mounted = __lookup_mnt(nd->path.mnt, nd->path.dentry);
1136-
if (!mounted)
1137-
break;
1138-
nd->path.mnt = &mounted->mnt;
1139-
nd->path.dentry = mounted->mnt.mnt_root;
1140-
nd->seq = read_seqcount_begin(&nd->path.dentry->d_seq);
1141-
}
1128+
return read_seqretry(&mount_lock, nd->m_seq);
11421129
}
11431130

11441131
static int follow_dotdot_rcu(struct nameidata *nd)
@@ -1166,7 +1153,17 @@ static int follow_dotdot_rcu(struct nameidata *nd)
11661153
break;
11671154
nd->seq = read_seqcount_begin(&nd->path.dentry->d_seq);
11681155
}
1169-
follow_mount_rcu(nd);
1156+
while (d_mountpoint(nd->path.dentry)) {
1157+
struct mount *mounted;
1158+
mounted = __lookup_mnt(nd->path.mnt, nd->path.dentry);
1159+
if (!mounted)
1160+
break;
1161+
nd->path.mnt = &mounted->mnt;
1162+
nd->path.dentry = mounted->mnt.mnt_root;
1163+
nd->seq = read_seqcount_begin(&nd->path.dentry->d_seq);
1164+
if (!read_seqretry(&mount_lock, nd->m_seq))
1165+
goto failed;
1166+
}
11701167
nd->inode = nd->path.dentry->d_inode;
11711168
return 0;
11721169

fs/read_write.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,7 @@ SYSCALL_DEFINE5(llseek, unsigned int, fd, unsigned long, offset_high,
307307
unsigned int, whence)
308308
{
309309
int retval;
310-
struct fd f = fdget(fd);
310+
struct fd f = fdget_pos(fd);
311311
loff_t offset;
312312

313313
if (!f.file)
@@ -327,7 +327,7 @@ SYSCALL_DEFINE5(llseek, unsigned int, fd, unsigned long, offset_high,
327327
retval = 0;
328328
}
329329
out_putf:
330-
fdput(f);
330+
fdput_pos(f);
331331
return retval;
332332
}
333333
#endif

0 commit comments

Comments
 (0)