| 항목 | 내용 |
|---|---|
| CVE ID | CVE-2023-32233 |
| 영향 버전 | Linux 6.3.1 이하 (익명 집합 기능이 있는 상당 기간의 커널) |
| CVSS v3.1 | 7.8 (High) — AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H |
| 공개일 | 2023-05-08 |
| 비고 | 배치(batch) 트랜잭션 처리 로직의 상태 관리 오류 |
nftables는 여러 개의 변경 작업(규칙 추가/삭제 등)을 하나의 배치(batch) 로 묶어 한 번에 커밋할 수 있다. CVE-2023-32233은 이 배치 안에서 "규칙을 지우면서 그 규칙에 딸린 익명 집합(anonymous set)도 암묵적으로 지워지는 상황"과 "같은 배치 안에서 그 집합을 다시 건드리는 작업"이 함께 오면, 커널이 이미 해제 예정인 집합을 여전히 살아있는 것처럼 다뤄서 use-after-free 가 발생하는 취약점이다. 권한 없는 로컬 사용자가 커널 메모리를 임의로 읽고 쓸 수 있는 상태까지 이어질 수 있어 root 권한 획득이 가능하다.
nftables의 "집합(set)"은 IP 주소 목록처럼 여러 값을 묶어 규칙에서 참조할 수 있게 해주는
자료구조다. 익명 집합은 이름을 붙이지 않고 규칙 안에 인라인으로 즉석에서 만들어지는
집합이다 — 그 집합을 참조하는 규칙(정확히는 lookup 표현식)이 사라지면, 익명 집합도 같이
사라지는 게 정상이다. 즉 익명 집합의 수명은 그것을 참조하는 규칙의 수명에 종속된다.
nftables는 배치 하나를 커밋할 때 여러 단계를 거친다. 이 문서에서 중요한 두 단계는:
- PREPARE: "이 변경들을 실제로 적용해도 되는지" 미리 준비하는 단계. 아직 최종 확정은 아니다.
- COMMIT / 실제 반영: PREPARE 를 통과한 변경들이 실제 커널 상태에 반영되는 단계.
집합이나 규칙에는 use(참조 카운트) 라는 값이 있어서, 몇 곳에서 이 집합을 쓰고 있는지를
추적한다. 그리고 "활성 상태인지" 를 나타내는 별도의 세대(generation) 비트마스크도 있다 —
이 두 가지가 서로 다른 시점에 갱신되면 문제가 생긴다는 것이 이 취약점의 핵심이다.
패치 전 nf_tables_deactivate_set() 은 PREPARE 단계에서 참조 카운트만 줄일 뿐, 익명
집합을 "다음 세대에서는 비활성 상태" 로 표시하지는 않았다.
// net/netfilter/nf_tables_api.c — nf_tables_deactivate_set() (패치 전)
switch (phase) {
case NFT_TRANS_PREPARE:
set->use--; // 참조 카운트만 감소, "비활성 표시"는 없음
return;
case NFT_TRANS_ABORT:
...
}즉 같은 배치 안에서 "규칙을 지워서 익명 집합의 use 가 0이 됨" 과 "그 집합의 원소를 지우는
또 다른 작업" 이 순서대로 들어오면, 두 번째 작업이 실행되는 시점에도 커널은 "이 집합이
아직 유효하다" 고 착각한다 — use 카운트는 줄었지만 "비활성" 이라는 상태 자체가 별도로
기록되지 않았기 때문이다.
배치 안의 작업 순서 (패치 전)
[1] NFT_MSG_DELRULE ─▶ 규칙 삭제 ─▶ 딸려 있던 익명 집합도 암묵적으로 삭제 대상이 됨
└─ nf_tables_deactivate_set(PREPARE)
set->use-- (비활성 "표시"는 안 됨)
[2] NFT_MSG_DELSETELEM ─▶ "그 집합의 원소를 지워라"
└─ 커널: 이 집합, 아직 유효한 걸로 보임 → 그대로 진행
(하지만 실제 메모리 해제는 이미 예약된 상태)
[실제 커밋 단계] nf_tables_trans_destroy_work()
└─ [1]에서 예약된 집합 메모리 해제 실행
└─ [2]가 참조했던 포인터는 이미 해제된 메모리를 가리킴
→ Use-After-Free
이 문제는 "규칙 하나 지우고 끝" 이었다면 일어나지 않는다. 하나의 배치 안에 여러 작업을 순서대로 넣을 수 있다는 nftables의 기능 자체가 공격 표면이 된다 — 공격자는 "지운 것을 다시 건드리는" 순서를 의도적으로 만들어 이 틈을 노릴 수 있다.
- 로컬 사용자가 (권한 없는 network namespace 안에서도 가능)
lookup표현식으로 익명 집합을 참조하는 규칙을 하나 만든다. - 하나의 batch netlink 메시지 안에 다음을 순서대로 담는다: 그 규칙을 지우는
NFT_MSG_DELRULE, 그리고 곧바로 이어서 그 규칙이 참조하던 익명 집합의 원소를 지우는NFT_MSG_DELSETELEM. - 커널이 이 배치를 처리하면서
nf_tables_deactivate_set()이 PREPARE 단계에서 집합을 "비활성"으로 표시하지 않기 때문에, 두 번째 작업이 "아직 유효한 집합"이라고 믿고 그대로 진행된다. - 실제 커밋 단계에서 집합의 메모리가 해제되면, 이미 만들어진 댕글링 참조를 통해 해제된 메모리에 접근(읽기/쓰기)할 수 있는 상태가 된다.
- 커널 힙 할당자를 원하는 대로 유도(heap grooming)해 그 해제된 메모리 자리에 공격자가 제어하는 다른 객체를 채워 넣으면, 임의 커널 메모리 읽기/쓰기 프리미티브로 발전시킬 수 있고, 이를 이용해 프로세스 자격 증명(credential) 구조체를 덮어써 root 권한을 얻을 수 있다.
수정 커밋(c1592a89942e9678f7d9c8030efa777c0d57edab, "netfilter: nf_tables: deactivate
anonymous set from preparation phase")은 PREPARE 단계에서 익명 집합을 실제로 비활성
상태로 표시하도록 고쳤고, 그 반대 동작(활성화)을 위한 새 함수도 추가했다.
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@
+void nf_tables_activate_set(const struct nft_ctx *ctx, struct nft_set *set)
+{
+ if (nft_set_is_anonymous(set))
+ nft_clear(ctx->net, set);
+
+ set->use++;
+}
+
void nf_tables_deactivate_set(const struct nft_ctx *ctx, struct nft_set *set,
struct nft_set_binding *binding,
enum nft_trans_phase phase)
{
switch (phase) {
case NFT_TRANS_PREPARE:
+ if (nft_set_is_anonymous(set))
+ nft_deactivate_next(ctx->net, set);
+
set->use--;
return;그리고 집합을 사용하는 각 표현식(nft_dynset, nft_lookup, nft_objref 등)의 활성화
경로도 단순히 set->use++ 만 하던 것에서 새로 만든 nf_tables_activate_set() 을 호출하도록
통일했다. 이제 배치 안에서 집합이 삭제 대상이 되는 순간 "비활성" 세대 표시가 즉시 반영되므로,
같은 배치의 이후 작업이 그 집합을 참조하려 하면 "이미 비활성"임을 정확히 인식한다.
배치 안의 작업 순서 (패치 후)
[1] NFT_MSG_DELRULE ─▶ 규칙 삭제 ─▶ 익명 집합도 삭제 대상
└─ nf_tables_deactivate_set(PREPARE)
nft_deactivate_next() 로 "다음 세대엔 비활성" 즉시 표시
set->use--
[2] NFT_MSG_DELSETELEM ─▶ "그 집합의 원소를 지워라"
└─ 커널: 이 집합은 이미 비활성 상태로 표시됨 → 요청 거부/무효화
→ 해제 예정 메모리에 접근하는 경로 자체가 차단됨
- CVE-2023-32233 — oss-security (공개 공지)
- CVE-2023-32233 — NVD
- 수정 커밋 c1592a89942e9678f7d9c8030efa777c0d57edab — torvalds/linux
- Bugzilla Red Hat 2196105 — CVE-2023-32233
- "해제된 집합 메모리를 힙 그루밍으로 다른 객체와 겹치게 만드는" 구체적인 익스플로잇 기법
(어떤 커널 객체로 재점유하는지 등)은 이번에는 다루지 않았다. Google의
security-research저장소에 CVE-2023-32233 관련 exploit 문서가 있는 것으로 검색되었으나 이번에는 직접 열어 대조하지 못했다. nft_tables_trans_destroy_work()가 정확히 어느 시점에 실행되는지(워크큐 스케줄링 디테일)는 커밋 메시지 수준까지만 확인했다.