Skip to content

Commit f16ab99

Browse files
committed
Merge tag 'pull-bcachefs-fix' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull bcachefs locking fix from Al Viro: "Fix broken locking in bch2_ioctl_subvolume_destroy()" * tag 'pull-bcachefs-fix' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: bch2_ioctl_subvolume_destroy(): fix locking new helper: user_path_locked_at()
2 parents 1acc24b + bbe6a7c commit f16ab99

File tree

3 files changed

+31
-17
lines changed

3 files changed

+31
-17
lines changed

fs/bcachefs/fs-ioctl.c

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -443,33 +443,36 @@ static long bch2_ioctl_subvolume_create(struct bch_fs *c, struct file *filp,
443443
static long bch2_ioctl_subvolume_destroy(struct bch_fs *c, struct file *filp,
444444
struct bch_ioctl_subvolume arg)
445445
{
446+
const char __user *name = (void __user *)(unsigned long)arg.dst_ptr;
446447
struct path path;
447448
struct inode *dir;
449+
struct dentry *victim;
448450
int ret = 0;
449451

450452
if (arg.flags)
451453
return -EINVAL;
452454

453-
ret = user_path_at(arg.dirfd,
454-
(const char __user *)(unsigned long)arg.dst_ptr,
455-
LOOKUP_FOLLOW, &path);
456-
if (ret)
457-
return ret;
455+
victim = user_path_locked_at(arg.dirfd, name, &path);
456+
if (IS_ERR(victim))
457+
return PTR_ERR(victim);
458458

459-
if (path.dentry->d_sb->s_fs_info != c) {
459+
if (victim->d_sb->s_fs_info != c) {
460460
ret = -EXDEV;
461461
goto err;
462462
}
463-
464-
dir = path.dentry->d_parent->d_inode;
465-
466-
ret = __bch2_unlink(dir, path.dentry, true);
467-
if (ret)
463+
if (!d_is_positive(victim)) {
464+
ret = -ENOENT;
468465
goto err;
469-
470-
fsnotify_rmdir(dir, path.dentry);
471-
d_delete(path.dentry);
466+
}
467+
dir = d_inode(path.dentry);
468+
ret = __bch2_unlink(dir, victim, true);
469+
if (!ret) {
470+
fsnotify_rmdir(dir, victim);
471+
d_delete(victim);
472+
}
473+
inode_unlock(dir);
472474
err:
475+
dput(victim);
473476
path_put(&path);
474477
return ret;
475478
}

fs/namei.c

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2572,13 +2572,13 @@ static int filename_parentat(int dfd, struct filename *name,
25722572
}
25732573

25742574
/* does lookup, returns the object with parent locked */
2575-
static struct dentry *__kern_path_locked(struct filename *name, struct path *path)
2575+
static struct dentry *__kern_path_locked(int dfd, struct filename *name, struct path *path)
25762576
{
25772577
struct dentry *d;
25782578
struct qstr last;
25792579
int type, error;
25802580

2581-
error = filename_parentat(AT_FDCWD, name, 0, path, &last, &type);
2581+
error = filename_parentat(dfd, name, 0, path, &last, &type);
25822582
if (error)
25832583
return ERR_PTR(error);
25842584
if (unlikely(type != LAST_NORM)) {
@@ -2597,12 +2597,22 @@ static struct dentry *__kern_path_locked(struct filename *name, struct path *pat
25972597
struct dentry *kern_path_locked(const char *name, struct path *path)
25982598
{
25992599
struct filename *filename = getname_kernel(name);
2600-
struct dentry *res = __kern_path_locked(filename, path);
2600+
struct dentry *res = __kern_path_locked(AT_FDCWD, filename, path);
26012601

26022602
putname(filename);
26032603
return res;
26042604
}
26052605

2606+
struct dentry *user_path_locked_at(int dfd, const char __user *name, struct path *path)
2607+
{
2608+
struct filename *filename = getname(name);
2609+
struct dentry *res = __kern_path_locked(dfd, filename, path);
2610+
2611+
putname(filename);
2612+
return res;
2613+
}
2614+
EXPORT_SYMBOL(user_path_locked_at);
2615+
26062616
int kern_path(const char *name, unsigned int flags, struct path *path)
26072617
{
26082618
struct filename *filename = getname_kernel(name);

include/linux/namei.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ extern struct dentry *kern_path_create(int, const char *, struct path *, unsigne
6666
extern struct dentry *user_path_create(int, const char __user *, struct path *, unsigned int);
6767
extern void done_path_create(struct path *, struct dentry *);
6868
extern struct dentry *kern_path_locked(const char *, struct path *);
69+
extern struct dentry *user_path_locked_at(int , const char __user *, struct path *);
6970
int vfs_path_parent_lookup(struct filename *filename, unsigned int flags,
7071
struct path *parent, struct qstr *last, int *type,
7172
const struct path *root);

0 commit comments

Comments
 (0)