n_gsm TTY use-after-free (CVE-2023-6546)¶
Linux
n_gsmGSM 0710 line discipline'ında bir race condition: eşzamanlıGSMIOC_SETCONFioctl'leristruct gsm_dlci'yi free edip yeniden okuyor ve mux restart sırasında bir use-after-free doğuruyor — bu n_gsm DLCI UAF'ı için gerçek CVE, CVE-2023-31436 değil CVE-2023-6546.
Mechanism¶
Warning
CVE ID düzeltmesi. Başlıktaki CVE-2023-31436 alias'ı bir n_gsm
bug'ını tarif etmiyor. NVD'ye göre CVE-2023-31436, QFQ packet
scheduler net/sched/sch_qfq.c'deki bir out-of-bounds write
(qfq_change_class, lmax'ın QFQ_MIN_LMAX'ı aşması) — tamamen
farklı bir subsystem. Bu sayfanın asıl anlattığı n_gsm DLCI
use-after-free'i CVE-2023-6546 olarak takip ediliyor. Biz doğrulanmış
n_gsm bug'ını belgeliyoruz ve yanlış etiketi tekrarlamak yerine işaret
ediyoruz.
Info
Aynı vulnerability. Bu sayfa, gsm-0710-multiplexing-race-uaf
ile aynı n_gsm race'ini (CVE-2023-6546, fix commit 3c4f8333b582)
anlatır. Fark yalnızca vurgu: bu sayfa hatalı CVE-2023-31436 alias'ının
düzeltilmesine odaklanır; diğer sayfa exploitation path'ine (ZDI-24-020
PoC, gsm->output() function-pointer overwrite) odaklanır. İki sayfa
birbirinin karşılıklı see_also'sunda listelenir.
Note
n_gsm line discipline'ı (drivers/tty/n_gsm.c), tek bir serial/tty
link üzerine birden çok logical channel'ı (DLCI — Data Link Connection
Identifier) katmanlayan 3GPP GSM 07.10 / 0710 multiplexing
protokolünü implemente eder. Her channel bir struct gsm_dlci; mux'un
kendisi struct gsm_mux (gsm), gsm->dlci[0] ise control channel.
GSMIOC_SETCONF ioctl'i, canlı bir mux'u yeniden konfigüre eder.
Reconfiguration mux'u yıkıp yeniden kurar ve teardown,
gsm_cleanup_mux() üzerinden işler — bu fonksiyon DLCI nesnelerini
free eder ve slot'larını NULL'a temizler.
Bug, use-after-free'e yol açan bir race condition. İki thread, gsm
line discipline etkinken aynı tty fd'si üzerinde GSMIOC_SETCONF
çağırdığında:
- Thread 2, mux mutex'ini almadan önce DLCI pointer'ını cache'liyor:
struct gsm_dlci *dlci = gsm->dlci[0]; - Thread 1,
mutex_lock(&gsm->mutex)alıyor, DLCI nesnelerini free edip slot'larıNULL'a set ediyor, sonra lock'ı bırakıyor. - Thread 2 nihayet mutex'i alıyor ve bayatlamış cache'li pointer'ını
dereference ediyor — örn.
dlci->dead = true;— free edilmiş belleğe dokunuyor.
İhlal edilen invariant: "paylaşılan bir yapıdan okunan bir pointer,
o yapıyı koruyan lock altında yeniden doğrulanmalıdır."
gsm_cleanup_mux(), gsm->dlci[0]'ı critical section dışında okudu;
böylece free edilmiş/NULL'lanmış slot ile lokal cache'lenmiş pointer
birbirinden ayrıştı.
Upstream fix (commit 3c4f8333b582), dlci = gsm->dlci[0] atamasını
mutex_lock(&gsm->mutex)'tan sonraya taşıyarak window'u kapatıyor;
böylece pointer yalnızca lock, DLCI'nin eşzamanlı olarak free
edilmediğini garantilediğinde okunuyor.
Walkthrough¶
Race için kavramsal tetikleme (yalnızca yetkili test):
-
Bir pty/serial master aç ve line discipline'ını gsm'e geçir:
-
Aynı
fd'yi paylaşan iki thread'den, reconfigure ioctl'ini döveç gibi çağır; böylece bir thread mux'u free ederken diğeri yeniden içeri giriyor:
Reconfigure yolu mux'u yeniden başlatır; gsm_cleanup_mux() bir
thread'de gsm->dlci[0]'ı free ederken, diğer thread hâlâ o pointer'ın
pre-lock bir kopyasını tutuyor.
- Yarışı kaybeden thread, free edilmiş
struct gsm_dlci'yi dereference eder (dlci->dead = true;) — use-after-free.
Note
struct gsm_dlci free edildiği ve attacker timing artı tty input'unu
kontrol ettiği için, free edilmiş slab nesnesi aynı boyutta bir spray
ile geri alınabilir (örn. tty nesnelerine karşı kullanılan
heap-grooming teknikleri). Free edilmiş DLCI, attacker'ın kontrol
ettiği data ile bir kez örtüştüğünde, sonraki field write/dereference'ler
kontrol edilebilir bir primitive haline gelir — tty-subsystem bug'ları
için standart UAF-to-LPE yolu.
Fix'in etkisi (commit 3c4f8333b582, "tty: n_gsm: Fix UAF in
gsm_cleanup_mux"), pseudo-diff biçiminde:
- struct gsm_dlci *dlci = gsm->dlci[0];
...
mutex_lock(&gsm->mutex);
+ dlci = gsm->dlci[0]; // read only after the lock is held
...
mutex_unlock(&gsm->mutex);
Pointer'ı lock altında okumak, eşzamanlı bir gsm_cleanup_mux()'un onu
okuma ile kullanım arasında free etmiş olamayacağı anlamına gelir.
Detection¶
- Reachability: tarihsel olarak gsm line discipline'ı unprivileged
kullanıcılar tarafından attach edilebiliyordu;
n_gsm'iCAP_NET_ADMINarkasına alan / module-blocklisting yapan dağıtımlar local attack surface'ini ortadan kaldırır. - Runtime: KASAN bunu doğrudan, eşzamanlı
GSMIOC_SETCONFsırasındagsm_cleanup_muxiçinde bir use-after-free read/write olarak işaretler. - Behavioural: bir tty açan,
N_GSM0710set eden ve birden çok thread'denGSMIOC_SETCONFveren unprivileged bir process, cellular-modem userland'ı dışında anormaldir.
Mitigation¶
- Commit
3c4f8333b582'yi içeren bir kernel'e patch'le (yetkili fix; aynı n_gsm race ailesi ayrıca CVE-2023-6546 altında da takip ediliyor). - GSM 0710 muxing'in kullanılmadığı yerlerde
n_gsmmodülünü blocklist'le. - Race'in unprivileged koddan ulaşılamaz olması için gsm line discipline'ı
attach etmeyi
CAP_NET_ADMIN'e bağla.