lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <3o3ra7vjn44iey2dosunsm3wa4kagfeas2o4yzsl34girgn2eb@6rnktm2dmwul>
Date: Tue, 15 Jul 2025 09:08:14 +0200
From: Alejandro Colomar <alx@...nel.org>
To: Kees Cook <kees@...nel.org>
Cc: Linus Torvalds <torvalds@...ux-foundation.org>, 
	David Laight <david.laight.linux@...il.com>, Martin Uecker <ma.uecker@...il.com>, linux-mm@...ck.org, 
	linux-hardening@...r.kernel.org, Christopher Bazley <chris.bazley.wg14@...il.com>, 
	shadow <~hallyn/shadow@...ts.sr.ht>, linux-kernel@...r.kernel.org, 
	Andrew Morton <akpm@...ux-foundation.org>, kasan-dev@...glegroups.com, Dmitry Vyukov <dvyukov@...gle.com>, 
	Alexander Potapenko <glider@...gle.com>, Marco Elver <elver@...gle.com>, Christoph Lameter <cl@...ux.com>, 
	David Rientjes <rientjes@...gle.com>, Vlastimil Babka <vbabka@...e.cz>, 
	Roman Gushchin <roman.gushchin@...ux.dev>, Harry Yoo <harry.yoo@...cle.com>, 
	Andrew Clayton <andrew@...ital-domain.net>, Rasmus Villemoes <linux@...musvillemoes.dk>, 
	Michal Hocko <mhocko@...e.com>, Al Viro <viro@...iv.linux.org.uk>, Sam James <sam@...too.org>, 
	Andrew Pinski <pinskia@...il.com>
Subject: Re: [RFC v5 6/7] sprintf: Add [v]sprintf_array()

Hi Kees,

On Mon, Jul 14, 2025 at 10:19:39PM -0700, Kees Cook wrote:
> On Fri, Jul 11, 2025 at 10:58:56AM -0700, Linus Torvalds wrote:
> >         struct seq_buf s;
> >         seq_buf_init(&s, buf, szie);
> 
> And because some folks didn't like this "declaration that requires a
> function call", we even added:
> 
> 	DECLARE_SEQ_BUF(s, 32);
> 
> to do it in 1 line. :P
> 
> I would love to see more string handling replaced with seq_buf.

The thing is, it's not as easy as the fixes I'm proposing, and
sprintf_end() solves a lot of UB in a minimal diff that you can dumbly
apply.

And transitioning from sprintf_end() to seq_buf will still be a
possibility --probably even easier, because the code is simpler than
with s[c]nprintf()--.

Another thing, and this is my opinion, is that I'm not fond of APIs that
keep an internal state.  With sprintf_end(), the state is minimal and
external: the state is the 'p' pointer to where you're going to write.
That way, the programmer knows exactly where the writes occur, and can
reason about it without having to read the implementation and keep a
model of the state in its head.  With a struct-based approach, you hide
the state inside the structure, which means it's not so easy to reason
about how an action will affect the string, at first glance; you need an
expert in the API to know how to use it.

With sprintf_end(), either one is stupid/careless enough to get the
parameters wrong, or the function necessarily works well, *and is simple
to fully understand*.  And considering that we have ENDOF(), it's hard
to understand how one could get it wrong:

	p = buf;
	e = ENDOF(buf);
	p = sprintf_end(p, e, ...);
	p = sprintf_end(p, e, ...);
	p = sprintf_end(p, e, ...);
	p = sprintf_end(p, e, ...);

Admittedly, ENDOF() doesn't compile if buf is not an array, so in those
cases, there's a chance of a paranoic programmer slapping a -1 just in
case, but that doesn't hurt:

	p = buf;
	e = buf + size;  // Someone might accidentally -1 that?

I'm working on extending the _Countof() operator so that it can be
applied to array parameters to functions, so that it can be used to
count arrays that are not arrays:

	void
	f(size_t n, char buf[n])
	{
		p = buf;
		e = buf + _Countof(buf);  // _Countof(buf) will evaluate to n.
		...
	}

Which will significantly enhance the usability of sprintf_end().  I want
to implement this for GCC next year (there are a few things that need to
be improved first to be able to do that), and also propose it for
standardization.

For a similar comparison of stateful vs stateless functions, there are
strtok(3) and strsep(3), which apart from minor differences (strtok(3)
collapses adjacent delimiters) are more or less the same.  But I'd use
strsep(3) over strtok(3), even if just because strtok(3) keeps an
internal state, so I always need to be very careful of reading the
documentation to remind myself of what happens to the state after each
call.  strsep(3) is dead simple: you call it, and it updates the pointer
you passed; nothing is kept secretly from the programmer.


Have a lovely day!
Alex

-- 
<https://www.alejandro-colomar.es/>

Download attachment "signature.asc" of type "application/pgp-signature" (834 bytes)

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ