BUG/MEDIUM: acme: protect against risk of null-deref on connection failure

7 ACME state handlers iterate over hc->res.hdrs, but they can be called
after an error was detected, and the HTTP client will leave res.hdrs NULL
on connection errors before headers are received. Let's check this inside
the loop, like the chkorder handler already does.

Most of them, if not all, need to be backported to 3.2.
This commit is contained in:
Willy Tarreau 2026-05-26 08:36:36 +02:00
parent e583b38c63
commit 8cb0a0c53d

View file

@ -1532,7 +1532,7 @@ int acme_res_certificate(struct task *task, struct acme_ctx *ctx, char **errmsg)
hdrs = hc->res.hdrs;
for (hdr = hdrs; isttest(hdr->v); hdr++) {
for (hdr = hdrs; hdrs && isttest(hdr->v); hdr++) {
if (isteqi(hdr->n, ist("Replay-Nonce"))) {
istfree(&ctx->nonce);
ctx->nonce = istdup(hdr->v);
@ -1745,7 +1745,7 @@ int acme_res_finalize(struct task *task, struct acme_ctx *ctx, char **errmsg)
hdrs = hc->res.hdrs;
for (hdr = hdrs; isttest(hdr->v); hdr++) {
for (hdr = hdrs; hdrs && isttest(hdr->v); hdr++) {
if (isteqi(hdr->n, ist("Replay-Nonce"))) {
istfree(&ctx->nonce);
ctx->nonce = istdup(hdr->v);
@ -1846,7 +1846,7 @@ enum acme_ret acme_res_challenge(struct task *task, struct acme_ctx *ctx, struct
TRACE_DATA(__FUNCTION__, ACME_EV_RES, ctx, NULL, &hc->res.buf);
for (hdr = hdrs; isttest(hdr->v); hdr++) {
for (hdr = hdrs; hdrs && isttest(hdr->v); hdr++) {
if (isteqi(hdr->n, ist("Replay-Nonce"))) {
istfree(&ctx->nonce);
ctx->nonce = istdup(hdr->v);
@ -1973,7 +1973,7 @@ int acme_res_auth(struct task *task, struct acme_ctx *ctx, struct acme_auth *aut
hdrs = hc->res.hdrs;
for (hdr = hdrs; isttest(hdr->v); hdr++) {
for (hdr = hdrs; hdrs && isttest(hdr->v); hdr++) {
if (isteqi(hdr->n, ist("Replay-Nonce"))) {
istfree(&ctx->nonce);
ctx->nonce = istdup(hdr->v);
@ -2289,7 +2289,7 @@ int acme_res_neworder(struct task *task, struct acme_ctx *ctx, char **errmsg)
hdrs = hc->res.hdrs;
for (hdr = hdrs; isttest(hdr->v); hdr++) {
for (hdr = hdrs; hdrs && isttest(hdr->v); hdr++) {
if (isteqi(hdr->n, ist("Replay-Nonce"))) {
istfree(&ctx->nonce);
ctx->nonce = istdup(hdr->v);
@ -2468,7 +2468,7 @@ int acme_res_account(struct task *task, struct acme_ctx *ctx, int newaccount, ch
hdrs = hc->res.hdrs;
for (hdr = hdrs; isttest(hdr->v); hdr++) {
for (hdr = hdrs; hdrs && isttest(hdr->v); hdr++) {
if (isteqi(hdr->n, ist("Location"))) {
istfree(&ctx->kid);
ctx->kid = istdup(hdr->v);
@ -2535,7 +2535,7 @@ int acme_nonce(struct task *task, struct acme_ctx *ctx, char **errmsg)
hdrs = hc->res.hdrs;
for (hdr = hdrs; isttest(hdr->v); hdr++) {
for (hdr = hdrs; hdrs && isttest(hdr->v); hdr++) {
if (isteqi(hdr->n, ist("Replay-Nonce"))) {
istfree(&ctx->nonce);
ctx->nonce = istdup(hdr->v);