Print this page
new smatch
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/tools/smatch/src/check_get_user_overflow.c
+++ new/usr/src/tools/smatch/src/check_get_user_overflow.c
1 1 /*
2 2 * Copyright (C) 2010 Dan Carpenter.
3 3 *
4 4 * This program is free software; you can redistribute it and/or
5 5 * modify it under the terms of the GNU General Public License
6 6 * as published by the Free Software Foundation; either version 2
7 7 * of the License, or (at your option) any later version.
8 8 *
9 9 * This program is distributed in the hope that it will be useful,
10 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 * GNU General Public License for more details.
13 13 *
14 14 * You should have received a copy of the GNU General Public License
15 15 * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
16 16 */
17 17
18 18 /*
19 19 * Looks for integers that we get from the user which can be attacked
20 20 * with an integer overflow.
21 21 *
22 22 */
23 23
24 24 #include "smatch.h"
25 25 #include "smatch_slist.h"
26 26
27 27 static int my_max_id;
28 28 static int my_min_id;
29 29
30 30 STATE(capped);
31 31 STATE(user_data);
32 32
33 33 static void match_condition(struct expression *expr)
34 34 {
35 35 struct smatch_state *left_max_true = NULL;
36 36 struct smatch_state *left_max_false = NULL;
37 37 struct smatch_state *right_max_true = NULL;
38 38 struct smatch_state *right_max_false = NULL;
39 39
40 40 struct smatch_state *left_min_true = NULL;
41 41 struct smatch_state *left_min_false = NULL;
42 42 struct smatch_state *right_min_true = NULL;
43 43 struct smatch_state *right_min_false = NULL;
44 44
45 45 if (expr->type != EXPR_COMPARE)
46 46 return;
47 47
48 48 switch (expr->op) {
49 49 case '<':
50 50 case SPECIAL_LTE:
51 51 case SPECIAL_UNSIGNED_LT:
52 52 case SPECIAL_UNSIGNED_LTE:
53 53 left_max_true = &capped;
54 54 right_max_false = &capped;
55 55 right_min_true = &capped;
56 56 left_min_false = &capped;
57 57 break;
58 58 case '>':
59 59 case SPECIAL_GTE:
60 60 case SPECIAL_UNSIGNED_GT:
61 61 case SPECIAL_UNSIGNED_GTE:
62 62 left_max_false = &capped;
63 63 right_max_true = &capped;
64 64 left_min_true = &capped;
65 65 right_min_false = &capped;
66 66 break;
67 67 case SPECIAL_EQUAL:
68 68 left_max_true = &capped;
69 69 right_max_true = &capped;
70 70 left_min_true = &capped;
71 71 right_min_true = &capped;
72 72 break;
73 73 case SPECIAL_NOTEQUAL:
74 74 left_max_false = &capped;
75 75 right_max_false = &capped;
76 76 left_min_false = &capped;
77 77 right_min_false = &capped;
78 78 break;
79 79 default:
80 80 return;
81 81 }
82 82
83 83 if (get_state_expr(my_max_id, expr->left)) {
84 84 set_true_false_states_expr(my_max_id, expr->left, left_max_true, left_max_false);
85 85 set_true_false_states_expr(my_min_id, expr->left, left_min_true, left_min_false);
86 86 }
87 87 if (get_state_expr(my_max_id, expr->right)) {
88 88 set_true_false_states_expr(my_max_id, expr->right, right_max_true, right_max_false);
89 89 set_true_false_states_expr(my_min_id, expr->right, right_min_true, right_min_false);
90 90 }
91 91 }
92 92
93 93 static void match_normal_assign(struct expression *expr)
94 94 {
95 95 if (get_state_expr(my_max_id, expr->left)) {
96 96 set_state_expr(my_max_id, expr->left, &capped);
97 97 set_state_expr(my_min_id, expr->left, &capped);
98 98 }
99 99 }
100 100
↓ open down ↓ |
100 lines elided |
↑ open up ↑ |
101 101 static void match_assign(struct expression *expr)
102 102 {
103 103 char *name;
104 104
105 105 name = get_macro_name(expr->pos);
106 106 if (!name || strcmp(name, "get_user") != 0) {
107 107 match_normal_assign(expr);
108 108 return;
109 109 }
110 110 name = expr_to_var(expr->right);
111 - if (!name || strcmp(name, "__val_gu") != 0)
111 + if (!name || (strcmp(name, "__val_gu") != 0 && strcmp(name, "__gu_val")))
112 112 goto free;
113 113 set_state_expr(my_max_id, expr->left, &user_data);
114 114 set_state_expr(my_min_id, expr->left, &user_data);
115 115 free:
116 116 free_string(name);
117 117 }
118 118
119 119 static void check_expr(struct expression *expr)
120 120 {
121 121 struct sm_state *sm;
122 122 sval_t max;
123 123 sval_t sval;
124 124 char *name;
125 125 int overflow = 0;
126 126 int underflow = 0;
127 127
128 128 sm = get_sm_state_expr(my_max_id, expr);
129 129 if (sm && slist_has_state(sm->possible, &user_data)) {
130 - if (!get_absolute_max(expr, &max) || sval_cmp_val(max, 20000) > 0)
130 + get_absolute_max(expr, &max);
131 + if (sval_cmp_val(max, 20000) > 0)
131 132 overflow = 1;
132 133 }
133 134
134 135 sm = get_sm_state_expr(my_min_id, expr);
135 136 if (sm && slist_has_state(sm->possible, &user_data)) {
136 - if (!get_absolute_min(expr, &sval) ||
137 - (sval_is_negative(sval) && sval_cmp_val(sval, -20000) < 0))
137 + get_absolute_min(expr, &sval);
138 + if (sval_is_negative(sval) && sval_cmp_val(sval, -20000) < 0)
138 139 underflow = 1;
139 140 }
140 141
141 142 if (!overflow && !underflow)
142 143 return;
143 144
144 145 name = expr_to_var_sym(expr, NULL);
145 146 if (overflow && underflow)
146 147 sm_warning("check for integer over/underflow '%s'", name);
147 148 else if (underflow)
148 149 sm_warning("check for integer underflow '%s'", name);
149 150 else
150 151 sm_warning("check for integer overflow '%s'", name);
151 152 free_string(name);
152 153
153 154 set_state_expr(my_max_id, expr, &capped);
154 155 set_state_expr(my_min_id, expr, &capped);
155 156 }
156 157
157 158 static void match_binop(struct expression *expr)
158 159 {
159 160 if (expr->op == '^')
160 161 return;
161 162 if (expr->op == '&')
162 163 return;
163 164 if (expr->op == '|')
164 165 return;
165 166 if (expr->op == SPECIAL_RIGHTSHIFT)
166 167 return;
167 168 if (expr->op == SPECIAL_LEFTSHIFT)
168 169 return;
169 170
170 171 check_expr(expr->left);
171 172 check_expr(expr->right);
172 173 }
173 174
174 175 void check_get_user_overflow(int id)
175 176 {
176 177 if (option_project != PROJ_KERNEL)
177 178 return;
178 179 my_max_id = id;
179 180 add_hook(&match_condition, CONDITION_HOOK);
180 181 add_hook(&match_assign, ASSIGNMENT_HOOK);
181 182 add_hook(&match_binop, BINOP_HOOK);
182 183 }
183 184
184 185 void check_get_user_overflow2(int id)
185 186 {
186 187 my_min_id = id;
187 188 }
↓ open down ↓ |
40 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX