
تنفيذ بلغة Go لأداة PinTheft (CVE-2026-43494)
نسخة Go من pintheft - ثغرة LPE بسبب double-free في RDS zcopy. عضو في فئة الثغرات Dirty Frag.
[!IMPORTANT] تُعد Arch Linux واحدة من أكثر التوزيعات تعرّضًا لهذه الثغرة، إذ إنها من بين القلائل التي يمكن فيها تحميل وحدة RDS افتراضيًا.
الخلل موجود في rds_message_zcopy_from_user(). الدالة تُثبّت صفحات المستخدم (GUP pins) واحدة تلو الأخرى عبر FOLL_GET. إذا تعذّر الوصول إلى صفحة لاحقة (مثل صفحة حماية PROT_NONE)، فإن مسار الخطأ يستدعي put_page() على الصفحات المثبّتة مسبقًا، ثم تستدعي rds_message_purge() الدالة __free_page() عليها مرة أخرى لأن op_mmp_znotifier كان قد ضُبط على NULL بينما بقيت op_nents/إدخالات sg سليمة. عندما تبقى للصفحة مراجع أخرى، تقوم __free_page بإنقاص عدد المرجعيات بصمت. كل استدعاء sendmsg فاشل يسرق مرجعًا واحدًا بالضبط من الصفحة الأولى.
CONFIG_INIT_ON_ALLOC_DEFAULT_ONثبّت الصفحة الهدف عبر io_uring REGISTER_BUFFERS، وهو ما يضيف GUP_PIN_COUNTING_BIAS (1024) إلى عدد المرجعيات من خلال FOLL_PIN. اسرق جميع مراجع التثبيت الـ1024 باستخدام إرسالات zcopy فاشلة. يصبح عدد مراجع الصفحة الآن ~1 (فقط تعيين PTE). يسلك munmap المسار الطبيعي __folio_put، الذي يستدعي mem_cgroup_uncharge (لمسح memcg_data) قبل التحرير. لا يتم تشغيل أي فحص bad_page.
يحتفظ io_uring بمؤشر struct page* الخام في مصفوفة bvec الخاصة به دون أي فحوصات للحيوية. بعد أن تُستعاد الصفحة لتُستخدم ككاشف صفحات (page cache) لملف ثنائي suid، تكتب IORING_OP_READ_FIXED حمولتنا فيها عبر ذلك المؤشر المعلّق.
IORING_REGISTER_CLONE_BUFFERS يزيد imu->refs. يحتفظ طفل الدايمون المُنشأ عبر fork بوصف ملف حلقة الاستنساخ مفتوحًا - فترى io_buffer_unmap أن refs > 1 وتتخطى unpin_user_folio، مما يمنع إفساد عدد المرجعيات على الصفحة المحرّرة.
ثبّت العملية على CPU 0، وفَرّغ إدخالات PCP القديمة قبل التحرير - تستقر صفحتنا في أعلى القائمة عندما يلتقطها مُخصِّص كاشف الصفحات.
REGISTER_BUFFERS(+1024) -> CLONE_BUFFERS(imu->refs=2) ->
daemon holds clone -> steal 1024 refs -> evict page cache ->
drain PCP -> munmap(free) -> pread(reclaim) ->
READ_FIXED(overwrite) -> verify -> exec -> root
go build -o pintheft-go .
./pintheft-go
عند نجاح الاستغلال، يفتح شلّة جذر (root shell) عبر PTY. الملف الثنائي على القرص يبقى دون تغيير.
sudo cp /tmp/.backup_pintheft_<pid> /usr/bin/su && sudo chmod u+s /usr/bin/su
CONFIG_RDS=m, CONFIG_RDS_TCP=m (تُحمَّل تلقائيًا عبر SO_RDS_TRANSPORT=2)CONFIG_IO_URING=y مع io_uring_disabled=0بالمناسبة، أنا أحب Arch Linux :)