diff options
Diffstat (limited to 'fs/ext4/xattr.c')
| -rw-r--r-- | fs/ext4/xattr.c | 42 | 
1 files changed, 19 insertions, 23 deletions
diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c index 499cb4b1fbd2..723df14f4084 100644 --- a/fs/ext4/xattr.c +++ b/fs/ext4/xattr.c @@ -230,12 +230,12 @@ __ext4_xattr_check_block(struct inode *inode, struct buffer_head *bh,  {  	int error = -EFSCORRUPTED; -	if (buffer_verified(bh)) -		return 0; -  	if (BHDR(bh)->h_magic != cpu_to_le32(EXT4_XATTR_MAGIC) ||  	    BHDR(bh)->h_blocks != cpu_to_le32(1))  		goto errout; +	if (buffer_verified(bh)) +		return 0; +  	error = -EFSBADCRC;  	if (!ext4_xattr_block_csum_verify(inode, bh))  		goto errout; @@ -1560,7 +1560,7 @@ static int ext4_xattr_set_entry(struct ext4_xattr_info *i,  				handle_t *handle, struct inode *inode,  				bool is_block)  { -	struct ext4_xattr_entry *last; +	struct ext4_xattr_entry *last, *next;  	struct ext4_xattr_entry *here = s->here;  	size_t min_offs = s->end - s->base, name_len = strlen(i->name);  	int in_inode = i->in_inode; @@ -1595,7 +1595,13 @@ static int ext4_xattr_set_entry(struct ext4_xattr_info *i,  	/* Compute min_offs and last. */  	last = s->first; -	for (; !IS_LAST_ENTRY(last); last = EXT4_XATTR_NEXT(last)) { +	for (; !IS_LAST_ENTRY(last); last = next) { +		next = EXT4_XATTR_NEXT(last); +		if ((void *)next >= s->end) { +			EXT4_ERROR_INODE(inode, "corrupted xattr entries"); +			ret = -EFSCORRUPTED; +			goto out; +		}  		if (!last->e_value_inum && last->e_value_size) {  			size_t offs = le16_to_cpu(last->e_value_offs);  			if (offs < min_offs) @@ -1688,7 +1694,7 @@ static int ext4_xattr_set_entry(struct ext4_xattr_info *i,  	/* No failures allowed past this point. */ -	if (!s->not_found && here->e_value_offs) { +	if (!s->not_found && here->e_value_size && here->e_value_offs) {  		/* Remove the old value. */  		void *first_val = s->base + min_offs;  		size_t offs = le16_to_cpu(here->e_value_offs); @@ -2206,23 +2212,8 @@ int ext4_xattr_ibody_inline_set(handle_t *handle, struct inode *inode,  	if (EXT4_I(inode)->i_extra_isize == 0)  		return -ENOSPC;  	error = ext4_xattr_set_entry(i, s, handle, inode, false /* is_block */); -	if (error) { -		if (error == -ENOSPC && -		    ext4_has_inline_data(inode)) { -			error = ext4_try_to_evict_inline_data(handle, inode, -					EXT4_XATTR_LEN(strlen(i->name) + -					EXT4_XATTR_SIZE(i->value_len))); -			if (error) -				return error; -			error = ext4_xattr_ibody_find(inode, i, is); -			if (error) -				return error; -			error = ext4_xattr_set_entry(i, s, handle, inode, -						     false /* is_block */); -		} -		if (error) -			return error; -	} +	if (error) +		return error;  	header = IHDR(inode, ext4_raw_inode(&is->iloc));  	if (!IS_LAST_ENTRY(s->first)) {  		header->h_magic = cpu_to_le32(EXT4_XATTR_MAGIC); @@ -2651,6 +2642,11 @@ static int ext4_xattr_make_inode_space(handle_t *handle, struct inode *inode,  		last = IFIRST(header);  		/* Find the entry best suited to be pushed into EA block */  		for (; !IS_LAST_ENTRY(last); last = EXT4_XATTR_NEXT(last)) { +			/* never move system.data out of the inode */ +			if ((last->e_name_len == 4) && +			    (last->e_name_index == EXT4_XATTR_INDEX_SYSTEM) && +			    !memcmp(last->e_name, "data", 4)) +				continue;  			total_size = EXT4_XATTR_LEN(last->e_name_len);  			if (!last->e_value_inum)  				total_size += EXT4_XATTR_SIZE(  |