extra: make dereferences limit to valid pointer range again
[smatch.git] / check_get_user_overflow.c
blob05125f668f26ea33693fb96586373d39513dec04
1 /*
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
19 * Looks for integers that we get from the user which can be attacked
20 * with an integer overflow.
24 #include "smatch.h"
25 #include "smatch_slist.h"
27 static int my_max_id;
28 static int my_min_id;
30 STATE(capped);
31 STATE(user_data);
33 static void match_condition(struct expression *expr)
35 struct smatch_state *left_max_true = NULL;
36 struct smatch_state *left_max_false = NULL;
37 struct smatch_state *right_max_true = NULL;
38 struct smatch_state *right_max_false = NULL;
40 struct smatch_state *left_min_true = NULL;
41 struct smatch_state *left_min_false = NULL;
42 struct smatch_state *right_min_true = NULL;
43 struct smatch_state *right_min_false = NULL;
45 switch (expr->op) {
46 case '<':
47 case SPECIAL_LTE:
48 case SPECIAL_UNSIGNED_LT:
49 case SPECIAL_UNSIGNED_LTE:
50 left_max_true = &capped;
51 right_max_false = &capped;
52 right_min_true = &capped;
53 left_min_false = &capped;
54 break;
55 case '>':
56 case SPECIAL_GTE:
57 case SPECIAL_UNSIGNED_GT:
58 case SPECIAL_UNSIGNED_GTE:
59 left_max_false = &capped;
60 right_max_true = &capped;
61 left_min_true = &capped;
62 right_min_false = &capped;
63 break;
64 case SPECIAL_EQUAL:
65 left_max_true = &capped;
66 right_max_true = &capped;
67 left_min_true = &capped;
68 right_min_true = &capped;
69 break;
70 case SPECIAL_NOTEQUAL:
71 left_max_false = &capped;
72 right_max_false = &capped;
73 left_min_false = &capped;
74 right_min_false = &capped;
75 break;
76 default:
77 return;
80 if (get_state_expr(my_max_id, expr->left)) {
81 set_true_false_states_expr(my_max_id, expr->left, left_max_true, left_max_false);
82 set_true_false_states_expr(my_min_id, expr->left, left_min_true, left_min_false);
84 if (get_state_expr(my_max_id, expr->right)) {
85 set_true_false_states_expr(my_max_id, expr->right, right_max_true, right_max_false);
86 set_true_false_states_expr(my_min_id, expr->right, right_min_true, right_min_false);
90 static void match_normal_assign(struct expression *expr)
92 if (get_state_expr(my_max_id, expr->left)) {
93 set_state_expr(my_max_id, expr->left, &capped);
94 set_state_expr(my_min_id, expr->left, &capped);
98 static void match_assign(struct expression *expr)
100 char *name;
102 name = get_macro_name(expr->pos);
103 if (!name || strcmp(name, "get_user") != 0) {
104 match_normal_assign(expr);
105 return;
107 name = expr_to_var(expr->right);
108 if (!name || strcmp(name, "__val_gu") != 0)
109 goto free;
110 set_state_expr(my_max_id, expr->left, &user_data);
111 set_state_expr(my_min_id, expr->left, &user_data);
112 free:
113 free_string(name);
116 static void check_expr(struct expression *expr)
118 struct sm_state *sm;
119 sval_t max;
120 sval_t sval;
121 char *name;
122 int overflow = 0;
123 int underflow = 0;
125 sm = get_sm_state_expr(my_max_id, expr);
126 if (sm && slist_has_state(sm->possible, &user_data)) {
127 if (!get_absolute_max(expr, &max) || sval_cmp_val(max, 20000) > 0)
128 overflow = 1;
131 sm = get_sm_state_expr(my_min_id, expr);
132 if (sm && slist_has_state(sm->possible, &user_data)) {
133 if (!get_absolute_min(expr, &sval) ||
134 (sval_is_negative(sval) && sval_cmp_val(sval, -20000) < 0))
135 underflow = 1;
138 if (!overflow && !underflow)
139 return;
141 name = expr_to_var_sym(expr, NULL);
142 if (overflow && underflow)
143 sm_msg("warn: check for integer over/underflow '%s'", name);
144 else if (underflow)
145 sm_msg("warn: check for integer underflow '%s'", name);
146 else
147 sm_msg("warn: check for integer overflow '%s'", name);
148 free_string(name);
150 set_state_expr(my_max_id, expr, &capped);
151 set_state_expr(my_min_id, expr, &capped);
154 static void match_binop(struct expression *expr)
156 if (expr->op == '^')
157 return;
158 if (expr->op == '&')
159 return;
160 if (expr->op == '|')
161 return;
162 if (expr->op == SPECIAL_RIGHTSHIFT)
163 return;
164 if (expr->op == SPECIAL_LEFTSHIFT)
165 return;
167 check_expr(expr->left);
168 check_expr(expr->right);
171 void check_get_user_overflow(int id)
173 if (option_project != PROJ_KERNEL)
174 return;
175 my_max_id = id;
176 add_hook(&match_condition, CONDITION_HOOK);
177 add_hook(&match_assign, ASSIGNMENT_HOOK);
178 add_hook(&match_binop, BINOP_HOOK);
181 void check_get_user_overflow2(int id)
183 my_min_id = id;