mirror of
https://github.com/torvalds/linux.git
synced 2026-11-10 17:11:02 +01:00
ntfs: validate attribute-list sizes before allocation
The NULL point dereference could occur when an on-disk
$ATTRIBUTE_LIST size was truncated before it was validated and allocated.
To fix this issue and prevent excessive memory allocation, limit the
$ATTRIBUTE_LIST size to 256 KiB.
The following existing implementation and Windows test provide evidence
for this 256 KiB compatibility limit:
NTFS already treats 256 KiB as the $ATTRIBUTE_LIST limit in its
attribute-size checks and $MFT attribute list repack/expand paths.
For additional Windows testing, when $MFT's attribute-list data_size was
above 256 KiB, Windows attached the disk partition but did not mount a NTFS
volume and target access failed.
Fixes: af0db57d42 ("ntfs: update inode operations")
Link: https://lore.kernel.org/ntfs/88468.1790006025@30-10-12.wireless.csail.mit.edu/T/#u
Cc: stable@vger.kernel.org
Cc: Robert Morris <rtm@mit.edu>
Signed-off-by: Hyunchul Lee <hyc.lee@gmail.com>
Reviewed-by: Baolin Liu <liubaolin@kylinos.cn>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
This commit is contained in:
parent
749357bd48
commit
ca43660672
|
|
@ -1775,7 +1775,7 @@ int ntfs_attr_size_bounds_check(const struct ntfs_volume *vol, const __le32 type
|
|||
* $ATTRIBUTE_LIST has a maximum size of 256kiB, but this is not
|
||||
* listed in $AttrDef.
|
||||
*/
|
||||
if (unlikely(type == AT_ATTRIBUTE_LIST && size > 256 * 1024))
|
||||
if (unlikely(type == AT_ATTRIBUTE_LIST && size > NTFS_MAX_ATTR_LIST_SIZE))
|
||||
return -ERANGE;
|
||||
/* Get the $AttrDef entry for the attribute @type. */
|
||||
ad = ntfs_attr_find_in_attrdef(vol, type);
|
||||
|
|
|
|||
|
|
@ -14,8 +14,6 @@
|
|||
#include "attrlist.h"
|
||||
#include "lcnalloc.h"
|
||||
|
||||
#define NTFS_MAX_ATTR_LIST_SIZE (256 * 1024)
|
||||
|
||||
/*
|
||||
* ntfs_attrlist_need - check whether inode need attribute list
|
||||
* @ni: opened ntfs inode for which perform check
|
||||
|
|
|
|||
|
|
@ -805,6 +805,8 @@ static int ntfs_read_locked_inode(struct inode *vi)
|
|||
goto unm_err_out;
|
||||
}
|
||||
} else {
|
||||
s64 attr_list_size;
|
||||
|
||||
if (vi->i_ino == FILE_MFT)
|
||||
goto skip_attr_list_load;
|
||||
ntfs_debug("Attribute list found in inode 0x%llx.", ni->mft_no);
|
||||
|
|
@ -827,11 +829,14 @@ static int ntfs_read_locked_inode(struct inode *vi)
|
|||
ni->mft_no);
|
||||
}
|
||||
/* Now allocate memory for the attribute list. */
|
||||
ni->attr_list_size = (u32)ntfs_attr_size(a);
|
||||
if (!ni->attr_list_size) {
|
||||
ntfs_error(vi->i_sb, "Attr_list_size is zero");
|
||||
attr_list_size = ntfs_attr_size(a);
|
||||
if (attr_list_size <= 0 ||
|
||||
attr_list_size > NTFS_MAX_ATTR_LIST_SIZE) {
|
||||
ntfs_error(vi->i_sb, "Invalid attribute list size %lld (mft_no 0x%llx).",
|
||||
(long long)attr_list_size, ni->mft_no);
|
||||
goto unm_err_out;
|
||||
}
|
||||
ni->attr_list_size = (u32)attr_list_size;
|
||||
ni->attr_list = kvzalloc(ni->attr_list_size, GFP_NOFS);
|
||||
if (!ni->attr_list) {
|
||||
ntfs_error(vi->i_sb,
|
||||
|
|
@ -1955,6 +1960,7 @@ int ntfs_read_inode_mount(struct inode *vi)
|
|||
} else /* if (!err) */ {
|
||||
struct attr_list_entry *al_entry, *next_al_entry;
|
||||
u8 *al_end;
|
||||
s64 attr_list_size;
|
||||
static const char *es = " Not allowed. $MFT is corrupt. You should run chkdsk.";
|
||||
|
||||
ntfs_debug("Attribute list attribute found in $MFT.");
|
||||
|
|
@ -1978,11 +1984,14 @@ int ntfs_read_inode_mount(struct inode *vi)
|
|||
"Resident attribute list attribute in $MFT system file is marked encrypted/sparse which is not true. However, Windows allows this and chkdsk does not detect or correct it so we will just ignore the invalid flags and pretend they are not set.");
|
||||
}
|
||||
/* Now allocate memory for the attribute list. */
|
||||
ni->attr_list_size = (u32)ntfs_attr_size(a);
|
||||
if (!ni->attr_list_size) {
|
||||
ntfs_error(sb, "Attr_list_size is zero");
|
||||
attr_list_size = ntfs_attr_size(a);
|
||||
if (attr_list_size <= 0 ||
|
||||
attr_list_size > NTFS_MAX_ATTR_LIST_SIZE) {
|
||||
ntfs_error(sb, "Invalid attribute list size %lld (mft_no 0x%llx).%s",
|
||||
(long long)attr_list_size, ni->mft_no, es);
|
||||
goto put_err_out;
|
||||
}
|
||||
ni->attr_list_size = (u32)attr_list_size;
|
||||
ni->attr_list = kvzalloc(round_up(ni->attr_list_size, SECTOR_SIZE),
|
||||
GFP_NOFS);
|
||||
if (!ni->attr_list) {
|
||||
|
|
|
|||
|
|
@ -80,6 +80,8 @@ enum {
|
|||
NTFS_MAX_LABEL_LEN = 128,
|
||||
};
|
||||
|
||||
#define NTFS_MAX_ATTR_LIST_SIZE (256 * 1024)
|
||||
|
||||
enum {
|
||||
CASE_SENSITIVE = 0,
|
||||
IGNORE_CASE = 1,
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user