]> git.kaiwu.me - haproxy.git/commitdiff
BUG/MEDIUM: log: reserve the trailing 0 in CBOR int and bool encoders
authorChristopher Faulet <cfaulet@haproxy.com>
Wed, 23 Sep 2026 04:31:28 +0000 (04:31 +0000)
committerChristopher Faulet <cfaulet@haproxy.com>
Wed, 23 Sep 2026 12:05:25 +0000 (14:05 +0200)
Commit 378386e14 ("BUG/MEDIUM: log: always reserve room for trailing 0 when
using CBOR encoding helpers") made the text encoding helpers reserve one
byte for the terminating NULL byte that sess_build_logline_orig() always
appends, but lf_bool_encode() and lf_int_encode() were missed:
_lf_cbor_encode_byte() and cbor_encode_int64_{bin,hex}() were still called
with "dst + size" as the stop pointer. So the trailing 0 could be written
one byte past the end of the output buffer.

Let's pass "dst + size - 1" to these encoders like the other helpers do.
The log_cbor reg-test was extended to sweep a string across the end of the
chunk, followed by an int or a bool, with pool tags enabled.

The was introduced by c614fd3b9 ("MINOR: log: add +cbor encoding
option"), so this must be backported up to 3.0.

reg-tests/log/log_cbor.vtc
src/log.c

index 78e0ba1e403ae5206b305acf43052ebe1aecd905..89e0491e3a2763fad4419a5f2c13a16461650134 100644 (file)
@@ -118,3 +118,125 @@ haproxy h1 -cli {
     send "show events myring"
     expect !~ "A#01B"
 }
+
+# The output of an int or a bool is written by encoders which use all the room
+# they are given, so they must be given one byte less than the output buffer,
+# which always receives a trailing zero. The syslog output has one spare byte
+# which hides a mistake there, but not the other users of log-formats, such as
+# set-var-fmt which builds into a trash chunk. So here a string whose length
+# is swept across the end of that chunk is followed by an int or a bool: at
+# one of these lengths the value exactly fills the chunk. The pool tags make
+# the process die if one byte is written past the end of the area.
+haproxy h2 -arg "-dMno-merge,tag" -conf {
+    defaults
+        mode http
+        timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+        timeout client  "${HAPROXY_TEST_TIMEOUT-5s}"
+        timeout server  "${HAPROXY_TEST_TIMEOUT-5s}"
+
+    frontend fe_int
+        bind "fd@${fe_int}"
+        http-request set-var-fmt(txn.x) "%{+cbor}o%(a)[req.hdr(x)]%(s)[int(1)]"
+        http-request return status 200
+
+    frontend fe_bool
+        bind "fd@${fe_bool}"
+        http-request set-var-fmt(txn.x) "%{+cbor}o%(a)[req.hdr(x)]%(s)[bool(1)]"
+        http-request return status 200
+} -start
+
+client c_int_8180 -connect ${h2_fe_int_sock} {
+    txreq -hdrlen x 8180
+    rxresp
+    expect resp.status == 200
+} -run
+
+client c_int_8181 -connect ${h2_fe_int_sock} {
+    txreq -hdrlen x 8181
+    rxresp
+    expect resp.status == 200
+} -run
+
+client c_int_8182 -connect ${h2_fe_int_sock} {
+    txreq -hdrlen x 8182
+    rxresp
+    expect resp.status == 200
+} -run
+
+client c_int_8183 -connect ${h2_fe_int_sock} {
+    txreq -hdrlen x 8183
+    rxresp
+    expect resp.status == 200
+} -run
+
+client c_int_8184 -connect ${h2_fe_int_sock} {
+    txreq -hdrlen x 8184
+    rxresp
+    expect resp.status == 200
+} -run
+
+client c_int_8185 -connect ${h2_fe_int_sock} {
+    txreq -hdrlen x 8185
+    rxresp
+    expect resp.status == 200
+} -run
+
+client c_int_8186 -connect ${h2_fe_int_sock} {
+    txreq -hdrlen x 8186
+    rxresp
+    expect resp.status == 200
+} -run
+
+client c_int_8187 -connect ${h2_fe_int_sock} {
+    txreq -hdrlen x 8187
+    rxresp
+    expect resp.status == 200
+} -run
+
+client c_bool_8180 -connect ${h2_fe_bool_sock} {
+    txreq -hdrlen x 8180
+    rxresp
+    expect resp.status == 200
+} -run
+
+client c_bool_8181 -connect ${h2_fe_bool_sock} {
+    txreq -hdrlen x 8181
+    rxresp
+    expect resp.status == 200
+} -run
+
+client c_bool_8182 -connect ${h2_fe_bool_sock} {
+    txreq -hdrlen x 8182
+    rxresp
+    expect resp.status == 200
+} -run
+
+client c_bool_8183 -connect ${h2_fe_bool_sock} {
+    txreq -hdrlen x 8183
+    rxresp
+    expect resp.status == 200
+} -run
+
+client c_bool_8184 -connect ${h2_fe_bool_sock} {
+    txreq -hdrlen x 8184
+    rxresp
+    expect resp.status == 200
+} -run
+
+client c_bool_8185 -connect ${h2_fe_bool_sock} {
+    txreq -hdrlen x 8185
+    rxresp
+    expect resp.status == 200
+} -run
+
+client c_bool_8186 -connect ${h2_fe_bool_sock} {
+    txreq -hdrlen x 8186
+    rxresp
+    expect resp.status == 200
+} -run
+
+client c_bool_8187 -connect ${h2_fe_bool_sock} {
+    txreq -hdrlen x 8187
+    rxresp
+    expect resp.status == 200
+} -run
index 91e43b5a992d297dc0b37f685d3a7886738ac0d8..ed8354a4ec5e046b490c0eda4cf74f71fa94f118 100644 (file)
--- a/src/log.c
+++ b/src/log.c
@@ -2694,9 +2694,12 @@ static char *lf_bool_encode(char *dst, size_t size, uint8_t value,
                return ret;
        }
        if (ctx->options & LOG_OPT_ENCODE_CBOR) {
+               /* the cbor encoder doesn't append terminating NULL byte, we
+                * must reserve 1 byte for that.
+                */
                if (value)
-                       return _lf_cbor_encode_byte(ctx, dst, dst + size, 0xF5);
-               return _lf_cbor_encode_byte(ctx, dst, dst + size, 0xF4);
+                       return _lf_cbor_encode_byte(ctx, dst, dst + size - 1, 0xF5);
+               return _lf_cbor_encode_byte(ctx, dst, dst + size - 1, 0xF4);
        }
 
        return NULL; /* not supported */
@@ -2737,12 +2740,13 @@ static char *lf_int_encode(char *dst, size_t size, int64_t value,
        }
        else if (ctx->options & LOG_OPT_ENCODE_CBOR) {
                /* Always print as a regular int64 number (STR typecast isn't
-                * supported)
+                * supported). The cbor encoder doesn't append terminating NULL
+                * byte, we must reserve 1 byte for that.
                 */
                if (ctx->options & LOG_OPT_BIN)
-                       return cbor_encode_int64_bin(dst, dst + size, value);
+                       return cbor_encode_int64_bin(dst, dst + size - 1, value);
                else
-                       return cbor_encode_int64_hex(dst, dst + size, value);
+                       return cbor_encode_int64_hex(dst, dst + size - 1, value);
        }
 
        return NULL; /* not supported */