[Full-disclosure] Advisory: FUSE: Filesystem in Userspace - Information Disclosure

From: Sven Tantau (sven_at_sven-tantau.de)
Date: 06/06/05

  • Next message: Sven Tantau: "[Full-disclosure] Advisory: FUSE: Filesystem in Userspace - Information Disclosure (version mixup update)"
    Date: Mon, 06 Jun 2005 09:09:09 +0200
    To: full-disclosure@lists.grok.org.uk
    
    

    Advisory: FUSE: Filesystem in Userspace - Information Disclosure

    Product: FUSE: Filesystem in Userspace
    Affected Version: 2.2.1(verified), other < 2.3.0 probably too
    Immune Version: 2.3.0
    OS affected: Linux 2.2, 2.2.1, 2.3-pre*, 2.3-rc1, 2.4.*, 2.6.*
                      (Linux < 2.2 is not vulnerable)
    Security-Risk: high
    Remote-Exploit: no
    Date: 03.06.2005
    Author: Sven Tantau - http://www.sven-tantau.de/
    Vendor-URL: http://sourceforge.net/projects/fuse
    Vendor-Status: informed, vendor released a fixed version
    Advisory-URL:
    http://www.sven-tantau.de/public_files/fuse/fuse_20050603.txt
    Exploit-URL: http://www.sven-tantau.de/public_files/fuse/memfs.c

    Product
    =======

    > From fuse/README

    FUSE (Filesystem in Userspace) is a simple interface for userspace
    programs to export a virtual filesystem to the linux kernel. FUSE
    also aims to provide a secure method for non privileged users to
    create and mount their own filesystem implementations.

    You can download the source code releases from

      http://sourceforge.net/projects/fuse

    Details
    =======

    kernel/file.c:
    static int fuse_readpage(struct file *file, struct page *page)
    {
            ....

            req->num_pages = 1;
            req->pages[0] = page;
            req->out.page_zeroing = 1;

            ....
    }

    kernel/dev.c:
    static int fuse_copy_pages(struct fuse_copy_state *cs, unsigned nbytes,
                               int zeroing)
    {
            unsigned i;
            struct fuse_req *req = cs->req;
            unsigned offset = req->page_offset;
            unsigned count = min(nbytes, (unsigned) PAGE_SIZE - offset);

            for (i = 0; i < req->num_pages && nbytes; i++) { // <--- nbytes
    can be 0
                    struct page *page = req->pages[i];
                    int err = fuse_copy_page(cs, page, offset, count, zeroing);
                    if (err)
                            return err;

                    nbytes -= count;
                    count = min(nbytes, (unsigned) PAGE_SIZE);
                    offset = 0;
            }
            return 0;
    }

    static inline int fuse_copy_page(struct fuse_copy_state *cs, struct page
    *page,
                                     unsigned offset, unsigned count, int zeroing)
    {
            if (page && zeroing && count < PAGE_SIZE) {
                    void *mapaddr = kmap_atomic(page, KM_USER1);
                    memset(mapaddr, 0, PAGE_SIZE);
                    kunmap_atomic(mapaddr, KM_USER1);
            }

            ....
    }

    Pages will not be zeroed if nbytes==0 which leads to
    information disclosure of previous page content. As those can contain
    sensitive data of other users (including root), risk is rated high.

    A proof of concept file system is available at:
    http://www.sven-tantau.de/public_files/fuse/memfs.c

    Workaround
    ==========

    rmmod fuse
    Install the patch or update to fuse-2.3.0.

    Patch
    =====

    Vendor (Miklos Szeredi) provided fix:

    Index: linux/fs/fuse/dev.c
    ===================================================================
    --- linux.orig/fs/fuse/dev.c 2005-06-01 12:22:08.000000000 +0200
    +++ linux/fs/fuse/dev.c 2005-06-02 11:10:08.000000000 +0200
    @@ -525,7 +525,7 @@ static int fuse_copy_pages(struct fuse_c
             unsigned offset = req->page_offset;
             unsigned count = min(nbytes, (unsigned) PAGE_SIZE - offset);

    - for (i = 0; i < req->num_pages && nbytes; i++) {
    + for (i = 0; i < req->num_pages && (nbytes || zeroing); i++) {
                     struct page *page = req->pages[i];
                     int err = fuse_copy_page(cs, page, offset, count, zeroing);
                     if (err)

    History
    =======

    2005-06-01 issue found by Sven Tantau
    2005-06-02 vendor contacted
    2005-06-02 quick vendor reaction with confirmation, patch and public
    disclosure
    2005-06-06 release of this advisory + exploit

    -- 
    Sven Tantau
    http://www.sven-tantau.de/  ***  http://www.beastiebytes.de/
    http://twe.sven-tantau.de/  ***  http://www.bewiso.de/
    _______________________________________________
    Full-Disclosure - We believe in it.
    Charter: http://lists.grok.org.uk/full-disclosure-charter.html
    Hosted and sponsored by Secunia - http://secunia.com/
    

  • Next message: Sven Tantau: "[Full-disclosure] Advisory: FUSE: Filesystem in Userspace - Information Disclosure (version mixup update)"

    Relevant Pages