Package: curl Version: 8.21.0-1 Severity: important Tags: patch upstream User: [email protected] Usertags: autopkgtest
Dear Maintainer, During recent autopkgtest runs triggered by the vsftpd migration (as shown in the migration excuses page: https://qa.debian.org/excuses.php?package=vsftpd), we observed consistent failures on 32-bit architectures (specifically i386) in the following test case: test_05_errors.py::TestErrors::test_05_04_unclean_tls_shutdown[http/1.0] The test fails with exit code 8 (CURLE_WEIRD_SERVER_REPLY) instead of the expected exit code 56 (CURLE_RECV_ERROR). The curl verbose log shows: * Invalid Content-Length: value * closing connection #0 Upon further investigation in a local unstable-i386 chroot, we found that the Apache test server (mod_curltest) is actually sending an invalid "Content-Length: -1" header. The root cause lies in a signed/unsigned type promotion bug in the Apache test module: tests/http/testenv/mod_curltest/mod_curltest.c Line 409 of mod_curltest.c contains the following ternary assignment: r->clength = with_cl ? (chunks * chunk_size) : -1; Where the variables are declared as: int chunks; size_t chunk_size; apr_off_t clength; /* signed 64-bit integer */ On a 32-bit architecture (i386): 1. `chunks * chunk_size` evaluates to `unsigned int` (32-bit unsigned). 2. Due to Usual Arithmetic Conversions in C, the signed `-1` (int) operand of the ternary operator is promoted to `unsigned int`, yielding `4294967295` (0xFFFFFFFF). 3. The ternary operator returns `4294967295` as an `unsigned int`. 4. This unsigned value is then assigned to `r->clength` (apr_off_t, 64-bit signed). Since the source is unsigned, it is zero-extended, resulting in `r->clength` becoming `+4294967295`. 5. The subsequently executed check `if(r->clength >= 0)` evaluates to true. 6. Inside the block, `apr_ltoa(r->pool, (long)r->clength)` casts it to a 32-bit signed `long` (on 32-bit platforms), which truncates it back to `-1`, formatting it as "-1" and sending the "Content-Length: -1" header. On a 64-bit architecture (amd64), `size_t` is 64-bit, and `-1` (32-bit int) is promoted to `unsigned long` (64-bit), yielding `18446744073709551615`. When assigned to `r->clength` (64-bit signed), it wraps back to `-1`, which correctly skips the Content-Length generation. This type promotion mismatch can be safely fixed by avoiding the signed/unsigned mixture in the ternary operator. Please find the attached patch which resolves this issue by explicitly assigning the values using a standard if-else block. Thanks, Keng-Yu Lin --- diff --git a/tests/http/testenv/mod_curltest/mod_curltest.c b/tests/http/testenv/mod_curltest/mod_curltest.c index 585c57b..308bf3b 100644 --- a/tests/http/testenv/mod_curltest/mod_curltest.c +++ b/tests/http/testenv/mod_curltest/mod_curltest.c @@ -406,8 +406,12 @@ static int curltest_tweak_handler(request_rec *r) ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "error_handler: processing " "request, %s", r->args? r->args : "(no args)"); r->status = http_status; - r->clength = with_cl ? (chunks * chunk_size) : -1; + if(with_cl) { + r->clength = (apr_off_t)chunks * chunk_size; + } + else { + r->clength = -1; + } r->chunked = (r->proto_num >= HTTP_VERSION(1, 1)) && !with_cl; apr_table_setn(r->headers_out, "request-id", request_id);

