Received: by 2002:a25:ad19:0:0:0:0:0 with SMTP id y25csp9567580ybi; Wed, 24 Jul 2019 06:22:31 -0700 (PDT) X-Google-Smtp-Source: APXvYqyyxssvWY2jcTkm1arievk9GCGQGkkECOm96bmvrR40l5mlsOvKxr4XK6Ad7ALqNAW0Ofw5 X-Received: by 2002:a62:764d:: with SMTP id r74mr11825730pfc.110.1563974551267; Wed, 24 Jul 2019 06:22:31 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1563974551; cv=none; d=google.com; s=arc-20160816; b=ciHAOxIsnDmbwO5ftG/jd0CmfZDw2ExDNcpN42FOnnfE3/hN32g9r1zn2duDTKZH80 huDMo72cPfZBX2pwck6FadVeQA6usI6IuDwGA7IVNBbtTI1WwU3OImhZNvDzPU00e0hZ lI7NSn5BU1ONG7VbFEKhgdNHSvY9OXDr/RtFPsabDPPyTSkAlOtSYZRovmBsloO1NQE6 fRqE36OB7tpMPmh6YlsfvB3Z0aLdeiTW4bVJk9aVnkpyJPgJIaMGSAXMIEbfjoNh6c2+ gVkqa4HFwg9RhkX2kXg++L6vETRX1WBnEaJwenooljqZGgVG4ATR9teBbdAdc8j+DTo7 VbAQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:mime-version:message-id:date:subject:cc :to:from; bh=Cy983kp82UdIzsoroRG6ixuAKCK7TjFIBimc+HOC8F0=; b=QgYJD9SbBzTYqjpIJfQYHvIAR+zXO3CAKkyP3+kvoX2FPqCUoGc3IHekrrLXV9aGsh VfzDnxXgUSQ6Ijzn6RtBO+4OpchRNCpNqtgS+NZD9zMXlwKiDk/6e7KeVrNm1dlDdZWh NC4HtXtdjoHRc/Sp4J1ojvvlxj0Enh1YVMPLyGVaT/Q1UOyDoihRuxhXL2IMxuYOJm0s F7SEjKVDbIgs5WMf6Te/7iXbvVQwJdIaSdjFdTUS4p0YZLJrNYJRzrpE0zGWu2oBW9yt LjKHQSXNhDQTxJWHkMa1GhuQ4S0q1L/UMu6JVby3pmCPPniulYERySfTJjvMAmu46Qcw yOUA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-ext4-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-ext4-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id 83si16506362pgc.207.2019.07.24.06.21.54; Wed, 24 Jul 2019 06:22:31 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-ext4-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-ext4-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-ext4-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727686AbfGXMFX (ORCPT + 99 others); Wed, 24 Jul 2019 08:05:23 -0400 Received: from szxga07-in.huawei.com ([45.249.212.35]:36042 "EHLO huawei.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1727412AbfGXMFX (ORCPT ); Wed, 24 Jul 2019 08:05:23 -0400 Received: from DGGEMS404-HUB.china.huawei.com (unknown [172.30.72.59]) by Forcepoint Email with ESMTP id D1AF773AC3B3BFAE40A0; Wed, 24 Jul 2019 20:05:21 +0800 (CST) Received: from huawei.com (10.90.53.225) by DGGEMS404-HUB.china.huawei.com (10.3.19.204) with Microsoft SMTP Server id 14.3.439.0; Wed, 24 Jul 2019 20:05:51 +0800 From: "zhangyi (F)" To: CC: , , Subject: [PATCH] ext4: fix potential use after free in system zone via remount with noblock_validity Date: Wed, 24 Jul 2019 20:11:08 +0800 Message-ID: <1563970268-33688-1-git-send-email-yi.zhang@huawei.com> X-Mailer: git-send-email 2.7.4 MIME-Version: 1.0 Content-Type: text/plain X-Originating-IP: [10.90.53.225] X-CFilter-Loop: Reflected Sender: linux-ext4-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-ext4@vger.kernel.org Remount process will release system zone which was allocated before if "noblock_validity" is specified. If we mount an ext4 file system to two mountpoints whit default mount options, and then remount one of them with "noblock_validity", it may trigger a use after free problem when someone accessing the other one. # mount /dev/sda foo # mount /dev/sda bar User access mountpoint "foo" | Remount mountpoint "bar" | ext4_map_blocks() | ext4_remount() check_block_validity() | ext4_setup_system_zone() ext4_data_block_valid() | ext4_release_system_zone() | free system_blks rb nodes access system_blks rb nodes | trigger use after free | This patch lock the system zone when accessing it to prevent it being released when doing a remount with "noblock_validity" mount option. Signed-off-by: zhangyi (F) Cc: stable@vger.kernel.org --- fs/ext4/block_validity.c | 21 +++++++++++++++++++-- fs/ext4/ext4.h | 2 ++ fs/ext4/super.c | 1 + 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/fs/ext4/block_validity.c b/fs/ext4/block_validity.c index 8e83741..d9c4792 100644 --- a/fs/ext4/block_validity.c +++ b/fs/ext4/block_validity.c @@ -191,7 +191,7 @@ int ext4_setup_system_zone(struct super_block *sb) if (!test_opt(sb, BLOCK_VALIDITY)) { if (sbi->system_blks.rb_node) - ext4_release_system_zone(sb); + ext4_release_system_zone_lock(sb); return 0; } if (sbi->system_blks.rb_node) @@ -239,6 +239,14 @@ void ext4_release_system_zone(struct super_block *sb) EXT4_SB(sb)->system_blks = RB_ROOT; } +/* Called when (re)mounting the filesystem without BLOCK_VALIDITY */ +void ext4_release_system_zone_lock(struct super_block *sb) +{ + spin_lock(&EXT4_SB(sb)->system_blks_lock); + ext4_release_system_zone(sb); + spin_unlock(&EXT4_SB(sb)->system_blks_lock); +} + /* * Returns 1 if the passed-in block region (start_blk, * start_blk+count) is valid; 0 if some part of the block region @@ -248,7 +256,7 @@ int ext4_data_block_valid(struct ext4_sb_info *sbi, ext4_fsblk_t start_blk, unsigned int count) { struct ext4_system_zone *entry; - struct rb_node *n = sbi->system_blks.rb_node; + struct rb_node *n; if ((start_blk <= le32_to_cpu(sbi->s_es->s_first_data_block)) || (start_blk + count < start_blk) || @@ -256,6 +264,13 @@ int ext4_data_block_valid(struct ext4_sb_info *sbi, ext4_fsblk_t start_blk, sbi->s_es->s_last_error_block = cpu_to_le64(start_blk); return 0; } + + /* + * Lock the system zone to prevent it being released concurrently + * when doing a remount with "noblock_validity" mount option. + */ + spin_lock(&sbi->system_blks_lock); + n = sbi->system_blks.rb_node; while (n) { entry = rb_entry(n, struct ext4_system_zone, node); if (start_blk + count - 1 < entry->start_blk) @@ -264,9 +279,11 @@ int ext4_data_block_valid(struct ext4_sb_info *sbi, ext4_fsblk_t start_blk, n = n->rb_right; else { sbi->s_es->s_last_error_block = cpu_to_le64(start_blk); + spin_unlock(&sbi->system_blks_lock); return 0; } } + spin_unlock(&sbi->system_blks_lock); return 1; } diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index bf660aa..fd34a7b 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -1421,6 +1421,7 @@ struct ext4_sb_info { int s_jquota_fmt; /* Format of quota to use */ #endif unsigned int s_want_extra_isize; /* New inodes should reserve # bytes */ + spinlock_t system_blks_lock; struct rb_root system_blks; #ifdef EXTENTS_STATS @@ -3191,6 +3192,7 @@ extern void ext4_exit_sysfs(void); /* block_validity */ extern void ext4_release_system_zone(struct super_block *sb); +extern void ext4_release_system_zone_lock(struct super_block *sb); extern int ext4_setup_system_zone(struct super_block *sb); extern int __init ext4_init_system_zone(void); extern void ext4_exit_system_zone(void); diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 4079605..c95f972 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -4490,6 +4490,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) ext4_set_resv_clusters(sb); + spin_lock_init(&sbi->system_blks_lock); err = ext4_setup_system_zone(sb); if (err) { ext4_msg(sb, KERN_ERR, "failed to initialize system " -- 2.7.4