diff options
Diffstat (limited to 'fs/ext4/inline.c')
| -rw-r--r-- | fs/ext4/inline.c | 17 | 
1 files changed, 14 insertions, 3 deletions
diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c index 859bc4e2c9b0..5854bd5a3352 100644 --- a/fs/ext4/inline.c +++ b/fs/ext4/inline.c @@ -34,6 +34,7 @@ static int get_max_inline_xattr_value_size(struct inode *inode,  	struct ext4_xattr_ibody_header *header;  	struct ext4_xattr_entry *entry;  	struct ext4_inode *raw_inode; +	void *end;  	int free, min_offs;  	if (!EXT4_INODE_HAS_XATTR_SPACE(inode)) @@ -57,14 +58,23 @@ static int get_max_inline_xattr_value_size(struct inode *inode,  	raw_inode = ext4_raw_inode(iloc);  	header = IHDR(inode, raw_inode);  	entry = IFIRST(header); +	end = (void *)raw_inode + EXT4_SB(inode->i_sb)->s_inode_size;  	/* Compute min_offs. */ -	for (; !IS_LAST_ENTRY(entry); entry = EXT4_XATTR_NEXT(entry)) { +	while (!IS_LAST_ENTRY(entry)) { +		void *next = EXT4_XATTR_NEXT(entry); + +		if (next >= end) { +			EXT4_ERROR_INODE(inode, +					 "corrupt xattr in inline inode"); +			return 0; +		}  		if (!entry->e_value_inum && entry->e_value_size) {  			size_t offs = le16_to_cpu(entry->e_value_offs);  			if (offs < min_offs)  				min_offs = offs;  		} +		entry = next;  	}  	free = min_offs -  		((void *)entry - (void *)IFIRST(header)) - sizeof(__u32); @@ -350,7 +360,7 @@ static int ext4_update_inline_data(handle_t *handle, struct inode *inode,  	error = ext4_xattr_ibody_get(inode, i.name_index, i.name,  				     value, len); -	if (error == -ENODATA) +	if (error < 0)  		goto out;  	BUFFER_TRACE(is.iloc.bh, "get_write_access"); @@ -1175,6 +1185,7 @@ static int ext4_finish_convert_inline_dir(handle_t *handle,  		ext4_initialize_dirent_tail(dir_block,  					    inode->i_sb->s_blocksize);  	set_buffer_uptodate(dir_block); +	unlock_buffer(dir_block);  	err = ext4_handle_dirty_dirblock(handle, inode, dir_block);  	if (err)  		return err; @@ -1249,6 +1260,7 @@ static int ext4_convert_inline_data_nolock(handle_t *handle,  	if (!S_ISDIR(inode->i_mode)) {  		memcpy(data_bh->b_data, buf, inline_size);  		set_buffer_uptodate(data_bh); +		unlock_buffer(data_bh);  		error = ext4_handle_dirty_metadata(handle,  						   inode, data_bh);  	} else { @@ -1256,7 +1268,6 @@ static int ext4_convert_inline_data_nolock(handle_t *handle,  						       buf, inline_size);  	} -	unlock_buffer(data_bh);  out_restore:  	if (error)  		ext4_restore_inline_data(handle, inode, iloc, buf, inline_size);  | 
