
PinTheft (CVE-2026-43494) का एक Go कार्यान्वयन
Go port of pintheft - RDS zcopy double-free LPE. Dirty Frag भेद्यता वर्ग का सदस्य।
[!IMPORTANT] आर्क लिनक्स इस भेद्यता के लिए सबसे अधिक प्रभावित डिस्ट्रिब्यूशन में से एक है, क्योंकि यह उन कुछ डिस्ट्रिब्यूशन में है जहाँ RDS मॉड्यूल सामान्यतः डिफ़ॉल्ट रूप से लोड हो सकता है।
यह बग rds_message_zcopy_from_user() में है। यह फ़ंक्शन FOLL_GET के माध्यम से उपयोगकर्ता पेजों (user pages) को एक-एक करके GUP-पिन करता है। यदि बाद में कोई पेज फॉल्ट होता है (जैसे PROT_NONE गार्ड पेज), तो एरर पाथ पहले से पिन किए गए पेजों पर put_page() कॉल करता है, फिर rds_message_purge() उन पर दोबारा __free_page() कॉल करता है क्योंकि op_mmp_znotifier को NULL कर दिया गया था लेकिन op_nents/sg एंट्रीज़ बरकरार रहीं। जब पेज पर अन्य रेफरेंस मौजूद होते हैं, __free_page चुपचाप refcount घटा देता है। प्रत्येक विफल sendmsg पहले पेज से ठीक एक ref चुरा लेता है।
CONFIG_INIT_ON_ALLOC_DEFAULT_ON को बायपास करनालक्षित पेज को io_uring REGISTER_BUFFERS के माध्यम से पिन करें, जो FOLL_PIN के ज़रिए refcount में GUP_PIN_COUNTING_BIAS (1024) जोड़ता है। विफल zcopy sends से सभी 1024 पिन refs चुरा लें। अब पेज का refcount ~1 है (केवल PTE मैपिंग)। munmap सामान्य __folio_put पथ लेता है, जो फ्री करने से पहले mem_cgroup_uncharge (जो memcg_data को साफ करता है) कॉल करता है। कोई bad_page चेक फायर नहीं होता।
io_uring अपने bvec array में बिना किसी liveness जाँच के कच्चा struct page* रखता है। जब पेज को एक suid बाइनरी के लिए page cache के रूप में reclaim कर लिया जाता है, तो IORING_OP_READ_FIXED उस डैंगलिंग पॉइंटर के माध्यम से उसमें हमारा पेलोड लिखता है।
IORING_REGISTER_CLONE_BUFFERS imu->refs बढ़ाता है। एक forked डेमॉन चाइल्ड clone ring fd को खुला रखता है - io_buffer_unmap refs > 1 देखता है और unpin_user_folio को छोड़ देता है, जिससे फ्री किए गए पेज पर refcount भ्रष्टाचार रुक जाता है।
CPU 0 पर पिन करें, फ्री करने से पहले पुरानी PCP एंट्रीज़ को drain करें - जब page cache आवंटनकर्ता इसे पकड़ता है तो हमारा पेज सबसे ऊपर आता है।
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
सफल होने पर 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 के माध्यम से स्वतः लोड होता है)io_uring_disabled=0 के साथ CONFIG_IO_URING=yवैसे मुझे Arch Linux बहुत पसंद है :)