mirror of
https://github.com/torvalds/linux.git
synced 2026-05-25 15:41:52 +02:00
Description for this pull request:
- Check the index depth limit via ntfs_icx_parent_inc(), avoiding context
corruption from excessively deep child chains.
- Switch security descriptor allocation to kzalloc() to avoid leaking
uninitialized memory.
- Prevent an inconsistent state where vol->volume_label becomes NULL on
allocation failure.
- Validate MFT records by verifying that attrs_offset sits within
bytes_in_use.
- Fix an off-by-one boundary comparison, correctly catching the
out-of-range MFT record number
- Validate the attribute name offset and length bounds prior to AT_UNUSED
enumeration.
- Check for a valid left neighbor before runlist merges to prevent an
8byte out-of-bounds write on crafted volumes.
- Add the missing record comparison against $MFTMirr during mount.
- Fix wrong inode lookup when writing extent MFT records.
- Redirty folio on memory allocation failure in ntfs_write_mft_block().
- Capture and propagate $MFTMirr sync errors during writeback.
- Ensure MFT mirror and synchronous writes wait for I/O completion.
- Fix buffer overflow/heap over-read in ntfs_bdev_write() when cluster
size is smaller than PAGE_SIZE.
- Fix use-after-free in ntfs_inode_sync_filename() when parent index inode
is evicted while still holding its mrec_lock.
- Update resident attribute length validation to match $AttrDef.
- Fix refcount underflow and UAF of the global upcase table.
- Fix two smatch warnings.
-----BEGIN PGP SIGNATURE-----
iQJKBAABCgA0FiEE6NzKS6Uv/XAAGHgyZwv7A1FEIQgFAmoMMfoWHGxpbmtpbmpl
b25Aa2VybmVsLm9yZwAKCRBnC/sDUUQhCFr9D/9gDFxn25jF6HM5dJ1TAQMCxjBE
UqOUtGpZkifQTc2860DnVavkg1RhIRR6cZMkY+5QmXqCr0464PpwWMOxaKrltITY
5E2eRV3PDfI3VL04eW2XwWPbruCpcFS7BF/A4SVOj5XNBVRbaLao1VRadDyZzAEN
Lua3RUUjHfz5PUjLrd4joa6zkuubYV135AB9jBzJkdAsFq5r1F4vi0jI14ozhm4j
BAlXgcJusGnPtNVfmCmUu/Ve3v6uM79sDlhBqoFSMccgV0FT+3KEl4TX8noNDXYF
fLk75EZvESR9rwb214OIdYesE6tXjP6Dy+pwatsXbk/7WXOuitgbtQ+nYnbG26Dl
/HcjBkuakq9W8Z99VRwctyjOQJydTQGWgINZXNM6yvJjCryADKtI9Yakj4y6+QL4
zQ9hyKkxoDLDif0XX5jTcaXuZ6fyDsL0tQr/QnH0vsjJE0A3gMnJfPnXej+yNVeP
bTeJowB68L0oV9/FTU6KDCTKf5YcWpbGeoisGL18PzUgEltc9DmbSkDObwpVTOp/
M/b4y1qltjvs8LzHFQWJWtfAJ8Ut0UyW5efNGMBC3ou5DRGxQeIIOmqGVkqGFHGy
K6kJBG3DnSW/trX1vd8tb1x+7EObwKt16VbHK9gutoO6aH9AqUedDWO07DnkSZyn
4c8CHBYnGRteWqbp8A==
=NZAT
-----END PGP SIGNATURE-----
Merge tag 'ntfs-for-7.1-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/linkinjeon/ntfs
Pull ntfs fixes from Namjae Jeon:
- Check the index depth limit via ntfs_icx_parent_inc(), avoiding
context corruption from excessively deep child chains
- Switch security descriptor allocation to kzalloc() to avoid leaking
uninitialized memory
- Prevent an inconsistent state where vol->volume_label becomes NULL on
allocation failure
- Validate MFT records by verifying that attrs_offset sits within
bytes_in_use
- Fix an off-by-one boundary comparison, correctly catching the
out-of-range MFT record number
- Validate the attribute name offset and length bounds prior to
AT_UNUSED enumeration
- Check for a valid left neighbor before runlist merges to prevent an
8byte out-of-bounds write on crafted volumes
- Add the missing record comparison against $MFTMirr during mount
- Fix wrong inode lookup when writing extent MFT records
- Redirty folio on memory allocation failure in ntfs_write_mft_block()
- Capture and propagate $MFTMirr sync errors during writeback
- Ensure MFT mirror and synchronous writes wait for I/O completion
- Fix buffer overflow/heap over-read in ntfs_bdev_write() when cluster
size is smaller than PAGE_SIZE
- Fix use-after-free in ntfs_inode_sync_filename() when parent index
inode is evicted while still holding its mrec_lock
- Update resident attribute length validation to match $AttrDef
- Fix refcount underflow and UAF of the global upcase table
- Fix two smatch warnings
* tag 'ntfs-for-7.1-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/linkinjeon/ntfs:
ntfs: restore $MFT mirror contents check
ntfs: fix empty_buf and ra lifetime bugs in ntfs_empty_logfile()
ntfs: validate attribute name bounds before returning it
ntfs: fix MFT bitmap scan 2^32 boundary check
ntfs: validate MFT attrs_offset against bytes_in_use
ntfs: fix missing kstrdup() error check in ntfs_write_volume_label()
ntfs: avoid leaking uninitialised bytes in new security descriptors
ntfs: fix out-of-bounds write in ntfs_index_walk_down()
ntfs: fix out-of-bounds write in ntfs_rl_collapse_range() merge path
ntfs: fix variable dereferenced before check ni in ntfs_attr_open()
ntfs: fix default_upcase refcount underflow and UAF on fs_context teardown
ntfs: match ntfs_resident_attr_min_value_length with $AttrDef
ntfs: avoid use-after-free of index inode in ntfs_inode_sync_filename()
ntfs: fix copy length in ntfs_bdev_write() for non-page-aligned start
ntfs: wait for sync mft writes to complete
ntfs: capture mft mirror sync errors in ntfs_write_mft_block()
ntfs: redirty folio when ntfs_write_mft_block() runs out of memory
ntfs: use base mft_no when looking up base inode for extent record
ntfs: fix variable dereferenced before check ni and attr in ntfs_attrlist_entry_add()
This commit is contained in:
commit
0c0b282d50
|
|
@ -583,24 +583,13 @@ static u32 ntfs_resident_attr_min_value_length(const __le32 type)
|
|||
case AT_STANDARD_INFORMATION:
|
||||
return offsetof(struct standard_information, ver) +
|
||||
sizeof(((struct standard_information *)0)->ver.v1.reserved12);
|
||||
case AT_ATTRIBUTE_LIST:
|
||||
return offsetof(struct attr_list_entry, name);
|
||||
case AT_FILE_NAME:
|
||||
return offsetof(struct file_name_attr, file_name);
|
||||
case AT_OBJECT_ID:
|
||||
return sizeof(struct guid);
|
||||
case AT_SECURITY_DESCRIPTOR:
|
||||
return sizeof(struct security_descriptor_relative);
|
||||
return offsetof(struct file_name_attr, file_name) +
|
||||
sizeof(__le16) * 1;
|
||||
case AT_VOLUME_INFORMATION:
|
||||
return sizeof(struct volume_information);
|
||||
case AT_INDEX_ROOT:
|
||||
return sizeof(struct index_root);
|
||||
case AT_REPARSE_POINT:
|
||||
return offsetof(struct reparse_point, reparse_data);
|
||||
case AT_EA_INFORMATION:
|
||||
return sizeof(struct ea_information);
|
||||
case AT_EA:
|
||||
return offsetof(struct ea_attr, ea_name) + 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -672,6 +661,9 @@ static int ntfs_attr_find(const __le32 type, const __le16 *name,
|
|||
__le16 *upcase = vol->upcase;
|
||||
u32 upcase_len = vol->upcase_len;
|
||||
unsigned int space;
|
||||
u16 name_offset;
|
||||
u32 attr_len;
|
||||
u32 name_size;
|
||||
|
||||
/*
|
||||
* Iterate over attributes in mft record starting at @ctx->attr, or the
|
||||
|
|
@ -699,6 +691,20 @@ static int ntfs_attr_find(const __le32 type, const __le16 *name,
|
|||
return -ENOENT;
|
||||
if (unlikely(!a->length))
|
||||
break;
|
||||
if (a->name_length) {
|
||||
name_offset = le16_to_cpu(a->name_offset);
|
||||
attr_len = le32_to_cpu(a->length);
|
||||
name_size = a->name_length * sizeof(__le16);
|
||||
|
||||
if (name_offset > attr_len ||
|
||||
attr_len - name_offset < name_size) {
|
||||
ntfs_error(vol->sb,
|
||||
"Corrupt attribute name in MFT record %llu\n",
|
||||
ctx->ntfs_ino->mft_no);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (type == AT_UNUSED)
|
||||
return 0;
|
||||
if (a->type != type)
|
||||
|
|
@ -712,14 +718,6 @@ static int ntfs_attr_find(const __le32 type, const __le16 *name,
|
|||
if (a->name_length)
|
||||
return -ENOENT;
|
||||
} else {
|
||||
if (a->name_length && ((le16_to_cpu(a->name_offset) +
|
||||
a->name_length * sizeof(__le16)) >
|
||||
le32_to_cpu(a->length))) {
|
||||
ntfs_error(vol->sb, "Corrupt attribute name in MFT record %llu\n",
|
||||
ctx->ntfs_ino->mft_no);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!ntfs_are_names_equal(name, name_len,
|
||||
(__le16 *)((u8 *)a + le16_to_cpu(a->name_offset)),
|
||||
a->name_length, ic, upcase, upcase_len)) {
|
||||
|
|
@ -2924,12 +2922,12 @@ int ntfs_attr_open(struct ntfs_inode *ni, const __le32 type,
|
|||
struct ntfs_inode *base_ni;
|
||||
int err;
|
||||
|
||||
ntfs_debug("Entering for inode %lld, attr 0x%x.\n",
|
||||
(unsigned long long)ni->mft_no, type);
|
||||
|
||||
if (!ni || !ni->vol)
|
||||
return -EINVAL;
|
||||
|
||||
ntfs_debug("Entering for inode %lld, attr 0x%x.\n",
|
||||
ni->mft_no, type);
|
||||
|
||||
if (NInoAttr(ni))
|
||||
base_ni = ni->ext.base_ntfs_ino;
|
||||
else
|
||||
|
|
|
|||
|
|
@ -119,15 +119,14 @@ int ntfs_attrlist_entry_add(struct ntfs_inode *ni, struct attr_record *attr)
|
|||
struct mft_record *ni_mrec;
|
||||
u8 *old_al;
|
||||
|
||||
ntfs_debug("Entering for inode 0x%llx, attr 0x%x.\n",
|
||||
(long long) ni->mft_no,
|
||||
(unsigned int) le32_to_cpu(attr->type));
|
||||
|
||||
if (!ni || !attr) {
|
||||
ntfs_debug("Invalid arguments.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ntfs_debug("Entering for inode 0x%llx, attr 0x%x.\n",
|
||||
ni->mft_no, (unsigned int) le32_to_cpu(attr->type));
|
||||
|
||||
ni_mrec = map_mft_record(ni);
|
||||
if (IS_ERR(ni_mrec)) {
|
||||
ntfs_debug("Invalid arguments.\n");
|
||||
|
|
|
|||
|
|
@ -97,6 +97,8 @@ int ntfs_bdev_write(struct super_block *sb, void *buf, loff_t start, size_t size
|
|||
idx_end++;
|
||||
|
||||
for (; idx < idx_end; idx++, from = 0) {
|
||||
u32 len;
|
||||
|
||||
folio = read_mapping_folio(sb->s_bdev->bd_mapping, idx, NULL);
|
||||
if (IS_ERR(folio)) {
|
||||
ntfs_error(sb, "Unable to read %ld page", idx);
|
||||
|
|
@ -105,9 +107,10 @@ int ntfs_bdev_write(struct super_block *sb, void *buf, loff_t start, size_t size
|
|||
|
||||
offset = (loff_t)idx << PAGE_SHIFT;
|
||||
to = min_t(u32, end - offset, PAGE_SIZE);
|
||||
len = to - from;
|
||||
|
||||
memcpy_to_folio(folio, from, buf + buf_off, to);
|
||||
buf_off += to;
|
||||
memcpy_to_folio(folio, from, buf + buf_off, len);
|
||||
buf_off += len;
|
||||
folio_mark_uptodate(folio);
|
||||
folio_mark_dirty(folio);
|
||||
folio_put(folio);
|
||||
|
|
|
|||
|
|
@ -677,11 +677,11 @@ static int ntfs_ib_read(struct ntfs_index_context *icx, s64 vcn, struct index_bl
|
|||
|
||||
static int ntfs_icx_parent_inc(struct ntfs_index_context *icx)
|
||||
{
|
||||
icx->pindex++;
|
||||
if (icx->pindex >= MAX_PARENT_VCN) {
|
||||
if (icx->pindex >= MAX_PARENT_VCN - 1) {
|
||||
ntfs_error(icx->idx_ni->vol->sb, "Index is over %d level deep", MAX_PARENT_VCN);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
icx->pindex++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1970,6 +1970,7 @@ struct index_entry *ntfs_index_walk_down(struct index_entry *ie, struct ntfs_ind
|
|||
{
|
||||
struct index_entry *entry;
|
||||
struct index_block *ib;
|
||||
int err;
|
||||
s64 vcn;
|
||||
|
||||
entry = ie;
|
||||
|
|
@ -1979,14 +1980,20 @@ struct index_entry *ntfs_index_walk_down(struct index_entry *ie, struct ntfs_ind
|
|||
ib = kvzalloc(ictx->block_size, GFP_NOFS);
|
||||
if (!ib)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
/* down from level zero */
|
||||
/*
|
||||
* Descending from root index (level 0) to the first
|
||||
* child level. is_in_root == true implies pindex == 0,
|
||||
* so advance to level 1.
|
||||
*/
|
||||
ictx->pindex = 1;
|
||||
ictx->ir = NULL;
|
||||
ictx->ib = ib;
|
||||
ictx->pindex = 1;
|
||||
ictx->is_in_root = false;
|
||||
} else {
|
||||
/* down from non-zero level */
|
||||
ictx->pindex++;
|
||||
err = ntfs_icx_parent_inc(ictx);
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
ictx->parent_pos[ictx->pindex] = 0;
|
||||
|
|
|
|||
|
|
@ -2582,8 +2582,8 @@ int ntfs_inode_sync_filename(struct ntfs_inode *ni)
|
|||
|
||||
mutex_lock_nested(&index_ni->mrec_lock, NTFS_INODE_MUTEX_PARENT);
|
||||
if (NInoBeingDeleted(ni)) {
|
||||
iput(index_vi);
|
||||
mutex_unlock(&index_ni->mrec_lock);
|
||||
iput(index_vi);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -2591,8 +2591,8 @@ int ntfs_inode_sync_filename(struct ntfs_inode *ni)
|
|||
if (!ictx) {
|
||||
ntfs_error(sb, "Failed to get index ctx, inode %llu",
|
||||
index_ni->mft_no);
|
||||
iput(index_vi);
|
||||
mutex_unlock(&index_ni->mrec_lock);
|
||||
iput(index_vi);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -2601,8 +2601,8 @@ int ntfs_inode_sync_filename(struct ntfs_inode *ni)
|
|||
ntfs_debug("Index lookup failed, inode %llu",
|
||||
index_ni->mft_no);
|
||||
ntfs_index_ctx_put(ictx);
|
||||
iput(index_vi);
|
||||
mutex_unlock(&index_ni->mrec_lock);
|
||||
iput(index_vi);
|
||||
continue;
|
||||
}
|
||||
/* Update flags and file size. */
|
||||
|
|
|
|||
|
|
@ -710,6 +710,9 @@ bool ntfs_empty_logfile(struct inode *log_vi)
|
|||
if (unlikely(lcn == LCN_RL_NOT_MAPPED)) {
|
||||
vcn = rl->vcn;
|
||||
kvfree(empty_buf);
|
||||
empty_buf = NULL;
|
||||
kfree(ra);
|
||||
ra = NULL;
|
||||
goto map_vcn;
|
||||
}
|
||||
/* If this run is not valid abort with an error. */
|
||||
|
|
@ -753,7 +756,7 @@ bool ntfs_empty_logfile(struct inode *log_vi)
|
|||
} while (start < end);
|
||||
} while ((++rl)->vcn < end_vcn);
|
||||
up_write(&log_ni->runlist.lock);
|
||||
kfree(empty_buf);
|
||||
kvfree(empty_buf);
|
||||
kfree(ra);
|
||||
truncate_inode_pages(log_vi->i_mapping, 0);
|
||||
/* Set the flag so we do not have to do it again on remount. */
|
||||
|
|
|
|||
|
|
@ -30,6 +30,8 @@ int ntfs_mft_record_check(const struct ntfs_volume *vol, struct mft_record *m,
|
|||
{
|
||||
struct attr_record *a;
|
||||
struct super_block *sb = vol->sb;
|
||||
u16 attrs_offset;
|
||||
u32 bytes_in_use;
|
||||
|
||||
if (!ntfs_is_file_record(m->magic)) {
|
||||
ntfs_error(sb, "Record %llu has no FILE magic (0x%x)\n",
|
||||
|
|
@ -65,7 +67,16 @@ int ntfs_mft_record_check(const struct ntfs_volume *vol, struct mft_record *m,
|
|||
goto err_out;
|
||||
}
|
||||
|
||||
a = (struct attr_record *)((char *)m + le16_to_cpu(m->attrs_offset));
|
||||
attrs_offset = le16_to_cpu(m->attrs_offset);
|
||||
bytes_in_use = le32_to_cpu(m->bytes_in_use);
|
||||
|
||||
if (attrs_offset > bytes_in_use ||
|
||||
bytes_in_use - attrs_offset < sizeof_field(struct attr_record, type)) {
|
||||
ntfs_error(sb, "Record %llu has corrupt attribute offset\n", mft_no);
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
a = (struct attr_record *)((char *)m + attrs_offset);
|
||||
if ((char *)a < (char *)m || (char *)a > (char *)m + vol->mft_record_size) {
|
||||
ntfs_error(sb, "Record %llu is corrupt\n", mft_no);
|
||||
goto err_out;
|
||||
|
|
@ -449,7 +460,7 @@ static void ntfs_bio_end_io(struct bio *bio)
|
|||
int ntfs_sync_mft_mirror(struct ntfs_volume *vol, const u64 mft_no,
|
||||
struct mft_record *m)
|
||||
{
|
||||
u8 *kmirr = NULL;
|
||||
u8 *kmirr;
|
||||
struct folio *folio;
|
||||
unsigned int folio_ofs, lcn_folio_off = 0;
|
||||
int err = 0;
|
||||
|
|
@ -479,6 +490,7 @@ int ntfs_sync_mft_mirror(struct ntfs_volume *vol, const u64 mft_no,
|
|||
kmirr = kmap_local_folio(folio, 0) + folio_ofs;
|
||||
/* Copy the mst protected mft record to the mirror. */
|
||||
memcpy(kmirr, m, vol->mft_record_size);
|
||||
kunmap_local(kmirr);
|
||||
|
||||
if (vol->cluster_size_bits > PAGE_SHIFT) {
|
||||
lcn_folio_off = folio->index << PAGE_SHIFT;
|
||||
|
|
@ -490,20 +502,22 @@ int ntfs_sync_mft_mirror(struct ntfs_volume *vol, const u64 mft_no,
|
|||
NTFS_B_TO_SECTOR(vol, NTFS_CLU_TO_B(vol, vol->mftmirr_lcn) +
|
||||
lcn_folio_off + folio_ofs);
|
||||
|
||||
if (!bio_add_folio(bio, folio, vol->mft_record_size, folio_ofs)) {
|
||||
if (bio_add_folio(bio, folio, vol->mft_record_size, folio_ofs))
|
||||
err = submit_bio_wait(bio);
|
||||
else
|
||||
err = -EIO;
|
||||
bio_put(bio);
|
||||
goto unlock_folio;
|
||||
}
|
||||
bio_put(bio);
|
||||
|
||||
bio->bi_end_io = ntfs_bio_end_io;
|
||||
submit_bio(bio);
|
||||
/* Current state: all buffers are clean, unlocked, and uptodate. */
|
||||
/*
|
||||
* The in-memory mirror is now valid because we just memcpy()'d the
|
||||
* mst-protected mft record into it. Mark the folio uptodate even on
|
||||
* write error so a subsequent read_mapping_folio() does not refetch
|
||||
* the stale on-disk mirror and overwrite this copy. The error is
|
||||
* propagated to the caller via @err.
|
||||
*/
|
||||
folio_mark_uptodate(folio);
|
||||
|
||||
unlock_folio:
|
||||
folio_unlock(folio);
|
||||
kunmap_local(kmirr);
|
||||
folio_put(folio);
|
||||
if (likely(!err)) {
|
||||
ntfs_debug("Done.");
|
||||
|
|
@ -588,20 +602,36 @@ int write_mft_record_nolock(struct ntfs_inode *ni, struct mft_record *m, int syn
|
|||
}
|
||||
|
||||
/* Synchronize the mft mirror now if not @sync. */
|
||||
if (!sync && ni->mft_no < vol->mftmirr_size)
|
||||
ntfs_sync_mft_mirror(vol, ni->mft_no, fixup_m);
|
||||
if (!sync && ni->mft_no < vol->mftmirr_size) {
|
||||
int sub_err = ntfs_sync_mft_mirror(vol, ni->mft_no,
|
||||
fixup_m);
|
||||
if (unlikely(sub_err) && !err)
|
||||
err = sub_err;
|
||||
}
|
||||
|
||||
folio_get(folio);
|
||||
bio->bi_private = folio;
|
||||
bio->bi_end_io = ntfs_bio_end_io;
|
||||
submit_bio(bio);
|
||||
if (sync) {
|
||||
int sub_err = submit_bio_wait(bio);
|
||||
|
||||
bio_put(bio);
|
||||
if (unlikely(sub_err) && !err)
|
||||
err = sub_err;
|
||||
} else {
|
||||
folio_get(folio);
|
||||
bio->bi_private = folio;
|
||||
bio->bi_end_io = ntfs_bio_end_io;
|
||||
submit_bio(bio);
|
||||
}
|
||||
offset += vol->cluster_size;
|
||||
i++;
|
||||
}
|
||||
|
||||
/* If @sync, now synchronize the mft mirror. */
|
||||
if (sync && ni->mft_no < vol->mftmirr_size)
|
||||
ntfs_sync_mft_mirror(vol, ni->mft_no, fixup_m);
|
||||
if (sync && ni->mft_no < vol->mftmirr_size) {
|
||||
int sub_err = ntfs_sync_mft_mirror(vol, ni->mft_no, fixup_m);
|
||||
|
||||
if (unlikely(sub_err) && !err)
|
||||
err = sub_err;
|
||||
}
|
||||
kunmap_local(kaddr);
|
||||
if (unlikely(err)) {
|
||||
/* I/O error during writing. This is really bad! */
|
||||
|
|
@ -617,10 +647,10 @@ int write_mft_record_nolock(struct ntfs_inode *ni, struct mft_record *m, int syn
|
|||
bio_put(bio);
|
||||
err_out:
|
||||
/*
|
||||
* Current state: all buffers are clean, unlocked, and uptodate.
|
||||
* The caller should mark the base inode as bad so that no more i/o
|
||||
* happens. ->drop_inode() will still be invoked so all extent inodes
|
||||
* and other allocated memory will be freed.
|
||||
* The caller should mark the base inode as bad so no more I/O
|
||||
* happens. ->drop_inode() will still be invoked so all extent inodes
|
||||
* and other allocated memory will be freed. ENOMEM is retried by
|
||||
* redirtying the mft record below.
|
||||
*/
|
||||
if (err == -ENOMEM) {
|
||||
ntfs_error(vol->sb,
|
||||
|
|
@ -833,7 +863,7 @@ static bool ntfs_may_write_mft_record(struct ntfs_volume *vol, const u64 mft_no,
|
|||
vi = igrab(mft_vi);
|
||||
WARN_ON(vi != mft_vi);
|
||||
} else {
|
||||
vi = find_inode_nowait(sb, mft_no, ntfs_test_inode_wb, &na);
|
||||
vi = find_inode_nowait(sb, na.mft_no, ntfs_test_inode_wb, &na);
|
||||
if (na.state == NI_BeingDeleted || na.state == NI_BeingCreated)
|
||||
return false;
|
||||
}
|
||||
|
|
@ -1034,7 +1064,7 @@ static s64 ntfs_mft_bitmap_find_and_alloc_free_rec_nolock(struct ntfs_volume *vo
|
|||
b = ffz((unsigned long)*byte);
|
||||
if (b < 8 && b >= (bit & 7)) {
|
||||
ll = data_pos + (bit & ~7ull) + b;
|
||||
if (unlikely(ll > (1ll << 32))) {
|
||||
if (unlikely(ll >= (1ll << 32))) {
|
||||
folio_unlock(folio);
|
||||
kunmap_local(buf);
|
||||
folio_put(folio);
|
||||
|
|
@ -2721,8 +2751,11 @@ static int ntfs_write_mft_block(struct folio *folio, struct writeback_control *w
|
|||
ntfs_debug("Entering for inode 0x%llx, attribute type 0x%x, folio index 0x%lx.",
|
||||
ni->mft_no, ni->type, folio->index);
|
||||
|
||||
if (!locked_nis || !ref_inos)
|
||||
if (!locked_nis || !ref_inos) {
|
||||
folio_redirty_for_writepage(wbc, folio);
|
||||
folio_unlock(folio);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* We have to zero every time due to mmap-at-end-of-file. */
|
||||
if (folio->index >= (i_size >> folio_shift(folio)))
|
||||
|
|
@ -2840,9 +2873,13 @@ static int ntfs_write_mft_block(struct folio *folio, struct writeback_control *w
|
|||
}
|
||||
prev_mft_ofs = mft_ofs;
|
||||
|
||||
if (mft_no < vol->mftmirr_size)
|
||||
ntfs_sync_mft_mirror(vol, mft_no,
|
||||
if (mft_no < vol->mftmirr_size) {
|
||||
int sub_err = ntfs_sync_mft_mirror(vol, mft_no,
|
||||
(struct mft_record *)(kaddr + mft_ofs));
|
||||
|
||||
if (unlikely(sub_err) && !err)
|
||||
err = sub_err;
|
||||
}
|
||||
} else if (ref_inos[nr_ref_inos])
|
||||
nr_ref_inos++;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -344,9 +344,9 @@ static int ntfs_sd_add_everyone(struct ntfs_inode *ni)
|
|||
sd_len = sizeof(struct security_descriptor_relative) + 2 *
|
||||
(sizeof(struct ntfs_sid) + 8) + sizeof(struct ntfs_acl) +
|
||||
sizeof(struct ntfs_ace) + 4;
|
||||
sd = kmalloc(sd_len, GFP_NOFS);
|
||||
sd = kzalloc(sd_len, GFP_NOFS);
|
||||
if (!sd)
|
||||
return -1;
|
||||
return -ENOMEM;
|
||||
|
||||
sd->revision = 1;
|
||||
sd->control = SE_DACL_PRESENT | SE_SELF_RELATIVE;
|
||||
|
|
|
|||
|
|
@ -2056,10 +2056,11 @@ struct runlist_element *ntfs_rl_collapse_range(struct runlist_element *dst_rl, i
|
|||
* consists of holes.
|
||||
*/
|
||||
merge_cnt = 0;
|
||||
i = new_1st_cnt == 0 ? 1 : new_1st_cnt;
|
||||
if (ntfs_rle_lcn_contiguous(&new_rl[i - 1], &new_rl[i])) {
|
||||
/* Merge right and left */
|
||||
s_rl = &new_rl[new_1st_cnt - 1];
|
||||
if (new_1st_cnt > 0 &&
|
||||
ntfs_rle_lcn_contiguous(&new_rl[new_1st_cnt - 1],
|
||||
&new_rl[new_1st_cnt])) {
|
||||
/* Merge right and left. */
|
||||
s_rl = &new_rl[new_1st_cnt - 1];
|
||||
s_rl->length += s_rl[1].length;
|
||||
merge_cnt = 1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -413,6 +413,7 @@ int ntfs_write_volume_label(struct ntfs_volume *vol, char *label)
|
|||
{
|
||||
struct ntfs_inode *vol_ni = NTFS_I(vol->vol_ino);
|
||||
struct ntfs_attr_search_ctx *ctx;
|
||||
char *new_label;
|
||||
__le16 *uname;
|
||||
int uname_len, ret;
|
||||
|
||||
|
|
@ -425,7 +426,7 @@ int ntfs_write_volume_label(struct ntfs_volume *vol, char *label)
|
|||
return uname_len;
|
||||
}
|
||||
|
||||
if (uname_len > NTFS_MAX_LABEL_LEN) {
|
||||
if (uname_len > NTFS_MAX_LABEL_LEN) {
|
||||
ntfs_error(vol->sb,
|
||||
"Volume label is too long (max %d characters).",
|
||||
NTFS_MAX_LABEL_LEN);
|
||||
|
|
@ -433,11 +434,22 @@ int ntfs_write_volume_label(struct ntfs_volume *vol, char *label)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate the in-memory label copy up front. If kstrdup() fails we
|
||||
* bail out before touching on-disk metadata, so the in-memory label
|
||||
* and the on-disk label stay in sync.
|
||||
*/
|
||||
new_label = kstrdup(label, GFP_KERNEL);
|
||||
if (!new_label) {
|
||||
kvfree(uname);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
mutex_lock(&vol_ni->mrec_lock);
|
||||
ctx = ntfs_attr_get_search_ctx(vol_ni, NULL);
|
||||
if (!ctx) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!ntfs_attr_lookup(AT_VOLUME_NAME, NULL, 0, 0, 0, NULL, 0,
|
||||
|
|
@ -450,12 +462,14 @@ int ntfs_write_volume_label(struct ntfs_volume *vol, char *label)
|
|||
out:
|
||||
mutex_unlock(&vol_ni->mrec_lock);
|
||||
kvfree(uname);
|
||||
mark_inode_dirty_sync(vol->vol_ino);
|
||||
|
||||
if (ret >= 0) {
|
||||
kfree(vol->volume_label);
|
||||
vol->volume_label = kstrdup(label, GFP_KERNEL);
|
||||
vol->volume_label = new_label;
|
||||
mark_inode_dirty_sync(vol->vol_ino);
|
||||
ret = 0;
|
||||
} else {
|
||||
kfree(new_label);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -979,6 +993,13 @@ static bool check_mft_mirror(struct ntfs_volume *vol)
|
|||
ntfs_is_baad_recordp((__le32 *)kmirr))
|
||||
bytes = vol->mft_record_size;
|
||||
}
|
||||
/* Compare the two records. */
|
||||
if (memcmp(kmft, kmirr, bytes)) {
|
||||
ntfs_error(sb,
|
||||
"$MFT and $MFTMirr record %i do not match. Run chkdsk.",
|
||||
i);
|
||||
goto mm_unmap_out;
|
||||
}
|
||||
kmft += vol->mft_record_size;
|
||||
kmirr += vol->mft_record_size;
|
||||
} while (++i < vol->mftmirr_size);
|
||||
|
|
@ -1671,7 +1692,7 @@ static bool load_system_files(struct ntfs_volume *vol)
|
|||
iput_upcase_err_out:
|
||||
vol->upcase_len = 0;
|
||||
mutex_lock(&ntfs_lock);
|
||||
if (vol->upcase == default_upcase) {
|
||||
if (vol->upcase && vol->upcase == default_upcase) {
|
||||
ntfs_nr_upcase_users--;
|
||||
vol->upcase = NULL;
|
||||
}
|
||||
|
|
@ -1701,7 +1722,7 @@ static void ntfs_volume_free(struct ntfs_volume *vol)
|
|||
* the number of upcase users if we are a user.
|
||||
*/
|
||||
mutex_lock(&ntfs_lock);
|
||||
if (vol->upcase == default_upcase) {
|
||||
if (vol->upcase && vol->upcase == default_upcase) {
|
||||
ntfs_nr_upcase_users--;
|
||||
vol->upcase = NULL;
|
||||
}
|
||||
|
|
@ -2494,7 +2515,7 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
|
|||
}
|
||||
vol->upcase_len = 0;
|
||||
mutex_lock(&ntfs_lock);
|
||||
if (vol->upcase == default_upcase) {
|
||||
if (vol->upcase && vol->upcase == default_upcase) {
|
||||
ntfs_nr_upcase_users--;
|
||||
vol->upcase = NULL;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user