From nobody Wed Apr 1 08:17:51 2026 Received: from mail-pl1-f182.google.com (mail-pl1-f182.google.com [209.85.214.182]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 346EC2773F0 for ; Wed, 1 Apr 2026 01:39:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.182 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775007566; cv=none; b=LgqBASAXHelv2sUujvKKS0u2tXcKsmB0j5a3hVYdt/bnQjoK73qOSVmBLxnGTxxXaYLfnmYvVROHOT021MYXumVSabSn5Wn/QVAYqaK8EsI8/tPF//Cns3tV6I4ssrF4OeLMDl9BPirAQqEXeOlUM8pNSUEnf97KMaFB61341Wo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775007566; c=relaxed/simple; bh=1K5YNg6goourLvYf+5GyXSZzC8Xg639aEmLb5t7/504=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version; b=F51OgpuJF9RBaPzIHyH/TOX3TXSvwH3QFhqJA6uDe0IzX5AvjyDdYHroZEA6GSo0Ahngz9/5yXSuRj0VTegv5ZrujEZdeLmkfClhbKJMiURyxZoKiSnO0YnOI+M8Mimf/i1dcAHcWbKQLn2ZI+7t6QJNhYepTFsR8Vqyrv8qmus= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=dfmkIk56; arc=none smtp.client-ip=209.85.214.182 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="dfmkIk56" Received: by mail-pl1-f182.google.com with SMTP id d9443c01a7336-2b256a4c6b5so15985745ad.0 for ; Tue, 31 Mar 2026 18:39:25 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1775007564; x=1775612364; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to; bh=r8r8/bpiXzZ96Llz4sHkNmoXHZp4csIr6fCQclwBPYM=; b=dfmkIk56+2ee/0GAAIQ6Fp0gXGyX6QP9FIRdG2aG7Ezzv327exIn+Ucx8d6S9P5Ihi +UcSTo5kxGaWYpxEGTjr9xgLaNrWwkxnXRIQ2nmdN3E/HsD1f5cfqGPjA135qHvYN7+W XSQytPNrKUPMNFEN3R7cWHU4KdbDXBJ9L1v6qOAtTrp4dBYcUAzOsqZ9NJSqhDIRbPtD ok56rMgfzq+AzSbiRX8KmANp3kzbWzIohzaJsQqYN1Sl0DPSjnqAQtAmQ2qrFRxKGNTS Tvs0sjQS4g4+9dsjQx2wF7o99sC97WfMaPM46bg1owMRq6IcanHEaNe7GmC+j7c5cIYJ O68w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1775007564; x=1775612364; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=r8r8/bpiXzZ96Llz4sHkNmoXHZp4csIr6fCQclwBPYM=; b=StOaYPpn+p455kVbkXC1cH3Ksb6tTSd0SesHCPeOa9IG1zAvDLs5cUBWY1RQsiNltY 4Xzw13tkmXe54zc2HhjHGe+emKJ2+Mgm7qcJQzvFMvDnTfBdIPAPbS5PJSJ3X1fzTVGe zl8ww1dV5/Ob1KZAZpdRcGwejVGTRR8icISB4EiJegdWrdXBxBspTFRnjy+f70hl81L+ onAi4v8MCJ2XkX9TClcyDCQ8CpixCvEmephW/OMIOS4QOvubI24lELXk9Kdc3G9qf8QK dX7vbnsOOo8Q2J2HGWlCcd8jlFP8N0/Fuwo0s0k5yvNTLbWtvWd5E6swZS7BU27/n3bU bc1g== X-Forwarded-Encrypted: i=1; AJvYcCWGc1I9/Jb8mzSo0DPu0WXoIWRCDkssP8LqpQEHGZWDChjZHQwA7dlOtvBl4ujYnfbJcto3sNShvSbx/MM=@vger.kernel.org X-Gm-Message-State: AOJu0YzpIIavQqA+/z/DiMOeA3Wob8Xe9298nmi3pm45dg/J3iwZfv40 HIkg0BENp1Yte5DsevjoZV8/rfeQ7vewEgES249PrLNOH9Rzhas0ZMlA X-Gm-Gg: ATEYQzzLd9K/kZ/cK5xdksb/0QcSRHxDJHkLedW8K16M346tgsa1iC1OOhLnk0WPO+r Fogq9ss2plNyKuh/mi3dLNhAPdMQHscTSown/0cTVDYbrxh1rM/9HleSH1TUI03pdphDelzLlC2 yZDHhXtrDy+8cZ2QL2pnGpe4vMU+k0cPDrSWWfXN9b4uNglW0fw72CREOvPETM/x8/K4P2svzdf JWYqKGXfOReaoz5juEeGc76+HZtLG7XwQOhsTdTi5exkIGYONeQwRJz3jcgcNpisAtpw93DzmuK BNDYxg/pW+m9nN6BxPGI7Gk7d0LrzeoCbqy7FBn1gHCqgb/pyhS3bUZ2kJQ3PXl2mEKLcvMNaAd 2PZ+g3f5RB6rPf8QEAD85jspxwvFbkeIuojEpLt+u6eiL1i/P+Pwu+oGod/3DdYomF9cM4OLI51 4h5slUoNL11UjatEfJoZpOGOVkf+1WVMemRzs8t8AfUk35bKN5scbA1caao/7tQW1jx4MyvI8= X-Received: by 2002:a17:903:90f:b0:2b0:5ec1:97c1 with SMTP id d9443c01a7336-2b269a950c8mr13744885ad.7.1775007564166; Tue, 31 Mar 2026 18:39:24 -0700 (PDT) Received: from kernel-fuzz.. ([103.172.182.26]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2b2427afa57sm158766785ad.71.2026.03.31.18.39.20 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 31 Mar 2026 18:39:23 -0700 (PDT) From: ZhengYuan Huang To: mark@fasheh.com, jlbec@evilplan.org, joseph.qi@linux.alibaba.com Cc: ocfs2-devel@lists.linux.dev, linux-kernel@vger.kernel.org, baijiaju1990@gmail.com, r33s3n6@gmail.com, zzzccc427@gmail.com, ZhengYuan Huang Subject: [PATCH] ocfs2: validate dx extent list bounds during lookup Date: Wed, 1 Apr 2026 09:39:14 +0800 Message-ID: <20260401013914.3543304-1-gality369@gmail.com> X-Mailer: git-send-email 2.43.0 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 Content-Type: text/plain; charset="utf-8" [BUG] A corrupted indexed directory can trigger a KASAN use-after-free in ocfs2_dx_dir_lookup_rec() when the dx root or leaf extent list carries an out-of-range l_count or l_next_free_rec value. BUG: KASAN: use-after-free in ocfs2_dx_dir_lookup_rec+0x6f7/0x880 fs/ocfs2/= dir.c:813 Read of size 4 at addr ffff888043b7b0e0 by task syz.0.3467/8031 Call Trace: ... ocfs2_dx_dir_lookup_rec+0x6f7/0x880 fs/ocfs2/dir.c:813 ocfs2_dx_dir_lookup+0x100/0x5d0 fs/ocfs2/dir.c:868 ocfs2_dx_dir_search+0x7bc/0x11c0 fs/ocfs2/dir.c:928 ocfs2_find_entry_dx fs/ocfs2/dir.c:1042 [inline] ocfs2_find_entry+0x97e/0xce0 fs/ocfs2/dir.c:1079 ocfs2_find_files_on_disk+0xa9/0x2f0 fs/ocfs2/dir.c:2002 ocfs2_lookup_ino_from_name+0xae/0x110 fs/ocfs2/dir.c:2024 ocfs2_lookup+0x45e/0x860 fs/ocfs2/namei.c:122 lookup_open.isra.0+0x4a2/0x1460 fs/namei.c:3774 open_last_lookups fs/namei.c:3895 [inline] path_openat+0x11fe/0x2ce0 fs/namei.c:4131 do_filp_open+0x1f6/0x430 fs/namei.c:4161 do_sys_openat2+0x117/0x1c0 fs/open.c:1437 do_sys_open fs/open.c:1452 [inline] __do_sys_openat fs/open.c:1468 [inline] __se_sys_openat fs/open.c:1463 [inline] __x64_sys_openat+0x15b/0x220 fs/open.c:1463 ... [CAUSE] ocfs2_dx_dir_lookup_rec() only checked for an empty extent list before iterating over the directory index records. It did not verify that the root dx list fits within a dx root block, or that the leaf list fits within an extent block. Comparing l_next_free_rec only against the on-disk l_count is also not enough because l_count itself can be corrupted. [FIX] Validate both the dx root list and the leaf extent list against their physical record capacities before indexing into l_recs[]. Use ocfs2_extent_recs_per_dx_root() for the root and ocfs2_extent_recs_per_eb() for the leaf block so the bounds check does not trust on-disk sizing fields. Fixes: 9b7895efac90 ("ocfs2: Add a name indexed b-tree to directory inodes") Signed-off-by: ZhengYuan Huang --- fs/ocfs2/dir.c | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/fs/ocfs2/dir.c b/fs/ocfs2/dir.c index b82fe4431eb1..3403c0d3810e 100644 --- a/fs/ocfs2/dir.c +++ b/fs/ocfs2/dir.c @@ -790,15 +790,25 @@ static int ocfs2_dx_dir_lookup_rec(struct inode *inod= e, struct buffer_head *eb_bh =3D NULL; struct ocfs2_extent_block *eb; struct ocfs2_extent_rec *rec =3D NULL; + unsigned int max_recs; =20 - if (le16_to_cpu(el->l_count) !=3D - ocfs2_extent_recs_per_dx_root(inode->i_sb)) { + max_recs =3D ocfs2_extent_recs_per_dx_root(inode->i_sb); + if (le16_to_cpu(el->l_count) !=3D max_recs) { ret =3D ocfs2_error(inode->i_sb, "Inode %llu has invalid extent list length %u\n", inode->i_ino, le16_to_cpu(el->l_count)); goto out; } =20 + if (le16_to_cpu(el->l_next_free_rec) > max_recs) { + ret =3D ocfs2_error(inode->i_sb, + "Inode %llu has invalid dx root next free %u, max %u\n", + inode->i_ino, + le16_to_cpu(el->l_next_free_rec), + max_recs); + goto out; + } + if (el->l_tree_depth) { ret =3D ocfs2_find_leaf(INODE_CACHE(inode), el, major_hash, &eb_bh); @@ -817,6 +827,27 @@ static int ocfs2_dx_dir_lookup_rec(struct inode *inode, (unsigned long long)eb_bh->b_blocknr); goto out; } + + max_recs =3D ocfs2_extent_recs_per_eb(inode->i_sb); + if (le16_to_cpu(el->l_count) !=3D max_recs) { + ret =3D ocfs2_error(inode->i_sb, + "Inode %llu has invalid tree block %llu list count %u, max %u\n", + inode->i_ino, + (unsigned long long)eb_bh->b_blocknr, + le16_to_cpu(el->l_count), + max_recs); + goto out; + } + + if (le16_to_cpu(el->l_next_free_rec) > max_recs) { + ret =3D ocfs2_error(inode->i_sb, + "Inode %llu has invalid tree block %llu next free %u, max %u\n", + inode->i_ino, + (unsigned long long)eb_bh->b_blocknr, + le16_to_cpu(el->l_next_free_rec), + max_recs); + goto out; + } } =20 if (le16_to_cpu(el->l_next_free_rec) =3D=3D 0) {