mirror of
https://github.com/torvalds/linux.git
synced 2026-05-12 16:18:45 +02:00
Changes for 7.1-rc1
Added:
reject inodes with zero non-DOS link count
return folios from ntfs_lock_new_page()
subset of W=1 warnings for stricter checks
work around -Wmaybe-uninitialized warnings
buffer boundary checks to run_unpack()
terminate the cached volume label after UTF-8 conversion
Fixed:
check return value of indx_find to avoid infinite loop
prevent uninitialized lcn caused by zero len
increase CLIENT_REC name field size to prevent buffer overflow
missing run load for vcn0 in attr_data_get_block_locked()
memory leak in indx_create_allocate()
OOB write in attr_wof_frame_info()
mount failure on volumes with fragmented MFT bitmap
integer overflow in run_unpack() volume boundary check
validate rec->used in journal-replay file record check
Changed:
resolve compare function in public index APIs
$LXDEV xattr lookup
potential double iput on d_make_root() failure
initialize err in ni_allocate_da_blocks_locked()
correct the pre_alloc condition in attr_allocate_clusters()
-----BEGIN PGP SIGNATURE-----
iQIzBAABCgAdFiEEh0DEKNP0I9IjwfWEqbAzH4MkB7YFAmnmPm0ACgkQqbAzH4Mk
B7a0pxAAwqmZJ4vA4B7Yp7ysOBSvvQTR4wkIkfgLniJXqxHgIsFodSfB1/qI74q1
+Zg34q0sVF8HxrSDEdyA8rze0OYJu51eszpNvD6GTEph9TYZtWYRDW7bBqQBCW3z
4xLeh3Bn2SgoxqAQWa8tQEH9Z+JUf2zCD+gfeuf3/Vlinl3z32DrlVy0lqkc9+dW
LZPRMSV2Bsodn0TRyGlJX1MlY9vOJxhGMXnqZwdK0Q31FfZwL3VmfABHUGNMRP2y
QWkejLfow40Pd/iJW1/2HM4On2RUC9ozBwkGQvdHitK11VCa3FCM8owBgwyuG2cN
XycpqDgpE2MhBKP1bba5RIMj781cg3138wNIQDlt/5QWTs4K8CvJVhF22spjqN/A
mDwLIqHtstjjgTe9grlD4xwD6m/iA4GnICun+n+dqpsd8JjDrh9TCcGRFvdPhjC9
8S3V6hswssxrPTqZybpnwdiqXrPAwhD4oP7OrvHGF8hUrbL2SYwP2DDdJWlszLh2
kwSC4BfKZD7Ulc57ardTzPDEDut9RC4IIdJPcWlZu4RYcXKILIdxrIqq4LgZRwmt
KIbK2XdjKw5eAEWAX+S7s+DZOzaTkpv39NvzC3qzB4EN22X3ActY/JY+syX29ZOs
KzEFTRKbCoBS1cd16D2VaFwUQVRqsv4FQnpLftJE5/zol6VA7Ac=
=vZKA
-----END PGP SIGNATURE-----
Merge tag 'ntfs3_for_7.1' of https://github.com/Paragon-Software-Group/linux-ntfs3
Pull ntfs3 updates from Konstantin Komarov:
"New:
- reject inodes with zero non-DOS link count
- return folios from ntfs_lock_new_page()
- subset of W=1 warnings for stricter checks
- work around -Wmaybe-uninitialized warnings
- buffer boundary checks to run_unpack()
- terminate the cached volume label after UTF-8 conversion
Fixes:
- check return value of indx_find to avoid infinite loop
- prevent uninitialized lcn caused by zero len
- increase CLIENT_REC name field size to prevent buffer overflow
- missing run load for vcn0 in attr_data_get_block_locked()
- memory leak in indx_create_allocate()
- OOB write in attr_wof_frame_info()
- mount failure on volumes with fragmented MFT bitmap
- integer overflow in run_unpack() volume boundary check
- validate rec->used in journal-replay file record check
Updates:
- resolve compare function in public index APIs
- $LXDEV xattr lookup
- potential double iput on d_make_root() failure
- initialize err in ni_allocate_da_blocks_locked()
- correct the pre_alloc condition in attr_allocate_clusters()"
* tag 'ntfs3_for_7.1' of https://github.com/Paragon-Software-Group/linux-ntfs3:
fs/ntfs3: fix Smatch warnings
fs/ntfs3: validate rec->used in journal-replay file record check
fs/ntfs3: terminate the cached volume label after UTF-8 conversion
fs/ntfs3: fix potential double iput on d_make_root() failure
ntfs3: fix integer overflow in run_unpack() volume boundary check
ntfs3: add buffer boundary checks to run_unpack()
ntfs3: fix mount failure on volumes with fragmented MFT bitmap
fs/ntfs3: fix $LXDEV xattr lookup
ntfs3: fix OOB write in attr_wof_frame_info()
ntfs3: fix memory leak in indx_create_allocate()
ntfs3: work around false-postive -Wmaybe-uninitialized warnings
fs/ntfs3: fix missing run load for vcn0 in attr_data_get_block_locked()
fs/ntfs3: increase CLIENT_REC name field size
fs/ntfs3: prevent uninitialized lcn caused by zero len
fs/ntfs3: add a subset of W=1 warnings for stricter checks
fs/ntfs3: return folios from ntfs_lock_new_page()
fs/ntfs3: resolve compare function in public index APIs
ntfs3: reject inodes with zero non-DOS link count
This commit is contained in:
commit
a5d1079c28
|
|
@ -3,6 +3,26 @@
|
|||
# Makefile for the ntfs3 filesystem support.
|
||||
#
|
||||
|
||||
# Subset of W=1 warnings
|
||||
subdir-ccflags-y += -Wextra -Wunused -Wno-unused-parameter
|
||||
subdir-ccflags-y += -Wmissing-declarations
|
||||
subdir-ccflags-y += -Wmissing-format-attribute
|
||||
subdir-ccflags-y += -Wmissing-prototypes
|
||||
subdir-ccflags-y += -Wold-style-definition
|
||||
subdir-ccflags-y += -Wmissing-include-dirs
|
||||
condflags := \
|
||||
$(call cc-option, -Wunused-but-set-variable) \
|
||||
$(call cc-option, -Wunused-const-variable) \
|
||||
$(call cc-option, -Wpacked-not-aligned) \
|
||||
$(call cc-option, -Wstringop-truncation) \
|
||||
$(call cc-option, -Wmaybe-uninitialized)
|
||||
subdir-ccflags-y += $(condflags)
|
||||
# The following turn off the warnings enabled by -Wextra
|
||||
subdir-ccflags-y += -Wno-missing-field-initializers
|
||||
subdir-ccflags-y += -Wno-sign-compare
|
||||
subdir-ccflags-y += -Wno-type-limits
|
||||
subdir-ccflags-y += -Wno-shift-negative-value
|
||||
|
||||
# to check robot warnings
|
||||
ccflags-y += -Wint-to-pointer-cast \
|
||||
$(call cc-option,-Wunused-but-set-variable,-Wunused-const-variable) \
|
||||
|
|
|
|||
|
|
@ -173,7 +173,7 @@ int attr_allocate_clusters(struct ntfs_sb_info *sbi, struct runs_tree *run,
|
|||
|
||||
if (err == -ENOSPC && pre) {
|
||||
pre = 0;
|
||||
if (*pre_alloc)
|
||||
if (pre_alloc)
|
||||
*pre_alloc = 0;
|
||||
continue;
|
||||
}
|
||||
|
|
@ -1152,6 +1152,21 @@ int attr_data_get_block_locked(struct ntfs_inode *ni, CLST vcn, CLST clen,
|
|||
if (err)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (vcn0 < svcn || evcn1 <= vcn0) {
|
||||
struct ATTRIB *attr2;
|
||||
|
||||
attr2 = ni_find_attr(ni, attr_b, &le_b, ATTR_DATA, NULL,
|
||||
0, &vcn0, &mi);
|
||||
if (!attr2) {
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
err = attr_load_runs(attr2, ni, run, NULL);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
|
||||
da = false; /* no delalloc for compressed file. */
|
||||
}
|
||||
|
||||
|
|
@ -1576,6 +1591,12 @@ int attr_wof_frame_info(struct ntfs_inode *ni, struct ATTRIB *attr,
|
|||
u64 from = vbo[i] & ~(u64)(PAGE_SIZE - 1);
|
||||
u64 to = min(from + PAGE_SIZE, wof_size);
|
||||
|
||||
if (from >= wof_size) {
|
||||
_ntfs_bad_inode(&ni->vfs_inode);
|
||||
err = -EINVAL;
|
||||
goto out1;
|
||||
}
|
||||
|
||||
err = attr_load_runs_range(ni, ATTR_DATA, WOF_NAME,
|
||||
ARRAY_SIZE(WOF_NAME), run,
|
||||
from, to);
|
||||
|
|
|
|||
|
|
@ -1852,27 +1852,31 @@ enum REPARSE_SIGN ni_parse_reparse(struct ntfs_inode *ni, struct ATTRIB *attr,
|
|||
return REPARSE_LINK;
|
||||
}
|
||||
|
||||
static struct page *ntfs_lock_new_page(struct address_space *mapping,
|
||||
pgoff_t index, gfp_t gfp)
|
||||
static struct folio *ntfs_lock_new_page(struct address_space *mapping,
|
||||
pgoff_t index, gfp_t gfp)
|
||||
{
|
||||
struct folio *folio = __filemap_get_folio(
|
||||
mapping, index, FGP_LOCK | FGP_ACCESSED | FGP_CREAT, gfp);
|
||||
struct page *page;
|
||||
struct folio *folio = __filemap_get_folio(mapping, index,
|
||||
FGP_LOCK | FGP_ACCESSED | FGP_CREAT, gfp);
|
||||
|
||||
if (IS_ERR(folio))
|
||||
return ERR_CAST(folio);
|
||||
return folio;
|
||||
|
||||
if (!folio_test_uptodate(folio))
|
||||
return folio_file_page(folio, index);
|
||||
if (!folio_test_uptodate(folio)) {
|
||||
struct page *page = folio_file_page(folio, index);
|
||||
|
||||
if (IS_ERR(page))
|
||||
return ERR_CAST(page);
|
||||
return page_folio(page);
|
||||
}
|
||||
|
||||
/* Use a temporary page to avoid data corruption */
|
||||
folio_unlock(folio);
|
||||
folio_put(folio);
|
||||
page = alloc_page(gfp);
|
||||
if (!page)
|
||||
folio = folio_alloc(gfp, 0);
|
||||
if (!folio)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
__SetPageLocked(page);
|
||||
return page;
|
||||
__folio_set_locked(folio);
|
||||
return folio;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -1894,6 +1898,7 @@ int ni_read_folio_cmpr(struct ntfs_inode *ni, struct folio *folio)
|
|||
u32 i, idx, frame_size, pages_per_frame;
|
||||
gfp_t gfp_mask;
|
||||
struct page *pg;
|
||||
struct folio *f;
|
||||
|
||||
if (vbo >= i_size_read(&ni->vfs_inode)) {
|
||||
folio_zero_range(folio, 0, folio_size(folio));
|
||||
|
|
@ -1929,12 +1934,12 @@ int ni_read_folio_cmpr(struct ntfs_inode *ni, struct folio *folio)
|
|||
if (i == idx)
|
||||
continue;
|
||||
|
||||
pg = ntfs_lock_new_page(mapping, index, gfp_mask);
|
||||
if (IS_ERR(pg)) {
|
||||
err = PTR_ERR(pg);
|
||||
f = ntfs_lock_new_page(mapping, index, gfp_mask);
|
||||
if (IS_ERR(f)) {
|
||||
err = PTR_ERR(f);
|
||||
goto out1;
|
||||
}
|
||||
pages[i] = pg;
|
||||
pages[i] = &f->page;
|
||||
}
|
||||
|
||||
ni_lock(ni);
|
||||
|
|
@ -2023,18 +2028,18 @@ int ni_decompress_file(struct ntfs_inode *ni)
|
|||
}
|
||||
|
||||
for (i = 0; i < pages_per_frame; i++, index++) {
|
||||
struct page *pg;
|
||||
struct folio *f;
|
||||
|
||||
pg = ntfs_lock_new_page(mapping, index, gfp_mask);
|
||||
if (IS_ERR(pg)) {
|
||||
f = ntfs_lock_new_page(mapping, index, gfp_mask);
|
||||
if (IS_ERR(f)) {
|
||||
while (i--) {
|
||||
unlock_page(pages[i]);
|
||||
put_page(pages[i]);
|
||||
}
|
||||
err = PTR_ERR(pg);
|
||||
err = PTR_ERR(f);
|
||||
goto out;
|
||||
}
|
||||
pages[i] = pg;
|
||||
pages[i] = &f->page;
|
||||
}
|
||||
|
||||
err = ni_read_frame(ni, vbo, pages, pages_per_frame, 1);
|
||||
|
|
@ -3262,7 +3267,7 @@ int ni_allocate_da_blocks(struct ntfs_inode *ni)
|
|||
*/
|
||||
int ni_allocate_da_blocks_locked(struct ntfs_inode *ni)
|
||||
{
|
||||
int err;
|
||||
int err = 0;
|
||||
|
||||
if (!ni->file.run_da.count)
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -45,10 +45,10 @@ struct CLIENT_REC {
|
|||
__le16 seq_num; // 0x14:
|
||||
u8 align[6]; // 0x16:
|
||||
__le32 name_bytes; // 0x1C: In bytes.
|
||||
__le16 name[32]; // 0x20: Name of client.
|
||||
__le16 name[64]; // 0x20: Name of client.
|
||||
};
|
||||
|
||||
static_assert(sizeof(struct CLIENT_REC) == 0x60);
|
||||
static_assert(sizeof(struct CLIENT_REC) == 0xa0);
|
||||
|
||||
/* Two copies of these will exist at the beginning of the log file */
|
||||
struct RESTART_AREA {
|
||||
|
|
@ -2791,13 +2791,14 @@ static inline bool check_file_record(const struct MFT_REC *rec,
|
|||
u16 fn = le16_to_cpu(rec->rhdr.fix_num);
|
||||
u16 ao = le16_to_cpu(rec->attr_off);
|
||||
u32 rs = sbi->record_size;
|
||||
u32 used = le32_to_cpu(rec->used);
|
||||
|
||||
/* Check the file record header for consistency. */
|
||||
if (rec->rhdr.sign != NTFS_FILE_SIGNATURE ||
|
||||
fo > (SECTOR_SIZE - ((rs >> SECTOR_SHIFT) + 1) * sizeof(short)) ||
|
||||
(fn - 1) * SECTOR_SIZE != rs || ao < MFTRECORD_FIXUP_OFFSET_1 ||
|
||||
ao > sbi->record_size - SIZEOF_RESIDENT || !is_rec_inuse(rec) ||
|
||||
le32_to_cpu(rec->total) != rs) {
|
||||
le32_to_cpu(rec->total) != rs || used > rs || used < ao) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -2809,6 +2810,15 @@ static inline bool check_file_record(const struct MFT_REC *rec,
|
|||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* The do_action() handlers compute memmove lengths as
|
||||
* "rec->used - <offset of validated attr>", which underflows when
|
||||
* rec->used is smaller than the attribute walk reached. At this
|
||||
* point attr is the ATTR_END marker; rec->used must cover it.
|
||||
*/
|
||||
if (used < PtrOffset(rec, attr) + sizeof(attr->type))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1440,8 +1440,8 @@ int ntfs_write_bh(struct ntfs_sb_info *sbi, struct NTFS_RECORD_HEADER *rhdr,
|
|||
u16 fo = le16_to_cpu(rhdr->fix_off);
|
||||
u16 fn = le16_to_cpu(rhdr->fix_num);
|
||||
u32 idx;
|
||||
__le16 *fixup;
|
||||
__le16 sample;
|
||||
__le16 *fixup = NULL;
|
||||
__le16 sample = cpu_to_le16(-1u);
|
||||
|
||||
if ((fo & 1) || fo + fn * sizeof(short) > SECTOR_SIZE || !fn-- ||
|
||||
fn * SECTOR_SIZE > bytes) {
|
||||
|
|
|
|||
|
|
@ -714,10 +714,10 @@ static bool fnd_is_empty(struct ntfs_fnd *fnd)
|
|||
*/
|
||||
static struct NTFS_DE *hdr_find_e(const struct ntfs_index *indx,
|
||||
const struct INDEX_HDR *hdr, const void *key,
|
||||
size_t key_len, const void *ctx, int *diff)
|
||||
size_t key_len, const void *ctx, int *diff,
|
||||
NTFS_CMP_FUNC cmp)
|
||||
{
|
||||
struct NTFS_DE *e, *found = NULL;
|
||||
NTFS_CMP_FUNC cmp = indx->cmp;
|
||||
int min_idx = 0, mid_idx, max_idx = 0;
|
||||
int diff2;
|
||||
int table_size = 8;
|
||||
|
|
@ -727,9 +727,6 @@ static struct NTFS_DE *hdr_find_e(const struct ntfs_index *indx,
|
|||
u32 total = le32_to_cpu(hdr->total);
|
||||
u16 offs[128];
|
||||
|
||||
if (unlikely(!cmp))
|
||||
return NULL;
|
||||
|
||||
fill_table:
|
||||
if (end > total)
|
||||
return NULL;
|
||||
|
|
@ -800,7 +797,8 @@ static struct NTFS_DE *hdr_find_e(const struct ntfs_index *indx,
|
|||
static struct NTFS_DE *hdr_insert_de(const struct ntfs_index *indx,
|
||||
struct INDEX_HDR *hdr,
|
||||
const struct NTFS_DE *de,
|
||||
struct NTFS_DE *before, const void *ctx)
|
||||
struct NTFS_DE *before, const void *ctx,
|
||||
NTFS_CMP_FUNC cmp)
|
||||
{
|
||||
int diff;
|
||||
size_t off = PtrOffset(hdr, before);
|
||||
|
|
@ -823,7 +821,7 @@ static struct NTFS_DE *hdr_insert_de(const struct ntfs_index *indx,
|
|||
}
|
||||
/* No insert point is applied. Get it manually. */
|
||||
before = hdr_find_e(indx, hdr, de + 1, le16_to_cpu(de->key_size), ctx,
|
||||
&diff);
|
||||
&diff, cmp);
|
||||
if (!before)
|
||||
return NULL;
|
||||
off = PtrOffset(hdr, before);
|
||||
|
|
@ -915,10 +913,6 @@ int indx_init(struct ntfs_index *indx, struct ntfs_sb_info *sbi,
|
|||
|
||||
init_rwsem(&indx->run_lock);
|
||||
|
||||
indx->cmp = get_cmp_func(root);
|
||||
if (!indx->cmp)
|
||||
goto out;
|
||||
|
||||
return 0;
|
||||
|
||||
out:
|
||||
|
|
@ -1141,6 +1135,7 @@ int indx_find(struct ntfs_index *indx, struct ntfs_inode *ni,
|
|||
int err;
|
||||
struct NTFS_DE *e;
|
||||
struct indx_node *node;
|
||||
NTFS_CMP_FUNC cmp;
|
||||
|
||||
if (!root)
|
||||
root = indx_get_root(&ni->dir, ni, NULL, NULL);
|
||||
|
|
@ -1150,10 +1145,16 @@ int indx_find(struct ntfs_index *indx, struct ntfs_inode *ni,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
cmp = get_cmp_func(root);
|
||||
if (unlikely(!cmp)) {
|
||||
WARN_ON_ONCE(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Check cache. */
|
||||
e = fnd->level ? fnd->de[fnd->level - 1] : fnd->root_de;
|
||||
if (e && !de_is_last(e) &&
|
||||
!(*indx->cmp)(key, key_len, e + 1, le16_to_cpu(e->key_size), ctx)) {
|
||||
!(*cmp)(key, key_len, e + 1, le16_to_cpu(e->key_size), ctx)) {
|
||||
*entry = e;
|
||||
*diff = 0;
|
||||
return 0;
|
||||
|
|
@ -1163,7 +1164,7 @@ int indx_find(struct ntfs_index *indx, struct ntfs_inode *ni,
|
|||
fnd_clear(fnd);
|
||||
|
||||
/* Lookup entry that is <= to the search value. */
|
||||
e = hdr_find_e(indx, &root->ihdr, key, key_len, ctx, diff);
|
||||
e = hdr_find_e(indx, &root->ihdr, key, key_len, ctx, diff, cmp);
|
||||
if (!e)
|
||||
return -EINVAL;
|
||||
|
||||
|
|
@ -1183,7 +1184,7 @@ int indx_find(struct ntfs_index *indx, struct ntfs_inode *ni,
|
|||
|
||||
/* Lookup entry that is <= to the search value. */
|
||||
e = hdr_find_e(indx, &node->index->ihdr, key, key_len, ctx,
|
||||
diff);
|
||||
diff, cmp);
|
||||
if (!e) {
|
||||
put_indx_node(node);
|
||||
return -EINVAL;
|
||||
|
|
@ -1481,6 +1482,7 @@ static int indx_create_allocate(struct ntfs_index *indx, struct ntfs_inode *ni,
|
|||
run_deallocate(sbi, &run, false);
|
||||
|
||||
out:
|
||||
run_close(&run);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
@ -1585,7 +1587,7 @@ static int indx_add_allocate(struct ntfs_index *indx, struct ntfs_inode *ni,
|
|||
static int indx_insert_into_root(struct ntfs_index *indx, struct ntfs_inode *ni,
|
||||
const struct NTFS_DE *new_de,
|
||||
struct NTFS_DE *root_de, const void *ctx,
|
||||
struct ntfs_fnd *fnd, bool undo)
|
||||
struct ntfs_fnd *fnd, bool undo, NTFS_CMP_FUNC cmp)
|
||||
{
|
||||
int err = 0;
|
||||
struct NTFS_DE *e, *e0, *re;
|
||||
|
|
@ -1626,7 +1628,7 @@ static int indx_insert_into_root(struct ntfs_index *indx, struct ntfs_inode *ni,
|
|||
if ((undo || asize + ds_root < sbi->max_bytes_per_attr) &&
|
||||
mi_resize_attr(mi, attr, ds_root)) {
|
||||
hdr->total = cpu_to_le32(hdr_total + ds_root);
|
||||
e = hdr_insert_de(indx, hdr, new_de, root_de, ctx);
|
||||
e = hdr_insert_de(indx, hdr, new_de, root_de, ctx, cmp);
|
||||
WARN_ON(!e);
|
||||
fnd_clear(fnd);
|
||||
fnd->root_de = e;
|
||||
|
|
@ -1767,7 +1769,7 @@ static int indx_insert_into_root(struct ntfs_index *indx, struct ntfs_inode *ni,
|
|||
* Now root is a parent for new index buffer.
|
||||
* Insert NewEntry a new buffer.
|
||||
*/
|
||||
e = hdr_insert_de(indx, hdr, new_de, NULL, ctx);
|
||||
e = hdr_insert_de(indx, hdr, new_de, NULL, ctx, cmp);
|
||||
if (!e) {
|
||||
err = -EINVAL;
|
||||
goto out_put_n;
|
||||
|
|
@ -1797,7 +1799,7 @@ static int indx_insert_into_root(struct ntfs_index *indx, struct ntfs_inode *ni,
|
|||
static int
|
||||
indx_insert_into_buffer(struct ntfs_index *indx, struct ntfs_inode *ni,
|
||||
struct INDEX_ROOT *root, const struct NTFS_DE *new_de,
|
||||
const void *ctx, int level, struct ntfs_fnd *fnd)
|
||||
const void *ctx, int level, struct ntfs_fnd *fnd, NTFS_CMP_FUNC cmp)
|
||||
{
|
||||
int err;
|
||||
const struct NTFS_DE *sp;
|
||||
|
|
@ -1814,7 +1816,7 @@ indx_insert_into_buffer(struct ntfs_index *indx, struct ntfs_inode *ni,
|
|||
|
||||
/* Try the most easy case. */
|
||||
e = fnd->level - 1 == level ? fnd->de[level] : NULL;
|
||||
e = hdr_insert_de(indx, hdr1, new_de, e, ctx);
|
||||
e = hdr_insert_de(indx, hdr1, new_de, e, ctx, cmp);
|
||||
fnd->de[level] = e;
|
||||
if (e) {
|
||||
/* Just write updated index into disk. */
|
||||
|
|
@ -1891,12 +1893,12 @@ indx_insert_into_buffer(struct ntfs_index *indx, struct ntfs_inode *ni,
|
|||
* (depending on sp <=> new_de).
|
||||
*/
|
||||
hdr_insert_de(indx,
|
||||
(*indx->cmp)(new_de + 1, le16_to_cpu(new_de->key_size),
|
||||
(*cmp)(new_de + 1, le16_to_cpu(new_de->key_size),
|
||||
up_e + 1, le16_to_cpu(up_e->key_size),
|
||||
ctx) < 0 ?
|
||||
hdr2 :
|
||||
hdr1,
|
||||
new_de, NULL, ctx);
|
||||
new_de, NULL, ctx, cmp);
|
||||
|
||||
indx_mark_used(indx, ni, new_vbn >> indx->idx2vbn_bits);
|
||||
|
||||
|
|
@ -1911,14 +1913,14 @@ indx_insert_into_buffer(struct ntfs_index *indx, struct ntfs_inode *ni,
|
|||
*/
|
||||
if (!level) {
|
||||
/* Insert in root. */
|
||||
err = indx_insert_into_root(indx, ni, up_e, NULL, ctx, fnd, 0);
|
||||
err = indx_insert_into_root(indx, ni, up_e, NULL, ctx, fnd, 0, cmp);
|
||||
} else {
|
||||
/*
|
||||
* The target buffer's parent is another index buffer.
|
||||
* TODO: Remove recursion.
|
||||
*/
|
||||
err = indx_insert_into_buffer(indx, ni, root, up_e, ctx,
|
||||
level - 1, fnd);
|
||||
level - 1, fnd, cmp);
|
||||
}
|
||||
|
||||
if (err) {
|
||||
|
|
@ -1952,6 +1954,7 @@ int indx_insert_entry(struct ntfs_index *indx, struct ntfs_inode *ni,
|
|||
struct NTFS_DE *e;
|
||||
struct ntfs_fnd *fnd_a = NULL;
|
||||
struct INDEX_ROOT *root;
|
||||
NTFS_CMP_FUNC cmp;
|
||||
|
||||
if (!fnd) {
|
||||
fnd_a = fnd_get();
|
||||
|
|
@ -1968,6 +1971,12 @@ int indx_insert_entry(struct ntfs_index *indx, struct ntfs_inode *ni,
|
|||
goto out;
|
||||
}
|
||||
|
||||
cmp = get_cmp_func(root);
|
||||
if (unlikely(!cmp)) {
|
||||
WARN_ON_ONCE(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (fnd_is_empty(fnd)) {
|
||||
/*
|
||||
* Find the spot the tree where we want to
|
||||
|
|
@ -1991,13 +2000,13 @@ int indx_insert_entry(struct ntfs_index *indx, struct ntfs_inode *ni,
|
|||
* new entry into it.
|
||||
*/
|
||||
err = indx_insert_into_root(indx, ni, new_de, fnd->root_de, ctx,
|
||||
fnd, undo);
|
||||
fnd, undo, cmp);
|
||||
} else {
|
||||
/*
|
||||
* Found a leaf buffer, so we'll insert the new entry into it.
|
||||
*/
|
||||
err = indx_insert_into_buffer(indx, ni, root, new_de, ctx,
|
||||
fnd->level - 1, fnd);
|
||||
fnd->level - 1, fnd, cmp);
|
||||
}
|
||||
|
||||
indx->version += 1;
|
||||
|
|
@ -2291,6 +2300,7 @@ int indx_delete_entry(struct ntfs_index *indx, struct ntfs_inode *ni,
|
|||
u32 e_size, root_size, new_root_size;
|
||||
size_t trim_bit;
|
||||
const struct INDEX_NAMES *in;
|
||||
NTFS_CMP_FUNC cmp;
|
||||
|
||||
fnd = fnd_get();
|
||||
if (!fnd) {
|
||||
|
|
@ -2310,6 +2320,12 @@ int indx_delete_entry(struct ntfs_index *indx, struct ntfs_inode *ni,
|
|||
goto out;
|
||||
}
|
||||
|
||||
cmp = get_cmp_func(root);
|
||||
if (unlikely(!cmp)) {
|
||||
WARN_ON_ONCE(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Locate the entry to remove. */
|
||||
err = indx_find(indx, ni, root, key, key_len, ctx, &diff, &e, fnd);
|
||||
if (err)
|
||||
|
|
@ -2376,9 +2392,9 @@ int indx_delete_entry(struct ntfs_index *indx, struct ntfs_inode *ni,
|
|||
err = level ? indx_insert_into_buffer(indx, ni, root,
|
||||
re, ctx,
|
||||
fnd->level - 1,
|
||||
fnd) :
|
||||
fnd, cmp) :
|
||||
indx_insert_into_root(indx, ni, re, e,
|
||||
ctx, fnd, 0);
|
||||
ctx, fnd, 0, cmp);
|
||||
kfree(re);
|
||||
|
||||
if (err)
|
||||
|
|
@ -2673,6 +2689,7 @@ int indx_update_dup(struct ntfs_inode *ni, struct ntfs_sb_info *sbi,
|
|||
struct INDEX_ROOT *root;
|
||||
struct mft_inode *mi;
|
||||
struct ntfs_index *indx = &ni->dir;
|
||||
NTFS_CMP_FUNC cmp;
|
||||
|
||||
fnd = fnd_get();
|
||||
if (!fnd)
|
||||
|
|
@ -2684,6 +2701,12 @@ int indx_update_dup(struct ntfs_inode *ni, struct ntfs_sb_info *sbi,
|
|||
goto out;
|
||||
}
|
||||
|
||||
cmp = get_cmp_func(root);
|
||||
if (unlikely(!cmp)) {
|
||||
WARN_ON_ONCE(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Find entry in directory. */
|
||||
err = indx_find(indx, ni, root, fname, fname_full_size(fname), sbi,
|
||||
&diff, &e, fnd);
|
||||
|
|
|
|||
|
|
@ -432,6 +432,11 @@ static struct inode *ntfs_read_mft(struct inode *inode,
|
|||
ni->mi.dirty = true;
|
||||
}
|
||||
|
||||
if (!links) {
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
set_nlink(inode, links);
|
||||
|
||||
if (S_ISDIR(mode)) {
|
||||
|
|
@ -773,6 +778,11 @@ static int ntfs_iomap_begin(struct inode *inode, loff_t offset, loff_t length,
|
|||
return err;
|
||||
}
|
||||
|
||||
if (!clen) {
|
||||
/* broken file? */
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (lcn == EOF_LCN) {
|
||||
/* request out of file. */
|
||||
if (flags & IOMAP_REPORT) {
|
||||
|
|
@ -806,11 +816,6 @@ static int ntfs_iomap_begin(struct inode *inode, loff_t offset, loff_t length,
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (!clen) {
|
||||
/* broken file? */
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
iomap->bdev = inode->i_sb->s_bdev;
|
||||
iomap->offset = offset;
|
||||
iomap->length = ((loff_t)clen << cluster_bits) - off;
|
||||
|
|
|
|||
|
|
@ -196,9 +196,6 @@ struct ntfs_index {
|
|||
struct rw_semaphore run_lock;
|
||||
size_t version; /* increment each change */
|
||||
|
||||
/*TODO: Remove 'cmp'. */
|
||||
NTFS_CMP_FUNC cmp;
|
||||
|
||||
u8 index_bits; // log2(root->index_block_size)
|
||||
u8 idx2vbn_bits; // log2(root->index_block_clst)
|
||||
u8 vbn2vbo_bits; // index_block_size < cluster? 9 : cluster_bits
|
||||
|
|
|
|||
|
|
@ -1008,6 +1008,9 @@ int run_unpack(struct runs_tree *run, struct ntfs_sb_info *sbi, CLST ino,
|
|||
if (size_size > sizeof(len))
|
||||
return -EINVAL;
|
||||
|
||||
if (run_buf + size_size > run_last)
|
||||
return -EINVAL;
|
||||
|
||||
len = run_unpack_s64(run_buf, size_size, 0);
|
||||
/* Skip size_size. */
|
||||
run_buf += size_size;
|
||||
|
|
@ -1020,6 +1023,9 @@ int run_unpack(struct runs_tree *run, struct ntfs_sb_info *sbi, CLST ino,
|
|||
else if (offset_size <= sizeof(s64)) {
|
||||
s64 dlcn;
|
||||
|
||||
if (run_buf + offset_size > run_last)
|
||||
return -EINVAL;
|
||||
|
||||
/* Initial value of dlcn is -1 or 0. */
|
||||
dlcn = (run_buf[offset_size - 1] & 0x80) ? (s64)-1 : 0;
|
||||
dlcn = run_unpack_s64(run_buf, offset_size, dlcn);
|
||||
|
|
@ -1059,9 +1065,15 @@ int run_unpack(struct runs_tree *run, struct ntfs_sb_info *sbi, CLST ino,
|
|||
return -EOPNOTSUPP;
|
||||
}
|
||||
#endif
|
||||
if (lcn != SPARSE_LCN64 && lcn + len > sbi->used.bitmap.nbits) {
|
||||
/* LCN range is out of volume. */
|
||||
return -EINVAL;
|
||||
if (lcn != SPARSE_LCN64) {
|
||||
u64 lcn_end;
|
||||
|
||||
if (check_add_overflow(lcn, len, &lcn_end))
|
||||
return -EINVAL;
|
||||
if (lcn_end > sbi->used.bitmap.nbits) {
|
||||
/* LCN range is out of volume. */
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (!run)
|
||||
|
|
|
|||
|
|
@ -1332,8 +1332,13 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
|
|||
le32_to_cpu(attr->res.data_size) >> 1,
|
||||
UTF16_LITTLE_ENDIAN, sbi->volume.label,
|
||||
sizeof(sbi->volume.label));
|
||||
if (err < 0)
|
||||
if (err < 0) {
|
||||
sbi->volume.label[0] = 0;
|
||||
} else if (err >= sizeof(sbi->volume.label)) {
|
||||
sbi->volume.label[sizeof(sbi->volume.label) - 1] = 0;
|
||||
} else {
|
||||
sbi->volume.label[err] = 0;
|
||||
}
|
||||
} else {
|
||||
/* Should we break mounting here? */
|
||||
//err = -EINVAL;
|
||||
|
|
@ -1419,16 +1424,47 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
|
|||
tt = inode->i_size >> sbi->record_bits;
|
||||
sbi->mft.next_free = MFT_REC_USER;
|
||||
|
||||
err = wnd_init(&sbi->mft.bitmap, sb, tt);
|
||||
if (err)
|
||||
goto put_inode_out;
|
||||
|
||||
err = ni_load_all_mi(ni);
|
||||
if (err) {
|
||||
ntfs_err(sb, "Failed to load $MFT's subrecords (%d).", err);
|
||||
goto put_inode_out;
|
||||
}
|
||||
|
||||
/* Merge MFT bitmap runs from extent records loaded by ni_load_all_mi. */
|
||||
{
|
||||
struct ATTRIB *a = NULL;
|
||||
struct ATTR_LIST_ENTRY *le = NULL;
|
||||
|
||||
while ((a = ni_enum_attr_ex(ni, a, &le, NULL))) {
|
||||
CLST svcn, evcn;
|
||||
u16 roff;
|
||||
|
||||
if (a->type != ATTR_BITMAP || !a->non_res)
|
||||
continue;
|
||||
|
||||
svcn = le64_to_cpu(a->nres.svcn);
|
||||
if (!svcn)
|
||||
continue; /* Base record runs already loaded. */
|
||||
|
||||
evcn = le64_to_cpu(a->nres.evcn);
|
||||
roff = le16_to_cpu(a->nres.run_off);
|
||||
|
||||
err = run_unpack_ex(&sbi->mft.bitmap.run, sbi,
|
||||
MFT_REC_MFT, svcn, evcn, svcn,
|
||||
Add2Ptr(a, roff),
|
||||
le32_to_cpu(a->size) - roff);
|
||||
if (err < 0) {
|
||||
ntfs_err(sb, "Failed to unpack $MFT bitmap extent (%d).", err);
|
||||
goto put_inode_out;
|
||||
}
|
||||
err = 0;
|
||||
}
|
||||
}
|
||||
|
||||
err = wnd_init(&sbi->mft.bitmap, sb, tt);
|
||||
if (err)
|
||||
goto put_inode_out;
|
||||
|
||||
sbi->mft.ni = ni;
|
||||
|
||||
/* Load $Bitmap. */
|
||||
|
|
@ -1666,7 +1702,7 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
|
|||
sb->s_root = d_make_root(inode);
|
||||
if (!sb->s_root) {
|
||||
err = -ENOMEM;
|
||||
goto put_inode_out;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (boot2) {
|
||||
|
|
|
|||
|
|
@ -1031,7 +1031,7 @@ void ntfs_get_wsl_perm(struct inode *inode)
|
|||
i_gid_write(inode, (gid_t)le32_to_cpu(value[1]));
|
||||
inode->i_mode = le32_to_cpu(value[2]);
|
||||
|
||||
if (ntfs_get_ea(inode, "$LXDEV", sizeof("$$LXDEV") - 1,
|
||||
if (ntfs_get_ea(inode, "$LXDEV", sizeof("$LXDEV") - 1,
|
||||
&value[0], sizeof(value),
|
||||
&sz) == sizeof(value[0])) {
|
||||
inode->i_rdev = le32_to_cpu(value[0]);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user