2 * Copyright (C) 2013 Oracle.
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 * 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.
36 struct param_info zero_one
= {0, 1};
38 static int handle_format(struct expression
*call
, char **pp
, int *arg_nr
)
40 struct expression
*arg
;
46 p
++; /* we passed it with *p == '%' */
60 if (isdigit(*p
) || *p
== '.') {
66 num
= strtoul(p
, &p
, 10);
71 p
++; /* eat the 'd' char */
81 if (option_project
== PROJ_KERNEL
&& *p
== 'z')
84 if (option_project
== PROJ_KERNEL
&& *p
== 'p') {
85 if (*(p
+ 1) == 'I' || *(p
+ 1) == 'i') {
90 if (*p
== 'h' || *p
== 'n' || *p
== 'b' || *p
== 'l')
108 if (*(p
+ 1) == 'M') {
110 if (*p
== 'R' || *p
== 'F')
115 if (*(p
+ 1) == 'm') {
124 arg
= get_argument_from_call_expr(call
->args
, *arg_nr
);
129 ret
= get_array_size_bytes(arg
);
132 /* we don't print the NUL here */
138 if (*p
!= 'd' && *p
!= 'i' && *p
!= 'x' && *p
!= 'X' && *p
!= 'u' && *p
!= 'p') {
144 get_absolute_max(arg
, &max
);
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
)) {
154 ret
= snprintf(buf
, sizeof(buf
), "%lld", max
.value
);
155 get_absolute_min(arg
, &min
);
156 tmp
= snprintf(buf
, sizeof(buf
), "%lld", min
.value
);
160 ret
= snprintf(buf
, sizeof(buf
), "%lld", max
.value
);
171 int get_formatted_string_size(struct expression
*call
, int arg
)
173 struct expression
*expr
;
177 expr
= get_argument_from_call_expr(call
->args
, arg
);
178 if (!expr
|| expr
->type
!= EXPR_STRING
)
183 p
= expr
->string
->data
;
187 count
+= handle_format(call
, &p
, &arg
);
188 } else if (*p
== '\\') {
196 count
++; /* count the NUL terminator */
200 static void match_not_limited(const char *fn
, struct expression
*call
, void *info
)
202 struct param_info
*params
= info
;
203 struct range_list
*rl
;
204 struct expression
*dest
;
205 struct expression
*arg
;
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
== '+') {
216 if (get_hard_max(dest
->right
, &max
))
222 buf_size
= get_array_size_bytes(dest
);
226 size
= get_formatted_string_size(call
, params
->string
);
231 if (size
<= buf_size
)
235 FOR_EACH_PTR(call
->args
, arg
) {
236 if (i
++ <= params
->string
)
238 if (get_user_rl(arg
, &rl
))
240 } END_FOR_EACH_PTR(arg
);
242 sm_error("format string overflow. buf_size: %d length: %d%s",
243 buf_size
, size
, user
? " [user data]": "");
246 void check_string_len(int id
)
249 add_function_hook("sprintf", &match_not_limited
, &zero_one
);