[PATCH] ecryptfs: reject destroy mount crypt stat if sb's active refer is 1

Edward Adam Davis posted 1 patch 6 days, 23 hours ago
fs/ecryptfs/main.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
[PATCH] ecryptfs: reject destroy mount crypt stat if sb's active refer is 1
Posted by Edward Adam Davis 6 days, 23 hours ago
When sget_fc() is executed within ecryptfs_get_tree(), the active reference
count of the superblock is not incremented (e.g., via grab_super()).

A fault injection [0] causes super_setup_bdi() to fail and return -ENOMEM,
triggering a jump to the out1 label in ecryptfs_get_tree(). At this point,
the superblock's active reference count remains at its initial value of 1,
it causing deactivate_locked_super() to free the superblock and the sbi,
potentially hitting uaf [1].

Destroy mount crypt stat should only be performed when the superblock's
active reference count is greater than 1.

[0]
FAULT_INJECTION: forcing a failure.
name failslab, interval 1, probability 0, space 0, times 0
Call Trace:
 security_sb_alloc+0x25/0x240
 sget_fc+0x3ca/0x1f20
 ecryptfs_get_tree+0x615/0x15b0
 vfs_get_tree+0x92/0x320
 path_mount+0x7d0/0x24c0

[1]
BUG: KASAN: slab-use-after-free in ecryptfs_destroy_mount_crypt_stat+0x28f/0x360 fs/ecryptfs/crypto.c:137
Read of size 4 at addr ffff88802b378610 by task syz.0.20/5927
Call Trace:
 ecryptfs_destroy_mount_crypt_stat+0x28f/0x360 fs/ecryptfs/crypto.c:137
 ecryptfs_get_tree+0x10b6/0x15b0 fs/ecryptfs/main.c:566
 vfs_get_tree+0x92/0x320 fs/super.c:1933
 fc_mount fs/namespace.c:1198 [inline]
 do_new_mount_fc fs/namespace.c:3772 [inline]
 do_new_mount fs/namespace.c:3848 [inline]

Allocated by task 5927:
 ecryptfs_init_fs_context+0x6b/0x200 fs/ecryptfs/main.c:617
 alloc_fs_context+0x60c/0xf40 fs/fs_context.c:295
 do_new_mount fs/namespace.c:3828 [inline]

Freed by task 5927:
 ecryptfs_kill_block_super+0x81/0xa0 fs/ecryptfs/main.c:586
 deactivate_locked_super+0xbd/0x140 fs/super.c:589
 ecryptfs_get_tree+0x10e9/0x15b0 fs/ecryptfs/main.c:563
 vfs_get_tree+0x92/0x320 fs/super.c:1933
 fc_mount fs/namespace.c:1198 [inline]
 do_new_mount_fc fs/namespace.c:3772 [inline]
 do_new_mount fs/namespace.c:3848 [inline]
 
Fixes: 2ccde7c631f9 ("Clean ecryptfs ->get_sb() up")
Reported-by: syzbot+baa24e4b7e349e388442@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=baa24e4b7e349e388442
Tested-by: syzbot+baa24e4b7e349e388442@syzkaller.appspotmail.com
Signed-off-by: Edward Adam Davis <eadavis@sina.com>
---
 fs/ecryptfs/main.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c
index 5f37cddb956f..6b82c077c0d6 100644
--- a/fs/ecryptfs/main.c
+++ b/fs/ecryptfs/main.c
@@ -441,7 +441,7 @@ static int ecryptfs_get_tree(struct fs_context *fc)
 	const char *err = "Getting sb failed";
 	struct inode *inode;
 	struct path path;
-	int rc;
+	int rc, active;
 
 	if (!fc->source) {
 		rc = -EINVAL;
@@ -468,6 +468,7 @@ static int ecryptfs_get_tree(struct fs_context *fc)
 		goto out;
 	}
 
+	active = atomic_read(&s->s_active);
 	rc = super_setup_bdi(s);
 	if (rc)
 		goto out1;
@@ -562,7 +563,7 @@ static int ecryptfs_get_tree(struct fs_context *fc)
 out1:
 	deactivate_locked_super(s);
 out:
-	if (sbi)
+	if (sbi && active > 1)
 		ecryptfs_destroy_mount_crypt_stat(&sbi->mount_crypt_stat);
 
 	printk(KERN_ERR "%s; rc = [%d]\n", err, rc);
-- 
2.43.0