staging: erofs: keep corrupted fs from crashing kernel in erofs_readdir()
After commit419d6efc50
, kernel cannot be crashed in the namei path. However, corrupted nameoff can do harm in the process of readdir for scenerios without dm-verity as well. Fix it now. Fixes:3aa8ec716e
("staging: erofs: add directory operations") Cc: <stable@vger.kernel.org> # 4.19+ Signed-off-by: Gao Xiang <gaoxiang25@huawei.com> Reviewed-by: Chao Yu <yuchao0@huawei.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
9498da46d1
commit
33bac91284
@ -23,6 +23,21 @@ static const unsigned char erofs_filetype_table[EROFS_FT_MAX] = {
|
||||
[EROFS_FT_SYMLINK] = DT_LNK,
|
||||
};
|
||||
|
||||
static void debug_one_dentry(unsigned char d_type, const char *de_name,
|
||||
unsigned int de_namelen)
|
||||
{
|
||||
#ifdef CONFIG_EROFS_FS_DEBUG
|
||||
/* since the on-disk name could not have the trailing '\0' */
|
||||
unsigned char dbg_namebuf[EROFS_NAME_LEN + 1];
|
||||
|
||||
memcpy(dbg_namebuf, de_name, de_namelen);
|
||||
dbg_namebuf[de_namelen] = '\0';
|
||||
|
||||
debugln("found dirent %s de_len %u d_type %d", dbg_namebuf,
|
||||
de_namelen, d_type);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int erofs_fill_dentries(struct dir_context *ctx,
|
||||
void *dentry_blk, unsigned int *ofs,
|
||||
unsigned int nameoff, unsigned int maxsize)
|
||||
@ -33,14 +48,10 @@ static int erofs_fill_dentries(struct dir_context *ctx,
|
||||
de = dentry_blk + *ofs;
|
||||
while (de < end) {
|
||||
const char *de_name;
|
||||
int de_namelen;
|
||||
unsigned int de_namelen;
|
||||
unsigned char d_type;
|
||||
#ifdef CONFIG_EROFS_FS_DEBUG
|
||||
unsigned int dbg_namelen;
|
||||
unsigned char dbg_namebuf[EROFS_NAME_LEN];
|
||||
#endif
|
||||
|
||||
if (unlikely(de->file_type < EROFS_FT_MAX))
|
||||
if (de->file_type < EROFS_FT_MAX)
|
||||
d_type = erofs_filetype_table[de->file_type];
|
||||
else
|
||||
d_type = DT_UNKNOWN;
|
||||
@ -48,26 +59,20 @@ static int erofs_fill_dentries(struct dir_context *ctx,
|
||||
nameoff = le16_to_cpu(de->nameoff);
|
||||
de_name = (char *)dentry_blk + nameoff;
|
||||
|
||||
de_namelen = unlikely(de + 1 >= end) ?
|
||||
/* last directory entry */
|
||||
strnlen(de_name, maxsize - nameoff) :
|
||||
le16_to_cpu(de[1].nameoff) - nameoff;
|
||||
/* the last dirent in the block? */
|
||||
if (de + 1 >= end)
|
||||
de_namelen = strnlen(de_name, maxsize - nameoff);
|
||||
else
|
||||
de_namelen = le16_to_cpu(de[1].nameoff) - nameoff;
|
||||
|
||||
/* a corrupted entry is found */
|
||||
if (unlikely(de_namelen < 0)) {
|
||||
if (unlikely(nameoff + de_namelen > maxsize ||
|
||||
de_namelen > EROFS_NAME_LEN)) {
|
||||
DBG_BUGON(1);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_EROFS_FS_DEBUG
|
||||
dbg_namelen = min(EROFS_NAME_LEN - 1, de_namelen);
|
||||
memcpy(dbg_namebuf, de_name, dbg_namelen);
|
||||
dbg_namebuf[dbg_namelen] = '\0';
|
||||
|
||||
debugln("%s, found de_name %s de_len %d d_type %d", __func__,
|
||||
dbg_namebuf, de_namelen, d_type);
|
||||
#endif
|
||||
|
||||
debug_one_dentry(d_type, de_name, de_namelen);
|
||||
if (!dir_emit(ctx, de_name, de_namelen,
|
||||
le64_to_cpu(de->nid), d_type))
|
||||
/* stopped by some reason */
|
||||
|
Loading…
Reference in New Issue
Block a user