1 /* 2 * Copyright (C) 2014 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 * Sometimes we aren't able to track a variable through a function call. This 20 * usually happens because a function changes too many variables so we give up. 21 * Another reason this happens is because we call a function pointer and there 22 * are too many functions which implement that function pointer so we give up. 23 * Also maybe we don't have the database enabled. 24 * 25 * The goal here is to make a call back so what if we call: 26 * 27 * frob(&foo); 28 * 29 * but we're not able to say what happens to "foo", then let's assume that we 30 * don't know anything about "foo" if it's an untracked call. 31 * 32 */ 33 34 #include "smatch.h" 35 #include "smatch_slist.h" 36 #include "smatch_extra.h" 37 38 static int my_id; 39 static int tracked; 40 41 STATE(untracked); 42 43 typedef void (untracked_hook)(struct expression *call, int param); 44 DECLARE_PTR_LIST(untracked_hook_list, untracked_hook *); 45 static struct untracked_hook_list *untracked_hooks; 46 47 struct int_stack *tracked_stack; 48 49 void add_untracked_param_hook(void (func)(struct expression *call, int param)) 50 { 51 untracked_hook **p = malloc(sizeof(untracked_hook *)); 52 *p = func; 53 add_ptr_list(&untracked_hooks, p); 54 } 55 56 static void call_untracked_callbacks(struct expression *expr, int param) 57 { 58 untracked_hook **fn; 59 60 FOR_EACH_PTR(untracked_hooks, fn) { 61 (*fn)(expr, param); 62 } END_FOR_EACH_PTR(fn); 63 } 64 65 static void assume_tracked(struct expression *call_expr, int param, char *key, char *value) 66 { 67 tracked = 1; 68 } 69 70 void mark_untracked(struct expression *expr, int param, const char *key, const char *value) 71 { 72 char *name; 73 struct symbol *sym; 74 75 while (expr->type == EXPR_ASSIGNMENT) 76 expr = strip_expr(expr->right); 77 if (expr->type != EXPR_CALL) 78 return; 79 80 name = return_state_to_var_sym(expr, param, key, &sym); 81 if (!name || !sym) 82 goto free; 83 84 call_untracked_callbacks(expr, param); 85 set_state(my_id, name, sym, &untracked); 86 free: 87 free_string(name); 88 } 89 90 static int lost_in_va_args(struct expression *expr) 91 { 92 struct symbol *fn; 93 char *name; 94 int is_lost; 95 96 fn = get_type(expr->fn); 97 if (!fn || !fn->variadic) 98 return 0; 99 100 is_lost = 1; 101 name = expr_to_var(expr->fn); 102 if (name && strstr(name, "print")) 103 is_lost = 0; 104 free_string(name); 105 106 return is_lost; 107 } 108 109 static void match_after_call(struct expression *expr) 110 { 111 struct expression *arg; 112 struct symbol *type; 113 int i; 114 115 if (lost_in_va_args(expr)) 116 tracked = 0; 117 118 if (tracked) { 119 tracked = 0; 120 return; 121 } 122 123 i = -1; 124 FOR_EACH_PTR(expr->args, arg) { 125 i++; 126 127 type = get_type(arg); 128 if (!type || type->type != SYM_PTR) 129 continue; 130 131 call_untracked_callbacks(expr, i); 132 set_state_expr(my_id, arg, &untracked); 133 } END_FOR_EACH_PTR(arg); 134 } 135 136 void mark_all_params_untracked(int return_id, char *return_ranges, struct expression *expr) 137 { 138 struct symbol *arg; 139 int param; 140 141 param = -1; 142 FOR_EACH_PTR(cur_func_sym->ctype.base_type->arguments, arg) { 143 param++; 144 145 if (!arg->ident) 146 continue; 147 sql_insert_return_states(return_id, return_ranges, 148 UNTRACKED_PARAM, param, "$", ""); 149 } END_FOR_EACH_PTR(arg); 150 } 151 152 static void print_untracked_params(int return_id, char *return_ranges, struct expression *expr) 153 { 154 struct symbol *arg; 155 int param; 156 157 param = -1; 158 FOR_EACH_PTR(cur_func_sym->ctype.base_type->arguments, arg) { 159 param++; 160 161 if (!arg->ident) 162 continue; 163 if (!get_state(my_id, arg->ident->name, arg) && 164 !__bail_on_rest_of_function) /* hairy functions are untrackable */ 165 continue; 166 167 sql_insert_return_states(return_id, return_ranges, 168 UNTRACKED_PARAM, param, "$", ""); 169 } END_FOR_EACH_PTR(arg); 170 } 171 172 static void match_param_assign(struct expression *expr) 173 { 174 struct expression *right; 175 struct symbol *type; 176 int param; 177 178 if (__in_fake_assign) 179 return; 180 181 right = strip_expr(expr->right); 182 type = get_type(right); 183 if (!type || type->type != SYM_PTR) 184 return; 185 186 param = get_param_num(right); 187 if (param < 0) 188 return; 189 190 set_state_expr(my_id, right, &untracked); 191 } 192 193 194 static void match_param_assign_in_asm(struct statement *stmt) 195 { 196 197 struct expression *expr; 198 struct symbol *type; 199 int state = 0; 200 int param; 201 202 FOR_EACH_PTR(stmt->asm_inputs, expr) { 203 switch (state) { 204 case 0: /* identifier */ 205 case 1: /* constraint */ 206 state++; 207 continue; 208 case 2: /* expression */ 209 state = 0; 210 211 expr = strip_expr(expr); 212 type = get_type(expr); 213 if (!type || type->type != SYM_PTR) 214 continue; 215 param = get_param_num(expr); 216 if (param < 0) 217 continue; 218 set_state_expr(my_id, expr, &untracked); 219 continue; 220 } 221 } END_FOR_EACH_PTR(expr); 222 } 223 224 static void match_inline_start(struct expression *expr) 225 { 226 push_int(&tracked_stack, tracked); 227 } 228 229 static void match_inline_end(struct expression *expr) 230 { 231 tracked = pop_int(&tracked_stack); 232 } 233 234 void register_untracked_param(int id) 235 { 236 my_id = id; 237 238 select_return_states_hook(INTERNAL, &assume_tracked); 239 select_return_states_hook(UNTRACKED_PARAM, &mark_untracked); 240 add_hook(&match_after_call, FUNCTION_CALL_HOOK_AFTER_DB); 241 242 add_split_return_callback(&print_untracked_params); 243 244 add_hook(&match_param_assign, ASSIGNMENT_HOOK); 245 add_hook(&match_param_assign_in_asm, ASM_HOOK); 246 247 add_hook(&match_inline_start, INLINE_FN_START); 248 add_hook(&match_inline_end, INLINE_FN_END); 249 } 250