xref: /illumos-gate/usr/src/tools/smatch/src/smatch_buf_comparison.c (revision efe51d0cc2398b9ac179568b63a44e4bf295b8e2)
1 /*
2  * Copyright (C) 2012 Oracle.
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 /*
19  * The point here is to store that a buffer has x bytes even if we don't know
20  * the value of x.
21  *
22  */
23 
24 #include "smatch.h"
25 #include "smatch_extra.h"
26 #include "smatch_slist.h"
27 
28 static int size_id;
29 static int link_id;
30 
31 /*
32  * There is a bunch of code which does this:
33  *
34  *     if (size)
35  *         foo = malloc(size);
36  *
37  * So if "size" is non-zero then the size of "foo" is size.  But really it's
38  * also true if size is zero.  It's just better to assume to not trample over
39  * the data that we have by merging &undefined states.
40  *
41  */
unmatched_state(struct sm_state * sm)42 static struct smatch_state *unmatched_state(struct sm_state *sm)
43 {
44 	return sm->state;
45 }
46 
merge_links(struct smatch_state * s1,struct smatch_state * s2)47 static struct smatch_state *merge_links(struct smatch_state *s1, struct smatch_state *s2)
48 {
49 	struct expression *expr1, *expr2;
50 
51 	expr1 = s1->data;
52 	expr2 = s2->data;
53 
54 	if (expr1 && expr2 && expr_equiv(expr1, expr2))
55 		return s1;
56 	return &merged;
57 }
58 
match_link_modify(struct sm_state * sm,struct expression * mod_expr)59 static void match_link_modify(struct sm_state *sm, struct expression *mod_expr)
60 {
61 	struct expression *expr;
62 	struct sm_state *tmp;
63 
64 	expr = sm->state->data;
65 	if (expr) {
66 		set_state_expr(size_id, expr, &undefined);
67 		set_state(link_id, sm->name, sm->sym, &undefined);
68 		return;
69 	}
70 
71 	FOR_EACH_PTR(sm->possible, tmp) {
72 		expr = tmp->state->data;
73 		if (expr)
74 			set_state_expr(size_id, expr, &undefined);
75 	} END_FOR_EACH_PTR(tmp);
76 	set_state(link_id, sm->name, sm->sym, &undefined);
77 }
78 
79 static const char *limit_map[] = {
80 	"byte_count",
81 	"elem_count",
82 	"elem_last",
83 	"used_count",
84 	"used_last",
85 };
86 
state_to_limit(struct smatch_state * state)87 int state_to_limit(struct smatch_state *state)
88 {
89 	int i;
90 
91 	if (!state || !state->data)
92 		return -1;
93 
94 	for (i = 0; i < ARRAY_SIZE(limit_map); i++) {
95 		if (strncmp(state->name, limit_map[i], strlen(limit_map[i])) == 0)
96 			return i + BYTE_COUNT;
97 	}
98 
99 	return -1;
100 }
101 
limit_type_str(unsigned int limit_type)102 const char *limit_type_str(unsigned int limit_type)
103 {
104 	if (limit_type - BYTE_COUNT >= ARRAY_SIZE(limit_map)) {
105 		sm_msg("internal: wrong size type %u", limit_type);
106 		return "unknown";
107 	}
108 
109 	return limit_map[limit_type - BYTE_COUNT];
110 }
111 
alloc_compare_size(int limit_type,struct expression * expr)112 static struct smatch_state *alloc_compare_size(int limit_type, struct expression *expr)
113 {
114 	struct smatch_state *state;
115 	char *name;
116 	char buf[256];
117 
118 	state = __alloc_smatch_state(0);
119 	expr = strip_expr(expr);
120 	name = expr_to_str(expr);
121 	snprintf(buf, sizeof(buf), "%s %s", limit_type_str(limit_type), name);
122 	state->name = alloc_sname(buf);
123 	free_string(name);
124 	state->data = expr;
125 	return state;
126 }
127 
bytes_per_element(struct expression * expr)128 static int bytes_per_element(struct expression *expr)
129 {
130 	struct symbol *type;
131 
132 	type = get_type(expr);
133 	if (!type)
134 		return 0;
135 
136 	if (type->type != SYM_PTR && type->type != SYM_ARRAY)
137 		return 0;
138 
139 	type = get_base_type(type);
140 	return type_bytes(type);
141 }
142 
db_save_type_links(struct expression * array,int type_limit,struct expression * size)143 static void db_save_type_links(struct expression *array, int type_limit, struct expression *size)
144 {
145 	const char *array_name;
146 
147 	array_name = get_data_info_name(array);
148 	if (!array_name)
149 		array_name = "";
150 	sql_insert_data_info(size, type_limit, array_name);
151 }
152 
match_alloc_helper(struct expression * pointer,struct expression * size)153 static void match_alloc_helper(struct expression *pointer, struct expression *size)
154 {
155 	struct expression *tmp;
156 	struct sm_state *sm;
157 	int limit_type = ELEM_COUNT;
158 	sval_t sval;
159 	int cnt = 0;
160 
161 	pointer = strip_expr(pointer);
162 	size = strip_expr(size);
163 	if (!size || !pointer)
164 		return;
165 
166 	while ((tmp = get_assigned_expr(size))) {
167 		size = strip_expr(tmp);
168 		if (cnt++ > 5)
169 			break;
170 	}
171 
172 	if (size->type == EXPR_BINOP && size->op == '*') {
173 		struct expression *mult_left, *mult_right;
174 
175 		mult_left = strip_expr(size->left);
176 		mult_right = strip_expr(size->right);
177 
178 		if (get_implied_value(mult_left, &sval) &&
179 		    sval.value == bytes_per_element(pointer))
180 			size = mult_right;
181 		else if (get_implied_value(mult_right, &sval) &&
182 		    sval.value == bytes_per_element(pointer))
183 			size = mult_left;
184 		else
185 			return;
186 	}
187 
188 	/* Only save links to variables, not fixed sizes */
189 	if (get_value(size, &sval))
190 		return;
191 
192 	if (size->type == EXPR_BINOP && size->op == '+' &&
193 	    get_value(size->right, &sval) && sval.value == 1) {
194 		size = size->left;
195 		limit_type = ELEM_LAST;
196 	}
197 
198 	db_save_type_links(pointer, limit_type, size);
199 	sm = set_state_expr(size_id, pointer, alloc_compare_size(limit_type, size));
200 	if (!sm)
201 		return;
202 	set_state_expr(link_id, size, alloc_state_expr(pointer));
203 }
204 
match_alloc(const char * fn,struct expression * expr,void * _size_arg)205 static void match_alloc(const char *fn, struct expression *expr, void *_size_arg)
206 {
207 	int size_arg = PTR_INT(_size_arg);
208 	struct expression *pointer, *call, *arg;
209 
210 	pointer = strip_expr(expr->left);
211 	call = strip_expr(expr->right);
212 	arg = get_argument_from_call_expr(call->args, size_arg);
213 	match_alloc_helper(pointer, arg);
214 }
215 
match_calloc(const char * fn,struct expression * expr,void * _start_arg)216 static void match_calloc(const char *fn, struct expression *expr, void *_start_arg)
217 {
218 	int start_arg = PTR_INT(_start_arg);
219 	struct expression *pointer, *call, *arg;
220 	struct sm_state *tmp;
221 	int limit_type = ELEM_COUNT;
222 	sval_t sval;
223 
224 	pointer = strip_expr(expr->left);
225 	call = strip_expr(expr->right);
226 	arg = get_argument_from_call_expr(call->args, start_arg);
227 	if (get_implied_value(arg, &sval) &&
228 	    sval.value == bytes_per_element(pointer))
229 		arg = get_argument_from_call_expr(call->args, start_arg + 1);
230 
231 	if (arg->type == EXPR_BINOP && arg->op == '+' &&
232 	    get_value(arg->right, &sval) && sval.value == 1) {
233 		arg = arg->left;
234 		limit_type = ELEM_LAST;
235 	}
236 
237 	db_save_type_links(pointer, limit_type, arg);
238 	tmp = set_state_expr(size_id, pointer, alloc_compare_size(limit_type, arg));
239 	if (!tmp)
240 		return;
241 	set_state_expr(link_id, arg, alloc_state_expr(pointer));
242 }
243 
get_size_variable(struct expression * buf,int * limit_type)244 struct expression *get_size_variable(struct expression *buf, int *limit_type)
245 {
246 	struct smatch_state *state;
247 
248 	state = get_state_expr(size_id, buf);
249 	if (!state)
250 		return NULL;
251 	*limit_type = state_to_limit(state);
252 	return state->data;
253 }
254 
get_array_variable(struct expression * size)255 struct expression *get_array_variable(struct expression *size)
256 {
257 	struct smatch_state *state;
258 
259 	state = get_state_expr(link_id, size);
260 	if (state)
261 		return state->data;
262 	return NULL;
263 }
264 
array_check(struct expression * expr)265 static void array_check(struct expression *expr)
266 {
267 	struct expression *array;
268 	struct expression *size;
269 	struct expression *offset;
270 	char *array_str, *offset_str;
271 	int limit_type;
272 
273 	expr = strip_expr(expr);
274 	if (!is_array(expr))
275 		return;
276 
277 	array = get_array_base(expr);
278 	size = get_size_variable(array, &limit_type);
279 	if (!size)
280 		return;
281 	if (limit_type != ELEM_COUNT)
282 		return;
283 	offset = get_array_offset(expr);
284 	if (!possible_comparison(size, SPECIAL_EQUAL, offset))
285 		return;
286 
287 	array_str = expr_to_str(array);
288 	offset_str = expr_to_str(offset);
289 	sm_warning("potentially one past the end of array '%s[%s]'", array_str, offset_str);
290 	free_string(array_str);
291 	free_string(offset_str);
292 }
293 
294 struct db_info {
295 	char *name;
296 	int ret;
297 };
298 
db_limitter_callback(void * _info,int argc,char ** argv,char ** azColName)299 static int db_limitter_callback(void *_info, int argc, char **argv, char **azColName)
300 {
301 	struct db_info *info = _info;
302 
303 	/*
304 	 * If possible the limitters are tied to the struct they limit.  If we
305 	 * aren't sure which struct they limit then we use them as limitters for
306 	 * everything.
307 	 */
308 	if (!info->name || argv[0][0] == '\0' || strcmp(info->name, argv[0]) == 0)
309 		info->ret = 1;
310 	return 0;
311 }
312 
vsl_to_data_info_name(const char * name,struct var_sym_list * vsl)313 static char *vsl_to_data_info_name(const char *name, struct var_sym_list *vsl)
314 {
315 	struct var_sym *vs;
316 	struct symbol *type;
317 	static char buf[80];
318 	const char *p;
319 
320 	if (ptr_list_size((struct ptr_list *)vsl) != 1)
321 		return NULL;
322 	vs = first_ptr_list((struct ptr_list *)vsl);
323 
324 	type = get_real_base_type(vs->sym);
325 	if (!type || type->type != SYM_PTR)
326 		goto top_level_name;
327 	type = get_real_base_type(type);
328 	if (!type || type->type != SYM_STRUCT)
329 		goto top_level_name;
330 	if (!type->ident)
331 		goto top_level_name;
332 
333 	p = name;
334 	while ((name = strstr(p, "->")))
335 		p = name + 2;
336 
337 	snprintf(buf, sizeof(buf),"(struct %s)->%s", type->ident->name, p);
338 	return alloc_sname(buf);
339 
340 top_level_name:
341 	if (!(vs->sym->ctype.modifiers & MOD_TOPLEVEL))
342 		return NULL;
343 	if (vs->sym->ctype.modifiers & MOD_STATIC)
344 		snprintf(buf, sizeof(buf),"static %s", name);
345 	else
346 		snprintf(buf, sizeof(buf),"global %s", name);
347 	return alloc_sname(buf);
348 }
349 
db_var_is_array_limit(struct expression * array,const char * name,struct var_sym_list * vsl)350 int db_var_is_array_limit(struct expression *array, const char *name, struct var_sym_list *vsl)
351 {
352 	char *size_name;
353 	char *array_name = get_data_info_name(array);
354 	struct db_info db_info = {.name = array_name,};
355 
356 	size_name = vsl_to_data_info_name(name, vsl);
357 	if (!size_name)
358 		return 0;
359 
360 	run_sql(db_limitter_callback, &db_info,
361 		"select value from data_info where type = %d and data = '%s';",
362 		ARRAY_LEN, size_name);
363 
364 	return db_info.ret;
365 }
366 
buf_comparison_index_ok(struct expression * expr)367 int buf_comparison_index_ok(struct expression *expr)
368 {
369 	struct expression *array;
370 	struct expression *size;
371 	struct expression *offset;
372 	int limit_type;
373 	int comparison;
374 
375 	array = get_array_base(expr);
376 	size = get_size_variable(array, &limit_type);
377 	if (!size)
378 		return 0;
379 	offset = get_array_offset(expr);
380 	comparison = get_comparison(offset, size);
381 	if (!comparison)
382 		return 0;
383 
384 	if ((limit_type == ELEM_COUNT || limit_type == ELEM_LAST) &&
385 	    (comparison == '<' || comparison == SPECIAL_UNSIGNED_LT))
386 		return 1;
387 	if (limit_type == ELEM_LAST &&
388 	    (comparison == SPECIAL_LTE ||
389 	     comparison == SPECIAL_UNSIGNED_LTE ||
390 	     comparison == SPECIAL_EQUAL))
391 		return 1;
392 
393 	return 0;
394 }
395 
known_access_ok_numbers(struct expression * expr)396 static int known_access_ok_numbers(struct expression *expr)
397 {
398 	struct expression *array;
399 	struct expression *offset;
400 	sval_t max;
401 	int size;
402 
403 	array = get_array_base(expr);
404 	offset = get_array_offset(expr);
405 
406 	size = get_array_size(array);
407 	if (size <= 0)
408 		return 0;
409 
410 	get_absolute_max(offset, &max);
411 	if (max.uvalue < size)
412 		return 1;
413 	return 0;
414 }
415 
array_check_data_info(struct expression * expr)416 static void array_check_data_info(struct expression *expr)
417 {
418 	struct expression *array;
419 	struct expression *offset;
420 	struct state_list *slist;
421 	struct sm_state *sm;
422 	struct compare_data *comp;
423 	char *offset_name;
424 	const char *equal_name = NULL;
425 
426 	expr = strip_expr(expr);
427 	if (!is_array(expr))
428 		return;
429 
430 	if (known_access_ok_numbers(expr))
431 		return;
432 	if (buf_comparison_index_ok(expr))
433 		return;
434 
435 	array = get_array_base(expr);
436 	offset = get_array_offset(expr);
437 	offset_name = expr_to_var(offset);
438 	if (!offset_name)
439 		return;
440 	slist = get_all_possible_equal_comparisons(offset);
441 	if (!slist)
442 		goto free;
443 
444 	FOR_EACH_PTR(slist, sm) {
445 		comp = sm->state->data;
446 		if (strcmp(comp->left_var, offset_name) == 0) {
447 			if (db_var_is_array_limit(array, comp->right_var, comp->right_vsl)) {
448 				equal_name = comp->right_var;
449 				break;
450 			}
451 		} else if (strcmp(comp->right_var, offset_name) == 0) {
452 			if (db_var_is_array_limit(array, comp->left_var, comp->left_vsl)) {
453 				equal_name = comp->left_var;
454 				break;
455 			}
456 		}
457 	} END_FOR_EACH_PTR(sm);
458 
459 	if (equal_name) {
460 		char *array_name = expr_to_str(array);
461 
462 		sm_warning("potential off by one '%s[]' limit '%s'", array_name, equal_name);
463 		free_string(array_name);
464 	}
465 
466 free:
467 	free_slist(&slist);
468 	free_string(offset_name);
469 }
470 
add_allocation_function(const char * func,void * call_back,int param)471 static void add_allocation_function(const char *func, void *call_back, int param)
472 {
473 	add_function_assign_hook(func, call_back, INT_PTR(param));
474 }
475 
is_sizeof(struct expression * expr)476 static int is_sizeof(struct expression *expr)
477 {
478 	const char *name;
479 
480 	if (expr->type == EXPR_SIZEOF)
481 		return 1;
482 	name = pos_ident(expr->pos);
483 	if (name && strcmp(name, "sizeof") == 0)
484 		return 1;
485 	return 0;
486 }
487 
match_size_binop(struct expression * size,struct expression * expr,int * limit_type)488 static int match_size_binop(struct expression *size, struct expression *expr, int *limit_type)
489 {
490 	int orig_type = *limit_type;
491 	struct expression *left;
492 	sval_t sval;
493 
494 	left = expr->left;
495 	if (!expr_equiv(size, left))
496 		return 0;
497 
498 	if (expr->op == '-' &&
499 	    get_value(expr->right, &sval) &&
500 	    sval.value == 1 &&
501 	    orig_type == ELEM_COUNT) {
502 		*limit_type = ELEM_LAST;
503 		return 1;
504 	}
505 
506 	if (expr->op == '+' &&
507 	    get_value(expr->right, &sval) &&
508 	    sval.value == 1 &&
509 	    orig_type == ELEM_LAST) {
510 		*limit_type = ELEM_COUNT;
511 		return 1;
512 	}
513 
514 	if (expr->op == '*' &&
515 	    is_sizeof(expr->right) &&
516 	    orig_type == ELEM_COUNT) {
517 		*limit_type = BYTE_COUNT;
518 		return 1;
519 	}
520 
521 	if (expr->op == '/' &&
522 	    is_sizeof(expr->right) &&
523 	    orig_type == BYTE_COUNT) {
524 		*limit_type = ELEM_COUNT;
525 		return 1;
526 	}
527 
528 	return 0;
529 }
530 
buf_size_param_comparison(struct expression * array,struct expression_list * args,int * limit_type)531 static char *buf_size_param_comparison(struct expression *array, struct expression_list *args, int *limit_type)
532 {
533 	struct expression *tmp, *arg;
534 	struct expression *size;
535 	static char buf[32];
536 	int i;
537 
538 	size = get_size_variable(array, limit_type);
539 	if (!size)
540 		return NULL;
541 
542 	if (*limit_type == USED_LAST)
543 		*limit_type = ELEM_LAST;
544 	if (*limit_type == USED_COUNT)
545 		*limit_type = ELEM_COUNT;
546 
547 	i = -1;
548 	FOR_EACH_PTR(args, tmp) {
549 		i++;
550 		arg = tmp;
551 		if (arg == array)
552 			continue;
553 		if (expr_equiv(arg, size) ||
554 		    (arg->type == EXPR_BINOP &&
555 		     match_size_binop(size, arg, limit_type))) {
556 			snprintf(buf, sizeof(buf), "==$%d", i);
557 			return buf;
558 		}
559 	} END_FOR_EACH_PTR(tmp);
560 
561 	return NULL;
562 }
563 
match_call(struct expression * call)564 static void match_call(struct expression *call)
565 {
566 	struct expression *arg;
567 	char *compare;
568 	int param;
569 	char buf[5];
570 	int limit_type;
571 
572 	param = -1;
573 	FOR_EACH_PTR(call->args, arg) {
574 		param++;
575 		if (!is_pointer(arg))
576 			continue;
577 		compare = buf_size_param_comparison(arg, call->args, &limit_type);
578 		if (!compare)
579 			continue;
580 		snprintf(buf, sizeof(buf), "%d", limit_type);
581 		sql_insert_caller_info(call, limit_type, param, compare, buf);
582 	} END_FOR_EACH_PTR(arg);
583 }
584 
get_param(int param,char ** name,struct symbol ** sym)585 static int get_param(int param, char **name, struct symbol **sym)
586 {
587 	struct symbol *arg;
588 	int i;
589 
590 	i = 0;
591 	FOR_EACH_PTR(cur_func_sym->ctype.base_type->arguments, arg) {
592 		/*
593 		 * this is a temporary hack to work around a bug (I think in sparse?)
594 		 * 2.6.37-rc1:fs/reiserfs/journal.o
595 		 * If there is a function definition without parameter name found
596 		 * after a function implementation then it causes a crash.
597 		 * int foo() {}
598 		 * int bar(char *);
599 		 */
600 		if (arg->ident->name < (char *)100)
601 			continue;
602 		if (i == param) {
603 			*name = arg->ident->name;
604 			*sym = arg;
605 			return TRUE;
606 		}
607 		i++;
608 	} END_FOR_EACH_PTR(arg);
609 
610 	return FALSE;
611 }
612 
set_param_compare(const char * array_name,struct symbol * array_sym,char * key,char * value)613 static void set_param_compare(const char *array_name, struct symbol *array_sym, char *key, char *value)
614 {
615 	struct expression *array_expr;
616 	struct expression *size_expr;
617 	struct symbol *size_sym;
618 	char *size_name;
619 	long param;
620 	struct sm_state *tmp;
621 	int limit_type;
622 
623 	if (strncmp(key, "==$", 3) != 0)
624 		return;
625 	param = strtol(key + 3, NULL, 10);
626 	if (!get_param(param, &size_name, &size_sym))
627 		return;
628 	array_expr = symbol_expression(array_sym);
629 	size_expr = symbol_expression(size_sym);
630 	limit_type = strtol(value, NULL, 10);
631 
632 	tmp = set_state_expr(size_id, array_expr, alloc_compare_size(limit_type, size_expr));
633 	if (!tmp)
634 		return;
635 	set_state_expr(link_id, size_expr, alloc_state_expr(array_expr));
636 }
637 
set_implied(struct expression * call,struct expression * array_expr,char * key,char * value)638 static void set_implied(struct expression *call, struct expression *array_expr, char *key, char *value)
639 {
640 	struct expression *size_expr;
641 	struct symbol *size_sym;
642 	char *size_name;
643 	long param;
644 	struct sm_state *tmp;
645 	int limit_type;
646 
647 	if (strncmp(key, "==$", 3) != 0)
648 		return;
649 	param = strtol(key + 3, NULL, 10);
650 	if (!get_param(param, &size_name, &size_sym))
651 		return;
652 	size_expr = symbol_expression(size_sym);
653 
654 	limit_type = strtol(value, NULL, 10);
655 	tmp = set_state_expr(size_id, array_expr, alloc_compare_size(limit_type, size_expr));
656 	if (!tmp)
657 		return;
658 	set_state_expr(link_id, size_expr, alloc_state_expr(array_expr));
659 }
660 
munge_start_states(struct statement * stmt)661 static void munge_start_states(struct statement *stmt)
662 {
663 	struct state_list *slist = NULL;
664 	struct sm_state *sm;
665 	struct sm_state *poss;
666 
667 	FOR_EACH_MY_SM(size_id, __get_cur_stree(), sm) {
668 		if (sm->state != &merged)
669 			continue;
670 		/*
671 		 * screw it.  let's just assume that if one caller passes the
672 		 * size then they all do.
673 		 */
674 		FOR_EACH_PTR(sm->possible, poss) {
675 			if (poss->state != &merged &&
676 			    poss->state != &undefined) {
677 				add_ptr_list(&slist, poss);
678 				break;
679 			}
680 		} END_FOR_EACH_PTR(poss);
681 	} END_FOR_EACH_SM(sm);
682 
683 	FOR_EACH_PTR(slist, sm) {
684 		set_state(size_id, sm->name, sm->sym, sm->state);
685 	} END_FOR_EACH_PTR(sm);
686 
687 	free_slist(&slist);
688 }
689 
set_used(struct expression * expr)690 static void set_used(struct expression *expr)
691 {
692 	struct expression *parent;
693 	struct expression *array;
694 	struct expression *offset;
695 	struct sm_state *tmp;
696 	int limit_type;
697 
698 	if (expr->op != SPECIAL_INCREMENT)
699 		return;
700 
701 	limit_type = USED_LAST;
702 	if (expr->type == EXPR_POSTOP)
703 		limit_type = USED_COUNT;
704 
705 	parent = expr_get_parent_expr(expr);
706 	if (!parent || parent->type != EXPR_BINOP)
707 		return;
708 	parent = expr_get_parent_expr(parent);
709 	if (!parent || !is_array(parent))
710 		return;
711 
712 	array = get_array_base(parent);
713 	offset = get_array_offset(parent);
714 	if (offset != expr)
715 		return;
716 
717 	tmp = set_state_expr(size_id, array, alloc_compare_size(limit_type, offset->unop));
718 	if (!tmp)
719 		return;
720 	set_state_expr(link_id, offset->unop, alloc_state_expr(array));
721 }
722 
match_assign_array(struct expression * expr)723 static int match_assign_array(struct expression *expr)
724 {
725 	// FIXME: implement
726 	return 0;
727 }
728 
match_assign_size(struct expression * expr)729 static int match_assign_size(struct expression *expr)
730 {
731 	struct expression *right, *size, *array;
732 	struct smatch_state *state;
733 	struct sm_state *tmp;
734 	int limit_type;
735 
736 	right = expr->right;
737 	size = right;
738 	if (size->type == EXPR_BINOP)
739 		size = size->left;
740 
741 	array = get_array_variable(size);
742 	if (!array)
743 		return 0;
744 	state = get_state_expr(size_id, array);
745 	if (!state || !state->data)
746 		return 0;
747 
748 	limit_type = state_to_limit(state);
749 	if (limit_type < 0)
750 		return 0;
751 
752 	if (right->type == EXPR_BINOP && !match_size_binop(size, right, &limit_type))
753 		return 0;
754 
755 	tmp = set_state_expr(size_id, array, alloc_compare_size(limit_type, expr->left));
756 	if (!tmp)
757 		return 0;
758 	set_state_expr(link_id, expr->left, alloc_state_expr(array));
759 	return 1;
760 }
761 
match_assign(struct expression * expr)762 static void match_assign(struct expression *expr)
763 {
764 	if (expr->op != '=')
765 		return;
766 
767 	if (match_assign_array(expr))
768 		return;
769 	match_assign_size(expr);
770 }
771 
match_copy(const char * fn,struct expression * expr,void * unused)772 static void match_copy(const char *fn, struct expression *expr, void *unused)
773 {
774 	struct expression *src, *size;
775 	int src_param, size_param;
776 
777 	src = get_argument_from_call_expr(expr->args, 1);
778 	size = get_argument_from_call_expr(expr->args, 2);
779 	src = strip_expr(src);
780 	size = strip_expr(size);
781 	if (!src || !size)
782 		return;
783 	if (src->type != EXPR_SYMBOL || size->type != EXPR_SYMBOL)
784 		return;
785 
786 	src_param = get_param_num_from_sym(src->symbol);
787 	size_param = get_param_num_from_sym(size->symbol);
788 	if (src_param < 0 || size_param < 0)
789 		return;
790 
791 	sql_insert_cache(call_implies, "'%s', '%s', 0, %d, %d, %d, '==$%d', '%d'",
792 			 get_base_file(), get_function(), fn_static(),
793 			 BYTE_COUNT, src_param, size_param, BYTE_COUNT);
794 }
795 
register_buf_comparison(int id)796 void register_buf_comparison(int id)
797 {
798 	int i;
799 
800 	size_id = id;
801 
802 	set_dynamic_states(size_id);
803 
804 	add_unmatched_state_hook(size_id, &unmatched_state);
805 
806 	add_allocation_function("malloc", &match_alloc, 0);
807 	add_allocation_function("memdup", &match_alloc, 1);
808 	add_allocation_function("realloc", &match_alloc, 1);
809 	if (option_project == PROJ_KERNEL) {
810 		add_allocation_function("kmalloc", &match_alloc, 0);
811 		add_allocation_function("kzalloc", &match_alloc, 0);
812 		add_allocation_function("vmalloc", &match_alloc, 0);
813 		add_allocation_function("__vmalloc", &match_alloc, 0);
814 		add_allocation_function("sock_kmalloc", &match_alloc, 1);
815 		add_allocation_function("kmemdup", &match_alloc, 1);
816 		add_allocation_function("kmemdup_user", &match_alloc, 1);
817 		add_allocation_function("dma_alloc_attrs", &match_alloc, 1);
818 		add_allocation_function("pci_alloc_consistent", &match_alloc, 1);
819 		add_allocation_function("pci_alloc_coherent", &match_alloc, 1);
820 		add_allocation_function("devm_kmalloc", &match_alloc, 1);
821 		add_allocation_function("devm_kzalloc", &match_alloc, 1);
822 		add_allocation_function("kcalloc", &match_calloc, 0);
823 		add_allocation_function("devm_kcalloc", &match_calloc, 1);
824 		add_allocation_function("kmalloc_array", &match_calloc, 0);
825 		add_allocation_function("krealloc", &match_alloc, 1);
826 
827 		add_function_hook("copy_from_user", &match_copy, NULL);
828 		add_function_hook("__copy_from_user", &match_copy, NULL);
829 	}
830 
831 	add_hook(&array_check, OP_HOOK);
832 	add_hook(&array_check_data_info, OP_HOOK);
833 	add_hook(&set_used, OP_HOOK);
834 
835 	add_hook(&match_call, FUNCTION_CALL_HOOK);
836 	add_hook(&munge_start_states, AFTER_DEF_HOOK);
837 
838 	add_hook(&match_assign, ASSIGNMENT_HOOK);
839 
840 	for (i = BYTE_COUNT; i <= USED_COUNT; i++) {
841 		select_call_implies_hook(i, &set_implied);
842 		select_caller_info_hook(set_param_compare, i);
843 		select_return_implies_hook(i, &set_implied);
844 	}
845 }
846 
register_buf_comparison_links(int id)847 void register_buf_comparison_links(int id)
848 {
849 	link_id = id;
850 	set_dynamic_states(link_id);
851 	add_merge_hook(link_id, &merge_links);
852 	add_modification_hook(link_id, &match_link_modify);
853 }
854