rxrpc page-cache write Dirty Frag (CVE-2026-43500)¶
"Dirty Frag": rxrpc'nin DATA/RESPONSE handler'ları, externally-owned paged fragment taşıyan non-cloned bir skb'yi yalnızca cloned olduğunda un-share ediyor; bu yüzden in-place AEAD decrypt,
splice()ile pin'lenmiş read-only page-cache page'ler üzerine yazıyor — dosyaları (örn./etc/passwd) düzenleyip root veren Dirty-Pipe sınıfı bir page-cache write.
Mechanism¶
Note
Neden çalışır: page cache, bir dosyanın verisinin tek in-RAM kopyasını tutar; tüm reader'lar bunu paylaşır ve filesystem permission check'leri yalnızca write path'inde uygulanır. "page-cache write" bug sınıfı (Dirty Pipe, "Copy Fail", Dirty Frag) aynı karışıklığı paylaşır: bir subsystem, privately sahip olduğunu varsaydığı bir bellek üzerine in-place write yapar, ama bu aslında unprivileged bir kullanıcının splice()/vmsplice() ile pin'lediği read-only bir page-cache page'idir. Diskteki dosya değişmeden kalır, ama sonrasındaki her reader saldırganın byte'larını görür — /etc/passwd'ı düzenleyip root'a pivot etmeye yeter, üstelik hiçbir permission check'e bakılmadan.
Dirty Frag, pin'lenmiş page'i bir pipe buffer'dan (Dirty Pipe) bir sk_buff paged fragment'ına taşır ve "write", pipe merge yerine in-place crypto decryption ile gerçekleştirilir. rxrpc'nin DATA handler'ı (rxrpc_input_call_event()) ve RESPONSE handler'ı (rxrpc_verify_response()), skb'nin private linear kopyasını yalnızca skb_cloned() true olduğunda yapıyordu. Cloned olmayan ama hâlâ externally-owned paged frag taşıyan bir skb (SKBFL_SHARED_FRAG, __ip_append_data üzerinden bir UDP socket'e splice() ile set edilir, ya da zincirlenmiş bir skb_has_frag_list()), zero-copy fast path'e düşer; bu da frag page'lerini skb_to_sgvec() ile doğrudan AEAD/skcipher scatter-gather listesine bağlar. Decryption ardından bu shared page'lerin üzerine in place yazar.
Walkthrough¶
Fix'in birebir subject'i bug'ı şöyle ifade eder: "rxrpc: Also unshare DATA/RESPONSE packets when paged frags are present." Açık bırakan gate yalnızca skb_cloned()'ı kontrol ediyordu:
/* net/rxrpc/call_event.c & conn_event.c (pre-fix, conceptual) */
if (skb_cloned(skb))
skb = unshare_linear_copy(skb); /* private copy ONLY when cloned */
/* non-cloned skb with SHARED_FRAG pages falls through to in-place crypto */
skb_to_sgvec(skb, sg, ...);
skcipher_request_set_crypt(req, sg, sg, 8, iv); /* src == dst: in-place 8-byte STORE */
Attack flow (deterministik — kaybedilecek bir race yok):
# 1. pin a read-only page-cache page of the target file into a UDP send buffer
fd=$(open /etc/passwd O_RDONLY)
# splice(fd -> pipe -> udp_socket): __ip_append_data stores it as a paged
# fragment marked SKBFL_SHARED_FRAG (externally owned, still user-referenced)
# 2. send over rxrpc on loopback so the DATA/RESPONSE handler receives the skb
# skb is NOT cloned -> falls through to the zero-copy in-place decrypt path
Neden deterministik ve write neden tutuyor
skb_to_sgvec()pin'lenmiş frag page'lerini doğrudan crypto SGL'ine besler; rxkadsrc == dstset ettiği için decryption çıktısı page-cache page'in kendisinin üzerine yazar.- rxkad'ın cipher'ı zayıf/deterministik olduğundan, saldırgan key/IV materyalini offline brute-force eder; böylece in-place decryption, page cache'e yazılmasını istediği tam olarak o plaintext byte'larını üretir. Bu da onu bir timing race değil, deterministik bir logic flaw yapar — yüksek güvenilirlik, düşük panic riski.
- Net etki: saldırganın seçtiği 8 byte'lık bir STORE doğrudan kurban dosyanın read-only page-cache page'ine düşer; tüm write-permission check'lerini bypass eder;
/etc/passwd'ı düzenle → root.
Warning
Kardeş CVE-2026-43284, xfrm-ESP (IPsec) esp4/esp6 in-place decrypt path'inde aynı pattern'e vurur ve "Copy Fail ile aynı sink'i paylaşır", ama algif_aead yüklü olsun olmasın tetiklenir. Dirty Frag ve ESP bug'ı birlikte açıklandı (Hyunwoo Kim / @v4bel, Mayıs 2026).
Dirty Pipe ile ilişkisi (şablon): Dirty Pipe (CVE-2022-0847) bir page-cache page'i bir pipe'a splice() eder ve geride stale bir PIPE_BUF_FLAG_CAN_MERGE flag'i taşıyan bir pipe_buffer bırakır; sonraki bir write() read-only page'e "merge" yapar. Dirty Pipe bir uninitialized flag'i istismar etti; Dirty Frag ise bir network receive path'inde in-place crypto öncesi eksik bir un-share / ownership check'i istismar eder. Aynı sink (shared page-cache page'in üzerine yazma), farklı source path.
Detection¶
net/rxrpc/call_event.cveyaconn_event.ciçinde,skb_to_sgvec/skcipher decrypt civarında KASAN/out-of-bounds-write report'ları (CWE-787).- Loopback üzerinde unprivileged rxrpc (
AF_RXRPC) trafiğinin, read-only bir fd'densplice()/sendmsg(MSG_SPLICE_PAGES)ile birleşmesi anormaldir. - Hassas dosyaların in-RAM sapmasını (page cache vs. diskteki hali) yakalayan file-integrity monitoring, Dirty-Pipe sınıfı için kanonik tespittir.
Mitigation¶
- Upstream'de
aa54b1d27fe0commit'i ile düzeltildi (subject "rxrpc: Also unshare DATA/RESPONSE packets when paged frags are present"; backport'lar3711382a7734,3eae0f4f9f72,7c504ffab3ef,d45179f8795). Patch, un-share gate'iniskb_has_frag_list()veyaskb_has_shared_frag()üzerinde de ateşlenecek şekilde genişletir; herhangi bir in-place crypto öncesi kernel-private bir linear kopya zorlar ve zero-copy'yi yalnızca gerçekten kernel-owned frag'lar (NICpage_poolRX, GRO) için saklar. - Zaafiyeti getiren in-place fast path,
2dc334f1a63a(2023-06-08) commit'i ile eklendi — bu fix'inFixes:referansı, yani regression'ın kaynağı, patch tarihi değil. Flaw yaklaşık 3 yıl latent kaldı; private disclosure ile birlikte 8 Mayıs 2026'da yukarıdakiaa54b1d27fe0ile fix'lendi (Hyunwoo Kim / @v4bel). Yani "2023 → 2026" boşluğu bir tutarsızlık değil: 2023'te introduce edilip 2026'da açıklanan latent bir bug. CVSS 7.8 HIGH (AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H). - Mitigation'lar: kullanılmadığı yerlerde
rxrpc/kafsblacklist'le; unprivilegedsplice/vmsplice'ın socket'lere girişini kısıtla; distro güncellemelerini uygula.