From nobody Sun May 24 19:34:48 2026 Received: from mail-pf1-f176.google.com (mail-pf1-f176.google.com [209.85.210.176]) (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 D39192264A8 for ; Fri, 22 May 2026 00:48:08 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.176 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779410890; cv=none; b=U0T9pPAvHaGUVWRpPMUso9tTUBtlenDWfp5oWDzdzS30eB29DB5m6Urci8s0rWovEl+z+puvgXxokG3qnLDFIde0ByyZOo7hidqHtCLUgrLY/BjqsHmEqD/Y+yb4jkCnnUyYM/P5VwIH2E0LwlCVxMh0TAPKph0cB7XZvQVynPQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779410890; c=relaxed/simple; bh=AWj7qAqmhbK41yk+phxzm2L/KqvZXbL15LYla5B3NZs=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=VKsTox240eAjhsqCOQ0Jo1prG9yRzc0hpCmKCyW/J6ILdE9mawwg+2PrVZ6X+M1YVoZ6EVnjMRkEU/l7/6UPyInKC99niE2zATaf1VLiFGRb7hw9HM4ak6hEjn9foJChsXcQpRNq3/LOfgFFxsAAFmHe7hJ/rQFBK6VcobMlaW8= 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=SZGXc2bs; arc=none smtp.client-ip=209.85.210.176 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="SZGXc2bs" Received: by mail-pf1-f176.google.com with SMTP id d2e1a72fcca58-835399c11e0so3112351b3a.0 for ; Thu, 21 May 2026 17:48:08 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1779410888; x=1780015688; 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=LBOwiFRsNBVa0NQLLrIYAw0qxWG+4YcJNT8Zjbdg13U=; b=SZGXc2bsPUOEjDOPobem+5NeLq/sTDk5Y8ZZtwBvxLFFWFuYKzTAZ83G5sZbSVrFeC wf+RENAM0MKC7qjK5z65nrL6Xm5BEPERvVF+95OTysNM+TSHbNw3eaNGUAv0VeRD3x7A 37NAMZFbftLRCeKSZYl1B443sanyQxSrkfw752ndUh+pDV92PoIo5Qulk1UD+Ghsaptv ye7tvX/Pzv6VzilzLk8RzOyS9khC83ndB6UU+4Mb2IbZOWbzGNMOZvClX/k3IIQm3+Sm sYoYYKjfvbmrKFLHBDIgNsZOLIVEQSM0XNbC1fAgSPlE0t5fJRo+/gIDnKsWRlrVNEU7 h0Vg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779410888; x=1780015688; 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=LBOwiFRsNBVa0NQLLrIYAw0qxWG+4YcJNT8Zjbdg13U=; b=sJHdxSsT+IEEtfJkT7rDoJQy55RTwRR1K32VI2QPNxoDVucaTYJ60Po5QY9BnNSkrc Tn3foXym/jhDMFQs88apgT8pq5BV7kcz4iVbd7hQ8HWI21bonLNHp24HDR8+6X2XTK6j Mb7j6nbqRXdVs3WU3y/swR+TBLITTC1xcd9Gcttgu36XECE5e9YG92XurPNdDXcGocyS yqSrb4nP52MS31ToYpGu9mOU/kKYM6iL4BqNjE8zVFKXusAseptZpH4l87zIklgRQY5Z au9OYZP28XrE1vpJT6KzW6bcDA0RL9sTB2+ji6Dn0wR4Vdf/WHTYdPcBDYC5OIN4JVRi ukSQ== X-Forwarded-Encrypted: i=1; AFNElJ96xsSPFEM7akFPTfzVJAZy0UoDCP1+8XcRw7AvAl0+/FjgyMUIml2CUiqJ1BWWkLSR37yTfxxfzih5gsg=@vger.kernel.org X-Gm-Message-State: AOJu0YxBrkG32IzW2EBBQcJpDYfQNC/j8BJZy3pHyPys9hGmvZ6FGqt5 eZvESWNihGGY3ykH4upviIDkRfC13/sPRlNG9xrXcLOgHrvriDQgZ7Rl X-Gm-Gg: Acq92OEkhERQqL1lMjKxHZmC0/+5yTA9sywCL6FZn8ykxvNPcL/Sup64Cra9QoQyJ1F l91c5UZxXLOrJuAPkKZp3709QyV8aFnwBFJKwppSenXrtKLVVtcCkFinHEz9Z4EZm30UYSgivCh lU2sUeJZuh67n7kfYTFs5ShO8Y0wWjwOsILcPwqEMPOg9Gduzj7C0kaAv3GqSGEN2Nfxqw2T4sB DcEAStUVz5WDPOCfLF/pqSWfKTExSwYD74Cc2d9JARqCgNWTb4+vmBSqkZ5A4Wdjla+MyGmlf0O bMYbC2fCtxc5iaa3gNABdzrbphk6RRcl+sO301lAZCrHMuLVPNGxWl9wtLUiUQxeTdjfuHswfHe 7cVAPN3ZhKbav4B2cd64HVgVUlIKkEYPz+GBe70ImlmFq7H2MTSvRZcxrFeT4K4m7xOBiU7+chX iRu/rlNY4NgeQxlUIH740OsoVrJnwBQGSBbvrTfJhe X-Received: by 2002:a05:6a00:2d25:b0:835:3f51:72fb with SMTP id d2e1a72fcca58-8415f5aef23mr1397447b3a.12.1779410887939; Thu, 21 May 2026 17:48:07 -0700 (PDT) Received: from hyunchul-PC02.lge.net ([27.122.242.71]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-84164ac99b0sm78484b3a.4.2026.05.21.17.48.05 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 21 May 2026 17:48:06 -0700 (PDT) From: Hyunchul Lee To: Namjae Jeon Cc: Hyunchul Lee , linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH 1/4] ntfs: validate index block header more strictly Date: Fri, 22 May 2026 09:47:44 +0900 Message-ID: <20260522-t-fix-oob-v2-v1-1-0bea6582a361@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260522-t-fix-oob-v2-v1-0-0bea6582a361@gmail.com> References: <20260522-t-fix-oob-v2-v1-0-0bea6582a361@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" X-Mailer: b4 0.13.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=7776; i=hyc.lee@gmail.com; h=from:subject:message-id; bh=AWj7qAqmhbK41yk+phxzm2L/KqvZXbL15LYla5B3NZs=; b=owEBbQKS/ZANAwAKATTyMPr3jkjTAcsmYgBqD6Z9ltmOkpOyJgZEyWHq2Qb28Iz/tN4ByeZ6V IYG1b9xkL+JAjMEAAEKAB0WIQTVhSnMU3bjbW4eb2I08jD6945I0wUCag+mfQAKCRA08jD6945I 0/1zD/98kLRKtSgKKu9FOehgC0fkYnexjRJBSwJh0Tc3/7G+2oCstvaH0oWFeg78EIIV2ZkysjZ 5VYzfUo9aj8LvxF02PWNFA5nhWs12KSdmgTnxTYPTXViphVsEu5NX7sJLmdTpUZO6cjpZLJM0eJ 7JAwb8KWiV///nF9eo8afct1Q1vN9NeTDGnP2qm7MdMooBbGAttnOs+NtaUlyLF4jT2z+TJeYyl pjUuQW+Ga9TykBRpQ4ETvvuXJEGX+SYbx6eohtK2WqBROSyNsS5u8JLO73Wa2AsX/h5VHHcjP29 Lx0EZjkRcgEzKmQXXY5I6sqhj9HNxjsuG7v6pVKSlhgI2R1Vo0t3/twZ933FTwscbM2YPD6Fzkc sWMeF5/cj9ZaR4dqyC7R3FLQSuTRZ6qta9+KX+PZNhjqFcMlyMV0Rn8YE2TybpQ1XKUi/ybPOWY oUu0s5FP0PISZVfi5CwE6FbR4yrSKDQsjT3cbieVspGXgPE96xLi6DZ21GBNugOCrJv6AJEviRp IFVyNDZX+iMk8y/eT9B+0pAWaawr5vmeRyyAHlQZCII1wuy2Ue43NePucpgGbEe10N4gqzKSnLu DNwk0mjNhEYUuxe884UmUICs2DqstCkvCwhlUxzdq9AkhomyWIEJFQxcE4aa/IwAeBLutXa+nQw Q7kfmY6Z/HBX2EA== X-Developer-Key: i=hyc.lee@gmail.com; a=openpgp; fpr=D58529CC5376E36D6E1E6F6234F230FAF78E48D3 Content-Transfer-Encoding: quoted-printable 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. Signed-off-by: Hyunchul Lee --- fs/ntfs/dir.c | 38 +++++--------------------- fs/ntfs/index.c | 85 +++++++++++++++++++++++++++++++++++++++++------------= ---- fs/ntfs/index.h | 3 ++ 3 files changed, 72 insertions(+), 54 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..c203a5ad47b6 100644 --- a/fs/ntfs/index.c +++ b/fs/ntfs/index.c @@ -303,6 +303,53 @@ 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 =3D le32_to_cpu(ih->entries_offset); + u32 index_length =3D le32_to_cpu(ih->index_length); + u32 allocated_size =3D le32_to_cpu(ih->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; + } + + 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 */ @@ -452,20 +499,19 @@ 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); + vcn, (unsigned long long)inum); return -1; } =20 @@ -477,27 +523,18 @@ static int ntfs_index_block_inconsistent(struct ntfs_= index_context *icx, return -1; } =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); + "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 -1; } =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); + if (ntfs_index_header_inconsistent(vol, &ib->index, + block_size - + offsetof(struct index_block, index), + 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; - } =20 return 0; } @@ -669,7 +706,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, dst, vcn)) + if (ntfs_index_block_inconsistent(icx->idx_ni->vol, dst, + icx->block_size, vcn, + icx->idx_ni->mft_no)) return -1; =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:34:48 2026 Received: from mail-pf1-f176.google.com (mail-pf1-f176.google.com [209.85.210.176]) (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 4BC9C25B0A4 for ; Fri, 22 May 2026 00:48:22 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.176 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779410903; cv=none; b=Ar0tXS17W3EDLF9i+qIRXb6YEQkVzQFZ66W6U1FUQ4q/q6C02NQA8t9Z6mPOG1c1E59RMkyxezOuKbO0fcP0Kr0dfxTmOWvw2U16b+0i9SdcXLrW5NIpZGcmuGg8J9WP2knntWTWokBGUjN8NnBvG+UTOVVkahUohr75hyRqBlk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779410903; c=relaxed/simple; bh=5Xs+CX5lLKoEHUMPSPmQPu5YJB7zvPSf/xuEQmphgTo=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=ZQQtiNvzhGTFcr2UhkSbLkDqkPEuxuV5iyFKxOsrhf8riTKSzezUmNj0PCaLswgKf1tUNL9OsNjplwmtKRlB7+cc/5Yru/caO0wb7Ejo7fD9c4g3oCDlP06ifZleSdj8eYWUIOPk50O8/qwJdoKmk2yap09d3dv6pfuhH9RlvcE= 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=fhzocWNY; arc=none smtp.client-ip=209.85.210.176 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="fhzocWNY" Received: by mail-pf1-f176.google.com with SMTP id d2e1a72fcca58-8413ac3d82fso1913311b3a.0 for ; Thu, 21 May 2026 17:48:22 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1779410901; x=1780015701; 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=hKq9lV/G7NzgSQyheH8/bgGyRcC1BkjmeWEjYZwko3I=; b=fhzocWNYiVszPs7CJqWw+4gHJnCopTtUSkyUq0P7v+96EWsDMCOS/abQyUWP7vDIBL VIGCkrUB5+imE5j0EekvIcd8Trbk3NwSrvBulq/NOZ/iM+zo1qam3kVAaFpjwfYSOi8K VVmJWkqjwxXSbucY+26CB/WX3Y+Nti4uGwnpNWZHERGmNN9SDVFEPUsZaED2/cKZ0T3z L3nDjXIDoyJkxgBsOMHHbYj7UadbDl064NCxnAbzcz7OU2QpWp35zKtYW2Xn2ihSI6xk bKhTfbIR/zRCA/RmpaCjFhp+vva7uDUsp4uMEhUwX4ZBge6ZJGI0CUNIoibK8U0WJHFN 1doA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779410901; x=1780015701; 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=hKq9lV/G7NzgSQyheH8/bgGyRcC1BkjmeWEjYZwko3I=; b=ebZCUJcQg9C2/ul2hgjFUA+n+PCtwlZargAPiBE+6B7+nOxgejFVsuwFRDXwp1nZMz vmPhMqiO+dPdfP8PO2N3b3mcH6bZis4bBEXnv/5tgyMRYtahQDS3PHtxpWnopyqCNY1E SsRYvTp0Dhl9ABcfnHSV1WZi2oW0oQ/SKcvIJqbxYGS4aMWbjCQ7dw3Kbu/I14jUU5vR UFqcPVgNSIBMtuNA5na7clQUNyi3jndfAo+xbi2xZ4FKKxMlRPE5fNrZ11sAgkFiy0my 8x518j9cvtJgGf6ukYeJPdzgQIkMzsuiV+1ZdaGXyzIuN3Ou421W8xALkzuhJGoC2lad GgPg== X-Forwarded-Encrypted: i=1; AFNElJ+d+WKoJzPtJQW7VUw4di6FY2jputum0gPfVuZAB9SPsp+Ej2dfoHCdbLUXn+qJVwLOowJROiXRDnu+jHk=@vger.kernel.org X-Gm-Message-State: AOJu0YwFWErllFTuWnCpbTWVljE5Vv4Ebrod5lyOcgbZamSkxz7+ejnI Q9IaL3PBMG4hCZcqLMxFhAHMIPm9sl2BCK0Ijony9H5yNNPQef5L9IkyTEv4Ag== X-Gm-Gg: Acq92OHKMcisrZYKUlgrT/v3D2VQJGPUm8OEM+GDPQGY+w/FeDfzTKAFIsaMrWuTFCG C1XgK8CDTTbPIGJa0NXpcQElGgP3MAGFY41x2KevazlWc/+mXa/p43g0E2Y/4muY2+1PZSW5pKh IJ3bIzA7CpizLkIagpXFwHO+PzuZ4/6eLNYOrpButPExUQH+Q7rLUI8+ZvpHe44YjUHgcNvcKWa +0Y5SPgs4lObdEuoldowE91jML8w3FMneYZMRUmju1t9e+SOVSOHR8Ur9sW8rBXs8iIdRpZCBPs W6dCJGJAATNEIL3hOtIW9r24D90O3gZgY0TMYrye9/15n0Pg6HVL1BJzJ2B+H9S35hl3jPPmSVO 3+preEZS/gjoiFvXCG28yCG2xKSsrJBeh4mmB53W66kjv8551gYdOpwtI82GNZzW8p88JHoAIuc iKUeAON0GBB9PCUV98kUKAAZ5JEsQ3mYeC1OXgFl1F X-Received: by 2002:a05:6a00:f95:b0:82c:dfea:9e2a with SMTP id d2e1a72fcca58-8415f0f02d6mr1538639b3a.2.1779410901547; Thu, 21 May 2026 17:48:21 -0700 (PDT) Received: from hyunchul-PC02.lge.net ([27.122.242.71]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-84164ac99b0sm78484b3a.4.2026.05.21.17.48.19 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 21 May 2026 17:48:20 -0700 (PDT) From: Hyunchul Lee To: Namjae Jeon Cc: Hyunchul Lee , linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH 2/4] ntfs: centalize $INDEX_ROOT header validation Date: Fri, 22 May 2026 09:47:45 +0900 Message-ID: <20260522-t-fix-oob-v2-v1-2-0bea6582a361@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260522-t-fix-oob-v2-v1-0-0bea6582a361@gmail.com> References: <20260522-t-fix-oob-v2-v1-0-0bea6582a361@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" X-Mailer: b4 0.13.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=3560; i=hyc.lee@gmail.com; h=from:subject:message-id; bh=5Xs+CX5lLKoEHUMPSPmQPu5YJB7zvPSf/xuEQmphgTo=; b=owEBbQKS/ZANAwAKATTyMPr3jkjTAcsmYgBqD6Z9O4ltOV9eAaDf2wkRmLfLYyTGxMD0/dERE bp2COK1gBOJAjMEAAEKAB0WIQTVhSnMU3bjbW4eb2I08jD6945I0wUCag+mfQAKCRA08jD6945I 03soEADEufoIfYsv9rPrXePjHYzfQOMkdxD6CvOd+d2rPoKOe3BDgYiXpHFKoUiFFM8SyyJ7u8S JFIrJ974ULrCdOODLr9zHPZsv/bQOFXcGomwbt21TMs2o9ajzoij0SXWLL3MzwcQ2FZcbsn0dwZ 7fPcp6pEpMFFKOOHNnaM7t1HWocRhb7cMdav9JsXEgRKF5+e7TX75JBSxaek1BcMHs3FyGUfpRY ps0wBDF+N5nX972KRePa9+naoAD1neLDfEOmrvw21cnmhORwTWAMfolXhWGaMxMMABuW/CMELX2 zrRdyQ1wE9U/DGHnZGr0HPXRb1aDI3qH6bY+3G+5Ojt8OpYimH2jiTHu7DR/ljh02P76nl/WPFr XmVFDLo68eHEjidnvYmE+dFNfn1ESrtfMFgFVkh5Yc7LA616UZD9QS+om4+8uUaVr4tBR6a6QWp 2iOzcN82qNEwyRNDWBPM0xoE/bc5z9Ny7X+zme4A281sBOPBGOl3GcjD0oX3S25C7PSEWYa0VcS JiGHvejecHKXgXiMtPnxJ+UZrTkODey+ZpfNmVS9/lOv+q0nyTc0zkGWsW7/6MhNMkJlVWrrL3Y 7K/hIuQYcFsBOnXo7XMSfXmoYxvh4C953KRXujSuOgq2gNPAbp7hw3nNx0/13ng7jalhwvlZGS4 vYPnvrHChX7sf+A== X-Developer-Key: i=hyc.lee@gmail.com; a=openpgp; fpr=D58529CC5376E36D6E1E6F6234F230FAF78E48D3 Content-Transfer-Encoding: quoted-printable 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. 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 c203a5ad47b6..91fcaa79f8ac 100644 --- a/fs/ntfs/index.c +++ b/fs/ntfs/index.c @@ -539,6 +539,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:34:48 2026 Received: from mail-pf1-f173.google.com (mail-pf1-f173.google.com [209.85.210.173]) (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 90BD52405E1 for ; Fri, 22 May 2026 00:48:27 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.173 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779410909; cv=none; b=iXl7ZkdKI57nYOHp2cSN+2gFdDXJ+I6AL2L1msc76foMl5Qh9mbNzxkVtgkb2kx/eQ+7AieUxBRSXyLY9p6qTlNYl99gpbzInzAaQfGov4LcKMLQea1jt9Dm/XRQejkSPOjGE+gSGGkvgCWNe1XTP7tbYfNrpGOdFgVwaiIlTPU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779410909; c=relaxed/simple; bh=dcCWOB4BeVqjZPJUd0+HQG4oF8oQzhW58FogfZUawoQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=VYYt+kRy8L66zOvHv0PTZcquAQzAtnUr9XhdPTpboWPVoM+CnjaTV6OIoSnFB2iWcGCmS8R37x91KfJi2dRfypuHKvo+dbIhg7mdlpG2yARz5Yf8y8+//IPYIwYALQtdHdTt1MyH6Q6UF+c8bfqpaXb74xkLRFWk0YkpyVfQajs= 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=LipX0gyM; arc=none smtp.client-ip=209.85.210.173 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="LipX0gyM" Received: by mail-pf1-f173.google.com with SMTP id d2e1a72fcca58-8353ca0f1f1so2955190b3a.1 for ; Thu, 21 May 2026 17:48:27 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1779410907; x=1780015707; 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=JVlt00jdkrtb4Wx5jimUgpYV6iF7+tQ5Xz5hxOJ/pOI=; b=LipX0gyM60UDhofice6nRfpierbaf5iX0oAaT8+sN1khgpvzSYb2JjX/FzczOs+ni6 ShjtqVP5jBweLSekEun+hG3JdwNhuMxP6Mz7uE/oyNSzlLJywzkyGSJdb6MmN7nogfrf /q7jPAtFR0cR1/mB7OAlVhLAiQ7zH9gqMxcUelMOrtSXfuM0X/Sfd4XsMuA9FlexvgS+ eSO6cvijA+aRmw9N48L5lOv+AIXsqbxjbNic7YjHvOyRlgmSG/XmDbivEgF2uo2fGU2V IcMPfLlOhATodvUM7P2cf54Auwu/S/Ndbt3Io5c6BL5tmGffVINGJAtVyUCaey5Vo1F3 Uvxg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779410907; x=1780015707; 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=JVlt00jdkrtb4Wx5jimUgpYV6iF7+tQ5Xz5hxOJ/pOI=; b=TioFrpC/oLJZJTb6RlxEywcFTZbIcD5MFdU23GJ1ynuxjkCI9IoEANh3vyOvdrU055 bAWGA8f2Rs1iI+EoVY3adWcCXBw/HoQMAlEk4HbjvnaCXQl3w3eWthAq5G5UUUEFnczX GUiVNQwjg3HPGK3lFg5kTub7S1LkPcz3F6R3iK+3LCuTg6RNu7iPank0guBF9G5Q3zKL MMDuA2LRaJ+ZavgNnsezJKgt1ZlcSL4U4pNbufX8ZZ2Z5Ki8iE4Sru52qpk8UkGXUVj2 L5SzJxc/bi9/htKY5NGqJ5iIcZq3X151bRSuk7ksGvU+onl8DCelc6DjvC6B+2uvvEIM 5asA== X-Forwarded-Encrypted: i=1; AFNElJ/DSNMQGryEDAQaoFyzRgAJ1FAn3EynY/WDLP0g30dbLDuUlUVrYvEnIWEVMP98iJggqxEMtnZ8e3/WtoA=@vger.kernel.org X-Gm-Message-State: AOJu0YwTJSy9jwA9skx2WCXud/mIuIPj5iElhn5iy4rSIIPH3ymhR5R+ 58An9twPv/OPLqljgwyWd0NRfFBXalusofDx70ujQ5MDhnttARH2gWo9KlItiw== X-Gm-Gg: Acq92OGQPxzoWpVkbI3QrAoYFAwtWSH1NtiUQLq9NF7Kxw38hxiPfnbSC9ZegfEU6nD 7W8Y7gYM9H129zVhzmK8/4PFeObrub0MGgea6NZw1K+sDfHKs4zfZPKAjJhNLKWyyQLEgU62/BR 3L0zG6+9NIkq6pQq+og7psww/wqddZXnaYfvMk0Jnt1QKiM0geIZa2X+OmfKsssMNMBwe4ZZJmI KjzUgpumNzX1As8DrFwN9OMAK3vopHT8Lpc78X/ZseCD3sP94cizYr3dg55SNPbsMOWyr1Af0Ap p5lDZ4orpux0o0h65YdDd5MTrcBCioFwYjPwBzEY0aTj56Jv2vJo4hl2U550/qr4EeMaY6G7YJI VLoCVuds6bXRi/TxCmIRlmK6CB/3lG81D8soLlktdf0BJcFHFiSBkMXnggpYyRulYLkbcvkAEzD aiA+TdT/wblFWSvWgJVDC/j9670m+UvFeEPGAbJTyR X-Received: by 2002:a05:6a00:bc8a:b0:82f:39df:dd54 with SMTP id d2e1a72fcca58-8414b40f5c6mr4195197b3a.8.1779410906721; Thu, 21 May 2026 17:48:26 -0700 (PDT) Received: from hyunchul-PC02.lge.net ([27.122.242.71]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-84164ac99b0sm78484b3a.4.2026.05.21.17.48.24 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 21 May 2026 17:48:25 -0700 (PDT) From: Hyunchul Lee To: Namjae Jeon Cc: Hyunchul Lee , linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH 3/4] ntfs: validate index entries on reading Date: Fri, 22 May 2026 09:47:46 +0900 Message-ID: <20260522-t-fix-oob-v2-v1-3-0bea6582a361@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260522-t-fix-oob-v2-v1-0-0bea6582a361@gmail.com> References: <20260522-t-fix-oob-v2-v1-0-0bea6582a361@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" X-Mailer: b4 0.13.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=10630; i=hyc.lee@gmail.com; h=from:subject:message-id; bh=dcCWOB4BeVqjZPJUd0+HQG4oF8oQzhW58FogfZUawoQ=; b=kA0DAAoBNPIw+veOSNMByyZiAGoPpn6iqM4AEFykhObBdEVg0Rr95uE3JUqGn5Yg3fMOC49qd IkCMwQAAQoAHRYhBNWFKcxTduNtbh5vYjTyMPr3jkjTBQJqD6Z+AAoJEDTyMPr3jkjT9IgP/1qn Bc1fD/iqN/vK3D9fBAT0LmiJrgyl+tH0W9jx2pBVm8LFzoD6Scte5bru36pRntASZgCxHIoAaT5 SnUohXfER1PjIHXCeHA6DwSXBxMkJ3QT6juBdhBvyAY+7Ihqu3AZsR2cee9JIUTSZ5X2KO/hWCP QHVXGojOJelUV2VMhkFceoBAJFwb7kyHdcs+13sKeVo1F5ZdgCB/1L0zHx7VsPydvjaG/VHEu4H Dubr+yRbPnBRlsMay7vGVi55XGmLRDNeY9GwT6EnB/7bnVlpcLE730kUBqRU2bM66kdBnXwfNKB 0DAsRFEAGxUQwTCzCpHZdujCNoLCRJWpiEKxIGs9YBoUlXIMuFgQBGTvClK1jQ8Tcfpc0bB6wsI YmKuL/aonc19iLz1lMvwJW57qmgOoSKgv/ABgWLD8W3gP5OTJvbMv9BHpYOwnekrsSneuijyl/n 2kBzKx+IFguYUeHPOJkSFmw4wa2rkwKFd05GpFyAvxWuCHpaokyE8KQ7eboq6cBuBThwPtUNUhZ vDvThoCOMm/jjxfHiRxPvsP6DY02ao0e8Vmx/LbuwUKqtzcJf5WuNyx8Ms0SEwHNHPLNN94Ehml nPIG/oc7LoR9ihTNOz6kf064ADLogpiUaC8lPIhelRpKAKsBwhV5kolLUKQNb8J6PmLBKDkQjH2 L19n9 X-Developer-Key: i=hyc.lee@gmail.com; a=openpgp; fpr=D58529CC5376E36D6E1E6F6234F230FAF78E48D3 Content-Transfer-Encoding: quoted-printable 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. Signed-off-by: Hyunchul Lee --- fs/ntfs/dir.c | 28 ++--------------- fs/ntfs/index.c | 96 +++++++++++++++++++++++++++++++----------------------= ---- fs/ntfs/index.h | 8 +++-- fs/ntfs/inode.c | 8 +++-- 4 files changed, 66 insertions(+), 74 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 91fcaa79f8ac..456e195ca5c9 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))) { @@ -350,6 +319,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 */ @@ -501,7 +508,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); @@ -512,7 +520,7 @@ int ntfs_index_block_inconsistent(struct ntfs_volume *v= ol, if (!ntfs_is_indx_record(ib->magic)) { ntfs_error(sb, "Corrupt index block signature: vcn %lld inode %llu\n", vcn, (unsigned long long)inum); - return -1; + return -EIO; } =20 if (le64_to_cpu(ib->index_block_vcn) !=3D vcn) { @@ -520,22 +528,23 @@ int ntfs_index_block_inconsistent(struct ntfs_volume = *vol, "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 block_size) { ntfs_error(sb, "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 -1; + return -EIO; } =20 if (ntfs_index_header_inconsistent(vol, &ib->index, block_size - offsetof(struct index_block, index), inum)) - return -1; - + return -EIO; + if (ntfs_index_entries_inconsistent(vol, &ib->index, cr, inum)) + return -EIO; return 0; } =20 @@ -720,15 +729,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->idx_ni->vol, dst, - icx->block_size, vcn, + icx->block_size, vcn, icx->cr, icx->idx_ni->mft_no)) - return -1; - + 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:34:48 2026 Received: from mail-pf1-f179.google.com (mail-pf1-f179.google.com [209.85.210.179]) (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 18F7725B0A4 for ; Fri, 22 May 2026 00:48:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.179 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779410915; cv=none; b=daSMiyYqtPkrn8CgJ0FWO+nzefLmfsYZwskvH2ijFLmaPgHYD/tTt9snV5nqSzWvL1IsfaOnVMLzSK3H17tQYOS5nRPQmkXxz25cAV/48qVk+WplQgABN4b6EbTDGk/IofYgMB6/OY9hvyYWh/LS08WGjsBjDjmAVQD682F5jN8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779410915; c=relaxed/simple; bh=3Z7DGIxd99r47inav3ntEvoXxx75MHxcbUAHkNmIls0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=TtTTFAGzppmKcmKR7WlT4waqT9Eq1Yr+Zek1Rk0d8wtLMJNrDYXt75P4ecko3HQ0eODRlwjRvN2L2kybgd/eYjHSkcPIHSsubYM5Ldg0aXDqmdcyvkt04SsIdNVa3fM7nidqbDxD0hxqIn0ybLXPBgLHSWziQlX+/priFkZgC2Q= 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=iFVkqLoL; arc=none smtp.client-ip=209.85.210.179 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="iFVkqLoL" Received: by mail-pf1-f179.google.com with SMTP id d2e1a72fcca58-83659d38e38so2696967b3a.1 for ; Thu, 21 May 2026 17:48:33 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1779410913; x=1780015713; 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=v6ToQuIOvYiLinMKHYAl5XCRT3szRUzaMC8NZZn/8eg=; b=iFVkqLoLLHjIdvee32+iZpYGQd43WGCjzXkMZaFH7r3Nkjs5q07FqM/5qCUlCEyiy7 Y9HU/tk4erLLlBFn3dJJA49KOIID2EaF+JzpH7w9d0Zf6GxPyLm0UvA4WOy8Iz9jmyAa eODaubHzNDYBNO3PrEorIk2tNuk+tNr8SD9hhGa1lv4cN/kZc2MPUDn6T1ly82Grjfbe JATgQ02jjyEN3vDnZ6fuCuoOYirspEejMKNgDL59hTgjrOgLjT0o3cIIT9EXmTFH0LXb u9wkbkwqecypsgMWgANLydFZA1xZ10PNERQrDoiAIxwbf5NmOMH7GRPSFh1J4S5ofCWY scuA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779410913; x=1780015713; 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=v6ToQuIOvYiLinMKHYAl5XCRT3szRUzaMC8NZZn/8eg=; b=oKYCKsP9gJZuMQotMUQgog1KT9PzXM0q5dqrux9sE/5k3NYrI3Mral3seN62599EoI 7zeOaczmtw3rxrplI7rERR2caL3yTX1IvG5oaUEz8pPDwXlFhcxXh2chezGldkDbL5Gd UcLBABR+LusdtfRmkbHPoUpkPy5SGcDmR5w5obPaVv20xALSwXU5UJ46NgWkmF4ybuxt lfINgCtIrfxjHc6/KM0bzSamuXFFwzetC7MG/z6sXTTFeWYqgrPOBiRlwCju6IFyl79z 5RaseR+g5ZUU2Kjft1HZ6W+dafzmUgvYdJeSJkd5aVH54R3VF4I63S1j4yPvdw7PjmZH W4Jw== X-Forwarded-Encrypted: i=1; AFNElJ9nR+CpnFvN1rJFSnBP39oQAvfkyS331CvP7SLJlJwOb06X7yxYv2D55it8NUh32uJLmWWuEWxb3IcS1NI=@vger.kernel.org X-Gm-Message-State: AOJu0YyPmzFmXe6D7+bWwjNp//uupU7QfMxpQkbWak1BYuz/fkJ2MDeg JF0nVbAMfxbCjyinzs07chzXROBN0oIXujo85owxTqyz68bOCP/6AUx0JXxpIw== X-Gm-Gg: Acq92OFptyxMDiM+PD1T3P0RuSD8aI50ydnvyeJYaJA1Km2ici1svKk9Iuq7082VKc5 ZzZVqvPYMHRZR2mhA7Z250Dw7Ve7RG2FrcM+XGh7SzbUFC2N+jdi+zepl0YUrbYqpfxbfx49ZUL M1Nb/3iis9hIGR6LBhS5lgN8BvKqiog4+BrXq+7riCQjAfM77slrHJRjEc3HxW71GQ8de+qCvRe oiJnWX4MZSRC4hzJdK0Azuf0D6ABHsOQIpRzwurMuQQz0A4dn2cRxBHd6PIKdTzGDKSUq+e/d8S BW2JYdfNyZtGyH8WdM3f8xqomouTy0ggRewFtVla7QdSw2YFX0sC6KpZglycDJbg3myKDAYuNqU pjr9Rz7Q7FykWimBq2TagETCAy5856/+mNb3uTKH7i7+abkF0x4wRjPDgLUflLUQxTPdU0RtOrO G86X5YMrxMSD39XCwux8HFSvIIoQcuTg== X-Received: by 2002:a05:6a00:240b:b0:83e:c8fb:54dc with SMTP id d2e1a72fcca58-8415f371ed1mr1374745b3a.19.1779410913282; Thu, 21 May 2026 17:48:33 -0700 (PDT) Received: from hyunchul-PC02.lge.net ([27.122.242.71]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-84164ac99b0sm78484b3a.4.2026.05.21.17.48.31 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 21 May 2026 17:48:32 -0700 (PDT) From: Hyunchul Lee To: Namjae Jeon Cc: Hyunchul Lee , linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH 4/4] ntfs: add bounds check before accessing EA entries Date: Fri, 22 May 2026 09:47:47 +0900 Message-ID: <20260522-t-fix-oob-v2-v1-4-0bea6582a361@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260522-t-fix-oob-v2-v1-0-0bea6582a361@gmail.com> References: <20260522-t-fix-oob-v2-v1-0-0bea6582a361@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" X-Mailer: b4 0.13.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=1139; i=hyc.lee@gmail.com; h=from:subject:message-id; bh=3Z7DGIxd99r47inav3ntEvoXxx75MHxcbUAHkNmIls0=; b=owEBbQKS/ZANAwAKATTyMPr3jkjTAcsmYgBqD6Z+cFDBjuledse+5nJbmJnJj56LafD+i8u0y veIqKVWyBCJAjMEAAEKAB0WIQTVhSnMU3bjbW4eb2I08jD6945I0wUCag+mfgAKCRA08jD6945I 0w9AEACkKBX81TnC4SSljMrZpJ8gTh/HttJMfT7jCTgPMinnt0reiSs2h7lPcPdoo+b5gySYeSB 5F61Wl3s48tpbCzzpUeuJtdMALZ5REplplKXV0/qgkigf2/7KZsp9DQagJhwbMqf2ONv7asIFlT 1gbK5Qy3cFuWb/hNJVIBHRBJPM6p2gk14un3adqGeg1UFJqPJGteLmGVvaCwyl12tF9+zznyCns eOW4Gzsn9tgOw7YBz5HhvJR6XMBXWdYlF4/SRVhJDKcWEJFePUcemMZ3gmnb0NmO+bZCUZrEX69 v2oTYGi1nrh99/Lthu50XQFJ85PPWvP+s2oMw8lEvUmGjVPDypDUu1Gf7FwD1q5pXoPLV5BSc3r K3MM29FP0Jlksp/I2MyXf+Irt0gFUvPNvL2/wuBA4Fb8UqB03+GEzRvht1RsbUQ4fcfm7bYSqVc I8wKFCpHEUkxi22fDbXcrG4jmVnpto3t09zfqwgoowJ0mioP2ZbQ5bkzWxCyyTrxaSe/BARkmdF v9KTR63W1TNCx99u+i6VXG0kc3OwsKSAY5m3RB9VN27u49v9sqVO50t5M3+zIK+LLXwdfYX/awC t7r7vQp3G8K5fqVWFjSFZgPckzNBBkAv11L4EpGz7PQflBHDOHcknrZ3GEDkqiaU8Jp2cPfxAuv 7DARDS62pTxVY/w== X-Developer-Key: i=hyc.lee@gmail.com; a=openpgp; fpr=D58529CC5376E36D6E1E6F6234F230FAF78E48D3 Content-Transfer-Encoding: quoted-printable 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 | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/fs/ntfs/ea.c b/fs/ntfs/ea.c index c4a4a3e3e599..323caced77ea 100644 --- a/fs/ntfs/ea.c +++ b/fs/ntfs/ea.c @@ -58,6 +58,9 @@ static int ntfs_ea_lookup(char *ea_buf, s64 ea_buf_size, = const char *name, =20 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); @@ -486,6 +489,11 @@ ssize_t ntfs_listxattr(struct dentry *dentry, char *bu= ffer, size_t size) =20 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