aboutsummaryrefslogtreecommitdiff
path: root/gcc/testsuite/gcc.dg/plugin/infoleak-CVE-2017-18550-1.c
blob: 449348a1017f828ae8dbcffed8fc528e3f980243 (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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
/* "An issue was discovered in drivers/scsi/aacraid/commctrl.c in the 
   Linux kernel before 4.13. There is potential exposure of kernel stack
   memory because aac_get_hba_info does not initialize the hbainfo structure."

   Fixed e.g. by 342ffc26693b528648bdc9377e51e4f2450b4860 on linux-4.13.y
   in linux-stable.

   This is a simplified version of that code (before and after the fix). */

/* { dg-do compile } */
/* { dg-options "-fanalyzer" } */
/* { dg-require-effective-target analyzer } */
/* { dg-skip-if "structure layout assumption not met" { default_packed } } */

#include <string.h>

typedef unsigned int __u32;
typedef unsigned int u32;
typedef unsigned char u8;

#include "test-uaccess.h"

/* Adapted from include/uapi/linux/types.h  */

#define __bitwise
typedef __u32 __bitwise __le32;

/* Adapted from drivers/scsi/aacraid/aacraid.h  */

struct aac_hba_info {

	u8	driver_name[50]; /* { dg-message "field 'driver_name' is uninitialized \\(50 bytes\\)" } */
	u8	adapter_number;
	u8	system_io_bus_number;
	u8	device_number; /* { dg-message "padding after field 'device_number' is uninitialized \\(3 bytes\\)" } */
	u32	function_number;
	u32	vendor_id;
	u32	device_id;
	u32	sub_vendor_id;
	u32	sub_system_id;
	u32	mapped_base_address_size; /* { dg-message "field 'mapped_base_address_size' is uninitialized \\(4 bytes\\)"  } */
	u32	base_physical_address_high_part;
	u32	base_physical_address_low_part;

	u32	max_command_size;
	u32	max_fib_size;
	u32	max_scatter_gather_from_os;
	u32	max_scatter_gather_to_fw;
	u32	max_outstanding_fibs;

	u32	queue_start_threshold;
	u32	queue_dump_threshold;
	u32	max_io_size_queued;
	u32	outstanding_io;

	u32	firmware_build_number;
	u32	bios_build_number;
	u32	driver_build_number;
	u32	serial_number_high_part;
	u32	serial_number_low_part;
	u32	supported_options;
	u32	feature_bits;
	u32	currentnumber_ports;

	u8	new_comm_interface:1; /* { dg-message "field 'new_comm_interface' is uninitialized \\(1 bit\\)" } */
	u8	new_commands_supported:1;
	u8	disable_passthrough:1;
	u8	expose_non_dasd:1;
	u8	queue_allowed:1;
	u8	bled_check_enabled:1;
	u8	reserved1:1;
	u8	reserted2:1;

	u32	reserved3[10]; /* { dg-message "field 'reserved3' is uninitialized \\(40 bytes\\)" } */

};

struct aac_dev
{
	/* [...snip...] */
	int			id;
	/* [...snip...] */
	struct pci_dev		*pdev;		/* Our PCI interface */
	/* [...snip...] */
};

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

struct pci_dev {
	/* [...snip...] */
	struct pci_bus	*bus;		/* bus this device is on */
	/* [...snip...] */
	unsigned int	devfn;		/* encoded device & function index */
	unsigned short	vendor;
	unsigned short	device;
	unsigned short	subsystem_vendor;
	unsigned short	subsystem_device;
	/* [...snip...] */
};

struct pci_bus {
	/* [...snip...] */
	unsigned char	number;		/* bus number */
	/* [...snip...] */
};

/* Adapted from drivers/scsi/aacraid/commctrl.c  */

static int aac_get_hba_info(struct aac_dev *dev, void __user *arg)
{
	struct aac_hba_info hbainfo; /* { dg-message "region created on stack here" "memspace message" } */
	/* { dg-message "capacity: 200 bytes" "capacity message" { target *-*-* } .-1 } */

	hbainfo.adapter_number		= (u8) dev->id;
	hbainfo.system_io_bus_number	= dev->pdev->bus->number;
	hbainfo.device_number		= (dev->pdev->devfn >> 3);
	hbainfo.function_number		= (dev->pdev->devfn & 0x0007);

	hbainfo.vendor_id		= dev->pdev->vendor;
	hbainfo.device_id		= dev->pdev->device;
	hbainfo.sub_vendor_id		= dev->pdev->subsystem_vendor;
	hbainfo.sub_system_id		= dev->pdev->subsystem_device;

	if (copy_to_user(arg, &hbainfo, sizeof(struct aac_hba_info))) { /* { dg-warning "potential exposure of sensitive information by copying uninitialized data from stack" "warning" } */
		/* { dg-message "177 bytes are uninitialized" "how much" { target *-*-* } .-1 } */
		/* [...snip...] */
	}

	return 0;
}

static int aac_get_hba_info_fixed(struct aac_dev *dev, void __user *arg)
{
	struct aac_hba_info hbainfo;

	memset(&hbainfo, 0, sizeof(hbainfo));
	hbainfo.adapter_number		= (u8) dev->id;
	hbainfo.system_io_bus_number	= dev->pdev->bus->number;
	hbainfo.device_number		= (dev->pdev->devfn >> 3);
	hbainfo.function_number		= (dev->pdev->devfn & 0x0007);

	hbainfo.vendor_id		= dev->pdev->vendor;
	hbainfo.device_id		= dev->pdev->device;
	hbainfo.sub_vendor_id		= dev->pdev->subsystem_vendor;
	hbainfo.sub_system_id		= dev->pdev->subsystem_device;

	if (copy_to_user(arg, &hbainfo, sizeof(struct aac_hba_info))) { /* { dg-bogus "" } */
		/* [...snip...] */
	}

	return 0;
}

/* An alternate fix using "= {0}" rather than memset.  */

static int aac_get_hba_info_fixed_alt(struct aac_dev *dev, void __user *arg)
{
	struct aac_hba_info hbainfo = {0};

	memset(&hbainfo, 0, sizeof(hbainfo));
	hbainfo.adapter_number		= (u8) dev->id;
	hbainfo.system_io_bus_number	= dev->pdev->bus->number;
	hbainfo.device_number		= (dev->pdev->devfn >> 3);
	hbainfo.function_number		= (dev->pdev->devfn & 0x0007);

	hbainfo.vendor_id		= dev->pdev->vendor;
	hbainfo.device_id		= dev->pdev->device;
	hbainfo.sub_vendor_id		= dev->pdev->subsystem_vendor;
	hbainfo.sub_system_id		= dev->pdev->subsystem_device;

	if (copy_to_user(arg, &hbainfo, sizeof(struct aac_hba_info))) { /* { dg-bogus "" } */
		/* [...snip...] */
	}

	return 0;
}