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
|
/* Verify that -Wanalyzer-exposure-through-uninit-copy doesn't get confused
if size argument to copy_to_user is an upper bound, rather than a
constant. */
/* { dg-do compile } */
/* { dg-options "-fanalyzer" } */
/* { dg-require-effective-target analyzer } */
#include "../analyzer/analyzer-decls.h"
typedef __SIZE_TYPE__ size_t;
#include "test-uaccess.h"
typedef unsigned __INT32_TYPE__ u32;
/* min_t adapted from include/linux/kernel.h. */
#define min_t(type, x, y) ({ \
type __min1 = (x); \
type __min2 = (y); \
__min1 < __min2 ? __min1: __min2; })
struct st
{
u32 a;
u32 b;
};
/* Verify that we cope with min_t. */
void test_1_full_init (void __user *dst, u32 x, u32 y, unsigned long in_sz)
{
struct st s;
s.a = x;
s.b = y;
unsigned long copy_sz = min_t(unsigned long, in_sz, sizeof(s));
copy_to_user(dst, &s, copy_sz); /* { dg-bogus "exposure" } */
}
void test_1_partial_init (void __user *dst, u32 x, u32 y, unsigned long in_sz)
{
struct st s;
s.a = x;
/* s.y not initialized. */
unsigned long copy_sz = min_t(unsigned long, in_sz, sizeof(s));
copy_to_user(dst, &s, copy_sz); /* { dg-warning "exposure" } */
}
/* Constant on LHS rather than RHS. */
void test_2_full_init (void __user *dst, u32 x, u32 y, unsigned long in_sz)
{
struct st s;
s.a = x;
s.b = y;
unsigned long copy_sz = min_t(unsigned long, sizeof(s), in_sz);
copy_to_user(dst, &s, copy_sz); /* { dg-bogus "exposure" } */
}
void test_2_partial_init (void __user *dst, u32 x, u32 y, unsigned long in_sz)
{
struct st s;
s.a = x;
/* s.y not initialized. */
unsigned long copy_sz = min_t(unsigned long, sizeof(s), in_sz);
copy_to_user(dst, &s, copy_sz); /* { dg-warning "exposure" } */
}
/* min_t with various casts. */
void test_3_full_init (void __user *dst, u32 x, u32 y, int in_sz)
{
struct st s;
s.a = x;
s.b = y;
int copy_sz = min_t(unsigned int, in_sz, sizeof(s));
copy_to_user(dst, &s, copy_sz); /* { dg-bogus "exposure" } */
}
void test_3_partial_init (void __user *dst, u32 x, u32 y, int in_sz)
{
struct st s;
s.a = x;
/* s.y not initialized. */
int copy_sz = min_t(unsigned int, in_sz, sizeof(s));
copy_to_user(dst, &s, copy_sz); /* { dg-warning "exposure" } */
}
/* Comparison against an upper bound. */
void test_4_full_init (void __user *dst, u32 x, u32 y, size_t in_sz)
{
struct st s;
s.a = x;
s.b = y;
size_t copy_sz = in_sz;
if (copy_sz > sizeof(s))
copy_sz = sizeof(s);
copy_to_user(dst, &s, copy_sz); /* { dg-bogus "exposure" } */
}
void test_4_partial_init (void __user *dst, u32 x, u32 y, size_t in_sz)
{
struct st s;
s.a = x;
/* s.y not initialized. */
size_t copy_sz = in_sz;
if (copy_sz > sizeof(s))
copy_sz = sizeof(s);
copy_to_user(dst, &s, copy_sz); /* { dg-warning "exposure" } */
}
/* Comparison against an upper bound with casts. */
void test_5_full_init (void __user *dst, u32 x, u32 y, int in_sz)
{
struct st s;
s.a = x;
s.b = y;
int copy_sz = in_sz;
if (copy_sz > sizeof(s))
copy_sz = sizeof(s);
copy_to_user(dst, &s, copy_sz); /* { dg-bogus "exposure" } */
}
/* Comparison against an upper bound with casts. */
void test_5_partial_init (void __user *dst, u32 x, u32 y, int in_sz)
{
struct st s;
s.a = x;
/* s.y not initialized. */
int copy_sz = in_sz;
if (copy_sz > sizeof(s))
copy_sz = sizeof(s);
copy_to_user(dst, &s, copy_sz); /* { dg-warning "exposure" "" } */
}
|