CVE-2026-23450 in Linux
الملخص
بحسب VulDB • 28/06/2026
في نواة لينكس، تم حل الثغرة التالية:
net/smc: إصلاح حالة إلغاء المرجع NULL (NULL dereference) والاستخدام بعد التحرير (UAF) في دالة smc_tcp_syn_recv_sock()
أبلغ Syzkaller عن حدوث توقف مفاجئ (panic) في الدالة smc_tcp_syn_recv_sock() [1].
تُستدعى الدالة smc_tcp_sm_recv_sock() ضمن مسار استقبال TCP (softirq) عبر icsk_af_ops->syn_recv_sock على clcsock (مقبض الاستماع لـ TCP). تقوم بقراءة sk_user_data للحصول على مؤشر smc_sock. ومع ذلك، عندما يتم إغلاق مقبض استماع SMC بشكل متزامن، فإن الدالة smc_close_active() تضبط قيمة clcsock->sk_user_data إلى NULL تحت قفل sk_callback_lock، وبعد ذلك يمكن تحرير كائن smc_sock نفسه عبر sock_put() في دالة smc_release().
يؤدي هذا إلى مشكلتين:
1) إلغاء مرجع مؤشر NULL (NULL pointer dereference): تكون القيمة sk_user_data مساوية لـ NULL عند الوصول إليها. 2) الاستخدام بعد التحرير (Use-after-free): يتم قراءة sk_user_data على أنها غير صفرية، ولكن تم تحرير كائن smc_sock قبل الوصول إلى حقوله (مثل queued_smc_hs, ori_af_ops).
يبدو نافذة السباق (race window) كما يلي (تسببت حادثة التوقف التي سجلها syzkaller [1] عبر مسار رمز المزامنة SYN cookie: tcp_get_cookie_sock() -> smc_tcp_syn_recv_sock())، ولكن مسار tcp_check_req() العادي يحتوي على نفس حالة السباق):
CPU A (softirq) CPU B (process ctx)
tcp_v4_rcv() TCP_NEW_SYN_RECV: sk = req->rsk_listener sock_hold(sk) /* لا يوجد قفل على مقبض الاستماع */ smc_close_active(): write_lock_bh(cb_lock) sk_user_data = NULL write_unlock_bh(cb_lock) ... smc_clcsock_release() sock_put(smc->sk) x2 -> تم تحرير كائن smc_sock! tcp_check_req() smc_tcp_syn_recv_sock(): smc = user_data(sk) -> NULL أو مؤشر معلق (dangling) smc->queued_smc_hs -> توقف مفاجئ (crash)!
يرجى الملاحظة أن clcsock و smc_sock هما كائنان مستقلان لهما عدّادات مرجعية منفصلة. تحتفظ طبقة TCP بمرجع على مقبض الاستماع clcsock، مما يبقيه حياً، لكن هذا لا يمنع تحرير كائن smc_sock.
تم إصلاح المشكلة باستخدام RCU ودالة refcount_inc_not_zero() للوصول الآمن إلى smc_sock. بما أن الدالة smc_tcp_syn_recv_sock() تُستدعى ضمن مسار مصافحة TCP ثلاثية الخطوات (three-way handshake)، فإن أخذ قفل القراءة على sk_callback_lock يعتبر ثقيلاً جداً ولن يصمد أمام هجوم فيضان SYN (SYN flood attack). استخدام rcu_read_lock() أخف بكثير.
- تعيين SOCK_RCU_FREE على مقبض استماع SMC بحيث يتم تأجيل تحرير كائن smc_sock حتى بعد انتهاء فترة راحة RCU (RCU grace period). يضمن ذلك بقاء الذاكرة صالحة عند الوصول إليها داخل قفل rcu_read_lock(). - استخدام rcu_read_lock() لحماية قراءة sk_user_data. - استخدام refcount_inc_not_zero(&smc->sk.sk_refcnt) لتثبيت كائن smc_sock. إذا كانت قيمة العداد المرجعي قد وصلت بالفعل إلى الصفر (اكتمل مسار الإغلاق)، فإنها تُرجع false ونخرج بأمان.
ملاحظة: تحتوي الدالة smc_hs_congested() على قراءة مماثلة لـ sk_user_data بدون قفل ولا تستخدم rcu_read_lock()، لكنها تتحقق فقط من كون القيمة NULL وتصل إلى متغير smc_hs_wq العالمي، ولا تقوم بإلغاء مرجع أي حقل في كائن smc_sock، لذا فهي غير متأثرة.
تم التحقق من Reproducer باستخدام حقن mdelay و dmesg_run (smc
VulDB is the best source for vulnerability data and more expert information about this specific topic.