1 /* 2 * Copyright (C) 2017 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 "smatch.h" 19 #include "smatch_extra.h" 20 21 static int my_id; 22 23 struct allocator { 24 const char *func; 25 int param; 26 int param2; 27 }; 28 29 static struct allocator illumos_user_allocator_table[] = { 30 {"libld_malloc", 0}, 31 {"libld_realloc", 1}, 32 }; 33 34 static struct allocator generic_allocator_table[] = { 35 {"malloc", 0}, 36 {"memdup", 1}, 37 {"realloc", 1}, 38 }; 39 40 static struct allocator kernel_allocator_table[] = { 41 {"kmalloc", 0}, 42 {"kzalloc", 0}, 43 {"vmalloc", 0}, 44 {"__vmalloc", 0}, 45 {"vzalloc", 0}, 46 {"sock_kmalloc", 1}, 47 {"kmemdup", 1}, 48 {"kmemdup_user", 1}, 49 {"dma_alloc_attrs", 1}, 50 {"pci_alloc_consistent", 1}, 51 {"pci_alloc_coherent", 1}, 52 {"devm_kmalloc", 1}, 53 {"devm_kzalloc", 1}, 54 {"krealloc", 1}, 55 }; 56 57 static struct allocator illumos_user_calloc_table[] = { 58 {"libld_calloc", 0, 1}, 59 {"calloc", 0, 1}, 60 {"kcalloc", 0, 1}, 61 {"kmalloc_array", 0, 1}, 62 {"devm_kcalloc", 1, 2}, 63 }; 64 65 static struct allocator generic_calloc_table[] = { 66 {"calloc", 0, 1}, 67 }; 68 69 static struct allocator kernel_calloc_table[] = { 70 {"kcalloc", 0, 1}, 71 {"kmalloc_array", 0, 1}, 72 {"devm_kcalloc", 1, 2}, 73 }; 74 75 static int bytes_per_element(struct expression *expr) 76 { 77 struct symbol *type; 78 79 type = get_type(expr); 80 if (!type) 81 return 0; 82 83 if (type->type != SYM_PTR && type->type != SYM_ARRAY) 84 return 0; 85 86 type = get_base_type(type); 87 return type_bytes(type); 88 } 89 90 static void save_constraint_required(struct expression *pointer, int op, struct expression *constraint) 91 { 92 char *data, *limit; 93 94 data = get_constraint_str(pointer); 95 if (!data) 96 return; 97 98 limit = get_constraint_str(constraint); 99 if (!limit) { 100 // FIXME deal with <= also 101 if (op == '<') 102 set_state_expr(my_id, constraint, alloc_state_expr(pointer)); 103 goto free_data; 104 } 105 106 sql_save_constraint_required(data, op, limit); 107 108 free_string(limit); 109 free_data: 110 free_string(data); 111 } 112 113 static int handle_zero_size_arrays(struct expression *pointer, struct expression *size) 114 { 115 struct expression *left, *right; 116 struct symbol *type, *array, *array_type; 117 sval_t struct_size; 118 char *limit; 119 char data[128]; 120 121 if (size->type != EXPR_BINOP || size->op != '+') 122 return 0; 123 124 type = get_type(pointer); 125 if (!type || type->type != SYM_PTR) 126 return 0; 127 type = get_real_base_type(type); 128 if (!type || !type->ident || type->type != SYM_STRUCT) 129 return 0; 130 if (!last_member_is_resizable(type)) 131 return 0; 132 array = last_ptr_list((struct ptr_list *)type->symbol_list); 133 if (!array || !array->ident) 134 return 0; 135 array_type = get_real_base_type(array); 136 if (!array_type || array_type->type != SYM_ARRAY) 137 return 0; 138 array_type = get_real_base_type(array_type); 139 140 left = strip_expr(size->left); 141 right = strip_expr(size->right); 142 143 if (!get_implied_value(left, &struct_size)) 144 return 0; 145 if (struct_size.value != type_bytes(type)) 146 return 0; 147 148 if (right->type == EXPR_BINOP && right->op == '*') { 149 struct expression *mult_left, *mult_right; 150 sval_t sval; 151 152 mult_left = strip_expr(right->left); 153 mult_right = strip_expr(right->right); 154 155 if (get_implied_value(mult_left, &sval) && 156 sval.value == type_bytes(array_type)) 157 size = mult_right; 158 else if (get_implied_value(mult_right, &sval) && 159 sval.value == type_bytes(array_type)) 160 size = mult_left; 161 else 162 return 0; 163 } 164 165 snprintf(data, sizeof(data), "(struct %s)->%s", type->ident->name, array->ident->name); 166 limit = get_constraint_str(size); 167 if (!limit) { 168 set_state_expr(my_id, size, alloc_state_expr( 169 member_expression(deref_expression(pointer), '*', array->ident))); 170 return 1; 171 } 172 173 sql_save_constraint_required(data, '<', limit); 174 175 free_string(limit); 176 return 1; 177 } 178 179 static void match_alloc_helper(struct expression *pointer, struct expression *size, int recurse) 180 { 181 struct expression *size_orig, *tmp; 182 sval_t sval; 183 int cnt = 0; 184 185 pointer = strip_expr(pointer); 186 size = strip_expr(size); 187 if (!size || !pointer) 188 return; 189 190 size_orig = size; 191 if (recurse) { 192 while ((tmp = get_assigned_expr(size))) { 193 size = strip_expr(tmp); 194 if (cnt++ > 5) 195 break; 196 } 197 if (size != size_orig) { 198 match_alloc_helper(pointer, size, 0); 199 size = size_orig; 200 } 201 } 202 203 if (handle_zero_size_arrays(pointer, size)) 204 return; 205 206 if (size->type == EXPR_BINOP && size->op == '*') { 207 struct expression *mult_left, *mult_right; 208 209 mult_left = strip_expr(size->left); 210 mult_right = strip_expr(size->right); 211 212 if (get_implied_value(mult_left, &sval) && 213 sval.value == bytes_per_element(pointer)) 214 size = mult_right; 215 else if (get_implied_value(mult_right, &sval) && 216 sval.value == bytes_per_element(pointer)) 217 size = mult_left; 218 else 219 return; 220 } 221 222 if (size->type == EXPR_BINOP && size->op == '+' && 223 get_implied_value(size->right, &sval) && 224 sval.value == 1) 225 save_constraint_required(pointer, SPECIAL_LTE, size->left); 226 else 227 save_constraint_required(pointer, '<', size); 228 } 229 230 static void match_alloc(const char *fn, struct expression *expr, void *_size_arg) 231 { 232 int size_arg = PTR_INT(_size_arg); 233 struct expression *call, *arg; 234 235 call = strip_expr(expr->right); 236 arg = get_argument_from_call_expr(call->args, size_arg); 237 238 match_alloc_helper(expr->left, arg, 1); 239 } 240 241 static void match_calloc(const char *fn, struct expression *expr, void *_start_arg) 242 { 243 struct expression *pointer, *call, *size; 244 struct expression *count = NULL; 245 int start_arg = PTR_INT(_start_arg); 246 sval_t sval; 247 248 pointer = strip_expr(expr->left); 249 call = strip_expr(expr->right); 250 251 size = get_argument_from_call_expr(call->args, start_arg); 252 if (get_implied_value(size, &sval) && 253 sval.value == bytes_per_element(pointer)) 254 count = get_argument_from_call_expr(call->args, start_arg + 1); 255 else { 256 size = get_argument_from_call_expr(call->args, start_arg + 1); 257 if (get_implied_value(size, &sval) && 258 sval.value == bytes_per_element(pointer)) 259 count = get_argument_from_call_expr(call->args, start_arg); 260 } 261 262 if (!count) 263 return; 264 265 save_constraint_required(pointer, '<', count); 266 } 267 268 static void add_allocation_function(const char *func, void *call_back, int param) 269 { 270 add_function_assign_hook(func, call_back, INT_PTR(param)); 271 } 272 273 static void match_assign_size(struct expression *expr) 274 { 275 struct smatch_state *state; 276 char *data, *limit; 277 278 state = get_state_expr(my_id, expr->right); 279 if (!state || !state->data) 280 return; 281 282 data = get_constraint_str(state->data); 283 if (!data) 284 return; 285 286 limit = get_constraint_str(expr->left); 287 if (!limit) 288 goto free_data; 289 290 sql_save_constraint_required(data, '<', limit); 291 292 free_string(limit); 293 free_data: 294 free_string(data); 295 } 296 297 static void match_assign_has_buf_comparison(struct expression *expr) 298 { 299 struct expression *size; 300 301 if (expr->op != '=') 302 return; 303 if (expr->right->type == EXPR_CALL) 304 return; 305 size = get_size_variable(expr->right); 306 if (!size) 307 return; 308 match_alloc_helper(expr->left, size, 1); 309 } 310 311 static void match_assign_data(struct expression *expr) 312 { 313 struct expression *right, *arg, *tmp; 314 int i; 315 int size_arg; 316 int size_arg2 = -1; 317 318 if (expr->op != '=') 319 return; 320 321 /* Direct calls are handled else where (for now at least) */ 322 tmp = get_assigned_expr(expr->right); 323 if (!tmp) 324 return; 325 326 right = strip_expr(tmp); 327 if (right->type != EXPR_CALL) 328 return; 329 330 if (right->fn->type != EXPR_SYMBOL || 331 !right->fn->symbol || 332 !right->fn->symbol->ident) 333 return; 334 335 for (i = 0; i < ARRAY_SIZE(generic_allocator_table); i++) { 336 if (strcmp(right->fn->symbol->ident->name, 337 generic_allocator_table[i].func) == 0) { 338 size_arg = generic_allocator_table[i].param; 339 goto found; 340 } 341 } 342 343 for (i = 0; i < ARRAY_SIZE(generic_calloc_table); i++) { 344 if (strcmp(right->fn->symbol->ident->name, 345 generic_calloc_table[i].func) == 0) { 346 size_arg = generic_calloc_table[i].param; 347 size_arg2 = generic_calloc_table[i].param2; 348 goto found; 349 } 350 } 351 352 if (option_project == PROJ_ILLUMOS_USER) { 353 if (strcmp(right->fn->symbol->ident->name, 354 illumos_user_allocator_table[i].func) == 0) { 355 size_arg = illumos_user_allocator_table[i].param; 356 goto found; 357 } 358 359 for (i = 0; i < ARRAY_SIZE(illumos_user_calloc_table); i++) { 360 if (strcmp(right->fn->symbol->ident->name, 361 illumos_user_calloc_table[i].func) == 0) { 362 size_arg = illumos_user_calloc_table[i].param; 363 size_arg2 = illumos_user_calloc_table[i].param2; 364 goto found; 365 } 366 } 367 } 368 369 if (option_project != PROJ_KERNEL) 370 return; 371 372 for (i = 0; i < ARRAY_SIZE(kernel_allocator_table); i++) { 373 if (strcmp(right->fn->symbol->ident->name, 374 kernel_allocator_table[i].func) == 0) { 375 size_arg = kernel_allocator_table[i].param; 376 goto found; 377 } 378 } 379 380 for (i = 0; i < ARRAY_SIZE(kernel_calloc_table); i++) { 381 if (strcmp(right->fn->symbol->ident->name, 382 kernel_calloc_table[i].func) == 0) { 383 size_arg = kernel_calloc_table[i].param; 384 size_arg2 = kernel_calloc_table[i].param2; 385 goto found; 386 } 387 } 388 389 return; 390 391 found: 392 arg = get_argument_from_call_expr(right->args, size_arg); 393 match_alloc_helper(expr->left, arg, 1); 394 if (size_arg2 == -1) 395 return; 396 arg = get_argument_from_call_expr(right->args, size_arg2); 397 match_alloc_helper(expr->left, arg, 1); 398 } 399 400 static void match_assign_ARRAY_SIZE(struct expression *expr) 401 { 402 struct expression *array; 403 char *data, *limit; 404 const char *macro; 405 406 macro = get_macro_name(expr->right->pos); 407 if (!macro || strcmp(macro, "ARRAY_SIZE") != 0) 408 return; 409 array = strip_expr(expr->right); 410 if (array->type != EXPR_BINOP || array->op != '+') 411 return; 412 array = strip_expr(array->left); 413 if (array->type != EXPR_BINOP || array->op != '/') 414 return; 415 array = strip_expr(array->left); 416 if (array->type != EXPR_SIZEOF) 417 return; 418 array = strip_expr(array->cast_expression); 419 if (array->type != EXPR_PREOP || array->op != '*') 420 return; 421 array = strip_expr(array->unop); 422 423 data = get_constraint_str(array); 424 limit = get_constraint_str(expr->left); 425 if (!data || !limit) 426 goto free; 427 428 sql_save_constraint_required(data, '<', limit); 429 430 free: 431 free_string(data); 432 free_string(limit); 433 } 434 435 static void match_assign_buf_comparison(struct expression *expr) 436 { 437 struct expression *pointer; 438 439 if (expr->op != '=') 440 return; 441 pointer = get_array_variable(expr->right); 442 if (!pointer) 443 return; 444 445 match_alloc_helper(pointer, expr->right, 1); 446 } 447 448 static int constraint_found(void *_found, int argc, char **argv, char **azColName) 449 { 450 int *found = _found; 451 452 *found = 1; 453 return 0; 454 } 455 456 static int has_constraint(struct expression *expr, const char *constraint) 457 { 458 int found = 0; 459 460 if (get_state_expr(my_id, expr)) 461 return 1; 462 463 run_sql(constraint_found, &found, 464 "select data from constraints_required where bound = '%q' limit 1", 465 escape_newlines(constraint)); 466 467 return found; 468 } 469 470 static void match_assign_constraint(struct expression *expr) 471 { 472 struct symbol *type; 473 char *left, *right; 474 475 if (expr->op != '=') 476 return; 477 478 type = get_type(expr->left); 479 if (!type || type->type != SYM_BASETYPE) 480 return; 481 482 left = get_constraint_str(expr->left); 483 if (!left) 484 return; 485 right = get_constraint_str(expr->right); 486 if (!right) 487 goto free; 488 if (!has_constraint(expr->right, right)) 489 return; 490 sql_copy_constraint_required(left, right); 491 free: 492 free_string(right); 493 free_string(left); 494 } 495 496 void register_constraints_required(int id) 497 { 498 my_id = id; 499 500 add_hook(&match_assign_size, ASSIGNMENT_HOOK); 501 add_hook(&match_assign_data, ASSIGNMENT_HOOK); 502 add_hook(&match_assign_has_buf_comparison, ASSIGNMENT_HOOK); 503 504 add_hook(&match_assign_ARRAY_SIZE, ASSIGNMENT_HOOK); 505 add_hook(&match_assign_ARRAY_SIZE, GLOBAL_ASSIGNMENT_HOOK); 506 add_hook(&match_assign_buf_comparison, ASSIGNMENT_HOOK); 507 add_hook(&match_assign_constraint, ASSIGNMENT_HOOK); 508 509 add_allocation_function("malloc", &match_alloc, 0); 510 add_allocation_function("memdup", &match_alloc, 1); 511 add_allocation_function("realloc", &match_alloc, 1); 512 add_allocation_function("calloc", &match_calloc, 0); 513 if (option_project == PROJ_ILLUMOS_USER) { 514 add_allocation_function("libld_malloc", &match_alloc, 0); 515 add_allocation_function("libld_realloc", &match_alloc, 1); 516 add_allocation_function("libld_calloc", &match_calloc, 0); 517 } 518 if (option_project == PROJ_KERNEL) { 519 add_allocation_function("kmalloc", &match_alloc, 0); 520 add_allocation_function("kzalloc", &match_alloc, 0); 521 add_allocation_function("vmalloc", &match_alloc, 0); 522 add_allocation_function("__vmalloc", &match_alloc, 0); 523 add_allocation_function("vzalloc", &match_alloc, 0); 524 add_allocation_function("sock_kmalloc", &match_alloc, 1); 525 add_allocation_function("kmemdup", &match_alloc, 1); 526 add_allocation_function("kmemdup_user", &match_alloc, 1); 527 add_allocation_function("dma_alloc_attrs", &match_alloc, 1); 528 add_allocation_function("pci_alloc_consistent", &match_alloc, 1); 529 add_allocation_function("pci_alloc_coherent", &match_alloc, 1); 530 add_allocation_function("devm_kmalloc", &match_alloc, 1); 531 add_allocation_function("devm_kzalloc", &match_alloc, 1); 532 add_allocation_function("kcalloc", &match_calloc, 0); 533 add_allocation_function("kmalloc_array", &match_calloc, 0); 534 add_allocation_function("devm_kcalloc", &match_calloc, 1); 535 add_allocation_function("krealloc", &match_alloc, 1); 536 } 537 }