क्या प्रोग्राम सत्यापन तकनीक हार्टलेड की शैली के कीड़े को होने से रोक सकती है?


9

हार्टलेड बग की बात पर, ब्रूस श्नेयर ने 15 अप्रैल के अपने क्रिप्टो-ग्राम में लिखा था: '' कैटास्ट्रॉफिक '' सही शब्द है। 1 से 10 के पैमाने पर, यह एक 11. ' मैंने कई साल पहले पढ़ा था कि एक निश्चित ऑपरेटिंग सिस्टम के कर्नेल को एक आधुनिक प्रोग्राम सत्यापन प्रणाली के साथ सख्ती से सत्यापित किया गया है। इसलिए हार्टलेड की शैली के बग को आज कार्यक्रम सत्यापन तकनीकों के अनुप्रयोग के माध्यम से होने से रोका जा सकता है या यह अभी तक अवास्तविक है या मुख्यतः असंभव है?


2
जे। रेगर द्वारा इस प्रश्न का एक दिलचस्प विश्लेषण यहाँ दिया गया है।
मार्टिन बर्जर

जवाबों:


6

सबसे संक्षिप्त तरीके से अपने प्रश्न का उत्तर देने के लिए - हाँ, यह बग औपचारिक सत्यापन उपकरण द्वारा संभवतः पकड़ा जा सकता था। वास्तव में, संपत्ति "कभी भी एक ब्लॉक नहीं भेजती है, जो कि भेजी गई दिल की धड़कन के आकार से बड़ी है" सबसे विनिर्देश भाषाओं (जैसे एलटीएल) को औपचारिक रूप देने के लिए काफी सरल है।

समस्या (जो औपचारिक तरीकों के खिलाफ एक आम आलोचना है) यह है कि आपके द्वारा उपयोग किए जाने वाले विनिर्देश मनुष्यों द्वारा लिखे गए हैं। वास्तव में, औपचारिक विधियाँ बगों को खोजने से लेकर बग को परिभाषित करने की चुनौती को ही परिभाषित करती हैं। यह एक मुश्किल काम है।

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

इस प्रकार, हार्दिक मामले में, आवश्यकताओं को औपचारिक रूप देने का प्रयास करते हुए भी, प्रश्न में बंधे को दूर किया जा सकता था, जिसके परिणामस्वरूप समान व्यवहार होता है।

संक्षेप में, औपचारिक तरीकों का उपयोग करके संभावित रूप से इस बग से बचा जा सकता था, लेकिन इस संपत्ति को अग्रिम रूप से निर्दिष्ट करने वाला एक मानव होना चाहिए था।


5

व्यावसायिक कार्यक्रम चेकर्स जैसे कि क्लोकार्ट या कवर्सिटी हार्टबल को खोजने में सक्षम हो सकते हैं क्योंकि यह एक अपेक्षाकृत सरल है "एक सीमा जाँच त्रुटि करना भूल गया," जो कि उन मुख्य समस्याओं में से एक है जिनकी जाँच के लिए उन्हें डिज़ाइन किया गया है। लेकिन एक बहुत सरल तरीका है: अपारदर्शी अमूर्त डेटा प्रकारों का उपयोग करें जो बफर ओवररन से मुक्त होने के लिए अच्छी तरह से परीक्षण किए जाते हैं।

सी प्रोग्रामिंग के लिए "सुरक्षित स्ट्रिंग" सार डेटा प्रकार उपलब्ध हैं। जिस से मैं सबसे ज्यादा परिचित हूँ, वह है वर्स्ट । लेखक, जेम्स एंटिल, के बारे में एक महान चर्चा है कि आपको अपने स्वयं के निर्माणकर्ताओं / कारखाने के तरीकों के साथ एक स्ट्रिंग अमूर्त डेटा प्रकार की आवश्यकता क्यों है और सी के लिए अन्य स्ट्रिंग अमूर्त डेटा प्रकारों की एक सूची भी है


2
कवर हार्टलेड नहीं लगता है, जॉन रेगर द्वारा इस विश्लेषण को देखें ।
मार्टिन बर्जर

अच्छा लिंक! यह कहानी के असली नैतिकता को प्रदर्शित करता है: प्रोग्राम सत्यापन खराब रूप से तैयार किए गए (या गैर-मौजूद) सार के लिए नहीं बना सकता है।
भटकते हुए तर्क

2
यह निर्भर करता है कि प्रोग्राम वेरिफिकेशन से आपका क्या मतलब है। यदि आप स्थैतिक विश्लेषण का मतलब है, तो हाँ, यह हमेशा एक अनुमान है, चावल के प्रमेय के प्रत्यक्ष परिणाम के रूप में। यदि आप एक इंटरैक्टिव प्रमेय प्रॉसर में पूर्ण व्यवहार को सत्यापित करते हैं, तो आपको एक कच्चा लोहा की गारंटी मिलती है कि कार्यक्रम इसके विनिर्देशों को पूरा करता है, लेकिन यह बहुत लाभदायक है। और आप अभी भी इस समस्या का सामना कर रहे हैं कि आपके विनिर्देश गलत हो सकते हैं (उदाहरण के लिए एरियन 5 विस्फोट देखें)।
मार्टिन बर्जर

1
@MartinBerger: कवरेज अब इसे ढूँढता है ।
मोनिका को पुनः स्थापित करें - एम। श्रोडर

4

यदि आप रनटाइम बाउंड-चेकिंग और फ़ज़िंग के संयोजन को " प्रोग्राम वेरिफिकेशन तकनीक  " के रूप में गिनते हैं  , तो हाँ इस विशेष बग को पकड़ा जा सकता है

उचित फ़ज़िंग के कारण अब कुख्यात memcpy(bp, pl, payload);मेमोरी ब्लॉक की सीमा के पार पढ़ने के plलिए होगा। रनटाइम बाउंड-चेकिंग सिद्धांत रूप में इस तरह की किसी भी पहुंच को पकड़ सकती है, और व्यवहार में, इस विशेष मामले में, यहां तक mallocकि उस डिबग संस्करण का भी एक बाउंड वर्जन जांचने के memcpyलिए काम करता है (एमएमयू के साथ गड़बड़ करने की कोई जरूरत नहीं है) । समस्या है, प्रत्येक प्रकार के नेटवर्क पैकेट पर फ़ज़िंग परीक्षण करना प्रयास करता है।


1
OpenSSL के मामले में सामान्य रूप से IIRC के लेखकों ने अपने स्वयं के आंतरिक मेमोरी प्रबंधन को इस तरह से लागू किया कि यह memcpyमूल रूप से सिस्टम से अनुरोधित (बड़े) क्षेत्र की वास्तविक सीमा से टकराने की बहुत कम संभावना थी malloc
विलियम प्राइस

हां, ओपनएसएसएल के मामले में जैसा कि बग के समय था, memcpy(bp, pl, payload)ओपनएसएसएल के mallocप्रतिस्थापन द्वारा उपयोग किए जाने वाले सीमा के खिलाफ जांचना होगा , न कि सिस्टम malloc। यह बाइनरी स्तर पर स्वचालित बाउंड-चेकिंग (कम से कम mallocप्रतिस्थापन के गहन ज्ञान के बिना ) को नियंत्रित करता है । स्रोत-स्तर के विज़ार्ड के साथ पुनर्संयोजन होना चाहिए जैसे कि सी मैक्रोज़ टोकन की जगह mallocया जो भी ओपनएसएसएल इस्तेमाल किया गया हो; और ऐसा लगता है कि हमें memcpyबहुत चतुर MMU ट्रिक्स को छोड़कर उसी की आवश्यकता है ।
fgrieu

4

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

पॉइंटर अंकगणित जैसा कि सामान्य रूप से तैयार किया गया है, यह निराधार है क्योंकि प्रकार प्रणाली वास्तव में इसका मतलब नहीं है कि इसका क्या मतलब है। आप कचरा एकत्र भाषा (सामान्य दृष्टिकोण जो आपको अमूर्तता के लिए भी भुगतान करता है) में काम करके इस समस्या से पूरी तरह से बच सकते हैं। या आप इस बारे में अधिक विशिष्ट हो सकते हैं कि आप किस प्रकार के पॉइंटर्स का उपयोग कर रहे हैं, ताकि कंपाइलर किसी भी चीज को अस्वीकार कर सके जो असंगत है या सिर्फ लिखित रूप में सही साबित नहीं हो सकती है। यह रुस्त जैसी कुछ भाषाओं का दृष्टिकोण है।

निर्मित प्रकार सबूतों के बराबर होते हैं, इसलिए यदि आप एक प्रकार की प्रणाली लिखते हैं जो यह भूल जाती है, तो सभी प्रकार की चीजें गलत हो जाती हैं। कुछ समय के लिए मान लें कि जब हम एक प्रकार की घोषणा करते हैं, तो हम वास्तव में इसका मतलब है कि हम चर में क्या है के बारे में सच्चाई का आश्वासन दे रहे हैं।

  • int * x; // एक असत्य कथन। एक्स मौजूद है और एक इंट की ओर इशारा नहीं करता है
  • int * y = z; // केवल सच अगर z एक इंट को इंगित करता है
  • * (x + 3) = 5; // केवल सच है अगर (x + 3) x के समान सरणी में एक इंट को इंगित करता है
  • int c = a / b; // केवल सच है अगर बी नॉनज़रो है, जैसे: "नॉनज़रो इंट बी = ...;"
  • अशक्त int * z = NULL; // nullable int * एक int * के समान नहीं है
  • int d = * z; // झूठा दावा, क्योंकि z अशक्त है
  • if (z! = NULL) {int * e = z; } // ठीक है क्योंकि z शून्य नहीं है
  • नि: शुल्क (y); int w = * y; // गलत दावा, क्योंकि y अब w पर मौजूद नहीं है

इस दुनिया में, संकेत शून्य नहीं हो सकते। NullPointer dereferences मौजूद नहीं है, और संकेत कहीं भी अशक्तता के लिए जाँच करने के लिए नहीं है। इसके बजाय, एक "अशक्त int *" एक अलग प्रकार है जिसका मान या तो नल या पॉइंटर में निकाला जा सकता है। इसका मतलब यह है कि उस बिंदु पर जहां गैर-अशक्त धारणा शुरू होती है आप या तो अपने अपवाद को लॉग इन करें या एक शून्य शाखा के नीचे जाएं।

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

इसके अलावा, यदि आपके पास एक पॉइंटर नहीं है जो कि इनिशियलाइज़ नहीं है, तो आपके पास अनइंस्टाल्ड मेमोरी के लिए पॉइंटर्स नहीं होंगे। यदि आपके पास मुक्त मेमोरी के लिए एक संकेतक है, तो इसे संकलक द्वारा अस्वीकार कर दिया जाना चाहिए। जंग में, इन प्रकार के साक्ष्यों को अपेक्षा के अनुकूल बनाने के लिए अलग-अलग सूचक प्रकार हैं। विशेष रूप से स्वामित्व वाले संकेत (यानी: कोई उपनाम नहीं), गहरी अपरिवर्तनीय संरचनाओं के संकेत हैं। डिफ़ॉल्ट भंडारण प्रकार अपरिवर्तनीय है, आदि।

प्रोटोकॉल सतह पर एक वास्तविक अच्छी तरह से परिभाषित व्याकरण लागू करने का मुद्दा भी है (जिसमें इंटरफ़ेस सदस्य शामिल हैं), इनपुट सतह क्षेत्र को ठीक से अनुमानित करने के लिए सीमित करने के लिए। "शुद्धता" के बारे में बात यह है: 1) सभी अपरिभाषित राज्यों से छुटकारा पाएं 2) तार्किक स्थिरता सुनिश्चित करें । वहाँ होने की कठिनाई का बहुत बुरा टूलींग (शुद्धता के दृष्टिकोण से) का उपयोग करने के साथ बहुत कुछ करना है।

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

ध्यान रखें कि यह केवल गूंगा गलतियों के बारे में नहीं है। यह चतुर घुसपैठियों से कोड आधार का बचाव करने के बारे में भी है। ऐसे मामले होंगे जहां आपको "औपचारिक रूप से निर्दिष्ट प्रोटोकॉल का पालन करना" जैसे महत्वपूर्ण गुणों के एक ठोस मशीन-जनित प्रमाण के बिना एक सबमिशन को अस्वीकार करना होगा।


2

आवरण जैसे स्थैतिक विश्लेषण उपकरण वास्तव में हार्टलेड और समान दोष पा सकते हैं। पूर्ण प्रकटीकरण: मैंने कवरफ़ॉफ़ को cofounded किया।

हार्टब्लेड की हमारी जाँच पर मेरा ब्लॉग पोस्ट देखें और इसका पता लगाने के लिए हमारे विश्लेषण को कैसे बढ़ाया गया:

http://security.coverity.com/blog/2014/Apr/on-detecting-heartbleed-with-static-analysis.html


1

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

मीडिया से अधिक bkg इसकी उत्पत्ति का विवरण:

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.