xorl %eax, %eax

CVE-2011-0521: Linux kernel av7110 DVB Invalid Array Index Value

with 2 comments

This vulnerability was discovered by Tavis Ormandy and it was reported to Kees Cook. The buggy code is part of drivers/media/dvb/ttpci/av7110_ca.c source code file which implements routines for av7110 based DVB. More specifically, the susceptible code is part of the IOCTL handler function of the discussed device driver which is shown below.

static int dvb_ca_ioctl(struct file *file, unsigned int cmd, void *parg)
{
        struct dvb_device *dvbdev = file->private_data;
        struct av7110 *av7110 = dvbdev->priv;
        unsigned long arg = (unsigned long) parg;

        dprintk(8, "av7110:%p\n",av7110);

        switch (cmd) {
    ...
        case CA_GET_SLOT_INFO:
        {
                ca_slot_info_t *info=(ca_slot_info_t *)parg;

                if (info->num > 1)
                        return -EINVAL;
                av7110->ci_slot[info->num].num = info->num;
                av7110->ci_slot[info->num].type = FW_CI_LL_SUPPORT(av7110->arm_app) ?
                                                        CA_CI_LINK : CA_CI;
                memcpy(info, &av7110->ci_slot[info->num], sizeof(ca_slot_info_t));
                break;
        }
    ...
        return 0;
}

Using the above IOCTL command a user could initialize a ‘ca_slot_info_t’ structure which is defined at the include/linux/dvb/ca.h header file like this:

/* slot interface types and info */

typedef struct ca_slot_info {
        int num;               /* slot number */

        int type;              /* CA interface this slot supports */
#define CA_CI            1     /* CI high level interface */
#define CA_CI_LINK       2     /* CI link layer level interface */
#define CA_CI_PHYS       4     /* CI physical layer level interface */
#define CA_DESCR         8     /* built-in descrambler */
#define CA_SC          128     /* simple smart card interface */

        unsigned int flags;
#define CA_CI_MODULE_PRESENT 1 /* module (or card) inserted */
#define CA_CI_MODULE_READY   2
} ca_slot_info_t;

Since the slot number ‘num’ is a signed integer and it is only checked for being greater than one, a user could pass a negative value that will result in writing to arbitrary kernel memory when this is used as an index value to the ‘av7110->ci_slot[]’ array which is defined at drivers/media/dvb/ttpci/av7110.h with a static value.

/* place to store all the necessary device information */
struct av7110 {

        /* devices */

        struct dvb_device       dvb_dev;
    ...
        /* CA */

        ca_slot_info_t          ci_slot[2];
    ...
        int (*fe_set_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
};

The fix to this bug was the following patch.

                ca_slot_info_t *info=(ca_slot_info_t *)parg;
 
-               if (info->num > 1)
+               if (info->num < 0 || info->num > 1)
                        return -EINVAL;

Which checks the ‘info->num’ for not being negative as well as being greater than one.

Written by xorl

January 30, 2011 at 01:17

Posted in bugs, linux

2 Responses

Subscribe to comments with RSS.

  1. In such cases, the condition in the if statement is always extended with a “not lower than zero” check. Would it not be nicer, to define the variable unsigned?

    axtaxt

    January 31, 2011 at 19:30

  2. I totally agree with you at having ‘num’ as an unsigned integer.
    However, I don’t have good knowledge of the av7110 implementation. There might be cases where ‘num’ contains negative values on errorneous situations (although I’m finding this quite unlikely).

    xorl

    January 31, 2011 at 20:35


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