Replace the 'p += snprintf' idiom with a bounded append - #592
Closed
somethingwithproof wants to merge 1 commit into
Closed
Replace the 'p += snprintf' idiom with a bounded append#592somethingwithproof wants to merge 1 commit into
somethingwithproof wants to merge 1 commit into
Conversation
snprintf returns the length it would have written, so the cursor moves past the buffer on the first truncation and the next remainder underflows to a huge size_t: an effectively unbounded size at a destination already out of bounds. util.c:829-851 was the worst of it. Every call there passed a fixed BUFSIZE rather than a shrinking remainder, so the bound never moved, and one of them interpolates set.host_id_list, which --hostlist can fill with 65534 bytes. spine_appendf() owns the arithmetic and reports truncation. Converted all 53 sites, keeping each recompute line so no buffer depends on being initialised in a new place. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
Member
Author
|
Consolidated into #597, which carries this branch's commits unchanged. Every pair of these ten conflicted on Nothing here is dropped. Reopen this if you would rather review it separately. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #588.
snprintfreturns the length it would have written, so the first truncation moves the cursor past the end of the buffer. The nextremainingis then negative, and as asize_tit is effectively unbounded, at a destination that is already out of bounds.The idiom appears at 53 sites, 47 in
util.cand 6 inspine.c.The one that is already wrong
util.c:829-851passed a fixedBUFSIZEto every call rather than a shrinking remainder, so the bound never moved at all:--hostlistcan fillset.host_id_listwith up to 65534 bytes. The third call writes at most 1023 of them, then advancessqlpby about 65550, and the query that reachesdb_query()is the truncated prefix. The buffer isHUGE_BUFSIZE, so this is malformed SQL rather than a stack overflow, but nothing here is doing what it reads as doing.poller_push_data_to_main()is where the margin matters: on the stock schema it lands near 1.75 MB against a 2.048 MB buffer, about 15 percent, with a guard that does not work.The change
spine_appendf()owns the arithmetic, advances by what was actually written, and returns FALSE on truncation. On truncation it leaves the cursor on the terminator, so the buffer stays a valid string and every later append fails there rather than running past the end.All 53 sites are converted. Each recompute line is kept:
spine_appendf()maintainsremainingitself, so the recompute is redundant. Dropping it would mean finding the right initialisation point for every cursor in a function that resetssqlpinside loops. Keeping it makes the conversion purely local: no buffer depends on being initialised somewhere new, and the recompute still self-heals. Removing them is a separate, later change.Two
int remainingdeclarations becamesize_t.Tests
Seven cases against the shipped
util.o, each using a struct with a0x7ecanary after the buffer so an overflow is observable rather than merely undefined:remainingto 1test_old_idiom_overshoots_where_appendf_does_notruns the old expression and asserts the cursor lands outside the buffer and the next remainder is negative, then the same input throughspine_appendf()and asserts it does notThat last one is the point: it fails if the defect is ever not a defect, and it documents why the other six exist.
44 of 44 pass. Clean
ubuntu:24.04rebuild carries the same 4 warnings as develop.No
CHANGELOGentry here; #578 is the changelog PR for this batch.