summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHyunchul Lee <hyc.lee@gmail.com>2026-03-09 16:06:46 +0900
committerNamjae Jeon <linkinjeon@kernel.org>2026-03-16 20:27:38 +0900
commitc451d34ae14201c2bb40652bf74072a79ff82f7d (patch)
treec0096c2858635cee90499222324839a0769b3d08
parent10993e525b1ee81cbe02a8ca7d0005712f6b3d82 (diff)
ntfs: harden ntfs_ea_lookup against malformed EA entries
Validate p_ea->ea_name_length tightly, and the used entry size for every EA. Signed-off-by: Hyunchul Lee <hyc.lee@gmail.com> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
-rw-r--r--fs/ntfs/ea.c36
1 files changed, 17 insertions, 19 deletions
diff --git a/fs/ntfs/ea.c b/fs/ntfs/ea.c
index 115e3c5552a3..813c7b3b45d9 100644
--- a/fs/ntfs/ea.c
+++ b/fs/ntfs/ea.c
@@ -46,10 +46,11 @@ static int ntfs_write_ea(struct ntfs_inode *ni, __le32 type, char *value, s64 ea
}
static int ntfs_ea_lookup(char *ea_buf, s64 ea_buf_size, const char *name,
- int name_len, s64 *ea_offset, s64 *ea_size)
+ int name_len, s64 *ea_offset, s64 *ea_size)
{
const struct ea_attr *p_ea;
- s64 offset;
+ size_t actual_size;
+ loff_t offset, p_ea_size;
unsigned int next;
if (ea_buf_size < sizeof(struct ea_attr))
@@ -59,27 +60,25 @@ static int ntfs_ea_lookup(char *ea_buf, s64 ea_buf_size, const char *name,
do {
p_ea = (const struct ea_attr *)&ea_buf[offset];
next = le32_to_cpu(p_ea->next_entry_offset);
+ p_ea_size = next ? next : (ea_buf_size - offset);
- if (offset + next > ea_buf_size ||
- ((1 + p_ea->ea_name_length) > (ea_buf_size - offset)))
+ if (p_ea_size < sizeof(struct ea_attr) ||
+ offset + p_ea_size > ea_buf_size)
+ break;
+
+ if ((s64)p_ea->ea_name_length + 1 >
+ p_ea_size - offsetof(struct ea_attr, ea_name))
+ break;
+
+ actual_size = ALIGN(struct_size(p_ea, ea_name, 1 + p_ea->ea_name_length +
+ le16_to_cpu(p_ea->ea_value_length)), 4);
+ if (actual_size > p_ea_size)
break;
if (p_ea->ea_name_length == name_len &&
!memcmp(p_ea->ea_name, name, name_len)) {
*ea_offset = offset;
- if (next)
- *ea_size = next;
- else {
- unsigned int ea_len = 1 + p_ea->ea_name_length +
- le16_to_cpu(p_ea->ea_value_length);
-
- if ((ea_buf_size - offset) < ea_len)
- goto out;
-
- *ea_size = ALIGN(struct_size(p_ea, ea_name,
- 1 + p_ea->ea_name_length +
- le16_to_cpu(p_ea->ea_value_length)), 4);
- }
+ *ea_size = next ? next : actual_size;
if (ea_buf_size < *ea_offset + *ea_size)
goto out;
@@ -87,8 +86,7 @@ static int ntfs_ea_lookup(char *ea_buf, s64 ea_buf_size, const char *name,
return 0;
}
offset += next;
- } while (next > 0 && offset < ea_buf_size &&
- sizeof(struct ea_attr) < (ea_buf_size - offset));
+ } while (next > 0 && offset < ea_buf_size);
out:
return -ENOENT;