summaryrefslogtreecommitdiff
path: root/fs/ntfs
diff options
context:
space:
mode:
authorHyunchul Lee <hyc.lee@gmail.com>2026-03-09 16:40:09 +0900
committerNamjae Jeon <linkinjeon@kernel.org>2026-03-16 20:27:40 +0900
commite6a95c5a8066b4d6a74651f89612f13ed1a03fe6 (patch)
tree272a88cec39d0e07a8bac555703dfd511b1d3ab7 /fs/ntfs
parentc451d34ae14201c2bb40652bf74072a79ff82f7d (diff)
ntfs: harden ntfs_listxattr against EA entries
Validate every EA entry only if the buffer length is required to prevent large memory allocation. Signed-off-by: Hyunchul Lee <hyc.lee@gmail.com> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Diffstat (limited to 'fs/ntfs')
-rw-r--r--fs/ntfs/ea.c40
1 files changed, 22 insertions, 18 deletions
diff --git a/fs/ntfs/ea.c b/fs/ntfs/ea.c
index 813c7b3b45d9..ee99baf9c7d2 100644
--- a/fs/ntfs/ea.c
+++ b/fs/ntfs/ea.c
@@ -450,7 +450,9 @@ ssize_t ntfs_listxattr(struct dentry *dentry, char *buffer, size_t size)
struct ntfs_inode *ni = NTFS_I(inode);
const struct ea_attr *p_ea;
s64 offset, ea_buf_size, ea_info_size;
- int next, err = 0, ea_size;
+ s64 ea_size;
+ u32 next;
+ int err = 0;
u32 ea_info_qsize;
char *ea_buf = NULL;
ssize_t ret = 0;
@@ -471,43 +473,45 @@ ssize_t ntfs_listxattr(struct dentry *dentry, char *buffer, size_t size)
if (!ea_buf)
goto out;
- if (ea_info_qsize > ea_buf_size)
+ if (ea_info_qsize > ea_buf_size || ea_info_qsize == 0)
goto out;
- if (ea_buf_size < sizeof(struct ea_attr))
+ if (ea_info_qsize < sizeof(struct ea_attr)) {
+ err = -EIO;
goto out;
+ }
offset = 0;
do {
p_ea = (const struct ea_attr *)&ea_buf[offset];
next = le32_to_cpu(p_ea->next_entry_offset);
- if (next)
- ea_size = next;
- else
- ea_size = ALIGN(struct_size(p_ea, ea_name,
- 1 + p_ea->ea_name_length +
- le16_to_cpu(p_ea->ea_value_length)),
- 4);
- if (buffer) {
- if (offset + ea_size > ea_info_qsize)
- break;
+ ea_size = next ? next : (ea_info_qsize - offset);
+
+ if (ea_size < sizeof(struct ea_attr) ||
+ offset + ea_size > ea_info_qsize) {
+ err = -EIO;
+ goto out;
+ }
+ if ((int)p_ea->ea_name_length + 1 >
+ ea_size - offsetof(struct ea_attr, ea_name)) {
+ err = -EIO;
+ goto out;
+ }
+
+ if (buffer) {
if (ret + p_ea->ea_name_length + 1 > size) {
err = -ERANGE;
goto out;
}
- if (p_ea->ea_name_length + 1 > (ea_info_qsize - offset))
- break;
-
memcpy(buffer + ret, p_ea->ea_name, p_ea->ea_name_length);
buffer[ret + p_ea->ea_name_length] = 0;
}
ret += p_ea->ea_name_length + 1;
offset += ea_size;
- } while (next > 0 && offset < ea_info_qsize &&
- sizeof(struct ea_attr) < (ea_info_qsize - offset));
+ } while (next > 0 && offset < ea_info_qsize);
out:
mutex_unlock(&NTFS_I(inode)->mrec_lock);