mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH v5 0/4] ntfs: finish index root lookup validation
@ 2026-06-07  5:17 DaeMyung Kang
  2026-06-07  5:17 ` [PATCH v5 1/4] ntfs: reject non-resident records for resident-only attributes DaeMyung Kang
                   ` (3 more replies)
  0 siblings, 4 replies; 7+ messages in thread
From: DaeMyung Kang @ 2026-06-07  5:17 UTC (permalink / raw)
  To: Namjae Jeon, Hyunchul Lee; +Cc: linux-fsdevel, linux-kernel, DaeMyung Kang

This v5 is based on the current linux-ntfs ntfs-next branch at commit
c864077b8d73 ("ntfs: use d_splice_alias() for ->lookup() return value").
That branch already contains v4 patches 1/6 through 4/6, the
ntfs_readdir() index-root entries_offset validation, and the initial
resident $INDEX_ROOT lookup validator. This series does not resend those
applied patches.

The extent inode lifetime fix is independent of this attribute
validation work and is not included in this series.

The merged lookup-time $INDEX_ROOT validator does not yet validate
index.allocated_size. Enabling that check exposed a generic/013 failure
in earlier testing because ntfs_ir_reparent() could publish a larger
resident root header before growing the resident value. In the failing
case, the root had value_len=48, index_size=32, index_length=40, and
allocated_size=40, so allocated_size validation correctly rejected the
transient layout and ntfsprogs-plus ntfsck reported a corrupt index root.
Patches 2 and 3 are the prerequisite resize-ordering fixes for enabling
that allocated_size validation: patch 2 fixes the grow side, and patch 3
keeps the shrink side consistent for the same validator.

Patch 1 also finishes the lookup contract for resident-only attributes.
The current shared validator rejects non-resident $FILE_NAME and
$VOLUME_NAME records, but other resident-only attribute types can still
pass the non-resident path. That is unsafe for callers such as
$STANDARD_INFORMATION and $VOLUME_INFORMATION users that read
data.resident.value_offset after lookup, and it also makes the
$INDEX_ROOT lookup contract incomplete. The patch factors the existing
checks into a resident-only helper and extends it to the remaining
resident-only types.

Patch 4 extends the merged $INDEX_ROOT validator to check
index.allocated_size. The driver does consume root index.allocated_size
as the capacity field in
ntfs_ie_add() when deciding whether an insert can be done in place, and
ntfs_ie_insert() does not re-check that boundary. The validation only
rejects layouts where allocated_size extends past the resident value;
valid slack remains allowed as index_length <= allocated_size <= the
resident index area.

The current series applies cleanly to linux-ntfs ntfs-next commit
c864077b8d73 ("ntfs: use d_splice_alias() for ->lookup() return value")
with `git am -p3`. checkpatch.pl --strict and git diff --check were clean.

The same final validator and resize-ordering changes were also tested on
the earlier clean v4 application stack used for runtime testing. A KASAN
kernel with CONFIG_NTFS_FS=y built successfully, and KASAN generic/013
passed three consecutive runs. ntfsprogs-plus ntfsck v1.0.0, built from
ntfsprogs-plus revision 53943dae, reported the three resulting generic/013
test images clean with `ntfsck -n` (errors:0, fixed:0).

Changes since v4:
- Do not resend v4 patches 1/6 through 4/6, which have already been
  applied.
- Add a resident-only attribute helper and reject non-resident records
  for the remaining resident-only attribute types.
- Add the ntfs_ir_reparent() grow-before-header fix required before
  enabling the allocated_size part of the $INDEX_ROOT validator.
- Keep the ntfs_ir_truncate() shrink-ordering fix, now framed as the
  shrink-side consistency fix for lookup-time $INDEX_ROOT validation.
- Rework the final patch as an incremental allocated_size check for the
  $INDEX_ROOT validator already merged in ntfs-next.

DaeMyung Kang (4):
  ntfs: reject non-resident records for resident-only attributes
  ntfs: grow index root value before reparent header update
  ntfs: update index root allocated size before shrink
  ntfs: validate index root allocated_size on lookup

 fs/ntfs/attrib.c | 24 ++++++++++++++--
 fs/ntfs/index.c  | 96 ++++++++++++++++++++++++++++++++++++++++++----------------------
 2 files changed, 85 insertions(+), 35 deletions(-)

-- 
2.43.0

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH v5 1/4] ntfs: reject non-resident records for resident-only attributes
  2026-06-07  5:17 [PATCH v5 0/4] ntfs: finish index root lookup validation DaeMyung Kang
@ 2026-06-07  5:17 ` DaeMyung Kang
  2026-06-07  5:17 ` [PATCH v5 2/4] ntfs: grow index root value before reparent header update DaeMyung Kang
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 7+ messages in thread
From: DaeMyung Kang @ 2026-06-07  5:17 UTC (permalink / raw)
  To: Namjae Jeon, Hyunchul Lee; +Cc: linux-fsdevel, linux-kernel, DaeMyung Kang

The shared lookup-time attribute validator rejects non-resident
$FILE_NAME and $VOLUME_NAME records because their formats require
resident values and callers handle returned records as resident
attributes. Other resident-only attribute types still pass through the
generic non-resident mapping-pairs checks.

That leaves real resident/non-resident union confusion paths. Inode load
looks up $STANDARD_INFORMATION and then reads data.resident.value_offset
without checking a->non_resident. ntfs_inode_sync_standard_information()
does the same when updating the standard information value.
ntfs_write_volume_flags() also looks up $VOLUME_INFORMATION and reads
data.resident.value_offset directly. $INDEX_ROOT callers in dir.c and
index.c depend on the same lookup contract before consuming the resident
index root value.

Reject non-resident records for all resident-only attribute types in the
shared validator. Keep the existing $FILE_NAME and $VOLUME_NAME behavior,
but factor it through a helper and extend it to
$STANDARD_INFORMATION, $OBJECT_ID, $VOLUME_INFORMATION, $INDEX_ROOT, and
$EA_INFORMATION. For $OBJECT_ID and $EA_INFORMATION this is contract
hardening for resident-only formats; this patch only rejects the
non-resident form and does not add new resident value validation for
those types.

Signed-off-by: DaeMyung Kang <charsyam@gmail.com>
---
 fs/ntfs/attrib.c | 18 +++++++++++++++++-
 1 file changed, 17 insertions(+), 1 deletion(-)

diff --git a/fs/ntfs/attrib.c b/fs/ntfs/attrib.c
index 7e293b85ad19..0fb2b6acf8b2 100644
--- a/fs/ntfs/attrib.c
+++ b/fs/ntfs/attrib.c
@@ -595,6 +595,22 @@ static u32 ntfs_resident_attr_min_value_length(const __le32 type)
 	}
 }
 
+static bool ntfs_attr_type_must_be_resident(const __le32 type)
+{
+	switch (type) {
+	case AT_STANDARD_INFORMATION:
+	case AT_FILE_NAME:
+	case AT_OBJECT_ID:
+	case AT_VOLUME_NAME:
+	case AT_VOLUME_INFORMATION:
+	case AT_INDEX_ROOT:
+	case AT_EA_INFORMATION:
+		return true;
+	default:
+		return false;
+	}
+}
+
 static bool ntfs_file_name_attr_value_is_valid(const u8 *value, const u32 value_length)
 {
 	const struct file_name_attr *fn;
@@ -665,7 +681,7 @@ static bool ntfs_attr_value_is_valid(struct ntfs_volume *vol,
 	u32 min_len;
 
 	if (a->non_resident) {
-		if (a->type == AT_FILE_NAME || a->type == AT_VOLUME_NAME)
+		if (ntfs_attr_type_must_be_resident(a->type))
 			goto corrupt;
 		if (!ntfs_non_resident_attr_value_is_valid(a))
 			goto corrupt;
-- 
2.43.0

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH v5 2/4] ntfs: grow index root value before reparent header update
  2026-06-07  5:17 [PATCH v5 0/4] ntfs: finish index root lookup validation DaeMyung Kang
  2026-06-07  5:17 ` [PATCH v5 1/4] ntfs: reject non-resident records for resident-only attributes DaeMyung Kang
@ 2026-06-07  5:17 ` DaeMyung Kang
  2026-06-07  5:17 ` [PATCH v5 3/4] ntfs: update index root allocated size before shrink DaeMyung Kang
  2026-06-07  5:17 ` [PATCH v5 4/4] ntfs: validate index root allocated_size on lookup DaeMyung Kang
  3 siblings, 0 replies; 7+ messages in thread
From: DaeMyung Kang @ 2026-06-07  5:17 UTC (permalink / raw)
  To: Namjae Jeon, Hyunchul Lee; +Cc: linux-fsdevel, linux-kernel, DaeMyung Kang

ntfs_ir_reparent() moves the resident index root entries into an index
block and leaves a small root stub containing the child VCN. That root
stub can be larger than the existing resident value. For example, an
empty root with value_length 48 has an index area of 32 bytes, while the
large-index root stub needs index_length and allocated_size of 40 bytes.

The current code publishes the larger index.index_length and
index.allocated_size before resizing the resident value. If the resize
returns -ENOSPC, the recovery path can call ntfs_inode_add_attrlist(),
which looks attributes up again while the root header says
allocated_size 40 but the resident value still only provides 32 bytes of
index area. Lookup-time $INDEX_ROOT validation then correctly rejects
that transient layout as corrupt.

This reproduces as a generic/013 failure under qemu. In the failing run,
the transient root had value_len=48, index_size=32, index_length=40, and
allocated_size=40, and ntfsprogs-plus ntfsck reported "Corrupt index
root in MFT record 1177".

When the root stub grows, resize the resident value before publishing the
larger root header. If the resize fails, the old root remains valid for
recovery lookups. Keep the existing header-before-resize ordering for
shrink or same-size cases so the resident value never temporarily
exposes an allocated_size beyond its bounds.

Signed-off-by: DaeMyung Kang <charsyam@gmail.com>
---
 fs/ntfs/index.c | 78 ++++++++++++++++++++++++++++++-------------------
 1 file changed, 48 insertions(+), 30 deletions(-)

diff --git a/fs/ntfs/index.c b/fs/ntfs/index.c
index 146e011c1a41..ab9a4bc36f0b 100644
--- a/fs/ntfs/index.c
+++ b/fs/ntfs/index.c
@@ -1173,6 +1173,8 @@ static int ntfs_ir_reparent(struct ntfs_index_context *icx)
 	struct index_entry *ie;
 	struct index_block *ib = NULL;
 	s64 new_ib_vcn;
+	u32 index_length;
+	u32 old_value_length;
 	int ix_root_size;
 	int ret = 0;
 
@@ -1220,6 +1222,21 @@ static int ntfs_ir_reparent(struct ntfs_index_context *icx)
 		goto clear_bmp;
 	}
 
+	old_value_length = le32_to_cpu(ctx->attr->data.resident.value_length);
+	index_length = le32_to_cpu(ir->index.entries_offset) +
+		sizeof(struct index_entry_header) + sizeof(s64);
+	ix_root_size = offsetof(struct index_root, index) + index_length;
+	/* Grow the resident value before publishing the larger root header. */
+	if (ix_root_size > old_value_length) {
+		ret = ntfs_resident_attr_value_resize(ctx->mrec, ctx->attr, ix_root_size);
+		if (ret)
+			goto resize_failed;
+
+		icx->idx_ni->data_size = ix_root_size;
+		icx->idx_ni->initialized_size = ix_root_size;
+		icx->idx_ni->allocated_size = (ix_root_size + 7) & ~7;
+	}
+
 	ntfs_ir_nill(ir);
 
 	ie = ntfs_ie_get_first(&ir->index);
@@ -1228,48 +1245,49 @@ static int ntfs_ir_reparent(struct ntfs_index_context *icx)
 
 	ir->index.flags = LARGE_INDEX;
 	NInoSetIndexAllocPresent(icx->idx_ni);
-	ir->index.index_length = cpu_to_le32(le32_to_cpu(ir->index.entries_offset) +
-			le16_to_cpu(ie->length));
+	ir->index.index_length = cpu_to_le32(index_length);
 	ir->index.allocated_size = ir->index.index_length;
 
-	ix_root_size = sizeof(struct index_root) - sizeof(struct index_header) +
-		le32_to_cpu(ir->index.allocated_size);
-	ret  = ntfs_resident_attr_value_resize(ctx->mrec, ctx->attr, ix_root_size);
-	if (ret) {
-		/*
-		 * When there is no space to build a non-resident
-		 * index, we may have to move the root to an extent
-		 */
-		if ((ret == -ENOSPC) && (ctx->al_entry || !ntfs_inode_add_attrlist(icx->idx_ni))) {
+	if (ix_root_size <= old_value_length) {
+		ret = ntfs_resident_attr_value_resize(ctx->mrec, ctx->attr, ix_root_size);
+		if (ret)
+			goto resize_failed;
+
+		icx->idx_ni->data_size = ix_root_size;
+		icx->idx_ni->initialized_size = ix_root_size;
+		icx->idx_ni->allocated_size = (ix_root_size + 7) & ~7;
+	}
+	ntfs_ie_set_vcn(ie, new_ib_vcn);
+	goto err_out;
+
+resize_failed:
+	/*
+	 * When there is no space to build a non-resident
+	 * index, we may have to move the root to an extent
+	 */
+	if ((ret == -ENOSPC) && (ctx->al_entry || !ntfs_inode_add_attrlist(icx->idx_ni))) {
+		ntfs_attr_put_search_ctx(ctx);
+		ctx = NULL;
+		ir = ntfs_ir_lookup(icx->idx_ni, icx->name, icx->name_len, &ctx);
+		if (ir && !ntfs_attr_record_move_away(ctx, ix_root_size -
+				le32_to_cpu(ctx->attr->data.resident.value_length))) {
+			if (ntfs_attrlist_update(ctx->base_ntfs_ino ?
+						 ctx->base_ntfs_ino : ctx->ntfs_ino))
+				goto clear_bmp;
 			ntfs_attr_put_search_ctx(ctx);
 			ctx = NULL;
-			ir = ntfs_ir_lookup(icx->idx_ni, icx->name, icx->name_len, &ctx);
-			if (ir && !ntfs_attr_record_move_away(ctx, ix_root_size -
-					le32_to_cpu(ctx->attr->data.resident.value_length))) {
-				if (ntfs_attrlist_update(ctx->base_ntfs_ino ?
-							 ctx->base_ntfs_ino : ctx->ntfs_ino))
-					goto clear_bmp;
-				ntfs_attr_put_search_ctx(ctx);
-				ctx = NULL;
-				goto retry;
-			}
+			goto retry;
 		}
-		goto clear_bmp;
-	} else {
-		icx->idx_ni->data_size = icx->idx_ni->initialized_size = ix_root_size;
-		icx->idx_ni->allocated_size = (ix_root_size  + 7) & ~7;
 	}
-	ntfs_ie_set_vcn(ie, new_ib_vcn);
-
+clear_bmp:
+	ntfs_ibm_clear(icx, new_ib_vcn);
+	goto err_out;
 err_out:
 	kvfree(ib);
 	if (ctx)
 		ntfs_attr_put_search_ctx(ctx);
 out:
 	return ret;
-clear_bmp:
-	ntfs_ibm_clear(icx, new_ib_vcn);
-	goto err_out;
 }
 
 /*
-- 
2.43.0


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH v5 3/4] ntfs: update index root allocated size before shrink
  2026-06-07  5:17 [PATCH v5 0/4] ntfs: finish index root lookup validation DaeMyung Kang
  2026-06-07  5:17 ` [PATCH v5 1/4] ntfs: reject non-resident records for resident-only attributes DaeMyung Kang
  2026-06-07  5:17 ` [PATCH v5 2/4] ntfs: grow index root value before reparent header update DaeMyung Kang
@ 2026-06-07  5:17 ` DaeMyung Kang
  2026-06-07  5:17 ` [PATCH v5 4/4] ntfs: validate index root allocated_size on lookup DaeMyung Kang
  3 siblings, 0 replies; 7+ messages in thread
From: DaeMyung Kang @ 2026-06-07  5:17 UTC (permalink / raw)
  To: Namjae Jeon, Hyunchul Lee; +Cc: linux-fsdevel, linux-kernel, DaeMyung Kang

ntfs_ir_truncate() currently shrinks the resident $INDEX_ROOT value first
and only updates index.allocated_size after re-looking up the attribute.
During that relookup, the resident value_length can already be smaller
while index.allocated_size still contains the old larger size.

That leaves a transiently inconsistent $INDEX_ROOT layout and prevents
lookup-time $INDEX_ROOT validation from being enabled: validation can
correctly reject allocated_size extending past the newly shrunk resident
value.

When shrinking, lower index.allocated_size before shrinking value_length.
If the truncate fails, restore the old allocated_size. Keep the existing
grow ordering because the old allocated_size remains within the enlarged
resident value until it is updated after the relookup. The shrink path is
safe because the new value_length still covers struct index_root, so the
index.allocated_size field remains present while it is updated first.

Signed-off-by: DaeMyung Kang <charsyam@gmail.com>
---
 fs/ntfs/index.c | 18 +++++++++++++++---
 1 file changed, 15 insertions(+), 3 deletions(-)

diff --git a/fs/ntfs/index.c b/fs/ntfs/index.c
index ab9a4bc36f0b..a411ca7fe629 100644
--- a/fs/ntfs/index.c
+++ b/fs/ntfs/index.c
@@ -1298,9 +1298,16 @@ static int ntfs_ir_reparent(struct ntfs_index_context *icx)
 static int ntfs_ir_truncate(struct ntfs_index_context *icx, int data_size)
 {
 	int ret;
+	u32 old_allocated_size;
+	bool shrink;
 
 	ntfs_debug("Entering\n");
 
+	old_allocated_size = le32_to_cpu(icx->ir->index.allocated_size);
+	shrink = data_size < old_allocated_size;
+	if (shrink)
+		icx->ir->index.allocated_size = cpu_to_le32(data_size);
+
 	/*
 	 *  INDEX_ROOT must be resident and its entries can be moved to
 	 *  struct index_block, so ENOSPC isn't a real error.
@@ -1312,9 +1319,14 @@ static int ntfs_ir_truncate(struct ntfs_index_context *icx, int data_size)
 		if (!icx->ir)
 			return -ENOENT;
 
-		icx->ir->index.allocated_size = cpu_to_le32(data_size);
-	} else if (ret != -ENOSPC)
-		ntfs_error(icx->idx_ni->vol->sb, "Failed to truncate INDEX_ROOT");
+		if (!shrink)
+			icx->ir->index.allocated_size = cpu_to_le32(data_size);
+	} else {
+		if (shrink)
+			icx->ir->index.allocated_size = cpu_to_le32(old_allocated_size);
+		if (ret != -ENOSPC)
+			ntfs_error(icx->idx_ni->vol->sb, "Failed to truncate INDEX_ROOT");
+	}
 
 	return ret;
 }
-- 
2.43.0


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH v5 4/4] ntfs: validate index root allocated_size on lookup
  2026-06-07  5:17 [PATCH v5 0/4] ntfs: finish index root lookup validation DaeMyung Kang
                   ` (2 preceding siblings ...)
  2026-06-07  5:17 ` [PATCH v5 3/4] ntfs: update index root allocated size before shrink DaeMyung Kang
@ 2026-06-07  5:17 ` DaeMyung Kang
  2026-06-08  5:08   ` Hyunchul Lee
  3 siblings, 1 reply; 7+ messages in thread
From: DaeMyung Kang @ 2026-06-07  5:17 UTC (permalink / raw)
  To: Namjae Jeon, Hyunchul Lee; +Cc: linux-fsdevel, linux-kernel, DaeMyung Kang

The resident $INDEX_ROOT validator already checks the index root header
fields, but it still does not bound index_length through allocated_size or
ensure allocated_size stays within the resident index area.

Callers consume index.allocated_size as the resident root capacity.
ntfs_ie_add() uses it to decide whether an insertion can be done in place,
and ntfs_ie_insert() then updates the root without re-checking the resident
value boundary.

Read allocated_size in the resident $INDEX_ROOT validator, require it to be
8-byte aligned, require index_length <= allocated_size, and require
allocated_size <= the resident index area. Valid slack remains allowed.

Signed-off-by: DaeMyung Kang <charsyam@gmail.com>
---
 fs/ntfs/attrib.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/fs/ntfs/attrib.c b/fs/ntfs/attrib.c
index cf49eade6b22..49c8f1f3b9dd 100644
--- a/fs/ntfs/attrib.c
+++ b/fs/ntfs/attrib.c
@@ -657,15 +657,19 @@ static bool ntfs_index_root_attr_value_is_valid(const u8 *value, const u32 value
 	u32 index_size;
 	u32 entries_offset;
 	u32 index_length;
+	u32 allocated_size;
 
 	ir = (const struct index_root *)value;
 	index_size = value_length - offsetof(struct index_root, index);
 	entries_offset = le32_to_cpu(ir->index.entries_offset);
 	index_length = le32_to_cpu(ir->index.index_length);
+	allocated_size = le32_to_cpu(ir->index.allocated_size);
 
-	if ((entries_offset | index_length) & 7 ||
+	if ((entries_offset | index_length | allocated_size) & 7 ||
 	    entries_offset < sizeof(struct index_header) ||
 	    entries_offset > index_length ||
+	    index_length > allocated_size ||
+	    allocated_size > index_size ||
 	    index_length - entries_offset < sizeof(struct index_entry_header))
 		return false;
 
-- 
2.43.0

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH v5 4/4] ntfs: validate index root allocated_size on lookup
  2026-06-07  5:17 ` [PATCH v5 4/4] ntfs: validate index root allocated_size on lookup DaeMyung Kang
@ 2026-06-08  5:08   ` Hyunchul Lee
  2026-06-08  5:38     ` CharSyam
  0 siblings, 1 reply; 7+ messages in thread
From: Hyunchul Lee @ 2026-06-08  5:08 UTC (permalink / raw)
  To: DaeMyung Kang; +Cc: Namjae Jeon, linux-fsdevel, linux-kernel

Hi Daemyung,

2026년 6월 7일 (일) 오후 2:17, DaeMyung Kang <charsyam@gmail.com>님이 작성:
>
> The resident $INDEX_ROOT validator already checks the index root header
> fields, but it still does not bound index_length through allocated_size or
> ensure allocated_size stays within the resident index area.
>
> Callers consume index.allocated_size as the resident root capacity.
> ntfs_ie_add() uses it to decide whether an insertion can be done in place,
> and ntfs_ie_insert() then updates the root without re-checking the resident
> value boundary.
>
> Read allocated_size in the resident $INDEX_ROOT validator, require it to be
> 8-byte aligned, require index_length <= allocated_size, and require
> allocated_size <= the resident index area. Valid slack remains allowed.
>
> Signed-off-by: DaeMyung Kang <charsyam@gmail.com>
> ---
>  fs/ntfs/attrib.c | 6 +++++-
>  1 file changed, 5 insertions(+), 1 deletion(-)
>
> diff --git a/fs/ntfs/attrib.c b/fs/ntfs/attrib.c
> index cf49eade6b22..49c8f1f3b9dd 100644
> --- a/fs/ntfs/attrib.c
> +++ b/fs/ntfs/attrib.c
> @@ -657,15 +657,19 @@ static bool ntfs_index_root_attr_value_is_valid(const u8 *value, const u32 value

Applying this patch failed.
It seems that the patch below has not been merged yet.
https://lore.kernel.org/all/20260530143514.3083601-7-charsyam@gmail.com/

>         u32 index_size;
>         u32 entries_offset;
>         u32 index_length;
> +       u32 allocated_size;
>
>         ir = (const struct index_root *)value;
>         index_size = value_length - offsetof(struct index_root, index);
>         entries_offset = le32_to_cpu(ir->index.entries_offset);
>         index_length = le32_to_cpu(ir->index.index_length);
> +       allocated_size = le32_to_cpu(ir->index.allocated_size);
>
> -       if ((entries_offset | index_length) & 7 ||
> +       if ((entries_offset | index_length | allocated_size) & 7 ||
>             entries_offset < sizeof(struct index_header) ||
>             entries_offset > index_length ||
> +           index_length > allocated_size ||
> +           allocated_size > index_size ||
>             index_length - entries_offset < sizeof(struct index_entry_header))
>                 return false;
>
> --
> 2.43.0



-- 
Thanks,
Hyunchul

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH v5 4/4] ntfs: validate index root allocated_size on lookup
  2026-06-08  5:08   ` Hyunchul Lee
@ 2026-06-08  5:38     ` CharSyam
  0 siblings, 0 replies; 7+ messages in thread
From: CharSyam @ 2026-06-08  5:38 UTC (permalink / raw)
  To: Hyunchul Lee; +Cc: Namjae Jeon, linux-fsdevel, linux-kernel

Hi, Hyunchul.

The current patch series was prepared on top of ntfs-next,
assuming that V4 0001–0004 had already been merged.
I'll resend the entire series as V6, including those patches,
to make the dependency explicit.

Thanks.
DaeMyung

2026년 6월 8일 (월) 오후 2:08, Hyunchul Lee <hyc.lee@gmail.com>님이 작성:
>
> Hi Daemyung,
>
> 2026년 6월 7일 (일) 오후 2:17, DaeMyung Kang <charsyam@gmail.com>님이 작성:
> >
> > The resident $INDEX_ROOT validator already checks the index root header
> > fields, but it still does not bound index_length through allocated_size or
> > ensure allocated_size stays within the resident index area.
> >
> > Callers consume index.allocated_size as the resident root capacity.
> > ntfs_ie_add() uses it to decide whether an insertion can be done in place,
> > and ntfs_ie_insert() then updates the root without re-checking the resident
> > value boundary.
> >
> > Read allocated_size in the resident $INDEX_ROOT validator, require it to be
> > 8-byte aligned, require index_length <= allocated_size, and require
> > allocated_size <= the resident index area. Valid slack remains allowed.
> >
> > Signed-off-by: DaeMyung Kang <charsyam@gmail.com>
> > ---
> >  fs/ntfs/attrib.c | 6 +++++-
> >  1 file changed, 5 insertions(+), 1 deletion(-)
> >
> > diff --git a/fs/ntfs/attrib.c b/fs/ntfs/attrib.c
> > index cf49eade6b22..49c8f1f3b9dd 100644
> > --- a/fs/ntfs/attrib.c
> > +++ b/fs/ntfs/attrib.c
> > @@ -657,15 +657,19 @@ static bool ntfs_index_root_attr_value_is_valid(const u8 *value, const u32 value
>
> Applying this patch failed.
> It seems that the patch below has not been merged yet.
> https://lore.kernel.org/all/20260530143514.3083601-7-charsyam@gmail.com/
>
> >         u32 index_size;
> >         u32 entries_offset;
> >         u32 index_length;
> > +       u32 allocated_size;
> >
> >         ir = (const struct index_root *)value;
> >         index_size = value_length - offsetof(struct index_root, index);
> >         entries_offset = le32_to_cpu(ir->index.entries_offset);
> >         index_length = le32_to_cpu(ir->index.index_length);
> > +       allocated_size = le32_to_cpu(ir->index.allocated_size);
> >
> > -       if ((entries_offset | index_length) & 7 ||
> > +       if ((entries_offset | index_length | allocated_size) & 7 ||
> >             entries_offset < sizeof(struct index_header) ||
> >             entries_offset > index_length ||
> > +           index_length > allocated_size ||
> > +           allocated_size > index_size ||
> >             index_length - entries_offset < sizeof(struct index_entry_header))
> >                 return false;
> >
> > --
> > 2.43.0
>
>
>
> --
> Thanks,
> Hyunchul

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2026-06-08  5:39 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-06-07  5:17 [PATCH v5 0/4] ntfs: finish index root lookup validation DaeMyung Kang
2026-06-07  5:17 ` [PATCH v5 1/4] ntfs: reject non-resident records for resident-only attributes DaeMyung Kang
2026-06-07  5:17 ` [PATCH v5 2/4] ntfs: grow index root value before reparent header update DaeMyung Kang
2026-06-07  5:17 ` [PATCH v5 3/4] ntfs: update index root allocated size before shrink DaeMyung Kang
2026-06-07  5:17 ` [PATCH v5 4/4] ntfs: validate index root allocated_size on lookup DaeMyung Kang
2026-06-08  5:08   ` Hyunchul Lee
2026-06-08  5:38     ` CharSyam

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®