diff options
Diffstat (limited to 'fs/f2fs/xattr.c')
| -rw-r--r-- | fs/f2fs/xattr.c | 36 | 
1 files changed, 27 insertions, 9 deletions
diff --git a/fs/f2fs/xattr.c b/fs/f2fs/xattr.c index 848a785abe25..e791741d193b 100644 --- a/fs/f2fs/xattr.c +++ b/fs/f2fs/xattr.c @@ -202,12 +202,17 @@ static inline const struct xattr_handler *f2fs_xattr_handler(int index)  	return handler;  } -static struct f2fs_xattr_entry *__find_xattr(void *base_addr, int index, -					size_t len, const char *name) +static struct f2fs_xattr_entry *__find_xattr(void *base_addr, +				void *last_base_addr, int index, +				size_t len, const char *name)  {  	struct f2fs_xattr_entry *entry;  	list_for_each_xattr(entry, base_addr) { +		if ((void *)(entry) + sizeof(__u32) > last_base_addr || +			(void *)XATTR_NEXT_ENTRY(entry) > last_base_addr) +			return NULL; +  		if (entry->e_name_index != index)  			continue;  		if (entry->e_name_len != len) @@ -297,20 +302,22 @@ static int lookup_all_xattrs(struct inode *inode, struct page *ipage,  				const char *name, struct f2fs_xattr_entry **xe,  				void **base_addr, int *base_size)  { -	void *cur_addr, *txattr_addr, *last_addr = NULL; +	void *cur_addr, *txattr_addr, *last_txattr_addr; +	void *last_addr = NULL;  	nid_t xnid = F2FS_I(inode)->i_xattr_nid; -	unsigned int size = xnid ? VALID_XATTR_BLOCK_SIZE : 0;  	unsigned int inline_size = inline_xattr_size(inode);  	int err = 0; -	if (!size && !inline_size) +	if (!xnid && !inline_size)  		return -ENODATA; -	*base_size = inline_size + size + XATTR_PADDING_SIZE; +	*base_size = XATTR_SIZE(xnid, inode) + XATTR_PADDING_SIZE;  	txattr_addr = f2fs_kzalloc(F2FS_I_SB(inode), *base_size, GFP_NOFS);  	if (!txattr_addr)  		return -ENOMEM; +	last_txattr_addr = (void *)txattr_addr + XATTR_SIZE(xnid, inode); +  	/* read from inline xattr */  	if (inline_size) {  		err = read_inline_xattr(inode, ipage, txattr_addr); @@ -337,7 +344,11 @@ static int lookup_all_xattrs(struct inode *inode, struct page *ipage,  	else  		cur_addr = txattr_addr; -	*xe = __find_xattr(cur_addr, index, len, name); +	*xe = __find_xattr(cur_addr, last_txattr_addr, index, len, name); +	if (!*xe) { +		err = -EFAULT; +		goto out; +	}  check:  	if (IS_XATTR_LAST_ENTRY(*xe)) {  		err = -ENODATA; @@ -581,7 +592,8 @@ static int __f2fs_setxattr(struct inode *inode, int index,  			struct page *ipage, int flags)  {  	struct f2fs_xattr_entry *here, *last; -	void *base_addr; +	void *base_addr, *last_base_addr; +	nid_t xnid = F2FS_I(inode)->i_xattr_nid;  	int found, newsize;  	size_t len;  	__u32 new_hsize; @@ -605,8 +617,14 @@ static int __f2fs_setxattr(struct inode *inode, int index,  	if (error)  		return error; +	last_base_addr = (void *)base_addr + XATTR_SIZE(xnid, inode); +  	/* find entry with wanted name. */ -	here = __find_xattr(base_addr, index, len, name); +	here = __find_xattr(base_addr, last_base_addr, index, len, name); +	if (!here) { +		error = -EFAULT; +		goto exit; +	}  	found = IS_XATTR_LAST_ENTRY(here) ? 0 : 1;  |