2009-10-15 7 views
12

मेरे पास सी ++ में लिखा गया एक प्रोग्राम है जो गतिशील पुस्तकालय (लिनक्स, i386, .so) लोड करने के लिए डलोपेन का उपयोग करता है। जब लाइब्रेरी फ़ाइल को बाद में संशोधित किया जाता है, तो मेरा प्रोग्राम क्रैश हो जाता है। यह समझ में आता है, क्योंकि संभवतः फ़ाइल को स्मृति में मैप किया गया है।डलोपेन का उपयोग करके, मैं लोड की गई लाइब्रेरी फ़ाइल में परिवर्तनों का सामना कैसे कर सकता हूं?

मेरा प्रश्न है: बस मुझे फ़ाइल की प्रतिलिपि बनाने और dlopening बनाने के अलावा, मेरे लिए एक साझा ऑब्जेक्ट लोड करने का कोई तरीका है जो बाद में संशोधनों के विरुद्ध सुरक्षित है, या किसी भी ऑब्जेक्ट को संशोधित ऑब्जेक्ट में पुनर्प्राप्त करने के लिए कि मैंने लोड किया है?

स्पष्टीकरण: सवाल यह है कि नहीं "कैसे मैं इस कार्यक्रम दुर्घटनाग्रस्त बिना एक नए पुस्तकालय स्थापित कर सकते हैं", यह "है अगर किसी को मैं कौन नियंत्रण नहीं भर के पुस्तकालयों को कॉपी है, यह संभव है मेरे खिलाफ की रक्षा करने के लिए है उस?"

उत्तर

17

यदि आप rm नया स्थापित करने से पहले लाइब्रेरी है, तो मुझे लगता है कि आपका सिस्टम इनोड आवंटित, फ़ाइल खोलने और आपके प्रोग्राम को चालू रखेगा। (और जब आपका प्रोग्राम अंततः निकलता है, तो अधिकतर छिपे हुए-लेकिन-अभी भी वहां फ़ाइल संसाधन जारी किए जाते हैं।)

अद्यतन: ठीक है, स्पष्टीकरण के बाद। गतिशील लिंकर वास्तव में पर MAP_COPY ध्वज को पार करके इस समस्या को "हल" करता है। हालांकि, MAP_COPY लिनक्स पर मौजूद नहीं है और यह योजनाबद्ध भविष्य की सुविधा नहीं है। दूसरा सबसे अच्छा MAP_DENYWRITE है, जो मुझे लगता है कि लोडर उपयोग करता है, और जो कि लिनक्स एपीआई में है, और जो लिनक्स करता था। यह एक क्षेत्र मैप किए जाने पर त्रुटियों को लिखता है। यह अभी भी एक आरएम और प्रतिस्थापित करने की अनुमति देनी चाहिए। यहां समस्या यह है कि फ़ाइल में पढ़ने के लिए कोई भी व्यक्ति इसे मैप कर सकता है और लिख सकता है, जो एक स्थानीय डीओएस छेद खोलता है। (/etc/utmp पर विचार करें। इसे ठीक करने के लिए निष्पादन अनुमति बिट का उपयोग करने का एक प्रस्ताव है।)

आप इसे पसंद नहीं करेंगे, लेकिन एक छोटा कर्नेल पैच है जो MAP_DENYWRITE कार्यक्षमता को पुनर्स्थापित करेगा। लिनक्स में अभी भी सुविधा है, यह mmap(2) के मामले में थोड़ा सा साफ़ करता है। आपको इसे कोड में पैच करना होगा जो प्रति-आर्किटेक्चर को डुप्लिकेट किया गया है, IIA32 के लिए मेरा मानना ​​है कि फ़ाइल arch/x86/ia32/sys_ia32.c है।

asmlinkage long sys32_mmap2(unsigned long addr, unsigned long len, 
          unsigned long prot, unsigned long flags, 
          unsigned long fd, unsigned long pgoff) 
{ 
     struct mm_struct *mm = current->mm; 
     unsigned long error; 
     struct file *file = NULL; 

     flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); // fix this line to not clear MAP_DENYWRITE 

यह तब तक ठीक होना चाहिए जब तक आपके पास प्रमाण-पत्र वाले स्थानीय उपयोगकर्ता नहीं हैं। यह रिमोट डीओएस नहीं है, सिर्फ एक स्थानीय है।

+0

यह सही है। –

6

यदि आप लाइब्रेरी का एक नया संस्करण स्थापित करते हैं, तो सही प्रक्रिया एक ही निर्देशिका में एक नई फ़ाइल बनाने के लिए है, फिर इसे पुराने नाम पर पुनर्नामित करें। पुरानी फ़ाइल तब तक रहेगी जब यह खुली है, और इसका उपयोग जारी रहेगा।

आरपीएम जैसे पैकेज प्रबंधक स्वचालित रूप से ऐसा करते हैं - ताकि आप साझा होने के दौरान साझा लाइब्रेरीज़ और निष्पादन योग्य अपडेट कर सकें - लेकिन पुराने संस्करण चलते रहते हैं।

ऐसे मामले में जहां आपको एक नया संस्करण लेने की आवश्यकता है, प्रक्रिया को पुनरारंभ करें या लाइब्रेरी को पुनः लोड करें - प्रक्रिया को पुनरारंभ करना बेहतर लगता है - आपका प्रोग्राम स्वयं निष्पादित हो सकता है। यहां तक ​​कि इनिट भी ऐसा कर सकता है।

1

यदि आप यह पता लगा सकते हैं कि आपकी लाइब्रेरी मेमोरी में मैप की गई है, तो आप mprotect लिख सकते हैं और यह प्रत्येक पृष्ठ पर एक छोटा सा लिख ​​सकता है (उदाहरण के लिए प्रत्येक पृष्ठ के पहले बाइट को पढ़ें और लिखें)। आपको हर पृष्ठ की एक निजी प्रति प्राप्त करनी चाहिए।

यदि 'mprotect' काम नहीं करता है (हो सकता है कि मूल फ़ाइल शायद केवल पढ़ने के लिए खोला गया हो), तो आप इस क्षेत्र को किसी अन्य स्थान पर कॉपी कर सकते हैं, क्षेत्र को रीमेप कर सकते हैं (mmap का उपयोग करके) एक निजी, लिखने योग्य क्षेत्र, फिर क्षेत्र को वापस कॉपी करें।

काश ओएस था एक "एक प्रति-ऑन-राइट क्षेत्र को यह केवल पढ़ने के लिए क्षेत्र को बदलने"। मुझे नहीं लगता कि ऐसा कुछ मौजूद है, यद्यपि।

इन किसी भी स्थिति में, वहां अभी भी असुरक्षा की एक खिड़की है - जबकि dlopen initializers बुला रहा है कोई पुस्तकालय को संशोधित करने या करने से पहले अपने remap कॉल होता कर सकते हैं। आप वास्तव में सुरक्षित नहीं हैं जब तक आप डायनामिक लिंकर को ठीक नहीं कर सकते जैसे @DigitalRoss वर्णन करता है।

कौन वैसे भी आप के नीचे से, अपने पुस्तकालयों बाहर संपादित कर रहा है? उस व्यक्ति को ढूंढें और उसे फ्राइंग पैन के साथ सिर पर मारा।

+1

सुझावों के लिए धन्यवाद - दुर्भाग्य से अगर मैं अक्सर लोगों को फ्राइंग करता हूं तो मुझे बहुत परेशानी होती है :-) – kdt

0

यह एक पेचीदा सवाल है। मुझे लिनक्स में इस तरह के छेद खोजने से नफरत है, और उन्हें ठीक करने के तरीकों को ढूंढना पसंद है।

मेरे सुझाव this question about temporary files on Linux को @Paul Tomblin जवाब से प्रेरित है। यहां कुछ अन्य उत्तरों ने इस तंत्र के अस्तित्व का सुझाव दिया है, लेकिन आपने अनुरोध किए अनुसार क्लाइंट एप्लिकेशन से इसका शोषण करने की विधि का वर्णन नहीं किया है।

मैं इस परीक्षण नहीं किया है, इसलिए मैं पता नहीं कैसे यह अच्छी तरह से काम करेगा। साथ ही, जब अस्थायी फ़ाइल बनाई जाती है और जब यह अनलिंक हो जाती है, तो उस समय की संक्षिप्त अवधि से संबंधित दौड़ की स्थिति से जुड़ी छोटी सुरक्षा चिंताएं हो सकती हैं। इसके अलावा, आपने पहले ही लाइब्रेरी की एक प्रति बनाने की संभावना पर ध्यान दिया है, जो मैं प्रस्तावित कर रहा हूं। इस पर मेरा मोड़ यह है कि आपकी अस्थायी प्रति फ़ाइल सिस्टम में केवल एक पल के लिए एक प्रविष्टि के रूप में मौजूद है, इस पर ध्यान दिए बिना कि आप वास्तव में लाइब्रेरी को कब तक खोलते हैं।

आप किसी लाइब्रेरी लोड करना चाहते हैं जब इन चरणों का पालन करें:

  1. प्रति एक अस्थायी स्थान के लिए फ़ाइल, शायद mkstemp()
  2. लोड पुस्तकालय की अस्थायी प्रतिलिपि dlopen का उपयोग कर()
  3. के साथ शुरू
  4. अनलिंक() अस्थायी फ़ाइल
  5. सामान्य रूप में आगे बढ़ना, फ़ाइल के संसाधनों स्वचालित रूप से हटा दिया जाएगा जब आप dlclose()

यह अच्छा होगा अगर फ़ाइल को प्रतिलिपि बनाने की आवश्यकता के बिना "फ़ाइल कॉपी करें" चरण प्राप्त करने का वास्तव में आसान तरीका था। हार्ड-लिंकिंग दिमाग में आती है, लेकिन मुझे नहीं लगता कि यह इन उद्देश्यों के लिए काम करेगा। यह आदर्श होगा यदि लिनक्स की कॉपी-ऑन-राइट मैकेनिज्म थी जो लिंक() के रूप में उपयोग करना आसान था, लेकिन मुझे ऐसी सुविधा के बारे में पता नहीं है।

संपादित करें: @Zan Lynx उत्तर बताता है कि गतिशील पुस्तकालयों की कस्टम प्रतियां बर्बाद हो सकती हैं यदि उन्हें कई प्रक्रियाओं में दोहराया जाता है। तो मेरा सुझाव शायद समझ में आता है अगर इसे न्यायसंगत रूप से लागू किया जाता है - केवल उन्हीं पुस्तकालयों को जो स्टॉम्प्ड होने का खतरा होता है (संभवतः सभी पुस्तकालयों का एक छोटा सबसेट जिसमें/lib या/usr/lib में फ़ाइलें शामिल नहीं होती हैं)।

4

यदि उनके पास फ़ाइल लिखने की अनुमति है तो किसी व्यक्ति के खिलाफ आपकी लाइब्रेरी को ओवरराइट करने के विरुद्ध बचाव करना संभव नहीं है।

क्योंकि dlopen मेमोरी लाइब्रेरी फ़ाइल को मानचित्र करता है, फ़ाइल में सभी परिवर्तन इसे खोलने वाली प्रत्येक प्रक्रिया में दिखाई दे रहे हैं।

dlopen फ़ंक्शन मेमोरी मैपिंग का उपयोग करता है क्योंकि यह साझा पुस्तकालयों का उपयोग करने का सबसे मेमोरी प्रभावी तरीका है। एक निजी प्रति स्मृति बर्बाद कर देगा।

के रूप में अन्य लोगों ने कहा, एक यूनिक्स में एक साझा पुस्तकालय को बदलने के लिए उचित तरीके से अनलिंक का उपयोग करें या नाम बदलने के लिए है, नहीं एक नई प्रतिलिपि के साथ पुस्तकालय अधिलेखित करने के लिए। install कमांड यह ठीक से करेगा।

संबंधित मुद्दे

 संबंधित मुद्दे