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
21 #include "smatch_slist.h"
22 #include "smatch_extra.h"
28 static struct limiter b0_l2
= {0, 2};
29 static struct limiter b1_l2
= {1, 2};
31 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
))
41 if (get_fuzzy_max(expr
, sval
))
43 if (!get_user_rl(expr
, &rl
))
49 static int bytes_to_end_of_struct(struct expression
*expr
)
51 struct expression
*deref
;
56 if (expr
->type
== EXPR_PREOP
&& expr
->op
== '&')
57 expr
= strip_parens(expr
->unop
);
59 type
= get_type(expr
);
60 if (!type
|| type
->type
!= SYM_ARRAY
)
63 if (expr
->type
!= EXPR_DEREF
|| !expr
->member
)
66 if (deref
->type
== EXPR_PREOP
&& deref
->op
== '*')
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
);
76 return struct_bytes
- expr
->member_offset
;
79 static int size_of_union(struct expression
*expr
)
83 if (expr
->type
!= EXPR_PREOP
|| expr
->op
!= '&')
85 expr
= strip_parens(expr
->unop
);
86 if (expr
->type
!= EXPR_DEREF
|| !expr
->member
)
89 type
= get_type(expr
);
90 if (!type
|| type
->type
!= SYM_UNION
)
92 return type_bytes(type
);
95 static int is_likely_multiple(int has
, int needed
, struct expression
*limit
)
99 limit
= strip_parens(limit
);
100 if (limit
->type
!= EXPR_BINOP
|| limit
->op
!= '*')
102 if (!get_value(limit
->left
, &mult
))
104 if (has
* mult
.value
== needed
)
106 if (!get_value(limit
->right
, &mult
))
108 if (has
* mult
.value
== needed
)
114 static int name_in_union(struct symbol
*type
, const char *name
)
118 if (type
->type
== SYM_NODE
)
119 type
= get_real_base_type(type
);
120 if (!type
|| type
->type
!= SYM_UNION
)
123 FOR_EACH_PTR(type
->symbol_list
, tmp
) {
125 strcmp(name
, tmp
->ident
->name
) == 0)
127 } END_FOR_EACH_PTR(tmp
);
132 static int ends_on_struct_member_boundary(struct expression
*expr
, int needed
)
134 struct symbol
*type
, *tmp
;
139 expr
= strip_expr(expr
);
140 if (expr
->type
== EXPR_PREOP
&& expr
->op
== '&') {
141 expr
= strip_parens(expr
->unop
);
143 type
= get_type(expr
);
144 if (!type
|| type
->type
!= SYM_ARRAY
)
147 if (expr
->type
!= EXPR_DEREF
|| !expr
->member
)
150 type
= get_type(expr
->unop
);
153 if (type
->type
== SYM_UNION
) {
154 struct expression
*unop
= strip_expr(expr
->unop
);
156 if (unop
->type
!= EXPR_DEREF
)
158 type
= get_type(unop
->unop
);
162 if (type
->type
!= SYM_STRUCT
)
166 FOR_EACH_PTR(type
->symbol_list
, tmp
) {
169 strcmp(expr
->member
->name
, tmp
->ident
->name
) == 0) ||
170 name_in_union(tmp
, expr
->member
->name
))
173 if (!type
->ctype
.attribute
->is_packed
)
174 offset
= ALIGN(offset
, tmp
->ctype
.alignment
);
176 offset
+= type_bytes(tmp
);
177 size
= type_bytes(tmp
);
181 /* if there is a hole then fail. */
182 if (!type
->ctype
.attribute
->is_packed
&&
183 offset
!= ALIGN(offset
, tmp
->ctype
.alignment
))
185 offset
+= type_bytes(tmp
);
186 size
+= type_bytes(tmp
);
192 } END_FOR_EACH_PTR(tmp
);
196 static int is_one_element_array(struct expression
*expr
)
201 if (expr
->type
== EXPR_PREOP
&& expr
->op
== '&')
203 if (expr
->type
== EXPR_BINOP
) /* array elements foo[5] */
206 type
= get_type(expr
);
209 if (!type
|| type
->type
!= SYM_ARRAY
)
212 if (!get_implied_value(type
->array_size
, &sval
))
220 static int is_ignored_struct(struct expression
*expr
)
224 type
= get_type(expr
);
227 if (type
->type
== SYM_PTR
)
228 type
= get_real_base_type(type
);
229 if (type
->type
!= SYM_STRUCT
)
233 if (list_has_string(ignored_structs
, type
->ident
->name
))
238 static void match_limited(const char *fn
, struct expression
*expr
, void *_limiter
)
240 struct limiter
*limiter
= (struct limiter
*)_limiter
;
241 struct expression
*dest
;
242 struct expression
*limit
;
243 char *dest_name
= NULL
;
247 dest
= get_argument_from_call_expr(expr
->args
, limiter
->buf_arg
);
248 limit
= get_argument_from_call_expr(expr
->args
, limiter
->limit_arg
);
249 if (!get_the_max(limit
, &needed
))
251 has
= get_array_size_bytes_max(dest
);
254 if (has
>= needed
.value
)
257 if (needed
.value
== bytes_to_end_of_struct(dest
))
260 if (needed
.value
<= size_of_union(dest
))
263 if (is_likely_multiple(has
, needed
.value
, limit
))
266 if (ends_on_struct_member_boundary(dest
, needed
.value
))
269 if (is_one_element_array(dest
))
272 if (is_ignored_struct(dest
))
275 dest_name
= expr_to_str(dest
);
276 sm_msg("error: %s() '%s' too small (%d vs %s)", fn
, dest_name
, has
, sval_to_str(needed
));
277 free_string(dest_name
);
280 static void register_funcs_from_file(void)
286 struct limiter
*limiter
;
288 snprintf(name
, 256, "%s.sizeof_param", option_project_str
);
290 token
= get_tokens_file(name
);
293 if (token_type(token
) != TOKEN_STREAMBEGIN
)
296 while (token_type(token
) != TOKEN_STREAMEND
) {
297 if (token_type(token
) != TOKEN_IDENT
)
299 func
= show_ident(token
->ident
);
302 if (token_type(token
) != TOKEN_NUMBER
)
304 size
= atoi(token
->number
);
307 if (token_type(token
) == TOKEN_SPECIAL
) {
308 if (token
->special
!= '-')
311 if (token_type(token
) != TOKEN_NUMBER
)
317 if (token_type(token
) != TOKEN_NUMBER
)
319 buf
= atoi(token
->number
);
321 limiter
= malloc(sizeof(*limiter
));
322 limiter
->limit_arg
= size
;
323 limiter
->buf_arg
= buf
;
325 add_function_hook(func
, &match_limited
, limiter
);
329 if (token_type(token
) != TOKEN_STREAMEND
)
330 printf("internal: error parsing '%s'\n", name
);
334 static void register_ignored_structs_from_file(void)
338 const char *struct_type
;
340 snprintf(name
, 256, "%s.ignore_memcpy_struct_overflows", option_project_str
);
342 token
= get_tokens_file(name
);
345 if (token_type(token
) != TOKEN_STREAMBEGIN
)
348 while (token_type(token
) != TOKEN_STREAMEND
) {
349 if (token_type(token
) != TOKEN_IDENT
)
352 struct_type
= show_ident(token
->ident
);
353 insert_string(&ignored_structs
, alloc_string(struct_type
));
360 void check_memcpy_overflow(int id
)
362 register_funcs_from_file();
363 register_ignored_structs_from_file();
364 add_function_hook("memcmp", &match_limited
, &b0_l2
);
365 add_function_hook("memcmp", &match_limited
, &b1_l2
);
366 if (option_project
== PROJ_KERNEL
) {
367 add_function_hook("copy_to_user", &match_limited
, &b1_l2
);
368 add_function_hook("_copy_to_user", &match_limited
, &b1_l2
);
369 add_function_hook("__copy_to_user", &match_limited
, &b1_l2
);
370 add_function_hook("copy_from_user", &match_limited
, &b0_l2
);
371 add_function_hook("_copy_from_user", &match_limited
, &b0_l2
);
372 add_function_hook("__copy_from_user", &match_limited
, &b0_l2
);