Print this page
11506 smatch resync
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/tools/smatch/src/check_string_len.c
+++ new/usr/src/tools/smatch/src/check_string_len.c
1 1 /*
2 2 * Copyright (C) 2013 Oracle.
3 3 *
4 4 * This program is free software; you can redistribute it and/or
5 5 * modify it under the terms of the GNU General Public License
6 6 * as published by the Free Software Foundation; either version 2
7 7 * of the License, or (at your option) any later version.
8 8 *
9 9 * This program is distributed in the hope that it will be useful,
10 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 * GNU General Public License for more details.
13 13 *
14 14 * You should have received a copy of the GNU General Public License
15 15 * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
16 16 */
17 17
18 18 /*
19 19 * This tries to find buffer overflows in sprintf().
20 20 * I'll freely admit that the code is sort of crap.
21 21 * Also if it sees "sprintf("%2d\n", x)" then it assumes x is less than 99.
22 22 * That might not be true so there maybe buffer overflows which are missed.
23 23 *
24 24 */
25 25
26 26 #include <ctype.h>
27 27 #include "smatch.h"
↓ open down ↓ |
27 lines elided |
↑ open up ↑ |
28 28
29 29 static int my_id;
30 30
31 31 struct param_info {
32 32 int buf_or_limit;
33 33 int string;
34 34 };
35 35
36 36 struct param_info zero_one = {0, 1};
37 37
38 -static int handle_format(struct expression *call, char **pp, int *arg_nr)
38 +static int handle_format(struct expression *call, char **pp, int *arg_nr, bool use_max)
39 39 {
40 40 struct expression *arg;
41 41 char *p = *pp;
42 42 int ret = 1;
43 43 char buf[256];
44 - sval_t max;
44 + sval_t sval;
45 45
46 46 p++; /* we passed it with *p == '%' */
47 47
48 48 if (*p == '%') {
49 49 p++;
50 50 ret = 1;
51 51 goto out_no_arg;
52 52 }
53 53 if (*p == 'c') {
54 54 p++;
55 55 ret = 1;
56 56 goto out;
57 57 }
58 58
59 59
60 60 if (isdigit(*p) || *p == '.') {
61 61 unsigned long num;
62 62
63 63 if (*p == '.')
64 64 p++;
65 65
66 66 num = strtoul(p, &p, 10);
67 67 ret = num;
68 68
69 69 while (*p == 'l')
70 70 p++;
71 71 p++; /* eat the 'd' char */
72 72 goto out;
73 73 }
74 74
75 75 if (*p == 'l') {
76 76 p++;
77 77 if (*p == 'l')
78 78 p++;
79 79 }
80 80
81 81 if (option_project == PROJ_KERNEL && *p == 'z')
82 82 p++;
83 83
84 84 if (option_project == PROJ_KERNEL && *p == 'p') {
85 85 if (*(p + 1) == 'I' || *(p + 1) == 'i') {
86 86 char *eye;
87 87
88 88 eye = p + 1;
89 89 p += 2;
90 90 if (*p == 'h' || *p == 'n' || *p == 'b' || *p == 'l')
91 91 p++;
92 92 if (*p == '4') {
93 93 p++;
94 94 ret = 15;
95 95 goto out;
96 96 }
97 97 if (*p == '6') {
98 98 p++;
99 99 if (*p == 'c')
100 100 p++;
101 101 if (*eye == 'I')
102 102 ret = 39;
103 103 if (*eye == 'i')
104 104 ret = 32;
105 105 goto out;
106 106 }
107 107 }
108 108 if (*(p + 1) == 'M') {
109 109 p += 2;
110 110 if (*p == 'R' || *p == 'F')
111 111 p++;
112 112 ret = 17;
113 113 goto out;
114 114 }
115 115 if (*(p + 1) == 'm') {
116 116 p += 2;
117 117 if (*p == 'R')
118 118 p++;
119 119 ret = 12;
120 120 goto out;
121 121 }
122 122 }
123 123
124 124 arg = get_argument_from_call_expr(call->args, *arg_nr);
125 125 if (!arg)
126 126 goto out;
127 127
128 128 if (*p == 's') {
129 129 ret = get_array_size_bytes(arg);
130 130 if (ret < 0)
131 131 ret = 1;
132 132 /* we don't print the NUL here */
133 133 ret--;
↓ open down ↓ |
79 lines elided |
↑ open up ↑ |
134 134 p++;
135 135 goto out;
136 136 }
137 137
138 138 if (*p != 'd' && *p != 'i' && *p != 'x' && *p != 'X' && *p != 'u' && *p != 'p') {
139 139 ret = 1;
140 140 p++;
141 141 goto out;
142 142 }
143 143
144 - get_absolute_max(arg, &max);
144 + if (use_max) {
145 + get_absolute_max(arg, &sval);
146 + } else {
147 + get_absolute_min(arg, &sval);
148 + if (sval_is_negative(sval))
149 + sval.value = 0;
150 + }
145 151
152 +
146 153 if (*p == 'x' || *p == 'X' || *p == 'p') {
147 - ret = snprintf(buf, sizeof(buf), "%llx", max.uvalue);
154 + ret = snprintf(buf, sizeof(buf), "%llx", sval.uvalue);
148 155 } else if (*p == 'u') {
149 - ret = snprintf(buf, sizeof(buf), "%llu", max.uvalue);
156 + ret = snprintf(buf, sizeof(buf), "%llu", sval.uvalue);
150 157 } else if (!expr_unsigned(arg)) {
151 158 sval_t min;
152 159 int tmp;
153 160
154 - ret = snprintf(buf, sizeof(buf), "%lld", max.value);
161 + ret = snprintf(buf, sizeof(buf), "%lld", sval.value);
155 162 get_absolute_min(arg, &min);
156 163 tmp = snprintf(buf, sizeof(buf), "%lld", min.value);
157 164 if (tmp > ret)
158 165 ret = tmp;
159 166 } else {
160 - ret = snprintf(buf, sizeof(buf), "%lld", max.value);
167 + ret = snprintf(buf, sizeof(buf), "%lld", sval.value);
161 168 }
162 169 p++;
163 170
164 171 out:
165 172 (*arg_nr)++;
166 173 out_no_arg:
167 174 *pp = p;
168 175 return ret;
169 176 }
170 177
171 -int get_formatted_string_size(struct expression *call, int arg)
178 +int get_formatted_string_size_helper(struct expression *call, int arg, bool use_max)
172 179 {
173 180 struct expression *expr;
174 181 char *p;
175 182 int count;
176 183
177 184 expr = get_argument_from_call_expr(call->args, arg);
178 185 if (!expr || expr->type != EXPR_STRING)
179 186 return -1;
180 187
181 188 arg++;
182 189 count = 0;
183 190 p = expr->string->data;
184 191 while (*p) {
185 192
186 193 if (*p == '%') {
187 - count += handle_format(call, &p, &arg);
194 + count += handle_format(call, &p, &arg, use_max);
188 195 } else if (*p == '\\') {
189 196 p++;
190 197 }else {
191 198 p++;
192 199 count++;
193 200 }
194 201 }
195 202
196 - count++; /* count the NUL terminator */
197 203 return count;
198 204 }
199 205
206 +int get_formatted_string_size(struct expression *call, int arg)
207 +{
208 + return get_formatted_string_size_helper(call, arg, true);
209 +}
210 +
211 +int get_formatted_string_min_size(struct expression *call, int arg)
212 +{
213 + return get_formatted_string_size_helper(call, arg, false);
214 +}
215 +
200 216 static void match_not_limited(const char *fn, struct expression *call, void *info)
201 217 {
202 218 struct param_info *params = info;
203 219 struct range_list *rl;
204 220 struct expression *dest;
205 221 struct expression *arg;
206 222 int buf_size, size;
207 223 int user = 0;
208 224 int i;
209 225 int offset = 0;
210 226
211 227 dest = get_argument_from_call_expr(call->args, params->buf_or_limit);
212 228 dest = strip_expr(dest);
213 229 if (dest->type == EXPR_BINOP && dest->op == '+') {
214 230 sval_t max;
215 231
216 232 if (get_hard_max(dest->right, &max))
↓ open down ↓ |
7 lines elided |
↑ open up ↑ |
217 233 offset = max.value;
218 234 dest = dest->left;
219 235 }
220 236
221 237
222 238 buf_size = get_array_size_bytes(dest);
223 239 if (buf_size <= 0)
224 240 return;
225 241
226 242 size = get_formatted_string_size(call, params->string);
227 - if (size <= 0)
243 + if (size < 0)
228 244 return;
229 245 if (size < offset)
230 246 size -= offset;
247 + size++; /* add the NULL terminator */
231 248 if (size <= buf_size)
232 249 return;
233 250
234 251 i = 0;
235 252 FOR_EACH_PTR(call->args, arg) {
236 253 if (i++ <= params->string)
237 254 continue;
238 255 if (get_user_rl(arg, &rl))
239 256 user = 1;
240 257 } END_FOR_EACH_PTR(arg);
241 258
242 259 sm_error("format string overflow. buf_size: %d length: %d%s",
243 260 buf_size, size, user ? " [user data]": "");
244 261 }
245 262
246 263 void check_string_len(int id)
247 264 {
248 265 my_id = id;
249 266 add_function_hook("sprintf", &match_not_limited, &zero_one);
250 267 }
251 268
↓ open down ↓ |
11 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX