<span id="7ztzv"></span>
<sub id="7ztzv"></sub>

<span id="7ztzv"></span><form id="7ztzv"></form>

<span id="7ztzv"></span>

        <address id="7ztzv"></address>

            原文地址:http://drops.wooyun.org/papers/13127

            0x00 背景


            眾所周知,現代操作系統為了安全和統籌硬件的原因,采用了一套非常復雜的管理內存的方式,并由此產生了物理地址,邏輯地址,虛擬地址等概念。這部分內容不負累述,簡單來說如下圖

            p1

            kernel與用戶態進程擁有不同的邏輯地址空間,kernel所在的頁面擁有更高的權限,用戶權限是不可以隨意更改的,否則豈不是可以改掉自己的權限,為所欲為。

            p2

            不過這也不是完全密不透風的墻,內核提供了多種途徑供用戶態交流數據。其中如果需要在短時間內交換大量數據,并且有實時的要求,linux kernel 提供了一種簡單有效的方式:共享內存——mmap syscall。

            原理也非常簡單,映射給kernel的物理頁面也同樣映射一份給用戶進程,并且修改掉權限屬性。這樣的話分屬不同地址空間的兩塊內存實際上對應的是同一個物理頁面,一方修改數據,另一方也能夠實時看到變化。

            p3

            一般的應用場景是在嵌入式設備的外設中,比如要實施刷新LED顯示屏,實施記錄大量傳感器數據,等。這需要開發人員在自己的驅動程序和用戶代碼中同時實現mmap的邏輯才能夠實現。

            首先,在自定義的驅動文件中要提供這樣的接口函數:

            p4

            內核函數remap_pfn_range()會根據需求映射頁面進用戶進程。

            詳見:http://www.makelinux.net/ldd3/chp-15-sect-2

            隨后在用戶程序中簡單掉用這個自定義的mmap函數就可以建立起頁面映射,達到共享內存的目的了。

            0x01 漏洞


            越是簡單好用的,就越容易出現問題。

            函數remap_pfn_range()并不會檢查傳入的參數,它會完全按照需求的內存起始位置,所需長度,訪問權限,去映射頁面進用戶態。所有這些檢查都需要自定義的驅動中實現的mmap函數去完成。

            上面的截圖是官方文檔中給出的例子,當然不能用這段代碼直接用到產品中!

            比如如下的這個產品實現:
            https://github.com/rajamalw/galaxy-s5360/blob/master/modules/drivers/video/hantro/ldriver/kernel_26x/hx170dec.c

            #!cpp
            /*------------------------------------------------------------------------------
                Function name   : hx170dec_mmap
                Description     : mmap method
                Return type     : int
            ------------------------------------------------------------------------------*/
            static int hx170dec_mmap(struct file *file, struct vm_area_struct *vma)
            {
                if (vma->vm_end - vma->vm_start >
                    ((DEC_IO_SIZE + PAGE_SIZE - 1) & PAGE_MASK))
                    return -EINVAL;
            
                vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
                /* Remap-pfn-range will mark the range VM_IO and VM_RESERVED */
                if (remap_pfn_range(vma,
                            vma->vm_start,
                            (DEC_IO_BASE >> PAGE_SHIFT),
                            vma->vm_end - vma->vm_start, vma->vm_page_prot)) {
                    pr_err("%s(): remap_pfn_range() failed\n", __FUNCTION__);
                    return -EINVAL;
                }
            
                return 0;
            }
            

            只是稍微對申請的長度做了檢查,其他的理所當然地相信了用戶代碼。

            造成的后果很嚴重:

            我們再來看一個比較好的例子:
            https://github.com/nirodg/android_device_huawei_hwp7/blob/master/kernel/huawei/hwp7/drivers/hik3/g1dec/hx170dec.c

            #!cpp
            static int hx170dec_mmap(struct file *file, struct vm_area_struct *vma)
            {
                unsigned long start = vma->vm_start;
                unsigned long size = vma->vm_end - vma->vm_start;
                int retval = 0;
            
                unsigned long pyhs_start = vma->vm_pgoff << PAGE_SHIFT;
                unsigned long pyhs_end = pyhs_start + size;
                if(!(pyhs_start >= hisi_reserved_codec_phymem//not codec memory
                        && pyhs_end <= hisi_reserved_codec_phymem + HISI_MEM_CODEC_SIZE)
                    && !(pyhs_start >= hx170dec_data.iobaseaddr//not io address
                        && pyhs_end <= hx170dec_data.iobaseaddr + hx170dec_data.iosize)) {
                    printk(KERN_ERR "%s(%d) failed map:0x%lx-0x%lx\n", __FUNCTION__, __LINE__, pyhs_start, pyhs_end);
                    return -EFAULT;
                }
                /* make buffers write-thru cacheable */
            
                vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
                if (remap_pfn_range(vma, start, vma->vm_pgoff, size, vma->vm_page_prot))
                    retval = -ENOBUFS;
            
                return retval;
            }
            

            在調用remap_pfn_range函數之前做了諸多檢查,限制了申請地址的起始和結束位置。

            0x02 其他


            android系統的整體安全架構是很繁復龐大的,上文中出現的漏洞如果發生在某個驅動中是不能單獨被利用提權的。因為其他應用沒有權限去訪問這個有問題的驅動。但是如果這個驅動的訪問權限再出錯,比如:

            P5

            那么連續的犯錯下來,對于攻擊者來說,就真的是666了。

            0x03 結語


            本文所討論的安全問題在某廠商的設備中經常出現,并且時間跨度長達幾年,希望貴廠能夠提高安全意識,加班趕工的同時也注意下代碼質量。

            <span id="7ztzv"></span>
            <sub id="7ztzv"></sub>

            <span id="7ztzv"></span><form id="7ztzv"></form>

            <span id="7ztzv"></span>

                  <address id="7ztzv"></address>

                      亚洲欧美在线