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 (!is_user_data(expr
))
45 if (!get_user_rl(expr
, &rl
))
51 static int bytes_to_end_of_struct(struct expression
*expr
)
53 struct expression
*deref
;
58 if (expr
->type
== EXPR_PREOP
&& expr
->op
== '&')
59 expr
= strip_parens(expr
->unop
);
61 type
= get_type(expr
);
62 if (!type
|| type
->type
!= SYM_ARRAY
)
65 if (expr
->type
!= EXPR_DEREF
|| !expr
->member
)
68 if (deref
->type
== EXPR_PREOP
&& deref
->op
== '*')
70 struct_bytes
= get_array_size_bytes_max(deref
);
71 if (struct_bytes
<= 0) {
72 type
= get_type(expr
->deref
);
73 struct_bytes
= type_bytes(type
);
75 offset
= get_member_offset_from_deref(expr
);
78 return struct_bytes
- expr
->member_offset
;
81 static int size_of_union(struct expression
*expr
)
85 if (expr
->type
!= EXPR_PREOP
|| expr
->op
!= '&')
87 expr
= strip_parens(expr
->unop
);
88 if (expr
->type
!= EXPR_DEREF
|| !expr
->member
)
91 type
= get_type(expr
);
92 if (!type
|| type
->type
!= SYM_UNION
)
94 return type_bytes(type
);
97 static int is_likely_multiple(int has
, int needed
, struct expression
*limit
)
101 limit
= strip_parens(limit
);
102 if (limit
->type
!= EXPR_BINOP
|| limit
->op
!= '*')
104 if (!get_value(limit
->left
, &mult
))
106 if (has
* mult
.value
== needed
)
108 if (!get_value(limit
->right
, &mult
))
110 if (has
* mult
.value
== needed
)
116 static int name_in_union(struct symbol
*type
, const char *name
)
120 if (type
->type
== SYM_NODE
)
121 type
= get_real_base_type(type
);
122 if (!type
|| type
->type
!= SYM_UNION
)
125 FOR_EACH_PTR(type
->symbol_list
, tmp
) {
127 strcmp(name
, tmp
->ident
->name
) == 0)
129 } END_FOR_EACH_PTR(tmp
);
134 static int ends_on_struct_member_boundary(struct expression
*expr
, int needed
)
136 struct symbol
*type
, *tmp
;
141 expr
= strip_expr(expr
);
142 if (expr
->type
== EXPR_PREOP
&& expr
->op
== '&') {
143 expr
= strip_parens(expr
->unop
);
145 type
= get_type(expr
);
146 if (!type
|| type
->type
!= SYM_ARRAY
)
149 if (expr
->type
!= EXPR_DEREF
|| !expr
->member
)
152 type
= get_type(expr
->unop
);
155 if (type
->type
== SYM_UNION
) {
156 struct expression
*unop
= strip_expr(expr
->unop
);
158 if (unop
->type
!= EXPR_DEREF
)
160 type
= get_type(unop
->unop
);
164 if (type
->type
!= SYM_STRUCT
)
168 FOR_EACH_PTR(type
->symbol_list
, tmp
) {
171 strcmp(expr
->member
->name
, tmp
->ident
->name
) == 0) ||
172 name_in_union(tmp
, expr
->member
->name
))
175 if (!type
->ctype
.attribute
->is_packed
)
176 offset
= ALIGN(offset
, tmp
->ctype
.alignment
);
178 offset
+= type_bytes(tmp
);
179 size
= type_bytes(tmp
);
183 /* if there is a hole then fail. */
184 if (!type
->ctype
.attribute
->is_packed
&&
185 offset
!= ALIGN(offset
, tmp
->ctype
.alignment
))
187 offset
+= type_bytes(tmp
);
188 size
+= type_bytes(tmp
);
194 } END_FOR_EACH_PTR(tmp
);
198 static int is_one_element_array(struct expression
*expr
)
203 if (expr
->type
== EXPR_PREOP
&& expr
->op
== '&')
205 if (expr
->type
== EXPR_BINOP
) /* array elements foo[5] */
208 type
= get_type(expr
);
211 if (!type
|| type
->type
!= SYM_ARRAY
)
214 if (!get_implied_value(type
->array_size
, &sval
))
222 static int is_ignored_struct(struct expression
*expr
)
226 type
= get_type(expr
);
229 if (type
->type
== SYM_PTR
)
230 type
= get_real_base_type(type
);
231 if (type
->type
!= SYM_STRUCT
)
235 if (list_has_string(ignored_structs
, type
->ident
->name
))
240 static void match_limited(const char *fn
, struct expression
*expr
, void *_limiter
)
242 struct limiter
*limiter
= (struct limiter
*)_limiter
;
243 struct expression
*dest
;
244 struct expression
*limit
;
245 char *dest_name
= NULL
;
249 dest
= get_argument_from_call_expr(expr
->args
, limiter
->buf_arg
);
250 limit
= get_argument_from_call_expr(expr
->args
, limiter
->limit_arg
);
251 if (!get_the_max(limit
, &needed
))
253 has
= get_array_size_bytes_max(dest
);
256 if (has
>= needed
.value
)
259 if (needed
.value
== bytes_to_end_of_struct(dest
))
262 if (needed
.value
<= size_of_union(dest
))
265 if (is_likely_multiple(has
, needed
.value
, limit
))
268 if (ends_on_struct_member_boundary(dest
, needed
.value
))
271 if (is_one_element_array(dest
))
274 if (is_ignored_struct(dest
))
277 dest_name
= expr_to_str(dest
);
278 sm_msg("error: %s() '%s' too small (%d vs %s)", fn
, dest_name
, has
, sval_to_str(needed
));
279 free_string(dest_name
);
282 static void register_funcs_from_file(void)
288 struct limiter
*limiter
;
290 snprintf(name
, 256, "%s.sizeof_param", option_project_str
);
292 token
= get_tokens_file(name
);
295 if (token_type(token
) != TOKEN_STREAMBEGIN
)
298 while (token_type(token
) != TOKEN_STREAMEND
) {
299 if (token_type(token
) != TOKEN_IDENT
)
301 func
= show_ident(token
->ident
);
304 if (token_type(token
) != TOKEN_NUMBER
)
306 size
= atoi(token
->number
);
309 if (token_type(token
) != TOKEN_NUMBER
)
311 buf
= atoi(token
->number
);
313 limiter
= malloc(sizeof(*limiter
));
314 limiter
->limit_arg
= size
;
315 limiter
->buf_arg
= buf
;
317 add_function_hook(func
, &match_limited
, limiter
);
324 static void register_ignored_structs_from_file(void)
328 const char *struct_type
;
330 snprintf(name
, 256, "%s.ignore_memcpy_struct_overflows", option_project_str
);
332 token
= get_tokens_file(name
);
335 if (token_type(token
) != TOKEN_STREAMBEGIN
)
338 while (token_type(token
) != TOKEN_STREAMEND
) {
339 if (token_type(token
) != TOKEN_IDENT
)
342 struct_type
= show_ident(token
->ident
);
343 insert_string(&ignored_structs
, alloc_string(struct_type
));
350 void check_memcpy_overflow(int id
)
352 register_funcs_from_file();
353 register_ignored_structs_from_file();
354 add_function_hook("memcmp", &match_limited
, &b0_l2
);
355 add_function_hook("memcmp", &match_limited
, &b1_l2
);
356 if (option_project
== PROJ_KERNEL
) {
357 add_function_hook("copy_to_user", &match_limited
, &b1_l2
);
358 add_function_hook("_copy_to_user", &match_limited
, &b1_l2
);
359 add_function_hook("__copy_to_user", &match_limited
, &b1_l2
);
360 add_function_hook("copy_from_user", &match_limited
, &b0_l2
);
361 add_function_hook("_copy_from_user", &match_limited
, &b0_l2
);
362 add_function_hook("__copy_from_user", &match_limited
, &b0_l2
);