aboutsummaryrefslogtreecommitdiff
path: root/gcc/testsuite/gcc.dg/plugin/infoleak-CVE-2014-1446-1.c
blob: 2726a9c0f3850f385f18f7753dedeff6d0822888 (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
116
117
/* "The yam_ioctl function in drivers/net/hamradio/yam.c in the Linux kernel
   before 3.12.8 does not initialize a certain structure member, which allows
   local users to obtain sensitive information from kernel memory by
   leveraging the CAP_NET_ADMIN capability for an SIOCYAMGCFG ioctl call."

   Fixed e.g. by e7834c71c2cacc621ddc64bd71f83ef2054f6539 on linux-3.12.y
   in linux-stable.  */

#include <string.h>

#include "test-uaccess.h"

/* Adapted from include/linux/yam.h  */

struct yamcfg {
	unsigned int mask;		/* Mask of commands */
	unsigned int iobase;	/* IO Base of COM port */
	unsigned int irq;		/* IRQ of COM port */
	unsigned int bitrate;	/* Bit rate of radio port */
	unsigned int baudrate;	/* Baud rate of the RS232 port */
	unsigned int txdelay;	/* TxDelay */
	unsigned int txtail;	/* TxTail */
	unsigned int persist;	/* Persistence */
	unsigned int slottime;	/* Slottime */
	unsigned int mode;		/* mode 0 (simp), 1(Dupl), 2(Dupl+delay) */
	unsigned int holddly;	/* PTT delay in FullDuplex 2 mode */
};

struct yamdrv_ioctl_cfg {
	int cmd; /* { dg-message "field 'cmd' is uninitialized \\(4 bytes\\)" } */
	struct yamcfg cfg;
};

/* Adapted from include/asm-generic/errno-base.h  */

#define	EFAULT		14	/* Bad address */

/* Adapted from drivers/net/hamradio/yam.c  */

struct yam_port {
	/* [...snip...] */

	int bitrate;
	int baudrate;
	int iobase;
	int irq;
	int dupmode;

	/* [...snip...] */

	int txd;				/* tx delay */
	int holdd;				/* duplex ptt delay */
	int txtail;				/* txtail delay */
	int slot;				/* slottime */
	int pers;				/* persistence */

	/* [...snip...] */
};

/* Broken version, leaving yi.cmd uninitialized.  */

static int yam_ioctl(/* [...snip...] */
		     void __user *dst, struct yam_port *yp)
{
	struct yamdrv_ioctl_cfg yi; /* { dg-message "region created on stack here" "memspace event" } */
	/* { dg-message "capacity: 48 bytes" "capacity event" { target *-*-* } .-1 } */

	/* [...snip...] */

	/* case SIOCYAMGCFG: */
		yi.cfg.mask = 0xffffffff;
		yi.cfg.iobase = yp->iobase;
		yi.cfg.irq = yp->irq;
		yi.cfg.bitrate = yp->bitrate;
		yi.cfg.baudrate = yp->baudrate;
		yi.cfg.mode = yp->dupmode;
		yi.cfg.txdelay = yp->txd;
		yi.cfg.holddly = yp->holdd;
		yi.cfg.txtail = yp->txtail;
		yi.cfg.persist = yp->pers;
		yi.cfg.slottime = yp->slot;
		if (copy_to_user(dst, &yi, sizeof(struct yamdrv_ioctl_cfg))) /* { dg-warning "potential exposure of sensitive information by copying uninitialized data from stack" "warning" } */
			/* { dg-message "4 bytes are uninitialized" "how much note" { target *-*-* } .-1 } */
			 return -EFAULT;
	/* [...snip...] */

	return 0;
}

/* Fixed version, with a memset.  */

static int yam_ioctl_fixed(/* [...snip...] */
			   void __user *dst, struct yam_port *yp)
{
	struct yamdrv_ioctl_cfg yi;

	/* [...snip...] */

	/* case SIOCYAMGCFG: */
		memset(&yi, 0, sizeof(yi));
		yi.cfg.mask = 0xffffffff;
		yi.cfg.iobase = yp->iobase;
		yi.cfg.irq = yp->irq;
		yi.cfg.bitrate = yp->bitrate;
		yi.cfg.baudrate = yp->baudrate;
		yi.cfg.mode = yp->dupmode;
		yi.cfg.txdelay = yp->txd;
		yi.cfg.holddly = yp->holdd;
		yi.cfg.txtail = yp->txtail;
		yi.cfg.persist = yp->pers;
		yi.cfg.slottime = yp->slot;
		if (copy_to_user(dst, &yi, sizeof(struct yamdrv_ioctl_cfg))) /* { dg-bogus "" } */
			 return -EFAULT;
	/* [...snip...] */

	return 0;
}