xorl %eax, %eax

CVE-2010-3078: Linux kernel XFS IOCTL 12-Bytes Information Leak

leave a comment »

This vulnerability was reported and fixed by Dan Rosenberg as we can read in this email to xfs-masters mailing list. Specifically, here is the buggy code as seen at fs/xfs/linux-2.6/xfs_ioctl.c of 2.6.35 release of the Linux kernel…

STATIC int
xfs_ioc_fsgetxattr(
        xfs_inode_t             *ip,
        int                     attr,
        void                    __user *arg)
{
        struct fsxattr          fa;
       ...
        fa.fsx_xflags = xfs_ip2xflags(ip);
        fa.fsx_extsize = ip->i_d.di_extsize << ip->i_mount->m_sb.sb_blocklog;
        fa.fsx_projid = ip->i_d.di_projid;
       ...
                        fa.fsx_nextents = ip->i_d.di_nextents;

       ...
        if (copy_to_user(arg, &fa, sizeof(fa)))
                return -EFAULT;
        return 0;
}

For convenience, here is the ‘fsxattr’ structure as it is defined in fs/xfs/xfs_fs.h:

/*
 * Structure for XFS_IOC_FSGETXATTR[A] and XFS_IOC_FSSETXATTR.
 */
#ifndef HAVE_FSXATTR
struct fsxattr {
        __u32           fsx_xflags;     /* xflags field value (get/set) */
        __u32           fsx_extsize;    /* extsize field value (get/set)*/
        __u32           fsx_nextents;   /* nextents field value (get)   */
        __u32           fsx_projid;     /* project identifier (get/set) */
        unsigned char   fsx_pad[12];
};
#endif

Back to xfs_ioc_fsgetxattr() we can see that all of the members are initialized properly apart from the padding of the structure which is an array of 12 Bytes named ‘fsx_pad’. Since xfs_ioc_fsgetxattr() is using its stack to store the ‘fsxattr’ structure, the memory will be uninitialized and thus the subsequent copy to userspace using copy_to_user() will result in leaking 12-Bytes of unitialized memory to userspace.
To make things even better, this code could be easily reached through an IOCTL call as you can read at fs/xfs/linux-2.6/xfs_ioctl.c:

long
xfs_file_ioctl(
        struct file             *filp,
        unsigned int            cmd,
        unsigned long           p)
{
        struct inode            *inode = filp->f_path.dentry->d_inode;
        struct xfs_inode        *ip = XFS_I(inode);
        struct xfs_mount        *mp = ip->i_mount;
        void                    __user *arg = (void __user *)p;
        int                     ioflags = 0;
        int                     error;
       ...
        switch (cmd) {
       ...
        case XFS_IOC_FSGETXATTRA:
                return xfs_ioc_fsgetxattr(ip, 1, arg);
       ...
}

Clearly, to fix this vulnerability the patch was to simply zero out the structure before using it using memset() like this:

        struct fsxattr          fa;

+       memset(&fa, 0, sizeof(struct fsxattr));
+
        xfs_ilock(ip, XFS_ILOCK_SHARED);

Written by xorl

September 13, 2010 at 23:14

Posted in bugs, linux

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 )

Twitter picture

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

Facebook photo

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

Google+ photo

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

Connecting to %s