Commit 31a17efa authored by Anton Altaparmakov's avatar Anton Altaparmakov Committed by Richard Russon

NTFS: Check for location of attribute name and improve error handling in

      general in fs/ntfs/inode.c::ntfs_read_locked_inode() and friends.
Signed-off-by: default avatarAnton Altaparmakov <aia21@cantab.net>
parent fd07cb99
......@@ -40,6 +40,8 @@ ToDo/Notes:
analagous to the way it is done in __set_page_dirty_buffers().
- Ensure the mft record size does not exceed the PAGE_CACHE_SIZE at
mount time as this cannot work with the current implementation.
- Check for location of attribute name and improve error handling in
general in fs/ntfs/inode.c::ntfs_read_locked_inode() and friends.
2.1.21 - Fix some races and bugs, rewrite mft write code, add mft allocator.
......
......@@ -564,13 +564,11 @@ static int ntfs_read_locked_inode(struct inode *vi)
}
if (!(m->flags & MFT_RECORD_IN_USE)) {
ntfs_error(vi->i_sb, "Inode is not in use! You should "
"run chkdsk.");
ntfs_error(vi->i_sb, "Inode is not in use!");
goto unm_err_out;
}
if (m->base_mft_record) {
ntfs_error(vi->i_sb, "Inode is an extent inode! You should "
"run chkdsk.");
ntfs_error(vi->i_sb, "Inode is an extent inode!");
goto unm_err_out;
}
......@@ -667,7 +665,7 @@ static int ntfs_read_locked_inode(struct inode *vi)
if (err) {
if (unlikely(err != -ENOENT)) {
ntfs_error(vi->i_sb, "Failed to lookup attribute list "
"attribute. You should run chkdsk.");
"attribute.");
goto unm_err_out;
}
} else /* if (!err) */ {
......@@ -679,9 +677,7 @@ static int ntfs_read_locked_inode(struct inode *vi)
ctx->attr->flags & ATTR_COMPRESSION_MASK ||
ctx->attr->flags & ATTR_IS_SPARSE) {
ntfs_error(vi->i_sb, "Attribute list attribute is "
"compressed/encrypted/sparse. Not "
"allowed. Corrupt inode. You should "
"run chkdsk.");
"compressed/encrypted/sparse.");
goto unm_err_out;
}
/* Now allocate memory for the attribute list. */
......@@ -697,9 +693,7 @@ static int ntfs_read_locked_inode(struct inode *vi)
NInoSetAttrListNonResident(ni);
if (ctx->attr->data.non_resident.lowest_vcn) {
ntfs_error(vi->i_sb, "Attribute list has non "
"zero lowest_vcn. Inode is "
"corrupt. You should run "
"chkdsk.");
"zero lowest_vcn.");
goto unm_err_out;
}
/*
......@@ -712,10 +706,7 @@ static int ntfs_read_locked_inode(struct inode *vi)
err = PTR_ERR(ni->attr_list_rl.rl);
ni->attr_list_rl.rl = NULL;
ntfs_error(vi->i_sb, "Mapping pairs "
"decompression failed with "
"error code %i. Corrupt "
"attribute list in inode.",
-err);
"decompression failed.");
goto unm_err_out;
}
/* Now load the attribute list. */
......@@ -770,9 +761,18 @@ static int ntfs_read_locked_inode(struct inode *vi)
goto unm_err_out;
}
/* Set up the state. */
if (ctx->attr->non_resident) {
ntfs_error(vi->i_sb, "$INDEX_ROOT attribute is "
"not resident. Not allowed.");
if (unlikely(ctx->attr->non_resident)) {
ntfs_error(vol->sb, "$INDEX_ROOT attribute is not "
"resident.");
goto unm_err_out;
}
/* Ensure the attribute name is placed before the value. */
if (unlikely(ctx->attr->name_length &&
(le16_to_cpu(ctx->attr->name_offset) >=
le16_to_cpu(ctx->attr->data.resident.
value_offset)))) {
ntfs_error(vol->sb, "$INDEX_ROOT attribute name is "
"placed after the attribute value.");
goto unm_err_out;
}
/*
......@@ -786,8 +786,7 @@ static int ntfs_read_locked_inode(struct inode *vi)
if (ctx->attr->flags & ATTR_IS_ENCRYPTED) {
if (ctx->attr->flags & ATTR_COMPRESSION_MASK) {
ntfs_error(vi->i_sb, "Found encrypted and "
"compressed attribute. Not "
"allowed.");
"compressed attribute.");
goto unm_err_out;
}
NInoSetEncrypted(ni);
......@@ -811,12 +810,12 @@ static int ntfs_read_locked_inode(struct inode *vi)
}
if (ir->type != AT_FILE_NAME) {
ntfs_error(vi->i_sb, "Indexed attribute is not "
"$FILE_NAME. Not allowed.");
"$FILE_NAME.");
goto unm_err_out;
}
if (ir->collation_rule != COLLATION_FILE_NAME) {
ntfs_error(vi->i_sb, "Index collation rule is not "
"COLLATION_FILE_NAME. Not allowed.");
"COLLATION_FILE_NAME.");
goto unm_err_out;
}
ni->itype.index.collation_rule = ir->collation_rule;
......@@ -883,8 +882,7 @@ static int ntfs_read_locked_inode(struct inode *vi)
if (err == -ENOENT)
ntfs_error(vi->i_sb, "$INDEX_ALLOCATION "
"attribute is not present but "
"$INDEX_ROOT indicated it "
"is.");
"$INDEX_ROOT indicated it is.");
else
ntfs_error(vi->i_sb, "Failed to lookup "
"$INDEX_ALLOCATION "
......@@ -896,6 +894,19 @@ static int ntfs_read_locked_inode(struct inode *vi)
"is resident.");
goto unm_err_out;
}
/*
* Ensure the attribute name is placed before the mapping pairs
* array.
*/
if (unlikely(ctx->attr->name_length &&
(le16_to_cpu(ctx->attr->name_offset) >=
le16_to_cpu(ctx->attr->data.non_resident.
mapping_pairs_offset)))) {
ntfs_error(vol->sb, "$INDEX_ALLOCATION attribute name "
"is placed after the mapping pairs "
"array.");
goto unm_err_out;
}
if (ctx->attr->flags & ATTR_IS_ENCRYPTED) {
ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute "
"is encrypted.");
......@@ -914,8 +925,7 @@ static int ntfs_read_locked_inode(struct inode *vi)
if (ctx->attr->data.non_resident.lowest_vcn) {
ntfs_error(vi->i_sb, "First extent of "
"$INDEX_ALLOCATION attribute has non "
"zero lowest_vcn. Inode is corrupt. "
"You should run chkdsk.");
"zero lowest_vcn.");
goto unm_err_out;
}
vi->i_size = sle64_to_cpu(
......@@ -997,8 +1007,7 @@ static int ntfs_read_locked_inode(struct inode *vi)
goto no_data_attr_special_case;
// FIXME: File is corrupt! Hot-fix with empty data
// attribute if recovery option is set.
ntfs_error(vi->i_sb, "$DATA attribute is "
"missing.");
ntfs_error(vi->i_sb, "$DATA attribute is missing.");
goto unm_err_out;
}
/* Setup the state. */
......@@ -1029,9 +1038,7 @@ static int ntfs_read_locked_inode(struct inode *vi)
ntfs_error(vi->i_sb, "Found "
"nonstandard compression unit "
"(%u instead of 4). Cannot "
"handle this. This might "
"indicate corruption so you "
"should run chkdsk.",
"handle this.",
ctx->attr->data.non_resident.
compression_unit);
err = -EOPNOTSUPP;
......@@ -1057,8 +1064,7 @@ static int ntfs_read_locked_inode(struct inode *vi)
if (ctx->attr->data.non_resident.lowest_vcn) {
ntfs_error(vi->i_sb, "First extent of $DATA "
"attribute has non zero "
"lowest_vcn. Inode is corrupt. "
"You should run chkdsk.");
"lowest_vcn.");
goto unm_err_out;
}
/* Setup all the sizes. */
......@@ -1127,9 +1133,11 @@ static int ntfs_read_locked_inode(struct inode *vi)
if (m)
unmap_mft_record(ni);
err_out:
ntfs_error(vi->i_sb, "Failed with error code %i. Marking inode 0x%lx "
"as bad.", -err, vi->i_ino);
ntfs_error(vol->sb, "Failed with error code %i. Marking corrupt "
"inode 0x%lx as bad. Run chkdsk.", err, vi->i_ino);
make_bad_inode(vi);
if (err != -EOPNOTSUPP && err != -ENOMEM)
NVolSetErrors(vol);
return err;
}
......@@ -1200,15 +1208,21 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi)
goto unm_err_out;
if (!ctx->attr->non_resident) {
/* Ensure the attribute name is placed before the value. */
if (unlikely(ctx->attr->name_length &&
(le16_to_cpu(ctx->attr->name_offset) >=
le16_to_cpu(ctx->attr->data.resident.
value_offset)))) {
ntfs_error(vol->sb, "Attribute name is placed after "
"the attribute value.");
goto unm_err_out;
}
if (NInoMstProtected(ni) || ctx->attr->flags) {
ntfs_error(vi->i_sb, "Found mst protected attribute "
"or attribute with non-zero flags but "
"the attribute is resident (mft_no "
"0x%lx, type 0x%x, name_len %i). "
"Please report you saw this message "
"to linux-ntfs-dev@lists."
"sourceforge.net",
vi->i_ino, ni->type, ni->name_len);
"the attribute is resident. Please "
"report you saw this message to "
"linux-ntfs-dev@lists.sourceforge.net");
goto unm_err_out;
}
/*
......@@ -1219,58 +1233,61 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi)
le32_to_cpu(ctx->attr->data.resident.value_length);
} else {
NInoSetNonResident(ni);
/*
* Ensure the attribute name is placed before the mapping pairs
* array.
*/
if (unlikely(ctx->attr->name_length &&
(le16_to_cpu(ctx->attr->name_offset) >=
le16_to_cpu(ctx->attr->data.non_resident.
mapping_pairs_offset)))) {
ntfs_error(vol->sb, "Attribute name is placed after "
"the mapping pairs array.");
goto unm_err_out;
}
if (ctx->attr->flags & ATTR_COMPRESSION_MASK) {
if (NInoMstProtected(ni)) {
ntfs_error(vi->i_sb, "Found mst protected "
"attribute but the attribute "
"is compressed (mft_no 0x%lx, "
"type 0x%x, name_len %i). "
"Please report you saw this "
"message to linux-ntfs-dev@"
"lists.sourceforge.net",
vi->i_ino, ni->type,
ni->name_len);
"is compressed. Please report "
"you saw this message to "
"linux-ntfs-dev@lists."
"sourceforge.net");
goto unm_err_out;
}
NInoSetCompressed(ni);
if ((ni->type != AT_DATA) || (ni->type == AT_DATA &&
ni->name_len)) {
ntfs_error(vi->i_sb, "Found compressed non-"
"data or named data attribute "
"(mft_no 0x%lx, type 0x%x, "
"name_len %i). Please report "
ntfs_error(vi->i_sb, "Found compressed "
"non-data or named data "
"attribute. Please report "
"you saw this message to "
"linux-ntfs-dev@lists."
"sourceforge.net",
vi->i_ino, ni->type,
ni->name_len);
"sourceforge.net");
goto unm_err_out;
}
if (vol->cluster_size > 4096) {
ntfs_error(vi->i_sb, "Found "
"compressed attribute but "
"compression is disabled due "
"to cluster size (%i) > 4kiB.",
ntfs_error(vi->i_sb, "Found compressed "
"attribute but compression is "
"disabled due to cluster size "
"(%i) > 4kiB.",
vol->cluster_size);
goto unm_err_out;
}
if ((ctx->attr->flags & ATTR_COMPRESSION_MASK)
!= ATTR_IS_COMPRESSED) {
ntfs_error(vi->i_sb, "Found unknown "
"compression method or "
"corrupt file.");
"compression method.");
goto unm_err_out;
}
ni->itype.compressed.block_clusters = 1U <<
ctx->attr->data.non_resident.
compression_unit;
if (ctx->attr->data.non_resident.compression_unit != 4) {
ntfs_error(vi->i_sb, "Found "
"nonstandard compression unit "
"(%u instead of 4). Cannot "
"handle this. This might "
"indicate corruption so you "
"should run chkdsk.",
if (ctx->attr->data.non_resident.compression_unit !=
4) {
ntfs_error(vi->i_sb, "Found nonstandard "
"compression unit (%u instead "
"of 4). Cannot handle this.",
ctx->attr->data.non_resident.
compression_unit);
err = -EOPNOTSUPP;
......@@ -1292,13 +1309,10 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi)
if (NInoMstProtected(ni)) {
ntfs_error(vi->i_sb, "Found mst protected "
"attribute but the attribute "
"is encrypted (mft_no 0x%lx, "
"type 0x%x, name_len %i). "
"Please report you saw this "
"message to linux-ntfs-dev@"
"lists.sourceforge.net",
vi->i_ino, ni->type,
ni->name_len);
"is encrypted. Please report "
"you saw this message to "
"linux-ntfs-dev@lists."
"sourceforge.net");
goto unm_err_out;
}
NInoSetEncrypted(ni);
......@@ -1307,21 +1321,17 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi)
if (NInoMstProtected(ni)) {
ntfs_error(vi->i_sb, "Found mst protected "
"attribute but the attribute "
"is sparse (mft_no 0x%lx, "
"type 0x%x, name_len %i). "
"Please report you saw this "
"message to linux-ntfs-dev@"
"lists.sourceforge.net",
vi->i_ino, ni->type,
ni->name_len);
"is sparse. Please report "
"you saw this message to "
"linux-ntfs-dev@lists."
"sourceforge.net");
goto unm_err_out;
}
NInoSetSparse(ni);
}
if (ctx->attr->data.non_resident.lowest_vcn) {
ntfs_error(vi->i_sb, "First extent of attribute has "
"non-zero lowest_vcn. Inode is "
"corrupt. You should run chkdsk.");
"non-zero lowest_vcn.");
goto unm_err_out;
}
/* Setup all the sizes. */
......@@ -1372,10 +1382,15 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi)
ntfs_attr_put_search_ctx(ctx);
unmap_mft_record(base_ni);
err_out:
ntfs_error(vi->i_sb, "Failed with error code %i while reading "
"attribute inode (mft_no 0x%lx, type 0x%x, name_len "
"%i.", -err, vi->i_ino, ni->type, ni->name_len);
ntfs_error(vol->sb, "Failed with error code %i while reading attribute "
"inode (mft_no 0x%lx, type 0x%x, name_len %i). "
"Marking corrupt inode and base inode 0x%lx as bad. "
"Run chkdsk.", err, vi->i_ino, ni->type, ni->name_len,
base_vi->i_ino);
make_bad_inode(vi);
make_bad_inode(base_vi);
if (err != -ENOMEM)
NVolSetErrors(vol);
return err;
}
......@@ -1460,16 +1475,24 @@ static int ntfs_read_locked_index_inode(struct inode *base_vi, struct inode *vi)
goto unm_err_out;
}
/* Set up the state. */
if (ctx->attr->non_resident) {
ntfs_error(vi->i_sb, "$INDEX_ROOT attribute is not resident. "
"Not allowed.");
if (unlikely(ctx->attr->non_resident)) {
ntfs_error(vol->sb, "$INDEX_ROOT attribute is not resident.");
goto unm_err_out;
}
/* Ensure the attribute name is placed before the value. */
if (unlikely(ctx->attr->name_length &&
(le16_to_cpu(ctx->attr->name_offset) >=
le16_to_cpu(ctx->attr->data.resident.
value_offset)))) {
ntfs_error(vol->sb, "$INDEX_ROOT attribute name is placed "
"after the attribute value.");
goto unm_err_out;
}
/* Compressed/encrypted/sparse index root is not allowed. */
if (ctx->attr->flags & (ATTR_COMPRESSION_MASK | ATTR_IS_ENCRYPTED |
ATTR_IS_SPARSE)) {
ntfs_error(vi->i_sb, "Found compressed/encrypted/sparse index "
"root attribute. Not allowed.");
"root attribute.");
goto unm_err_out;
}
ir = (INDEX_ROOT*)((u8*)ctx->attr +
......@@ -1485,8 +1508,8 @@ static int ntfs_read_locked_index_inode(struct inode *base_vi, struct inode *vi)
goto unm_err_out;
}
if (ir->type) {
ntfs_error(vi->i_sb, "Index type is not 0 (type is 0x%x). "
"Not allowed.", le32_to_cpu(ir->type));
ntfs_error(vi->i_sb, "Index type is not 0 (type is 0x%x).",
le32_to_cpu(ir->type));
goto unm_err_out;
}
ni->itype.index.collation_rule = ir->collation_rule;
......@@ -1552,6 +1575,16 @@ static int ntfs_read_locked_index_inode(struct inode *base_vi, struct inode *vi)
"resident.");
goto unm_err_out;
}
/*
* Ensure the attribute name is placed before the mapping pairs array.
*/
if (unlikely(ctx->attr->name_length && (le16_to_cpu(
ctx->attr->name_offset) >= le16_to_cpu(
ctx->attr->data.non_resident.mapping_pairs_offset)))) {
ntfs_error(vol->sb, "$INDEX_ALLOCATION attribute name is "
"placed after the mapping pairs array.");
goto unm_err_out;
}
if (ctx->attr->flags & ATTR_IS_ENCRYPTED) {
ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute is "
"encrypted.");
......@@ -1568,8 +1601,7 @@ static int ntfs_read_locked_index_inode(struct inode *base_vi, struct inode *vi)
}
if (ctx->attr->data.non_resident.lowest_vcn) {
ntfs_error(vi->i_sb, "First extent of $INDEX_ALLOCATION "
"attribute has non zero lowest_vcn. Inode is "
"corrupt. You should run chkdsk.");
"attribute has non zero lowest_vcn.");
goto unm_err_out;
}
vi->i_size = sle64_to_cpu(ctx->attr->data.non_resident.data_size);
......@@ -1595,16 +1627,16 @@ static int ntfs_read_locked_index_inode(struct inode *base_vi, struct inode *vi)
bni = NTFS_I(bvi);
if (NInoCompressed(bni) || NInoEncrypted(bni) ||
NInoSparse(bni)) {
ntfs_error(vi->i_sb, "$BITMAP attribute is compressed "
"and/or encrypted and/or sparse.");
ntfs_error(vi->i_sb, "$BITMAP attribute is compressed and/or "
"encrypted and/or sparse.");
goto iput_unm_err_out;
}
/* Consistency check bitmap size vs. index allocation size. */
if ((bvi->i_size << 3) < (vi->i_size >>
ni->itype.index.block_size_bits)) {
ntfs_error(vi->i_sb, "Index bitmap too small (0x%llx) "
"for index allocation (0x%llx).",
bvi->i_size << 3, vi->i_size);
ntfs_error(vi->i_sb, "Index bitmap too small (0x%llx) for "
"index allocation (0x%llx).", bvi->i_size << 3,
vi->i_size);
goto iput_unm_err_out;
}
ni->itype.index.bmp_ino = bvi;
......@@ -1637,9 +1669,11 @@ static int ntfs_read_locked_index_inode(struct inode *base_vi, struct inode *vi)
unmap_mft_record(base_ni);
err_out:
ntfs_error(vi->i_sb, "Failed with error code %i while reading index "
"inode (mft_no 0x%lx, name_len %i.", -err, vi->i_ino,
"inode (mft_no 0x%lx, name_len %i.", err, vi->i_ino,
ni->name_len);
make_bad_inode(vi);
if (err != -EOPNOTSUPP && err != -ENOMEM)
NVolSetErrors(vol);
return err;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment