nf_tables register validation flaws (CVE-2022-1015/1016)¶
nftables register index'lerinin eksik bounds validation'ı, bir CAP_NET_ADMIN kullanıcısının register array'inin ötesine yazmasına (CVE-2022-1015, OOB write) ve initialize edilmemiş register/stack verisini leak etmesine (CVE-2022-1016, infoleak) olanak veriyor.
Mechanism¶
Registers as a fixed-size scratch array
nf_tables expression'ları küçük, sabit boyutlu bir 32-bit register array'i aracılığıyla iletişim kurar, struct nft_regs (data member'ı 0x50 = 80 byte'tır). Her expression hangi register'dan okuduğunu (sreg) veya hangisine yazdığını (dreg) bildirir. Kernel, rule-build zamanında register_index * 4 + access_length'ın o 80-byte'lık array içinde kaldığını doğrulamalıdır — aksi hâlde paket başına evaluate edilen bir expression, register penceresinin dışını okur veya yazar.
İki ayrı correctness invariant'ı söz konusudur:
- CVE-2022-1015 (bounds):
nft_validate_register_store()/nft_validate_register_load()reg * NFT_REG32_SIZE + len > sizeof_field(struct nft_regs, data)'yı kontrol eder.regtamamen kullanıcı kontrollü biru32'den alındığında,reg * 4çarpımı wrap edebilir ve/veya index daha sonra biru8 dreg/sreg'e daraltıldığında, validation'dan geçen bir değer runtime'da out-of-range bir register'a eşlenebilir — register block'una komşu kernel stack'ine bir OOB write. - CVE-2022-1016 (initialisation): register array'i, bir expression chain çalışmadan önce tamamen sıfırlanmaz. Chain'in hiç yazmadığı bir register'ı okuyan bir expression eski stack içeriğini döndürür; bu da dışarı kopyalanabilir (örneğin bir verdict/payload'a), kernel belleğini leak eder ve KASLR'yi yener.
Walkthrough¶
Store-tarafı validation (pre-patch, basitleştirilmiş):
/* net/netfilter/nf_tables_api.c */
int nft_validate_register_store(const struct nft_ctx *ctx,
enum nft_registers reg, ...,
unsigned int len)
{
...
if (reg * NFT_REG32_SIZE + len > /* NFT_REG32_SIZE == 4 */
sizeof_field(struct nft_regs, data)) /* == 0x50 */
return -ERANGE;
...
}
nft_parse_register() kullanıcı değerini eşler: legacy register'lar NFT_REG_1..NFT_REG_4 ölçeklenir, daha yeni NFT_REG32_00.. ise 4 kadar aşağı kaydırılır. 0xffffffff'e yakın özel hazırlanmış bir index, aritmetik kontrolden geçebilir ama evaluation sırasında gerçekte kullanılan u8 register field'ına daraltıldığında 80-byte'lık array'in dışına işaret edebilir.
CVE-2022-1015 fix'i (6e1acfa387b9, "netfilter: nf_tables: validate registers
coming from userspace."), overflow eden product yerine register değerini düzgün
valide eder. Bug, nft_parse_register_store() v5.12'de (345023b0db3) eklendiğinde
reachable oldu; 5.12'den fix'e kadarki kernel'ler etkilenir.
Public exploitation altitude'da (David Bouman), aynı OOB primitive birkaç
expression üzerinden ifade edilir: nft_payload/nft_payload_set register file'a
göre OOB read/write yapar ve sıfır shift'li bir nft_bitwise, OOB-read data'sını
geçerli bir register'a kopyalayarak exfiltrate edilebilir kılar — "bitwise" pivot
adlandırması buradan gelir. Chain kernel base'i leak eder, sonra bir stack return
address'ini commit_creds()/prepare_kernel_cred() çağıran bir ROP chain ile
overwrite eder.
Tetikleyici taslağı (netlink, CAP_NET_ADMIN gerektirir, örneğin unshare -Urn'de):
NFT_MSG_NEWTABLE/NFT_MSG_NEWCHAIN— bir base chain kur.NFTA_*_DREG/SREG'i sınır register index'ini taşıyan bir expression (örneğinnft_payload,nft_bitwise,nft_immediate) ileNFT_MSG_NEWRULE.- CVE-2022-1015: expression'ın paket başına store'u
nft_regs'in dışına düşer, komşu kernel stack'ini corrupt eder — bir ROP'a pivot için kullanılabilir kontrollü bir write. Bkz. nft tables ROP exploitation (CVE-2023-0179 ile alternatif bir ROP yolu; farklı bir root cause —nft_payload_copy_vlan()VLAN underflow'u —, buradaki register OOB'nin exploit'i değil). - CVE-2022-1016: yazılmamış bir register oku ve onu emit et; yanıt initialize edilmemiş kernel stack byte'larını taşır.
Conceptual CVE-2022-1016 leak path
Tam register index'i ve leak edilen offset'ler kernel build'ine bağlıdır; yeniden üretilmedikçe bunları kavramsal tutun.Two CVEs, two patches
CVE-2022-1015 (OOB write) ve CVE-2022-1016 (uninitialised-register infoleak) birlikte açıklandı ama bağımsız fix'lerdir. Bir kernel biri için yamalanmış ama diğerine hâlâ vulnerable olabilir; her iki commit'i de kontrol edin.
Detection¶
nft_*_eval'innft_regskomşularına yazdığı yere yakın KASAN out-of-bounds raporları.- Bildirilen register index'leri
u32aralığının üst ucunda oturan rule'lar.
Mitigation¶
- CVE-2022-1015, register bounds'ı wrap olmadan doğrulayarak ve out-of-range index'leri reddederek düzeltilir.
- CVE-2022-1016, evaluation öncesinde register array'ini sıfırlayarak düzeltilir; böylece yazılmamış register'ların okunması eski belleği leak edemez.
CAP_NET_ADMINdayanağını kaldırmak için unprivileged user namespace'leri kısıtlayın.