1 /*
2  * Copyright (C) 2014 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  * Looks for integers that we get from the user which can be attacked
20  * with an integer overflow.
21  *
22  */
23 
24 #include "smatch.h"
25 #include "smatch_slist.h"
26 
27 static int my_id;
28 
match_condition(struct expression * expr)29 static void match_condition(struct expression *expr)
30 {
31 	struct expression *left, *right;
32 	struct symbol *type;
33 	char *right_name;
34 	char *left_name;
35 
36 	if (expr->type != EXPR_COMPARE)
37 		return;
38 	if (expr->op != '<')
39 		return;
40 
41 	type = get_type(expr);
42 	if (!type_signed(type))
43 		return;
44 
45 	left = strip_expr(expr->left);
46 	right = strip_expr(expr->right);
47 
48 	if (left->type != EXPR_BINOP) {
49 		left = get_assigned_expr(left);
50 		left = strip_expr(left);
51 		if (!left || left->type != EXPR_BINOP)
52 			return;
53 	}
54 
55 	if (left->op != '+' && left->op != '*' && left->op != SPECIAL_LEFTSHIFT)
56 		return;
57 
58 	if (has_variable(left, right) == 1) {
59 		left_name = expr_to_str(left);
60 		right_name = expr_to_str(right);
61 		sm_warning("signed overflow undefined. '%s %s %s'", left_name, show_special(expr->op), right_name);
62 		free_string(left_name);
63 		free_string(right_name);
64 	}
65 }
66 
match_binop(struct expression * expr)67 static void match_binop(struct expression *expr)
68 {
69 	sval_t left_val, right_min;
70 	char *str;
71 
72 	if (expr->op != '-')
73 		return;
74 
75 	if (!get_value(expr->left, &left_val))
76 		return;
77 
78 	switch (left_val.uvalue) {
79 	case SHRT_MAX:
80 	case USHRT_MAX:
81 	case INT_MAX:
82 	case UINT_MAX:
83 	case LLONG_MAX:
84 	case ULLONG_MAX:
85 		break;
86 	default:
87 		return;
88 	}
89 
90 	get_absolute_min(expr->right, &right_min);
91 	if (!sval_is_negative(right_min))
92 		return;
93 
94 	str = expr_to_str(expr);
95 	sm_warning("potential negative subtraction from max '%s'", str);
96 	free_string(str);
97 }
98 
check_signed_integer_overflow_check(int id)99 void check_signed_integer_overflow_check(int id)
100 {
101 	my_id = id;
102 
103 	if (option_project == PROJ_KERNEL) {
104 		/* The kernel uses -fno-strict-overflow so it's fine */
105 		return;
106 	}
107 
108 	add_hook(&match_condition, CONDITION_HOOK);
109 	add_hook(&match_binop, BINOP_HOOK);
110 }
111 
112