From: Christopher Faulet Date: Wed, 23 Sep 2026 04:31:28 +0000 (+0000) Subject: BUG/MEDIUM: log: reserve the trailing 0 in CBOR int and bool encoders X-Git-Tag: v3.5-dev8~130 X-Git-Url: https://git.kaiwu.me/?a=commitdiff_plain;h=cf9670997ad9ad018ad5e85bd1542e5c186ade7f;p=haproxy.git BUG/MEDIUM: log: reserve the trailing 0 in CBOR int and bool encoders 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. --- diff --git a/reg-tests/log/log_cbor.vtc b/reg-tests/log/log_cbor.vtc index 78e0ba1e4..89e0491e3 100644 --- a/reg-tests/log/log_cbor.vtc +++ b/reg-tests/log/log_cbor.vtc @@ -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 diff --git a/src/log.c b/src/log.c index 91e43b5a9..ed8354a4e 100644 --- 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 */