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;
}
|