Skip to content

Commit 8ca1ed2

Browse files
hclee1Naim
authored andcommitted
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>
1 parent 6460f9a commit 8ca1ed2

1 file changed

Lines changed: 22 additions & 18 deletions

File tree

fs/ntfs/ea.c

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -450,7 +450,9 @@ ssize_t ntfs_listxattr(struct dentry *dentry, char *buffer, size_t size)
450450
struct ntfs_inode *ni = NTFS_I(inode);
451451
const struct ea_attr *p_ea;
452452
s64 offset, ea_buf_size, ea_info_size;
453-
int next, err = 0, ea_size;
453+
s64 ea_size;
454+
u32 next;
455+
int err = 0;
454456
u32 ea_info_qsize;
455457
char *ea_buf = NULL;
456458
ssize_t ret = 0;
@@ -471,43 +473,45 @@ ssize_t ntfs_listxattr(struct dentry *dentry, char *buffer, size_t size)
471473
if (!ea_buf)
472474
goto out;
473475

474-
if (ea_info_qsize > ea_buf_size)
476+
if (ea_info_qsize > ea_buf_size || ea_info_qsize == 0)
475477
goto out;
476478

477-
if (ea_buf_size < sizeof(struct ea_attr))
479+
if (ea_info_qsize < sizeof(struct ea_attr)) {
480+
err = -EIO;
478481
goto out;
482+
}
479483

480484
offset = 0;
481485
do {
482486
p_ea = (const struct ea_attr *)&ea_buf[offset];
483487
next = le32_to_cpu(p_ea->next_entry_offset);
484-
if (next)
485-
ea_size = next;
486-
else
487-
ea_size = ALIGN(struct_size(p_ea, ea_name,
488-
1 + p_ea->ea_name_length +
489-
le16_to_cpu(p_ea->ea_value_length)),
490-
4);
491-
if (buffer) {
492-
if (offset + ea_size > ea_info_qsize)
493-
break;
488+
ea_size = next ? next : (ea_info_qsize - offset);
489+
490+
if (ea_size < sizeof(struct ea_attr) ||
491+
offset + ea_size > ea_info_qsize) {
492+
err = -EIO;
493+
goto out;
494+
}
494495

496+
if ((int)p_ea->ea_name_length + 1 >
497+
ea_size - offsetof(struct ea_attr, ea_name)) {
498+
err = -EIO;
499+
goto out;
500+
}
501+
502+
if (buffer) {
495503
if (ret + p_ea->ea_name_length + 1 > size) {
496504
err = -ERANGE;
497505
goto out;
498506
}
499507

500-
if (p_ea->ea_name_length + 1 > (ea_info_qsize - offset))
501-
break;
502-
503508
memcpy(buffer + ret, p_ea->ea_name, p_ea->ea_name_length);
504509
buffer[ret + p_ea->ea_name_length] = 0;
505510
}
506511

507512
ret += p_ea->ea_name_length + 1;
508513
offset += ea_size;
509-
} while (next > 0 && offset < ea_info_qsize &&
510-
sizeof(struct ea_attr) < (ea_info_qsize - offset));
514+
} while (next > 0 && offset < ea_info_qsize);
511515

512516
out:
513517
mutex_unlock(&NTFS_I(inode)->mrec_lock);

0 commit comments

Comments
 (0)