亚洲av成人无遮挡网站在线观看,少妇性bbb搡bbb爽爽爽,亚洲av日韩精品久久久久久,兔费看少妇性l交大片免费,无码少妇一区二区三区

  免費(fèi)注冊(cè) 查看新帖 |

Chinaunix

  平臺(tái) 論壇 博客 文庫(kù)
最近訪問(wèn)板塊 發(fā)新帖
查看: 5532 | 回復(fù): 1
打印 上一主題 下一主題

對(duì)Linux Kernel vmsplice Exploit的分析 [復(fù)制鏈接]

論壇徽章:
0
跳轉(zhuǎn)到指定樓層
1 [收藏(0)] [報(bào)告]
發(fā)表于 2008-04-19 19:31 |只看該作者 |倒序?yàn)g覽
參考文檔:
   http://lwn.net/Articles/268783/
   http://www.avertlabs.com/researc ... l-vmsplice-exploit/
   http://lwn.net/Articles/271688/  
   溢出程序在http://www.milw0rm.com/exploits/5092,存在該問(wèn)題的內(nèi)核版本是2.6.17 – 2.6.24.1。
   首先分析一下造成溢出的原因:
  Vmsplice的作用是將一個(gè)文件描述符(必須是一個(gè)pipe)和一段內(nèi)存連接起來(lái)。這個(gè)功能的實(shí)現(xiàn)是通過(guò)fs/splice.c的do_vmsplice()function來(lái)實(shí)現(xiàn),在該function種,定義了兩個(gè)數(shù)組:
struct page *pages[PIPE_BUFFERS];
struct partial_page partial[PIPE_BUFFERS];
   PIPE_BUFFERS的值在存在溢出問(wèn)題的版本中的是定義為16。這兩個(gè)函數(shù)都傳遞到了 get_iovec_page_array()這個(gè)function中。
  以2.6.22.14版本的源代碼為例,看看在fs/splice.c的1565行開始的get_iovec_page_array函數(shù)。
在該函數(shù)中我們看到:
error = get_user(len, &iov->iov_len);
if (unlikely(!len))
break;
在這里僅僅判斷l(xiāng)en是正數(shù)就ok,而len是可以通過(guò)用戶控制的。
npages = (off + len + PAGE_SIZE - 1) >> PAGE_SHIFT;
if (npages > PIPE_BUFFERS - buffers)
   npages = PIPE_BUFFERS – buffers;
error = get_user_pages(current, current->mm,
                   (unsigned long) base, npages, 0, 0,&pages[buffers], NULL);
npages的值是通過(guò)len計(jì)算得出,那么我們將len值設(shè)為UINT32_MAX的話,那么計(jì)算off+len+PAGE_SIZE的結(jié)果就會(huì)導(dǎo)致整型數(shù)包裹(integer wrap),那么npages的將會(huì)是0,這是unexpected的。我們現(xiàn)在來(lái)分析get_user_pages在得到了unexpected的npages值后,會(huì)有什么樣的結(jié)果。get_user_pages是用來(lái)將用戶空間中頁(yè)(pages)映射(pin)入內(nèi)存,并且得到他們頁(yè)結(jié)構(gòu)(struct page)的指針。然而在get_user_pages()函數(shù)內(nèi)部,處理頁(yè)面時(shí)使用的do{}while()的結(jié)尾處是:
        len--;
    } while (len && start < vma->vm_end);
如果len的值是0的話(正如我們期望的那樣),那么這個(gè)循環(huán)將會(huì)至少循環(huán)一次,將len值減為-1后,繼續(xù)在頁(yè)面中錯(cuò)誤地執(zhí)行,直到執(zhí)行到?jīng)]有有效的mapping的地址后,指針將會(huì)停止并返回。但是在這時(shí),他或許已經(jīng)在儲(chǔ)了比他當(dāng)時(shí)所分配的內(nèi)存空間更多的內(nèi)容,到其page數(shù)組中。也就是說(shuō)在這種情況下get_user_pages()將會(huì)溢出pages數(shù)組,寫了不僅僅是PIPE_BUFFERS(16)個(gè)指針到數(shù)組中。然而真正被溢出程序所利用數(shù)組是partial數(shù)組。
  在do_vmsplice()中定義的partial數(shù)組同樣被傳遞給了get_iovec_page_array()。在partial數(shù)組中描述了需要寫入到管道中的頁(yè)面的其他的部分。        在get_user_pages()返回后,緊跟著一個(gè)循環(huán)語(yǔ)句:
for (i = 0; i < error; i++) {
     const int plen = min_t(size_t, len, PAGE_SIZE - off);

     partial[buffers].offset = off;
     partial[buffers].len = plen;

     off = 0;
     len -= plen;
     buffers++;
                }
在這種情況下,因?yàn)樗许?yè)面都被寫入,被計(jì)算的偏移量(offset)將會(huì)是zero,并且長(zhǎng)度(length)值是PAGE_SIZE(4096).而從get_user_pages()的返回值error,將會(huì)是在被溢出的情況下 被mapped的pages頁(yè)的數(shù)量:46。那么實(shí)際上partial數(shù)組的同樣是被定義為16個(gè)元素,因此上邊的這個(gè)循環(huán)同樣會(huì)導(dǎo)致溢出的發(fā)生。
這兩個(gè)數(shù)組都是在vmsplice_to_page()中聲明的。在內(nèi)存分配中partial數(shù)組將會(huì)放在pages的下邊,因此一點(diǎn)partial數(shù)組被overflow,那么這個(gè)循環(huán)將會(huì)同樣溢出放在上邊的pages數(shù)組。因此pages數(shù)組的內(nèi)容將會(huì)被改寫為0,而不是先前的指向pages結(jié)構(gòu)的指針。
當(dāng)這些完成后,控制權(quán)返回到vmsplice_to_page()-溢出并不足以覆蓋返回地址。針對(duì)splice_to_pipe()的調(diào)用目前看來(lái)要結(jié)束了,但是一些有趣的事情發(fā)生了。在這個(gè)function的開始,有一個(gè)test:
    if (!pipe->readers) {
        send_sig(SIGPIPE, current, 0);
        if (!ret)
            ret = -EPIPE;
        break;
    }
如果我們看攻擊代碼的話,我們會(huì)看到
        if (pipe(pi) < 0) die("pipe", errno);
        close(pi[0]);
在調(diào)用vmsplice()之前,已經(jīng)將pipe的讀取端關(guān)閉了。因此splice_to_pipe將會(huì)立即退出,然而在退出時(shí),將會(huì)執(zhí)行如下操作:
    while (page_nr < spd_pages)
        page_cache_release(spd->pages[page_nr++]);
我們知道get_user_pages()函數(shù)的調(diào)用將會(huì)lock內(nèi)存中的相關(guān)頁(yè),以便允許內(nèi)核對(duì)其進(jìn)行訪問(wèn);上邊這兩行是一段清理代碼用來(lái)返回并unlock先前鎖住而目前不再使用的pages。但是在我們這個(gè)例子中,pages數(shù)組的內(nèi)容已經(jīng)被改寫為0。那么接下來(lái)發(fā)生的事情,將會(huì)是內(nèi)核欺騙(kernel oops),因?yàn)閜ages數(shù)組中填充的內(nèi)容并不是合法的地址。溢出代碼通過(guò)一些小方法,比如使用一些特定的mmap()調(diào)用,將會(huì)在內(nèi)存地址的底部構(gòu)造任意的內(nèi)容。
當(dāng)運(yùn)行在內(nèi)核模式,直接去取指向用戶空間的指針的值盡管可能會(huì)造成很多問(wèn)題,但是確實(shí)可以被忍受的。如果地址是有效的并且相關(guān)也駐留內(nèi)存當(dāng)中,那么直接的取值也是能夠成功的。因此當(dāng)kernel開始工作在他以為是指向struct page空間的指針的內(nèi)存時(shí),并沒(méi)有得到任何的錯(cuò)誤提示;而是得到了通過(guò)exploit程序所構(gòu)造的數(shù)據(jù)內(nèi)容。
kernle 一般情況下將每頁(yè)page看為個(gè)體。但是在有些時(shí)候,或有多個(gè)page組成的集合,被稱為”compound pages”.這種情況發(fā)生在一段被kernel所需要的連續(xù)的空間的大小大于一個(gè)page的大小時(shí);當(dāng)這種調(diào)用發(fā)生時(shí),一組compound pages被傳遞給調(diào)用者。比較特別的地方是,他們?cè)诒会尫艜r(shí),是會(huì)被拆分開,因此就會(huì)有拆分的動(dòng)作發(fā)生。因此compound pages會(huì)有一個(gè)普通pages所沒(méi)有的屬性:當(dāng)pages被釋放時(shí),會(huì)調(diào)用destructor。
我們來(lái)看一下攻擊程序中是如何設(shè)置low-memory page structures的:
    pages[0]->flags    = 1 << PG_compound;
    pages[0]->private  = (unsigned long) pages[0];
    pages[0]->count    = 1;
    pages[1]->lru.next = (long) kernel_code;
當(dāng)內(nèi)核在用戶空間的0位置開始尋找page structure時(shí),將會(huì)發(fā)現(xiàn)該page structure是組compound page.  destructor(存放在第2個(gè)page 結(jié)構(gòu)中的lru.next)所指向的是一段先前在exploit代碼中定義的kernel_code()。因?yàn)閏ount被設(shè)置為1,因此執(zhí)行page_cache_release()(會(huì)將count值減1)將會(huì)得出沒(méi)有剩余的指針了,而這段page看起來(lái)像一段compound page,destructor將會(huì)被調(diào)用。這時(shí),存放在kernel_code位置的任意代碼就可以在內(nèi)核狀態(tài)運(yùn)行。

論壇徽章:
0
2 [報(bào)告]
發(fā)表于 2009-05-21 21:17 |只看該作者
頂~~~~
您需要登錄后才可以回帖 登錄 | 注冊(cè)

本版積分規(guī)則 發(fā)表回復(fù)

  

北京盛拓優(yōu)訊信息技術(shù)有限公司. 版權(quán)所有 京ICP備16024965號(hào)-6 北京市公安局海淀分局網(wǎng)監(jiān)中心備案編號(hào):11010802020122 niuxiaotong@pcpop.com 17352615567
未成年舉報(bào)專區(qū)
中國(guó)互聯(lián)網(wǎng)協(xié)會(huì)會(huì)員  聯(lián)系我們:huangweiwei@itpub.net
感謝所有關(guān)心和支持過(guò)ChinaUnix的朋友們 轉(zhuǎn)載本站內(nèi)容請(qǐng)注明原作者名及出處

清除 Cookies - ChinaUnix - Archiver - WAP - TOP