summaryrefslogtreecommitdiff
path: root/fs/ntfs/inode.c
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>2026-07-24 16:21:27 +0200
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2026-07-24 16:21:27 +0200
commit8f9aa2c90530ab92301a82231ae44f3722becd93 (patch)
treefb282e955b0a880b07131a135257fe3ec764e928 /fs/ntfs/inode.c
parent93467b31bec6da512b51544e5e4584f2745e995e (diff)
parent155b42bec9cbb6b8cdc47dd9bd09503a81fbe493 (diff)
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'fs/ntfs/inode.c')
-rw-r--r--fs/ntfs/inode.c38
1 files changed, 25 insertions, 13 deletions
diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c
index 360bebd1ee3f..f577f7abed54 100644
--- a/fs/ntfs/inode.c
+++ b/fs/ntfs/inode.c
@@ -848,6 +848,12 @@ static int ntfs_read_locked_inode(struct inode *vi)
a->data.resident.value_offset),
le32_to_cpu(
a->data.resident.value_length));
+ /* A resident list is not validated on load; check it now. */
+ if (!ntfs_attr_list_is_valid(ni->attr_list,
+ ni->attr_list_size)) {
+ ntfs_error(vi->i_sb, "Corrupt attribute list.");
+ goto unm_err_out;
+ }
}
}
skip_attr_list_load:
@@ -890,7 +896,6 @@ skip_attr_list_load:
*/
if (S_ISDIR(vi->i_mode)) {
struct index_root *ir;
- u8 *ir_end, *index_end;
view_index_meta:
/* It is a directory, find index root attribute. */
@@ -940,10 +945,9 @@ view_index_meta:
}
ir = (struct index_root *)((u8 *)a +
le16_to_cpu(a->data.resident.value_offset));
- ir_end = (u8 *)ir + le32_to_cpu(a->data.resident.value_length);
- index_end = (u8 *)&ir->index +
- le32_to_cpu(ir->index.index_length);
- if (index_end > ir_end) {
+ if (ntfs_index_root_inconsistent(ni->vol, a, ir, ni->mft_no) ||
+ ntfs_index_entries_inconsistent(ni->vol, &ir->index,
+ ir->collation_rule, ni->mft_no)) {
ntfs_error(vi->i_sb, "Directory index is corrupt.");
goto unm_err_out;
}
@@ -1180,6 +1184,15 @@ no_data_attr_special_case:
vi->i_flags |= S_IMMUTABLE;
/*
+ * System files such as $Bitmap and $MFT are maintained by the driver
+ * itself, and writing them from userspace corrupts the volume.
+ * Always make them immutable regardless of the sys_immutable option.
+ * Directories are skipped so the root and $Extend stay usable.
+ */
+ if (ni->mft_no < FILE_first_user && S_ISREG(vi->i_mode))
+ vi->i_flags |= S_IMMUTABLE;
+
+ /*
* The number of 512-byte blocks used on disk (for stat). This is in so
* far inaccurate as it doesn't account for any named streams or other
* special non-resident attributes, but that is how Windows works, too,
@@ -1195,6 +1208,9 @@ no_data_attr_special_case:
else
vi->i_blocks = ni->allocated_size >> 9;
+ if (S_ISLNK(vi->i_mode) && ni->target)
+ vi->i_size = strlen(ni->target);
+
ntfs_debug("Done.");
return 0;
unm_err_out:
@@ -1483,7 +1499,6 @@ static int ntfs_read_locked_index_inode(struct inode *base_vi, struct inode *vi)
struct attr_record *a;
struct ntfs_attr_search_ctx *ctx;
struct index_root *ir;
- u8 *ir_end, *index_end;
int err = 0;
ntfs_debug("Entering for i_ino 0x%llx.", ni->mft_no);
@@ -1534,9 +1549,9 @@ static int ntfs_read_locked_index_inode(struct inode *base_vi, struct inode *vi)
}
ir = (struct index_root *)((u8 *)a + le16_to_cpu(a->data.resident.value_offset));
- ir_end = (u8 *)ir + le32_to_cpu(a->data.resident.value_length);
- index_end = (u8 *)&ir->index + le32_to_cpu(ir->index.index_length);
- if (index_end > ir_end) {
+ if (ntfs_index_root_inconsistent(vol, a, ir, ni->mft_no) ||
+ ntfs_index_entries_inconsistent(vol, &ir->index,
+ ir->collation_rule, ni->mft_no)) {
ntfs_error(vi->i_sb, "Index is corrupt.");
goto unm_err_out;
}
@@ -1994,10 +2009,7 @@ int ntfs_read_inode_mount(struct inode *vi)
/* Catch the end of the attribute list. */
if ((u8 *)al_entry == al_end)
goto em_put_err_out;
- if (!al_entry->length)
- goto em_put_err_out;
- if ((u8 *)al_entry + 6 > al_end ||
- (u8 *)al_entry + le16_to_cpu(al_entry->length) > al_end)
+ if (!ntfs_attr_list_entry_is_valid(al_entry, al_end))
goto em_put_err_out;
next_al_entry = (struct attr_list_entry *)((u8 *)al_entry +
le16_to_cpu(al_entry->length));