mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-31 14:04:27 -04:00
ntfs: return errors from ntfs_attr_readall
ntfs_attr_readall() currently loses the failure reason for attribute lookup, allocation, and read failures by returning NULL. Return ERR_PTR() with the original error instead. The reparse parser can then propagate allocation and I/O errors without treating them as filesystem corruption. Signed-off-by: Hyunchul Lee <hyc.lee@gmail.com> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
This commit is contained in:
committed by
Namjae Jeon
parent
d38ce59d16
commit
56cc42a7b3
@@ -5296,6 +5296,7 @@ int ntfs_attr_remove(struct ntfs_inode *ni, const __le32 type, __le16 *name,
|
||||
* On success a buffer is allocated with the content of the attribute
|
||||
* and which needs to be freed when it's not needed anymore. If the
|
||||
* @data_size parameter is non-NULL then the data size is set there.
|
||||
* On error, an ERR_PTR() containing the negative error code is returned.
|
||||
*/
|
||||
void *ntfs_attr_readall(struct ntfs_inode *ni, const __le32 type,
|
||||
__le16 *name, u32 name_len, s64 *data_size)
|
||||
@@ -5310,6 +5311,7 @@ void *ntfs_attr_readall(struct ntfs_inode *ni, const __le32 type,
|
||||
|
||||
bmp_vi = ntfs_attr_iget(VFS_I(ni), type, name, name_len);
|
||||
if (IS_ERR(bmp_vi)) {
|
||||
ret = ERR_PTR(PTR_ERR(bmp_vi));
|
||||
ntfs_debug("ntfs_attr_iget failed");
|
||||
goto err_exit;
|
||||
}
|
||||
@@ -5319,17 +5321,21 @@ void *ntfs_attr_readall(struct ntfs_inode *ni, const __le32 type,
|
||||
(bmp_ni->type != AT_BITMAP ||
|
||||
bmp_ni->data_size > ((ni->vol->nr_clusters + 7) >> 3))) {
|
||||
ntfs_error(sb, "Invalid attribute data size");
|
||||
ret = ERR_PTR(-EIO);
|
||||
goto out;
|
||||
}
|
||||
|
||||
data = kvmalloc(bmp_ni->data_size, GFP_NOFS);
|
||||
if (!data)
|
||||
if (!data) {
|
||||
ret = ERR_PTR(-ENOMEM);
|
||||
goto out;
|
||||
}
|
||||
|
||||
size = ntfs_inode_attr_pread(VFS_I(bmp_ni), 0, bmp_ni->data_size,
|
||||
(u8 *)data);
|
||||
if (size != bmp_ni->data_size) {
|
||||
ntfs_error(sb, "ntfs_attr_pread failed");
|
||||
ret = size < 0 ? ERR_PTR((int)size) : ERR_PTR(-EIO);
|
||||
kvfree(data);
|
||||
goto out;
|
||||
}
|
||||
|
||||
38
fs/ntfs/ea.c
38
fs/ntfs/ea.c
@@ -122,17 +122,19 @@ static int ntfs_get_ea(struct inode *inode, const char *name, size_t name_len,
|
||||
|
||||
p_ea_info = ntfs_attr_readall(ni, AT_EA_INFORMATION, NULL, 0,
|
||||
&ea_info_size);
|
||||
if (!p_ea_info || ea_info_size != sizeof(struct ea_information)) {
|
||||
if (IS_ERR(p_ea_info))
|
||||
return PTR_ERR(p_ea_info);
|
||||
if (ea_info_size != sizeof(struct ea_information)) {
|
||||
kvfree(p_ea_info);
|
||||
return -ENODATA;
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
ea_info_qlen = le32_to_cpu(p_ea_info->ea_query_length);
|
||||
kvfree(p_ea_info);
|
||||
|
||||
ea_buf = ntfs_attr_readall(ni, AT_EA, NULL, 0, &all_ea_size);
|
||||
if (!ea_buf)
|
||||
return -ENODATA;
|
||||
if (IS_ERR(ea_buf))
|
||||
return PTR_ERR(ea_buf);
|
||||
|
||||
if (ea_info_qlen > all_ea_size) {
|
||||
err = -EIO;
|
||||
@@ -208,10 +210,22 @@ static int ntfs_set_ea(struct inode *inode, const char *name, size_t name_len,
|
||||
if (ntfs_attr_exist(ni, AT_EA_INFORMATION, AT_UNNAMED, 0)) {
|
||||
p_ea_info = ntfs_attr_readall(ni, AT_EA_INFORMATION, NULL, 0,
|
||||
&ea_info_size);
|
||||
if (!p_ea_info || ea_info_size != sizeof(struct ea_information))
|
||||
if (IS_ERR(p_ea_info)) {
|
||||
err = PTR_ERR(p_ea_info);
|
||||
p_ea_info = NULL;
|
||||
goto out;
|
||||
}
|
||||
if (ea_info_size != sizeof(struct ea_information)) {
|
||||
err = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ea_buf = ntfs_attr_readall(ni, AT_EA, NULL, 0, &all_ea_size);
|
||||
if (IS_ERR(ea_buf)) {
|
||||
err = PTR_ERR(ea_buf);
|
||||
ea_buf = NULL;
|
||||
goto out;
|
||||
}
|
||||
if (!ea_buf) {
|
||||
ea_info_qsize = 0;
|
||||
kvfree(p_ea_info);
|
||||
@@ -514,14 +528,24 @@ ssize_t ntfs_listxattr(struct dentry *dentry, char *buffer, size_t size)
|
||||
mutex_lock(&NTFS_I(inode)->mrec_lock);
|
||||
ea_info = ntfs_attr_readall(ni, AT_EA_INFORMATION, NULL, 0,
|
||||
&ea_info_size);
|
||||
if (!ea_info || ea_info_size != sizeof(struct ea_information))
|
||||
if (IS_ERR(ea_info)) {
|
||||
err = PTR_ERR(ea_info);
|
||||
ea_info = NULL;
|
||||
goto out;
|
||||
}
|
||||
if (ea_info_size != sizeof(struct ea_information)) {
|
||||
err = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ea_info_qsize = le32_to_cpu(ea_info->ea_query_length);
|
||||
|
||||
ea_buf = ntfs_attr_readall(ni, AT_EA, NULL, 0, &ea_buf_size);
|
||||
if (!ea_buf)
|
||||
if (IS_ERR(ea_buf)) {
|
||||
err = PTR_ERR(ea_buf);
|
||||
ea_buf = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (ea_info_qsize > ea_buf_size || ea_info_qsize == 0)
|
||||
goto out;
|
||||
|
||||
@@ -1108,8 +1108,8 @@ static s64 ntfs_ibm_get_free(struct ntfs_index_context *icx)
|
||||
|
||||
bm = ntfs_attr_readall(icx->idx_ni, AT_BITMAP, icx->name, icx->name_len,
|
||||
&size);
|
||||
if (!bm)
|
||||
return -EIO;
|
||||
if (IS_ERR(bm))
|
||||
return PTR_ERR(bm);
|
||||
|
||||
for (byte = 0; byte < size; byte++) {
|
||||
if (bm[byte] == 255)
|
||||
|
||||
@@ -256,6 +256,8 @@ unsigned int ntfs_make_symlink(struct ntfs_inode *ni)
|
||||
|
||||
reparse_attr = ntfs_attr_readall(ni, AT_REPARSE_POINT, NULL, 0,
|
||||
&attr_size);
|
||||
if (IS_ERR(reparse_attr))
|
||||
reparse_attr = NULL;
|
||||
if (reparse_attr &&
|
||||
valid_reparse_data(ni, reparse_attr, attr_size)) {
|
||||
err = -EINVAL;
|
||||
@@ -335,6 +337,8 @@ unsigned int ntfs_reparse_tag_dt_types(struct ntfs_volume *vol, unsigned long mr
|
||||
|
||||
reparse_attr = (struct reparse_point *)ntfs_attr_readall(NTFS_I(vi),
|
||||
AT_REPARSE_POINT, NULL, 0, &attr_size);
|
||||
if (IS_ERR(reparse_attr))
|
||||
reparse_attr = NULL;
|
||||
|
||||
if (reparse_attr && attr_size >= sizeof(*reparse_attr)) {
|
||||
switch (reparse_attr->reparse_tag) {
|
||||
|
||||
Reference in New Issue
Block a user