
तीन प्रकाशित f_hid फिक्सों के बैकपोर्ट (CVE-2026-31721, CVE-2026-31606 सहित) एक EOL Linux 4.14.190 Android वेंडर कर्नेल के लिए, डिवाइस-पर सत्यापन रिकॉर्ड के साथ।
drivers/usb/gadget/function/f_hid.c में तीन सुधार, जिन्हें हाथ से 4.14.190 Android वेंडर
कर्नेल में ले जाया गया और जिस डिवाइस पर ये चलते हैं उसी पर सत्यापित किया गया।
4.14 अब जीवन-चक्र के अंत (end-of-life) पर है। इनमें से किसी के लिए भी कोई स्थिर बैकपोर्ट मौजूद नहीं है, और न ही आने वाला है। यही इस रिपॉज़िटरी के होने का पूरा कारण है: डिवाइस मेरा है, और इनमें से एक दोष उसे रीसेट कर रहा था।
यह स्पष्ट करना कि कौन क्या बनाए रखता है: जिस NetHunter ट्री से यह बनाया गया है
(AzeAstro/samsung_kernel_sm7125, ब्रांच
OneUI-6) वह सक्रिय रूप से बनाए रखा जा रहा है, और उस काम पर यहाँ कोई प्रश्न नहीं है। लेकिन वह डिवाइस और
NetHunter सक्षमता है — आधार Samsung के 4.14.190 वेंडर ड्रॉप पर पिन रहता है। कोई भी
4.14.y स्थिर सुरक्षा सुधारों को उसमें नीचे नहीं ले जा रहा है, और Samsung भी उन्हें नहीं भेज रहा है — 4.14.y स्वयं
10 जनवरी 2024 को 4.14.336 पर समाप्त हो गया, और यह श्रृंखला अब kernel.org की
समर्थित रिलीज़ों में सूचीबद्ध नहीं है। यही अंतराल है जिसमें ये तीन पैच स्थित हैं।
मैंने इन कमज़ोरियों की खोज नहीं की। तीनों प्रकाशित हैं, अन्य लोगों द्वारा लिखे गए अपस्ट्रीम पैच के साथ, नीचे श्रेय दिया गया है। मैंने जो किया:
बिंदु 3 वह हिस्सा है जिस पर मैं पाठक से विचार करने का अनुरोध करूँगा। इनमें से दो को आधार-रेखा के विरुद्ध मापन द्वारा पुष्टि की गई है। तीसरे की नहीं, और इस डिवाइस पर नहीं की जा सकती। इस अंतर को पूरे दस्तावेज़ में बनाए रखा गया है बजाय इसे छुपाने के।
| # | पैच | अपस्ट्रीम लेखक | हार्डवेयर पर स्थिति |
|---|---|---|---|
| 1 | f_hidg जीवनकाल बनाम cdev (use-after-free) | John Keeping, 2022-11-22 | ✅ प्रभावशीलता मापी गई |
| 2 | CVE-2026-31721 — hidg_bind में ऑब्जेक्ट-जीवनकाल स्थिति पुनः आरंभ | Michael Zimmermann, 2026-03-31 | ✅ प्रभावशीलता मापी गई |
| 3 | CVE-2026-31606 — उपयोग में लाए जा रहे cdev पर cdev_init | Michael Zimmermann (81ebd43cc0d6d), 2026-03-27; -ENOMEM फ़ॉलो-अप Ethan Tidmore द्वारा, 2026-04-02 | ⛔ इस डिवाइस पर अवलोकनीय नहीं |
f_hidg जीवनकाल बनाम cdevf_hidg_open ने f_hidg * संग्रहीत किया और कोई संदर्भ नहीं लिया। f_hidg_poll ने
kzalloc'd f_hidg में अंतर्निहित वेट क्यू पर पोल वेटर पंजीकृत किए। hidg_unbind ने cdev_del() कॉल किया, जो
खुले fds को अमान्य नहीं करता, और hidg_free ने फिर ऑब्जेक्ट को kfree कर दिया। किसी भी चीज़ ने इसे खुली
फ़ाइलों के विरुद्ध refcount नहीं किया — refcount|kref|atomic_|open_count के लिए पूरी फ़ाइल में grep करने पर केवल opts->lock मिला।
तो /dev/hidg0 पर एक select()/poll() लूप जो Android द्वारा गैजेट को पुनः-संयोजित करने के बाद भी बचा रहता, वह
मुक्त slab पर remove_wait_queue() कॉल करता, कचरा टिकट शब्द पर spin_lock_irqsave लेता, और
IRQs मास्क करके हमेशा के लिए स्पिन करता। स्थानीय टाइमर रुक जाता है, वॉचडॉग पेट थ्रेड कभी जागृत नहीं होता, और
~11 सेकंड बाद नॉन-सिक्योर वॉचडॉग भौंकता है। व्यवहार में: हैंडसेट हार्ड-रीसेट हो जाता है। Android का
UsbDeviceManager अपने आप पुनः-संयोजित करता है — दो बार ~550 ms पर मापा गया — बिना किसी उपयोगकर्ता क्रिया के, इसलिए इसके लिए
किसी विचित्र ट्रिगर की आवश्यकता नहीं थी।
अपस्ट्रीम सुधार: "usb: gadget: f_hid: fix f_hidg lifetime vs cdev", John Keeping, 2022-11-22,
Fixes: 71adf1189469। बैकपोर्ट साफ़ है — हर प्रिमिटिव 4.14.190 पर मौजूद है — सिवाय
पैच के kfree(hidg->set_report_buf) के, जो एक ऐसा फ़ील्ड है जो इस संस्करण में नहीं है, जिसे हटा दिया गया है।
CVSS 3.1 5.5, वेक्टर AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H। hidg_bind ने ऑब्जेक्ट के जीवनकाल से संबंधित स्थिति को
पुनः आरंभ किया, न कि बाइंड की: दो स्पिनलॉक, दो वेट क्यू हेड, और एक लिस्ट
हेड, जिनमें से कोई भी hidg_alloc में नहीं दिखता। init_waitqueue_head लिस्ट हेड को
स्व-इंगित करने के लिए रीसेट करता है, इसलिए रीबाइंड से पहले पंजीकृत एक पोल/select वेटर चुपचाप अनाथ हो जाता है, और उसका
poll_freewait → remove_wait_queue फिर prev->next को गलत पाता है।
Upstream hidg_bind से नौ initialisations को बाहर निकालता है; उनमें से केवल पाँच 4.14.190 पर मौजूद हैं।
⚠ कई vendor advisories इसे "privilege escalation" शीर्षक देते हैं। वेक्टर C:N/I:N/A:H है —
केवल availability, अर्थात् एक local denial of service। मैं इसे इसलिए चिह्नित कर रहा हूँ क्योंकि अधिक भयावह पाठ्यांक
उस प्राथमिकता को उचित ठहराता जिसे वेक्टर समर्थन नहीं देता, और कोई भी vendor पृष्ठ से स्वयं को सिद्ध करने को नहीं कहता।
यह patch upstream से एक कदम आगे भी जाता है। initialisations को hidg_bind से बाहर निकालने पर lock-संरक्षित
फ़ील्ड्स के लिए दो unlocked stores बच जाते हैं, जो आज केवल इसलिए masked हैं क्योंकि lock को उनके ठीक ऊपर
पुनः-आरंभ किया जा रहा था। एक बार lock स्थायी हो जाने पर race वास्तविक है: f_hidg_write के wait loop में
अवरुद्ध एक writer, जो unbind से बचे एक fd पर है, lock ले सकता है, जाँच पास कर सकता है
और hidg->req पढ़ सकता है जबकि bind उसके बाहर NULL संग्रहीत करता है — पुनः-जाँच dereference के बाद आती है।
इसलिए patch दोनों stores के चारों ओर write_spinlock लेता है।
सामान्य रूप कहने योग्य है: किसी initialisation को bind से बाहर निकालना एक ऐसी race उत्पन्न कर सकता है जिसे पुनः-आरंभ छिपा रहा था। पूछें कि हटाया गया init संयोगवश किस चीज़ की रक्षा कर रहा था।
CVSS 5.5, वही वेक्टर। struct cdev cdev struct f_hidg में embedded है, और hidg_bind ने उस पर
cdev_init() कॉल किया — जो memset(cdev, 0, sizeof *cdev) के साथ-साथ kobject_init है — ठीक
cdev_device_add से पहले। एक खुला fd chrdev_open →
cdev_get → kobject_get_unless_zero के माध्यम से उसी kobject पर एक reference रखता है। fd खुला रहने के दौरान unbind→rebind पर, bind एक referenced object पर
live reference state को मिटा देता है।
समाधान एक guard के बजाय struct परिवर्तन है: embedded struct cdev एक struct cdev * बन जाता है
जिसमें प्रति-bind cdev_alloc() होता है। तब फ़ाइल में cdev_init शून्य बार प्रकट होता है — पुनः-आरंभ करने के लिए
कोई in-use object शेष नहीं बचता।
⛔ यह device इस दोष का पता नहीं लगा सकता, fix से पहले या बाद में। देखें
verification/03-cve-2026-31606.md। यह device की instrumentation के बारे में एक सकारात्मक दावा है, कोई
बचाव-वाक्य नहीं।
विधि और प्रति-दोष रिकॉर्ड verification/ में। संक्षिप्त संस्करण: fix 1 और 2
तत्काल पूर्व build के विरुद्ध single-variable regression द्वारा, positive
controls के साथ बंद किए गए, और fix 2 की पुष्टि एक भिन्न log source से दूसरी बार की गई। Fix 3 का प्रमाण
केवल source पढ़ने से है।
Patches 4.14.190 Samsung vendor tree के विरुद्ध git format-patch आउटपुट हैं, क्रम में:
git am patches/0001-*.patch patches/0002-*.patch patches/0003-*.patch
ये संचयी हैं और क्रम में लागू होने की अपेक्षा करते हैं — 3 मानता है कि struct वैसा ही है जैसा 1 ने छोड़ा था।
GPL-2.0, Linux kernel के व्युत्पन्न कार्यों के रूप में। देखें LICENSE। मूल fixes का upstream authorship ऊपर श्रेय दिया गया है; backporting, patch 2 में जोड़ी गई locking, और सत्यापन कार्य मेरे हैं।
यहाँ कोई संकलित artifact वितरित नहीं किया जाता — न कोई kernel image, न modules, न flashable package। यह repository केवल source और evidence है।