From nobody Sun May 24 19:33:41 2026 Received: from mail-pl1-f180.google.com (mail-pl1-f180.google.com [209.85.214.180]) (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 90AFC2E6CCD for ; Sat, 23 May 2026 04:14:57 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.180 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779509699; cv=none; b=BS2FvxuASBW9W8bSItWS3DN09EcfE3vOl8MyQQteJxaD42hMP87FMy/jtinXoo4Xus2cLvB8DSRSpc6RhtcbzS9Ewcut4SgQ2BS+k2rkz207Jd6XUHPBr+FT3w3SLV6k3p7Rit7WQSmVzDryT8gbe/88hdKs9nN0OZbZaU4zdPY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779509699; c=relaxed/simple; bh=Sj4TYlqsEDJ1E31zDNcwz8WQKjkuNqBUsRzmM/JS7m4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=KB2/aBhlvfkz7rSOw1HjzRyt63gC0LKoARxbPax35Y2eaQH4HQ0vUnQpGlwNu6FZtJxn5zEe6XObgL+yYH5YOzO8cIQ90mvAHWzUsIV+J3DUYxQHyfOcChl8oc1jLwQpGuu8wLzrzBMo5uay+xkd9eJDO0C+X+sbnc+GF68P7gE= 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=LA4/M0vG; arc=none smtp.client-ip=209.85.214.180 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="LA4/M0vG" Received: by mail-pl1-f180.google.com with SMTP id d9443c01a7336-2b9ec9443c2so46966565ad.1 for ; Fri, 22 May 2026 21:14:57 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1779509697; x=1780114497; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=YPHBFgx2JoaZqgDjoqYVl+IzgvEea3y23kJ9Tps9FIk=; b=LA4/M0vGsCpsET6fxYomucSjNVfJ3f142u3gnqKmrqt8WgKnjc5/by+zxnGkBAGrl4 b0MjcOReHlDuFJql2pI231yZw5ATgDxNxMQ2+HzVB8L1g1lhecI/JvTAlXYi/0Av1m4T 86nohoHbk0UlEfGxwWwgY/CsUz1apv49jVKC4i+VWh172jqLCIx6zy6h9/nWR3DG67tv mfNX93PjBgZEYPcsYh9B4yvinhZiBqaoJxwttDog4VvCjg4Ddi4gNkvcRHaMc2HE9MC8 E/BInw8ofv9ls5s+eqNWV0pX80NadFLrdvFtnkWIAfH50Su4atud5EcnBZjDzlfglXRT SUJw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779509697; x=1780114497; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=YPHBFgx2JoaZqgDjoqYVl+IzgvEea3y23kJ9Tps9FIk=; b=bLInmLN8hB/K7YMhl6VID7zLyEX/Y7VgrsUQYkQpPjIu27Q9LV5b5UoK9hq3DqOamd M1s070LvEVdSaUtO4eu08HsHeuTpnWuKUjk2IyqvO3lvOpEWnXj49RaLGFDm3/Lm+wHS yfV7fliFikETb9XDvonbGQeiy96A+i2GgYB/PcON23w4fCDV3O3OWzRN1xbMMwW1Npjn ZndlrL5vFL3N8bRdHkkrZJkuMiprkdq2zat157AuY46u2SpDQ8eSHSFmvZQLIaJ+BVrX 1AZXi+pj393ac9jPdgXdTcOAAHiTLAE+tzm4YWeP7CN052XgAct5la97uXdIIVddHW6/ 0swA== X-Forwarded-Encrypted: i=1; AFNElJ95qK6l9NjifRpYdzWYLHzc+0R/OWsDyI5TjSmlOGFG6W5/esmiA1aead7e+wawIirXHuUdJdDFgGmZDYU=@vger.kernel.org X-Gm-Message-State: AOJu0YwJYD3PVqtEzidId4bj/XtXaXjWg0oxwRoFltYxrXZEwUSVY0gw HYrylvj3MphH14amzfxXCJ39Qe1sY04Wg5P30SFjaza0VUQ8EDka0kzP X-Gm-Gg: Acq92OHa6KIfgc+6oY8t0POPNooFbF8XoMyuGXJxYo1h5bJX/AlX7mt5oTs8gPuGpeg Or0ec/ClElnfAta2nava1M83xPg57iQihaF3ZWYq4h+TwemvcfH7K07XqdRa+PZQEhL2wi23QzF k+iJIFfN/T9HhjKOyobqyyDlu32uAsr7SweZbbIrrDj4hCrL90zyZbfU/aEhh9unOClzA6ZMmdq UJX23G58yuuwtZYwZjSVOS5FxdfmKO7xx4xMBQAS2gS++lUuPFpUh/gtsiuIDZ0NTajuVJNTDyg ejtEizEEa24vBg8IVGpOyjG5PjPt91RGrr7YxQ/imzJqz0gSM5hGI/+BTGS6G0bSP17U1+ubuR5 6bABT2a0SLHbK04E56x7LSGyHIs9hLLUT+aVctdO3aHvEjWJnqexb1oEpkDnXUZexgrjWyn8JMK F8xN8RmAzItIhNCucspE7FCN5y4LyLfg== X-Received: by 2002:a17:903:41c4:b0:2ba:21c2:d6cb with SMTP id d9443c01a7336-2beb08843d7mr52197895ad.16.1779509696527; Fri, 22 May 2026 21:14:56 -0700 (PDT) Received: from hyunchul-PC02.lge.net ([27.122.242.71]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2beb591a277sm31887675ad.80.2026.05.22.21.14.54 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 22 May 2026 21:14:55 -0700 (PDT) From: Hyunchul Lee To: Namjae Jeon Cc: Hyunchul Lee , linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, woot000 Subject: [PATCH v2 1/4] ntfs: validate index block header more strictly Date: Sat, 23 May 2026 13:14:20 +0900 Message-ID: <20260523041423.2726275-2-hyc.lee@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260523041423.2726275-1-hyc.lee@gmail.com> References: <20260523041423.2726275-1-hyc.lee@gmail.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 Content-Type: text/plain; charset="utf-8" Modify ntfs_index_block_inconsisent() to perform stricter validation of INDEX_HEADER geometry in INDX blocks, and update ntfs_lookup_inode_by_name() to use that function to validate INDX blocks. Tested-by: woot000 Signed-off-by: Hyunchul Lee --- fs/ntfs/dir.c | 38 ++++-------------- fs/ntfs/index.c | 101 ++++++++++++++++++++++++++++++++++-------------- fs/ntfs/index.h | 3 ++ 3 files changed, 81 insertions(+), 61 deletions(-) diff --git a/fs/ntfs/dir.c b/fs/ntfs/dir.c index 20f5c7074bdd..6745a0e6e3e7 100644 --- a/fs/ntfs/dir.c +++ b/fs/ntfs/dir.c @@ -342,43 +342,19 @@ u64 ntfs_lookup_inode_by_name(struct ntfs_inode *dir_= ni, const __le16 *uname, dir_ni->mft_no); goto unm_err_out; } - /* Catch multi sector transfer fixup errors. */ - if (unlikely(!ntfs_is_indx_record(ia->magic))) { - ntfs_error(sb, - "Directory index record with vcn 0x%llx is corrupt. Corrupt inode 0x%l= lx. Run chkdsk.", - vcn, dir_ni->mft_no); - goto unm_err_out; - } - if (le64_to_cpu(ia->index_block_vcn) !=3D vcn) { - ntfs_error(sb, - "Actual VCN (0x%llx) of index buffer is different from expected VCN (0x= %llx). Directory inode 0x%llx is corrupt or driver bug.", - le64_to_cpu(ia->index_block_vcn), - vcn, dir_ni->mft_no); - goto unm_err_out; - } - if (le32_to_cpu(ia->index.allocated_size) + 0x18 !=3D - dir_ni->itype.index.block_size) { - ntfs_error(sb, - "Index buffer (VCN 0x%llx) of directory inode 0x%llx has a size (%u) di= ffering from the directory specified size (%u). Directory inode is corrupt = or driver bug.", - vcn, dir_ni->mft_no, - le32_to_cpu(ia->index.allocated_size) + 0x18, - dir_ni->itype.index.block_size); - goto unm_err_out; - } index_end =3D (u8 *)ia + dir_ni->itype.index.block_size; if (index_end > kaddr + PAGE_SIZE) { ntfs_error(sb, - "Index buffer (VCN 0x%llx) of directory inode 0x%llx crosses page bound= ary. Impossible! Cannot access! This is probably a bug in the driver.", - vcn, dir_ni->mft_no); + "Index buffer (VCN 0x%llx) of directory inode 0x%llx crosses page bo= undary. Impossible! Cannot access! This is probably a bug in the driver.", + vcn, dir_ni->mft_no); goto unm_err_out; } - index_end =3D (u8 *)&ia->index + le32_to_cpu(ia->index.index_length); - if (index_end > (u8 *)ia + dir_ni->itype.index.block_size) { - ntfs_error(sb, - "Size of index buffer (VCN 0x%llx) of directory inode 0x%llx exceeds ma= ximum size.", - vcn, dir_ni->mft_no); + err =3D ntfs_index_block_inconsistent(vol, ia, + dir_ni->itype.index.block_size, + vcn, dir_ni->mft_no); + if (err) goto unm_err_out; - } + index_end =3D (u8 *)&ia->index + le32_to_cpu(ia->index.index_length); /* The first index entry. */ ie =3D (struct index_entry *)((u8 *)&ia->index + le32_to_cpu(ia->index.entries_offset)); diff --git a/fs/ntfs/index.c b/fs/ntfs/index.c index 146e011c1a41..9713b082b03d 100644 --- a/fs/ntfs/index.c +++ b/fs/ntfs/index.c @@ -303,6 +303,55 @@ static int ntfs_ie_end(struct index_entry *ie) return ie->flags & INDEX_ENTRY_END || !ie->length; } =20 +static int ntfs_index_header_inconsistent(struct ntfs_volume *vol, + const struct index_header *ih, + u32 bytes_available, u64 inum) +{ + u32 entries_offset, index_length, allocated_size; + + if (bytes_available < sizeof(struct index_header)) { + ntfs_error(vol->sb, + "index block in inode %llu is smaller than an index header.", + (unsigned long long)inum); + return -EIO; + } + + entries_offset =3D le32_to_cpu(ih->entries_offset); + index_length =3D le32_to_cpu(ih->index_length); + allocated_size =3D le32_to_cpu(ih->allocated_size); + + if (entries_offset < sizeof(struct index_header) || + entries_offset > bytes_available) { + ntfs_error(vol->sb, + "Invalid index entry offset in inode %llu.", + (unsigned long long)inum); + return -EIO; + } + + if (index_length <=3D entries_offset) { + ntfs_error(vol->sb, + "No space for index entries in inode %llu.", + (unsigned long long)inum); + return -EIO; + } + + if (allocated_size < index_length) { + ntfs_error(vol->sb, + "Index entries overflow in inode %llu.", + (unsigned long long)inum); + return -EIO; + } + + if (allocated_size > bytes_available || index_length > bytes_available) { + ntfs_error(vol->sb, + "Index entries in inode %llu exceed the available buffer.", + (unsigned long long)inum); + return -EIO; + } + + return 0; +} + /* * Find the last entry in the index block */ @@ -437,7 +486,7 @@ static struct index_entry *ntfs_ie_dup_novcn(struct ind= ex_entry *ie) * The size of block is assumed to have been checked to be what is * defined in the index root. * - * Returns 0 if no error was found -1 otherwise (with errno unchanged) + * Returns 0 if no error was found, -EIO otherwise * * |<--->| offsetof(struct index_block, index) * | |<--->| sizeof(struct index_header) @@ -452,21 +501,20 @@ static struct index_entry *ntfs_ie_dup_novcn(struct i= ndex_entry *ie) * * size(struct index_header) <=3D ent_offset < ind_length <=3D alloc_size = < bk_size */ -static int ntfs_index_block_inconsistent(struct ntfs_index_context *icx, - struct index_block *ib, s64 vcn) +int ntfs_index_block_inconsistent(struct ntfs_volume *vol, + const struct index_block *ib, + u32 block_size, s64 vcn, u64 inum) { u32 ib_size =3D (unsigned int)le32_to_cpu(ib->index.allocated_size) + offsetof(struct index_block, index); - struct super_block *sb =3D icx->idx_ni->vol->sb; - unsigned long long inum =3D icx->idx_ni->mft_no; + struct super_block *sb =3D vol->sb; =20 ntfs_debug("Entering\n"); =20 if (!ntfs_is_indx_record(ib->magic)) { - ntfs_error(sb, "Corrupt index block signature: vcn %lld inode %llu\n", - vcn, (unsigned long long)icx->idx_ni->mft_no); - return -1; + vcn, (unsigned long long)inum); + return -EIO; } =20 if (le64_to_cpu(ib->index_block_vcn) !=3D vcn) { @@ -474,30 +522,21 @@ static int ntfs_index_block_inconsistent(struct ntfs_= index_context *icx, "Corrupt index block: s64 (%lld) is different from expected s64 (%lld) = in inode %llu\n", (long long)le64_to_cpu(ib->index_block_vcn), vcn, inum); - return -1; + return -EIO; } =20 - if (ib_size !=3D icx->block_size) { + if (ib_size !=3D block_size) { ntfs_error(sb, - "Corrupt index block : s64 (%lld) of inode %llu has a size (%u) differi= ng from the index specified size (%u)\n", - vcn, inum, ib_size, icx->block_size); - return -1; + "Corrupt index block : s64 (%lld) of inode %llu has a size (%u) diff= ering from the index specified size (%u)\n", + vcn, inum, ib_size, block_size); + return -EIO; } =20 - if (le32_to_cpu(ib->index.entries_offset) < sizeof(struct index_header)) { - ntfs_error(sb, "Invalid index entry offset in inode %lld\n", inum); - return -1; - } - if (le32_to_cpu(ib->index.index_length) <=3D - le32_to_cpu(ib->index.entries_offset)) { - ntfs_error(sb, "No space for index entries in inode %lld\n", inum); - return -1; - } - if (le32_to_cpu(ib->index.allocated_size) < - le32_to_cpu(ib->index.index_length)) { - ntfs_error(sb, "Index entries overflow in inode %lld\n", inum); - return -1; - } + if (ntfs_index_header_inconsistent(vol, &ib->index, + block_size - + offsetof(struct index_block, index), + inum)) + return -EIO; =20 return 0; } @@ -665,12 +704,14 @@ static int ntfs_ib_read(struct ntfs_index_context *ic= x, s64 vcn, struct index_bl else ntfs_error(icx->idx_ni->vol->sb, "Failed to read full index block at %lld\n", pos); - return -1; + return -EIO; } =20 post_read_mst_fixup((struct ntfs_record *)((u8 *)dst), icx->block_size); - if (ntfs_index_block_inconsistent(icx, dst, vcn)) - return -1; + if (ntfs_index_block_inconsistent(icx->idx_ni->vol, dst, + icx->block_size, vcn, + icx->idx_ni->mft_no)) + return -EIO; =20 return 0; } diff --git a/fs/ntfs/index.h b/fs/ntfs/index.h index e68d6fabaf9f..3451ec8a1c4e 100644 --- a/fs/ntfs/index.h +++ b/fs/ntfs/index.h @@ -89,6 +89,9 @@ struct ntfs_index_context { bool sync_write; }; =20 +int ntfs_index_block_inconsistent(struct ntfs_volume *vol, + const struct index_block *ib, + u32 block_size, s64 vcn, u64 inum); int ntfs_index_entry_inconsistent(struct ntfs_index_context *icx, struct n= tfs_volume *vol, const struct index_entry *ie, __le32 collation_rule, u64 inum); struct ntfs_index_context *ntfs_index_ctx_get(struct ntfs_inode *ni, __le1= 6 *name, --=20 2.43.0 From nobody Sun May 24 19:33:41 2026 Received: from mail-pl1-f175.google.com (mail-pl1-f175.google.com [209.85.214.175]) (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 655A332860B for ; Sat, 23 May 2026 04:15:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.175 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779509705; cv=none; b=EjeJf3y3e6wehTkphA7lfMsOFfTyTVSdQVVy12PQRdRnlrABw/qXoXMkPxhvkijLd8LIEr6f/vEhCPKwV4hItnCro4XcWnwFsvkrmY73O+Qe0xpS4bSV5EQhFQay9roCVyIc23z+C2V7ti+jFhAPcSGWBjsYP1qlP10yyfwoa2M= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779509705; c=relaxed/simple; bh=6jofB/yXxm47kMPOD05SB9GL4SDnN6o6L7Cg9O4IUpA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=edjNf4avFXFxlao7EqD9RiZY28b6onXYlIkOKMqUfHLj1qJCuRVYUrPJXjanFvmvO64s+cfX/18gp6DpzkKuW9MLRvbn/ioIiyvd+r6kAbKCiYV7EcO1aywy2SejnwPusRA7WLY3yMOhWMTyveMfsa7isShOzk6zty7Au30cfdA= 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=O/qzTQdA; arc=none smtp.client-ip=209.85.214.175 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="O/qzTQdA" Received: by mail-pl1-f175.google.com with SMTP id d9443c01a7336-2bcd3ac3307so46641995ad.0 for ; Fri, 22 May 2026 21:15:04 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1779509703; x=1780114503; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=XJ9Wd6u4olIlHGlFZFpAmnHsxCYKujM9D/BFLc8A9dQ=; b=O/qzTQdAzdr2PQBHgxwQaerwOZD08fdqraUpa3zQa0fhIG3EPlC2BV8YRv5/CFGC1c xfOFSf0+Ce8pd4A3dtXDJ9pzOqAJW2aNUbp4Ai1NYDINMtA0uq+e/uO5orxMMLDA86Xj 7ZQrXJa11NtBgXqHcVBSwIrGcW/fyt81jTiA2NXc79e9V/2z37XNxxTQz43hDlmtWjyH jqlLhxtJutryMmmfJ6CHarD4GaCk/cln8pNvdNKWj3Wo6Hpl+bQxdVsReD/ezZgdQlsY fvdozMPfvxiM8tQySUv004tbgnfse2JvXesz9OIBcm+kZLgj5xtYR+FbHvJpSdYjRbVh WHzQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779509703; x=1780114503; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=XJ9Wd6u4olIlHGlFZFpAmnHsxCYKujM9D/BFLc8A9dQ=; b=jAQrS2XRATOcOrLncDlR0e1K2UAEjfY0WXmWC9FN49Fcs3RY5ld8kjDjtIQZrT1P2r Ij1k2A2ag1aeJbejHSXUIDIbEb/9HtmLt4AY7lGjFo+vQVtznvtZL0Kt+LJyizEZ0h0q Z4E9+G9T37yNEUnQA9HFw6jOYQmrBY80x9//AcJqN6K/fKpR8Ely5jOpJZCbZ2PhdBkd cH4UpRqKMfWw5c5n8XDALDc3lPVofDWveIrWp9gTrvgdwzGnqKf1KfM/McfrDItRfyK9 xW4u0orRlyab2lnJxmX87Sh+sJWAdiNU5TUS6xoJWJCv+hlVbwPTWmG9aryzYou5nU0l hA7w== X-Forwarded-Encrypted: i=1; AFNElJ9egrph7dF6Q4vQZQNHWvxHl5HsTaN7YK88l8IZaUNkeJVUFy90276RxDTX1Ayohrx6SIqlQgr2GOECh2s=@vger.kernel.org X-Gm-Message-State: AOJu0YxvwxJZ/62GF3fNMQqVyL2Pp9vOuncyJZa53dXDecPj9qhsRdYP P4ZkC65vOq1MYH+YzU2hm5QohuRvGFidVH6HkilDYEw8o7ptRyKCG+3v X-Gm-Gg: Acq92OGsSi0gtHP+kGy1nX9QyHVtBW0Re2NVI7Jr8BruzPjfKzoFEWdIMsr4I73ZmEe RnKsvo1hJLFnIlxo+wm4Pv5m94giDMEU4azMpBz+cq46/pxnS5CxPPieY1Tnro+huppO1FAsGuq tp2Tp9IJjR8nManTLilmRizShRimanN9Oy1EV1RBU2zN2Aas6MRodwkStV49m+C5JRq0sSZ7GUJ s07c+4P+jmC7Wwo9RTNL02zcp5bpuJlqAc4hBZ8hMWQ5jGP/zeLo/iibk85zFompdZHNAJxN365 YOV+8iyv2UgYlZHsC0FFskO+3KOusmEMMMrEINiONgf5F7DfCBquVEnUJsjJevL1HsSo7fD89ry bQykuBufmPNYk19w5H9Q+XXHBLpatvZSCOw6lFYQJWyeuAOWHLHhIVbVg2J7pKVbX5s9CmMJt9+ YpmmtdwSY4I9EV6jX4RURRt+MyKe2pcg== X-Received: by 2002:a17:903:2348:b0:2bd:a403:1d82 with SMTP id d9443c01a7336-2beb074fa6amr69071215ad.21.1779509703599; Fri, 22 May 2026 21:15:03 -0700 (PDT) Received: from hyunchul-PC02.lge.net ([27.122.242.71]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2beb591a277sm31887675ad.80.2026.05.22.21.15.01 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 22 May 2026 21:15:03 -0700 (PDT) From: Hyunchul Lee To: Namjae Jeon Cc: Hyunchul Lee , linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, woot000 Subject: [PATCH v2 2/4] ntfs: centalize $INDEX_ROOT header validation Date: Sat, 23 May 2026 13:14:21 +0900 Message-ID: <20260523041423.2726275-3-hyc.lee@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260523041423.2726275-1-hyc.lee@gmail.com> References: <20260523041423.2726275-1-hyc.lee@gmail.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 Content-Type: text/plain; charset="utf-8" Add a dedicated helper to perform stricter validation of $INDEX_ROOT and use it for both directory inodes and named index inodes. This keeps the root size and header geometry checks consistent across both read paths. Tested-by: woot000 Signed-off-by: Hyunchul Lee --- fs/ntfs/index.c | 18 ++++++++++++++++++ fs/ntfs/index.h | 3 +++ fs/ntfs/inode.c | 11 ++--------- 3 files changed, 23 insertions(+), 9 deletions(-) diff --git a/fs/ntfs/index.c b/fs/ntfs/index.c index 9713b082b03d..97c0e7d6a580 100644 --- a/fs/ntfs/index.c +++ b/fs/ntfs/index.c @@ -541,6 +541,24 @@ int ntfs_index_block_inconsistent(struct ntfs_volume *= vol, return 0; } =20 +int ntfs_index_root_inconsistent(struct ntfs_volume *vol, + const struct attr_record *a, + const struct index_root *ir, u64 inum) +{ + u32 value_length =3D le32_to_cpu(a->data.resident.value_length); + + if (value_length < offsetof(struct index_root, index)) { + ntfs_error(vol->sb, "$INDEX_ROOT in inode %llu is too small.", + (unsigned long long)inum); + return -EIO; + } + + return ntfs_index_header_inconsistent(vol, &ir->index, + value_length - + offsetof(struct index_root, index), + inum); +} + static struct index_root *ntfs_ir_lookup(struct ntfs_inode *ni, __le16 *na= me, u32 name_len, struct ntfs_attr_search_ctx **ctx) { diff --git a/fs/ntfs/index.h b/fs/ntfs/index.h index 3451ec8a1c4e..cad78568d8b3 100644 --- a/fs/ntfs/index.h +++ b/fs/ntfs/index.h @@ -89,6 +89,9 @@ struct ntfs_index_context { bool sync_write; }; =20 +int ntfs_index_root_inconsistent(struct ntfs_volume *vol, + const struct attr_record *a, + const struct index_root *ir, u64 inum); int ntfs_index_block_inconsistent(struct ntfs_volume *vol, const struct index_block *ib, u32 block_size, s64 vcn, u64 inum); diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c index 360bebd1ee3f..63ee7acff4fc 100644 --- a/fs/ntfs/inode.c +++ b/fs/ntfs/inode.c @@ -890,7 +890,6 @@ static int ntfs_read_locked_inode(struct inode *vi) */ if (S_ISDIR(vi->i_mode)) { struct index_root *ir; - u8 *ir_end, *index_end; =20 view_index_meta: /* It is a directory, find index root attribute. */ @@ -940,10 +939,7 @@ static int ntfs_read_locked_inode(struct inode *vi) } ir =3D (struct index_root *)((u8 *)a + le16_to_cpu(a->data.resident.value_offset)); - ir_end =3D (u8 *)ir + le32_to_cpu(a->data.resident.value_length); - index_end =3D (u8 *)&ir->index + - le32_to_cpu(ir->index.index_length); - if (index_end > ir_end) { + if (ntfs_index_root_inconsistent(ni->vol, a, ir, ni->mft_no)) { ntfs_error(vi->i_sb, "Directory index is corrupt."); goto unm_err_out; } @@ -1483,7 +1479,6 @@ static int ntfs_read_locked_index_inode(struct inode = *base_vi, struct inode *vi) struct attr_record *a; struct ntfs_attr_search_ctx *ctx; struct index_root *ir; - u8 *ir_end, *index_end; int err =3D 0; =20 ntfs_debug("Entering for i_ino 0x%llx.", ni->mft_no); @@ -1534,9 +1529,7 @@ static int ntfs_read_locked_index_inode(struct inode = *base_vi, struct inode *vi) } =20 ir =3D (struct index_root *)((u8 *)a + le16_to_cpu(a->data.resident.value= _offset)); - ir_end =3D (u8 *)ir + le32_to_cpu(a->data.resident.value_length); - index_end =3D (u8 *)&ir->index + le32_to_cpu(ir->index.index_length); - if (index_end > ir_end) { + if (ntfs_index_root_inconsistent(vol, a, ir, ni->mft_no)) { ntfs_error(vi->i_sb, "Index is corrupt."); goto unm_err_out; } --=20 2.43.0 From nobody Sun May 24 19:33:41 2026 Received: from mail-pl1-f170.google.com (mail-pl1-f170.google.com [209.85.214.170]) (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 B7E223126D6 for ; Sat, 23 May 2026 04:15:08 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.170 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779509710; cv=none; b=P8wzVGq6rWGqqQEqWYvZW3hTZQK3N8eTS0iAoRdy6B8y7O1zN0Xv7D3yCXI9FDGvW3gpv+mETZYvLuul4PesL9Uv1uTyxGyNPaNObEDVjcB7kAOshHpCfs7wFaO5l3wsdqVbuM223V07q1BMPyMZ13r0RttswXoNzWYo+R4R4/0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779509710; c=relaxed/simple; bh=46LqbPeXy4S6Qp+MoG6RKDX0X4N3JEhFCoWqH8N/us4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=jw2o76JhX3IazJBaNOBiiP5eJWpF54st1R1bKvvtZyMJcqEu+goFYRlXz3oVzNLKSw6XJECNg5Q6EhiOH0sFZP+CKOBPEfFihGopkWasHhyqqq2bct/WMFsnEoQxtYDkHeAd4dBcDawOT02mWF1+7sJfidmONB2guQFJ2O+aemM= 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=dfQmN+Js; arc=none smtp.client-ip=209.85.214.170 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="dfQmN+Js" Received: by mail-pl1-f170.google.com with SMTP id d9443c01a7336-2be1dd4af34so66140295ad.1 for ; Fri, 22 May 2026 21:15:08 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1779509708; x=1780114508; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=GZMXkjoayFC0xSY7u2blD+NZCRaguu/ihPEWNfu9YdE=; b=dfQmN+Jsw2Dv+5gMwse9hzJKwDFZImFiArVZ234pmMDG5VUEs0rxHvRK1mgZtEkCsS jju0NrDqHegCzrq0VzvN18kL4uFRqOkjqfsv/w9fCO8pFF+QetPPoe7SoNf/1Gi76zqn +eeYohkGYRavlwvO63RZt7UNAsxpCwKm4IjfBwRwyJaPPLppOrdD42fgBzGQkO4IFkEi 3mt2lNXDcO8/gAGHxHZoduUyxf03w+/te6dHV98ox7Ol7tXH1FcMnEwK4pJbCcoxdGXm A7273Sa7WNoR0zDIiSqi1Rq07r6il30t2h1MaQLJFhH7Squ2m8SMrL9SuUspAkE67/Vj mehA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779509708; x=1780114508; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=GZMXkjoayFC0xSY7u2blD+NZCRaguu/ihPEWNfu9YdE=; b=LaBhb/VpSwpNAh4BMfKtsiwGlG03noftwaNP6SsZJ/xl3b8oMoJexNc3WXJ1CS5y0F FhF/cLN4NteRO3qAPgB/zJ9otfmgAv82JtEBcZblrT2czTKtmZop6Ahtn1J94akxNVmZ +fxMWg1n37V8EUQKrkisiESuxY8kq5+b7hiN70XVvhUnuEj51YOWTceg3KozdXp24EB8 KD3MfebTxSpFnnSE9vsmdmYf78sXJHsgTDkQY+6LOs8qBGUcEQhK8jAHhvUv9CVeuEK3 Vage1ZD55gX27TRVzmh4bQPHyiVHjAMszEYh7urIs6nprCbmCHcW67mBwGh1Nuq49COn 2QTA== X-Forwarded-Encrypted: i=1; AFNElJ9FHcoiswmhCHjtC92bR7kkVjzEBT8q/9kDp/I5M8bLl/E3Bhc4M/ByYIwyOmjTPL7/x4Ns2LMa6Y9BI04=@vger.kernel.org X-Gm-Message-State: AOJu0YzC6bI0IN905e70EyUoq9SDHzRFtKF/oYP6lKb63AoDWepU3M0w 6pKxqaHl/FBYoP0Xyv7opaSh4XPwgMAA4ly7vDPCvi8SYxbMzhY7JWTo X-Gm-Gg: Acq92OH45J26ywjzUGO9alnzqR9SphfanBLr8qXhawLxP0mgvryWU9umK9R9WmBDtEl OSgh77bOy3mOr6z0e0DQeDUYb8PBdf8sYzEm8NAY19s0IB+KGlP2Oz+5o4C97/bF854FZ/Hy29l c2r2r1TIuGvp2T1NTVn9JWWDwEmNKlFUA8SkJDqv+X8ACt+m9wKwL1ZBd1JWxKiTVU95UglXRH0 t3mKl0TQH6ZkoJcF1A0ACAtImkjVvmg3/847TuRnBzn/F0mvmv4yXiMrmR0P2jv9893JP6nCFiJ QIV9DxU8kTyeAcElg1jACYA7JHw37NNbnmr/YyuVr+lgTSv9thxJ6y5s2HUDaV3QNGJGo93Ds0w TKe7DFGPGAyafBBJiV9u0S52uU0g4FfYjMkh+cHrseW7OYlxIAA0KZaq0KWxmSl51ezQwNY/htn W/cJfrkgy3JFwd6LAlw/z3gJJiyXBGTw== X-Received: by 2002:a17:903:1b43:b0:2b7:abc0:3bd7 with SMTP id d9443c01a7336-2beb035b8edmr71165615ad.9.1779509707758; Fri, 22 May 2026 21:15:07 -0700 (PDT) Received: from hyunchul-PC02.lge.net ([27.122.242.71]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2beb591a277sm31887675ad.80.2026.05.22.21.15.05 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 22 May 2026 21:15:07 -0700 (PDT) From: Hyunchul Lee To: Namjae Jeon Cc: Hyunchul Lee , linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, woot000 Subject: [PATCH v2 3/4] ntfs: validate index entries on reading Date: Sat, 23 May 2026 13:14:22 +0900 Message-ID: <20260523041423.2726275-4-hyc.lee@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260523041423.2726275-1-hyc.lee@gmail.com> References: <20260523041423.2726275-1-hyc.lee@gmail.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 Content-Type: text/plain; charset="utf-8" Validate index entries immediately after reading an index root or index block from disk. This eliminates repeated checks in lookup and readdir, and reduce the risk of missing checks in those paths. Tested-by: woot000 Signed-off-by: Hyunchul Lee --- fs/ntfs/dir.c | 28 ++--------------- fs/ntfs/index.c | 84 +++++++++++++++++++++++++++---------------------- fs/ntfs/index.h | 8 +++-- fs/ntfs/inode.c | 8 +++-- 4 files changed, 60 insertions(+), 68 deletions(-) diff --git a/fs/ntfs/dir.c b/fs/ntfs/dir.c index 6745a0e6e3e7..4b6bd5f30c65 100644 --- a/fs/ntfs/dir.c +++ b/fs/ntfs/dir.c @@ -135,10 +135,6 @@ u64 ntfs_lookup_inode_by_name(struct ntfs_inode *dir_n= i, const __le16 *uname, /* Key length should not be zero if it is not last entry. */ if (!ie->key_length) goto dir_err_out; - /* Check the consistency of an index entry */ - if (ntfs_index_entry_inconsistent(NULL, vol, ie, COLLATION_FILE_NAME, - dir_ni->mft_no)) - goto dir_err_out; /* * We perform a case sensitive comparison and if that matches * we are done and return the mft reference of the inode (i.e. @@ -351,7 +347,8 @@ u64 ntfs_lookup_inode_by_name(struct ntfs_inode *dir_ni= , const __le16 *uname, } err =3D ntfs_index_block_inconsistent(vol, ia, dir_ni->itype.index.block_size, - vcn, dir_ni->mft_no); + vcn, COLLATION_FILE_NAME, + dir_ni->mft_no); if (err) goto unm_err_out; index_end =3D (u8 *)&ia->index + le32_to_cpu(ia->index.index_length); @@ -364,15 +361,6 @@ u64 ntfs_lookup_inode_by_name(struct ntfs_inode *dir_n= i, const __le16 *uname, * reach the last entry. */ for (;; ie =3D (struct index_entry *)((u8 *)ie + le16_to_cpu(ie->length))= ) { - /* Bounds checks. */ - if ((u8 *)ie < (u8 *)ia || - (u8 *)ie + sizeof(struct index_entry_header) > index_end || - (u8 *)ie + sizeof(struct index_entry_header) + le16_to_cpu(ie->key_l= ength) > - index_end || (u8 *)ie + le16_to_cpu(ie->length) > index_end) { - ntfs_error(sb, "Index entry out of bounds in directory inode 0x%llx.", - dir_ni->mft_no); - goto unm_err_out; - } /* * The last entry cannot contain a name. It can however contain * a pointer to a child node in the B+tree so we just break out. @@ -382,10 +370,6 @@ u64 ntfs_lookup_inode_by_name(struct ntfs_inode *dir_n= i, const __le16 *uname, /* Key length should not be zero if it is not last entry. */ if (!ie->key_length) goto unm_err_out; - /* Check the consistency of an index entry */ - if (ntfs_index_entry_inconsistent(NULL, vol, ie, COLLATION_FILE_NAME, - dir_ni->mft_no)) - goto unm_err_out; /* * We perform a case sensitive comparison and if that matches * we are done and return the mft reference of the inode (i.e. @@ -868,6 +852,7 @@ static int ntfs_readdir(struct file *file, struct dir_c= ontext *actor) ictx->vcn_size_bits =3D vol->cluster_size_bits; else ictx->vcn_size_bits =3D NTFS_BLOCK_SIZE_BITS; + ictx->cr =3D ir->collation_rule; =20 /* The first index entry. */ next =3D (struct index_entry *)((u8 *)&ir->index + @@ -905,13 +890,6 @@ static int ntfs_readdir(struct file *file, struct dir_= context *actor) if (!next) break; nextdir: - /* Check the consistency of an index entry */ - if (ntfs_index_entry_inconsistent(ictx, vol, next, COLLATION_FILE_NAME, - ndir->mft_no)) { - err =3D -EIO; - goto out; - } - if (ie_pos < actor->pos) { ie_pos +=3D le16_to_cpu(next->length); continue; diff --git a/fs/ntfs/index.c b/fs/ntfs/index.c index 97c0e7d6a580..00e17637f771 100644 --- a/fs/ntfs/index.c +++ b/fs/ntfs/index.c @@ -28,41 +28,10 @@ * length must have been checked beforehand to not overflow from the * index record. */ -int ntfs_index_entry_inconsistent(struct ntfs_index_context *icx, - struct ntfs_volume *vol, const struct index_entry *ie, - __le32 collation_rule, u64 inum) +static int ntfs_index_entry_inconsistent(const struct ntfs_volume *vol, + const struct index_entry *ie, + __le32 collation_rule, u64 inum) { - if (icx) { - struct index_header *ih; - u8 *ie_start, *ie_end; - - if (icx->is_in_root) - ih =3D &icx->ir->index; - else - ih =3D &icx->ib->index; - - if ((le32_to_cpu(ih->index_length) > le32_to_cpu(ih->allocated_size)) || - (le32_to_cpu(ih->index_length) > icx->block_size)) { - ntfs_error(vol->sb, "%s Index entry(0x%p)'s length is too big.", - icx->is_in_root ? "Index root" : "Index block", - (u8 *)icx->entry); - return -EINVAL; - } - - ie_start =3D (u8 *)ih + le32_to_cpu(ih->entries_offset); - ie_end =3D (u8 *)ih + le32_to_cpu(ih->index_length); - - if (ie_start > (u8 *)ie || - ie_end <=3D (u8 *)ie + le16_to_cpu(ie->length) || - le16_to_cpu(ie->length) > le32_to_cpu(ih->allocated_size) || - le16_to_cpu(ie->length) > icx->block_size) { - ntfs_error(vol->sb, "Index entry(0x%p) is out of range from %s", - (u8 *)icx->entry, - icx->is_in_root ? "index root" : "index block"); - return -EIO; - } - } - if (ie->key_length && ((le16_to_cpu(ie->key_length) + offsetof(struct index_entry, key)) > le16_to_cpu(ie->length))) { @@ -352,6 +321,44 @@ static int ntfs_index_header_inconsistent(struct ntfs_= volume *vol, return 0; } =20 +int ntfs_index_entries_inconsistent(const struct ntfs_volume *vol, + const struct index_header *ih, + __le32 collation_rule, u64 inum) +{ + struct index_entry *ie; + u8 *index_end =3D (u8 *)ih + le32_to_cpu(ih->index_length); + + for (ie =3D ntfs_ie_get_first((struct index_header *)ih); + ; ie =3D ntfs_ie_get_next(ie)) { + if ((u8 *)ie + sizeof(struct index_entry_header) > index_end || + (u8 *)ie + le16_to_cpu(ie->length) > index_end) { + ntfs_error(vol->sb, + "Index entry out of bounds in inode %llu.", + (unsigned long long)inum); + return -EIO; + } + + if (le16_to_cpu(ie->length) < sizeof(struct index_entry_header)) { + ntfs_error(vol->sb, + "Index etnry too small in inode %llu.", + inum); + return -EIO; + } + + if (ntfs_ie_end(ie)) + break; + + if (!ie->key_length) + return -EIO; + + if (ntfs_index_entry_inconsistent(vol, ie, + collation_rule, inum)) + return -EIO; + } + + return 0; +} + /* * Find the last entry in the index block */ @@ -503,7 +510,8 @@ static struct index_entry *ntfs_ie_dup_novcn(struct ind= ex_entry *ie) */ int ntfs_index_block_inconsistent(struct ntfs_volume *vol, const struct index_block *ib, - u32 block_size, s64 vcn, u64 inum) + u32 block_size, s64 vcn, __le32 cr, + u64 inum) { u32 ib_size =3D (unsigned int)le32_to_cpu(ib->index.allocated_size) + offsetof(struct index_block, index); @@ -537,7 +545,8 @@ int ntfs_index_block_inconsistent(struct ntfs_volume *v= ol, offsetof(struct index_block, index), inum)) return -EIO; - + if (ntfs_index_entries_inconsistent(vol, &ib->index, cr, inum)) + return -EIO; return 0; } =20 @@ -727,10 +736,9 @@ static int ntfs_ib_read(struct ntfs_index_context *icx= , s64 vcn, struct index_bl =20 post_read_mst_fixup((struct ntfs_record *)((u8 *)dst), icx->block_size); if (ntfs_index_block_inconsistent(icx->idx_ni->vol, dst, - icx->block_size, vcn, + icx->block_size, vcn, icx->cr, icx->idx_ni->mft_no)) return -EIO; - return 0; } =20 diff --git a/fs/ntfs/index.h b/fs/ntfs/index.h index cad78568d8b3..9a03f53bba47 100644 --- a/fs/ntfs/index.h +++ b/fs/ntfs/index.h @@ -94,9 +94,11 @@ int ntfs_index_root_inconsistent(struct ntfs_volume *vol, const struct index_root *ir, u64 inum); int ntfs_index_block_inconsistent(struct ntfs_volume *vol, const struct index_block *ib, - u32 block_size, s64 vcn, u64 inum); -int ntfs_index_entry_inconsistent(struct ntfs_index_context *icx, struct n= tfs_volume *vol, - const struct index_entry *ie, __le32 collation_rule, u64 inum); + u32 block_size, s64 vcn, + __le32 cr, u64 inum); +int ntfs_index_entries_inconsistent(const struct ntfs_volume *vol, + const struct index_header *ih, + __le32 collation_rule, u64 inum); struct ntfs_index_context *ntfs_index_ctx_get(struct ntfs_inode *ni, __le1= 6 *name, u32 name_len); void ntfs_index_ctx_put(struct ntfs_index_context *ictx); diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c index 63ee7acff4fc..9717fb5b4709 100644 --- a/fs/ntfs/inode.c +++ b/fs/ntfs/inode.c @@ -939,7 +939,9 @@ static int ntfs_read_locked_inode(struct inode *vi) } ir =3D (struct index_root *)((u8 *)a + le16_to_cpu(a->data.resident.value_offset)); - if (ntfs_index_root_inconsistent(ni->vol, a, ir, ni->mft_no)) { + if (ntfs_index_root_inconsistent(ni->vol, a, ir, ni->mft_no) || + ntfs_index_entries_inconsistent(ni->vol, &ir->index, + ir->collation_rule, ni->mft_no)) { ntfs_error(vi->i_sb, "Directory index is corrupt."); goto unm_err_out; } @@ -1529,7 +1531,9 @@ static int ntfs_read_locked_index_inode(struct inode = *base_vi, struct inode *vi) } =20 ir =3D (struct index_root *)((u8 *)a + le16_to_cpu(a->data.resident.value= _offset)); - if (ntfs_index_root_inconsistent(vol, a, ir, ni->mft_no)) { + if (ntfs_index_root_inconsistent(vol, a, ir, ni->mft_no) || + ntfs_index_entries_inconsistent(vol, &ir->index, + ir->collation_rule, ni->mft_no)) { ntfs_error(vi->i_sb, "Index is corrupt."); goto unm_err_out; } --=20 2.43.0 From nobody Sun May 24 19:33:41 2026 Received: from mail-pl1-f178.google.com (mail-pl1-f178.google.com [209.85.214.178]) (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 23DE53314D9 for ; Sat, 23 May 2026 04:15:13 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.178 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779509714; cv=none; b=IygME8fV1D7OUqm4FfpDOPl655OblJiX1L1Uhy+Q64/sssmJgSObLsWnVk4Wiqn2AJgdjqJoVaYEc0rZzZuIvzj6oEJ80bR9c8i44utDnJt7kSUDHYkkoEUGSCSLJsbS1R8zldziXreOM7ShAmb+TYl6F5CbLOm4tGwZ7BxpqL0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779509714; c=relaxed/simple; bh=HqQecYhKN0ZfkC1p2kK45n+IQIFHeJl+F6L3+ooWb3c=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=YFjK+d8EWkra8qMkcMBMHaCeBjryIfBn8Z+iLPteV4VKOPg6Bwmo4ysieXSFkpY8c6USlxQITulDutNwziDy3jS1rWucM6f84vfIrwvKjjbjofO7+Ylngaib4lE70PwqDuA52HaJzR44X12mHod9fG1OOG9odSPJ7cOUY1W+4ok= 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=HX0ZF9E5; arc=none smtp.client-ip=209.85.214.178 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="HX0ZF9E5" Received: by mail-pl1-f178.google.com with SMTP id d9443c01a7336-2ba21d32776so58738725ad.2 for ; Fri, 22 May 2026 21:15:12 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1779509712; x=1780114512; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=WhzaN7BWimOMiqEoiQNjGpOIY4nGflNoP3vjImK4R3g=; b=HX0ZF9E53nSCx4qMVhBocRYY5tL9aJkW2QzveuNxJgl7B0i5Odrwwc1lGrAXDlwv9C ZyiF3XJaslnjSsyb+SUPj2rJ4n9CNqkB8zs2AP7EGqPHRPGJ25+DpPuftn2kmW7ndRmv I7ATIqFDSutUdHJ2ntswnqtDVYkgFILyCwU/akprtQ1khnT3siidbW78obBrDPSQb5mF J6jBm/UoHz9dQFzKyUMvq+4v14xBnXatm5nV8H0bMYQFqs11gkYzKTPVAElnlp29Xji2 yAC8vORLXBA5xBSPg9C/9HJm2NpIuxHz+DWvdP1O8RP5SuzxiBILJO/2QmR6LQecKWG6 1ZqQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779509712; x=1780114512; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=WhzaN7BWimOMiqEoiQNjGpOIY4nGflNoP3vjImK4R3g=; b=mdn/S7WttJZHAExKMMQSO5CQze3NPbozsZOoYgo0hazQtWp7VtoumqNUO7LUKcyNyu 7xXq4dfLY1uvQqS9l+QBgExi2//UK8hTtRqgn9s0B7Ziy32nuM4S2SlfcilHEObQCMnr xoigah5ExfO3O84pwiNzUnflSLTL1yB+Wmvt02SS4ZifvcSuncCBSWcaATe6f1FkxIow 2deZdK8zlf/GPhU/fl9EdUn5DSAHEeI/z4b+3jgI2hbJqgdVjy4AekqQ4EF4n5EnNG50 2np3jTjnA+Nxs6VFd1cDCiDtIWfb8MIPHC8ubstFCDkzTvtyJP8Fe3v2eC4/ZOgUEa4I t8nQ== X-Forwarded-Encrypted: i=1; AFNElJ9InX+BJ++VJkA9R1pGoE4hrDImPdpn7oS7icqE8zaUTPIjedpZI7KDnjusQtcGie4EZhco9tHdmlYT+/E=@vger.kernel.org X-Gm-Message-State: AOJu0Yw7dTIyWAxni7SETihe56Efuaoul+6Eruum6jzH9sjk+pUJ6QOd u5Hy94My+kgy7y/2erzTbJp1Y2xGJUZKJz9iQ4mr8jE2dpEPv7WS3sq1 X-Gm-Gg: Acq92OHC+Yjr4mapg1fMDDHQ6uSxe1oiPGlaD0vKVQuBftqFuM76LO93+Gs4m98ge5h zSmknQ9IjGF948d6b758QCzDs40CB6CJxSKmcqgF2b6igHbNKxz/+xs7pabnGHncPJTZwpjylvu rET9jp3cOzS8/6uGWXbMPpyiwuwDM5kCekC4Yo0eGMTlKSA+EGwEBD0rg8OVoYcWXULTI07Dral rgSuj4QI7vjlYiE4VfGpxtBsS5QDHeRRaKkY7ZohMQjflCoz3QH5ohw/AJ+BMmsa5+i7It0wPmd wobUqGcbqOm3cfgqphQJNA7P5T71s8Q6DseKYbmOmSNRyg+80Xv0EWZ8BWF9ahJ2hsZVBBNwycP E7zqR1lG9n9IwlAtTFKWqnVfOSAcq1i3s0wM1f9I00mYq/fRQVPaBdDuZbVsf7ud9z1TN3J8a6X o+0GfaB9q4Km3hqwzUqjREs8XGF83QlQ== X-Received: by 2002:a17:902:e88e:b0:2ba:839e:15cb with SMTP id d9443c01a7336-2beb05e306fmr70544575ad.27.1779509712129; Fri, 22 May 2026 21:15:12 -0700 (PDT) Received: from hyunchul-PC02.lge.net ([27.122.242.71]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2beb591a277sm31887675ad.80.2026.05.22.21.15.10 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 22 May 2026 21:15:11 -0700 (PDT) From: Hyunchul Lee To: Namjae Jeon Cc: Hyunchul Lee , linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v2 4/4] ntfs: add bounds check before accessing EA entries Date: Sat, 23 May 2026 13:14:23 +0900 Message-ID: <20260523041423.2726275-5-hyc.lee@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260523041423.2726275-1-hyc.lee@gmail.com> References: <20260523041423.2726275-1-hyc.lee@gmail.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 Content-Type: text/plain; charset="utf-8" in ntfs_ea_lookup and ntfs_listxattr, this verifies that there is enough space in the EA entry before accessing the next_entry_offset field of the EA entry. Signed-off-by: Hyunchul Lee --- fs/ntfs/ea.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/fs/ntfs/ea.c b/fs/ntfs/ea.c index c4a4a3e3e599..0cd192752b7c 100644 --- a/fs/ntfs/ea.c +++ b/fs/ntfs/ea.c @@ -53,11 +53,11 @@ static int ntfs_ea_lookup(char *ea_buf, s64 ea_buf_size= , const char *name, loff_t offset, p_ea_size; unsigned int next; =20 - if (ea_buf_size < sizeof(struct ea_attr)) - goto out; - offset =3D 0; do { + if (ea_buf_size - offset < sizeof(struct ea_attr)) + break; + p_ea =3D (const struct ea_attr *)&ea_buf[offset]; next =3D le32_to_cpu(p_ea->next_entry_offset); p_ea_size =3D next ? next : (ea_buf_size - offset); @@ -479,13 +479,13 @@ ssize_t ntfs_listxattr(struct dentry *dentry, char *b= uffer, size_t size) if (ea_info_qsize > ea_buf_size || ea_info_qsize =3D=3D 0) goto out; =20 - if (ea_info_qsize < sizeof(struct ea_attr)) { - err =3D -EIO; - goto out; - } - offset =3D 0; do { + if (ea_info_qsize - offset < sizeof(struct ea_attr)) { + err =3D -EIO; + goto out; + } + p_ea =3D (const struct ea_attr *)&ea_buf[offset]; next =3D le32_to_cpu(p_ea->next_entry_offset); ea_size =3D next ? next : (ea_info_qsize - offset); --=20 2.43.0