1. 程式人生 > >munmap引數錯誤導致程序空間異常

munmap引數錯誤導致程序空間異常

去年在現場遇到一個問題,使用mmap操作檔案的時候,總是莫名奇妙的core,用gdb 命令info file檢視程序空間,發現stack棧空間非常大,覺得莫名其妙。後來發現是munmap傳入的len引數錯誤,導致系統刪除了不該刪除的記憶體。一直以為kernel會幫我校驗地址空間是否合法,所以覺得奇怪,不過一直到這幾天,才拿出來程式碼看了看。原來核心不會校驗[addr,addr+len]範圍是否合法,也不管中間是否有空洞,只是儘量刪除更多的區域(vma)。

程式碼是3.13的,檔案是mm/mmap.c

SYSCALL_DEFINE2(munmap, unsigned long, addr, size_t, len
)
/* Munmap is split into 2 main parts -- this part which finds
 * what needs doing, and the areas themselves, which do the
 * work.  This now handles partial unmappings.
 * Jeremy Fitzhardinge <[email protected]>
 */
int do_munmap(struct mm_struct *mm, unsigned long start, size_t len)
{
    unsigned
long end; struct vm_area_struct *vma, *prev, *last; // start已經要頁對齊 // [start,start+len]一定在正確的範圍內,即都大於TASK_SIZE if ((start & ~PAGE_MASK) || start > TASK_SIZE || len > TASK_SIZE-start) return -EINVAL; // 長度不能是0 if ((len = PAGE_ALIGN(len)) == 0) return -EINVAL; /* Find the first overlapping VMA */
// 找到一個vma區域,他的vm_end要比start大。不過不能保證這個區域就包含了start,也可能vma.vm_start也在start後面,甚至在start+len後面 vma = find_vma(mm, start); if (!vma) return 0; prev = vma->vm_prev; /* we have start < vma->vm_end */ /* vma區域跟[start,end]沒有重疊,也只有找到的這個vma可能與[start,end]重疊 */ end = start + len; if (vma->vm_start >= end) return 0; // 如果vma與[start,end]重疊,就拆分vma。 // 只有start在(vma.vm_start, vma.vm_end)範圍內時才會有交叉重疊, // vma.vm_end肯定是比start大的,那麼如果vma.vm_start比start小, // 就能確定兩個區域有重疊,需要拆分vma。 if (start > vma->vm_start) { int error; /* * Make sure that map_count on return from munmap() will * not exceed its limit; but let map_count go just above * its limit temporarily, to help free resources as expected. */ if (end < vma->vm_end && mm->map_count >= sysctl_max_map_count) return -ENOMEM; error = __split_vma(mm, vma, start, 0); if (error) return error; prev = vma; } // end的判斷也是類似的,看看包含end的vma是否需要拆分 last = find_vma(mm, end); if (last && end > last->vm_start) { int error = __split_vma(mm, last, end, 1); if (error) return error; } vma = prev? prev->vm_next: mm->mmap; // 嘗試解鎖某些加鎖區域,如果存在的話 if (mm->locked_vm) { struct vm_area_struct *tmp = vma; while (tmp && tmp->vm_start < end) { if (tmp->vm_flags & VM_LOCKED) { mm->locked_vm -= vma_pages(tmp); munlock_vma_pages_all(tmp); } tmp = tmp->vm_next; } } // 把unmap需要刪除的vma從mm中刪除,並返回需要刪除的vma連結串列 detach_vmas_to_be_unmapped(mm, vma, prev, end); // 通知MMU,重新整理TLB unmap_region(mm, vma, prev, start, end); // 對每個vma做vma.vm_ops.close(如果有的話),還要釋放檔案(vma.vm_file) remove_vma_list(mm, vma); return 0; }

detach_vmas_to_be_unmapped這個函式負責把[start,end]範圍內的vma全部從程序空間中刪除,並沒有檢查中間的區域之間是否有空洞。所以如果傳入的長度比較大,超過了之前mmap的大小,也不會出現錯誤,導致undefined異常。

static void
detach_vmas_to_be_unmapped(struct mm_struct *mm, struct vm_area_struct *vma,
    struct vm_area_struct *prev, unsigned long end)
{
    struct vm_area_struct **insertion_point;
    struct vm_area_struct *tail_vma = NULL;

    insertion_point = (prev ? &prev->vm_next : &mm->mmap);
    vma->vm_prev = NULL;
    do {
        vma_rb_erase(vma, &mm->mm_rb); // 從程序空間中刪除所有的vma
        mm->map_count--;
        tail_vma = vma;
        vma = vma->vm_next;
    } while (vma && vma->vm_start < end);
    *insertion_point = vma;
    if (vma) {
        vma->vm_prev = prev;
        vma_gap_update(vma);
    } else
        mm->highest_vm_end = prev ? prev->vm_end : 0;
    tail_vma->vm_next = NULL;
    mm->mmap_cache = NULL;      /* Kill the cache. */
}

相關推薦

munmap引數錯誤導致程序空間異常

去年在現場遇到一個問題,使用mmap操作檔案的時候,總是莫名奇妙的core,用gdb 命令info file檢視程序空間,發現stack棧空間非常大,覺得莫名其妙。後來發現是munmap傳入的len引數錯誤,導致系統刪除了不該刪除的記憶體。一直以為kernel會

虛擬機器塊裝置掛載引數錯誤導致無法開機問題處理

故障現象 給虛擬機器增加一個卷後,重啟無法進入系統。   故障原因 /etc/fstab中填寫的檔案系統型別與分割槽實際檔案系統不一致。   處理方法 將虛擬機器系統卷掛載到其他虛擬機器上,修改/etc/fstab為正確配置。   排查過程 同事給一臺虛擬機器

Java效能分析及問題解決(二)jvm致命錯誤導致程序直接掛掉,錯誤日誌分析及解決

前言:   最近伺服器一臺機器,經常發現jvm錯誤日誌,因為程式有監控,所以程序能夠自動啟動,沒有產生什麼大的影響,利用空閒時間分析下這個問題以及給出最後的解決方案: jvm出現的致命錯誤,會在預設工

gcc引數錯誤導致的makefile錯誤

今天寫一個小makefile檔案,出現以下錯誤: linux:/mnt/hgfs/vmware-share # make cc -o my_bin.o my_bin.c cc -o my_bin my_bin.o my_bin.o:(.rodata+0x0): multip

子網掩碼錯誤導致通訊異常問題

子網掩碼 昨天遇到個小問題,雖然簡單但是覺得很容易被忽視,然後就會導致奇怪的現象。 兩臺終端PC,網關都在核心上,PC3為192.168.8.190/24,網關為192.168.8.1,PC4是192.168.13.224/24,網關為192.168.13.1。問題現場,PC3可以

linux異常處理:selinux配置錯誤導致無法重啟

嚴格 log htm 1.2 模式 想要 process info 磁盤 點擊返回自學Linux集錦 linux異常處理:selinux配置錯誤導致無法重啟 一次linux無法重啟異常記錄: 當時第一反應就是梳理最近的配置變更,特別是能預知相關的就是selinux配置變

org.apache.solr.common.SolrException: Request-URI Too Large(solr query操作因為引數過多導致uri過長錯誤

原文連結: org.apache.solr.common.SolrException: Request-URI Too Large   採用post提交url提交方式有兩種,一種是get方式,一種是post方式 sol查詢的時候添加個引數   &nb

未能載入檔案或程式集“AspNetPager”或它的某一個依賴項。引數錯誤。 (異常來自 HRESULT:0x80070057 (E_INVALIDARG))

刪掉了系統盤下所有這個資料夾。其實,這些資料夾就是asp.net生成之後的快取資料夾。例如 C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Temporary ASP.NET Files C:\Windows\Microsoft.NET\Framework\

Mybatis xml對映檔案錯誤,導致Tomcat無法啟動,也不報異常

在做的專案,有時候tomcat啟動會陷入死迴圈,一直在啟動中,無法結束,自然也不會報異常. 查了一下網上的資料,需要自己重寫一下SqlSessionFactoryBean中的buildSqlSessionFactory方法,並替換原有的SqlSessionFactoryBean import

引數錯誤。 (異常來自 HRESULT:0x80070057 (E_INVALIDARG))

==================================================================== 異常來自 HRESULT:0x80070057 (E_INVALIDARG) 未能載入程式集....... 幾次刪除引用然後重新

伺服器出現502錯誤 可能程序過多導致

通過命令檢視伺服器上一共開了多少的 php-cgi 程序 ps -fe |grep "php" | grep -v "grep" | wc -l 使用如下命令檢視已經有多少個php-cgi程序用來處理tcp請求 netstat -anop | grep "php" | gr

gc引數設定錯誤導致一直full gc

gc param JAVA_OPTS="${JAVA_OPTS} -Xms1g -Xmx1g -XX:NewSize=512m -XX:MaxNewSize=1g -Xss512k -XX:SurvivorRatio=6" JAVA_OPTS="${J

引數錯誤,異常來自HRESULT:0X80070057(E_INVALIDARG)

今天在用Entity Framwork生成實體的時候,報瞭如下錯誤: 引數錯誤。(異常來自HRESULT:0X80070057(E_INVALIDARG)) 如圖: 解決方法: 只需在EF連線資

錯誤使用 xlswrite (line 219) 呼叫錯誤,排程異常: 引數錯誤

一開始以為是xlswrite使用問題,經檢查後發現沒有問題 後來才發現是檔名出錯,系統找不到所指示的檔案所以報了呼叫錯誤 另外雖然在xlswrite的help中有: xlswrite(filename,A,xlRange) 但實踐表明x1range被識別為

解決鍵盤模式(佈局)的錯誤導致的部分鍵位失靈或異常(姑且這樣描述問題吧)

問題描述: 我的vmware虛擬機器截至目前安裝了三個系統分別是win xp, linux ubuntu, linux redhat,安裝好後,我在陸續的使用過程中,發現了問題: 在我的redhat和ubuntu裡,當我敲擊\這樣的一個鍵位(enter上方的反斜槓鍵)

Android開發小記:名稱空間錯誤導致自定義屬性不生效

前言 好久沒更新博文了,封閉開發一個多月,就問你怕不怕?最近在使用自定義控制元件的時候發現預覽有效果,可是執行起來就不展示,最後才發現自己的佈局中的名稱空間有問題,導致了控制元件屬性不生效。 名稱空間 名稱空間:namespace。在XML檔案中提供避免元

錯誤修改初始化引數檔案導致oracle啟動失敗!

如果錯誤的修改了引數檔案導致資料庫不能啟動,由於spfile是採用的二進位制檔案,不能直接修改。 可以通過spfile建立pfile,手動修改pfile,利用pfile啟動資料庫,然後再通過pfile建立spfile: SQL> startup ORACLE 例程已經

JAVA學習第十九課(java程序異常處理 (二))

num 函數 錯誤 style col 編譯失敗 return [] java 異常處理的捕捉形式: 這是能夠對異常進行針對性處理的方式 六、try、catch的理解 詳細格式: try { //須要被檢測異常的代碼 } catch(異常類 變量)//改變量用

MVC 分析器錯誤:“/”應用程序中的服務器錯誤

height logs 程序 .cn mvc 技術 log bin 加載 運行一個MVC項目的時候一運行就報以下這個錯誤 解決方法: 可能是因為該項目引用的dll會被加載到該項目的bin\文件下, 而不是b

小議C#錯誤調試和異常處理

才幹 avi blank {} sni 沒有 ng- fill back 在程序設計中不可避免地會出現各種各樣的錯誤,在編寫代碼時須要盡量避免。在處理錯誤時,首先應該分析錯 誤的類型,找出出錯的原因才幹解決錯誤。 錯誤的分類