/* { dg-do compile } */ // TODO: remove need for -fanalyzer-checker=taint here: /* { dg-options "-fanalyzer -fanalyzer-checker=taint" } */ /* { dg-require-effective-target analyzer } */ /* See notes in this header. */ #include "taint-CVE-2011-0521.h" /* Adapted from drivers/media/dvb/ttpci/av7110_ca.c */ 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; /* case CA_GET_SLOT_INFO: */ { ca_slot_info_t *info=(ca_slot_info_t *)parg; if (info->num < 0 || info->num > 1) return -EINVAL; av7110->ci_slot[info->num].num = info->num; /* { dg-bogus "attacker-controlled value" } */ 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)); } return 0; } static struct dvb_device dvbdev_ca = { .priv = NULL, /* [...snip...] */ .kernel_ioctl = dvb_ca_ioctl, }; /* Adapted from drivers/media/dvb/dvb-core/dvbdev.c */ static DEFINE_MUTEX(dvbdev_mutex); int dvb_usercopy(struct file *file, unsigned int cmd, unsigned long arg, int (*func)(struct file *file, unsigned int cmd, void *arg)) { char sbuf[128]; void *mbuf = NULL; void *parg = NULL; int err = -1; /* Copy arguments into temp kernel buffer */ switch (_IOC_DIR(cmd)) { case _IOC_NONE: /* * For this command, the pointer is actually an integer * argument. */ parg = (void *) arg; break; case _IOC_READ: /* some v4l ioctls are marked wrong ... */ case _IOC_WRITE: case (_IOC_WRITE | _IOC_READ): if (_IOC_SIZE(cmd) <= sizeof(sbuf)) { parg = sbuf; } else { /* too big to allocate from stack */ mbuf = kmalloc(_IOC_SIZE(cmd),GFP_KERNEL); if (NULL == mbuf) return -ENOMEM; parg = mbuf; } err = -EFAULT; if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd))) goto out; break; } /* call driver */ mutex_lock(&dvbdev_mutex); if ((err = func(file, cmd, parg)) == -ENOIOCTLCMD) err = -EINVAL; mutex_unlock(&dvbdev_mutex); if (err < 0) goto out; /* Copy results into user buffer */ switch (_IOC_DIR(cmd)) { case _IOC_READ: case (_IOC_WRITE | _IOC_READ): if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd))) err = -EFAULT; break; } out: kfree(mbuf); return err; } long dvb_generic_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct dvb_device *dvbdev = file->private_data; if (!dvbdev) return -ENODEV; if (!dvbdev->kernel_ioctl) return -EINVAL; return dvb_usercopy(file, cmd, arg, dvbdev->kernel_ioctl); }