Commit 33bac912 authored by Gao Xiang's avatar Gao Xiang Committed by Greg Kroah-Hartman

staging: erofs: keep corrupted fs from crashing kernel in erofs_readdir()

After commit 419d6efc, 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: 3aa8ec71 ("staging: erofs: add directory operations")
Cc: <stable@vger.kernel.org> # 4.19+
Signed-off-by: default avatarGao Xiang <gaoxiang25@huawei.com>
Reviewed-by: default avatarChao Yu <yuchao0@huawei.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 9498da46
...@@ -23,6 +23,21 @@ static const unsigned char erofs_filetype_table[EROFS_FT_MAX] = { ...@@ -23,6 +23,21 @@ static const unsigned char erofs_filetype_table[EROFS_FT_MAX] = {
[EROFS_FT_SYMLINK] = DT_LNK, [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, static int erofs_fill_dentries(struct dir_context *ctx,
void *dentry_blk, unsigned int *ofs, void *dentry_blk, unsigned int *ofs,
unsigned int nameoff, unsigned int maxsize) unsigned int nameoff, unsigned int maxsize)
...@@ -33,14 +48,10 @@ static int erofs_fill_dentries(struct dir_context *ctx, ...@@ -33,14 +48,10 @@ static int erofs_fill_dentries(struct dir_context *ctx,
de = dentry_blk + *ofs; de = dentry_blk + *ofs;
while (de < end) { while (de < end) {
const char *de_name; const char *de_name;
int de_namelen; unsigned int de_namelen;
unsigned char d_type; 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]; d_type = erofs_filetype_table[de->file_type];
else else
d_type = DT_UNKNOWN; d_type = DT_UNKNOWN;
...@@ -48,26 +59,20 @@ static int erofs_fill_dentries(struct dir_context *ctx, ...@@ -48,26 +59,20 @@ static int erofs_fill_dentries(struct dir_context *ctx,
nameoff = le16_to_cpu(de->nameoff); nameoff = le16_to_cpu(de->nameoff);
de_name = (char *)dentry_blk + nameoff; de_name = (char *)dentry_blk + nameoff;
de_namelen = unlikely(de + 1 >= end) ? /* the last dirent in the block? */
/* last directory entry */ if (de + 1 >= end)
strnlen(de_name, maxsize - nameoff) : de_namelen = strnlen(de_name, maxsize - nameoff);
le16_to_cpu(de[1].nameoff) - nameoff; else
de_namelen = le16_to_cpu(de[1].nameoff) - nameoff;
/* a corrupted entry is found */ /* a corrupted entry is found */
if (unlikely(de_namelen < 0)) { if (unlikely(nameoff + de_namelen > maxsize ||
de_namelen > EROFS_NAME_LEN)) {
DBG_BUGON(1); DBG_BUGON(1);
return -EIO; return -EIO;
} }
#ifdef CONFIG_EROFS_FS_DEBUG debug_one_dentry(d_type, de_name, de_namelen);
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
if (!dir_emit(ctx, de_name, de_namelen, if (!dir_emit(ctx, de_name, de_namelen,
le64_to_cpu(de->nid), d_type)) le64_to_cpu(de->nid), d_type))
/* stopped by some reason */ /* stopped by some reason */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment