1 #include "smatch.h" 2 #include "smatch_slist.h" 3 4 static int my_id; 5 6 /* If set, we ignore struct type symbols as implicit dependencies */ 7 static int ignore_structs; 8 9 static struct symbol *cur_syscall; 10 /* note: cannot track return type and remove from implicit dependencies, 11 * because every syscall returns a long, and we don't have a good way to know 12 * whether or not this is a resource. The only example I can think of is open 13 * returning a filedescriptor, so in the implicit dep parsing, we will just 14 * blacklist struct fd --> file 15 */ 16 static struct symbol *cur_return_type; 17 static char *syscall_name; 18 19 static struct tracker_list *read_list; // what fields does syscall branch on? 20 static struct tracker_list *write_list; // what fields does syscall modify? 21 static struct tracker_list *arg_list; // what struct arguments does the syscall take? 22 static struct tracker_list *parsed_syscalls; // syscalls we have already checked 23 24 static inline void prefix(void) 25 { 26 printf("%s:%d %s() ", get_filename(), get_lineno(), get_function()); 27 } 28 29 static void match_syscall_definition(struct symbol *sym) 30 { 31 struct symbol *arg; 32 struct tracker *tracker; 33 char *macro; 34 char *name; 35 int is_syscall = 0; 36 37 macro = get_macro_name(sym->pos); 38 if (macro && 39 (strncmp("SYSCALL_DEFINE", macro, strlen("SYSCALL_DEFINE")) == 0 || 40 strncmp("COMPAT_SYSCALL_DEFINE", macro, strlen("COMPAT_SYSCALL_DEFINE")) == 0)) 41 is_syscall = 1; 42 43 name = get_function(); 44 45 if (name && strncmp(name, "sys_", 4) == 0) 46 is_syscall = 1; 47 48 if (name && strncmp(name, "compat_sys_", 11) == 0) 49 is_syscall = 1; 50 51 if (!is_syscall) 52 return; 53 54 FOR_EACH_PTR(parsed_syscalls, tracker) { 55 if (tracker->sym == sym) // don't re-parse 56 return; 57 } END_FOR_EACH_PTR(tracker); 58 59 syscall_name = name; 60 cur_syscall = sym; 61 62 cur_return_type = cur_func_return_type(); 63 if (cur_return_type && cur_return_type->ident) 64 sm_msg("return type: %s\n", cur_return_type->ident->name); 65 66 67 FOR_EACH_PTR(sym->ctype.base_type->arguments, arg) { 68 // set_state(my_id, arg->ident->name, arg, &user_data_set); 69 sm_msg("=======check_impl: arguments for call %s=========\n", syscall_name); 70 if (arg->type == SYM_STRUCT) 71 arg = get_real_base_type(arg); 72 if (cur_return_type && cur_return_type->ident) 73 sm_msg("arg type: %s\n", cur_return_type->ident->name); 74 // add_tracker(&arg_list, my_id, member, arg); 75 sm_msg("=================================\n"); 76 } END_FOR_EACH_PTR(arg); 77 } 78 79 static void print_read_list(void) 80 { 81 struct tracker *tracker; 82 int i = 0; 83 84 FOR_EACH_PTR(read_list, tracker) { 85 if (i == 0) 86 sm_printf("%s read_list: [", syscall_name); 87 sm_printf("%s, ", tracker->name); 88 i++; 89 } END_FOR_EACH_PTR(tracker); 90 91 if (i > 0) 92 sm_printf("]\n"); 93 } 94 95 static void print_write_list(void) 96 { 97 struct tracker *tracker; 98 int i = 0; 99 100 FOR_EACH_PTR(write_list, tracker) { 101 if (i == 0) 102 sm_printf("%s write_list: [", syscall_name); 103 sm_printf("%s, ", tracker->name); 104 i++; 105 } END_FOR_EACH_PTR(tracker); 106 107 if (i > 0) 108 sm_printf("]\n"); 109 } 110 111 static void print_arg_list(void) 112 { 113 struct tracker *tracker; 114 int i = 0; 115 116 FOR_EACH_PTR(write_list, tracker) { 117 if (i == 0) 118 sm_printf("%s arg_list: [", syscall_name); 119 sm_printf("%s, ", tracker->name); 120 i++; 121 } END_FOR_EACH_PTR(tracker); 122 123 if (i > 0) 124 sm_printf("]\n"); 125 } 126 127 static void match_after_syscall(struct symbol *sym) 128 { 129 if (!cur_syscall || sym != cur_syscall) 130 return; 131 // printf("\n"); prefix(); 132 // printf("exiting scope of syscall %s\n", get_function()); 133 // printf("-------------------------\n"); 134 print_read_list(); 135 print_write_list(); 136 print_arg_list(); 137 free_trackers_and_list(&read_list); 138 free_trackers_and_list(&write_list); 139 free_trackers_and_list(&arg_list); 140 add_tracker(&parsed_syscalls, my_id, syscall_name, sym); 141 cur_syscall = NULL; 142 cur_return_type = NULL; 143 syscall_name = NULL; 144 } 145 146 static void print_read_member_type(struct expression *expr) 147 { 148 char *member; 149 struct symbol *sym; 150 struct symbol *member_sym; 151 152 member = get_member_name(expr); 153 if (!member) 154 return; 155 156 sym = get_type(expr->deref); 157 member_sym = get_type(expr); 158 159 if (member_sym->type == SYM_PTR) 160 member_sym = get_real_base_type(member_sym); 161 162 /* 163 if (member_sym->type == SYM_STRUCT) 164 printf("found struct type %s\n", member); 165 else 166 printf("found non-struct type %s with enum value%d\n", member, member_sym->type); 167 */ 168 169 if (ignore_structs && member_sym->type == SYM_STRUCT) { 170 // printf("ignoring %s\n", member); 171 return; 172 } 173 174 add_tracker(&read_list, my_id, member, sym); 175 // sm_msg("info: uses %s", member); 176 // prefix(); 177 // printf("info: uses %s\n", member); 178 free_string(member); 179 } 180 181 static void print_write_member_type(struct expression *expr) 182 { 183 char *member; 184 struct symbol *sym; 185 struct symbol *member_sym; 186 187 member = get_member_name(expr); 188 if (!member) 189 return; 190 191 sym = get_type(expr->deref); 192 member_sym = get_type(expr); 193 194 if (member_sym->type == SYM_PTR) 195 member_sym = get_real_base_type(member_sym); 196 197 /* 198 if (member_sym->type == SYM_STRUCT) 199 printf("found struct type %s\n", member); 200 else 201 printf("found non-struct type %s with enum value%d\n", member, member_sym->type); 202 */ 203 204 if (ignore_structs && member_sym->type == SYM_STRUCT) { 205 // printf("ignoring %s\n", member); 206 return; 207 } 208 209 add_tracker(&write_list, my_id, member, sym); 210 free_string(member); 211 } 212 213 static void match_condition(struct expression *expr) 214 { 215 struct expression *arg; 216 217 if (!cur_syscall) 218 return; 219 220 // prefix(); printf("-- condition found\n"); 221 222 if (expr->type == EXPR_COMPARE || 223 expr->type == EXPR_BINOP || 224 expr->type == EXPR_LOGICAL || 225 expr->type == EXPR_ASSIGNMENT || 226 expr->type == EXPR_COMMA) { 227 match_condition(expr->left); 228 match_condition(expr->right); 229 return; 230 } 231 232 if (expr->type == EXPR_CALL) { 233 FOR_EACH_PTR(expr->args, arg) { 234 // if we find deref in conditional call, 235 // mark it as a read dependency 236 print_read_member_type(arg); 237 } END_FOR_EACH_PTR(arg); 238 return; 239 } 240 241 print_read_member_type(expr); 242 } 243 244 245 /* when we are parsing an inline function and can no longer nest, 246 * assume that all struct fields passed to nested inline functions 247 * are read dependencies 248 */ 249 static void match_call_info(struct expression *expr) 250 { 251 struct expression *arg; 252 int i; 253 254 if (!__inline_fn || !cur_syscall) 255 return; 256 257 // prefix(); printf("fn: %s\n", expr->fn->symbol->ident->name); 258 259 i = 0; 260 FOR_EACH_PTR(expr->args, arg) { 261 /* 262 if (arg->type == EXPR_DEREF) 263 printf("arg %d is deref\n", i); 264 */ 265 print_read_member_type(arg); 266 i++; 267 } END_FOR_EACH_PTR(arg); 268 } 269 270 static void match_assign_value(struct expression *expr) 271 { 272 if (!cur_syscall) 273 return; 274 print_write_member_type(expr->left); 275 } 276 277 static void unop_expr(struct expression *expr) 278 { 279 if (!cur_syscall) 280 return; 281 282 if (expr->op == SPECIAL_ADD_ASSIGN || expr->op == SPECIAL_INCREMENT || 283 expr->op == SPECIAL_SUB_ASSIGN || expr->op == SPECIAL_DECREMENT || 284 expr->op == SPECIAL_MUL_ASSIGN || expr->op == SPECIAL_DIV_ASSIGN || 285 expr->op == SPECIAL_MOD_ASSIGN || expr->op == SPECIAL_AND_ASSIGN || 286 expr->op == SPECIAL_OR_ASSIGN || expr->op == SPECIAL_XOR_ASSIGN || 287 expr->op == SPECIAL_SHL_ASSIGN || expr->op == SPECIAL_SHR_ASSIGN) 288 print_write_member_type(strip_expr(expr->unop)); 289 } 290 291 void check_implicit_dependencies(int id) 292 { 293 my_id = id; 294 ignore_structs = 0; 295 296 if (option_project != PROJ_KERNEL) 297 return; 298 if (!option_info) 299 return; 300 301 add_hook(&match_syscall_definition, AFTER_DEF_HOOK); 302 add_hook(&match_after_syscall, AFTER_FUNC_HOOK); 303 add_hook(&match_condition, CONDITION_HOOK); 304 add_hook(&match_call_info, FUNCTION_CALL_HOOK); 305 306 /* hooks to track written fields */ 307 add_hook(&match_assign_value, ASSIGNMENT_HOOK_AFTER); 308 add_hook(&unop_expr, OP_HOOK); 309 }