2 * smatch/check_string_len.c
4 * Copyright (C) 2013 Oracle.
6 * Licensed under the Open Software License version 1.1
11 * This tries to find buffer overflows in sprintf().
12 * I'll freely admit that the code is sort of crap.
13 * Also if it sees "sprintf("%2d\n", x)" then it assumes x is less than 99.
14 * That might not be true so there maybe buffer overflows which are missed.
28 struct param_info zero_one
= {0, 1};
30 static int handle_format(struct expression
*call
, char **pp
, int *arg_nr
)
32 struct expression
*arg
;
38 p
++; /* we passed it with *p == '%' */
52 if (isdigit(*p
) || *p
== '.') {
58 num
= strtoul(p
, &p
, 10);
63 p
++; /* eat the 'd' char */
73 if (option_project
== PROJ_KERNEL
&& *p
== 'z')
76 if (option_project
== PROJ_KERNEL
&& *p
== 'p') {
77 if (*(p
+ 1) == 'I' || *(p
+ 1) == 'i') {
82 if (*p
== 'h' || *p
== 'n' || *p
== 'b' || *p
== 'l')
100 if (*(p
+ 1) == 'M') {
102 if (*p
== 'R' || *p
== 'F')
107 if (*(p
+ 1) == 'm') {
116 arg
= get_argument_from_call_expr(call
->args
, *arg_nr
);
121 ret
= get_array_size_bytes(arg
);
124 /* we don't print the NUL here */
130 if (*p
!= 'd' && *p
!= 'i' && *p
!= 'x' && *p
!= 'X' && *p
!= 'u' && *p
!= 'p') {
136 get_absolute_max(arg
, &max
);
138 if (*p
== 'x' || *p
== 'X' || *p
== 'p') {
139 ret
= snprintf(buf
, sizeof(buf
), "%llx", max
.uvalue
);
140 } else if (*p
== 'u') {
141 ret
= snprintf(buf
, sizeof(buf
), "%llu", max
.uvalue
);
142 } else if (!expr_unsigned(arg
)) {
146 ret
= snprintf(buf
, sizeof(buf
), "%lld", max
.value
);
147 get_absolute_min(arg
, &min
);
148 tmp
= snprintf(buf
, sizeof(buf
), "%lld", min
.value
);
152 ret
= snprintf(buf
, sizeof(buf
), "%lld", max
.value
);
163 static int get_string_size(struct expression
*call
, int arg
)
165 struct expression
*expr
;
169 expr
= get_argument_from_call_expr(call
->args
, arg
);
170 if (!expr
|| expr
->type
!= EXPR_STRING
)
175 p
= expr
->string
->data
;
179 count
+= handle_format(call
, &p
, &arg
);
180 } else if (*p
== '\\') {
188 count
++; /* count the NUL terminator */
192 static void match_not_limited(const char *fn
, struct expression
*call
, void *info
)
194 struct param_info
*params
= info
;
195 struct expression
*arg
;
200 arg
= get_argument_from_call_expr(call
->args
, params
->buf_or_limit
);
201 buf_size
= get_array_size_bytes(arg
);
205 size
= get_string_size(call
, params
->string
);
208 if (size
<= buf_size
)
212 FOR_EACH_PTR(call
->args
, arg
) {
213 if (i
++ <= params
->string
)
215 if (is_user_data(arg
))
217 } END_FOR_EACH_PTR(arg
);
219 sm_msg("error: format string overflow. buf_size: %d length: %d%s",
220 buf_size
, size
, user
? " [user data]": "");
223 void check_string_len(int id
)
226 add_function_hook("sprintf", &match_not_limited
, &zero_one
);