aboutsummaryrefslogtreecommitdiff
path: root/gcc/testsuite/gcc.dg/plugin/taint-CVE-2011-0521-1.c
blob: cde12b3b761ce331e7281a5469bd1b754045b880 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
/* { 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 > 1)
			return -EINVAL;
		av7110->ci_slot[info->num].num = info->num; /* { dg-warning "attacker-controlled value" "" { xfail *-*-* } } */
		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);
}