ext4: store maxbytes for bitmapped files and return EFBIG as appropriate
Calculate & store the max offset for bitmapped files, and catch too-large seeks, truncates, and writes in ext4, shortening or rejecting as appropriate. Signed-off-by: Eric Sandeen <sandeen@redhat.com>
This commit is contained in:
committed by
Theodore Ts'o
parent
19295529db
commit
e2b4657453
@@ -56,8 +56,25 @@ ext4_file_write(struct kiocb *iocb, const struct iovec *iov,
|
|||||||
ssize_t ret;
|
ssize_t ret;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
ret = generic_file_aio_write(iocb, iov, nr_segs, pos);
|
/*
|
||||||
|
* If we have encountered a bitmap-format file, the size limit
|
||||||
|
* is smaller than s_maxbytes, which is for extent-mapped files.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!(EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL)) {
|
||||||
|
struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
|
||||||
|
size_t length = iov_length(iov, nr_segs);
|
||||||
|
|
||||||
|
if (pos > sbi->s_bitmap_maxbytes)
|
||||||
|
return -EFBIG;
|
||||||
|
|
||||||
|
if (pos + length > sbi->s_bitmap_maxbytes) {
|
||||||
|
nr_segs = iov_shorten((struct iovec *)iov, nr_segs,
|
||||||
|
sbi->s_bitmap_maxbytes - pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = generic_file_aio_write(iocb, iov, nr_segs, pos);
|
||||||
/*
|
/*
|
||||||
* Skip flushing if there was an error, or if nothing was written.
|
* Skip flushing if there was an error, or if nothing was written.
|
||||||
*/
|
*/
|
||||||
|
@@ -314,7 +314,10 @@ static int ext4_block_to_path(struct inode *inode,
|
|||||||
offsets[n++] = i_block & (ptrs - 1);
|
offsets[n++] = i_block & (ptrs - 1);
|
||||||
final = ptrs;
|
final = ptrs;
|
||||||
} else {
|
} else {
|
||||||
ext4_warning(inode->i_sb, "ext4_block_to_path", "block > big");
|
ext4_warning(inode->i_sb, "ext4_block_to_path",
|
||||||
|
"block %u > max",
|
||||||
|
i_block + direct_blocks +
|
||||||
|
indirect_blocks + double_blocks);
|
||||||
}
|
}
|
||||||
if (boundary)
|
if (boundary)
|
||||||
*boundary = final - 1 - (i_block & (ptrs - 1));
|
*boundary = final - 1 - (i_block & (ptrs - 1));
|
||||||
@@ -3092,6 +3095,17 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr)
|
|||||||
ext4_journal_stop(handle);
|
ext4_journal_stop(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (attr->ia_valid & ATTR_SIZE) {
|
||||||
|
if (!(EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL)) {
|
||||||
|
struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
|
||||||
|
|
||||||
|
if (attr->ia_size > sbi->s_bitmap_maxbytes) {
|
||||||
|
error = -EFBIG;
|
||||||
|
goto err_out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (S_ISREG(inode->i_mode) &&
|
if (S_ISREG(inode->i_mode) &&
|
||||||
attr->ia_valid & ATTR_SIZE && attr->ia_size < inode->i_size) {
|
attr->ia_valid & ATTR_SIZE && attr->ia_size < inode->i_size) {
|
||||||
handle_t *handle;
|
handle_t *handle;
|
||||||
|
@@ -1922,6 +1922,7 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sbi->s_bitmap_maxbytes = ext4_max_bitmap_size(sb->s_blocksize_bits);
|
||||||
sb->s_maxbytes = ext4_max_size(sb->s_blocksize_bits);
|
sb->s_maxbytes = ext4_max_size(sb->s_blocksize_bits);
|
||||||
|
|
||||||
if (le32_to_cpu(es->s_rev_level) == EXT4_GOOD_OLD_REV) {
|
if (le32_to_cpu(es->s_rev_level) == EXT4_GOOD_OLD_REV) {
|
||||||
|
@@ -38,6 +38,7 @@ struct ext4_sb_info {
|
|||||||
ext4_group_t s_groups_count; /* Number of groups in the fs */
|
ext4_group_t s_groups_count; /* Number of groups in the fs */
|
||||||
unsigned long s_overhead_last; /* Last calculated overhead */
|
unsigned long s_overhead_last; /* Last calculated overhead */
|
||||||
unsigned long s_blocks_last; /* Last seen block count */
|
unsigned long s_blocks_last; /* Last seen block count */
|
||||||
|
loff_t s_bitmap_maxbytes; /* max bytes for bitmap files */
|
||||||
struct buffer_head * s_sbh; /* Buffer containing the super block */
|
struct buffer_head * s_sbh; /* Buffer containing the super block */
|
||||||
struct ext4_super_block * s_es; /* Pointer to the super block in the buffer */
|
struct ext4_super_block * s_es; /* Pointer to the super block in the buffer */
|
||||||
struct buffer_head ** s_group_desc;
|
struct buffer_head ** s_group_desc;
|
||||||
|
Reference in New Issue
Block a user