xorl %eax, %eax

CVE-2008-3531: FreeBSD mount(2) and nmount(2) Local Buffer Overflow

with 2 comments

This is one of my personally favourite bugs since it is hilarious for kernel code. The bug was found by James Gritton and affects FreeBSD 7.0-RELEASE as well as FreeBSD 7.0-STABLE. I believe everyone is familiar with those two system calls (mount and nmount) which can be enabled to unprivileged users simply by executing:

# sysctl vfs.usermount=1

The following code was taken from FreeBSD 7.0-RELEASE. The vulnerable code is located at src/sys/kern/vfs_mount.c, in function vfs_filteropt(). This function is used to parse the options and detect any unknown ones.

1800 int
1801 vfs_filteropt(struct vfsoptlist *opts, const char **legal)
1802 {
1803         struct vfsopt *opt;
1804         char errmsg[255];
1805         const char **t, *p, *q;
1806         int ret = 0;

Various parsing takes place in this function, but the most important part is this one:

1808         TAILQ_FOREACH(opt, opts, link) {
1809                 p = opt->name;
1823                 for(t = legal; *t != NULL; t++) {
1824                         if (strcmp(*t, p) == 0)
1825                                 break;
1831                 if (*t != NULL)
1832                         continue;
1833                 sprintf(errmsg, "mount option <%s> is unknown", p);
1834                 printf("%s\n", errmsg);
1835                 ret = EINVAL;

Yeah! Don’t start laughing… This is an sprintf overflow inside FreeBSD’s kernel. Let’s take this down a little bit. First of all, p contains the option name and t contains the argument of the legal option characters that we may have. The loop at line 1823 checks each one of them using a for loop. If t is nor NULL neither one of the list that legal has, then it throws out this error with p (aka. the option name). Of course, before printing them out, it copies it to a buffer (errmsg) at the stack using sprintf!!! As you can see at line 1804, errmsg is just a buffer of 255 bytes size!

This is probably the most straightforward kernel level bug I saw on 2008. Oh.. yea, how can this function be reached?
All of the mount()/nmount() functions for each filesystem supported natively by the FreeBSD kernel have somewhere a call similar to:

static int
my_super_fs_mount(struct mount *mp, /* more args from user*/ )
 ... doing stuff ...

 if (vfs_filteropt(mp->optnew, my_super_fs_options))
        return EINVAL;

 ... do more stuff ...</span>

Which is commonly used as a wrapper to mount() for filesystem specific additional tasks. If you think that this function isn’t being called by every *fs_mount, then check this out:

function: hpfs_mount()
at line: 106
location: fs/hpfs/hpfs_vfsops.c

function: msdosfs_mount()
at line: 235
location: fs/msdosfs/msdosfs_vfsops.c

function: ntfs_mount()
at line: 151
location: fs/ntfs/ntfs_vfsops.c

function: portal_mount()
at line: 93
location: fs/portalfs/portal_vfsops.c

function: smbfs_mount()
at line: 145
location: fs/smbfs/smbfs_vfsops.c

Also at CODA, TMPFS, EXT2, XFS, VFS, FFS and NFS. So, yeah.. It’s a really great vulnerability in my opinion. I’m not going to post any trigger code here since it is so damn ridiculously simple to do this. Even the exploitation is straightforward! Of course I know that FreeBSD kernel stack overflow exploitation are not the most simple thing in the world but maybe I’ll dedicate a separate post on this subject in the future.

Written by xorl

January 3, 2009 at 03:31

2 Responses

Subscribe to comments with RSS.

  1. Yes, a totally ridiculous bug. I have given a very thorough presentation last year on exploiting FreeBSD kernel stack overflows (currently only in greek unfortunately):


    Btw, nice blog. Keep up the good work.


    February 6, 2009 at 08:32

  2. First of all, thank you for your supportive comment. Now, regarding your presentation… I was there too. ;)


    February 7, 2009 at 08:03

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )


Connecting to %s