mirror of
git://git.yoctoproject.org/linux-yocto.git
synced 2025-10-22 23:13:01 +02:00
Changes for 6.15-rc1
Fixed: integer overflows on 32-bit systems; integer overflow in hdr_first_de(); 'proc_info_root' leak when NTFS initialization failed. Removed: unused functions ni_load_attr, ntfs_sb_read, ntfs_flush_inodes. Changed: updated inode->i_mapping->a_ops on compression state; ensured atomicity of write operations; refactored ntfs_{create/remove}_procdir(); refactored ntfs_{create/remove}_proc_root(). -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEh0DEKNP0I9IjwfWEqbAzH4MkB7YFAmfruBwACgkQqbAzH4Mk B7bEVhAApRbsnqA1R6xPc7nroKagZBVhBKANOND8Duxvdt7fkWVWRYlSzvngpEMc ikLhqQVx+6MEuQXuw3B8r1/HnCjfWxyiC4eIwTC8qdt3rG8LWdAn3qOdMSKGcw5t fHvV9o2kwM8JwI6GQ5KSBloirbPcDLsuuriT77aw8jRGQICcpDW84YhVQ4kT78si DEuIXxBuYzpeNxtvn3YVU4w3IIjPlM4pfPpMD+NdpGuwJJytNqugc1iU+JUR9Rbe AGNPuMdWLMhX8oB0JLn5WUyVtdLWbrCOWq460YLCkqvv6ceD2vQdYo0Eq5Jq6z1D PpT1hnGAO6NeBaq8Fy0t1eFMAqIjxVK0zes8HKvmC6NiOZY7qrp1h/SFkzI0Nr0c B5pYyng4DCNu+fVb9z72tI3GyBlu/puaSvZARXXwzJAleb1ZnXu6LWz3kf4ZqnuC BvSyCLvQGYeKN9Ml3ImIwh1o/MrHlk0KFKr5nvNeMmSWZRX9rHAfTD8dMtjlRqae flhCLqudAeSvcki/qQ3qC59xiYDJj+1ZyJcqQARZzBJd3HfJ2aQ+AQM5xHOshbHH WZWn6QaV0rLMue9KI4lro22er4kPO/rfCWi63xnHAqeiGVEza97Q1nlrlOpi1Fjh 96+RVyUNxYW/aAp9tMLUI2Cha1sMNrFnm6rXLr6IDsSOdtRLxIk= =N3l4 -----END PGP SIGNATURE----- Merge tag 'ntfs3_for_6.15' of https://github.com/Paragon-Software-Group/linux-ntfs3 Pull ntfs3 updates from Konstantin Komarov: - Fix integer overflows on 32-bit systems and in hdr_first_de() - Fix 'proc_info_root' leak on NTFS initialization failure - Remove unused functions ni_load_attr, ntfs_sb_read, ntfs_flush_inodes - update inode->i_mapping->a_ops on compression state - ensure atomicity of write operations - refactor ntfs_{create/remove}_{procdir,proc_root}() * tag 'ntfs3_for_6.15' of https://github.com/Paragon-Software-Group/linux-ntfs3: fs/ntfs3: Remove unused ntfs_flush_inodes fs/ntfs3: Remove unused ntfs_sb_read fs/ntfs3: Remove unused ni_load_attr fs/ntfs3: Prevent integer overflow in hdr_first_de() fs/ntfs3: Fix a couple integer overflows on 32bit systems fs/ntfs3: Update inode->i_mapping->a_ops on compression state fs/ntfs3: Fix WARNING in ntfs_extend_initialized_size fs/ntfs3: Fix 'proc_info_root' leak when init ntfs failed fs/ntfs3: Factor out ntfs_{create/remove}_proc_root() fs/ntfs3: Factor out ntfs_{create/remove}_procdir() fs/ntfs3: Keep write operations atomic
This commit is contained in:
commit
0cc5543fad
|
@ -2664,8 +2664,9 @@ int attr_set_compress(struct ntfs_inode *ni, bool compr)
|
|||
attr->nres.run_off = cpu_to_le16(run_off);
|
||||
}
|
||||
|
||||
/* Update data attribute flags. */
|
||||
/* Update attribute flags. */
|
||||
if (compr) {
|
||||
attr->flags &= ~ATTR_FLAG_SPARSED;
|
||||
attr->flags |= ATTR_FLAG_COMPRESSED;
|
||||
attr->nres.c_unit = NTFS_LZNT_CUNIT;
|
||||
} else {
|
||||
|
|
|
@ -101,8 +101,26 @@ int ntfs_fileattr_set(struct mnt_idmap *idmap, struct dentry *dentry,
|
|||
/* Allowed to change compression for empty files and for directories only. */
|
||||
if (!is_dedup(ni) && !is_encrypted(ni) &&
|
||||
(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode))) {
|
||||
/* Change compress state. */
|
||||
int err = ni_set_compress(inode, flags & FS_COMPR_FL);
|
||||
int err = 0;
|
||||
struct address_space *mapping = inode->i_mapping;
|
||||
|
||||
/* write out all data and wait. */
|
||||
filemap_invalidate_lock(mapping);
|
||||
err = filemap_write_and_wait(mapping);
|
||||
|
||||
if (err >= 0) {
|
||||
/* Change compress state. */
|
||||
bool compr = flags & FS_COMPR_FL;
|
||||
err = ni_set_compress(inode, compr);
|
||||
|
||||
/* For files change a_ops too. */
|
||||
if (!err)
|
||||
mapping->a_ops = compr ? &ntfs_aops_cmpr :
|
||||
&ntfs_aops;
|
||||
}
|
||||
|
||||
filemap_invalidate_unlock(mapping);
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
@ -412,6 +430,7 @@ static int ntfs_extend(struct inode *inode, loff_t pos, size_t count,
|
|||
}
|
||||
|
||||
if (extend_init && !is_compressed(ni)) {
|
||||
WARN_ON(ni->i_valid >= pos);
|
||||
err = ntfs_extend_initialized_size(file, ni, ni->i_valid, pos);
|
||||
if (err)
|
||||
goto out;
|
||||
|
@ -1228,21 +1247,22 @@ static ssize_t ntfs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
|
|||
ssize_t ret;
|
||||
int err;
|
||||
|
||||
err = check_write_restriction(inode);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (is_compressed(ni) && (iocb->ki_flags & IOCB_DIRECT)) {
|
||||
ntfs_inode_warn(inode, "direct i/o + compressed not supported");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (!inode_trylock(inode)) {
|
||||
if (iocb->ki_flags & IOCB_NOWAIT)
|
||||
return -EAGAIN;
|
||||
inode_lock(inode);
|
||||
}
|
||||
|
||||
ret = check_write_restriction(inode);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
if (is_compressed(ni) && (iocb->ki_flags & IOCB_DIRECT)) {
|
||||
ntfs_inode_warn(inode, "direct i/o + compressed not supported");
|
||||
ret = -EOPNOTSUPP;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = generic_write_checks(iocb, from);
|
||||
if (ret <= 0)
|
||||
goto out;
|
||||
|
|
|
@ -280,63 +280,6 @@ struct ATTRIB *ni_enum_attr_ex(struct ntfs_inode *ni, struct ATTRIB *attr,
|
|||
return rec_find_attr_le(ni, mi2, le2);
|
||||
}
|
||||
|
||||
/*
|
||||
* ni_load_attr - Load attribute that contains given VCN.
|
||||
*/
|
||||
struct ATTRIB *ni_load_attr(struct ntfs_inode *ni, enum ATTR_TYPE type,
|
||||
const __le16 *name, u8 name_len, CLST vcn,
|
||||
struct mft_inode **pmi)
|
||||
{
|
||||
struct ATTR_LIST_ENTRY *le;
|
||||
struct ATTRIB *attr;
|
||||
struct mft_inode *mi;
|
||||
struct ATTR_LIST_ENTRY *next;
|
||||
|
||||
if (!ni->attr_list.size) {
|
||||
if (pmi)
|
||||
*pmi = &ni->mi;
|
||||
return mi_find_attr(ni, &ni->mi, NULL, type, name, name_len,
|
||||
NULL);
|
||||
}
|
||||
|
||||
le = al_find_ex(ni, NULL, type, name, name_len, NULL);
|
||||
if (!le)
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* Unfortunately ATTR_LIST_ENTRY contains only start VCN.
|
||||
* So to find the ATTRIB segment that contains 'vcn' we should
|
||||
* enumerate some entries.
|
||||
*/
|
||||
if (vcn) {
|
||||
for (;; le = next) {
|
||||
next = al_find_ex(ni, le, type, name, name_len, NULL);
|
||||
if (!next || le64_to_cpu(next->vcn) > vcn)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ni_load_mi(ni, le, &mi))
|
||||
return NULL;
|
||||
|
||||
if (pmi)
|
||||
*pmi = mi;
|
||||
|
||||
attr = mi_find_attr(ni, mi, NULL, type, name, name_len, &le->id);
|
||||
if (!attr)
|
||||
return NULL;
|
||||
|
||||
if (!attr->non_res)
|
||||
return attr;
|
||||
|
||||
if (le64_to_cpu(attr->nres.svcn) <= vcn &&
|
||||
vcn <= le64_to_cpu(attr->nres.evcn))
|
||||
return attr;
|
||||
|
||||
_ntfs_bad_inode(&ni->vfs_inode);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* ni_load_all_mi - Load all subrecords.
|
||||
*/
|
||||
|
@ -3434,10 +3377,12 @@ int ni_set_compress(struct inode *inode, bool compr)
|
|||
}
|
||||
|
||||
ni->std_fa = std->fa;
|
||||
if (compr)
|
||||
if (compr) {
|
||||
std->fa &= ~FILE_ATTRIBUTE_SPARSE_FILE;
|
||||
std->fa |= FILE_ATTRIBUTE_COMPRESSED;
|
||||
else
|
||||
} else {
|
||||
std->fa &= ~FILE_ATTRIBUTE_COMPRESSED;
|
||||
}
|
||||
|
||||
if (ni->std_fa != std->fa) {
|
||||
ni->std_fa = std->fa;
|
||||
|
|
|
@ -1035,34 +1035,6 @@ struct buffer_head *ntfs_bread(struct super_block *sb, sector_t block)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
int ntfs_sb_read(struct super_block *sb, u64 lbo, size_t bytes, void *buffer)
|
||||
{
|
||||
struct block_device *bdev = sb->s_bdev;
|
||||
u32 blocksize = sb->s_blocksize;
|
||||
u64 block = lbo >> sb->s_blocksize_bits;
|
||||
u32 off = lbo & (blocksize - 1);
|
||||
u32 op = blocksize - off;
|
||||
|
||||
for (; bytes; block += 1, off = 0, op = blocksize) {
|
||||
struct buffer_head *bh = __bread(bdev, block, blocksize);
|
||||
|
||||
if (!bh)
|
||||
return -EIO;
|
||||
|
||||
if (op > bytes)
|
||||
op = bytes;
|
||||
|
||||
memcpy(buffer, bh->b_data + off, op);
|
||||
|
||||
put_bh(bh);
|
||||
|
||||
bytes -= op;
|
||||
buffer = Add2Ptr(buffer, op);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ntfs_sb_write(struct super_block *sb, u64 lbo, size_t bytes,
|
||||
const void *buf, int wait)
|
||||
{
|
||||
|
|
|
@ -618,7 +618,7 @@ static bool index_hdr_check(const struct INDEX_HDR *hdr, u32 bytes)
|
|||
u32 off = le32_to_cpu(hdr->de_off);
|
||||
|
||||
if (!IS_ALIGNED(off, 8) || tot > bytes || end > tot ||
|
||||
off + sizeof(struct NTFS_DE) > end) {
|
||||
size_add(off, sizeof(struct NTFS_DE)) > end) {
|
||||
/* incorrect index buffer. */
|
||||
return false;
|
||||
}
|
||||
|
@ -736,7 +736,7 @@ fill_table:
|
|||
if (end > total)
|
||||
return NULL;
|
||||
|
||||
if (off + sizeof(struct NTFS_DE) > end)
|
||||
if (size_add(off, sizeof(struct NTFS_DE)) > end)
|
||||
return NULL;
|
||||
|
||||
e = Add2Ptr(hdr, off);
|
||||
|
|
|
@ -1024,46 +1024,6 @@ int ntfs_sync_inode(struct inode *inode)
|
|||
return _ni_write_inode(inode, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* writeback_inode - Helper function for ntfs_flush_inodes().
|
||||
*
|
||||
* This writes both the inode and the file data blocks, waiting
|
||||
* for in flight data blocks before the start of the call. It
|
||||
* does not wait for any io started during the call.
|
||||
*/
|
||||
static int writeback_inode(struct inode *inode)
|
||||
{
|
||||
int ret = sync_inode_metadata(inode, 0);
|
||||
|
||||
if (!ret)
|
||||
ret = filemap_fdatawrite(inode->i_mapping);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* ntfs_flush_inodes
|
||||
*
|
||||
* Write data and metadata corresponding to i1 and i2. The io is
|
||||
* started but we do not wait for any of it to finish.
|
||||
*
|
||||
* filemap_flush() is used for the block device, so if there is a dirty
|
||||
* page for a block already in flight, we will not wait and start the
|
||||
* io over again.
|
||||
*/
|
||||
int ntfs_flush_inodes(struct super_block *sb, struct inode *i1,
|
||||
struct inode *i2)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (i1)
|
||||
ret = writeback_inode(i1);
|
||||
if (!ret && i2)
|
||||
ret = writeback_inode(i2);
|
||||
if (!ret)
|
||||
ret = filemap_flush(sb->s_bdev_file->f_mapping);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper function to read file.
|
||||
*/
|
||||
|
|
|
@ -717,7 +717,7 @@ static inline struct NTFS_DE *hdr_first_de(const struct INDEX_HDR *hdr)
|
|||
struct NTFS_DE *e;
|
||||
u16 esize;
|
||||
|
||||
if (de_off >= used || de_off + sizeof(struct NTFS_DE) > used )
|
||||
if (de_off >= used || size_add(de_off, sizeof(struct NTFS_DE)) > used)
|
||||
return NULL;
|
||||
|
||||
e = Add2Ptr(hdr, de_off);
|
||||
|
|
|
@ -530,9 +530,6 @@ struct ATTRIB *ni_find_attr(struct ntfs_inode *ni, struct ATTRIB *attr,
|
|||
struct ATTRIB *ni_enum_attr_ex(struct ntfs_inode *ni, struct ATTRIB *attr,
|
||||
struct ATTR_LIST_ENTRY **le,
|
||||
struct mft_inode **mi);
|
||||
struct ATTRIB *ni_load_attr(struct ntfs_inode *ni, enum ATTR_TYPE type,
|
||||
const __le16 *name, u8 name_len, CLST vcn,
|
||||
struct mft_inode **pmi);
|
||||
int ni_load_all_mi(struct ntfs_inode *ni);
|
||||
bool ni_add_subrecord(struct ntfs_inode *ni, CLST rno, struct mft_inode **mi);
|
||||
int ni_remove_attr(struct ntfs_inode *ni, enum ATTR_TYPE type,
|
||||
|
@ -619,7 +616,6 @@ enum NTFS_DIRTY_FLAGS {
|
|||
NTFS_DIRTY_ERROR = 2,
|
||||
};
|
||||
int ntfs_set_state(struct ntfs_sb_info *sbi, enum NTFS_DIRTY_FLAGS dirty);
|
||||
int ntfs_sb_read(struct super_block *sb, u64 lbo, size_t bytes, void *buffer);
|
||||
int ntfs_sb_write(struct super_block *sb, u64 lbo, size_t bytes,
|
||||
const void *buffer, int wait);
|
||||
int ntfs_sb_write_run(struct ntfs_sb_info *sbi, const struct runs_tree *run,
|
||||
|
@ -717,8 +713,6 @@ int ntfs_write_end(struct file *file, struct address_space *mapping, loff_t pos,
|
|||
u32 len, u32 copied, struct folio *folio, void *fsdata);
|
||||
int ntfs3_write_inode(struct inode *inode, struct writeback_control *wbc);
|
||||
int ntfs_sync_inode(struct inode *inode);
|
||||
int ntfs_flush_inodes(struct super_block *sb, struct inode *i1,
|
||||
struct inode *i2);
|
||||
int inode_read_data(struct inode *inode, void *data, size_t bytes);
|
||||
int ntfs_create_inode(struct mnt_idmap *idmap, struct inode *dir,
|
||||
struct dentry *dentry, const struct cpu_str *uni,
|
||||
|
|
|
@ -555,6 +555,55 @@ static const struct proc_ops ntfs3_label_fops = {
|
|||
.proc_write = ntfs3_label_write,
|
||||
};
|
||||
|
||||
static void ntfs_create_procdir(struct super_block *sb)
|
||||
{
|
||||
struct proc_dir_entry *e;
|
||||
|
||||
if (!proc_info_root)
|
||||
return;
|
||||
|
||||
e = proc_mkdir(sb->s_id, proc_info_root);
|
||||
if (e) {
|
||||
struct ntfs_sb_info *sbi = sb->s_fs_info;
|
||||
|
||||
proc_create_data("volinfo", 0444, e,
|
||||
&ntfs3_volinfo_fops, sb);
|
||||
proc_create_data("label", 0644, e,
|
||||
&ntfs3_label_fops, sb);
|
||||
sbi->procdir = e;
|
||||
}
|
||||
}
|
||||
|
||||
static void ntfs_remove_procdir(struct super_block *sb)
|
||||
{
|
||||
struct ntfs_sb_info *sbi = sb->s_fs_info;
|
||||
|
||||
if (!sbi->procdir)
|
||||
return;
|
||||
|
||||
remove_proc_entry("label", sbi->procdir);
|
||||
remove_proc_entry("volinfo", sbi->procdir);
|
||||
remove_proc_entry(sb->s_id, proc_info_root);
|
||||
sbi->procdir = NULL;
|
||||
}
|
||||
|
||||
static void ntfs_create_proc_root(void)
|
||||
{
|
||||
proc_info_root = proc_mkdir("fs/ntfs3", NULL);
|
||||
}
|
||||
|
||||
static void ntfs_remove_proc_root(void)
|
||||
{
|
||||
if (proc_info_root) {
|
||||
remove_proc_entry("fs/ntfs3", NULL);
|
||||
proc_info_root = NULL;
|
||||
}
|
||||
}
|
||||
#else
|
||||
static void ntfs_create_procdir(struct super_block *sb) {}
|
||||
static void ntfs_remove_procdir(struct super_block *sb) {}
|
||||
static void ntfs_create_proc_root(void) {}
|
||||
static void ntfs_remove_proc_root(void) {}
|
||||
#endif
|
||||
|
||||
static struct kmem_cache *ntfs_inode_cachep;
|
||||
|
@ -644,15 +693,7 @@ static void ntfs_put_super(struct super_block *sb)
|
|||
{
|
||||
struct ntfs_sb_info *sbi = sb->s_fs_info;
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
// Remove /proc/fs/ntfs3/..
|
||||
if (sbi->procdir) {
|
||||
remove_proc_entry("label", sbi->procdir);
|
||||
remove_proc_entry("volinfo", sbi->procdir);
|
||||
remove_proc_entry(sb->s_id, proc_info_root);
|
||||
sbi->procdir = NULL;
|
||||
}
|
||||
#endif
|
||||
ntfs_remove_procdir(sb);
|
||||
|
||||
/* Mark rw ntfs as clear, if possible. */
|
||||
ntfs_set_state(sbi, NTFS_DIRTY_CLEAR);
|
||||
|
@ -1590,20 +1631,7 @@ load_root:
|
|||
kfree(boot2);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
/* Create /proc/fs/ntfs3/.. */
|
||||
if (proc_info_root) {
|
||||
struct proc_dir_entry *e = proc_mkdir(sb->s_id, proc_info_root);
|
||||
static_assert((S_IRUGO | S_IWUSR) == 0644);
|
||||
if (e) {
|
||||
proc_create_data("volinfo", S_IRUGO, e,
|
||||
&ntfs3_volinfo_fops, sb);
|
||||
proc_create_data("label", S_IRUGO | S_IWUSR, e,
|
||||
&ntfs3_label_fops, sb);
|
||||
sbi->procdir = e;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
ntfs_create_procdir(sb);
|
||||
|
||||
if (is_legacy_ntfs(sb))
|
||||
sb->s_flags |= SB_RDONLY;
|
||||
|
@ -1853,14 +1881,11 @@ 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);
|
||||
#endif
|
||||
ntfs_create_proc_root();
|
||||
|
||||
err = ntfs3_init_bitmap();
|
||||
if (err)
|
||||
return err;
|
||||
goto out2;
|
||||
|
||||
ntfs_inode_cachep = kmem_cache_create(
|
||||
"ntfs_inode_cache", sizeof(struct ntfs_inode), 0,
|
||||
|
@ -1880,6 +1905,8 @@ out:
|
|||
kmem_cache_destroy(ntfs_inode_cachep);
|
||||
out1:
|
||||
ntfs3_exit_bitmap();
|
||||
out2:
|
||||
ntfs_remove_proc_root();
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -1890,11 +1917,7 @@ static void __exit exit_ntfs_fs(void)
|
|||
unregister_filesystem(&ntfs_fs_type);
|
||||
unregister_as_ntfs_legacy();
|
||||
ntfs3_exit_bitmap();
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
if (proc_info_root)
|
||||
remove_proc_entry("fs/ntfs3", NULL);
|
||||
#endif
|
||||
ntfs_remove_proc_root();
|
||||
}
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
Loading…
Reference in New Issue
Block a user