Re: [PATCH 1/3] ntfs: return view index entry data from lookup

From: Hyunchul Lee

Date: Tue May 12 2026 - 22:15:05 EST


2026년 5월 12일 (화) 오전 1:06, DaeMyung Kang <charsyam@xxxxxxxxx>님이 작성:
>
> ntfs_index_lookup() always exposes the matched entry key through
> icx->data. That is correct for file name indexes, where $I30 callers
> expect the key to be a struct file_name_attr and update it in place.
>
> NTFS view indexes store a separate value in index_entry.data.vi. For
> example, $Quota/$Q uses the owner_id as the key and stores the
> quota_control_entry in the entry value. Returning the key makes quota code
> see only the 4-byte owner_id instead of the quota control entry.
>
> Preserve the existing $FILE_NAME index behavior, but return the entry value
> for view indexes. Use the index root type for that layout decision:
> indexes with ir->type == AT_FILE_NAME expose the entry key, while view
> indexes have type 0 and expose the entry value through data.vi. Validate
> the value offset and length before exposing the pointer, and clear
> icx->data when the key is not found because the context then describes an
> insertion point rather than a matched value. Use unsigned arithmetic for
> the minimum data offset check, account for the VCN stored at the end of
> INDEX_ENTRY_NODE entries, and clear the returned context pointers before
> returning an entry-data validation error.
>
> Move the matched-entry data exposure and validation into a small helper,
> ntfs_index_lookup_set_data(), so the done label stays flat and the bounds
> check has a single return.
>
> Signed-off-by: DaeMyung Kang <charsyam@xxxxxxxxx>

Looks good to me.

Reviewed-by: Hyunchul Lee <hyc.lee@xxxxxxxxx>

> ---
> fs/ntfs/index.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++++---
> fs/ntfs/index.h | 3 +-
> 2 files changed, 73 insertions(+), 5 deletions(-)
>
> diff --git a/fs/ntfs/index.c b/fs/ntfs/index.c
> index a547bdc..30dfcbb 100644
> --- a/fs/ntfs/index.c
> +++ b/fs/ntfs/index.c
> @@ -696,6 +696,53 @@ static int ntfs_icx_parent_dec(struct ntfs_index_context *icx)
> }
>
> /*
> + * ntfs_index_lookup_set_data - populate icx->data for the matched entry
> + *
> + * For directory $FILE_NAME indexes the caller updates the key in place, so
> + * expose the key. For view indexes the value lives at data.vi; validate
> + * its offset and length before exposing the pointer. Return 0 on success,
> + * or -EIO if the entry value is out of bounds.
> + */
> +static int ntfs_index_lookup_set_data(struct ntfs_index_context *icx,
> + struct index_root *ir,
> + struct index_entry *ie)
> +{
> + u16 data_len, data_off, entry_len, found_key_len;
> + unsigned int data_end, min_data_off;
> +
> + if (ie->flags & INDEX_ENTRY_END)
> + return -EIO;
> +
> + found_key_len = le16_to_cpu(ie->key_length);
> + if (ir->type == AT_FILE_NAME) {
> + icx->data = (u8 *)ie + offsetof(struct index_entry, key);
> + icx->data_len = found_key_len;
> + return 0;
> + }
> +
> + entry_len = le16_to_cpu(ie->length);
> + data_off = le16_to_cpu(ie->data.vi.data_offset);
> + data_len = le16_to_cpu(ie->data.vi.data_length);
> + data_end = entry_len;
> + if (ie->flags & INDEX_ENTRY_NODE) {
> + /* The trailing child VCN is not part of the entry value. */
> + if (data_end < sizeof(s64))
> + return -EIO;
> + data_end -= sizeof(s64);
> + }
> +
> + min_data_off = offsetof(struct index_entry, key) + found_key_len;
> + if (data_off < min_data_off || data_off > data_end)
> + return -EIO;
> + if (data_len > data_end - data_off)
> + return -EIO;
> +
> + icx->data = (u8 *)ie + data_off;
> + icx->data_len = data_len;
> + return 0;
> +}
> +
> +/*
> * ntfs_index_lookup - find a key in an index and return its index entry
> * @key: key for which to search in the index
> * @key_len: length of @key in bytes
> @@ -710,7 +757,8 @@ static int ntfs_icx_parent_dec(struct ntfs_index_context *icx)
> * If the @key is found in the index, 0 is returned and @icx is setup to
> * describe the index entry containing the matching @key. @icx->entry is the
> * index entry and @icx->data and @icx->data_len are the index entry data and
> - * its length in bytes, respectively.
> + * its length in bytes, respectively. For file name indexes @icx->data points
> + * to the entry key; for view indexes @icx->data points to the entry value.
> *
> * If the @key is not found in the index, -ENOENT is returned and
> * @icx is setup to describe the index entry whose key collates immediately
> @@ -836,11 +884,30 @@ err_out:
> return err;
> done:
> icx->entry = ie;
> - icx->data = (u8 *)ie + offsetof(struct index_entry, key);
> - icx->data_len = le16_to_cpu(ie->key_length);
> + if (err) {
> + /* When the key is not found, ie is an insertion point. */
> + icx->data = NULL;
> + icx->data_len = 0;
> + ntfs_debug("Done.\n");
> + return err;
> + }
> + err = ntfs_index_lookup_set_data(icx, ir, ie);
> + if (err) {
> + ntfs_error(sb,
> + "Index entry data out of bounds in inode 0x%llx.",
> + (unsigned long long)ni->mft_no);
> + icx->entry = NULL;
> + icx->data = NULL;
> + icx->data_len = 0;
> + if (!icx->is_in_root) {
> + kvfree(ib);
> + ib = NULL;
> + icx->ib = NULL;
> + }
> + goto err_out;
> + }
> ntfs_debug("Done.\n");
> return err;
> -
> }
>
> static struct index_block *ntfs_ib_alloc(s64 ib_vcn, u32 ib_size,
> diff --git a/fs/ntfs/index.h b/fs/ntfs/index.h
> index e68d6fa..4b8c5c8 100644
> --- a/fs/ntfs/index.h
> +++ b/fs/ntfs/index.h
> @@ -58,7 +58,8 @@
> * To obtain a context call ntfs_index_ctx_get().
> *
> * We use this context to allow ntfs_index_lookup() to return the found index
> * @entry and its @data without having to allocate a buffer and copy the @entry
> - * and/or its @data into it.
> + * and/or its @data into it. For file name indexes @data points to the entry
> + * key; for view indexes @data points to the entry value.
> *
> * When finished with the @entry and its @data, call ntfs_index_ctx_put() to
> * free the context and other associated resources.
> --
> 2.43.0



--
Thanks,
Hyunchul