
تحليل وتخفيف ثغرة فشل النسخ في نواة لينكس (CVE-2026-31431) التي تستغل تحوير ذاكرة التخزين المؤقت للصفحات عبر AF_ALG/splice، مع أداة فحص PoC، وقواعد كشف auditd، والتحقق من تحديث النواة.
هذا المشروع عبارة عن مشروع مصغّر لتحليل مبدأ عمل ثغرة Copy Fail (CVE-2026-31431) في نواة Linux، ومقارنة الحالة قبل وبعد الترقيع باستخدام أداة الفحص غير المدمرة من مستودع PoC العام.
لم يتم تنفيذ أي استغلال فعلي لتعديل ثنائيات setuid أو تعديل /etc/passwd، بل تم التركيز على التحقق الآمن من وجود الثغرة باستخدام ملف testfile مؤقت، وتحليلها من منظور الاكتشاف والتخفيف.
الهدف من هذا المشروع ليس مجرد تشغيل استغلال (exploit)، بل فهم تركيبة البنى الداخلية التي تؤدي إلى ظهور ثغرة في نواة Linux، وتوثيق كيفية التحقق منها والاستجابة لها من المنظور التشغيلي.
نطاق العمل كما يلي:
تحليل مبدأ الثغرة
↓
تحليل بنية كود PoC
↓
ممارسة باستخدام أداة فحص غير مدمرة
↓
المقارنة قبل وبعد الترقيع
↓
توثيق خطط الاكتشاف/التخفيف
في هذه الممارسة العملية، تم تشغيل vulnerable.c فقط من مستودع copy-fail-c.
| البند | قبل الترقيع | بعد الترقيع |
|---|---|---|
| نظام التشغيل | Ubuntu 24.04.2 LTS | Ubuntu 24.04.4 LTS |
| النواة | 6.8.0-53-generic | 6.8.0-134-generic |
| الحساب | مستخدم عادي client | مستخدم عادي client |
| أداة الفحص | vulnerable | vulnerable |
| طريقة الاختبار | فحص غير مدمر باستخدام testfile مؤقت | إعادة تشغيل نفس أداة الفحص |
معلومات النواة قبل الترقيع:
Linux ubuntu-server 6.8.0-53-generic #55-Ubuntu SMP PREEMPT_DYNAMIC Fri Jan 17 15:37:52 UTC 2025 x86_64 x86_64 x86_64 GNU/Linux
معلومات النواة بعد الترقيع:
Linux ubuntu-server 6.8.0-134-generic #134-Ubuntu SMP PREEMPT_DYNAMIC Fri Jun 26 18:43:11 UTC 2026 x86_64 x86_64 x86_64 GNU/Linux
ملخص تغييرات حزمة النواة:
- linux-image-6.8.0-53-generic 6.8.0-53.55
- linux-image-generic 6.8.0-53.55+1
+ linux-image-6.8.0-134-generic 6.8.0-134.134
+ linux-image-generic 6.8.0-134.134
+ linux-generic 6.8.0-134.134
+ linux-headers-generic 6.8.0-134.134
ثغرة Copy Fail هي ثغرة تنشأ عند اجتماع مسار معالجة AEAD في AF_ALG بنواة Linux مع سلوك النسخ الصفري (zero-copy) في splice()، مما قد يسمح باستخدام page cache لملف قابل للقراءة فقط كوجهة كتابة خاطئة.
المكوّنات الأساسية كما يلي:
| المكوّن | الدور |
|---|---|
| Linux page cache | آلية نواة تخزّن محتوى ملفات القرص مؤقتًا في RAM |
splice() | استدعاء نظام بنسخ صفري يربط البيانات بمرجع داخل النواة دون نسخها إلى مساحة المستخدم |
AF_ALG | واجهة تتيح استخدام واجهة برمجة التشفير (crypto API) لنواة Linux من مساحة المستخدم مثل socket |
| معالجة AEAD في نفس المكان (in-place) | تحسين يعالج المخازن المؤقتة في نفس المخزن بدلًا من فصل مخزن الإدخال عن مخزن الإخراج |
authencesn | قالب تشفير (crypto template) يحدث كتابة مؤقتة (scratch write) بحجم 4 بايت أثناء معالجة AEAD |
التدفق الأساسي للثغرة كما يلي:
ملف قابل للقراءة
↓
يُحمَّل في Linux page cache
↓
تمرير مرجع page cache إلى مسار التشفير AF_ALG عبر splice()
↓
ترابط scatterlist للإدخال والإخراج عبر معالجة AEAD في نفس المكان (in-place)
↓
حدوث كتابة مؤقتة (scratch write) بحجم 4 بايت أثناء معالجة authencesn
↓
الكتابة تحدث في page cache وليس في مخزن إخراج منفصل
↓
حدوث طفرة page cache (mutation)
بمعنى أنه بينما ينقل splice() مرجع page cache، وتربط معالجة AEAD في نفس المكان بين الإدخال والإخراج عبر المسار نفسه، فإن authencesn هو ما يسبب الكتابة الفعلية بحجم 4 بايت.
بنية المستودع المستخدم في الممارسة كما يلي:
copy-fail-c/
├── exploit.c
├── exploit-passwd.c
├── vulnerable.c
├── payload.c
├── utils.c
├── utils.h
├── Makefile
└── nolibc/
| الملف | الدور | الاستخدام في هذه الممارسة |
|---|---|---|
utils.c, utils.h | تنفيذ primitive لطفرة page cache المعتمدة على AF_ALG/splice | استخدامها في التحليل وتشغيل vulnerable |
vulnerable.c | أداة فحص غير مدمرة للتحقق من الثغرة باستخدام testfile مؤقت | تم تشغيله |
exploit.c | متغيّر (variant) لتعديل page cache لثنائي setuid root | لم يتم تشغيله |
exploit-passwd.c | متغيّر لتعديل page cache لملف /etc/passwd | لم يتم تشغيله |
payload.c | الحمولة (payload) التي ستُنفَّذ بصلاحيات root | لم يتم تشغيله |
Makefile | أتمتة البناء | استخدام target vulnerable فقط |
nolibc/ | كود بديل خفيف عن libc لبناء حمولة ELF ثابتة صغيرة | للتحليل فقط |
utils.cيتمثل جوهر utils.c في primitive لطفرة page cache من عائلة patch_chunk(). تربط هذه الدالة page cache للملف المستهدف بمسار المعالجة المشفرة عبر AF_ALG وsplice()، وتبيّن ما إذا كان جزء من page cache يُستبدل أثناء معالجة AEAD في النواة غير المُرقّعة.
vulnerable.cلا يلمس vulnerable.c أي ملفات نظام فعلية. فهو ينشئ testfile مؤقتًا في الدليل الحالي ويتحقق مما إذا كانت page cache الخاصة بهذا الملف قد تعرّضت للتعديل.
في هذا المشروع، تم تشغيل هذا الملف فقط.
قبل تنفيذ تحديث النواة، تم تسجيل حالة نظام التشغيل والنواة والحزم.
mkdir -p ~/copyfail-mini/{before,after,logs}
cd ~/copyfail-mini
uname -a | tee before/uname.txt
cat /etc/os-release | tee before/os-release.txt
dpkg -l | grep -E 'linux-image|linux-headers|linux-generic|linux-virtual' | tee before/kernel-package.txt
git clone https://github.com/jihwan77/copy-fail-c.git
cd copy-fail-c
make clean
make vulnerable
في هذه الممارسة، لم يتم بناء ثنائيات الاستغلال عبر make الافتراضي، بل تم استخدام target vulnerable فقط.
./vulnerable > ../before/vulnerable-output.txt 2>&1
echo $? >> ../before/vulnerable-output.txt
cat ../before/vulnerable-output.txt
نتيجة التشغيل قبل الترقيع:

التقييم:
exit code 100
→ تم تأكيد طفرة page cache
→ تم تأكيد عمل primitive الخاصة بـ Copy Fail في النواة قبل الترقيع
بعد حفظ النتائج قبل الترقيع، تم تنفيذ تحديث حزم Ubuntu.
sudo apt update
sudo apt full-upgrade -y
sudo reboot
بعد إعادة التشغيل، تغيّرت النواة على النحو التالي:
Before: 6.8.0-53-generic
After : 6.8.0-134-generic
cd ~/copyfail-mini/copy-fail-c
make clean
make vulnerable
./vulnerable > ../after/vulnerable-output.txt 2>&1
echo "exit_code=$?" >> ../after/vulnerable-output.txt
cat ../after/vulnerable-output.txt
نتيجة التشغيل بعد الترقيع:

مقارنة النتائج:
| البند | قبل الترقيع | بعد الترقيع |
|---|---|---|
| النواة | 6.8.0-53-generic | 6.8.0-134-generic |
| نتيجة أداة الفحص | VULNERABLE | authencesn template not registered |
| رمز الخروج | 100 | 2 |
| طفرة page cache | تم تأكيدها | لم تصل أداة الفحص إلى مرحلة الطفرة |
| التفسير | عمل primitive الخاصة بـ Copy Fail | فشل الدخول إلى مسار AEAD/authencesn الذي يتطلبه PoC |
إن exit_code=2 بعد الترقيع لا يعني ببساطة «غير قابلة للاستغلال». التفسير الدقيق كما يلي:
نظرًا لعدم تسجيل template الخاص بـ authencesn(hmac(sha256),cbc(aes)) في AF_ALG،
لم تتمكن أداة الفحص من الحكم مباشرة على وجود الثغرة
وأظهر فحص إضافي أنه بعد تحديث Ubuntu، تم حظر تحميل وحدة algif_aead.
lsmod | grep -E 'af_alg|algif_aead'
النتيجة:
af_alg 32768 0
لم تكن وحدة algif_aead محمّلة.
sudo modprobe algif_aead
النتيجة:
modprobe: ERROR: ../libkmod/libkmod-module.c:1084 command_do() Error running install command '/bin/false' for module algif_aead: retcode 1
modprobe: ERROR: could not insert 'algif_aead': Invalid argument
التحقق من إعداد الحظر:
grep -R "algif_aead" /etc/modprobe.d /lib/modprobe.d 2>/dev/null
النتيجة: