1 /* 2 * Copyright (C) 2010 Dan Carpenter. 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 * According to an email on lkml you are not allowed to reuse the skb 20 * passed to dev_queue_xmit() 21 * 22 */ 23 24 #include "smatch.h" 25 #include "smatch_slist.h" 26 27 static int my_id; 28 29 STATE(do_not_use); 30 31 static void ok_to_use(struct sm_state *sm, struct expression *mod_expr) 32 { 33 set_state(my_id, sm->name, sm->sym, &undefined); 34 } 35 36 static int valid_use(void) 37 { 38 struct expression *tmp; 39 int i = 0; 40 int dot_ops = 0; 41 42 FOR_EACH_PTR_REVERSE(big_expression_stack, tmp) { 43 if (!i++) 44 continue; 45 if (tmp->type == EXPR_PREOP && tmp->op == '(') 46 continue; 47 if (tmp->op == '.' && !dot_ops++) 48 continue; 49 // if (tmp->type == EXPR_POSTOP) 50 // return 1; 51 if (tmp->type == EXPR_CALL && sym_name_is("kfree_skb", tmp->fn)) 52 return 1; 53 return 0; 54 } END_FOR_EACH_PTR_REVERSE(tmp); 55 return 0; 56 } 57 58 /* match symbol is expensive. only turn it on after we match the xmit function */ 59 static int match_symbol_active; 60 static void match_symbol(struct expression *expr) 61 { 62 struct sm_state *sm; 63 char *name; 64 65 sm = get_sm_state_expr(my_id, expr); 66 if (!sm || !slist_has_state(sm->possible, &do_not_use)) 67 return; 68 if (valid_use()) 69 return; 70 name = expr_to_var(expr); 71 sm_error("'%s' was already used up by dev_queue_xmit()", name); 72 free_string(name); 73 } 74 75 static void match_kfree_skb(const char *fn, struct expression *expr, void *param) 76 { 77 struct expression *arg; 78 79 arg = get_argument_from_call_expr(expr->args, 0); 80 if (!arg) 81 return; 82 set_state_expr(my_id, arg, &undefined); 83 } 84 85 static void match_xmit(const char *fn, struct expression *expr, void *param) 86 { 87 struct expression *arg; 88 89 arg = get_argument_from_call_expr(expr->args, PTR_INT(param)); 90 if (!arg) 91 return; 92 set_state_expr(my_id, arg, &do_not_use); 93 if (!match_symbol_active++) { 94 add_hook(&match_symbol, SYM_HOOK); 95 add_function_hook("kfree_skb", &match_kfree_skb, NULL); 96 } 97 } 98 99 static void register_funcs_from_file(void) 100 { 101 struct token *token; 102 const char *func; 103 int arg; 104 105 token = get_tokens_file("kernel.dev_queue_xmit"); 106 if (!token) 107 return; 108 if (token_type(token) != TOKEN_STREAMBEGIN) 109 return; 110 token = token->next; 111 while (token_type(token) != TOKEN_STREAMEND) { 112 if (token_type(token) != TOKEN_IDENT) 113 return; 114 func = show_ident(token->ident); 115 token = token->next; 116 if (token_type(token) != TOKEN_NUMBER) 117 return; 118 arg = atoi(token->number); 119 add_function_hook(func, &match_xmit, INT_PTR(arg)); 120 token = token->next; 121 } 122 clear_token_alloc(); 123 } 124 125 void check_dev_queue_xmit(int id) 126 { 127 if (option_project != PROJ_KERNEL) 128 return; 129 my_id = id; 130 add_modification_hook(my_id, ok_to_use); 131 register_funcs_from_file(); 132 } 133