1 /* 2 * Copyright (C) 2013 Oracle. 3 * 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. 8 * 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. 13 * 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 16 */ 17 18 #include <stdlib.h> 19 #include <errno.h> 20 #include "parse.h" 21 #include "smatch.h" 22 #include "smatch_slist.h" 23 #include "smatch_extra.h" 24 25 #define UNKNOWN_SIZE (-1) 26 27 static int my_strlen_id; 28 /* 29 * The trick with the my_equiv_id is that if we have: 30 * foo = strlen(bar); 31 * We don't know at that point what the strlen() is but we know it's equivalent 32 * to "foo" so maybe we can find the value of "foo" later. 33 */ 34 static int my_equiv_id; 35 36 static struct smatch_state *size_to_estate(int size) 37 { 38 sval_t sval; 39 40 sval.type = &int_ctype; 41 sval.value = size; 42 43 return alloc_estate_sval(sval); 44 } 45 46 static struct smatch_state *unmatched_strlen_state(struct sm_state *sm) 47 { 48 return size_to_estate(UNKNOWN_SIZE); 49 } 50 51 static void set_strlen_undefined(struct sm_state *sm, struct expression *mod_expr) 52 { 53 set_state(sm->owner, sm->name, sm->sym, size_to_estate(UNKNOWN_SIZE)); 54 } 55 56 static void set_strlen_equiv_undefined(struct sm_state *sm, struct expression *mod_expr) 57 { 58 set_state(sm->owner, sm->name, sm->sym, &undefined); 59 } 60 61 static void match_string_assignment(struct expression *expr) 62 { 63 struct range_list *rl; 64 65 if (expr->op != '=') 66 return; 67 if (!get_implied_strlen(expr->right, &rl)) 68 return; 69 set_state_expr(my_strlen_id, expr->left, alloc_estate_rl(clone_rl(rl))); 70 } 71 72 static void match_strlen(const char *fn, struct expression *expr, void *unused) 73 { 74 struct expression *right; 75 struct expression *str; 76 struct expression *len_expr; 77 char *len_name; 78 struct smatch_state *state; 79 80 right = strip_expr(expr->right); 81 str = get_argument_from_call_expr(right->args, 0); 82 len_expr = strip_expr(expr->left); 83 84 len_name = expr_to_var(len_expr); 85 if (!len_name) 86 return; 87 88 state = __alloc_smatch_state(0); 89 state->name = len_name; 90 state->data = len_expr; 91 92 set_state_expr(my_equiv_id, str, state); 93 } 94 95 static void match_strlen_condition(struct expression *expr) 96 { 97 struct expression *left; 98 struct expression *right; 99 struct expression *str = NULL; 100 int strlen_left = 0; 101 int strlen_right = 0; 102 sval_t sval; 103 struct smatch_state *true_state = NULL; 104 struct smatch_state *false_state = NULL; 105 int op; 106 107 if (expr->type != EXPR_COMPARE) 108 return; 109 110 left = strip_expr(expr->left); 111 right = strip_expr(expr->right); 112 113 if (left->type == EXPR_CALL && sym_name_is("strlen", left->fn)) { 114 str = get_argument_from_call_expr(left->args, 0); 115 strlen_left = 1; 116 } 117 if (right->type == EXPR_CALL && sym_name_is("strlen", right->fn)) { 118 str = get_argument_from_call_expr(right->args, 0); 119 strlen_right = 1; 120 } 121 122 if (!strlen_left && !strlen_right) 123 return; 124 if (strlen_left && strlen_right) 125 return; 126 127 op = expr->op; 128 if (strlen_left) { 129 if (!get_value(right, &sval)) 130 return; 131 } else { 132 op = flip_comparison(op); 133 if (!get_value(left, &sval)) 134 return; 135 } 136 137 switch (op) { 138 case '<': 139 case SPECIAL_UNSIGNED_LT: 140 true_state = size_to_estate(sval.value - 1); 141 break; 142 case SPECIAL_LTE: 143 case SPECIAL_UNSIGNED_LTE: 144 true_state = size_to_estate(sval.value); 145 break; 146 case SPECIAL_EQUAL: 147 true_state = size_to_estate(sval.value); 148 break; 149 case SPECIAL_NOTEQUAL: 150 false_state = size_to_estate(sval.value); 151 break; 152 case SPECIAL_GTE: 153 case SPECIAL_UNSIGNED_GTE: 154 false_state = size_to_estate(sval.value - 1); 155 break; 156 case '>': 157 case SPECIAL_UNSIGNED_GT: 158 false_state = size_to_estate(sval.value); 159 break; 160 } 161 162 set_true_false_states_expr(my_strlen_id, str, true_state, false_state); 163 } 164 165 static void match_snprintf(const char *fn, struct expression *expr, void *unused) 166 { 167 struct expression *dest; 168 struct expression *dest_size_expr; 169 sval_t limit_size; 170 171 dest = get_argument_from_call_expr(expr->args, 0); 172 dest_size_expr = get_argument_from_call_expr(expr->args, 1); 173 174 if (!get_implied_value(dest_size_expr, &limit_size)) 175 return; 176 177 if (limit_size.value <= 0) 178 return; 179 180 set_state_expr(my_strlen_id, dest, size_to_estate(limit_size.value - 1)); 181 } 182 183 static void match_strlcpycat(const char *fn, struct expression *expr, void *unused) 184 { 185 struct expression *dest; 186 struct expression *src; 187 struct expression *limit_expr; 188 int src_len; 189 sval_t limit; 190 191 dest = get_argument_from_call_expr(expr->args, 0); 192 src = get_argument_from_call_expr(expr->args, 1); 193 limit_expr = get_argument_from_call_expr(expr->args, 2); 194 195 src_len = get_size_from_strlen(src); 196 197 if (!get_implied_max(limit_expr, &limit)) 198 return; 199 if (limit.value < 0 || limit.value > INT_MAX) 200 return; 201 if (src_len != 0 && strcmp(fn, "strcpy") == 0 && src_len < limit.value) 202 limit.value = src_len; 203 204 set_state_expr(my_strlen_id, dest, size_to_estate(limit.value - 1)); 205 } 206 207 static void match_strcpy(const char *fn, struct expression *expr, void *unused) 208 { 209 struct expression *dest; 210 struct expression *src; 211 int src_len; 212 213 dest = get_argument_from_call_expr(expr->args, 0); 214 src = get_argument_from_call_expr(expr->args, 1); 215 216 src_len = get_size_from_strlen(src); 217 if (src_len == 0) 218 return; 219 220 set_state_expr(my_strlen_id, dest, size_to_estate(src_len - 1)); 221 } 222 223 static int get_strlen_from_string(struct expression *expr, struct range_list **rl) 224 { 225 sval_t sval; 226 int len; 227 228 len = expr->string->length; 229 sval = sval_type_val(&int_ctype, len - 1); 230 *rl = alloc_rl(sval, sval); 231 return 1; 232 } 233 234 235 static int get_strlen_from_state(struct expression *expr, struct range_list **rl) 236 { 237 struct smatch_state *state; 238 239 state = get_state_expr(my_strlen_id, expr); 240 if (!state) 241 return 0; 242 *rl = estate_rl(state); 243 return 1; 244 } 245 246 static int get_strlen_from_equiv(struct expression *expr, struct range_list **rl) 247 { 248 struct smatch_state *state; 249 250 state = get_state_expr(my_equiv_id, expr); 251 if (!state || !state->data) 252 return 0; 253 if (!get_implied_rl((struct expression *)state->data, rl)) 254 return 0; 255 return 1; 256 } 257 258 /* 259 * This returns the strlen() without the NUL char. 260 */ 261 int get_implied_strlen(struct expression *expr, struct range_list **rl) 262 { 263 264 *rl = NULL; 265 266 expr = strip_expr(expr); 267 if (expr->type == EXPR_STRING) 268 return get_strlen_from_string(expr, rl); 269 270 if (get_strlen_from_state(expr, rl)) 271 return 1; 272 if (get_strlen_from_equiv(expr, rl)) 273 return 1; 274 return 0; 275 } 276 277 int get_size_from_strlen(struct expression *expr) 278 { 279 struct range_list *rl; 280 sval_t max; 281 282 if (!get_implied_strlen(expr, &rl)) 283 return 0; 284 max = rl_max(rl); 285 if (sval_is_negative(max) || sval_is_max(max)) 286 return 0; 287 288 return max.value + 1; /* add one because strlen doesn't include the NULL */ 289 } 290 291 void set_param_strlen(const char *name, struct symbol *sym, char *key, char *value) 292 { 293 struct range_list *rl = NULL; 294 struct smatch_state *state; 295 char fullname[256]; 296 297 if (strncmp(key, "$", 1) != 0) 298 return; 299 300 snprintf(fullname, 256, "%s%s", name, key + 1); 301 302 str_to_rl(&int_ctype, value, &rl); 303 if (!rl || is_whole_rl(rl)) 304 return; 305 state = alloc_estate_rl(rl); 306 set_state(my_strlen_id, fullname, sym, state); 307 } 308 309 static void match_call(struct expression *expr) 310 { 311 struct expression *arg; 312 struct range_list *rl; 313 int i; 314 315 i = 0; 316 FOR_EACH_PTR(expr->args, arg) { 317 if (!get_implied_strlen(arg, &rl)) 318 continue; 319 if (!is_whole_rl(rl)) 320 sql_insert_caller_info(expr, STR_LEN, i, "$", show_rl(rl)); 321 i++; 322 } END_FOR_EACH_PTR(arg); 323 } 324 325 static void struct_member_callback(struct expression *call, int param, char *printed_name, struct sm_state *sm) 326 { 327 if (sm->state == &merged) 328 return; 329 sql_insert_caller_info(call, STR_LEN, param, printed_name, sm->state->name); 330 } 331 332 void register_strlen(int id) 333 { 334 my_strlen_id = id; 335 336 set_dynamic_states(my_strlen_id); 337 338 add_unmatched_state_hook(my_strlen_id, &unmatched_strlen_state); 339 340 select_caller_info_hook(set_param_strlen, STR_LEN); 341 add_hook(&match_string_assignment, ASSIGNMENT_HOOK); 342 343 add_modification_hook(my_strlen_id, &set_strlen_undefined); 344 add_merge_hook(my_strlen_id, &merge_estates); 345 add_hook(&match_call, FUNCTION_CALL_HOOK); 346 add_member_info_callback(my_strlen_id, struct_member_callback); 347 add_hook(&match_strlen_condition, CONDITION_HOOK); 348 349 add_function_hook("snprintf", &match_snprintf, NULL); 350 351 add_function_hook("strlcpy", &match_strlcpycat, NULL); 352 add_function_hook("strlcat", &match_strlcpycat, NULL); 353 add_function_hook("strcpy", &match_strcpy, NULL); 354 } 355 356 void register_strlen_equiv(int id) 357 { 358 my_equiv_id = id; 359 set_dynamic_states(my_equiv_id); 360 add_function_assign_hook("strlen", &match_strlen, NULL); 361 add_modification_hook(my_equiv_id, &set_strlen_equiv_undefined); 362 } 363