18 /*
19 * This tries to find buffer overflows in sprintf().
20 * I'll freely admit that the code is sort of crap.
21 * Also if it sees "sprintf("%2d\n", x)" then it assumes x is less than 99.
22 * That might not be true so there maybe buffer overflows which are missed.
23 *
24 */
25
26 #include <ctype.h>
27 #include "smatch.h"
28
29 static int my_id;
30
31 struct param_info {
32 int buf_or_limit;
33 int string;
34 };
35
36 struct param_info zero_one = {0, 1};
37
38 static int handle_format(struct expression *call, char **pp, int *arg_nr)
39 {
40 struct expression *arg;
41 char *p = *pp;
42 int ret = 1;
43 char buf[256];
44 sval_t max;
45
46 p++; /* we passed it with *p == '%' */
47
48 if (*p == '%') {
49 p++;
50 ret = 1;
51 goto out_no_arg;
52 }
53 if (*p == 'c') {
54 p++;
55 ret = 1;
56 goto out;
57 }
58
59
60 if (isdigit(*p) || *p == '.') {
61 unsigned long num;
62
63 if (*p == '.')
64 p++;
124 arg = get_argument_from_call_expr(call->args, *arg_nr);
125 if (!arg)
126 goto out;
127
128 if (*p == 's') {
129 ret = get_array_size_bytes(arg);
130 if (ret < 0)
131 ret = 1;
132 /* we don't print the NUL here */
133 ret--;
134 p++;
135 goto out;
136 }
137
138 if (*p != 'd' && *p != 'i' && *p != 'x' && *p != 'X' && *p != 'u' && *p != 'p') {
139 ret = 1;
140 p++;
141 goto out;
142 }
143
144 get_absolute_max(arg, &max);
145
146 if (*p == 'x' || *p == 'X' || *p == 'p') {
147 ret = snprintf(buf, sizeof(buf), "%llx", max.uvalue);
148 } else if (*p == 'u') {
149 ret = snprintf(buf, sizeof(buf), "%llu", max.uvalue);
150 } else if (!expr_unsigned(arg)) {
151 sval_t min;
152 int tmp;
153
154 ret = snprintf(buf, sizeof(buf), "%lld", max.value);
155 get_absolute_min(arg, &min);
156 tmp = snprintf(buf, sizeof(buf), "%lld", min.value);
157 if (tmp > ret)
158 ret = tmp;
159 } else {
160 ret = snprintf(buf, sizeof(buf), "%lld", max.value);
161 }
162 p++;
163
164 out:
165 (*arg_nr)++;
166 out_no_arg:
167 *pp = p;
168 return ret;
169 }
170
171 int get_formatted_string_size(struct expression *call, int arg)
172 {
173 struct expression *expr;
174 char *p;
175 int count;
176
177 expr = get_argument_from_call_expr(call->args, arg);
178 if (!expr || expr->type != EXPR_STRING)
179 return -1;
180
181 arg++;
182 count = 0;
183 p = expr->string->data;
184 while (*p) {
185
186 if (*p == '%') {
187 count += handle_format(call, &p, &arg);
188 } else if (*p == '\\') {
189 p++;
190 }else {
191 p++;
192 count++;
193 }
194 }
195
196 count++; /* count the NUL terminator */
197 return count;
198 }
199
200 static void match_not_limited(const char *fn, struct expression *call, void *info)
201 {
202 struct param_info *params = info;
203 struct range_list *rl;
204 struct expression *dest;
205 struct expression *arg;
206 int buf_size, size;
207 int user = 0;
208 int i;
209 int offset = 0;
210
211 dest = get_argument_from_call_expr(call->args, params->buf_or_limit);
212 dest = strip_expr(dest);
213 if (dest->type == EXPR_BINOP && dest->op == '+') {
214 sval_t max;
215
216 if (get_hard_max(dest->right, &max))
217 offset = max.value;
218 dest = dest->left;
219 }
220
221
222 buf_size = get_array_size_bytes(dest);
223 if (buf_size <= 0)
224 return;
225
226 size = get_formatted_string_size(call, params->string);
227 if (size <= 0)
228 return;
229 if (size < offset)
230 size -= offset;
231 if (size <= buf_size)
232 return;
233
234 i = 0;
235 FOR_EACH_PTR(call->args, arg) {
236 if (i++ <= params->string)
237 continue;
238 if (get_user_rl(arg, &rl))
239 user = 1;
240 } END_FOR_EACH_PTR(arg);
241
242 sm_error("format string overflow. buf_size: %d length: %d%s",
243 buf_size, size, user ? " [user data]": "");
244 }
245
246 void check_string_len(int id)
247 {
248 my_id = id;
249 add_function_hook("sprintf", &match_not_limited, &zero_one);
250 }
|
18 /*
19 * This tries to find buffer overflows in sprintf().
20 * I'll freely admit that the code is sort of crap.
21 * Also if it sees "sprintf("%2d\n", x)" then it assumes x is less than 99.
22 * That might not be true so there maybe buffer overflows which are missed.
23 *
24 */
25
26 #include <ctype.h>
27 #include "smatch.h"
28
29 static int my_id;
30
31 struct param_info {
32 int buf_or_limit;
33 int string;
34 };
35
36 struct param_info zero_one = {0, 1};
37
38 static int handle_format(struct expression *call, char **pp, int *arg_nr, bool use_max)
39 {
40 struct expression *arg;
41 char *p = *pp;
42 int ret = 1;
43 char buf[256];
44 sval_t sval;
45
46 p++; /* we passed it with *p == '%' */
47
48 if (*p == '%') {
49 p++;
50 ret = 1;
51 goto out_no_arg;
52 }
53 if (*p == 'c') {
54 p++;
55 ret = 1;
56 goto out;
57 }
58
59
60 if (isdigit(*p) || *p == '.') {
61 unsigned long num;
62
63 if (*p == '.')
64 p++;
124 arg = get_argument_from_call_expr(call->args, *arg_nr);
125 if (!arg)
126 goto out;
127
128 if (*p == 's') {
129 ret = get_array_size_bytes(arg);
130 if (ret < 0)
131 ret = 1;
132 /* we don't print the NUL here */
133 ret--;
134 p++;
135 goto out;
136 }
137
138 if (*p != 'd' && *p != 'i' && *p != 'x' && *p != 'X' && *p != 'u' && *p != 'p') {
139 ret = 1;
140 p++;
141 goto out;
142 }
143
144 if (use_max) {
145 get_absolute_max(arg, &sval);
146 } else {
147 get_absolute_min(arg, &sval);
148 if (sval_is_negative(sval))
149 sval.value = 0;
150 }
151
152
153 if (*p == 'x' || *p == 'X' || *p == 'p') {
154 ret = snprintf(buf, sizeof(buf), "%llx", sval.uvalue);
155 } else if (*p == 'u') {
156 ret = snprintf(buf, sizeof(buf), "%llu", sval.uvalue);
157 } else if (!expr_unsigned(arg)) {
158 sval_t min;
159 int tmp;
160
161 ret = snprintf(buf, sizeof(buf), "%lld", sval.value);
162 get_absolute_min(arg, &min);
163 tmp = snprintf(buf, sizeof(buf), "%lld", min.value);
164 if (tmp > ret)
165 ret = tmp;
166 } else {
167 ret = snprintf(buf, sizeof(buf), "%lld", sval.value);
168 }
169 p++;
170
171 out:
172 (*arg_nr)++;
173 out_no_arg:
174 *pp = p;
175 return ret;
176 }
177
178 int get_formatted_string_size_helper(struct expression *call, int arg, bool use_max)
179 {
180 struct expression *expr;
181 char *p;
182 int count;
183
184 expr = get_argument_from_call_expr(call->args, arg);
185 if (!expr || expr->type != EXPR_STRING)
186 return -1;
187
188 arg++;
189 count = 0;
190 p = expr->string->data;
191 while (*p) {
192
193 if (*p == '%') {
194 count += handle_format(call, &p, &arg, use_max);
195 } else if (*p == '\\') {
196 p++;
197 }else {
198 p++;
199 count++;
200 }
201 }
202
203 return count;
204 }
205
206 int get_formatted_string_size(struct expression *call, int arg)
207 {
208 return get_formatted_string_size_helper(call, arg, true);
209 }
210
211 int get_formatted_string_min_size(struct expression *call, int arg)
212 {
213 return get_formatted_string_size_helper(call, arg, false);
214 }
215
216 static void match_not_limited(const char *fn, struct expression *call, void *info)
217 {
218 struct param_info *params = info;
219 struct range_list *rl;
220 struct expression *dest;
221 struct expression *arg;
222 int buf_size, size;
223 int user = 0;
224 int i;
225 int offset = 0;
226
227 dest = get_argument_from_call_expr(call->args, params->buf_or_limit);
228 dest = strip_expr(dest);
229 if (dest->type == EXPR_BINOP && dest->op == '+') {
230 sval_t max;
231
232 if (get_hard_max(dest->right, &max))
233 offset = max.value;
234 dest = dest->left;
235 }
236
237
238 buf_size = get_array_size_bytes(dest);
239 if (buf_size <= 0)
240 return;
241
242 size = get_formatted_string_size(call, params->string);
243 if (size < 0)
244 return;
245 if (size < offset)
246 size -= offset;
247 size++; /* add the NULL terminator */
248 if (size <= buf_size)
249 return;
250
251 i = 0;
252 FOR_EACH_PTR(call->args, arg) {
253 if (i++ <= params->string)
254 continue;
255 if (get_user_rl(arg, &rl))
256 user = 1;
257 } END_FOR_EACH_PTR(arg);
258
259 sm_error("format string overflow. buf_size: %d length: %d%s",
260 buf_size, size, user ? " [user data]": "");
261 }
262
263 void check_string_len(int id)
264 {
265 my_id = id;
266 add_function_hook("sprintf", &match_not_limited, &zero_one);
267 }
|