f2fs: sanity check of xattr entry size
There is a security report where f2fs_getxattr() has a hole to expose wrong memory region when the image is malformed like this. f2fs_getxattr: entry->e_name_len: 4, size: 12288, buffer_size: 16384, len: 4 Cc: <stable@vger.kernel.org> Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
This commit is contained in:
parent
60aa4d5536
commit
64beba0558
@ -288,7 +288,7 @@ static int read_xattr_block(struct inode *inode, void *txattr_addr)
|
||||
static int lookup_all_xattrs(struct inode *inode, struct page *ipage,
|
||||
unsigned int index, unsigned int len,
|
||||
const char *name, struct f2fs_xattr_entry **xe,
|
||||
void **base_addr)
|
||||
void **base_addr, int *base_size)
|
||||
{
|
||||
void *cur_addr, *txattr_addr, *last_addr = NULL;
|
||||
nid_t xnid = F2FS_I(inode)->i_xattr_nid;
|
||||
@ -299,8 +299,8 @@ static int lookup_all_xattrs(struct inode *inode, struct page *ipage,
|
||||
if (!size && !inline_size)
|
||||
return -ENODATA;
|
||||
|
||||
txattr_addr = f2fs_kzalloc(F2FS_I_SB(inode),
|
||||
inline_size + size + XATTR_PADDING_SIZE, GFP_NOFS);
|
||||
*base_size = inline_size + size + XATTR_PADDING_SIZE;
|
||||
txattr_addr = f2fs_kzalloc(F2FS_I_SB(inode), *base_size, GFP_NOFS);
|
||||
if (!txattr_addr)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -312,8 +312,10 @@ static int lookup_all_xattrs(struct inode *inode, struct page *ipage,
|
||||
|
||||
*xe = __find_inline_xattr(inode, txattr_addr, &last_addr,
|
||||
index, len, name);
|
||||
if (*xe)
|
||||
if (*xe) {
|
||||
*base_size = inline_size;
|
||||
goto check;
|
||||
}
|
||||
}
|
||||
|
||||
/* read from xattr node block */
|
||||
@ -474,6 +476,7 @@ int f2fs_getxattr(struct inode *inode, int index, const char *name,
|
||||
int error = 0;
|
||||
unsigned int size, len;
|
||||
void *base_addr = NULL;
|
||||
int base_size;
|
||||
|
||||
if (name == NULL)
|
||||
return -EINVAL;
|
||||
@ -484,7 +487,7 @@ int f2fs_getxattr(struct inode *inode, int index, const char *name,
|
||||
|
||||
down_read(&F2FS_I(inode)->i_xattr_sem);
|
||||
error = lookup_all_xattrs(inode, ipage, index, len, name,
|
||||
&entry, &base_addr);
|
||||
&entry, &base_addr, &base_size);
|
||||
up_read(&F2FS_I(inode)->i_xattr_sem);
|
||||
if (error)
|
||||
return error;
|
||||
@ -498,6 +501,11 @@ int f2fs_getxattr(struct inode *inode, int index, const char *name,
|
||||
|
||||
if (buffer) {
|
||||
char *pval = entry->e_name + entry->e_name_len;
|
||||
|
||||
if (base_size - (pval - (char *)base_addr) < size) {
|
||||
error = -ERANGE;
|
||||
goto out;
|
||||
}
|
||||
memcpy(buffer, pval, size);
|
||||
}
|
||||
error = size;
|
||||
|
Loading…
Reference in New Issue
Block a user