Description
Summary
-------
Calling the `CURLX_SET_BINMODE(stream)` macro with `stream == NULL` leads to an unguarded call to `fileno(NULL)` in `tool_binmode.h`, which is undefined behavior and may crash the process. This is a robustness/UB issue and should be corrected by guarding against NULL streams before calling `fileno()`.
Reproducer
---------
A minimal test program is included below to demonstrate the issue. When built against the current header, running the program results in a crash (SIGSEGV) or other undefined behavior on many platforms.
Impact
------
Non-security robustness defect: an accidental `NULL` stream passed to the macro can crash the process. This can surface during CLI tool execution or in tests and is easy to trigger accidentally.
Fix
---
Add a simple NULL-check wrapper (inline function) that returns early when `stream == NULL`, then call `_setmode`/`setmode` inside the wrapper. I included a suggested patch below and a unit test to prevent regressions.
Notes
-----
This is non-security; public PR is appropriate. I recommend adding the unit test to CI (and an ASAN job) so regressions are caught.
(safe, reproducible)
Save as repro_binmode_null.c at the repository root (adjust include path if needed):
/* repro_binmode_null.c
*
* Minimal PoC demonstrating that calling CURLX_SET_BINMODE(NULL)
* results in an unguarded fileno(NULL) invocation (undefined behavior).
*
* Build:
* gcc -Wall -Wextra -g -I./include repro_binmode_null.c -o repro_binmode_null
*
* If you want a clearer diagnostic, build+run under ASAN:
* gcc -fsanitize=address,undefined -g -I./include repro_binmode_null.c -o repro_binmode_null_asan
*
* Run:
* ./repro_binmode_null
* ./repro_binmode_null_asan
*
* Note: This program intentionally triggers the problematic call for repro purposes.
*/
#include <stdio.h>
/* Adjust the path below if your include tree is located elsewhere */
#include "tool_binmode.h"
int main(void)
{
/* Intentionally pass NULL to reproduce the issue.
The current macro expands to fileno(NULL), which is UB. */
CURLX_SET_BINMODE(NULL);
/* If the program continues without crashing, print a confirmation */
printf("CURLX_SET_BINMODE(NULL) returned — either implementation avoided fileno(NULL) or UB did not manifest.\n");
return 0;
}
Build & run instructions :-
From the repo root (assuming include/tool_binmode.h exists):
Compile (regular):
gcc -Wall -Wextra -g -I./include repro_binmode_null.c -o repro_binmode_null
./repro_binmode_null
Compile & run with sanitizers (recommended):
gcc -fsanitize=address,undefined -g -I./include repro_binmode_null.c -o repro_binmode_null_asan
./repro_binmode_null_asan
Expected ASAN/UBSAN output (example)
You will likely see an error such as:
runtime error: null pointer passed to function 'fileno'
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior ...
or a segmentation fault (SIGSEGV) depending on platform and libc.
## Impact
The PoC intentionally triggers UB so it may crash; that is the point — to show behavior and allow maintainers to fix it.
For Windows cross-build or non-POSIX setups, behavior varies; running under ASAN/UBSAN is recommended to obtain a reliable diagnostic.
-------
Calling the `CURLX_SET_BINMODE(stream)` macro with `stream == NULL` leads to an unguarded call to `fileno(NULL)` in `tool_binmode.h`, which is undefined behavior and may crash the process. This is a robustness/UB issue and should be corrected by guarding against NULL streams before calling `fileno()`.
Reproducer
---------
A minimal test program is included below to demonstrate the issue. When built against the current header, running the program results in a crash (SIGSEGV) or other undefined behavior on many platforms.
Impact
------
Non-security robustness defect: an accidental `NULL` stream passed to the macro can crash the process. This can surface during CLI tool execution or in tests and is easy to trigger accidentally.
Fix
---
Add a simple NULL-check wrapper (inline function) that returns early when `stream == NULL`, then call `_setmode`/`setmode` inside the wrapper. I included a suggested patch below and a unit test to prevent regressions.
Notes
-----
This is non-security; public PR is appropriate. I recommend adding the unit test to CI (and an ASAN job) so regressions are caught.
(safe, reproducible)
Save as repro_binmode_null.c at the repository root (adjust include path if needed):
/* repro_binmode_null.c
*
* Minimal PoC demonstrating that calling CURLX_SET_BINMODE(NULL)
* results in an unguarded fileno(NULL) invocation (undefined behavior).
*
* Build:
* gcc -Wall -Wextra -g -I./include repro_binmode_null.c -o repro_binmode_null
*
* If you want a clearer diagnostic, build+run under ASAN:
* gcc -fsanitize=address,undefined -g -I./include repro_binmode_null.c -o repro_binmode_null_asan
*
* Run:
* ./repro_binmode_null
* ./repro_binmode_null_asan
*
* Note: This program intentionally triggers the problematic call for repro purposes.
*/
#include <stdio.h>
/* Adjust the path below if your include tree is located elsewhere */
#include "tool_binmode.h"
int main(void)
{
/* Intentionally pass NULL to reproduce the issue.
The current macro expands to fileno(NULL), which is UB. */
CURLX_SET_BINMODE(NULL);
/* If the program continues without crashing, print a confirmation */
printf("CURLX_SET_BINMODE(NULL) returned — either implementation avoided fileno(NULL) or UB did not manifest.\n");
return 0;
}
Build & run instructions :-
From the repo root (assuming include/tool_binmode.h exists):
Compile (regular):
gcc -Wall -Wextra -g -I./include repro_binmode_null.c -o repro_binmode_null
./repro_binmode_null
Compile & run with sanitizers (recommended):
gcc -fsanitize=address,undefined -g -I./include repro_binmode_null.c -o repro_binmode_null_asan
./repro_binmode_null_asan
Expected ASAN/UBSAN output (example)
You will likely see an error such as:
runtime error: null pointer passed to function 'fileno'
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior ...
or a segmentation fault (SIGSEGV) depending on platform and libc.
## Impact
The PoC intentionally triggers UB so it may crash; that is the point — to show behavior and allow maintainers to fix it.
For Windows cross-build or non-POSIX setups, behavior varies; running under ASAN/UBSAN is recommended to obtain a reliable diagnostic.
Basic Information
ID
H1:3400831
Published
Oct 27, 2025 at 06:55
Modified
Oct 27, 2025 at 10:51