diff options
| author | Hyunchul Lee <hyc.lee@gmail.com> | 2026-03-09 16:06:46 +0900 |
|---|---|---|
| committer | Namjae Jeon <linkinjeon@kernel.org> | 2026-03-16 20:27:38 +0900 |
| commit | c451d34ae14201c2bb40652bf74072a79ff82f7d (patch) | |
| tree | c0096c2858635cee90499222324839a0769b3d08 | |
| parent | 10993e525b1ee81cbe02a8ca7d0005712f6b3d82 (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.c | 36 |
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; |
