From nobody Fri Dec 19 10:57:30 2025 Received: from dggsgout11.his.huawei.com (dggsgout11.his.huawei.com [45.249.212.51]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B9C562AF16; Tue, 2 Jul 2024 13:25:35 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=45.249.212.51 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1719926737; cv=none; b=ZclrhFN7gxxXBAigcA2nT3b1JP5eUvEknjzYBWanorS2Dg74ozDWWLhZM5/xl/SnRLlJtiHb/JD4SZ/NMu+XUIaq/Yp03qEbwOddlqp7n3TFsEJiQtPT99SBnE3t/KG5ie4tqUwmBjb+Rq4G151AGIF6Q9q+R1drnTwLSLBuS4g= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1719926737; c=relaxed/simple; bh=/afTGIclt3fp6ucVNNuhF6iV22ZJeLND8TrVIthbzbc=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=QBLR4Oflg3zYHvrtHKt3sh2yyZO2wFiO1wWyrzbzpMclZHzG8J0ce2pyTMpjRuPXVP/F760EldLJfaV5LdlumKZ/clmi8+DaxqJOvjX2GQeh7MHP2XHALyCYe8p7HkhGISI33bMn+bXTa4CuuTyQC+n0KdEbJs0XNPkLhNeHX7w= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=huaweicloud.com; spf=pass smtp.mailfrom=huaweicloud.com; arc=none smtp.client-ip=45.249.212.51 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=huaweicloud.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=huaweicloud.com Received: from mail.maildlp.com (unknown [172.19.163.216]) by dggsgout11.his.huawei.com (SkyGuard) with ESMTP id 4WD3Yq6mWBz4f3lVp; Tue, 2 Jul 2024 21:25:19 +0800 (CST) Received: from mail02.huawei.com (unknown [10.116.40.75]) by mail.maildlp.com (Postfix) with ESMTP id 69A311A0170; Tue, 2 Jul 2024 21:25:32 +0800 (CST) Received: from huaweicloud.com (unknown [10.175.104.67]) by APP2 (Coremail) with SMTP id Syh0CgCXAYfI_4NmaZ_dAw--.32725S5; Tue, 02 Jul 2024 21:25:31 +0800 (CST) From: libaokun@huaweicloud.com To: linux-ext4@vger.kernel.org Cc: tytso@mit.edu, adilger.kernel@dilger.ca, jack@suse.cz, ritesh.list@gmail.com, linux-kernel@vger.kernel.org, yi.zhang@huawei.com, yangerkun@huawei.com, libaokun@huaweicloud.com, Baokun Li , syzbot+ae688d469e36fb5138d0@syzkaller.appspotmail.com, stable@kernel.org Subject: [PATCH 1/2] ext4: check dot and dotdot of dx_root before making dir indexed Date: Tue, 2 Jul 2024 21:23:48 +0800 Message-Id: <20240702132349.2600605-2-libaokun@huaweicloud.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20240702132349.2600605-1-libaokun@huaweicloud.com> References: <20240702132349.2600605-1-libaokun@huaweicloud.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-CM-TRANSID: Syh0CgCXAYfI_4NmaZ_dAw--.32725S5 X-Coremail-Antispam: 1UD129KBjvJXoWxZF4DtFW7WF1fXw48JrWDurg_yoW7Jry5pF sxKr93JryrGF9xur4avr45Zr1Yk34IgF1DGFZ3Xw10yrWa9w1xWFn2vF10qFWDKrWkuw1q qF4agry3Gw17XrJanT9S1TB71UUUUUUqnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDU0xBIdaVrnRJUUUPl14x267AKxVW5JVWrJwAFc2x0x2IEx4CE42xK8VAvwI8IcIk0 rVWrJVCq3wAFIxvE14AKwVWUJVWUGwA2048vs2IY020E87I2jVAFwI0_Jr4l82xGYIkIc2 x26xkF7I0E14v26r1I6r4UM28lY4IEw2IIxxk0rwA2F7IY1VAKz4vEj48ve4kI8wA2z4x0 Y4vE2Ix0cI8IcVAFwI0_Ar0_tr1l84ACjcxK6xIIjxv20xvEc7CjxVAFwI0_Cr0_Gr1UM2 8EF7xvwVC2z280aVAFwI0_GcCE3s1l84ACjcxK6I8E87Iv6xkF7I0E14v26rxl6s0DM2AI xVAIcxkEcVAq07x20xvEncxIr21l5I8CrVACY4xI64kE6c02F40Ex7xfMcIj6xIIjxv20x vE14v26r1j6r18McIj6I8E87Iv67AKxVWUJVW8JwAm72CE4IkC6x0Yz7v_Jr0_Gr1lF7xv r2IYc2Ij64vIr41lF7I21c0EjII2zVCS5cI20VAGYxC7M4IIrI8v6xkF7I0E8cxan2IY04 v7M4kE6xkIj40Ew7xC0wCF04k20xvY0x0EwIxGrwCFx2IqxVCFs4IE7xkEbVWUJVW8JwC2 0s026c02F40E14v26r1j6r18MI8I3I0E7480Y4vE14v26r106r1rMI8E67AF67kF1VAFwI 0_Jw0_GFylIxkGc2Ij64vIr41lIxAIcVC0I7IYx2IY67AKxVWUJVWUCwCI42IY6xIIjxv2 0xvEc7CjxVAFwI0_Gr0_Cr1lIxAIcVCF04k26cxKx2IYs7xG6r1j6r1xMIIF0xvEx4A2js IE14v26r1j6r4UMIIF0xvEx4A2jsIEc7CjxVAFwI0_Gr0_Gr1UYxBIdaVFxhVjvjDU0xZF pf9x0JUhTmDUUUUU= X-CM-SenderInfo: 5olet0hnxqqx5xdzvxpfor3voofrz/1tbiAgAMBV1jkHxOdgADsi Content-Type: text/plain; charset="utf-8" From: Baokun Li Syzbot reports a issue as follows: =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D BUG: unable to handle page fault for address: ffffed11022e24fe PGD 23ffee067 P4D 23ffee067 PUD 0 Oops: Oops: 0000 [#1] PREEMPT SMP KASAN PTI CPU: 0 PID: 5079 Comm: syz-executor306 Not tainted 6.10.0-rc5-g55027e689933= #0 Call Trace: make_indexed_dir+0xdaf/0x13c0 fs/ext4/namei.c:2341 ext4_add_entry+0x222a/0x25d0 fs/ext4/namei.c:2451 ext4_rename fs/ext4/namei.c:3936 [inline] ext4_rename2+0x26e5/0x4370 fs/ext4/namei.c:4214 [...] =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D The immediate cause of this problem is that there is only one valid dentry for the block to be split during do_split, so split=3D=3D0 results in out of bounds accesses to the map triggering the issue. do_split unsigned split dx_make_map count =3D 1 split =3D count/2 =3D 0; continued =3D hash2 =3D=3D map[split - 1].hash; ---> map[4294967295] The maximum length of a filename is 255 and the minimum block size is 1024, so it is always guaranteed that the number of entries is greater than or equal to 2 when do_split() is called. But syzbot's crafted image has no dot and dotdot in dir, and the dentry distribution in dirblock is as follows: bus dentry1 hole dentry2 free |xx--|xx-------------|...............|xx-------------|...............| 0 12 (8+248)=3D256 268 256 524 (8+256)=3D264 788 236 1024 So when renaming dentry1 increases its name_len length by 1, neither hole nor free is sufficient to hold the new dentry, and make_indexed_dir() is called. In make_indexed_dir() it is assumed that the first two entries of the dirblock must be dot and dotdot, so bus and dentry1 are left in dx_root because they are treated as dot and dotdot, and only dentry2 is moved to the new leaf block. That's why count is equal to 1. Therefore add the ext4_check_dx_root() helper function to add more sanity checks to dot and dotdot before starting the conversion to avoid the above issue. Reported-by: syzbot+ae688d469e36fb5138d0@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=3Dae688d469e36fb5138d0 Fixes: ac27a0ec112a ("[PATCH] ext4: initial copy of files from ext3") Cc: stable@kernel.org Signed-off-by: Baokun Li Reviewed-by: Jan Kara --- fs/ext4/namei.c | 56 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 51 insertions(+), 5 deletions(-) diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index e6769b97a970..35881e3dd880 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c @@ -2172,6 +2172,52 @@ static int add_dirent_to_buf(handle_t *handle, struc= t ext4_filename *fname, return err ? err : err2; } =20 +static bool ext4_check_dx_root(struct inode *dir, struct dx_root *root) +{ + struct fake_dirent *fde; + const char *error_msg; + unsigned int rlen; + unsigned int blocksize =3D dir->i_sb->s_blocksize; + char *blockend =3D (char *)root + dir->i_sb->s_blocksize; + + fde =3D &root->dot; + if (unlikely(fde->name_len !=3D 1)) { + error_msg =3D "invalid name_len for '.'"; + goto corrupted; + } + if (unlikely(strncmp(root->dot_name, ".", fde->name_len))) { + error_msg =3D "invalid name for '.'"; + goto corrupted; + } + rlen =3D ext4_rec_len_from_disk(fde->rec_len, blocksize); + if (unlikely((char *)fde + rlen >=3D blockend)) { + error_msg =3D "invalid rec_len for '.'"; + goto corrupted; + } + + fde =3D &root->dotdot; + if (unlikely(fde->name_len !=3D 2)) { + error_msg =3D "invalid name_len for '..'"; + goto corrupted; + } + if (unlikely(strncmp(root->dotdot_name, "..", fde->name_len))) { + error_msg =3D "invalid name for '..'"; + goto corrupted; + } + rlen =3D ext4_rec_len_from_disk(fde->rec_len, blocksize); + if (unlikely((char *)fde + rlen >=3D blockend)) { + error_msg =3D "invalid rec_len for '..'"; + goto corrupted; + } + + return true; + +corrupted: + EXT4_ERROR_INODE(dir, "Corrupt dir, %s, running e2fsck is recommended", + error_msg); + return false; +} + /* * This converts a one block unindexed directory to a 3 block indexed * directory, and adds the dentry to the indexed directory. @@ -2206,17 +2252,17 @@ static int make_indexed_dir(handle_t *handle, struc= t ext4_filename *fname, brelse(bh); return retval; } + root =3D (struct dx_root *) bh->b_data; + if (!ext4_check_dx_root(dir, root)) { + brelse(bh); + return -EFSCORRUPTED; + } =20 /* The 0th block becomes the root, move the dirents out */ fde =3D &root->dotdot; de =3D (struct ext4_dir_entry_2 *)((char *)fde + ext4_rec_len_from_disk(fde->rec_len, blocksize)); - if ((char *) de >=3D (((char *) root) + blocksize)) { - EXT4_ERROR_INODE(dir, "invalid rec_len for '..'"); - brelse(bh); - return -EFSCORRUPTED; - } len =3D ((char *) root) + (blocksize - csum_size) - (char *) de; =20 /* Allocate new block for the 0th block's dirents */ --=20 2.39.2