AppSec: SIGHUP reload deadlocks in shutdown — handlers block on InChan after runners exit, server.Shutdown waits forever
Los mantenedores suelen responder en 2 días
Nadie ha tomado este issue todavía.
Evaluación
- Dificultad
- 3/5
- Tiempo estimado
- 1-2 días
- Aptitud para principiantes
- 72/100
Línea de trabajo
Start at pkg/acquisition/modules/appsec/config.go appsecHandler around line 468, where the unconditional send w.InChan <- parsedRequest blocks, then read pkg/acquisition/modules/appsec/run.go listenAndServe (the unbounded server.Shutdown) and cmd/crowdsec/serve.go ShutdownCrowdsecRoutines/shutdownCrowdsec to see the shutdown order. The issue lists three candidate fixes; pick one and check existing tests under pkg/acquisition/modules/appsec/ for shutdown/HTTP coverage to extend. Done means a SIGHUP with at least one in-flight AppSec request completes the reload instead of hanging, verified by a test or a reproduced reload run.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
What happened?
A SIGHUP reload (sent by the packaged crowdsec-hubupdate after cscli hub upgrade found updates) never completed. The agent stopped all acquisition — file datasources and AppSec — and never started again. The process stayed alive, systemd kept reporting active (running), and nothing restarted it. WAF and log-based detection were both down for 8 hours until a manual systemctl restart (which itself had to fall back to SIGKILL after TimeoutStopSec).
The last lines in crowdsec.log, after which nothing is logged at all:
level=warning msg="SIGHUP received, reloading"
level=info msg="File datasource stopping" ...
level=info msg="Appsec Runner is dying" ...
There are no bind errors and no Error shutting down Appsec server — the reload never reaches the point of starting the new acquisition.
Goroutine dump of the hung process
Taken from /debug/pprof/goroutine?debug=1 before restarting. Relevant stacks (line numbers match commit 909b5157, the source of the 1.8.1 Debian package):
9 @ ...
# appsec.(*Source).appsecHandler+0x6f6 pkg/acquisition/modules/appsec/config.go:468
# net/http.HandlerFunc.ServeHTTP net/http/server.go:2286
# net/http.(*conn).serve net/http/server.go:2073
1 @ ...
# appsec.(*Source).listenAndServe+0x430 pkg/acquisition/modules/appsec/run.go:104
# appsec.(*Source).StreamingAcquisition.func1 pkg/acquisition/modules/appsec/run.go:153
1 @ ...
# main.ShutdownCrowdsecRoutines+0xc8 cmd/crowdsec/serve.go:113
# main.serveCrowdsec.func1 cmd/crowdsec/crowdsec.go:243
1 @ ...
# main.shutdownCrowdsec+0x53 cmd/crowdsec/serve.go:180
# main.shutdown cmd/crowdsec/serve.go:191
# main.HandleSignals.func1 cmd/crowdsec/serve.go:266
No AppSec runner goroutines are left.
Analysis
The shutdown order lets in-flight AppSec requests block forever:
acquisTomb.Kill(nil)— every goroutine of the AppSec source seesDying()at the same time.- The runners return immediately (
appsec_runner.go:564), so nothing readsinChanany more. - Requests that were already accepted by the HTTP server block in
appsecHandleron the unconditional sendw.InChan <- parsedRequest(config.go:468). There is noselectwith a cancellation case, so they can never return. listenAndServecallsw.server.Shutdown(ctx)(run.go:104).Shutdownwaits for active connections to finish, andctxhas no deadline, so it waits forever.acquisTomb.Wait()(serve.go:113) andcrowdsecTomb.Wait()(serve.go:180) never return; the reload never proceeds.
It only takes one request to be in flight at the moment the runners exit. On a bouncer with steady traffic (~7–8 inspected requests/s here) that is close to certain, so this is not a rare race in practice — it just only shows up on the nights when the hub actually upgrades something.
This is related to #4545 but is a different failure: there the shutdown completes and the listener leaks / fails to re-bind afterwards, here the shutdown itself never completes and there are no bind errors.
What did you expect to happen?
The reload completes, or — if AppSec cannot be stopped cleanly — the process fails loudly so a supervisor can restart it, instead of staying alive with every datasource stopped.
Possible fixes
Any one of these would break the cycle:
- In
appsecHandler, make the send toInChan(and the receive fromResponseChannelright after it) aselectthat also returns on shutdown, answering the bouncer with an error. - Call
server.Shutdownwith a bounded context and fall back toserver.Close()on timeout. - Shut the HTTP server down and let the runners drain
inChanbefore stopping the runners.
How can we reproduce it?
Enable AppSec, keep a steady stream of requests going through a bouncer, and send SIGHUP (or systemctl reload crowdsec). The hang needs at least one request to be inside appsecHandler when the runners exit.
Workaround
We replaced reload with restart both in a drop-in for crowdsec-hubupdate.service and in our configuration management handlers: a hung stop is then killed by systemd after TimeoutStopSec.
Crowdsec version
version: v1.8.1-debian-pragmatic-amd64-909b5157
Codename: alphaga
BuildDate: 2026-09-03_10:51:51
Installed from the crowdsec Debian package (1.8.1). AppSec enabled with the bot-challenge collections, OpenResty bouncer in front.
OS version
Ubuntu 22.04.5 LTS
Enabled collections and parsers
crowdsecurity/linux, sshd, nginx, base-http-scenarios, http-cve, http-dos, appsec-virtual-patching, appsec-generic-rules, appsec-bot-challenge-permissive, appsec-bot-challenge-good-bots, appsec-bot-challenge-exclude-paths, appsec-bot-challenge-scoring, plus a few local scenarios and parsers.
Acquisition config
File datasources on nginx and GitLab logs, plus:
source: appsec
listen_addr: <private address>:7422
appsec_configs:
- crowdsecurity/appsec-default
- crowdsecurity/appsec-bot-challenge-scoring
- crowdsecurity/appsec-bot-challenge-scoring-permissive
# ... bot-challenge exclusions ...
- Lenguaje dominante
- Go
- Estrellas
- 15.1k
- Forks
- 726
- Merge medio
- 1 d 10 h
- PR fusionados (30 d)
- 15
Preparar el entorno
Este proyecto no incluye contenedor de desarrollo, Dockerfile ni guía de contribución, así que la configuración corre por tu cuenta: empieza por su README y consulta nuestra guía para la primera contribución para los pasos generales.
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de crowdsecurity/crowdsec
-
[docker] Align build and debian releasePosiblemente ocupada @albundy83 la tomó hace 2 días. Abiertokind/enhancement needs/triage
Dificultad 2/5 1-3 horas Aptitud para principiantes 68/100
crowdsecurity/crowdsec#4803 · 3 comentarios ·
Los mantenedores suelen responder en 2 días
-
Bucket queues preallocate all their slots when the bucket is createdPosiblemente ocupada @AdzerKI la tomó hace 4 días. Abiertokind/bug needs/triage os/linux
Dificultad 2/5 1-3 horas Aptitud para principiantes 83/100
crowdsecurity/crowdsec#4799 · 3 comentarios ·
Los mantenedores suelen responder en 2 días
-
"Machine is not enrolled in the console, can't synchronize with the console" should not be an error logPosiblemente ocupada @bharathvemula la tomó hoy. Abiertokind/bug needs/triage os/linux
Dificultad 2/5 1-3 horas Aptitud para principiantes 30/100
crowdsecurity/crowdsec#4809 · 1 comentario ·
Los mantenedores suelen responder en 2 días
-
kind/bug needs/triage os/linux
Dificultad 3/5 1-2 días Aptitud para principiantes 25/100
crowdsecurity/crowdsec#4797 · 1 comentario ·
Los mantenedores suelen responder en 2 días
-
needs/kind needs/triage
Dificultad 5/5 Más de una semana Aptitud para principiantes 38/100
crowdsecurity/crowdsec#4795 · 2 comentarios ·
Los mantenedores suelen responder en 2 días
Todos los issues de crowdsecurity/crowdsec
Issues similares
-
Dificultad 1/5 Menos de una hora Aptitud para principiantes 88/100
eugenioenko/ttt#1461 ·
Los mantenedores suelen responder en 1 día
-
[Studio feedback] 对话内容向下滚动时执行过程吸顶时,由于背景色是透明的,导致执行过程标题与下面的具体执行内容重叠,导致了两行信息重叠显示;建议执行过程的背景色设置为会话界面的背景Abiertobug from-studio
Dificultad 2/5 1-3 horas Aptitud para principiantes 66/100
esengine/DeepSeek-Reasonix#15044 ·
Los mantenedores suelen responder en 1 día
-
Allow multiple -w wordlistsAbiertoarea: cli enhancement good first issue severity: low
Dificultad 2/5 1-3 horas Aptitud para principiantes 85/100
TMHSDigital/subenum#199 ·
Los mantenedores suelen responder en 1 día
-
type/bug
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 82/100
redhat-cop/vault-config-operator#419 ·
Los mantenedores suelen responder en 1 día