1 /*
2  * Copyright (C) 2010 Dan Carpenter.
3  *
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.
8  *
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.
13  *
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
16  */
17 
18 #include <stdlib.h>
19 #include "parse.h"
20 #include "smatch.h"
21 #include "smatch_slist.h"
22 #include "smatch_extra.h"
23 
24 struct limiter {
25 	int buf_arg;
26 	int limit_arg;
27 };
28 static struct limiter b0_l2 = {0, 2};
29 static struct limiter b1_l2 = {1, 2};
30 
31 struct string_list *ignored_structs;
32 
get_the_max(struct expression * expr,sval_t * sval)33 static int get_the_max(struct expression *expr, sval_t *sval)
34 {
35 	struct range_list *rl;
36 
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;
47 }
48 
bytes_to_end_of_struct(struct expression * expr)49 static int bytes_to_end_of_struct(struct expression *expr)
50 {
51 	struct expression *deref;
52 	struct symbol *type;
53 	int struct_bytes;
54 	int offset;
55 
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;
62 	}
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);
72 	}
73 	offset = get_member_offset_from_deref(expr);
74 	if (offset <= 0)
75 		return 0;
76 	return struct_bytes - expr->member_offset;
77 }
78 
size_of_union(struct expression * expr)79 static int size_of_union(struct expression *expr)
80 {
81 	struct symbol *type;
82 
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);
93 }
94 
is_likely_multiple(int has,int needed,struct expression * limit)95 static int is_likely_multiple(int has, int needed, struct expression *limit)
96 {
97 	sval_t mult;
98 
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;
110 
111 	return 0;
112 }
113 
name_in_union(struct symbol * type,const char * name)114 static int name_in_union(struct symbol *type, const char *name)
115 {
116 	struct symbol *tmp;
117 
118 	if (type->type == SYM_NODE)
119 		type = get_real_base_type(type);
120 	if (!type || type->type != SYM_UNION)
121 		return 0;
122 
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);
128 
129 	return 0;
130 }
131 
ends_on_struct_member_boundary(struct expression * expr,int needed)132 static int ends_on_struct_member_boundary(struct expression *expr, int needed)
133 {
134 	struct symbol *type, *tmp;
135 	int offset;
136 	int size;
137 	int found = 0;
138 
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;
146 	}
147 	if (expr->type != EXPR_DEREF || !expr->member)
148 		return 0;
149 
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);
155 
156 		if (unop->type != EXPR_DEREF)
157 			return 0;
158 		type = get_type(unop->unop);
159 		if (!type)
160 			return 0;
161 	}
162 	if (type->type != SYM_STRUCT)
163 		return 0;
164 
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;
172 
173 			offset = ALIGN(offset, tmp->ctype.alignment);
174 
175 			offset += type_bytes(tmp);
176 			size = type_bytes(tmp);
177 			continue;
178 		}
179 
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);
185 
186 		if (size == needed)
187 			return 1;
188 		if (size > needed)
189 			return 0;
190 	} END_FOR_EACH_PTR(tmp);
191 	return 0;
192 }
193 
is_one_element_array(struct expression * expr)194 static int is_one_element_array(struct expression *expr)
195 {
196 	struct symbol *type;
197 	sval_t sval;
198 
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;
203 
204 	type = get_type(expr);
205 	if (!type)
206 		return 0;
207 	if (!type || type->type != SYM_ARRAY)
208 		return 0;
209 
210 	if (!get_implied_value(type->array_size, &sval))
211 		return 0;
212 
213 	if (sval.value == 1)
214 		return 1;
215 	return 0;
216 }
217 
is_ignored_struct(struct expression * expr)218 static int is_ignored_struct(struct expression *expr)
219 {
220 	struct symbol *type;
221 
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;
234 }
235 
match_limited(const char * fn,struct expression * expr,void * _limiter)236 static void match_limited(const char *fn, struct expression *expr, void *_limiter)
237 {
238 	struct limiter *limiter = (struct limiter *)_limiter;
239 	struct expression *dest;
240 	struct expression *limit;
241 	char *dest_name = NULL;
242 	sval_t needed;
243 	int has;
244 
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))
248 		return;
249 	has = get_array_size_bytes_max(dest);
250 	if (!has)
251 		return;
252 	if (has >= needed.value)
253 		return;
254 
255 	if (needed.value == bytes_to_end_of_struct(dest))
256 		return;
257 
258 	if (needed.value <= size_of_union(dest))
259 		return;
260 
261 	if (is_likely_multiple(has, needed.value, limit))
262 		return;
263 
264 	if (ends_on_struct_member_boundary(dest, needed.value))
265 		return;
266 
267 	if (is_one_element_array(dest))
268 		return;
269 
270 	if (is_ignored_struct(dest))
271 		return;
272 
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);
276 }
277 
register_funcs_from_file(void)278 static void register_funcs_from_file(void)
279 {
280 	char name[256];
281 	struct token *token;
282 	const char *func;
283 	int size, buf;
284 	struct limiter *limiter;
285 
286 	snprintf(name, 256, "%s.sizeof_param", option_project_str);
287 	name[255] = '\0';
288 	token = get_tokens_file(name);
289 	if (!token)
290 		return;
291 	if (token_type(token) != TOKEN_STREAMBEGIN)
292 		return;
293 	token = token->next;
294 	while (token_type(token) != TOKEN_STREAMEND) {
295 		if (token_type(token) != TOKEN_IDENT)
296 			break;
297 		func = show_ident(token->ident);
298 
299 		token = token->next;
300 		if (token_type(token) != TOKEN_NUMBER)
301 			break;
302 		size = atoi(token->number);
303 
304 		token = token->next;
305 		if (token_type(token) == TOKEN_SPECIAL) {
306 			if (token->special != '-')
307 				break;
308 			token = token->next;
309 			if (token_type(token) != TOKEN_NUMBER)
310 				break;
311 			token = token->next;
312 			continue;
313 
314 		}
315 		if (token_type(token) != TOKEN_NUMBER)
316 			break;
317 		buf = atoi(token->number);
318 
319 		limiter = malloc(sizeof(*limiter));
320 		limiter->limit_arg = size;
321 		limiter->buf_arg = buf;
322 
323 		add_function_hook(func, &match_limited, limiter);
324 
325 		token = token->next;
326 	}
327 	if (token_type(token) != TOKEN_STREAMEND)
328 		sm_perror("parsing '%s'", name);
329 	clear_token_alloc();
330 }
331 
register_ignored_structs_from_file(void)332 static void register_ignored_structs_from_file(void)
333 {
334 	char name[256];
335 	struct token *token;
336 	const char *struct_type;
337 
338 	snprintf(name, 256, "%s.ignore_memcpy_struct_overflows", option_project_str);
339 	name[255] = '\0';
340 	token = get_tokens_file(name);
341 	if (!token)
342 		return;
343 	if (token_type(token) != TOKEN_STREAMBEGIN)
344 		return;
345 	token = token->next;
346 	while (token_type(token) != TOKEN_STREAMEND) {
347 		if (token_type(token) != TOKEN_IDENT)
348 			return;
349 
350 		struct_type = show_ident(token->ident);
351 		insert_string(&ignored_structs, alloc_string(struct_type));
352 
353 		token = token->next;
354 	}
355 	clear_token_alloc();
356 }
357 
check_memcpy_overflow(int id)358 void check_memcpy_overflow(int id)
359 {
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);
371 	}
372 }
373