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,
|
static int lookup_all_xattrs(struct inode *inode, struct page *ipage,
|
||||||
unsigned int index, unsigned int len,
|
unsigned int index, unsigned int len,
|
||||||
const char *name, struct f2fs_xattr_entry **xe,
|
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;
|
void *cur_addr, *txattr_addr, *last_addr = NULL;
|
||||||
nid_t xnid = F2FS_I(inode)->i_xattr_nid;
|
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)
|
if (!size && !inline_size)
|
||||||
return -ENODATA;
|
return -ENODATA;
|
||||||
|
|
||||||
txattr_addr = f2fs_kzalloc(F2FS_I_SB(inode),
|
*base_size = inline_size + size + XATTR_PADDING_SIZE;
|
||||||
inline_size + size + XATTR_PADDING_SIZE, GFP_NOFS);
|
txattr_addr = f2fs_kzalloc(F2FS_I_SB(inode), *base_size, GFP_NOFS);
|
||||||
if (!txattr_addr)
|
if (!txattr_addr)
|
||||||
return -ENOMEM;
|
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,
|
*xe = __find_inline_xattr(inode, txattr_addr, &last_addr,
|
||||||
index, len, name);
|
index, len, name);
|
||||||
if (*xe)
|
if (*xe) {
|
||||||
|
*base_size = inline_size;
|
||||||
goto check;
|
goto check;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* read from xattr node block */
|
/* read from xattr node block */
|
||||||
@ -474,6 +476,7 @@ int f2fs_getxattr(struct inode *inode, int index, const char *name,
|
|||||||
int error = 0;
|
int error = 0;
|
||||||
unsigned int size, len;
|
unsigned int size, len;
|
||||||
void *base_addr = NULL;
|
void *base_addr = NULL;
|
||||||
|
int base_size;
|
||||||
|
|
||||||
if (name == NULL)
|
if (name == NULL)
|
||||||
return -EINVAL;
|
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);
|
down_read(&F2FS_I(inode)->i_xattr_sem);
|
||||||
error = lookup_all_xattrs(inode, ipage, index, len, name,
|
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);
|
up_read(&F2FS_I(inode)->i_xattr_sem);
|
||||||
if (error)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
@ -498,6 +501,11 @@ int f2fs_getxattr(struct inode *inode, int index, const char *name,
|
|||||||
|
|
||||||
if (buffer) {
|
if (buffer) {
|
||||||
char *pval = entry->e_name + entry->e_name_len;
|
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);
|
memcpy(buffer, pval, size);
|
||||||
}
|
}
|
||||||
error = size;
|
error = size;
|
||||||
|
Loading…
Reference in New Issue
Block a user