1 /* 2 * Copyright (C) 2019 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 /* 19 * There are a bunch of allocation functions where we allocate some memory, 20 * set up some struct members and then return the allocated memory. One 21 * nice thing about this is that we just one pointer to the allocated memory 22 * so what we can do is we can generate a mtag alias for it in the caller. 23 */ 24 25 #include "smatch.h" 26 #include "smatch_extra.h" 27 #include "smatch_slist.h" 28 29 static int my_id; 30 31 STATE(fresh); 32 33 struct alloc_info *alloc_funcs; 34 35 struct alloc_info kernel_allocation_funcs[] = { 36 {"kmalloc", 0}, 37 {"kmalloc_node", 0}, 38 {"kzalloc", 0}, 39 {"kzalloc_node", 0}, 40 {"vmalloc", 0}, 41 {"__vmalloc", 0}, 42 {"kvmalloc", 0}, 43 {"kcalloc", 0, 1}, 44 {"kmalloc_array", 0, 1}, 45 {"sock_kmalloc", 1}, 46 {"kmemdup", 1}, 47 {"kmemdup_user", 1}, 48 {"dma_alloc_attrs", 1}, 49 {"pci_alloc_consistent", 1}, 50 {"pci_alloc_coherent", 1}, 51 {"devm_kmalloc", 1}, 52 {"devm_kzalloc", 1}, 53 {"krealloc", 1}, 54 {"__alloc_bootmem", 0}, 55 {"alloc_bootmem", 0}, 56 {"dma_alloc_contiguous", 1}, 57 {"dma_alloc_coherent", 1}, 58 {}, 59 }; 60 61 struct alloc_info general_allocation_funcs[] = { 62 {"malloc", 0}, 63 {"calloc", 0, 1}, 64 {"memdup", 1}, 65 {"realloc", 1}, 66 {}, 67 }; 68 69 static void pre_merge_hook(struct sm_state *cur, struct sm_state *other) 70 { 71 struct smatch_state *state; 72 sval_t sval; 73 74 state = get_state(SMATCH_EXTRA, cur->name, cur->sym); 75 if (estate_get_single_value(state, &sval) && sval.value == 0) 76 set_state(my_id, cur->name, cur->sym, &undefined); 77 } 78 79 static int fresh_callback(void *fresh, int argc, char **argv, char **azColName) 80 { 81 *(int *)fresh = 1; 82 return 0; 83 } 84 85 static int fresh_from_db(struct expression *call) 86 { 87 int fresh = 0; 88 89 /* for function pointers assume everything is used */ 90 if (call->fn->type != EXPR_SYMBOL) 91 return 0; 92 93 run_sql(&fresh_callback, &fresh, 94 "select * from return_states where %s and type = %d and parameter = -1 and key = '$' limit 1;", 95 get_static_filter(call->fn->symbol), FRESH_ALLOC); 96 return fresh; 97 } 98 99 bool is_fresh_alloc_var_sym(const char *var, struct symbol *sym) 100 { 101 return get_state(my_id, var, sym) == &fresh; 102 } 103 104 bool is_fresh_alloc(struct expression *expr) 105 { 106 sval_t sval; 107 int i; 108 109 if (!expr) 110 return false; 111 112 if (get_implied_value_fast(expr, &sval) && sval.value == 0) 113 return false; 114 115 if (get_state_expr(my_id, expr) == &fresh) 116 return true; 117 118 if (expr->type != EXPR_CALL) 119 return false; 120 if (fresh_from_db(expr)) 121 return true; 122 i = -1; 123 while (alloc_funcs[++i].fn) { 124 if (sym_name_is(kernel_allocation_funcs[i].fn, expr->fn)) 125 return true; 126 } 127 return false; 128 } 129 130 static void record_alloc_func(int return_id, char *return_ranges, struct expression *expr) 131 { 132 if (!is_fresh_alloc(expr)) 133 return; 134 sql_insert_return_states(return_id, return_ranges, FRESH_ALLOC, -1, "$", ""); 135 } 136 137 static void set_unfresh(struct expression *expr) 138 { 139 struct sm_state *sm; 140 141 sm = get_sm_state_expr(my_id, expr); 142 if (!sm) 143 return; 144 if (!slist_has_state(sm->possible, &fresh)) 145 return; 146 // TODO call unfresh hooks 147 set_state_expr(my_id, expr, &undefined); 148 } 149 150 static void match_assign(struct expression *expr) 151 { 152 set_unfresh(expr->right); 153 } 154 155 static void match_call(struct expression *expr) 156 { 157 struct expression *arg; 158 159 FOR_EACH_PTR(expr->args, arg) { 160 set_unfresh(arg); 161 } END_FOR_EACH_PTR(arg); 162 } 163 164 static struct expression *handled; 165 static void set_fresh(struct expression *expr) 166 { 167 struct range_list *rl; 168 169 expr = strip_expr(expr); 170 if (expr->type != EXPR_SYMBOL) 171 return; 172 if (expr == handled) 173 return; 174 175 get_absolute_rl(expr, &rl); 176 rl = rl_intersection(rl, valid_ptr_rl); 177 if (!rl) 178 return; 179 set_state_expr(my_id, expr, &fresh); 180 handled = expr; 181 } 182 183 static void returns_fresh_alloc(struct expression *expr, int param, char *key, char *value) 184 { 185 if (param != -1 || !key || strcmp(key, "$") != 0) 186 return; 187 if (expr->type != EXPR_ASSIGNMENT) 188 return; 189 190 set_fresh(expr->left); 191 } 192 193 static void match_alloc(const char *fn, struct expression *expr, void *_size_arg) 194 { 195 set_fresh(expr->left); 196 } 197 198 void register_fresh_alloc(int id) 199 { 200 int i; 201 202 my_id = id; 203 204 if (option_project == PROJ_KERNEL) 205 alloc_funcs = kernel_allocation_funcs; 206 else 207 alloc_funcs = general_allocation_funcs; 208 209 i = -1; 210 while (alloc_funcs[++i].fn) 211 add_function_assign_hook(alloc_funcs[i].fn, &match_alloc, 0); 212 213 add_split_return_callback(&record_alloc_func); 214 select_return_states_hook(FRESH_ALLOC, &returns_fresh_alloc); 215 add_hook(&match_assign, ASSIGNMENT_HOOK); 216 add_hook(&match_call, FUNCTION_CALL_HOOK); 217 218 add_pre_merge_hook(my_id, &pre_merge_hook); 219 } 220