← 목록
기타 2026-07-07 5KB 읽기 4분

게이트웨이Q 적대적검증 — 워커 고사(wedge) 치명 결함 발견

개요

한선게이트웨이(게이트웨이통합.한선) + Q감독(다중워커 REUSEPORT) 조합에 대한 레드팀 적대검증. 그림자 인스턴스(9160대·9161 포트, 라이브 8080/8443 무접촉)에서 실제로 재현.

핵심 발견 (Critical, 재현됨)

워커 완전 고사(wedge) — 클라이언트 종료로도 복구 불가, 워커 2개면 전체 게이트웨이 다운

  • 원인: 통합서버시작(게이트웨이통합.한선 547행)의 메인 루프가 TCP수락→_요청처리→TCP닫기
단일 블로킹 accept-loop다. 워커 프로세스 내부에 스레드/포크/비동기 전혀 없음 (grep 확인: 포크/쓰레드/프로세스생성 키워드 전무).
  • _프록시스트리밍(201행)의 2단계 본문릴레이 루프(296~317행)는 업스트림 유휴 3초
또는 최대 8192회 반복(이론상 최대 ~6.8시간)까지 지속되며, 클라이언트 소켓 쓰기 실패(TCP쓰기 반환값)를 검사하지 않고 루프를 계속 돈다 — 즉 클라이언트가 연결을 끊어도(kill -9) 워커는 전혀 풀리지 않고, 오직 업스트림이 닫혀야만 풀린다.
  • 실측: 워커 2개(라이브 기본값과 동일 GWQ_WORKERS=2)에 slow-drip 백엔드로의
연결 2개만 걸면 — 무관한 도메인(baseline-check.example) 요청조차 100% 타임아웃 (code=000). 공격 클라이언트를 kill -9 해도 그대로 000 유지. 백엔드 프로세스를 kill 하자 즉시 회복(404, 11ms).
  • 파급: 라이브는 293+ 도메인을 단 2워커로 서빙 → 내부 서비스 중 단 하나가
느려지거나 응답불능(hang)이면, 그 서비스로의 요청 단 2개만으로 전체 게이트웨이가 다른 292개 도메인까지 포함해 완전 다운된다. Q감독의 헬스체크는 PID 생존만 확인(kill -0)하므로 이 wedge 상태를 감지하지 못해 자동 보충되지 않는다 (라이브 "확정 사실"의 "보충 필요 살아있는=1" organic death 로그와 연관 가능성, 단 "죽음"과 "고사"는 다른 현상이라 완전 동일 원인 단정은 아님).

검증한 다른 가설 (재현 안 됨 — 코드 정독 + 실측으로 반박)

  • REUSEPORT 다중워커 동시부팅 라우트tsv 경합: GW_WID 접미 tsv라 5워커 동시기동해도
293쌍 전원 정상 로드(경합 없음). 반박됨.
  • 문자열되감기가 정적맵 eager로드보다 먼저 protect 경계를 굳혀 다음 요청에서
정적맵 문자열 회수→크래시: 소스 확인 결과 eager로드(535행)가 최종 문자열보호()(545행)보다 먼저 실행되고, _정적맵확보가 플래그 캐시라 재실행되지 않음 — 현재 코드는 안전. 반박됨(과거 06-16 버그는 이미 고쳐진 상태 확인).
  • 소켓슬롯 128 고갈: _프록시스트리밍의 모든 종료 경로(연결실패/헤더없음/정상완료)에서
소켓닫기 호출 확인 — 명시적 FD 누수는 없음. 대신 위의 "워커 자체가 통째로 멈추는" 훨씬 심한 문제 발견.

부수 발견 (프로세스 오류, 자기보고)

테스트 중 안전 포트범위(8085-8099, 9155-9169) 지시를 어기고 8090-8200대 포트를 사용, 그 결과 실제 운영중인 무관 서비스(uvicorn forge.server, PID 14933, port 8200) 위에 CROWNY_TCP_REUSEPORT=1로 내 그림자 워커가 공존 바인딩되어 그 서비스의 트래픽 일부를 가로챈 사고 발생. 즉시 발견 후 kill로 정리, 라이브 게이트웨이(8080/8443, PID 8558/10589)는 시종 무접촉·정상 확인. 이후 전 테스트를 9160/9161(사전 점유 확인) 로 재실행해 재현.

관련 파일

  • /Users/ef/crowny-gateway/한선게이트웨이/게이트웨이통합.한선 (296-320행 릴레이 루프, 547-559행 메인루프)
  • /Users/ef/crowny-gateway/게이트웨이Q/Q감독.sh (워커수 기본 2, PID기반 헬스체크만)
  • /Users/ef/crowny-gateway/한선게이트웨이/설정.한선 (GW_WID tsv 격리 — 정상 확인)

권고(다음 조치, 미실행)

  1. _프록시스트리밍 본문릴레이 루프에서 TCP쓰기 반환값 검사 → 실패 시 즉시 루프 탈출
(클라이언트 사망 시 워커 즉시 해제).
  1. Q감독 헬스체크를 PID 생존이 아니라 실제 accept-루프 진행 여부(하트비트 타임스탬프
등)로 승격 — wedge 감지 후 강제 재기동.
  1. 워커수 2 → 최소 4~8로 상향(단일 서비스 hang의 전체영향 반경 축소), 또는 업스트림별
circuit breaker/짧은 connect+read 타임아웃 도입.

잔여 이슈

  • REUSEPORT setsockopt 반환값 미검사(crownyc.c 11818행)는 저위험(실패 시 bind 단계에서
드러남) — 정보성으로만 기록, 재현시도 안 함(시간 예산 소진).