From nobody Fri Apr 3 22:38:07 2026 Received: from cstnet.cn (smtp81.cstnet.cn [159.226.251.81]) (using TLSv1.2 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 052D535DA56 for ; Mon, 23 Mar 2026 07:24:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=159.226.251.81 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774250670; cv=none; b=ip65FwLfEz1tFP9vVmXjV91ha67i2jD1FPvZmRE+Ue3ApRlDN8JBmHecEbBsvybz64Qwv8+s1XhiUPSno+8IQUJAygP6hBay+QoRn9QQDQ1vK3yRtybIum1Tg1Zd3WZSeqvY16+p2bOU81Na9hC4MlifVTSYM1kh90QXdU0pMgc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774250670; c=relaxed/simple; bh=txLkQ3a7mjQf9NbGmK02PWNhlZY1Tzaa7WzBnAFPAaE=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version; b=tEm3wXS8KpHW/Vn4A0tjseWEVgpb/qmpYmTR4RUyzOKcXQJjEH0wW8NGUdnC+iTQKvy6K9jLIHKEoAwmEzoT/gILjYD3bCnmKyYneXhTWEugbslimgSpj0Q/ss1gORXZFi2rYz6OVRQ3NooM0zjjyWSX8piFF4aPLz8ggox8psw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=iscas.ac.cn; spf=pass smtp.mailfrom=iscas.ac.cn; arc=none smtp.client-ip=159.226.251.81 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=iscas.ac.cn Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=iscas.ac.cn Received: from localhost.localdomain (unknown [111.196.245.197]) by APP-03 (Coremail) with SMTP id rQCowABng9qk6sBpV1SGCw--.32792S2; Mon, 23 Mar 2026 15:24:20 +0800 (CST) From: Pengpeng Hou To: shaggy@kernel.org Cc: duttaditya18@gmail.com, arnd@arndb.de, zheng.yu@northwestern.edu, jfs-discussion@lists.sourceforge.net, linux-kernel@vger.kernel.org, pengpeng@iscas.ac.cn Subject: [PATCH] jfs: bound Unicode name conversion to the dirent buffer Date: Mon, 23 Mar 2026 15:24:20 +0800 Message-ID: <20260323072420.60211-1-pengpeng@iscas.ac.cn> X-Mailer: git-send-email 2.50.1 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-CM-TRANSID: rQCowABng9qk6sBpV1SGCw--.32792S2 X-Coremail-Antispam: 1UD129KBjvJXoWxJFy5WF4rZF1Duw15GFyfJFb_yoWrGFyxpa 95Ka4fJrs3Grn7Xrn3Xw1kW3s8K348Gr45Wr1SyF1Sya4xXr17ZF10vr10yr18XrsYgryj 9FZ5tw17Zr15A3DanT9S1TB71UUUUU7qnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDU0xBIdaVrnRJUUUkG14x267AKxVW8JVW5JwAFc2x0x2IEx4CE42xK8VAvwI8IcIk0 rVWrJVCq3wAFIxvE14AKwVWUJVWUGwA2ocxC64kIII0Yj41l84x0c7CEw4AK67xGY2AK02 1l84ACjcxK6xIIjxv20xvE14v26F1j6w1UM28EF7xvwVC0I7IYx2IY6xkF7I0E14v26F4j 6r4UJwA2z4x0Y4vEx4A2jsIE14v26rxl6s0DM28EF7xvwVC2z280aVCY1x0267AKxVW0oV Cq3wAS0I0E0xvYzxvE52x082IY62kv0487Mc02F40EFcxC0VAKzVAqx4xG6I80ewAv7VC0 I7IYx2IY67AKxVWUXVWUAwAv7VC2z280aVAFwI0_Gr0_Cr1lOx8S6xCaFVCjc4AY6r1j6r 4UM4x0Y48IcxkI7VAKI48JM4x0x7Aq67IIx4CEVc8vx2IErcIFxwCY1x0262kKe7AKxVWU AVWUtwCF04k20xvY0x0EwIxGrwCFx2IqxVCFs4IE7xkEbVWUJVW8JwC20s026c02F40E14 v26r1j6r18MI8I3I0E7480Y4vE14v26r106r1rMI8E67AF67kF1VAFwI0_JF0_Jw1lIxkG c2Ij64vIr41lIxAIcVC0I7IYx2IY67AKxVWUJVWUCwCI42IY6xIIjxv20xvEc7CjxVAFwI 0_Gr0_Cr1lIxAIcVCF04k26cxKx2IYs7xG6r1j6r1xMIIF0xvEx4A2jsIE14v26r4j6F4U MIIF0xvEx4A2jsIEc7CjxVAFwI0_Gr0_Gr1UYxBIdaVFxhVjvjDU0xZFpf9x0JUhtxDUUU UU= X-CM-SenderInfo: pshqw1xhqjqxpvfd2hldfou0/ Content-Type: text/plain; charset="utf-8" jfs_readdir() only checks that d->namlen characters fit in the page, but jfs_strfromUCS_le() can expand each UCS-2 character into multiple output bytes when a codepage is active and then always appends a NUL. That lets a long multi-byte name run past the end of the temporary dirent page. Make jfs_strfromUCS_le() size-aware and stop the readdir walk when the converted name no longer fits in the remaining dirent buffer space. Signed-off-by: Pengpeng Hou --- fs/jfs/jfs_dtree.c | 23 +++++++++++++++++++---- fs/jfs/jfs_unicode.c | 21 ++++++++++++++++----- fs/jfs/jfs_unicode.h | 3 ++- 3 files changed, 37 insertions(+), 10 deletions(-) diff --git a/fs/jfs/jfs_dtree.c b/fs/jfs/jfs_dtree.c index 9ab3f2fc61d1..62c1ff7a2a38 100644 --- a/fs/jfs/jfs_dtree.c +++ b/fs/jfs/jfs_dtree.c @@ -2964,8 +2964,15 @@ int jfs_readdir(struct file *file, struct dir_contex= t *ctx) } =20 /* copy the name of head/only segment */ - outlen =3D jfs_strfromUCS_le(name_ptr, d->name, len, - codepage); + outlen =3D jfs_strfromUCS_le(name_ptr, + dirent_buf + PAGE_SIZE - + (unsigned long)name_ptr, + d->name, len, codepage); + if (outlen < 0) { + index =3D i; + overflow =3D 1; + break; + } jfs_dirent->name_len =3D outlen; =20 /* copy name in the additional segment(s) */ @@ -2984,8 +2991,16 @@ int jfs_readdir(struct file *file, struct dir_contex= t *ctx) goto skip_one; } len =3D min(d_namleft, DTSLOTDATALEN); - outlen =3D jfs_strfromUCS_le(name_ptr, t->name, - len, codepage); + outlen =3D jfs_strfromUCS_le(name_ptr, + dirent_buf + PAGE_SIZE - + (unsigned long)name_ptr, + t->name, len, + codepage); + if (outlen < 0) { + index =3D i; + overflow =3D 1; + break; + } jfs_dirent->name_len +=3D outlen; =20 next =3D t->next; diff --git a/fs/jfs/jfs_unicode.c b/fs/jfs/jfs_unicode.c index 0c1e9027245a..3ac6fd88a7eb 100644 --- a/fs/jfs/jfs_unicode.c +++ b/fs/jfs/jfs_unicode.c @@ -16,7 +16,7 @@ * FUNCTION: Convert little-endian unicode string to character string * */ -int jfs_strfromUCS_le(char *to, const __le16 * from, +int jfs_strfromUCS_le(char *to, size_t to_size, const __le16 *from, int len, struct nls_table *codepage) { int i; @@ -24,13 +24,22 @@ int jfs_strfromUCS_le(char *to, const __le16 * from, static int warn_again =3D 5; /* Only warn up to 5 times total */ int warn =3D !!warn_again; /* once per string */ =20 + if (!to_size) + return -ENAMETOOLONG; + if (codepage) { for (i =3D 0; (i < len) && from[i]; i++) { int charlen; + + if (outlen >=3D to_size - 1) + return -ENAMETOOLONG; + charlen =3D codepage->uni2char(le16_to_cpu(from[i]), &to[outlen], - NLS_MAX_CHARSET_SIZE); + min_t(size_t, + NLS_MAX_CHARSET_SIZE, + to_size - outlen - 1)); if (charlen > 0) outlen +=3D charlen; else @@ -38,8 +47,11 @@ int jfs_strfromUCS_le(char *to, const __le16 * from, } } else { for (i =3D 0; (i < len) && from[i]; i++) { + if (outlen >=3D to_size - 1) + return -ENAMETOOLONG; + if (unlikely(le16_to_cpu(from[i]) & 0xff00)) { - to[i] =3D '?'; + to[outlen++] =3D '?'; if (unlikely(warn)) { warn--; warn_again--; @@ -52,9 +64,8 @@ int jfs_strfromUCS_le(char *to, const __le16 * from, =20 } else - to[i] =3D (char) (le16_to_cpu(from[i])); + to[outlen++] =3D (char)(le16_to_cpu(from[i])); } - outlen =3D i; } to[outlen] =3D 0; return outlen; diff --git a/fs/jfs/jfs_unicode.h b/fs/jfs/jfs_unicode.h index b6a78d4aef1b..39b5710891ef 100644 --- a/fs/jfs/jfs_unicode.h +++ b/fs/jfs/jfs_unicode.h @@ -12,7 +12,8 @@ #include "jfs_types.h" =20 extern int get_UCSname(struct component_name *, struct dentry *); -extern int jfs_strfromUCS_le(char *, const __le16 *, int, struct nls_table= *); +extern int jfs_strfromUCS_le(char *to, size_t to_size, const __le16 *from, + int len, struct nls_table *codepage); =20 #define free_UCSname(COMP) kfree((COMP)->name) =20 --=20 2.50.1 (Apple Git-155)