From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id 80AABC83030 for ; Sat, 5 Jul 2025 20:40:55 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 201646B8074; Sat, 5 Jul 2025 16:40:55 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id 1D9476B8067; Sat, 5 Jul 2025 16:40:55 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 1160E6B8074; Sat, 5 Jul 2025 16:40:55 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0012.hostedemail.com [216.40.44.12]) by kanga.kvack.org (Postfix) with ESMTP id 0099E6B8067 for ; Sat, 5 Jul 2025 16:40:54 -0400 (EDT) Received: from smtpin08.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay07.hostedemail.com (Postfix) with ESMTP id 9715B160B1F for ; Sat, 5 Jul 2025 20:40:54 +0000 (UTC) X-FDA: 83631380028.08.73FDB73 Received: from tor.source.kernel.org (tor.source.kernel.org [172.105.4.254]) by imf25.hostedemail.com (Postfix) with ESMTP id 0B2C8A0004 for ; Sat, 5 Jul 2025 20:40:52 +0000 (UTC) Authentication-Results: imf25.hostedemail.com; dkim=pass header.d=kernel.org header.s=k20201202 header.b=WgrxJfBR; spf=pass (imf25.hostedemail.com: domain of alx@kernel.org designates 172.105.4.254 as permitted sender) smtp.mailfrom=alx@kernel.org; dmarc=pass (policy=quarantine) header.from=kernel.org ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1751748053; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=wB1AuKwBi60IwzCfLiylrHXBpKT2zT7u4DnAFQn2V08=; b=18O2+YEhKVH/oKGgjyUNYn2SmONf3ohFEZYsLc6fEzbqmjE1e1lKMh325Wl1fdGvhT2Zl3 h/tLsmWpHxHAsl8g9In48hyw+BqhqZ5rPVDmM4rD+yhkPIcgxXTEeh3X0/aN8kLRNf+QbQ xBGY3MzIzoUVnCbcMs7ojCIWpM9vOmg= ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1751748053; a=rsa-sha256; cv=none; b=dz4XtGLccYxy68Sxa8Bnio7MP+Ge3M4RAMZqqKVE97Eu574H5lzBVYAh3nn5iQ077ir1pq GUM0Y5eo9uNnyaLruRXZcxVpoWimHfU0iYNUt+lqIh7fBI2cNlu380WkdY0/1NkXCGIRxX Tef2Y+0eQ9Laup55OFEzx+/I7LH5BEM= ARC-Authentication-Results: i=1; imf25.hostedemail.com; dkim=pass header.d=kernel.org header.s=k20201202 header.b=WgrxJfBR; spf=pass (imf25.hostedemail.com: domain of alx@kernel.org designates 172.105.4.254 as permitted sender) smtp.mailfrom=alx@kernel.org; dmarc=pass (policy=quarantine) header.from=kernel.org Received: from smtp.kernel.org (transwarp.subspace.kernel.org [100.75.92.58]) by tor.source.kernel.org (Postfix) with ESMTP id 69E1361155; Sat, 5 Jul 2025 20:40:52 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 39231C4CEE7; Sat, 5 Jul 2025 20:40:51 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1751748052; bh=Sl88YxxAaHd/YsR1z8G/2KOwRYt4vN4CacwFtopcZqo=; h=Date:From:To:Cc:Subject:References:In-Reply-To:From; b=WgrxJfBRzSt4wG/yzG73d0f7M37donQF4ZMFIkIT+ZRDhejetUQsHAIQ9G0NKT6Yo 3gWiK0arnp72MgVQLrFuImZYpiedLXUK9kKy+Oq+9O2XBeB6iZD+/4ljIZh7kbzoQb SRTAXr5+ztQYXzpmxu4wuiwg2hI0Kt5iT24pf4m0BvFqPUPHPchryFecT/jEsl9zr2 ZgIEmX/vPmCpmL7nAoZSeS/pDksABqq1k183zx4qXMd4x6JsC2nYq5iuFily4d4bxm YL5oApUICgIDFSjfQ3dVsmFSIUyZ7MQjbXfePnUtSoKdI23oceOvTjLvCH56legkjn R0AgKkiqkIpKQ== Date: Sat, 5 Jul 2025 22:40:49 +0200 From: Alejandro Colomar To: linux-mm@kvack.org, linux-hardening@vger.kernel.org Cc: Kees Cook , Christopher Bazley , shadow <~hallyn/shadow@lists.sr.ht>, linux-kernel@vger.kernel.org, Andrew Morton , kasan-dev@googlegroups.com, Dmitry Vyukov , Alexander Potapenko , Marco Elver , Christoph Lameter , David Rientjes , Vlastimil Babka , Roman Gushchin , Harry Yoo Subject: Re: [RFC v1 1/3] vsprintf: Add [v]seprintf(), [v]stprintf() Message-ID: References: <2d20eaf1752efefcc23d0e7c5c2311dd5ae252af.1751747518.git.alx@kernel.org> MIME-Version: 1.0 Content-Type: multipart/signed; micalg=pgp-sha512; protocol="application/pgp-signature"; boundary="pgtmvcnqaimzwfi6" Content-Disposition: inline In-Reply-To: <2d20eaf1752efefcc23d0e7c5c2311dd5ae252af.1751747518.git.alx@kernel.org> X-Rspam-User: X-Rspamd-Server: rspam12 X-Rspamd-Queue-Id: 0B2C8A0004 X-Stat-Signature: 5td79rynqx7zrjbj3junt1qkzki9ttj7 X-HE-Tag: 1751748052-565158 X-HE-Meta: U2FsdGVkX19qyoR7FXRXDvWDNOuRn+oLKd0e29yIr0ddtG/efvcHVLfi22Zc7Mja73OSYdEYEJ4DGaOHp71O/wfBk2BRzQIVnsZF9Roa7B0NlN/1z/R+4bbtAeRwpcv4kxyZ4PwOBFtRL1brbi/L7v8B7LmYGUwU2PVsXZZsm+lSRhYZNTkoNfxUraMS7a7YXAKtDOjSMSkVcCQ965chIQbEeHxjYzCvkSWYBrvkBbBKXTFX3AvXnqPCPFJeeMtXGKyT3X17VKtyabEBkY0VPzRkHmMdK8XsHixa3ee6f3Jx8rtrBAvGyjAJyh/gi3MTN1xB/pwfDL+UeCIPoAq5o3Khok8UvPgiL79odIaetrhPVJ1dkV2MfEzVqL2xYx+J2ieeIb8mCZtSXwaJIf2UO3vhIGpRr7qjK6jVrSOJkEeOrR3Sd/Nh+I0YlABqnnks0yfBPlNhF2A6qo520UrmCcVoYFLBDuelCREOAane+feg7BTIgowTVRzKGBS2gC06LToDuuv7IgUwZULKNRiAvpdvf9TVNcoRU/ydFEQ1LyEF2JCQ3xhpYvK2oBEfCvy7zMeqgRplfv3hcxLeQ2m+vv1iTSi90pfG0a1F/B376n4OPmvgkB2lZtcUuQ88rVP2DDEME1GmwTtIA7+w4ORCXXP+lfzhIVEcCQsqRfUC7Y1rWgCkUooQj2EzwcpEJCP6Y00HviAl3Fsq9uAaUUc7gqo35dYKl7ycqfzjooXBllrVwRFPX0x59MwRVYfOlIusVdR7FSbuCFo/Rm+4wHe2fY96XgK/bece1wYxFi2P9WzqqrFkp7VxqpJNse3wphB87Azy7PjLTuMwzk94tMYIJ/Se7WH95WsQMfZqEki+1MJ5e17fosVJIupka/zWn04uuCHraB0gQpC6awXoHmi4m3122QT3gXsWbtn6Yvc8qwf5D/+Nc9sMq1MtVl8Yft6HbkT/iwYN5RDUIxEkkXu WX9n31f8 pEeV9ZphmD1P0buoBJNNVefDRLLUzfK0xYYc8vBnXj+SX4gtjZG/FCqFr2IweCmKYE/CPG7mHiGnrFh6nL2OzXDsZ6o5vAWUwGKvi9/3pRQzqsTJh+OR2sIrKFLTzE4fuFU/xjIINElxhL+5FDJLDjLyXeI9TPe2PJm74gnhsJtcXcyrWj13E8ru1J1VshQOKhYwMVWJDaTeTAedXMRoda3uFiQsCFiRmn1hRUThpL2IoOlHddC2Aol+xes/OuUQr3aaEbtHqqp9UQGbdFnWGLDX35iXd88UwiItmYL0xhf0m3afJDAjFueNwlaMKslFyExSz4x52gmGuj4zTVkOgMXCkm4z3Q4jjjF22T03nkTlv2ZO3149slnaHHbCisITEinOkKDqxORDa/jZAw0PV3ZTvK5hzdU1olizMllMk41LSQNlOLm1Qy8zvhBOH0Bglet+4rxEJ++OtsEuWjzuCMZ4529wmgx8jruqfWBu37ozzOm01SR4PRelIzmDRg6/mVcCBtaRMV7PBkKaqt5B2BEasSg== X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: List-Subscribe: List-Unsubscribe: --pgtmvcnqaimzwfi6 Content-Type: text/plain; protected-headers=v1; charset=utf-8 Content-Disposition: inline Content-Transfer-Encoding: quoted-printable From: Alejandro Colomar To: linux-mm@kvack.org, linux-hardening@vger.kernel.org Cc: Kees Cook , Christopher Bazley , shadow <~hallyn/shadow@lists.sr.ht>, linux-kernel@vger.kernel.org, Andrew Morton , kasan-dev@googlegroups.com, Dmitry Vyukov , Alexander Potapenko , Marco Elver , Christoph Lameter , David Rientjes , Vlastimil Babka , Roman Gushchin , Harry Yoo Subject: Re: [RFC v1 1/3] vsprintf: Add [v]seprintf(), [v]stprintf() References: <2d20eaf1752efefcc23d0e7c5c2311dd5ae252af.1751747518.git.alx@kernel.org> MIME-Version: 1.0 In-Reply-To: <2d20eaf1752efefcc23d0e7c5c2311dd5ae252af.1751747518.git.alx@kernel.org> On Sat, Jul 05, 2025 at 10:33:49PM +0200, Alejandro Colomar wrote: > seprintf() > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D >=20 > seprintf() is a function similar to stpcpy(3) in the sense that it > returns a pointer that is suitable for chaining to other copy > operations. >=20 > It takes a pointer to the end of the buffer as a sentinel for when to > truncate, which unlike a size, doesn't need to be updated after every > call. This makes it much more ergonomic, avoiding manually calculating > the size after each copy, which is error prone. >=20 > It also makes error handling much easier, by reporting truncation with > a null pointer, which is accepted and transparently passed down by > subsequent seprintf() calls. This results in only needing to report > errors once after a chain of seprintf() calls, unlike snprintf(3), which > requires checking after every call. >=20 > p =3D buf; > e =3D buf + countof(buf); > p =3D seprintf(p, e, foo); > p =3D seprintf(p, e, bar); > if (p =3D=3D NULL) > goto trunc; >=20 > vs >=20 > len =3D 0; > size =3D countof(buf); > len +=3D snprintf(buf + len, size - len, foo); > if (len >=3D size) > goto trunc; >=20 > len +=3D snprintf(buf + len, size - len, bar); > if (len >=3D size) > goto trunc; >=20 > And also better than scnprintf() calls: >=20 > len =3D 0; > size =3D countof(buf); > len +=3D scnprintf(buf + len, size - len, foo); > len +=3D scnprintf(buf + len, size - len, bar); > if (len >=3D size) > goto trunc; Oops, this error handling is incorrect, as scnprintf() doesn't report truncation. I should have compared p =3D buf; e =3D buf + countof(buf); p =3D seprintf(p, e, foo); p =3D seprintf(p, e, bar); vs len =3D 0; size =3D countof(buf); len +=3D scnprintf(buf + len, size - len, foo); len +=3D scnprintf(buf + len, size - len, bar); >=20 > It seems aparent that it's a more elegant approach to string catenation. >=20 > stprintf() > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D >=20 > stprintf() is a helper that is needed for implementing seprintf() > --although it could be open-coded within vseprintf(), of course--, but > it's also useful by itself. It has the same interface properties as > strscpy(): that is, it copies with truncation, and reports truncation > with -E2BIG. It would be useful to replace some calls to snprintf(3) > and scnprintf() which don't need chaining, and where it's simpler to > pass a size. >=20 > It is better than plain snprintf(3), because it results in simpler error > detection (it doesn't need a check >=3Dcountof(buf), but rather <0). >=20 > Cc: Kees Cook > Cc: Christopher Bazley > Signed-off-by: Alejandro Colomar > --- > lib/vsprintf.c | 109 +++++++++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 109 insertions(+) >=20 > diff --git a/lib/vsprintf.c b/lib/vsprintf.c > index 01699852f30c..a3efacadb5e5 100644 > --- a/lib/vsprintf.c > +++ b/lib/vsprintf.c > @@ -2892,6 +2892,37 @@ int vsnprintf(char *buf, size_t size, const char *= fmt_str, va_list args) > } > EXPORT_SYMBOL(vsnprintf); > =20 > +/** > + * vstprintf - Format a string and place it in a buffer > + * @buf: The buffer to place the result into > + * @size: The size of the buffer, including the trailing null space > + * @fmt: The format string to use > + * @args: Arguments for the format string > + * > + * The return value is the length of the new string. > + * If the string is truncated, the function returns -E2BIG. > + * > + * If you're not already dealing with a va_list consider using stprintf(= ). > + * > + * See the vsnprintf() documentation for format string extensions over C= 99. > + */ > +int vstprintf(char *buf, size_t size, const char *fmt, va_list args) > +{ > + int len; > + > + len =3D vsnprintf(buf, size, fmt, args); > + > + // It seems the kernel's vsnprintf() doesn't fail? > + //if (unlikely(len < 0)) > + // return -E2BIG; > + > + if (unlikely(len >=3D size)) > + return -E2BIG; > + > + return len; > +} > +EXPORT_SYMBOL(vstprintf); > + > /** > * vscnprintf - Format a string and place it in a buffer > * @buf: The buffer to place the result into > @@ -2923,6 +2954,36 @@ int vscnprintf(char *buf, size_t size, const char = *fmt, va_list args) > } > EXPORT_SYMBOL(vscnprintf); > =20 > +/** > + * vseprintf - Format a string and place it in a buffer > + * @p: The buffer to place the result into > + * @end: A pointer to one past the last character in the buffer > + * @fmt: The format string to use > + * @args: Arguments for the format string > + * > + * The return value is a pointer to the trailing '\0'. > + * If @p is NULL, the function returns NULL. > + * If the string is truncated, the function returns NULL. > + * > + * If you're not already dealing with a va_list consider using seprintf(= ). > + * > + * See the vsnprintf() documentation for format string extensions over C= 99. > + */ > +char *vseprintf(char *p, const char end[0], const char *fmt, va_list arg= s) > +{ > + int len; > + > + if (unlikely(p =3D=3D NULL)) > + return NULL; > + > + len =3D vstprintf(p, end - p, fmt, args); > + if (unlikely(len < 0)) > + return NULL; > + > + return p + len; > +} > +EXPORT_SYMBOL(vseprintf); > + > /** > * snprintf - Format a string and place it in a buffer > * @buf: The buffer to place the result into > @@ -2950,6 +3011,30 @@ int snprintf(char *buf, size_t size, const char *f= mt, ...) > } > EXPORT_SYMBOL(snprintf); > =20 > +/** > + * stprintf - Format a string and place it in a buffer > + * @buf: The buffer to place the result into > + * @size: The size of the buffer, including the trailing null space > + * @fmt: The format string to use > + * @...: Arguments for the format string > + * > + * The return value is the length of the new string. > + * If the string is truncated, the function returns -E2BIG. > + */ > + > +int stprintf(char *buf, size_t size, const char *fmt, ...) > +{ > + va_list args; > + int len; > + > + va_start(args, fmt); > + len =3D vstprintf(buf, size, fmt, args); > + va_end(args); > + > + return len; > +} > +EXPORT_SYMBOL(stprintf); > + > /** > * scnprintf - Format a string and place it in a buffer > * @buf: The buffer to place the result into > @@ -2974,6 +3059,30 @@ int scnprintf(char *buf, size_t size, const char *= fmt, ...) > } > EXPORT_SYMBOL(scnprintf); > =20 > +/** > + * seprintf - Format a string and place it in a buffer > + * @p: The buffer to place the result into > + * @end: A pointer to one past the last character in the buffer > + * @fmt: The format string to use > + * @...: Arguments for the format string > + * > + * The return value is a pointer to the trailing '\0'. > + * If @buf is NULL, the function returns NULL. > + * If the string is truncated, the function returns NULL. > + */ > + > +char *seprintf(char *p, const char end[0], const char *fmt, ...) > +{ > + va_list args; > + > + va_start(args, fmt); > + p =3D vseprintf(p, end, fmt, args); > + va_end(args); > + > + return p; > +} > +EXPORT_SYMBOL(seprintf); > + > /** > * vsprintf - Format a string and place it in a buffer > * @buf: The buffer to place the result into > --=20 > 2.50.0 >=20 --=20 --pgtmvcnqaimzwfi6 Content-Type: application/pgp-signature; name="signature.asc" -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEES7Jt9u9GbmlWADAi64mZXMKQwqkFAmhpjcsACgkQ64mZXMKQ wqmVzQ/+KqUYH2RJ6XCFWIsqgzQlHWhF5QOxlPi3CwpP/HjdGT+EmXEM1eNot1aX OMIiUD26IZTG9icnCMdPoUXUmIQ4k5GalCWxTP8iKbwE+LuREW/AEeF+qO5eiu58 LG0FsQbVZjOfFmGWRy55Wga0RnAGZH/jCn4qbroS+mlrpgXDyl+tdwtUNCMuQGiZ y0HUPpJqG8jh0e4LDdCvGyVVLWcpqgqG/eN/SrSM7w5SDZs7yRiqrT0DkeAJ4quI x34tG+smh4wRXUqHfcuhPyUXYUkC5M6jUPsrWoX1Gf0W8tGTzwHMs9K0Gvj0Oj/r uXAMGoCq/Z82kCxjCCngmFs1feJUc7DYis5gzWZivz2atf0SqYnOp9Je3X3tRp83 tBALc/mAPJCCmdgP5nTFQWdu1SLjysCf66zM+DU3xnbt8KasIVfRUVk5ElUafb/5 7ss6uDTymwU0wO9rDqsV4mBYcd2jdf/ozH9bSaePj9TEmpoBNY+aMNC20nF0bin6 lbOS3z/hITZE6+pdSlxgfY66s/Dld6atXBrBD8rphQ9JwBwBN0QoKhbcRbbj8eNO kcaJhLcMM7B58fjqJqnnsQRlITuMPfVgTv5BfFHlbmNvKC4WYaGNNWNgwAzfaKeU 7Qou5dxKwQorPHQriDuTMtkozWaW2hk02dsGE0ic7kUmBSJi3LY= =AQZ1 -----END PGP SIGNATURE----- --pgtmvcnqaimzwfi6--