1 /* 2 * Copyright (C) 2017 Oracle. All rights reserved. 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 /* 19 * One problem that I have is that it's really hard to track how pointers are 20 * passed around. For example, it would be nice to know that the probe() and 21 * remove() functions get the same pci_dev pointer. It would be good to know 22 * what pointers we're passing to the open() and close() functions. But that 23 * information gets lost in a call tree full of function pointer calls. 24 * 25 * I think the first step is to start naming specific pointers. So when a 26 * pointer is allocated, then it gets a tag. So calls to kmalloc() generate a 27 * tag. But we might not use that, because there might be a better name like 28 * framebuffer_alloc(). The framebuffer_alloc() is interesting because there is 29 * one per driver and it's passed around to all the file operations. 30 * 31 * Perhaps we could make a list of functions like framebuffer_alloc() which take 32 * a size and say that those are the interesting alloc functions. 33 * 34 * Another place where we would maybe name the pointer is when they are passed 35 * to the probe(). Because that's an important pointer, since there is one 36 * per driver (sort of). 37 * 38 * My vision is that you could take a pointer and trace it back to a global. So 39 * I'm going to track that pointer_tag - 28 bytes takes you to another pointer 40 * tag. You could follow that one back and so on. Also when we pass a pointer 41 * to a function that would be recorded as sort of a link or path or something. 42 * 43 */ 44 45 #include "smatch.h" 46 #include "smatch_slist.h" 47 #include "smatch_extra.h" 48 49 #include <openssl/md5.h> 50 51 static int my_id; 52 53 mtag_t str_to_mtag(const char *str) 54 { 55 unsigned char c[MD5_DIGEST_LENGTH]; 56 unsigned long long *tag = (unsigned long long *)&c; 57 MD5_CTX mdContext; 58 int len; 59 60 len = strlen(str); 61 MD5_Init(&mdContext); 62 MD5_Update(&mdContext, str, len); 63 MD5_Final(c, &mdContext); 64 65 *tag &= ~MTAG_ALIAS_BIT; 66 *tag &= ~MTAG_OFFSET_MASK; 67 68 return *tag; 69 } 70 71 static int save_allocator(void *_allocator, int argc, char **argv, char **azColName) 72 { 73 char **allocator = _allocator; 74 75 if (*allocator) { 76 if (strcmp(*allocator, argv[0]) == 0) 77 return 0; 78 /* should be impossible */ 79 free_string(*allocator); 80 *allocator = alloc_string("unknown"); 81 return 0; 82 } 83 *allocator = alloc_string(argv[0]); 84 return 0; 85 } 86 87 char *get_allocator_info_from_tag(mtag_t tag) 88 { 89 char *allocator = NULL; 90 91 run_sql(save_allocator, &allocator, 92 "select value from mtag_info where tag = %lld and type = %d;", 93 tag, ALLOCATOR); 94 95 return allocator; 96 } 97 98 static char *get_allocator_info(struct expression *expr, struct smatch_state *state) 99 { 100 sval_t sval; 101 102 if (expr->type != EXPR_ASSIGNMENT) 103 return NULL; 104 if (estate_get_single_value(state, &sval)) 105 return get_allocator_info_from_tag(sval.value); 106 107 expr = strip_expr(expr->right); 108 if (expr->type != EXPR_CALL || 109 !expr->fn || 110 expr->fn->type != EXPR_SYMBOL) 111 return NULL; 112 return expr_to_str(expr->fn); 113 } 114 115 static void update_mtag_info(struct expression *expr, mtag_t tag, 116 const char *left_name, const char *tag_info, 117 struct smatch_state *state) 118 { 119 char *allocator; 120 121 sql_insert_mtag_about(tag, left_name, tag_info); 122 123 allocator = get_allocator_info(expr, state); 124 if (allocator) 125 sql_insert_mtag_info(tag, ALLOCATOR, allocator); 126 } 127 128 struct smatch_state *get_mtag_return(struct expression *expr, struct smatch_state *state) 129 { 130 struct expression *left, *right; 131 char *left_name, *right_name; 132 struct symbol *left_sym; 133 struct range_list *rl; 134 char buf[256]; 135 mtag_t tag; 136 sval_t tag_sval; 137 138 if (!expr || expr->type != EXPR_ASSIGNMENT || expr->op != '=') 139 return NULL; 140 if (!is_fresh_alloc(expr->right)) 141 return NULL; 142 if (!rl_intersection(estate_rl(state), valid_ptr_rl)) 143 return NULL; 144 145 left = strip_expr(expr->left); 146 right = strip_expr(expr->right); 147 148 left_name = expr_to_str_sym(left, &left_sym); 149 if (!left_name || !left_sym) 150 return NULL; 151 right_name = expr_to_str(right); 152 153 snprintf(buf, sizeof(buf), "%s %s %s %s", get_filename(), get_function(), 154 left_name, right_name); 155 tag = str_to_mtag(buf); 156 tag_sval.type = estate_type(state); 157 tag_sval.uvalue = tag; 158 159 rl = rl_filter(estate_rl(state), valid_ptr_rl); 160 rl = clone_rl(rl); 161 add_range(&rl, tag_sval, tag_sval); 162 163 update_mtag_info(expr, tag, left_name, buf, state); 164 165 free_string(left_name); 166 free_string(right_name); 167 168 return alloc_estate_rl(rl); 169 } 170 171 int get_string_mtag(struct expression *expr, mtag_t *tag) 172 { 173 mtag_t xor; 174 175 if (expr->type != EXPR_STRING || !expr->string) 176 return 0; 177 178 /* I was worried about collisions so I added a xor */ 179 xor = str_to_mtag("__smatch string"); 180 *tag = str_to_mtag(expr->string->data); 181 *tag = *tag ^ xor; 182 183 return 1; 184 } 185 186 int get_toplevel_mtag(struct symbol *sym, mtag_t *tag) 187 { 188 char buf[256]; 189 190 if (!sym) 191 return 0; 192 193 if (!sym->ident || 194 !(sym->ctype.modifiers & MOD_TOPLEVEL)) 195 return 0; 196 197 snprintf(buf, sizeof(buf), "%s %s", 198 (sym->ctype.modifiers & MOD_STATIC) ? get_filename() : "extern", 199 sym->ident->name); 200 *tag = str_to_mtag(buf); 201 return 1; 202 } 203 204 bool get_symbol_mtag(struct symbol *sym, mtag_t *tag) 205 { 206 char buf[256]; 207 208 if (!sym || !sym->ident) 209 return false; 210 211 if (get_toplevel_mtag(sym, tag)) 212 return true; 213 214 if (get_param_num_from_sym(sym) >= 0) 215 return false; 216 217 snprintf(buf, sizeof(buf), "%s %s %s", 218 get_filename(), get_function(), sym->ident->name); 219 *tag = str_to_mtag(buf); 220 return true; 221 } 222 223 static void global_variable(struct symbol *sym) 224 { 225 mtag_t tag; 226 227 if (!get_toplevel_mtag(sym, &tag)) 228 return; 229 230 sql_insert_mtag_about(tag, 231 sym->ident->name, 232 (sym->ctype.modifiers & MOD_STATIC) ? get_filename() : "extern"); 233 } 234 235 static int get_array_mtag_offset(struct expression *expr, mtag_t *tag, int *offset) 236 { 237 struct expression *array, *offset_expr; 238 struct symbol *type; 239 sval_t sval; 240 int start_offset; 241 242 if (!is_array(expr)) 243 return 0; 244 245 array = get_array_base(expr); 246 if (!array) 247 return 0; 248 type = get_type(array); 249 if (!type || type->type != SYM_ARRAY) 250 return 0; 251 type = get_real_base_type(type); 252 if (!type_bytes(type)) 253 return 0; 254 255 if (!expr_to_mtag_offset(array, tag, &start_offset)) 256 return 0; 257 258 offset_expr = get_array_offset(expr); 259 if (!get_value(offset_expr, &sval)) 260 return 0; 261 *offset = start_offset + sval.value * type_bytes(type); 262 263 return 1; 264 } 265 266 struct range_list *swap_mtag_seed(struct expression *expr, struct range_list *rl) 267 { 268 char buf[256]; 269 char *name; 270 sval_t sval; 271 mtag_t tag; 272 273 if (!rl_to_sval(rl, &sval)) 274 return rl; 275 if (sval.type->type != SYM_PTR || sval.uvalue != MTAG_SEED) 276 return rl; 277 278 name = expr_to_str(expr); 279 snprintf(buf, sizeof(buf), "%s %s %s", get_filename(), get_function(), name); 280 free_string(name); 281 tag = str_to_mtag(buf); 282 sval.value = tag; 283 return alloc_rl(sval, sval); 284 } 285 286 int create_mtag_alias(mtag_t tag, struct expression *expr, mtag_t *new) 287 { 288 char buf[256]; 289 int lines_from_start; 290 char *str; 291 292 /* 293 * We need the alias to be unique. It's not totally required that it 294 * be the same from one DB build to then next, but it makes debugging 295 * a bit simpler. 296 * 297 */ 298 299 if (!cur_func_sym) 300 return 0; 301 302 lines_from_start = expr->pos.line - cur_func_sym->pos.line; 303 str = expr_to_str(expr); 304 snprintf(buf, sizeof(buf), "%lld %d %s", tag, lines_from_start, str); 305 free_string(str); 306 307 *new = str_to_mtag(buf); 308 sql_insert_mtag_alias(tag, *new); 309 310 return 1; 311 } 312 313 static int get_implied_mtag_offset(struct expression *expr, mtag_t *tag, int *offset) 314 { 315 struct smatch_state *state; 316 struct symbol *type; 317 sval_t sval; 318 319 type = get_type(expr); 320 if (!type_is_ptr(type)) 321 return 0; 322 state = get_extra_state(expr); 323 if (!state || !estate_get_single_value(state, &sval) || sval.value == 0) 324 return 0; 325 326 *tag = sval.uvalue & ~MTAG_OFFSET_MASK; 327 *offset = sval.uvalue & MTAG_OFFSET_MASK; 328 return 1; 329 } 330 331 /* 332 * The point of this function is to give you the mtag and the offset so 333 * you can look up the data in the DB. It takes an expression. 334 * 335 * So say you give it "foo->bar". Then it would give you the offset of "bar" 336 * and the implied value of "foo". Or if you lookup "*foo" then the offset is 337 * zero and we look up the implied value of "foo. But if the expression is 338 * foo, then if "foo" is a global variable, then we get the mtag and the offset 339 * is zero. If "foo" is a local variable, then there is nothing to look up in 340 * the mtag_data table because that's handled by smatch_extra.c to this returns 341 * false. 342 * 343 */ 344 int expr_to_mtag_offset(struct expression *expr, mtag_t *tag, int *offset) 345 { 346 *tag = 0; 347 *offset = 0; 348 349 if (bits_in_pointer != 64) 350 return 0; 351 352 expr = strip_expr(expr); 353 if (!expr) 354 return 0; 355 356 if (is_array(expr)) 357 return get_array_mtag_offset(expr, tag, offset); 358 359 if (expr->type == EXPR_PREOP && expr->op == '*') { 360 expr = strip_expr(expr->unop); 361 return get_implied_mtag_offset(expr, tag, offset); 362 } else if (expr->type == EXPR_DEREF) { 363 int tmp, tmp_offset = 0; 364 365 while (expr->type == EXPR_DEREF) { 366 tmp = get_member_offset_from_deref(expr); 367 if (tmp < 0) 368 return 0; 369 tmp_offset += tmp; 370 expr = strip_expr(expr->deref); 371 } 372 *offset = tmp_offset; 373 if (expr->type == EXPR_PREOP && expr->op == '*') { 374 expr = strip_expr(expr->unop); 375 376 if (get_implied_mtag_offset(expr, tag, &tmp_offset)) { 377 // FIXME: look it up recursively? 378 if (tmp_offset) 379 return 0; 380 return 1; 381 } 382 return 0; 383 } else if (expr->type == EXPR_SYMBOL) { 384 return get_symbol_mtag(expr->symbol, tag); 385 } 386 return 0; 387 } else if (expr->type == EXPR_SYMBOL) { 388 return get_symbol_mtag(expr->symbol, tag); 389 } 390 return 0; 391 } 392 393 /* 394 * This function takes an address and returns an sval. Let's take some 395 * example things you might pass to it: 396 * foo->bar: 397 * If we were only called from smatch_math, we wouldn't need to bother with 398 * this because it's already been looked up in smatch_extra.c but this is 399 * also called from other places so we have to check smatch_extra.c. 400 * &foo 401 * If "foo" is global return the mtag for "foo". 402 * &foo.bar 403 * If "foo" is global return the mtag for "foo" + the offset of ".bar". 404 * It also handles string literals. 405 * 406 */ 407 int get_mtag_sval(struct expression *expr, sval_t *sval) 408 { 409 struct symbol *type; 410 mtag_t tag; 411 int offset = 0; 412 413 if (bits_in_pointer != 64) 414 return 0; 415 416 expr = strip_expr(expr); 417 418 type = get_type(expr); 419 if (!type_is_ptr(type)) 420 return 0; 421 /* 422 * There are several options: 423 * 424 * If the expr is a string literal, that's an address/mtag. 425 * SYM_ARRAY and SYM_FN are mtags. There are "&foo" type addresses. 426 * And there are saved pointers "p = &foo;" 427 * 428 */ 429 430 if (expr->type == EXPR_STRING && get_string_mtag(expr, &tag)) 431 goto found; 432 433 if (expr->type == EXPR_SYMBOL && 434 (type->type == SYM_ARRAY || type->type == SYM_FN) && 435 get_toplevel_mtag(expr->symbol, &tag)) 436 goto found; 437 438 if (expr->type == EXPR_PREOP && expr->op == '&') { 439 expr = strip_expr(expr->unop); 440 if (expr_to_mtag_offset(expr, &tag, &offset)) 441 goto found; 442 return 0; 443 } 444 445 if (get_implied_mtag_offset(expr, &tag, &offset)) 446 goto found; 447 448 return 0; 449 found: 450 if (offset >= MTAG_OFFSET_MASK) 451 return 0; 452 453 sval->type = type; 454 sval->uvalue = tag | offset; 455 456 return 1; 457 } 458 459 void register_mtag(int id) 460 { 461 my_id = id; 462 463 464 /* 465 * The mtag stuff only works on 64 systems because we store the 466 * information in the pointer itself. 467 * bit 63 : set for alias mtags 468 * bit 62-12: mtag hash 469 * bit 11-0 : offset 470 * 471 */ 472 473 add_hook(&global_variable, BASE_HOOK); 474 }