فا

‫ برنامه نويسي امن با زبان C – پيشنهادات مديريت حافظه

IRCAR201009073

 

 

عنصر اصلي در برنامه نويسي امن با زبان هاي مختلف برنامه نويسي، مستند سازي خوب و استفاده از استانداردهاي قابل اجرا است. استانداردهاي كدنويسي، برنامه نويسان را ترغيب به پيروي از مجموعه اي متحدالشكل از قوانين و راهنماييها مي كند كه بر اساس نيازمندي هاي پروژه و سازمان تعيين شده است، نه بر اساس سلايق و مهارت هاي مختلف برنامه نويسان. به محض تعيين استانداردهاي مذكور، مي توان از آن به عنوان معياري براي ارزيابي كدهاي منبع، چه به صورت دستي و چه به صورت اتوماتيك استفاده كرد.

از استانداردهاي معروف در اين زمينه مي توان به استانداردCERT براي كدنويسي امن اشاره كرد كه يك سري از قوانين و پيشنهادات را براي كد نويسي امن با زبان هاي برنامه نويسي C، C++ و جاوا ارائه مي دهد. هدف از اين قوانين و پيشنهادات، حذف عادت هاي كدنويسي ناامن و رفتارهاي تعريف نشده است كه منجر به آسيب پذيري هاي قابل سوءاستفاده مي شود. به كارگيري استانداردهاي مذكور منجر به توليد سيستم هاي با كيفيت بالاتر مي شود كه در برابر حملات بالقوه، پايدارتر و مقاوم تر هستند.

در مقاله "آشنايي با استاندارد CERT براي برنامه نويسي امن"، كليات استاندارد CERT در زمينه مزبور را توضيح داديم و در سري مقاله هاي برنامه نويسي امن به زبان C به صورت تخصصي تر شيوه برنامه نويسي امن با اين زبان را مورد بررسي قرار مي دهيم. قابل ذكر است كه در اين استاندارد 89 قانون و 134 پيشنهاد براي برنامه نويسي امن با زبان C ارائه شده است كه در اين سري مقالات، مهمترين آنها را كه در سطح يك قرار دارند، شرح خواهيم داد. براي كسب اطلاعات بيشتر در مورد سطح بندي قوانين و پيشنهادات به مقاله "آشنايي با استاندارد CERT براي برنامه نويسي امن" مراجعه فرماييد. در مقاله قبلي در مورد قوانين  سطح اول ارائه شده در مورد آشته ها صحبت كرديم و در مقاله حاضر به پيشنهادات ارائه شده سطح اول در مورد مديريت حافظه خواهيم پرداخت.

 
مديريت حافظه
 

مديريت حافظه پويا يكي از منابع متداول ايجاد حفره هاي برنامه نويسي است كه منجر به آسيب پذيري هاي امنيتي مي شود. تصميم گيري در مورد اينكه حافظه پويا چگونه اختصاص داده شود، استفاده شود و آزاد شود، باري بر روي دوش برنامه نويسان است. مديريت حافظه ضعيف مي تواند منجر به مشكلات امنيتي همچون سرريز بافر heap، اشاره گرهاي بدون مرجع و خطاهاي دو بار آزاد كردن حافظه شود. از ديدگاه برنامه نويسان، مديريت حافظه، اختصاص حافظه، خواندن از و نوشتن در حافظه و آزاد كردن حافظه است.

در زير مهمترين پيشنهادات و قوانين برنامه نويسي امن براي پيش گيري از بروز آسيب پذيري هاي مربوط به مديريت حافظه، بر اساس استاندارد CERT آورده شده است.

 
پيشنهادات
 

24. MEM00-C – اختصاص دادن و آزاد كردن حافظه را در يك ماژول، در سطحي يكسان انجام دهيد.

 

اختصاص دادن و آزاد كردن حافظه در ماژول ها و سطوح مختلف تجريد (abstraction)، تشخيص زمان و چگونگي آزادسازي حافظه را مشكل ساخته و منجر به نقص هاي برنامه نويسي همچون نشت اطلاعات حافظه، آسيب پذيري هاي دوبار آزاد سازي حافظه، دسترسي به حافظه هاي آزاد يا نوشتن در حافظه هاي آزاد شده و يا اختصاص داده نشده  مي شود.

براي پيشگيري از چنين وضعيت هايي، حافظه بايد در سطح يكساني از تجريد و به صورت ايده آل در يك ماژول اختصاص داده شده و آزاد گردد. اين مسئله شامل تابع هاي تخصيص و آزاد سازي حافظه كه در ISO/IEC 9899:1999 توضيح داده شده است مي شود. توابع مذكور را در زير مشاهده مي كنيد:

 

در زير كدي را مشاهده مي كنيد كه از پيشنهاد مذكور استفاده نكرده است. در اين كد حافظه دو بار آزاد مي شود، زيرا در سطوح مختلفي از تجريد اختصاص داده شده و آزاد گشته است. در اين مثال، حافظه آرايه list در تابع process_list()  اختصاص داده شده است. سپس آرايه مذكور به تابع verify_size() فرستاده شده است كه مسئول بررسي وجود خطا در اندازه آرايه است. در صورتي كه اندازه آرايه زير يك مقدار حداقل باشد، حافظه اي كه اختصاص داده شده آزاد مي شود و كنترل برنامه به تابع فراخوان بر مي گردد. تابع فراخوان نيز حافظه مذكور را براي بار دوم آزاد مي كند. اين رفتار به صورت بالقوه يك آسيب پذيري قابل سوءاستفاده است. همچنين فراخواني آزاد كردن حافظه در تابع verify_size() اتفاق مي افتد كه زيرتابعي از process_list() است. لذا اختصاص و آزاد كردن حافظه در دو سطح متفاوت تجريد اتفاق مي افتد و پيشنهاد مذكور نقض مي شود.

 
 

براي اصلاح مشكل مذكور، كد رسيدگي به خطا در تابع verify_size به گونه اي تغيير پيدا كرده است كه حافظه آرايه را آزاد نمي كند. اين تغيير تضمين مي كند كه حافظه آرايه list تنها يك بار و در سطح يكساني از تجريد، در تابع process_list() آزاد مي شود.

 
 

25. MEM08-C – از realloc() تنها براي تغيير اندازه آرايه هايي كه به صورت پويا حافظه دهي شده اند، استفاده كنيد.

 
با توجه به مستندات C استاندارد، فراخواني realloc(ptr, size) منجر به روند زير مي شود:
 

"شئ قديمي را كه اشاره گر ptr به آن اشاره مي كند آزاد كرده و يك اشاره گر به شئ جديدي را بر مي گرداند كه اندازه آن توسط پارامتر size مشخص شده است. محتويات شئ جديد بايد مشابه محتويات شئ قديمي قبل از آزاد سازي باشد. در صورتي كه اندازه حافظه شئ جديد بيش از شئ قديمي باشد، هر بايت اضافي حاوي محتويات نامشخصي خواهد بود."

 

در زير يك كد را مشاهده مي كنيد كه با اين پيشنهاد همخواني ندارد. در اين مثال از realloc() براي اختصاص حافظه به شئ با يك نوع خاص استفاده شده است ولي آن را با يك نوع ديگر مقدار دهي اوليه مي كند.

 
 

در اينجا فراخواني realloc() براي تخصيص حافظه به widget است ولي آن را مانند يك gadget مقدار دهي اوليه مي كند. اين مسئله در بهترين حالت منجر به تبديل انواع از char * به int و يا از int به char * مي شود. حتي ممكن است يك double را با استفاده از محتويات اشاره گر، مقدار دهي اوليه كند.

يك برنامه تنها بايد از realloc() براي حافظه گيري مجدد آرايه هاي پويا استفاده كند. همچنين لازم است از آرايه هاي با نوع يكسان اما با ابعاد متفاوت براي جابجايي استفاده كند. يك نمونه كد سازگار با اين پيشنهاد را در زير مشاهده مي كنيد:

 
 
 

در مقاله بعدي در مورد قوانين ارائه شده براي مديريت حافظه صحبت خواهيم كرد.


نظرات

بدون نظر
شما برای نظر دادن باید وارد شوید

نوشته

 
تاریخ ایجاد: 18 مرداد 1393

دسته‌ها

امتیاز

امتیاز شما
تعداد امتیازها:0