units: move checks to check_ file and hide under the --spammy option
[smatch.git] / check_memcpy_overflow.c
blob577db67aeea360fd3672d36fb2a23a70e5805506
1 /*
2 * Copyright (C) 2010 Dan Carpenter.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
18 #include <stdlib.h>
19 #include "parse.h"
20 #include "smatch.h"
21 #include "smatch_slist.h"
22 #include "smatch_extra.h"
24 struct limiter {
25 int buf_arg;
26 int limit_arg;
28 static struct limiter b0_l2 = {0, 2};
29 static struct limiter b1_l2 = {1, 2};
31 static struct string_list *ignored_structs;
33 static int get_the_max(struct expression *expr, sval_t *sval)
35 struct range_list *rl;
37 if (get_hard_max(expr, sval))
38 return 1;
39 if (!option_spammy)
40 return 0;
41 if (get_fuzzy_max(expr, sval))
42 return 1;
43 if (!get_user_rl(expr, &rl))
44 return 0;
45 *sval = rl_max(rl);
46 return 1;
49 static int bytes_to_end_of_struct(struct expression *expr)
51 struct expression *deref;
52 struct symbol *type;
53 int struct_bytes;
54 int offset;
56 if (expr->type == EXPR_PREOP && expr->op == '&')
57 expr = strip_parens(expr->unop);
58 else {
59 type = get_type(expr);
60 if (!type || type->type != SYM_ARRAY)
61 return 0;
63 if (expr->type != EXPR_DEREF || !expr->member)
64 return 0;
65 deref = expr->deref;
66 if (deref->type == EXPR_PREOP && deref->op == '*')
67 deref = deref->unop;
68 struct_bytes = get_array_size_bytes_max(deref);
69 if (struct_bytes <= 0) {
70 type = get_type(expr->deref);
71 struct_bytes = type_bytes(type);
73 offset = get_member_offset_from_deref(expr);
74 if (offset <= 0)
75 return 0;
76 return struct_bytes - expr->member_offset;
79 static int size_of_union(struct expression *expr)
81 struct symbol *type;
83 if (expr->type != EXPR_PREOP || expr->op != '&')
84 return 0;
85 expr = strip_parens(expr->unop);
86 if (expr->type != EXPR_DEREF || !expr->member)
87 return 0;
88 expr = expr->unop;
89 type = get_type(expr);
90 if (!type || type->type != SYM_UNION)
91 return 0;
92 return type_bytes(type);
95 static int is_likely_multiple(int has, int needed, struct expression *limit)
97 sval_t mult;
99 limit = strip_parens(limit);
100 if (limit->type != EXPR_BINOP || limit->op != '*')
101 return 0;
102 if (!get_value(limit->left, &mult))
103 return 0;
104 if (has * mult.value == needed)
105 return 1;
106 if (!get_value(limit->right, &mult))
107 return 0;
108 if (has * mult.value == needed)
109 return 1;
111 return 0;
114 static int name_in_union(struct symbol *type, const char *name)
116 struct symbol *tmp;
118 if (type->type == SYM_NODE)
119 type = get_real_base_type(type);
120 if (!type || type->type != SYM_UNION)
121 return 0;
123 FOR_EACH_PTR(type->symbol_list, tmp) {
124 if (tmp->ident &&
125 strcmp(name, tmp->ident->name) == 0)
126 return 1;
127 } END_FOR_EACH_PTR(tmp);
129 return 0;
132 static int ends_on_struct_member_boundary(struct expression *expr, int needed)
134 struct symbol *type, *tmp;
135 int offset;
136 int size;
137 int found = 0;
139 expr = strip_expr(expr);
140 if (expr->type == EXPR_PREOP && expr->op == '&') {
141 expr = strip_parens(expr->unop);
142 } else {
143 type = get_type(expr);
144 if (!type || type->type != SYM_ARRAY)
145 return 0;
147 if (expr->type != EXPR_DEREF || !expr->member)
148 return 0;
150 type = get_type(expr->unop);
151 if (!type)
152 return 0;
153 if (type->type == SYM_UNION) {
154 struct expression *unop = strip_expr(expr->unop);
156 if (unop->type != EXPR_DEREF)
157 return 0;
158 type = get_type(unop->unop);
159 if (!type)
160 return 0;
162 if (type->type != SYM_STRUCT)
163 return 0;
165 offset = 0;
166 FOR_EACH_PTR(type->symbol_list, tmp) {
167 if (!found) {
168 if ((tmp->ident &&
169 strcmp(expr->member->name, tmp->ident->name) == 0) ||
170 name_in_union(tmp, expr->member->name))
171 found = 1;
173 offset = ALIGN(offset, tmp->ctype.alignment);
175 offset += type_bytes(tmp);
176 size = type_bytes(tmp);
177 continue;
180 /* if there is a hole then fail. */
181 if (offset != ALIGN(offset, tmp->ctype.alignment))
182 return 0;
183 offset += type_bytes(tmp);
184 size += type_bytes(tmp);
186 if (size == needed)
187 return 1;
188 if (size > needed)
189 return 0;
190 } END_FOR_EACH_PTR(tmp);
191 return 0;
194 static int is_one_element_array(struct expression *expr)
196 struct symbol *type;
197 sval_t sval;
199 if (expr->type == EXPR_PREOP && expr->op == '&')
200 expr = expr->unop;
201 if (expr->type == EXPR_BINOP) /* array elements foo[5] */
202 return 0;
204 type = get_type(expr);
205 if (!type)
206 return 0;
207 if (!type || type->type != SYM_ARRAY)
208 return 0;
210 if (!get_implied_value(type->array_size, &sval))
211 return 0;
213 if (sval.value == 1)
214 return 1;
215 return 0;
218 static int is_ignored_struct(struct expression *expr)
220 struct symbol *type;
222 type = get_type(expr);
223 if (!type)
224 return 0;
225 if (type->type == SYM_PTR)
226 type = get_real_base_type(type);
227 if (type->type != SYM_STRUCT)
228 return 0;
229 if (!type->ident)
230 return 0;
231 if (list_has_string(ignored_structs, type->ident->name))
232 return 1;
233 return 0;
236 static bool is_marked_unsafe(struct expression *expr)
238 char *macro;
240 macro = get_macro_name(expr->pos);
241 if (!macro)
242 return false;
243 return strcmp(macro, "unsafe_memcpy") == 0;
246 static void match_limited(const char *fn, struct expression *expr, void *_limiter)
248 struct limiter *limiter = (struct limiter *)_limiter;
249 struct expression *dest;
250 struct expression *limit;
251 char *dest_name = NULL;
252 sval_t needed;
253 int has;
255 dest = get_argument_from_call_expr(expr->args, limiter->buf_arg);
256 limit = get_argument_from_call_expr(expr->args, limiter->limit_arg);
257 if (!get_the_max(limit, &needed))
258 return;
259 has = get_array_size_bytes_max(dest);
260 if (!has)
261 return;
262 if (has >= needed.value)
263 return;
265 if (needed.value == bytes_to_end_of_struct(dest))
266 return;
268 if (needed.value <= size_of_union(dest))
269 return;
271 if (is_likely_multiple(has, needed.value, limit))
272 return;
274 if (ends_on_struct_member_boundary(dest, needed.value))
275 return;
277 if (is_one_element_array(dest))
278 return;
280 if (buf_comp_has_bytes(dest, limit))
281 return;
283 if (is_ignored_struct(dest))
284 return;
286 if (is_marked_unsafe(dest))
287 return;
289 dest_name = expr_to_str(dest);
290 sm_error("%s() '%s' too small (%d vs %s)", fn, dest_name, has, sval_to_str(needed));
291 free_string(dest_name);
294 static void register_funcs_from_file(void)
296 char name[256];
297 struct token *token;
298 const char *func;
299 int size, buf;
300 struct limiter *limiter;
302 snprintf(name, 256, "%s.sizeof_param", option_project_str);
303 name[255] = '\0';
304 token = get_tokens_file(name);
305 if (!token)
306 return;
307 if (token_type(token) != TOKEN_STREAMBEGIN)
308 return;
309 token = token->next;
310 while (token_type(token) != TOKEN_STREAMEND) {
311 if (token_type(token) != TOKEN_IDENT)
312 break;
313 func = show_ident(token->ident);
315 token = token->next;
316 if (token_type(token) != TOKEN_NUMBER)
317 break;
318 size = atoi(token->number);
320 token = token->next;
321 if (token_type(token) == TOKEN_SPECIAL) {
322 if (token->special != '-')
323 break;
324 token = token->next;
325 if (token_type(token) != TOKEN_NUMBER)
326 break;
327 token = token->next;
328 continue;
331 if (token_type(token) != TOKEN_NUMBER)
332 break;
333 buf = atoi(token->number);
335 limiter = malloc(sizeof(*limiter));
336 limiter->limit_arg = size;
337 limiter->buf_arg = buf;
339 add_function_hook(func, &match_limited, limiter);
341 token = token->next;
343 if (token_type(token) != TOKEN_STREAMEND)
344 sm_perror("parsing '%s'", name);
345 clear_token_alloc();
348 static void register_ignored_structs_from_file(void)
350 char name[256];
351 struct token *token;
352 const char *struct_type;
354 snprintf(name, 256, "%s.ignore_memcpy_struct_overflows", option_project_str);
355 name[255] = '\0';
356 token = get_tokens_file(name);
357 if (!token)
358 return;
359 if (token_type(token) != TOKEN_STREAMBEGIN)
360 return;
361 token = token->next;
362 while (token_type(token) != TOKEN_STREAMEND) {
363 if (token_type(token) != TOKEN_IDENT)
364 return;
366 struct_type = show_ident(token->ident);
367 insert_string(&ignored_structs, alloc_string(struct_type));
369 token = token->next;
371 clear_token_alloc();
374 void check_memcpy_overflow(int id)
376 register_funcs_from_file();
377 register_ignored_structs_from_file();
378 add_function_hook("memcmp", &match_limited, &b0_l2);
379 add_function_hook("memcmp", &match_limited, &b1_l2);
380 if (option_project == PROJ_KERNEL) {
381 add_function_hook("copy_to_user", &match_limited, &b1_l2);
382 add_function_hook("_copy_to_user", &match_limited, &b1_l2);
383 add_function_hook("__copy_to_user", &match_limited, &b1_l2);
384 add_function_hook("copy_from_user", &match_limited, &b0_l2);
385 add_function_hook("_copy_from_user", &match_limited, &b0_l2);
386 add_function_hook("__copy_from_user", &match_limited, &b0_l2);