Skip to content

Commit b4c0800

Browse files
committed
Merge branch 'fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull misc vfs fixes from Al Viro: "Assorted fixes all over the place; some of that is -stable fodder, some regressions from the last window" * 'fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: ecryptfs_lookup_interpose(): lower_dentry->d_parent is not stable either ecryptfs_lookup_interpose(): lower_dentry->d_inode is not stable ecryptfs: fix unlink and rmdir in face of underlying fs modifications audit_get_nd(): don't unlock parent too early exportfs_decode_fh(): negative pinned may become positive without the parent locked cgroup: don't put ERR_PTR() into fc->root autofs: fix a leak in autofs_expire_indirect() aio: Fix io_pgetevents() struct __compat_aio_sigset layout fs/namespace.c: fix use-after-free of mount in mnt_warn_timestamp_expiry()
2 parents 96b95ef + 762c696 commit b4c0800

File tree

7 files changed

+91
-61
lines changed

7 files changed

+91
-61
lines changed

fs/aio.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2179,7 +2179,7 @@ SYSCALL_DEFINE5(io_getevents_time32, __u32, ctx_id,
21792179
#ifdef CONFIG_COMPAT
21802180

21812181
struct __compat_aio_sigset {
2182-
compat_sigset_t __user *sigmask;
2182+
compat_uptr_t sigmask;
21832183
compat_size_t sigsetsize;
21842184
};
21852185

@@ -2193,7 +2193,7 @@ COMPAT_SYSCALL_DEFINE6(io_pgetevents,
21932193
struct old_timespec32 __user *, timeout,
21942194
const struct __compat_aio_sigset __user *, usig)
21952195
{
2196-
struct __compat_aio_sigset ksig = { NULL, };
2196+
struct __compat_aio_sigset ksig = { 0, };
21972197
struct timespec64 t;
21982198
bool interrupted;
21992199
int ret;
@@ -2204,7 +2204,7 @@ COMPAT_SYSCALL_DEFINE6(io_pgetevents,
22042204
if (usig && copy_from_user(&ksig, usig, sizeof(ksig)))
22052205
return -EFAULT;
22062206

2207-
ret = set_compat_user_sigmask(ksig.sigmask, ksig.sigsetsize);
2207+
ret = set_compat_user_sigmask(compat_ptr(ksig.sigmask), ksig.sigsetsize);
22082208
if (ret)
22092209
return ret;
22102210

@@ -2228,7 +2228,7 @@ COMPAT_SYSCALL_DEFINE6(io_pgetevents_time64,
22282228
struct __kernel_timespec __user *, timeout,
22292229
const struct __compat_aio_sigset __user *, usig)
22302230
{
2231-
struct __compat_aio_sigset ksig = { NULL, };
2231+
struct __compat_aio_sigset ksig = { 0, };
22322232
struct timespec64 t;
22332233
bool interrupted;
22342234
int ret;
@@ -2239,7 +2239,7 @@ COMPAT_SYSCALL_DEFINE6(io_pgetevents_time64,
22392239
if (usig && copy_from_user(&ksig, usig, sizeof(ksig)))
22402240
return -EFAULT;
22412241

2242-
ret = set_compat_user_sigmask(ksig.sigmask, ksig.sigsetsize);
2242+
ret = set_compat_user_sigmask(compat_ptr(ksig.sigmask), ksig.sigsetsize);
22432243
if (ret)
22442244
return ret;
22452245

fs/autofs/expire.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -459,9 +459,10 @@ static struct dentry *autofs_expire_indirect(struct super_block *sb,
459459
*/
460460
how &= ~AUTOFS_EXP_LEAVES;
461461
found = should_expire(expired, mnt, timeout, how);
462-
if (!found || found != expired)
463-
/* Something has changed, continue */
462+
if (found != expired) { // something has changed, continue
463+
dput(found);
464464
goto next;
465+
}
465466

466467
if (expired != dentry)
467468
dput(dentry);

fs/ecryptfs/inode.c

Lines changed: 53 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -128,24 +128,32 @@ static int ecryptfs_do_unlink(struct inode *dir, struct dentry *dentry,
128128
struct inode *inode)
129129
{
130130
struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry);
131-
struct inode *lower_dir_inode = ecryptfs_inode_to_lower(dir);
132131
struct dentry *lower_dir_dentry;
132+
struct inode *lower_dir_inode;
133133
int rc;
134134

135-
dget(lower_dentry);
136-
lower_dir_dentry = lock_parent(lower_dentry);
137-
rc = vfs_unlink(lower_dir_inode, lower_dentry, NULL);
135+
lower_dir_dentry = ecryptfs_dentry_to_lower(dentry->d_parent);
136+
lower_dir_inode = d_inode(lower_dir_dentry);
137+
inode_lock_nested(lower_dir_inode, I_MUTEX_PARENT);
138+
dget(lower_dentry); // don't even try to make the lower negative
139+
if (lower_dentry->d_parent != lower_dir_dentry)
140+
rc = -EINVAL;
141+
else if (d_unhashed(lower_dentry))
142+
rc = -EINVAL;
143+
else
144+
rc = vfs_unlink(lower_dir_inode, lower_dentry, NULL);
138145
if (rc) {
139146
printk(KERN_ERR "Error in vfs_unlink; rc = [%d]\n", rc);
140147
goto out_unlock;
141148
}
142149
fsstack_copy_attr_times(dir, lower_dir_inode);
143150
set_nlink(inode, ecryptfs_inode_to_lower(inode)->i_nlink);
144151
inode->i_ctime = dir->i_ctime;
145-
d_drop(dentry);
146152
out_unlock:
147-
unlock_dir(lower_dir_dentry);
148153
dput(lower_dentry);
154+
inode_unlock(lower_dir_inode);
155+
if (!rc)
156+
d_drop(dentry);
149157
return rc;
150158
}
151159

@@ -311,9 +319,9 @@ static int ecryptfs_i_size_read(struct dentry *dentry, struct inode *inode)
311319
static struct dentry *ecryptfs_lookup_interpose(struct dentry *dentry,
312320
struct dentry *lower_dentry)
313321
{
314-
struct inode *inode, *lower_inode = d_inode(lower_dentry);
322+
struct path *path = ecryptfs_dentry_to_lower_path(dentry->d_parent);
323+
struct inode *inode, *lower_inode;
315324
struct ecryptfs_dentry_info *dentry_info;
316-
struct vfsmount *lower_mnt;
317325
int rc = 0;
318326

319327
dentry_info = kmem_cache_alloc(ecryptfs_dentry_info_cache, GFP_KERNEL);
@@ -322,16 +330,23 @@ static struct dentry *ecryptfs_lookup_interpose(struct dentry *dentry,
322330
return ERR_PTR(-ENOMEM);
323331
}
324332

325-
lower_mnt = mntget(ecryptfs_dentry_to_lower_mnt(dentry->d_parent));
326333
fsstack_copy_attr_atime(d_inode(dentry->d_parent),
327-
d_inode(lower_dentry->d_parent));
334+
d_inode(path->dentry));
328335
BUG_ON(!d_count(lower_dentry));
329336

330337
ecryptfs_set_dentry_private(dentry, dentry_info);
331-
dentry_info->lower_path.mnt = lower_mnt;
338+
dentry_info->lower_path.mnt = mntget(path->mnt);
332339
dentry_info->lower_path.dentry = lower_dentry;
333340

334-
if (d_really_is_negative(lower_dentry)) {
341+
/*
342+
* negative dentry can go positive under us here - its parent is not
343+
* locked. That's OK and that could happen just as we return from
344+
* ecryptfs_lookup() anyway. Just need to be careful and fetch
345+
* ->d_inode only once - it's not stable here.
346+
*/
347+
lower_inode = READ_ONCE(lower_dentry->d_inode);
348+
349+
if (!lower_inode) {
335350
/* We want to add because we couldn't find in lower */
336351
d_add(dentry, NULL);
337352
return NULL;
@@ -512,22 +527,30 @@ static int ecryptfs_rmdir(struct inode *dir, struct dentry *dentry)
512527
{
513528
struct dentry *lower_dentry;
514529
struct dentry *lower_dir_dentry;
530+
struct inode *lower_dir_inode;
515531
int rc;
516532

517533
lower_dentry = ecryptfs_dentry_to_lower(dentry);
518-
dget(dentry);
519-
lower_dir_dentry = lock_parent(lower_dentry);
520-
dget(lower_dentry);
521-
rc = vfs_rmdir(d_inode(lower_dir_dentry), lower_dentry);
522-
dput(lower_dentry);
523-
if (!rc && d_really_is_positive(dentry))
534+
lower_dir_dentry = ecryptfs_dentry_to_lower(dentry->d_parent);
535+
lower_dir_inode = d_inode(lower_dir_dentry);
536+
537+
inode_lock_nested(lower_dir_inode, I_MUTEX_PARENT);
538+
dget(lower_dentry); // don't even try to make the lower negative
539+
if (lower_dentry->d_parent != lower_dir_dentry)
540+
rc = -EINVAL;
541+
else if (d_unhashed(lower_dentry))
542+
rc = -EINVAL;
543+
else
544+
rc = vfs_rmdir(lower_dir_inode, lower_dentry);
545+
if (!rc) {
524546
clear_nlink(d_inode(dentry));
525-
fsstack_copy_attr_times(dir, d_inode(lower_dir_dentry));
526-
set_nlink(dir, d_inode(lower_dir_dentry)->i_nlink);
527-
unlock_dir(lower_dir_dentry);
547+
fsstack_copy_attr_times(dir, lower_dir_inode);
548+
set_nlink(dir, lower_dir_inode->i_nlink);
549+
}
550+
dput(lower_dentry);
551+
inode_unlock(lower_dir_inode);
528552
if (!rc)
529553
d_drop(dentry);
530-
dput(dentry);
531554
return rc;
532555
}
533556

@@ -565,20 +588,22 @@ ecryptfs_rename(struct inode *old_dir, struct dentry *old_dentry,
565588
struct dentry *lower_new_dentry;
566589
struct dentry *lower_old_dir_dentry;
567590
struct dentry *lower_new_dir_dentry;
568-
struct dentry *trap = NULL;
591+
struct dentry *trap;
569592
struct inode *target_inode;
570593

571594
if (flags)
572595
return -EINVAL;
573596

597+
lower_old_dir_dentry = ecryptfs_dentry_to_lower(old_dentry->d_parent);
598+
lower_new_dir_dentry = ecryptfs_dentry_to_lower(new_dentry->d_parent);
599+
574600
lower_old_dentry = ecryptfs_dentry_to_lower(old_dentry);
575601
lower_new_dentry = ecryptfs_dentry_to_lower(new_dentry);
576-
dget(lower_old_dentry);
577-
dget(lower_new_dentry);
578-
lower_old_dir_dentry = dget_parent(lower_old_dentry);
579-
lower_new_dir_dentry = dget_parent(lower_new_dentry);
602+
580603
target_inode = d_inode(new_dentry);
604+
581605
trap = lock_rename(lower_old_dir_dentry, lower_new_dir_dentry);
606+
dget(lower_new_dentry);
582607
rc = -EINVAL;
583608
if (lower_old_dentry->d_parent != lower_old_dir_dentry)
584609
goto out_lock;
@@ -606,11 +631,8 @@ ecryptfs_rename(struct inode *old_dir, struct dentry *old_dentry,
606631
if (new_dir != old_dir)
607632
fsstack_copy_attr_all(old_dir, d_inode(lower_old_dir_dentry));
608633
out_lock:
609-
unlock_rename(lower_old_dir_dentry, lower_new_dir_dentry);
610-
dput(lower_new_dir_dentry);
611-
dput(lower_old_dir_dentry);
612634
dput(lower_new_dentry);
613-
dput(lower_old_dentry);
635+
unlock_rename(lower_old_dir_dentry, lower_new_dir_dentry);
614636
return rc;
615637
}
616638

fs/exportfs/expfs.c

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -519,26 +519,33 @@ struct dentry *exportfs_decode_fh(struct vfsmount *mnt, struct fid *fid,
519519
* inode is actually connected to the parent.
520520
*/
521521
err = exportfs_get_name(mnt, target_dir, nbuf, result);
522-
if (!err) {
523-
inode_lock(target_dir->d_inode);
524-
nresult = lookup_one_len(nbuf, target_dir,
525-
strlen(nbuf));
526-
inode_unlock(target_dir->d_inode);
527-
if (!IS_ERR(nresult)) {
528-
if (nresult->d_inode) {
529-
dput(result);
530-
result = nresult;
531-
} else
532-
dput(nresult);
533-
}
522+
if (err) {
523+
dput(target_dir);
524+
goto err_result;
534525
}
535526

527+
inode_lock(target_dir->d_inode);
528+
nresult = lookup_one_len(nbuf, target_dir, strlen(nbuf));
529+
if (!IS_ERR(nresult)) {
530+
if (unlikely(nresult->d_inode != result->d_inode)) {
531+
dput(nresult);
532+
nresult = ERR_PTR(-ESTALE);
533+
}
534+
}
535+
inode_unlock(target_dir->d_inode);
536536
/*
537537
* At this point we are done with the parent, but it's pinned
538538
* by the child dentry anyway.
539539
*/
540540
dput(target_dir);
541541

542+
if (IS_ERR(nresult)) {
543+
err = PTR_ERR(nresult);
544+
goto err_result;
545+
}
546+
dput(result);
547+
result = nresult;
548+
542549
/*
543550
* And finally make sure the dentry is actually acceptable
544551
* to NFSD.

fs/namespace.c

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2478,8 +2478,10 @@ static void mnt_warn_timestamp_expiry(struct path *mountpoint, struct vfsmount *
24782478

24792479
time64_to_tm(sb->s_time_max, 0, &tm);
24802480

2481-
pr_warn("Mounted %s file system at %s supports timestamps until %04ld (0x%llx)\n",
2482-
sb->s_type->name, mntpath,
2481+
pr_warn("%s filesystem being %s at %s supports timestamps until %04ld (0x%llx)\n",
2482+
sb->s_type->name,
2483+
is_mounted(mnt) ? "remounted" : "mounted",
2484+
mntpath,
24832485
tm.tm_year+1900, (unsigned long long)sb->s_time_max);
24842486

24852487
free_page((unsigned long)buf);
@@ -2764,14 +2766,11 @@ static int do_new_mount_fc(struct fs_context *fc, struct path *mountpoint,
27642766
if (IS_ERR(mnt))
27652767
return PTR_ERR(mnt);
27662768

2767-
error = do_add_mount(real_mount(mnt), mountpoint, mnt_flags);
2768-
if (error < 0) {
2769-
mntput(mnt);
2770-
return error;
2771-
}
2772-
27732769
mnt_warn_timestamp_expiry(mountpoint, mnt);
27742770

2771+
error = do_add_mount(real_mount(mnt), mountpoint, mnt_flags);
2772+
if (error < 0)
2773+
mntput(mnt);
27752774
return error;
27762775
}
27772776

kernel/audit_watch.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -351,12 +351,12 @@ static int audit_get_nd(struct audit_watch *watch, struct path *parent)
351351
struct dentry *d = kern_path_locked(watch->path, parent);
352352
if (IS_ERR(d))
353353
return PTR_ERR(d);
354-
inode_unlock(d_backing_inode(parent->dentry));
355354
if (d_is_positive(d)) {
356355
/* update watch filter fields */
357356
watch->dev = d->d_sb->s_dev;
358357
watch->ino = d_backing_inode(d)->i_ino;
359358
}
359+
inode_unlock(d_backing_inode(parent->dentry));
360360
dput(d);
361361
return 0;
362362
}

kernel/cgroup/cgroup.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2119,11 +2119,12 @@ int cgroup_do_get_tree(struct fs_context *fc)
21192119

21202120
nsdentry = kernfs_node_dentry(cgrp->kn, sb);
21212121
dput(fc->root);
2122-
fc->root = nsdentry;
21232122
if (IS_ERR(nsdentry)) {
2124-
ret = PTR_ERR(nsdentry);
21252123
deactivate_locked_super(sb);
2124+
ret = PTR_ERR(nsdentry);
2125+
nsdentry = NULL;
21262126
}
2127+
fc->root = nsdentry;
21272128
}
21282129

21292130
if (!ctx->kfc.new_sb_created)

0 commit comments

Comments
 (0)