Page MenuHomeFreeBSD

printf: Validate argument index is >0
ClosedPublic

Authored by brooks on Oct 19 2016, 3:26 PM.
Tags
None
Referenced Files
Unknown Object (File)
Sat, Apr 13, 5:34 AM
Unknown Object (File)
Sat, Apr 13, 5:33 AM
Unknown Object (File)
Sat, Apr 13, 5:23 AM
Unknown Object (File)
Sat, Apr 13, 3:30 AM
Unknown Object (File)
Mar 10 2024, 9:32 PM
Unknown Object (File)
Mar 10 2024, 9:27 PM
Unknown Object (File)
Mar 10 2024, 9:27 PM
Unknown Object (File)
Mar 10 2024, 9:27 PM
Subscribers

Diff Detail

Repository
rS FreeBSD src repository - subversion
Lint
Lint Not Applicable
Unit
Tests Not Applicable

Event Timeline

br retitled this revision from to Validate argument number is >0.
br updated this object.
br edited the test plan for this revision. (Show Details)
br retitled this revision from Validate argument number is >0 to Validate argument number is >=0.Oct 19 2016, 3:29 PM
br retitled this revision from Validate argument number is >=0 to Validate argument number is >0.

update comment and check including 0

br retitled this revision from Validate argument number is >0 to printf: Validate argument index is >0.

change commment

This does not seem wrong, but it is a bit strange to handle this undefined behaviour problem but not the integer overflow when parsing the number in __find_arguments() and __find_warguments() and the integer overflows in __grow_type_table().

One way to do that would be to start enforcing NL_ARGMAX (possibly increasing it if necessary to make applications work). This is not as bad as it seems because any n$ in printf(3) implies at least n + 1 arguments in some C function call that cannot be dynamically constructed. (printf(1) is different since one can dynamically construct very long argument lists to a builtin printf.)

br edited edge metadata.

you mean something like that ?
we have NL_ARGMAX defined in limits.h, it is set to 99, which should be enough for applications.
otherwise many thanks!

I wonder whether we should increase NL_ARGMAX if we're actually enforcing it, including for strings that do not have n$.

lib/libc/stdio/printf-pos.c
303–306 ↗(On Diff #21542)

This check should be moved inside the loop since you may have an overflowing calculation that overflows back into the allowed range.

increase NL_ARGMAX, also move overflow detection

This revision was automatically updated to reflect the committed changes.
mjg reopened this revision.EditedOct 1 2018, 11:11 PM
mjg added a subscriber: mjg.

This commit bumped NL_ARGMAX from 99 to 65536.

Turns out there is real-world software out there which uses this to size stuff. In particular postgres has a table of NL_ARGMAX * 4 which it then memsets, i.e. it is of 256KB of size. This significantly slows down single-threaded performance for this case. Chances are solid there are other victims. That said, fixing postgres aside, I would like to get reasoning for bumping the limit so high.

My grepping around suggests Linux sticks to 4096, which still sounds kind of high. I would be leaning towards a mere 1024.

As a data point, reducing the macro from 65536 to 4096 sped up single-threaded select queries from 34000 tps to 40000 on a Skylake box. It is a big deal. A naive memset loop zeroing such a big buffer (256KB!) does only 70k iterations per second.

It seems like cutting NL_ARGMAX back to 1024 or even reverting to 99 makes sense. You're doing some pretty weird macro meta-programming to get to a 100 argument printf.

That being said, if I'm reading the grok results (https://grok.dragonflybsd.org/search?project=dports&q=NL_ARGMAX&defs=&refs=&path=&hist=&type=&si=q&n=25)correctly this is kind of an own-goal on PostgreSQL's part due to their insistence on rolling their own versions of all sorts of things. We need to work with them, but part of that should probably be trying to convince them to pick up modern versions of things like snprintf.

They already took care of the problem on their side by defining their own macro to 31.

https://git.postgresql.org/gitweb/?p=postgresql.git;a=commitdiff;h=625b38ea0e98cb596b393c70e5eaba67c6f4279e

However, older postgres ports are still affected.

I suggested 4096 because that's what Linux sets it to, it probably is very arbitrary anyway. For all I care it can go back to 9. :->

I've created D17387 with a trivial patch to switch to 4096.

brooks edited reviewers, added: br; removed: brooks.

This was committed and should have auto-closed. Commandeer so I can close it.

This revision is now accepted and ready to land.Jan 29 2019, 7:33 PM