CVE-2023-33106: Qualcomm Adreno GPU KGSL_GPU_AUX_COMMAND_SYNC OOB (in-the-wild)¶
Devasa bir sync-point sayısıyla bir AUX command submit etmek, Adreno KGSL driver'ının tek bir
unsigned longbitmap'in (maksimum 32 sync point) sonunun ötesindeset_bit()yapmasına neden olur ve in-the-wild exploit edilmiş lineer bir out-of-bounds write üretir.
Mechanism¶
Sınırsız bir user count tarafından index'lenen 32-bit bir bitmap
Qualcomm'un Adreno GPU'su kernel KGSL driver'ı tarafından sürülür.
IOCTL_KGSL_GPU_AUX_COMMAND ioctl'i, user space'in auxiliary GPU işini
submit etmesine, opsiyonel olarak bir synchronization point listesi
eklemek için KGSL_GPU_AUX_COMMAND_SYNC flag'iyle izin verir. Sync point
sayısı user'ın verdiği param->numsyncs'ten alınır.
Dahili olarak bir sync object (struct kgsl_drawobj_sync), sync
point'lerinden hangilerinin hâlâ bekleyen olduğunu tek bir unsigned long
olan pending bitmap field'ı kullanarak izler. Driver
KGSL_MAX_SYNCPOINTS == 32 etrafında tasarlandı — yani o tek word'e sığan
en fazla 32 bit pending state. Eklenen her sync point bir index alır ve o
index, set_bit(event->id, &syncobj->pending)'te bit pozisyonu olarak
kullanılır.
Kodun sessizce varsaydığı invariant: event->id (numsyncs tarafından
sınırlanan sync-point index'inden türetilir) her zaman < 32. Ama
kgsl_ioctl_gpu_aux_command() iterate etmeden önce param->numsyncs'i
KGSL_MAX_SYNCPOINTS'e karşı doğrulamadı. Büyük bir numsyncs ile loop
(kgsl_drawobj_sync_add_synclist() → kgsl_drawobj_sync_add_sync() →
drawobj_add_sync_timeline(), syncobj->numsyncs'i artırarak) eninde
sonunda set_bit()'i >= 32 bir bit index'iyle çağırır.
Linux'ta set_bit(n, addr), addr'ı bir bitmap'in base'i olarak ele alır
ve bit n'i addr[n / BITS_PER_LONG]'a yazar. n, tek-word'lük pending
field'ının boyutunu aştığında, bit pending word'ünden sonraki
memory'ye yazılır — memory'de sync object'i takip eden ne varsa ona lineer
bir out-of-bounds write (CWE-787). ARM'de set_bit, hedef biti içeren
word üzerinde çalışır, yani attacker'ın seçtiği büyük bir index write'ı
bitmap'in ötesinde kontrol edilebilir bir mesafe yürütür. Komşu bir kernel
allocation'a giren o başıboş bit-set, corruption primitive'idir.
In-the-wild exploit edildi
Google Project Zero'nun root-cause analizine göre CVE-2023-33106, Google'ın Threat Analysis Group'undan Clément Lecigne tarafından raporlanmış, RCA'sı gerçek bir exploit sample'a karşı yapılmış, in-the-wild exploit edilmiş bir 0-day'di. İlgili Adreno ve Mali bug'larıyla birlikte 2023 sonu Android saldırı dalgasının parçasıydı ve Aralık 2023 Qualcomm/Android security update'inde düzeltildi. Aynı dönemden ilgili Adreno KGSL sorunları arasında CVE-2023-33107 var.
Walkthrough¶
Bug'a, bir KGSL fd tutan unprivileged bir process'ten, aşırı büyük bir sync list'le tek bir AUX command submit ederek ulaşılır.
OOB set_bit'in kavramsal tetiklenmesi
/* 1. Open the Adreno KGSL device (reachable by unprivileged apps). */
int fd = open("/dev/kgsl-3d0", O_RDWR);
/* 2. Build an AUX command that requests SYNC with far more than
* KGSL_MAX_SYNCPOINTS (32) sync points. */
struct kgsl_gpu_aux_command param = {
.flags = KGSL_GPU_AUX_COMMAND_SYNC,
.numsyncs = 0x4000, /* >> 32 : the missing bound check */
.synclist = (uintptr_t)synclist_with_many_entries,
/* ... timestamp, context id, etc ... */
};
/* 3. Submit. The handler iterates numsyncs, assigns each a bit index,
* and eventually does set_bit(id >= 32, &syncobj->pending),
* writing past the single unsigned long -> linear OOB write. */
ioctl(fd, IOCTL_KGSL_GPU_AUX_COMMAND, ¶m);
Call chain (public RCA'dan):
Patched bir driver'da beklenen davranış: kgsl_ioctl_gpu_aux_command()
isteği baştan reddeder. Fix bound check'i ekler:
if ((param->flags & KGSL_GPU_AUX_COMMAND_SYNC) &&
(param->numsyncs > KGSL_MAX_SYNCPOINTS))
return -EINVAL;
böylece numsyncs > 32 olan her istek -EINVAL döner ve set_bit'e asla
ulaşmaz.
Detection¶
- Patch level.
numsyncs <= KGSL_MAX_SYNCPOINTScheck'ini içeren 2023-12-01 (veya sonrası) Android/Qualcomm security patch level'ını doğrula. - Behavioral.
numsyncs > 32ileKGSL_GPU_AUX_COMMAND_SYNCflag'i taşıyan birIOCTL_KGSL_GPU_AUX_COMMANDçağrısı, patch'lenmemiş bir cihazda doğrudan bir exploitation girişimidir; patch'lenmiş bir cihazda basitçe-EINVALdöner.
Mitigation¶
- Aralık 2023 Qualcomm/Android security update'ini uygula.
- Root-cause fix, sync list işlenmeden önce
param->numsyncs'inKGSL_MAX_SYNCPOINTS'e karşı açık upper-bound doğrulamasıdır. - Hardening prensibi: sonunda fixed-size bir kernel structure'ına bit index'i veya array index'i olan herhangi bir user-supplied count, derinlerdeki bir helper'da değil ioctl boundary'sinde range-check edilmeli.