fix: memory-safety and polling correctness backports for 1.2.x - #574
somethingwithproof wants to merge 11 commits into
Conversation
…the buffer When strlen(src) was at least obuf the length clamped to obuf and the terminator went to dst[obuf], one past a buffer of exactly that size. The pragma that suppressed the compiler's warning about it is no longer needed. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
read() was handed the whole remaining buffer, so a script server result of exactly RESULTS_BUFFER bytes filled it and the terminator went one past the end. The loop also had no guard for the case where no capacity was left. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
…st() The copy used strlen(stack) as its size, and stack had just been zeroed, so nothing was copied and strtok() saw an empty string. Every branch that parses a transport prefix or port was unreachable as a result. strtok() also keeps one process-wide save pointer while this runs on each poller thread. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
php_close() sent SIGTERM and moved on, so a script server that ignores it or is stuck in uninterruptible I/O was left as an orphan. Shutdown now polls for the child over a bounded window, escalates to SIGKILL, and polls again. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
rdb_ssl_key, rdb_ssl_cert and rdb_ssl_ca were BIG_BUFSIZE while the config parser reads at most 255 characters into a BUFSIZE scratch buffer, so the copy bound exceeded the source and the compiler said so. develop already carries these at BUFSIZE. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
php_processes, debug_devices and both connection pools were dereferenced on the next statement. Backport of the develop fix for issue#564. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
Four settings helpers returned from the NULL-row branch without freeing while every other exit frees. Backport of the develop fix for issue#566. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
strcat() wrote the newline at LOGSIZE-1 and its terminator one past the end once the message filled the buffer. Backport of the develop fix for issue#565, with the changelog entries for this batch. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
|
Rolled in the 1.2.x half of three more bugs that are present on both branches, so this is now seven fixes rather than four. Still 0 warnings, matching the 1.2.x baseline.
The develop half of the same three is #576. |
There was a problem hiding this comment.
🟡 Changes recommended
There are remaining correctness/portability issues in php.c (inconsistent BUFSIZE vs RESULTS_BUFFER bounds check and an unguarded usleep() relative to existing SOLAR_THREAD handling) that should be resolved before merging.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
This PR backports several small, independent fixes from develop to the 1.2.x maintenance branch, primarily addressing memory-safety issues (off-by-one/overflow) and shutdown correctness in the PHP script-server path.
Changes:
- Harden string/buffer handling (
strncopy(),php_readpipe(), and log newline appending) to prevent out-of-bounds writes. - Improve correctness and thread-safety in hostname parsing (
get_namebyhost()uses proper copy +strtok_r). - Ensure resources/processes are cleaned up (free MySQL result sets on empty fetch paths; reap script-server children on shutdown).
File summaries
| File | Description |
|---|---|
| util.c | Fix result-set leaks in settings helpers; make spine_log() newline append bounded; fix strncopy() off-by-one/OOB behavior and remove warning-suppression pragmas. |
| spine.h | Reduce remote DB SSL path buffers to BUFSIZE to match config parsing limits and avoid misleading copy bounds. |
| spine.c | Add fatal checks for several calloc() allocations before dereference. |
| ping.c | Fix hostname copying so parsing is reachable; switch to strtok_r for reentrant tokenization. |
| php.c | Reserve NUL terminator space in php_readpipe(); add bounded shutdown/reap logic for script-server processes. |
| CHANGELOG | Document the backported fixes for 1.2.32. |
Review details
- Files reviewed: 6/6 changed files
- Comments generated: 2
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
|
@copilot Fix the code for all comments in this review thread. When a review comment includes a suggested change, apply the suggestion exactly. Do not make changes beyond what is described in the linked review thread. |
RESULTS_BUFFER defaults to 2048 and BUFSIZE is 1024, so the second guard rejected any reply over 1024 bytes that the read loop had already accepted, and it did not break, so the next read overwrote the buffer it had just declared out of range. The loop bound above it is the real limit. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
Every other usleep() in php.c sits inside #ifndef SOLAR_THREAD. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
477416b to
2579b34
Compare
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
2579b34 to
9d05e4e
Compare
|
Updated the consolidated backport through commit 9d05e4e after the full review cycle. The final pre-push verdict is PASS: all critical/high, secondary, medium, and missing-test scans are clean. I also built both the default nft_popen configuration and the supported --enable-popen configuration against Homebrew mysql-client, net-snmp, and OpenSSL 3. The PR body now documents the parser rationale, build evidence, and the remaining pre-existing descriptor/popen scope limitations. |
bmfmancini
left a comment
There was a problem hiding this comment.
LGTM — reviewed the memory-safety and polling correctness backports (strncopy overflow fix, php_readpipe terminator handling, SIGCHLD/fork serialization, close-on-exec descriptors, ICMP validation, snmp_count fail-closed paths). Approving.
Backports the memory-safety, process-lifecycle, and polling-correctness fixes identified in the 1.2.x review.
Memory safety and resource handling:
strncopyone-byte overflow and keep its scan portable to older Solarisphp_readpipeterminator byte, enforce one aggregate response/startup deadline, and recycle a server whose partial or oversized response leaves unread protocol dataflogmessageand initialize the buffer beforestrftimeProcess and privilege lifecycle:
SIGCHLDtoSIG_DFL, verify retained children withwaitpidbefore signaling, and prevent active slots from overwriting unreaped PIDsUpipe2/SOCK_CLOEXECwhen available and a serialized fallback otherwisevfork, optional libcpopen, and the complete process-wide euid-0 raw-socket window so data-input children cannot inherit rootPolling correctness:
snmp_countstop on internal Net-SNMP errors, distinguish SNMPv1noSuchNamewalk completion, and avoid turning internal errors into valid zero countsVerification:
./bootstrapcompletes (using Homebrewglibtoolize; the initial unavailable GNUlibtoolizeprobe is non-fatal)--enable-popenconfigure/build also succeeds--enable-warningsandmake -j4; remaining warnings are pre-existing macOS deprecations and unrelated unused variablesgit diff --checkpassesScope notes:
--enable-popenmode, the existing timeout path intentionally skipspcloseand can retain a child until it exits. This PR secures that mode's fork against the euid window but does not redesign its legacy timeout ownership.