Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e2b46574 authored by Eric Sandeen's avatar Eric Sandeen Committed by Theodore Ts'o
Browse files

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: default avatarEric Sandeen <sandeen@redhat.com>
parent 19295529
Loading
Loading
Loading
Loading
+18 −1
Original line number Original line Diff line number Diff line
@@ -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.
	 */
	 */
+15 −1
Original line number Original line Diff line number Diff line
@@ -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;
+1 −0
Original line number Original line Diff line number Diff line
@@ -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) {
+1 −0
Original line number Original line Diff line number Diff line
@@ -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;