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 99968C83F07 for ; Mon, 7 Jul 2025 09:48:23 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 29D406B03F7; Mon, 7 Jul 2025 05:48:23 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id 275A76B03F8; Mon, 7 Jul 2025 05:48:23 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 18A686B03F9; Mon, 7 Jul 2025 05:48:23 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0015.hostedemail.com [216.40.44.15]) by kanga.kvack.org (Postfix) with ESMTP id 04B306B03F7 for ; Mon, 7 Jul 2025 05:48:23 -0400 (EDT) Received: from smtpin02.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay09.hostedemail.com (Postfix) with ESMTP id 99FBB8043B for ; Mon, 7 Jul 2025 09:48:22 +0000 (UTC) X-FDA: 83636993244.02.ED1D89C Received: from mail-qv1-f48.google.com (mail-qv1-f48.google.com [209.85.219.48]) by imf15.hostedemail.com (Postfix) with ESMTP id CE190A000B for ; Mon, 7 Jul 2025 09:48:20 +0000 (UTC) Authentication-Results: imf15.hostedemail.com; dkim=pass header.d=google.com header.s=20230601 header.b=sfH+eFWr; dmarc=pass (policy=reject) header.from=google.com; spf=pass (imf15.hostedemail.com: domain of glider@google.com designates 209.85.219.48 as permitted sender) smtp.mailfrom=glider@google.com ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1751881700; a=rsa-sha256; cv=none; b=ZnI9wcEZuftoa0ESjl04d1ofCkN8RkAXQomACBcr+k646PhVxMMuMNGxoyTbfoZAIbDfJZ 84Hh0dSbtxFGEga+zkZfUXLAoWwznA9UatFhxJliOKOaSlXjVfjRzkYClib0Vg5T/jPdQh 6CRLIJH9ZFmIxMxVg/abV+FKQplwOTA= ARC-Authentication-Results: i=1; imf15.hostedemail.com; dkim=pass header.d=google.com header.s=20230601 header.b=sfH+eFWr; dmarc=pass (policy=reject) header.from=google.com; spf=pass (imf15.hostedemail.com: domain of glider@google.com designates 209.85.219.48 as permitted sender) smtp.mailfrom=glider@google.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1751881700; 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:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=frbjbKfca0mgstlmUpI74NtNTt6lUs+p9/a8UNKkFt4=; b=otJWGSz20KqGIhS1iSTDFk3fX5iCHPZLqOaoj2hwZwj7zV+644BYOEejxS5SskOGGh4UZK pe/7OGUxNTx5PNE3IVu7dx8UXr/u/Fvrbg8V22wCmka/vHBPsg7zSVkDtD94qqXgOGvnlV 0WAYLiSROw4Z8zR4uWUhUOa9YJ5gjzQ= Received: by mail-qv1-f48.google.com with SMTP id 6a1803df08f44-6fa980d05a8so32303896d6.2 for ; Mon, 07 Jul 2025 02:48:20 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1751881700; x=1752486500; darn=kvack.org; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:from:to:cc:subject:date :message-id:reply-to; bh=frbjbKfca0mgstlmUpI74NtNTt6lUs+p9/a8UNKkFt4=; b=sfH+eFWrVL7IBmasM+YXXrktxiNZORcU6t4rDoX72tztCTOLbyIQJnx7NkKmX1uBJE 1/03Y4QxFCrXKp3/MTR6QjygPtWqJaVaIlTgQNTtZQ3pMGvpBr+8ShxPpSvdZrLMvEkt M0eoEgYfXIwuUxKli4/4UyH0NygNwxdEWJFQ0+OQszjIswbAxJDQks0NFRMaCGNVuWwG Gk+mwsErMbkDjY9KpIo1wx5VQzkcG12TiwF4g7l0lOE7GjPVwExMX/z7uLJBDD2V8e+A jkdTq964Qir3fzSsXeCcVwTb3pLgw/W31YpP+wsBxgCAnuCnh2K4f1BzDXZvKGwbmkwh mSXg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1751881700; x=1752486500; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=frbjbKfca0mgstlmUpI74NtNTt6lUs+p9/a8UNKkFt4=; b=ZOHXDZIL+m9gaBKLhqkm0AYs1cbXlzP2o975nnvgaBTyHnXwMHIz9WAhnJM7Ibd0rj ay8qI2MyJj5pBm5Ie/1pJu+xCA8tWjqEnJGBiYoFS+G/kG5/n1zu/pqSUGsFVwDZEs6e Nt14MSgWAWjTz2gvpQNzqSYd+OM7yyTdUKqvukIHa9bUmCV5ky+2R2KjWgIabMDPNYFj ZZNXvYE6j9q/ilgMGrxpASXmxnXv4wGlLcbDhIzaO2F1rkfDP7g3RKgwrjVX0umfNNDL KU9SzYkfJ72OiImUiHar1WRWzr/MsQ5zXYo465a1PCqFINTEMKIi5vUb/8BSshxrCyAI 2o4w== X-Gm-Message-State: AOJu0YxeLCg2fzhoTTm7zOTAY6vedGVxdKHjmz1B9WUyBjEJ0viAbKzc IKat9HSopSjj+5uY/nP42PAb9ioY2nl1qz30N8kgFDaYGMzGMTs0FvoBn6hq1Uumzpm4Wj1xErm Cac3YbtBrRSt0K/Y2g58mJgVo0RhsyFcxJFGkJkgl X-Gm-Gg: ASbGncsVjYKMX2BH3DO7a1qSdWiqC70PgibiWSE0o0B8H4eGwndark/VMJ3lHRLy7ty Mg86wtftqgusxaMJt1us6pFExPVKDgU07yqwpLxEJstEnqtsTl8iZUS9icDPKI3l3cN9qCMSf1C 4oEgsWsdIOsUaNKL9tXURWtYMvUNhlhEexP+8CJruHhhr6+B8gKqusq7hrPxSs0w3Iyqe96RQ4c A== X-Google-Smtp-Source: AGHT+IHcO/y74R/A4icF5JMOnPuik0+R72LDFyPIAjvRILtiYXcsXDsbfAQD1GOxerZ6cpwinFaAl6Ff+ph2u1beSIo= X-Received: by 2002:a05:6214:5d0f:b0:6fd:609d:e924 with SMTP id 6a1803df08f44-702d16b5b13mr143596346d6.36.1751881699546; Mon, 07 Jul 2025 02:48:19 -0700 (PDT) MIME-Version: 1.0 References: <2d20eaf1752efefcc23d0e7c5c2311dd5ae252af.1751747518.git.alx@kernel.org> In-Reply-To: <2d20eaf1752efefcc23d0e7c5c2311dd5ae252af.1751747518.git.alx@kernel.org> From: Alexander Potapenko Date: Mon, 7 Jul 2025 11:47:43 +0200 X-Gm-Features: Ac12FXyyIGAsATyNgJop_7rvBktTGUGYSMPyLaAqY218kgxIasAxME7dbvT6CZY Message-ID: Subject: Re: [RFC v1 1/3] vsprintf: Add [v]seprintf(), [v]stprintf() To: Alejandro Colomar Cc: linux-mm@kvack.org, linux-hardening@vger.kernel.org, Kees Cook , Christopher Bazley , shadow <~hallyn/shadow@lists.sr.ht>, linux-kernel@vger.kernel.org, Andrew Morton , kasan-dev@googlegroups.com, Dmitry Vyukov , Marco Elver , Christoph Lameter , David Rientjes , Vlastimil Babka , Roman Gushchin , Harry Yoo Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable X-Rspamd-Server: rspam04 X-Rspamd-Queue-Id: CE190A000B X-Stat-Signature: qhsbdna4acn6ejy6d733ih7168k449bw X-Rspam-User: X-HE-Tag: 1751881700-665198 X-HE-Meta: U2FsdGVkX1/yX4y9ikfwsQKXEMgCJSkrQ9YYTbalMiOo/SUYRlV2VO5uQIvW1KX5f/sGDAMV5x72Hp5SJD0XcJM5Zra1bDc1ZdjSqqupyFD7TiZsvJdaKQxlmGCZF+J5UNbnN8vmFOmXznixn2fQ8MnscXytDL43y8SnZk4LYp6DcoN1SZPemjmvEFb1c4FpEK8z1TVThEdpzV/ls3TqK1/4iTTZRegdQ5szjhhQTxnVGy9W9/uBk9AaRWpg6AlbbdKDr4+vqHyy2w2RJjbGFnjBx7PTc0FWfAnBCc/Z8EfRN8WVE+0etGNdB2b4j8nu6LUWstNpPxjzXtcIxp8PF4dp0oCsSGaJidmoTYPCdMf9NqOSl0Z9U9PK+AnIn2X9lPIPL7RiigLOdevxNNvD8zDrQPRciQRaoLD1sZorY8d6Jr/oiMKlRII2kC6l1LsJe0RhkQuV7JQ8y+TliuuQg213C8ACc6KcaP4S9VUCpJHhfZdnBrZCTlQpvxezOmBN78xgbvgIz45SGzYAJYXtDVOD+JajNOjoG/iFjrpTfuNZqyYAfzXhlTuNLYF/t6pXezLA4BxIVIokJlryMtpDAypU/BKj9uEve2dwxvxLqlycA4SlmMUG+QYgVhw+srV247pVHNLn7zyWJnVxGMEX91S9YtY1debQ/5TXc6OSLKxBhBSradF63lIzyRskMC9pvNSln2kJ0P7zal9EJZ3AChVr1ybhM3S96kE6VxaczkyvE1EQtZGpSY6kiXuBMvBpgZzETBzax3pLt8bgbHFGUaRYIzWjN9lMQpcZLjHNuiMYdlPa0acQDEtagoy36HUa6QTBao8xV6UiBnN2P7tPpsbxhKBJmuFgftS84kCr4YmGtXKetvPjyZ2XD0z5nXlaCggwK47UnwSPZoZ/eq8ro7hZNcrQI+VU8b+eh1AVPxaDDTtf9dRHNhzbGK80Ed7y/I+U8As8c5yg7NVHOJx MesQxBv/ se+Mx66GxR6kCOGHzdq9U7V07OTlJFUUgEEvC55NnfM3T7/kOtCrGvMvMu3o3ze8UNGD4mSULVNSK2kxrS/TFe5pdNgSqxd8v7Gr+2pxEsbQVe4cLZA06i29ybHYiOa8qbD8R302c4ZCgmTBMx8An2qR57F5xUNtykIfRjx9NX+P3RoXAwuLU+rotLMSwBSHzAL3//1HR+9ckgJ84hBD9Z60yAlgdM8b5pcjZca+46FM5977xzKrCn94XIF9lLh1zM8H6rB3Vm4SxVJpLT2aM7GuW/OG62+uxAn3QBgVGD817uy5z8LlfVrrE9A== 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: On Sat, Jul 5, 2025 at 10:33=E2=80=AFPM Alejandro Colomar = wrote: > > seprintf() > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D > > 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. > > 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. > > 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. > > 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; > > vs > > len =3D 0; > size =3D countof(buf); > len +=3D snprintf(buf + len, size - len, foo); > if (len >=3D size) > goto trunc; > > len +=3D snprintf(buf + len, size - len, bar); > if (len >=3D size) > goto trunc; > > And also better than scnprintf() calls: > > 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; > > It seems aparent that it's a more elegant approach to string catenation. > > stprintf() > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D > > 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. > > 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). > > Cc: Kees Cook > Cc: Christopher Bazley > Signed-off-by: Alejandro Colomar > --- > lib/vsprintf.c | 109 +++++++++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 109 insertions(+) > > 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); > > +/** > + * 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); > > +/** > + * 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); It's easy to imagine a situation in which `end` is calculated from the user input and may overflow. Maybe we can add a check for `end > p` to be on the safe side?