]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MEDIUM: acme: protect against risk of null-deref on connection failure
authorWilly Tarreau <w@1wt.eu>
Tue, 26 May 2026 06:36:36 +0000 (08:36 +0200)
committerWilly Tarreau <w@1wt.eu>
Tue, 26 May 2026 11:13:24 +0000 (13:13 +0200)
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.

src/acme.c

index 6b4dcd2afd562c52ede9adb9cc71b65cdc765b23..7875f11e8b68fb58adf80378af0d58291e5a7a1b 100644 (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);