
तीन प्रकाशित 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) है। इनमें से किसी के लिए कोई स्थिर बैकपोर्ट मौजूद नहीं है, और आने वाला भी नहीं है। इस रिपॉजिटरी के अस्तित्व में होने का यही पूरा कारण है: डिवाइस मेरा है, यह एक ऐसा कर्नेल चलाता है जिसे कोई मेंटेन नहीं करता, और इनमें से एक दोष इसे रीसेट कर रहा था।
मैंने इन कमजोरियों की खोज नहीं की। ये तीनों प्रकाशित हैं, जिनके अपस्ट्रीम पैच अन्य लोगों द्वारा लिखे गए हैं, जिन्हें नीचे श्रेय दिया गया है। मैंने जो किया:
बिंदु 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; Ethan Tidmore द्वारा -ENOMEM अनुवर्ती, 2026-04-02 | ⛔ इस डिवाइस पर अवलोकन योग्य नहीं |
f_hidg जीवनकाल बनाम cdevf_hidg_open ने f_hidg * संग्रहीत किया और कोई संदर्भ (reference) नहीं लिया। f_hidg_poll ने kzalloc किए गए f_hidg में एम्बेडेड वेट क्यू पर पोल वेटर पंजीकृत किए। hidg_unbind ने cdev_del() कहा, जो खुले fds को अमान्य नहीं करता, और hidg_free ने फिर ऑब्जेक्ट को kfree कर दिया। किसी भी चीज़ ने इसे खुली फाइलों के विरुद्ध refcount नहीं किया — पूरी-फाइल grep refcount|kref|atomic_|open_count के लिए केवल opts->lock पाया।
इसलिए /dev/hidg0 पर एक select()/poll() लूप जो Android द्वारा गैजेट को पुनः-संयोजित करने पर बच गया, मुक्त स्लैब पर 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 लिस्ट हेड को स्व-संकेतक पर रीसेट करता है, इसलिए रीबाइंड से पहले पंजीकृत एक poll/select वेटर चुपचाप अनाथ हो जाता है, और उसका poll_freewait → remove_wait_queue फिर prev->next गलत पाता है।
अपस्ट्रीम नौ आरंभीकरणों को hidg_bind से बाहर ले जाता है; उनमें से केवल पाँच 4.14.190 पर मौजूद हैं।
⚠ कई वेंडर सलाहकार इसे "विशेषाधिकार वृद्धि" कहते हैं। वेक्टर C:N/I:N/A:H है — केवल उपलब्धता, यानी एक स्थानीय सेवा अस्वीकृति। मैं इसे इसलिए उजागर करता हूँ क्योंकि डरावना पठन एक ऐसी प्राथमिकता को उचित ठहराता जो वेक्टर समर्थन नहीं करता, और कोई भी वेंडर पेज से स्वयं को सिद्ध करने को नहीं कहता।
यह पैच अपस्ट्रीम से एक कदम आगे भी जाता है। आरंभीकरणों को hidg_bind से बाहर ले जाने से लॉक-संरक्षित फ़ील्ड्स पर दो अनलॉक्ड स्टोर रह जाते हैं, जो आज केवल इसलिए मास्क हैं क्योंकि लॉक उनके ठीक ऊपर पुनः-आरंभित किया जा रहा था। एक बार लॉक स्थायी हो जाने पर दौड़ वास्तविक है: एक लेखक जो f_hidg_write के वेट लूप में अवरुद्ध है, एक fd पर जो अनबाइंड से बच गया, लॉक ले सकता है, जाँच पास कर सकता है और hidg->req पढ़ सकता है जबकि बाइंड उसके बाहर NULL संग्रहीत करता है — पुनः-जाँच डीरेफरेंस के बाद आती है। इसलिए पैच दोनों स्टोर के चारों ओर write_spinlock लेता है।
सामान्य रूप कहने योग्य है: बाइंड से आरंभीकरण को बाहर ले जाना एक ऐसी दौड़ पैदा कर सकता है जिसे पुनः-आरंभीकरण छिपा रहा था। पूछें कि हटाया गया आरंभीकरण गलती से किसकी रक्षा कर रहा था।
CVSS 5.5, समान वेक्टर। struct cdev cdev struct f_hidg में एम्बेडेड है, और hidg_bind ने उस पर cdev_init() कहा — जो memset(cdev, 0, sizeof *cdev) प्लस kobject_init है — तुरंत cdev_device_add से पहले। एक खुला fd उसी kobject पर chrdev_open → cdev_get → kobject_get_unless_zero के माध्यम से संदर्भ रखता है। खुले fd के साथ unbind→rebind पर, बाइंड एक संदर्भित ऑब्जेक्ट पर जीवित संदर्भ स्थिति को मिटा देता है।
सुधार एक गार्ड के बजाय एक struct परिवर्तन है: एम्बेडेड struct cdev एक struct cdev * बन जाता है जिसमें प्रति-बाइंड cdev_alloc() होता है। cdev_init फिर फाइल में शून्य बार दिखाई देता है — पुनः-आरंभित करने के लिए कोई उपयोग में ऑब्जेक्ट नहीं बचा है।
⛔ यह डिवाइस इस दोष का पता नहीं लगा सकता, सुधार से पहले या बाद में। देखें verification/03-cve-2026-31606.md। यह डिवाइस के इंस्ट्रूमेंटेशन के बारे में एक सकारात्मक दावा है, कोई बचाव नहीं।
विधि और प्रति-दोष रिकॉर्ड verification/ में। संक्षिप्त संस्करण: सुधार 1 और 2 को तुरंत पिछले बिल्ड के विरुद्ध एकल-चर प्रतिगमन द्वारा बंद किया गया, सकारात्मक नियंत्रणों के साथ, और सुधार 2 की पुष्टि एक अलग लॉग स्रोत से दूसरी बार की गई। सुधार 3 केवल स्रोत पठन द्वारा प्रमाणित है।
पैच git format-patch आउटपुट हैं जो 4.14.190 Samsung वेंडर ट्री के विरुद्ध हैं, क्रम में:
git am patches/0001-*.patch patches/0002-*.patch patches/0003-*.patch
वे संचयी हैं और क्रम में लागू होने की अपेक्षा करते हैं — 3 उस struct को मानता है जैसा 1 ने छोड़ा था।
GPL-2.0, Linux कर्नेल के व्युत्पन्न कार्यों के रूप में। देखें LICENSE। मूल सुधारों का अपस्ट्रीम लेखकत्व ऊपर श्रेय दिया गया है; बैकपोर्टिंग, पैच 2 में जोड़ा गया लॉकिंग, और सत्यापन कार्य मेरा है।
यहाँ कोई संकलित आर्टिफैक्ट वितरित नहीं किया गया है — कोई कर्नेल इमेज नहीं, कोई मॉड्यूल नहीं, कोई फ्लैश करने योग्य पैकेज नहीं। यह रिपॉजिटरी केवल स्रोत और साक्ष्य है।