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