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 offset
= ALIGN(offset
, tmp
->ctype
.alignment
);
175 offset
+= type_bytes(tmp
);
176 size
= type_bytes(tmp
);
180 /* if there is a hole then fail. */
181 if (offset
!= ALIGN(offset
, tmp
->ctype
.alignment
))
183 offset
+= type_bytes(tmp
);
184 size
+= type_bytes(tmp
);
190 } END_FOR_EACH_PTR(tmp
);
194 static int is_one_element_array(struct expression
*expr
)
199 if (expr
->type
== EXPR_PREOP
&& expr
->op
== '&')
201 if (expr
->type
== EXPR_BINOP
) /* array elements foo[5] */
204 type
= get_type(expr
);
207 if (!type
|| type
->type
!= SYM_ARRAY
)
210 if (!get_implied_value(type
->array_size
, &sval
))
218 static int is_ignored_struct(struct expression
*expr
)
222 type
= get_type(expr
);
225 if (type
->type
== SYM_PTR
)
226 type
= get_real_base_type(type
);
227 if (type
->type
!= SYM_STRUCT
)
231 if (list_has_string(ignored_structs
, type
->ident
->name
))
236 static void match_limited(const char *fn
, struct expression
*expr
, void *_limiter
)
238 struct limiter
*limiter
= (struct limiter
*)_limiter
;
239 struct expression
*dest
;
240 struct expression
*limit
;
241 char *dest_name
= NULL
;
245 dest
= get_argument_from_call_expr(expr
->args
, limiter
->buf_arg
);
246 limit
= get_argument_from_call_expr(expr
->args
, limiter
->limit_arg
);
247 if (!get_the_max(limit
, &needed
))
249 has
= get_array_size_bytes_max(dest
);
252 if (has
>= needed
.value
)
255 if (needed
.value
== bytes_to_end_of_struct(dest
))
258 if (needed
.value
<= size_of_union(dest
))
261 if (is_likely_multiple(has
, needed
.value
, limit
))
264 if (ends_on_struct_member_boundary(dest
, needed
.value
))
267 if (is_one_element_array(dest
))
270 if (is_ignored_struct(dest
))
273 dest_name
= expr_to_str(dest
);
274 sm_error("%s() '%s' too small (%d vs %s)", fn
, dest_name
, has
, sval_to_str(needed
));
275 free_string(dest_name
);
278 static void register_funcs_from_file(void)
284 struct limiter
*limiter
;
286 snprintf(name
, 256, "%s.sizeof_param", option_project_str
);
288 token
= get_tokens_file(name
);
291 if (token_type(token
) != TOKEN_STREAMBEGIN
)
294 while (token_type(token
) != TOKEN_STREAMEND
) {
295 if (token_type(token
) != TOKEN_IDENT
)
297 func
= show_ident(token
->ident
);
300 if (token_type(token
) != TOKEN_NUMBER
)
302 size
= atoi(token
->number
);
305 if (token_type(token
) == TOKEN_SPECIAL
) {
306 if (token
->special
!= '-')
309 if (token_type(token
) != TOKEN_NUMBER
)
315 if (token_type(token
) != TOKEN_NUMBER
)
317 buf
= atoi(token
->number
);
319 limiter
= malloc(sizeof(*limiter
));
320 limiter
->limit_arg
= size
;
321 limiter
->buf_arg
= buf
;
323 add_function_hook(func
, &match_limited
, limiter
);
327 if (token_type(token
) != TOKEN_STREAMEND
)
328 sm_perror("parsing '%s'", name
);
332 static void register_ignored_structs_from_file(void)
336 const char *struct_type
;
338 snprintf(name
, 256, "%s.ignore_memcpy_struct_overflows", option_project_str
);
340 token
= get_tokens_file(name
);
343 if (token_type(token
) != TOKEN_STREAMBEGIN
)
346 while (token_type(token
) != TOKEN_STREAMEND
) {
347 if (token_type(token
) != TOKEN_IDENT
)
350 struct_type
= show_ident(token
->ident
);
351 insert_string(&ignored_structs
, alloc_string(struct_type
));
358 void check_memcpy_overflow(int id
)
360 register_funcs_from_file();
361 register_ignored_structs_from_file();
362 add_function_hook("memcmp", &match_limited
, &b0_l2
);
363 add_function_hook("memcmp", &match_limited
, &b1_l2
);
364 if (option_project
== PROJ_KERNEL
) {
365 add_function_hook("copy_to_user", &match_limited
, &b1_l2
);
366 add_function_hook("_copy_to_user", &match_limited
, &b1_l2
);
367 add_function_hook("__copy_to_user", &match_limited
, &b1_l2
);
368 add_function_hook("copy_from_user", &match_limited
, &b0_l2
);
369 add_function_hook("_copy_from_user", &match_limited
, &b0_l2
);
370 add_function_hook("__copy_from_user", &match_limited
, &b0_l2
);