From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from out30-98.freemail.mail.aliyun.com (out30-98.freemail.mail.aliyun.com [115.124.30.98]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2160A3ED134; Tue, 14 Apr 2026 16:00:58 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=115.124.30.98 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776182462; cv=none; b=dlMGr4NAUMopDlM5v4+F8sAtOkktW28veyrDJDhUZcUrN3t9i6tCMyM7l3rN0GxYIl8DX1hfblQ5yo4tB289UkGEhqXi/rCOYcfZZB1J3h6nSttj27TPh0OVXoyh1rVMDtpAxIFmUSr0ShiX17xzUMVKqAuqunChEeTTFCYToY0= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776182462; c=relaxed/simple; bh=Nb9E54j7JyxXwYaQivc4l1ZjfAyBVLqpdSCtzLODBSw=; h=Message-ID:Date:MIME-Version:Subject:To:Cc:References:From: In-Reply-To:Content-Type; b=N6qyNnr1PpJyiGTu/cPtBvEZVnelAIdY7VNO7GS/8p9aMG1M5c9zHkdRpfD/jSHcoM49cPmHHVrXaZWPyljAr0uYO4u9hYYkmAxLiv+cBfQwVCpo3Xy2uO7K/YjvTpFiMAZ71qhy1s38hrBKVYkKPbZuTgLQPje5+ipJr2OgMQA= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.alibaba.com; spf=pass smtp.mailfrom=linux.alibaba.com; dkim=pass (1024-bit key) header.d=linux.alibaba.com header.i=@linux.alibaba.com header.b=sCxxHwsL; arc=none smtp.client-ip=115.124.30.98 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.alibaba.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.alibaba.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.alibaba.com header.i=@linux.alibaba.com header.b="sCxxHwsL" DKIM-Signature:v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.alibaba.com; s=default; t=1776182450; h=Message-ID:Date:MIME-Version:Subject:To:From:Content-Type; bh=lISCl8I5Buw+OwTlgs9srKojhMfaMOl9ogFWa04xFyE=; b=sCxxHwsL+8xReDxjhdtuhgxOIFlHCiN6v12jZMSPvZFLdn2usxuj2vPbkmzxaJU+STOQHMAr6+WyyQHs8IS4aLhvzOFcUrxxDAnRQR4mO01LEGgy05HLZ45tndxO8ZxV+Ma7fl7GiQLQQb2eiw/OhkuJ+5VSChB9dMlnshDHhp0= X-Alimail-AntiSpam:AC=PASS;BC=-1|-1;BR=01201311R571e4;CH=green;DM=||false|;DS=||;FP=0|-1|-1|-1|0|-1|-1|-1;HT=maildocker-contentspam011083073210;MF=hsiangkao@linux.alibaba.com;NM=1;PH=DS;RN=14;SR=0;TI=SMTPD_---0X11pYal_1776182448; Received: from 30.41.54.139(mailfrom:hsiangkao@linux.alibaba.com fp:SMTPD_---0X11pYal_1776182448 cluster:ay36) by smtp.aliyun-inc.com; Wed, 15 Apr 2026 00:00:49 +0800 Message-ID: Date: Wed, 15 Apr 2026 00:00:48 +0800 Precedence: bulk X-Mailing-List: stable@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 User-Agent: Mozilla Thunderbird Subject: Re: [PATCH] erofs: validate nameoff for all dirents in erofs_fill_dentries() To: Junrui Luo Cc: linux-erofs@lists.ozlabs.org, linux-kernel@vger.kernel.org, stable@vger.kernel.org, Yuhao Jiang , Gao Xiang , Chao Yu , Yue Hu , Jeffle Xu , Sandeep Dhavale , Hongbo Li , Chunhai Guo , Miao Xie , Greg Kroah-Hartman References: From: Gao Xiang In-Reply-To: Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit Hi Junrui, On 2026/4/14 23:20, Junrui Luo wrote: > erofs_readdir() validates de[0].nameoff before calling > erofs_fill_dentries(), but subsequent dirents are used without > validation. The loop computes `maxsize - nameoff` as an unsigned int > to bound strnlen(). The issue is true, but I don't think the description is valid. I think what we missed is to check the last dirent nameoff vs maxsize. BTW, please don't "To" too many people (especially Miao Xie and Greg), basically I think you only need to post to people according to `./checkpoint.pl` but leave indivudual person into "Cc" instead. > > If a crafted EROFS image has a dirent with nameoff >= maxsize, the > subtraction underflows, causing strnlen() to read past the block > buffer. > > Fix by validating each entry's nameoff at the top of the loop: it > must be >= nameoff0 and <= maxsize. > > Cc: stable@vger.kernel.org > Fixes: 3aa8ec716e52 ("staging: erofs: add directory operations") > Reported-by: Yuhao Jiang > Signed-off-by: Junrui Luo > --- > fs/erofs/dir.c | 7 +++++++ > 1 file changed, 7 insertions(+) > > diff --git a/fs/erofs/dir.c b/fs/erofs/dir.c > index e5132575b9d3..2efa16fa162f 100644 > --- a/fs/erofs/dir.c > +++ b/fs/erofs/dir.c > @@ -19,6 +19,13 @@ static int erofs_fill_dentries(struct inode *dir, struct dir_context *ctx, > const char *de_name = (char *)dentry_blk + nameoff; > unsigned int de_namelen; > > + if (nameoff < nameoff0 || nameoff > maxsize) { > + erofs_err(dir->i_sb, "bogus dirent @ nid %llu", > + EROFS_I(dir)->nid); > + DBG_BUGON(1); > + return -EFSCORRUPTED; > + } I think the only thing we need is the following diff: [The reason why nameoff < nameoff0 is unneeded, since `de_namelen > EROFS_NAME_LEN` ensures the nameoff delta won't be negative (so nameoff will increase.) and `nameoff + de_namelen > maxsize` implies `nameoff > maxsize` so `nameoff > maxsize` is unneeded too.] diff --git a/fs/erofs/dir.c b/fs/erofs/dir.c index e5132575b9d3..e0666d6da9af 100644 --- a/fs/erofs/dir.c +++ b/fs/erofs/dir.c @@ -20,19 +20,18 @@ static int erofs_fill_dentries(struct inode *dir, struct dir_context *ctx, unsigned int de_namelen; /* the last dirent in the block? */ - if (de + 1 >= end) + if (de + 1 >= end) { + if (maxsize <= nameoff) + goto err_bogus; de_namelen = strnlen(de_name, maxsize - nameoff); - else + } else { de_namelen = le16_to_cpu(de[1].nameoff) - nameoff; + } /* a corrupted entry is found */ if (nameoff + de_namelen > maxsize || - de_namelen > EROFS_NAME_LEN) { - erofs_err(dir->i_sb, "bogus dirent @ nid %llu", - EROFS_I(dir)->nid); - DBG_BUGON(1); - return -EFSCORRUPTED; - } + de_namelen > EROFS_NAME_LEN) + goto err_bogus; if (!dir_emit(ctx, de_name, de_namelen, erofs_nid_to_ino64(EROFS_SB(dir->i_sb), @@ -42,6 +41,10 @@ static int erofs_fill_dentries(struct inode *dir, struct dir_context *ctx, ctx->pos += sizeof(struct erofs_dirent); } return 0; +err_bogus: + erofs_err(dir->i_sb, "bogus dirent @ nid %llu", EROFS_I(dir)->nid); + DBG_BUGON(1); + return -EFSCORRUPTED; } static int erofs_readdir(struct file *f, struct dir_context *ctx) Thanks, Gao Xiang > + > /* the last dirent in the block? */ > if (de + 1 >= end) > de_namelen = strnlen(de_name, maxsize - nameoff); > > --- > base-commit: 7aaa8047eafd0bd628065b15757d9b48c5f9c07d > change-id: 20260414-fixes-ae20cd389f52 > > Best regards,