【缺陷周話】第3期 :記憶體洩漏
記憶體洩漏指由於疏忽或錯誤造成程式未能釋放已經不再使用的記憶體。記憶體洩漏並非指記憶體在物理上的消失,而是應用程式分配某段記憶體後,由於設計錯誤,導致在釋放該段記憶體之前就失去了對該段記憶體的控制,從而造成了記憶體的浪費。或者說,由於軟體無法有效跟蹤和釋放分配的記憶體,從而導致效能下降。詳細請參見 ofollow,noindex" target="_blank">CWE ID 401: Improper Release of Memory Before Removing Last Reference (‘Memory Leak’) 。
2、記憶體洩漏的危害
記憶體洩漏是 C/C++ 程式中常見的漏洞型別,會因為減少可用記憶體的數量而降低計算機的效能,甚至導致全部或部分裝置停止正常工作或者應用程式崩潰。2018年1月至9月,CVE 中共有63條漏洞資訊與其相關。部分漏洞如下:
CVE-2018-17234 | HDF HDF5 1.10.3 版本 H5Ocache.c 中的 H5O__chunk_deserialize() 函式存在記憶體洩漏,導致允許攻擊發起拒絕服務攻擊。 |
CVE-2018-16807 | Bro是一個開源的網路分析和安全監控的框架。 Bro 2.5.5及之前版本中的 Kerberos protocol 解析器的 scripts/base/protocols/krb/main.bro 檔案存在記憶體洩漏。攻擊者可利用該漏洞造成拒絕服務。 |
CVE-2018-16750 | ImageMagick 是美國 ImageMagick Studio 公司的一套開源的圖象處理軟體。該軟體可讀取、轉換、寫入多種格式的圖片。 ImageMagick 7.0.7-29 版本及之前版本中的 coders/meta.c 檔案的 formatIPTCfromBuffer() 函式存在記憶體洩漏。 |
CVE-2018-16641 | ImageMagick 7.0.8-6 版本中的 coders/tiff.c 檔案的 TIFFWritePhotoshopLayers() 函式存在記憶體洩漏漏洞。攻擊者可利用該漏洞造成拒絕服務。 |
3、示例程式碼
本章節中使用示例程式碼來源於 Samate Juliet Test Suite for C/C++ v1.3 ( https://samate.nist.gov/SARD/testsuite.php) ,原始檔名:CWE401_Memory_Leak__int64_t_malloc_01.c。
3.1缺陷程式碼
上述示例程式碼在第29行使用malloc()函式進行記憶體分配,並在第30行對分配是否成功進行了判斷。但在第36行函式結束時,並沒有對分配的記憶體data進行有效合理釋放,產生記憶體洩漏。
使用360程式碼衛士對上述示例程式碼進行檢測,可以檢出“記憶體洩漏”缺陷,顯示等級為中。如圖1所示:
圖1 記憶體洩漏檢測示例
3.2 修復程式碼
在上述修復程式碼中,在第29行使用 malloc()函式進行記憶體分配,在第36行函式結束前對申請的記憶體使用free()函式進行釋放,從而避免了記憶體洩漏的發生。
使用360程式碼衛士對修復後的程式碼進行檢測,可以看到已不存在“記憶體洩漏”缺陷。如圖2:
圖2:修復後檢測結果
4、開原始碼檢測計劃某專案記憶體洩漏示例
開原始碼檢測計劃是一項免費的公益計劃。通過使用360程式碼衛士對開源專案進行原始碼檢測和審計,找到原始碼中存在的安全缺陷,使得開源專案的安全性得到提高。
以下是開源專案檢測計劃中檢測出的一個“記憶體洩漏”示例,如圖3所示。
圖3 開源專案檢出“記憶體洩漏”
4.1 缺陷程式碼
在缺陷程式碼中,記憶體在第445行通過new進行申請,但是在第448行函式返回時,沒有進行釋放,從而導致記憶體洩漏。
4.2 修復程式碼
針對該記憶體洩漏問題的提出,開發人員在近期對相關程式碼進行了修復。在448行使用delete 對記憶體進行釋放,從而避免了記憶體洩漏。
5、 如何避免記憶體洩漏
要避免記憶體洩漏,需要注意以下幾點:
(1)在允許的情況下,儘量避免手動管理記憶體,如在 C++ 開發中,使用智慧指標可以減少記憶體洩漏的發生。
(2)在程式碼編寫過程中養成良好的程式設計習慣,保證malloc/new 和 free/delete匹配使用。
(3)在同一個模組、同一個抽象層中分配記憶體和釋放記憶體。
(4)使用原始碼靜態分析工具,進行自動化的檢測,可以有效的發現原始碼中的記憶體洩漏問題。