← Commit list

7934b5400f

Joshua Rogers
Joshua Rogers
2026-09-21
SUCCESS Duration: 401s

Subject

capsule: reject a capsule that can never be buffered

Binary

No binary (build failed)

Architecture & Compiler Flags

Architecture: x86_64-linux-gnu Compiler: gcc (Ubuntu 11.4.0-1ubuntu1~22.04.3) 11.4.0

—

Build Log

(log yok)

Commit Diff GitHub →

lib/vquic/capsule.c+12 -6
@@ -256,7 +256,7 @@ size_t Curl_capsule_process_udp_raw(struct Curl_cfilter *cf,
*err = CURLE_RECV_ERROR;
return 0;
}
- if(capsule_length - 1 >= (uint64_t)SIZE_MAX) {
+ if(capsule_length - 1 > (uint64_t)(SIZE_MAX - offset)) {
infof(data, "Error! Capsule length too large: %" CURL_FORMAT_CURL_OFF_T,
(curl_off_t)capsule_length);
*err = CURLE_RECV_ERROR;
@@ -264,11 +264,6 @@ size_t Curl_capsule_process_udp_raw(struct Curl_cfilter *cf,
}
payload_len = (size_t)(capsule_length - 1);
- if(Curl_bufq_len(recvbufq) < offset + payload_len) {
- *err = CURLE_AGAIN;
- return 0;
- }
-
if(payload_len > len) {
infof(data, "UDP payload does not fit destination buffer: %zu > %zu",
payload_len, len);
@@ -277,6 +272,17 @@ size_t Curl_capsule_process_udp_raw(struct Curl_cfilter *cf,
return 0;
}
+ if(Curl_bufq_len(recvbufq) < offset + payload_len) {
+ if(Curl_bufq_is_full(recvbufq)) {
+ infof(data, "Error! Capsule does not fit the receive buffer: %zu",
+ payload_len);
+ *err = CURLE_RECV_ERROR;
+ return 0;
+ }
+ *err = CURLE_AGAIN;
+ return 0;
+ }
+
Curl_bufq_skip(recvbufq, offset);
if(!payload_len) {
*err = CURLE_OK;
tests/unit/unit3400.c+36 -0
@@ -241,6 +241,41 @@ static void test_capsule_decode_paths(void)
Curl_bufq_free(&q);
}
+
+static void test_capsule_full_buffer_reject(void)
+{
+ /* A capsule whose payload can never fit the bounded bufq must fail
+ instead of asking for more data forever. */
+ struct bufq q;
+ unsigned char out[256];
+ unsigned char cap[128];
+ CURLcode err = CURLE_OK;
+ size_t nread;
+ /* type 0x00, length 201 as a 2-byte varint, context 0x00 */
+ static const unsigned char hdr[] = { 0x00, 0x40, 0xC9, 0x00 };
+
+ Curl_bufq_init2(&q, 32, 4, BUFQ_OPT_NONE);
+
+ memset(cap, 0x5A, sizeof(cap));
+ memcpy(cap, hdr, sizeof(hdr));
+
+ /* the queue can still grow, so wait for the rest */
+ queue_bytes(&q, cap, 64);
+ nread = Curl_capsule_process_udp_raw(NULL, NULL, &q, out, sizeof(out), &err);
+ fail_unless(err == CURLE_AGAIN, "partial capsule should return AGAIN");
+ fail_unless(nread == 0, "partial capsule should read zero bytes");
+
+ /* the queue is full and the capsule is still short, it never completes */
+ queue_bytes(&q, cap + 64, sizeof(cap) - 64);
+ fail_unless(Curl_bufq_is_full(&q), "queue should be full");
+ nread = Curl_capsule_process_udp_raw(NULL, NULL, &q, out, sizeof(out), &err);
+ fail_unless(err == CURLE_RECV_ERROR,
+ "unbufferable capsule should return RECV_ERROR");
+ fail_unless(nread == 0, "unbufferable capsule should read zero bytes");
+
+ Curl_bufq_free(&q);
+}
+
#endif /* USE_NGTCP2 && !CURL_DISABLE_PROXY && !CURL_DISABLE_HTTP */
static CURLcode test_unit3400(const char *arg)
@@ -257,6 +292,7 @@ static CURLcode test_unit3400(const char *arg)
test_capsule_encode_decode_roundtrip();
test_capsule_decode_paths();
test_capsule_sequential_decode();
+ test_capsule_full_buffer_reject();
#endif
UNITTEST_END_SIMPLE