Commit f69d00d1 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'ntfs3_for_6.6' of https://github.com/Paragon-Software-Group/linux-ntfs3

Pull ntfs3 fixes from Konstantin Komarov:

 - memory leak

 - some logic errors, NULL dereferences

 - some code was refactored

 - more sanity checks

* tag 'ntfs3_for_6.6' of https://github.com/Paragon-Software-Group/linux-ntfs3:
  fs/ntfs3: Avoid possible memory leak
  fs/ntfs3: Fix directory element type detection
  fs/ntfs3: Fix possible null-pointer dereference in hdr_find_e()
  fs/ntfs3: Fix OOB read in ntfs_init_from_boot
  fs/ntfs3: fix panic about slab-out-of-bounds caused by ntfs_list_ea()
  fs/ntfs3: Fix NULL pointer dereference on error in attr_allocate_frame()
  fs/ntfs3: Fix possible NULL-ptr-deref in ni_readpage_cmpr()
  fs/ntfs3: Do not allow to change label if volume is read-only
  fs/ntfs3: Add more info into /proc/fs/ntfs3/<dev>/volinfo
  fs/ntfs3: Refactoring and comments
  fs/ntfs3: Fix alternative boot searching
  fs/ntfs3: Allow repeated call to ntfs3_put_sbi
  fs/ntfs3: Use inode_set_ctime_to_ts instead of inode_set_ctime
  fs/ntfs3: Fix shift-out-of-bounds in ntfs_fill_super
  fs/ntfs3: fix deadlock in mark_as_free_ex
  fs/ntfs3: Add more attributes checks in mi_enum_attr()
  fs/ntfs3: Use kvmalloc instead of kmalloc(... __GFP_NOWARN)
  fs/ntfs3: Write immediately updated ntfs state
  fs/ntfs3: Add ckeck in ni_update_parent()
parents 7cf4bea7 e4494770
......@@ -1106,10 +1106,10 @@ int attr_data_get_block(struct ntfs_inode *ni, CLST vcn, CLST clen, CLST *lcn,
}
}
/*
/*
* The code below may require additional cluster (to extend attribute list)
* and / or one MFT record
* It is too complex to undo operations if -ENOSPC occurs deep inside
* and / or one MFT record
* It is too complex to undo operations if -ENOSPC occurs deep inside
* in 'ni_insert_nonresident'.
* Return in advance -ENOSPC here if there are no free cluster and no free MFT.
*/
......@@ -1736,10 +1736,8 @@ int attr_allocate_frame(struct ntfs_inode *ni, CLST frame, size_t compr_size,
le_b = NULL;
attr_b = ni_find_attr(ni, NULL, &le_b, ATTR_DATA, NULL,
0, NULL, &mi_b);
if (!attr_b) {
err = -ENOENT;
goto out;
}
if (!attr_b)
return -ENOENT;
attr = attr_b;
le = le_b;
......
......@@ -52,7 +52,8 @@ int ntfs_load_attr_list(struct ntfs_inode *ni, struct ATTRIB *attr)
if (!attr->non_res) {
lsize = le32_to_cpu(attr->res.data_size);
le = kmalloc(al_aligned(lsize), GFP_NOFS | __GFP_NOWARN);
/* attr is resident: lsize < record_size (1K or 4K) */
le = kvmalloc(al_aligned(lsize), GFP_KERNEL);
if (!le) {
err = -ENOMEM;
goto out;
......@@ -80,7 +81,17 @@ int ntfs_load_attr_list(struct ntfs_inode *ni, struct ATTRIB *attr)
if (err < 0)
goto out;
le = kmalloc(al_aligned(lsize), GFP_NOFS | __GFP_NOWARN);
/* attr is nonresident.
* The worst case:
* 1T (2^40) extremely fragmented file.
* cluster = 4K (2^12) => 2^28 fragments
* 2^9 fragments per one record => 2^19 records
* 2^5 bytes of ATTR_LIST_ENTRY per one record => 2^24 bytes.
*
* the result is 16M bytes per attribute list.
* Use kvmalloc to allocate in range [several Kbytes - dozen Mbytes]
*/
le = kvmalloc(al_aligned(lsize), GFP_KERNEL);
if (!le) {
err = -ENOMEM;
goto out;
......
......@@ -125,6 +125,7 @@ void wnd_close(struct wnd_bitmap *wnd)
struct rb_node *node, *next;
kfree(wnd->free_bits);
wnd->free_bits = NULL;
run_close(&wnd->run);
node = rb_first(&wnd->start_tree);
......@@ -659,7 +660,8 @@ int wnd_init(struct wnd_bitmap *wnd, struct super_block *sb, size_t nbits)
wnd->bits_last = wbits;
wnd->free_bits =
kcalloc(wnd->nwnd, sizeof(u16), GFP_NOFS | __GFP_NOWARN);
kvmalloc_array(wnd->nwnd, sizeof(u16), GFP_KERNEL | __GFP_ZERO);
if (!wnd->free_bits)
return -ENOMEM;
......
......@@ -309,7 +309,11 @@ static inline int ntfs_filldir(struct ntfs_sb_info *sbi, struct ntfs_inode *ni,
return 0;
}
dt_type = (fname->dup.fa & FILE_ATTRIBUTE_DIRECTORY) ? DT_DIR : DT_REG;
/* NTFS: symlinks are "dir + reparse" or "file + reparse" */
if (fname->dup.fa & FILE_ATTRIBUTE_REPARSE_POINT)
dt_type = DT_LNK;
else
dt_type = (fname->dup.fa & FILE_ATTRIBUTE_DIRECTORY) ? DT_DIR : DT_REG;
return !dir_emit(ctx, (s8 *)name, name_len, ino, dt_type);
}
......
......@@ -745,8 +745,8 @@ static ssize_t ntfs_file_read_iter(struct kiocb *iocb, struct iov_iter *iter)
}
static ssize_t ntfs_file_splice_read(struct file *in, loff_t *ppos,
struct pipe_inode_info *pipe,
size_t len, unsigned int flags)
struct pipe_inode_info *pipe, size_t len,
unsigned int flags)
{
struct inode *inode = in->f_mapping->host;
struct ntfs_inode *ni = ntfs_i(inode);
......
......@@ -2148,7 +2148,7 @@ int ni_readpage_cmpr(struct ntfs_inode *ni, struct page *page)
for (i = 0; i < pages_per_frame; i++) {
pg = pages[i];
if (i == idx)
if (i == idx || !pg)
continue;
unlock_page(pg);
put_page(pg);
......@@ -3208,6 +3208,12 @@ static bool ni_update_parent(struct ntfs_inode *ni, struct NTFS_DUP_INFO *dup,
if (!fname || !memcmp(&fname->dup, dup, sizeof(fname->dup)))
continue;
/* Check simple case when parent inode equals current inode. */
if (ino_get(&fname->home) == ni->vfs_inode.i_ino) {
ntfs_set_state(sbi, NTFS_DIRTY_ERROR);
continue;
}
/* ntfs_iget5 may sleep. */
dir = ntfs_iget5(sb, &fname->home, NULL);
if (IS_ERR(dir)) {
......
......@@ -2168,8 +2168,10 @@ static int last_log_lsn(struct ntfs_log *log)
if (!page) {
page = kmalloc(log->page_size, GFP_NOFS);
if (!page)
return -ENOMEM;
if (!page) {
err = -ENOMEM;
goto out;
}
}
/*
......
......@@ -983,18 +983,11 @@ int ntfs_set_state(struct ntfs_sb_info *sbi, enum NTFS_DIRTY_FLAGS dirty)
if (err)
return err;
mark_inode_dirty(&ni->vfs_inode);
mark_inode_dirty_sync(&ni->vfs_inode);
/* verify(!ntfs_update_mftmirr()); */
/*
* If we used wait=1, sync_inode_metadata waits for the io for the
* inode to finish. It hangs when media is removed.
* So wait=0 is sent down to sync_inode_metadata
* and filemap_fdatawrite is used for the data blocks.
*/
err = sync_inode_metadata(&ni->vfs_inode, 0);
if (!err)
err = filemap_fdatawrite(ni->vfs_inode.i_mapping);
/* write mft record on disk. */
err = _ni_write_inode(&ni->vfs_inode, 1);
return err;
}
......@@ -2461,10 +2454,12 @@ void mark_as_free_ex(struct ntfs_sb_info *sbi, CLST lcn, CLST len, bool trim)
{
CLST end, i, zone_len, zlen;
struct wnd_bitmap *wnd = &sbi->used.bitmap;
bool dirty = false;
down_write_nested(&wnd->rw_lock, BITMAP_MUTEX_CLUSTERS);
if (!wnd_is_used(wnd, lcn, len)) {
ntfs_set_state(sbi, NTFS_DIRTY_ERROR);
/* mark volume as dirty out of wnd->rw_lock */
dirty = true;
end = lcn + len;
len = 0;
......@@ -2518,6 +2513,8 @@ void mark_as_free_ex(struct ntfs_sb_info *sbi, CLST lcn, CLST len, bool trim)
out:
up_write(&wnd->rw_lock);
if (dirty)
ntfs_set_state(sbi, NTFS_DIRTY_ERROR);
}
/*
......
......@@ -729,6 +729,9 @@ 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;
......
......@@ -170,8 +170,8 @@ static struct inode *ntfs_read_mft(struct inode *inode,
nt2kernel(std5->cr_time, &ni->i_crtime);
#endif
nt2kernel(std5->a_time, &inode->i_atime);
ctime = inode_get_ctime(inode);
nt2kernel(std5->c_time, &ctime);
inode_set_ctime_to_ts(inode, ctime);
nt2kernel(std5->m_time, &inode->i_mtime);
ni->std_fa = std5->fa;
......@@ -1660,7 +1660,8 @@ struct inode *ntfs_create_inode(struct mnt_idmap *idmap, struct inode *dir,
d_instantiate(dentry, inode);
/* Set original time. inode times (i_ctime) may be changed in ntfs_init_acl. */
inode->i_atime = inode->i_mtime = inode_set_ctime_to_ts(inode, ni->i_crtime);
inode->i_atime = inode->i_mtime =
inode_set_ctime_to_ts(inode, ni->i_crtime);
dir->i_mtime = inode_set_ctime_to_ts(dir, ni->i_crtime);
mark_inode_dirty(dir);
......
......@@ -156,8 +156,8 @@ static int ntfs_link(struct dentry *ode, struct inode *dir, struct dentry *de)
err = ntfs_link_inode(inode, de);
if (!err) {
dir->i_mtime = inode_set_ctime_to_ts(inode,
inode_set_ctime_current(dir));
dir->i_mtime = inode_set_ctime_to_ts(
inode, inode_set_ctime_current(dir));
mark_inode_dirty(inode);
mark_inode_dirty(dir);
d_instantiate(de, inode);
......@@ -373,7 +373,7 @@ static int ntfs_atomic_open(struct inode *dir, struct dentry *dentry,
#ifdef CONFIG_NTFS3_FS_POSIX_ACL
if (IS_POSIXACL(dir)) {
/*
/*
* Load in cache current acl to avoid ni_lock(dir):
* ntfs_create_inode -> ntfs_init_acl -> posix_acl_create ->
* ntfs_get_acl -> ntfs_get_acl_ex -> ni_lock
......
......@@ -847,7 +847,7 @@ struct OBJECT_ID {
// Birth Volume Id is the Object Id of the Volume on.
// which the Object Id was allocated. It never changes.
struct GUID BirthVolumeId; //0x10:
// Birth Object Id is the first Object Id that was
// ever assigned to this MFT Record. I.e. If the Object Id
// is changed for some reason, this field will reflect the
......
......@@ -42,9 +42,11 @@ enum utf16_endian;
#define MINUS_ONE_T ((size_t)(-1))
/* Biggest MFT / smallest cluster */
#define MAXIMUM_BYTES_PER_MFT 4096
#define MAXIMUM_SHIFT_BYTES_PER_MFT 12
#define NTFS_BLOCKS_PER_MFT_RECORD (MAXIMUM_BYTES_PER_MFT / 512)
#define MAXIMUM_BYTES_PER_INDEX 4096
#define MAXIMUM_SHIFT_BYTES_PER_INDEX 12
#define NTFS_BLOCKS_PER_INODE (MAXIMUM_BYTES_PER_INDEX / 512)
/* NTFS specific error code when fixup failed. */
......@@ -495,8 +497,6 @@ int ntfs_getattr(struct mnt_idmap *idmap, const struct path *path,
struct kstat *stat, u32 request_mask, u32 flags);
int ntfs3_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
struct iattr *attr);
void ntfs_sparse_cluster(struct inode *inode, struct page *page0, CLST vcn,
CLST len);
int ntfs_file_open(struct inode *inode, struct file *file);
int ntfs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
__u64 start, __u64 len);
......
......@@ -189,12 +189,19 @@ int mi_read(struct mft_inode *mi, bool is_mft)
return err;
}
/*
* mi_enum_attr - start/continue attributes enumeration in record.
*
* NOTE: mi->mrec - memory of size sbi->record_size
* here we sure that mi->mrec->total == sbi->record_size (see mi_read)
*/
struct ATTRIB *mi_enum_attr(struct mft_inode *mi, struct ATTRIB *attr)
{
const struct MFT_REC *rec = mi->mrec;
u32 used = le32_to_cpu(rec->used);
u32 t32, off, asize;
u32 t32, off, asize, prev_type;
u16 t16;
u64 data_size, alloc_size, tot_size;
if (!attr) {
u32 total = le32_to_cpu(rec->total);
......@@ -213,6 +220,7 @@ struct ATTRIB *mi_enum_attr(struct mft_inode *mi, struct ATTRIB *attr)
if (!is_rec_inuse(rec))
return NULL;
prev_type = 0;
attr = Add2Ptr(rec, off);
} else {
/* Check if input attr inside record. */
......@@ -226,11 +234,11 @@ struct ATTRIB *mi_enum_attr(struct mft_inode *mi, struct ATTRIB *attr)
return NULL;
}
if (off + asize < off) {
/* Overflow check. */
/* Overflow check. */
if (off + asize < off)
return NULL;
}
prev_type = le32_to_cpu(attr->type);
attr = Add2Ptr(attr, asize);
off += asize;
}
......@@ -250,7 +258,11 @@ struct ATTRIB *mi_enum_attr(struct mft_inode *mi, struct ATTRIB *attr)
/* 0x100 is last known attribute for now. */
t32 = le32_to_cpu(attr->type);
if ((t32 & 0xf) || (t32 > 0x100))
if (!t32 || (t32 & 0xf) || (t32 > 0x100))
return NULL;
/* attributes in record must be ordered by type */
if (t32 < prev_type)
return NULL;
/* Check overflow and boundary. */
......@@ -259,16 +271,15 @@ struct ATTRIB *mi_enum_attr(struct mft_inode *mi, struct ATTRIB *attr)
/* Check size of attribute. */
if (!attr->non_res) {
/* Check resident fields. */
if (asize < SIZEOF_RESIDENT)
return NULL;
t16 = le16_to_cpu(attr->res.data_off);
if (t16 > asize)
return NULL;
t32 = le32_to_cpu(attr->res.data_size);
if (t16 + t32 > asize)
if (t16 + le32_to_cpu(attr->res.data_size) > asize)
return NULL;
t32 = sizeof(short) * attr->name_len;
......@@ -278,21 +289,52 @@ struct ATTRIB *mi_enum_attr(struct mft_inode *mi, struct ATTRIB *attr)
return attr;
}
/* Check some nonresident fields. */
if (attr->name_len &&
le16_to_cpu(attr->name_off) + sizeof(short) * attr->name_len >
le16_to_cpu(attr->nres.run_off)) {
/* Check nonresident fields. */
if (attr->non_res != 1)
return NULL;
t16 = le16_to_cpu(attr->nres.run_off);
if (t16 > asize)
return NULL;
t32 = sizeof(short) * attr->name_len;
if (t32 && le16_to_cpu(attr->name_off) + t32 > t16)
return NULL;
/* Check start/end vcn. */
if (le64_to_cpu(attr->nres.svcn) > le64_to_cpu(attr->nres.evcn) + 1)
return NULL;
}
if (attr->nres.svcn || !is_attr_ext(attr)) {
data_size = le64_to_cpu(attr->nres.data_size);
if (le64_to_cpu(attr->nres.valid_size) > data_size)
return NULL;
alloc_size = le64_to_cpu(attr->nres.alloc_size);
if (data_size > alloc_size)
return NULL;
t32 = mi->sbi->cluster_mask;
if (alloc_size & t32)
return NULL;
if (!attr->nres.svcn && is_attr_ext(attr)) {
/* First segment of sparse/compressed attribute */
if (asize + 8 < SIZEOF_NONRESIDENT_EX)
return NULL;
tot_size = le64_to_cpu(attr->nres.total_size);
if (tot_size & t32)
return NULL;
if (tot_size > alloc_size)
return NULL;
} else {
if (asize + 8 < SIZEOF_NONRESIDENT)
return NULL;
if (attr->nres.c_unit)
return NULL;
} else if (asize + 8 < SIZEOF_NONRESIDENT_EX)
return NULL;
}
return attr;
}
......
......@@ -453,15 +453,23 @@ static struct proc_dir_entry *proc_info_root;
* ntfs3.1
* cluster size
* number of clusters
* total number of mft records
* number of used mft records ~= number of files + folders
* real state of ntfs "dirty"/"clean"
* current state of ntfs "dirty"/"clean"
*/
static int ntfs3_volinfo(struct seq_file *m, void *o)
{
struct super_block *sb = m->private;
struct ntfs_sb_info *sbi = sb->s_fs_info;
seq_printf(m, "ntfs%d.%d\n%u\n%zu\n", sbi->volume.major_ver,
sbi->volume.minor_ver, sbi->cluster_size,
sbi->used.bitmap.nbits);
seq_printf(m, "ntfs%d.%d\n%u\n%zu\n\%zu\n%zu\n%s\n%s\n",
sbi->volume.major_ver, sbi->volume.minor_ver,
sbi->cluster_size, sbi->used.bitmap.nbits,
sbi->mft.bitmap.nbits,
sbi->mft.bitmap.nbits - wnd_zeroes(&sbi->mft.bitmap),
sbi->volume.real_dirty ? "dirty" : "clean",
(sbi->volume.flags & VOLUME_FLAG_DIRTY) ? "dirty" : "clean");
return 0;
}
......@@ -488,9 +496,13 @@ static ssize_t ntfs3_label_write(struct file *file, const char __user *buffer,
{
int err;
struct super_block *sb = pde_data(file_inode(file));
struct ntfs_sb_info *sbi = sb->s_fs_info;
ssize_t ret = count;
u8 *label = kmalloc(count, GFP_NOFS);
u8 *label;
if (sb_rdonly(sb))
return -EROFS;
label = kmalloc(count, GFP_NOFS);
if (!label)
return -ENOMEM;
......@@ -502,7 +514,7 @@ static ssize_t ntfs3_label_write(struct file *file, const char __user *buffer,
while (ret > 0 && label[ret - 1] == '\n')
ret -= 1;
err = ntfs_set_label(sbi, label, ret);
err = ntfs_set_label(sb->s_fs_info, label, ret);
if (err < 0) {
ntfs_err(sb, "failed (%d) to write label", err);
......@@ -576,20 +588,30 @@ static noinline void ntfs3_put_sbi(struct ntfs_sb_info *sbi)
wnd_close(&sbi->mft.bitmap);
wnd_close(&sbi->used.bitmap);
if (sbi->mft.ni)
if (sbi->mft.ni) {
iput(&sbi->mft.ni->vfs_inode);
sbi->mft.ni = NULL;
}
if (sbi->security.ni)
if (sbi->security.ni) {
iput(&sbi->security.ni->vfs_inode);
sbi->security.ni = NULL;
}
if (sbi->reparse.ni)
if (sbi->reparse.ni) {
iput(&sbi->reparse.ni->vfs_inode);
sbi->reparse.ni = NULL;
}
if (sbi->objid.ni)
if (sbi->objid.ni) {
iput(&sbi->objid.ni->vfs_inode);
sbi->objid.ni = NULL;
}
if (sbi->volume.ni)
if (sbi->volume.ni) {
iput(&sbi->volume.ni->vfs_inode);
sbi->volume.ni = NULL;
}
ntfs_update_mftmirr(sbi, 0);
......@@ -836,7 +858,7 @@ static int ntfs_init_from_boot(struct super_block *sb, u32 sector_size,
struct ntfs_sb_info *sbi = sb->s_fs_info;
int err;
u32 mb, gb, boot_sector_size, sct_per_clst, record_size;
u64 sectors, clusters, mlcn, mlcn2;
u64 sectors, clusters, mlcn, mlcn2, dev_size0;
struct NTFS_BOOT *boot;
struct buffer_head *bh;
struct MFT_REC *rec;
......@@ -845,6 +867,9 @@ static int ntfs_init_from_boot(struct super_block *sb, u32 sector_size,
u32 boot_off = 0;
const char *hint = "Primary boot";
/* Save original dev_size. Used with alternative boot. */
dev_size0 = dev_size;
sbi->volume.blocks = dev_size >> PAGE_SHIFT;
bh = ntfs_bread(sb, 0);
......@@ -853,6 +878,11 @@ static int ntfs_init_from_boot(struct super_block *sb, u32 sector_size,
check_boot:
err = -EINVAL;
/* Corrupted image; do not read OOB */
if (bh->b_size - sizeof(*boot) < boot_off)
goto out;
boot = (struct NTFS_BOOT *)Add2Ptr(bh->b_data, boot_off);
if (memcmp(boot->system_id, "NTFS ", sizeof("NTFS ") - 1)) {
......@@ -899,9 +929,17 @@ static int ntfs_init_from_boot(struct super_block *sb, u32 sector_size,
goto out;
}
sbi->record_size = record_size =
boot->record_size < 0 ? 1 << (-boot->record_size) :
(u32)boot->record_size << cluster_bits;
if (boot->record_size >= 0) {
record_size = (u32)boot->record_size << cluster_bits;
} else if (-boot->record_size <= MAXIMUM_SHIFT_BYTES_PER_MFT) {
record_size = 1u << (-boot->record_size);
} else {
ntfs_err(sb, "%s: invalid record size %d.", hint,
boot->record_size);
goto out;
}
sbi->record_size = record_size;
sbi->record_bits = blksize_bits(record_size);
sbi->attr_size_tr = (5 * record_size >> 4); // ~320 bytes
......@@ -918,9 +956,15 @@ static int ntfs_init_from_boot(struct super_block *sb, u32 sector_size,
goto out;
}
sbi->index_size = boot->index_size < 0 ?
1u << (-boot->index_size) :
(u32)boot->index_size << cluster_bits;
if (boot->index_size >= 0) {
sbi->index_size = (u32)boot->index_size << cluster_bits;
} else if (-boot->index_size <= MAXIMUM_SHIFT_BYTES_PER_INDEX) {
sbi->index_size = 1u << (-boot->index_size);
} else {
ntfs_err(sb, "%s: invalid index size %d.", hint,
boot->index_size);
goto out;
}
/* Check index record size. */
if (sbi->index_size < SECTOR_SIZE || !is_power_of_2(sbi->index_size)) {
......@@ -1055,17 +1099,17 @@ static int ntfs_init_from_boot(struct super_block *sb, u32 sector_size,
if (bh->b_blocknr && !sb_rdonly(sb)) {
/*
* Alternative boot is ok but primary is not ok.
* Do not update primary boot here 'cause it may be faked boot.
* Let ntfs to be mounted and update boot later.
*/
* Alternative boot is ok but primary is not ok.
* Do not update primary boot here 'cause it may be faked boot.
* Let ntfs to be mounted and update boot later.
*/
*boot2 = kmemdup(boot, sizeof(*boot), GFP_NOFS | __GFP_NOWARN);
}
out:
if (err == -EINVAL && !bh->b_blocknr && dev_size > PAGE_SHIFT) {
if (err == -EINVAL && !bh->b_blocknr && dev_size0 > PAGE_SHIFT) {
u32 block_size = min_t(u32, sector_size, PAGE_SIZE);
u64 lbo = dev_size - sizeof(*boot);
u64 lbo = dev_size0 - sizeof(*boot);
/*
* Try alternative boot (last sector)
......@@ -1079,6 +1123,7 @@ static int ntfs_init_from_boot(struct super_block *sb, u32 sector_size,
boot_off = lbo & (block_size - 1);
hint = "Alternative boot";
dev_size = dev_size0; /* restore original size. */
goto check_boot;
}
brelse(bh);
......@@ -1367,7 +1412,7 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
}
bytes = inode->i_size;
sbi->def_table = t = kmalloc(bytes, GFP_NOFS | __GFP_NOWARN);
sbi->def_table = t = kvmalloc(bytes, GFP_KERNEL);
if (!t) {
err = -ENOMEM;
goto put_inode_out;
......@@ -1521,9 +1566,9 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
if (boot2) {
/*
* Alternative boot is ok but primary is not ok.
* Volume is recognized as NTFS. Update primary boot.
*/
* Alternative boot is ok but primary is not ok.
* Volume is recognized as NTFS. Update primary boot.
*/
struct buffer_head *bh0 = sb_getblk(sb, 0);
if (bh0) {
if (buffer_locked(bh0))
......@@ -1564,6 +1609,7 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
out:
ntfs3_put_sbi(sbi);
kfree(boot2);
ntfs3_put_sbi(sbi);
return err;
}
......@@ -1757,7 +1803,6 @@ static int __init init_ntfs_fs(void)
if (IS_ENABLED(CONFIG_NTFS3_LZX_XPRESS))
pr_info("ntfs3: Read-only LZX/Xpress compression included\n");
#ifdef CONFIG_PROC_FS
/* Create "/proc/fs/ntfs3" */
proc_info_root = proc_mkdir("fs/ntfs3", NULL);
......@@ -1799,7 +1844,6 @@ static void __exit exit_ntfs_fs(void)
if (proc_info_root)
remove_proc_entry("fs/ntfs3", NULL);
#endif
}
MODULE_LICENSE("GPL");
......
......@@ -211,7 +211,8 @@ static ssize_t ntfs_list_ea(struct ntfs_inode *ni, char *buffer,
size = le32_to_cpu(info->size);
/* Enumerate all xattrs. */
for (ret = 0, off = 0; off < size; off += ea_size) {
ret = 0;
for (off = 0; off + sizeof(struct EA_FULL) < size; off += ea_size) {
ea = Add2Ptr(ea_all, off);
ea_size = unpacked_ea_size(ea);
......@@ -219,6 +220,10 @@ static ssize_t ntfs_list_ea(struct ntfs_inode *ni, char *buffer,
break;
if (buffer) {
/* Check if we can use field ea->name */
if (off + ea_size > size)
break;
if (ret + ea->name_len + 1 > bytes_per_buffer) {
err = -ERANGE;
goto out;
......
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