From 34b54b7c67317dfb930aba35fe1f0234b7b0bb85 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 20 Sep 2012 11:18:25 +0300 Subject: [PATCH] function_hooks: introduce get_implied_return() In the old code there was a special hook called add_function_assign_hook_extra() which was similar to add_function_assign_hook() except that setting the values in SMATCH_EXTRA needed to be handled differently. This patch removes that an instead introduces a call back called add_implied_return_hook() which takes a function call and gives the implied range list which is returned. This is a better more flexible way of handling things. This patch doesn't make a lot of difference on it's own, but later I will add support so that: return ERR_PTR(-ENOMEM); is handled. In the old code, that wasn't handled because it wasn't an assignment. Signed-off-by: Dan Carpenter --- check_kernel.c | 37 +++++++++++++++++--------- check_return_efault.c | 22 ++++------------ smatch.h | 11 ++++++-- smatch_function_hooks.c | 69 +++++++++++++++++++++++++++++++++++++++---------- 4 files changed, 95 insertions(+), 44 deletions(-) diff --git a/check_kernel.c b/check_kernel.c index 8439e911..be518e63 100644 --- a/check_kernel.c +++ b/check_kernel.c @@ -14,19 +14,26 @@ #include "smatch.h" #include "smatch_extra.h" -static void match_err_cast(const char *fn, struct expression *expr, void *unused) +static int implied_err_cast_return(struct expression *call, void *unused, struct range_list **rl) { struct expression *arg; - struct expression *right; - struct range_list *rl; - right = strip_expr(expr->right); - arg = get_argument_from_call_expr(right->args, 0); + arg = get_argument_from_call_expr(call->args, 0); + if (!get_implied_range_list(arg, rl)) + *rl = alloc_range_list(-4095, -1); + return 1; +} - if (get_implied_range_list(arg, &rl)) - set_extra_expr_mod(expr->left, alloc_estate_range_list(rl)); - else - set_extra_expr_mod(expr->left, alloc_estate_range(-4095, -1)); +static int implied_copy_return(struct expression *call, void *unused, struct range_list **rl) +{ + struct expression *arg; + long long max; + + arg = get_argument_from_call_expr(call->args, 2); + if (!get_absolute_max(arg, &max)) + max = whole_range.max; + *rl = alloc_range_list(0, max); + return 1; } static void match_param_nonnull(const char *fn, struct expression *call_expr, @@ -80,12 +87,18 @@ void check_kernel(int id) if (option_project != PROJ_KERNEL) return; - add_function_assign_hook_extra("ERR_PTR", &match_err_cast, NULL); - add_function_assign_hook_extra("ERR_CAST", &match_err_cast, NULL); - add_function_assign_hook_extra("PTR_ERR", &match_err_cast, NULL); + add_implied_return_hook("ERR_PTR", &implied_err_cast_return, NULL); + add_implied_return_hook("ERR_CAST", &implied_err_cast_return, NULL); + add_implied_return_hook("PTR_ERR", &implied_err_cast_return, NULL); return_implies_state("IS_ERR_OR_NULL", 0, 0, &match_param_nonnull, (void *)0); return_implies_state("IS_ERR", 0, 0, &match_not_err, NULL); return_implies_state("IS_ERR", 1, 1, &match_err, NULL); return_implies_state("tomoyo_memory_ok", 1, 1, &match_param_nonnull, (void *)0); add_macro_assign_hook_extra("container_of", &match_container_of, NULL); + + add_implied_return_hook("copy_to_user", &implied_copy_return, NULL); + add_implied_return_hook("__copy_to_user", &implied_copy_return, NULL); + add_implied_return_hook("copy_from_user", &implied_copy_return, NULL); + add_implied_return_hook("__copy_fom_user", &implied_copy_return, NULL); + add_implied_return_hook("clear_user", &implied_copy_return, NULL); } diff --git a/check_return_efault.c b/check_return_efault.c index ea257e84..b4b7eec2 100644 --- a/check_return_efault.c +++ b/check_return_efault.c @@ -29,21 +29,9 @@ static void ok_to_use(struct sm_state *sm) static void match_copy(const char *fn, struct expression *expr, void *unused) { - struct expression *call; - struct expression *arg; - long long max; - if (expr->op == SPECIAL_SUB_ASSIGN) return; set_state_expr(my_id, expr->left, &remaining); - - call = strip_expr(expr->right); - if (call->type != EXPR_CALL) - return; - arg = get_argument_from_call_expr(call->args, 2); - if (!get_absolute_max(arg, &max)) - max = whole_range.max; - set_extra_expr_mod(expr->left, alloc_estate_range(0, max)); } static void match_condition(struct expression *expr) @@ -88,11 +76,11 @@ void check_return_efault(int id) return; my_id = id; - add_function_assign_hook_extra("copy_to_user", &match_copy, NULL); - add_function_assign_hook_extra("__copy_to_user", &match_copy, NULL); - add_function_assign_hook_extra("copy_from_user", &match_copy, NULL); - add_function_assign_hook_extra("__copy_from_user", &match_copy, NULL); - add_function_assign_hook_extra("clear_user", &match_copy, NULL); + add_function_assign_hook("copy_to_user", &match_copy, NULL); + add_function_assign_hook("__copy_to_user", &match_copy, NULL); + add_function_assign_hook("copy_from_user", &match_copy, NULL); + add_function_assign_hook("__copy_from_user", &match_copy, NULL); + add_function_assign_hook("clear_user", &match_copy, NULL); add_hook(&match_condition, CONDITION_HOOK); add_hook(&match_return, RETURN_HOOK); add_modification_hook(my_id, &ok_to_use); diff --git a/smatch.h b/smatch.h index ed7e2a41..502def57 100644 --- a/smatch.h +++ b/smatch.h @@ -94,6 +94,8 @@ enum hook_type { #define TRUE 1 #define FALSE 0 +struct range_list; + void add_hook(void *func, enum hook_type type); typedef struct smatch_state *(merge_func_t)(struct smatch_state *s1, struct smatch_state *s2); typedef struct smatch_state *(unmatched_func_t)(struct sm_state *state); @@ -106,12 +108,14 @@ typedef void (implication_hook)(const char *fn, struct expression *call_expr, struct expression *assign_expr, void *data); typedef void (return_implies_hook)(struct expression *call_expr, int param, char *key, char *value); +typedef int (implied_return_hook)(struct expression *call_expr, void *info, struct range_list **rl); void add_function_hook(const char *look_for, func_hook *call_back, void *data); void add_function_assign_hook(const char *look_for, func_hook *call_back, void *info); -void add_function_assign_hook_extra(const char *look_for, func_hook *call_back, - void *info); +void add_implied_return_hook(const char *look_for, + implied_return_hook *call_back, + void *info); void add_macro_assign_hook(const char *look_for, func_hook *call_back, void *info); void add_macro_assign_hook_extra(const char *look_for, func_hook *call_back, @@ -119,6 +123,8 @@ void add_macro_assign_hook_extra(const char *look_for, func_hook *call_back, void return_implies_state(const char *look_for, long long start, long long end, implication_hook *call_back, void *info); void add_db_return_implies_callback(int type, return_implies_hook *callback); +int get_implied_return(struct expression *expr, struct range_list **rl); + typedef void (modification_hook)(struct sm_state *sm); void add_modification_hook(int owner, modification_hook *call_back); void add_indirect_modification_hook(int owner, modification_hook *call_back); @@ -214,6 +220,7 @@ int get_fuzzy_min(struct expression *expr, long long *min); int get_fuzzy_max(struct expression *expr, long long *max); int get_absolute_min(struct expression *expr, long long *val); int get_absolute_max(struct expression *expr, long long *val); +int parse_call_math(struct expression *expr, char *math, long long *val); int is_zero(struct expression *expr); int known_condition_true(struct expression *expr); int known_condition_false(struct expression *expr); diff --git a/smatch_function_hooks.c b/smatch_function_hooks.c index 02d33caf..c75cdafe 100644 --- a/smatch_function_hooks.c +++ b/smatch_function_hooks.c @@ -8,9 +8,10 @@ */ /* - * There are three types of function hooks: + * There are several types of function hooks: * add_function_hook() - For any time a function is called. * add_function_assign_hook() - foo = the_function(). + * add_implied_return_hook() - Calculates the implied return value. * add_macro_assign_hook() - foo = the_macro(). * return_implies_state() - For when a return value of 1 implies locked * and 0 implies unlocked. etc. etc. @@ -27,7 +28,10 @@ struct fcall_back { int type; struct data_range *range; - func_hook *call_back; + union { + func_hook *call_back; + implied_return_hook *implied_return; + } u; void *info; }; @@ -40,7 +44,7 @@ static struct hashtable *func_hash; #define REGULAR_CALL 0 #define RANGED_CALL 1 #define ASSIGN_CALL 2 -#define ASSIGN_CALL_EXTRA 3 +#define IMPLIED_RETURN 3 #define MACRO_ASSIGN 4 #define MACRO_ASSIGN_EXTRA 5 @@ -52,14 +56,14 @@ ALLOCATOR(return_implies_callback, "return_implies callbacks"); DECLARE_PTR_LIST(db_implies_list, struct return_implies_callback); static struct db_implies_list *db_implies_list; -static struct fcall_back *alloc_fcall_back(int type, func_hook *call_back, +static struct fcall_back *alloc_fcall_back(int type, void *call_back, void *info) { struct fcall_back *cb; cb = __alloc_fcall_back(0); cb->type = type; - cb->call_back = call_back; + cb->u.call_back = call_back; cb->info = info; return cb; } @@ -81,12 +85,13 @@ void add_function_assign_hook(const char *look_for, func_hook *call_back, add_callback(func_hash, look_for, cb); } -void add_function_assign_hook_extra(const char *look_for, func_hook *call_back, - void *info) +void add_implied_return_hook(const char *look_for, + implied_return_hook *call_back, + void *info) { struct fcall_back *cb; - cb = alloc_fcall_back(ASSIGN_CALL_EXTRA, call_back, info); + cb = alloc_fcall_back(IMPLIED_RETURN, call_back, info); add_callback(func_hash, look_for, cb); } @@ -135,7 +140,7 @@ static int call_call_backs(struct call_back_list *list, int type, FOR_EACH_PTR(list, tmp) { if (tmp->type == type) { - (tmp->call_back)(fn, expr, tmp->info); + (tmp->u.call_back)(fn, expr, tmp->info); handled = 1; } } END_FOR_EACH_PTR(tmp); @@ -150,7 +155,7 @@ static void call_ranged_call_backs(struct call_back_list *list, struct fcall_back *tmp; FOR_EACH_PTR(list, tmp) { - ((implication_hook *)(tmp->call_back))(fn, call_expr, assign_expr, tmp->info); + ((implication_hook *)(tmp->u.call_back))(fn, call_expr, assign_expr, tmp->info); } END_FOR_EACH_PTR(tmp); } @@ -247,7 +252,7 @@ int call_implies_callbacks(int comparison, struct expression *expr, long long va continue; if (!true_comparison_range_lr(comparison, tmp->range, value_range, left)) continue; - ((implication_hook *)(tmp->call_back))(fn, expr, NULL, tmp->info); + ((implication_hook *)(tmp->u.call_back))(fn, expr, NULL, tmp->info); } END_FOR_EACH_PTR(tmp); tmp_slist = __pop_fake_cur_slist(); merge_slist(&true_states, tmp_slist); @@ -260,7 +265,7 @@ int call_implies_callbacks(int comparison, struct expression *expr, long long va continue; if (!false_comparison_range_lr(comparison, tmp->range, value_range, left)) continue; - ((implication_hook *)(tmp->call_back))(fn, expr, NULL, tmp->info); + ((implication_hook *)(tmp->u.call_back))(fn, expr, NULL, tmp->info); } END_FOR_EACH_PTR(tmp); tmp_slist = __pop_fake_cur_slist(); merge_slist(&false_states, tmp_slist); @@ -588,6 +593,16 @@ static int db_return_states_assign(struct expression *expr) return handled; } +static int handle_implied_return(struct expression *expr) +{ + struct range_list *rl; + + if (!get_implied_return(expr->right, &rl)) + return 0; + set_extra_expr_mod(expr->left, alloc_estate_range_list(rl)); + return 1; +} + static void match_assign_call(struct expression *expr) { struct call_back_list *call_backs; @@ -604,7 +619,7 @@ static void match_assign_call(struct expression *expr) call_backs = search_callback(func_hash, (char *)fn); call_call_backs(call_backs, ASSIGN_CALL, fn, expr); - handled |= call_call_backs(call_backs, ASSIGN_CALL_EXTRA, fn, expr); + handled |= handle_implied_return(expr); handled |= assign_ranged_funcs(fn, expr, call_backs); if (handled) return; @@ -734,6 +749,34 @@ static void match_macro_assign(struct expression *expr) call_call_backs(call_backs, MACRO_ASSIGN_EXTRA, macro, expr); } +int get_implied_return(struct expression *expr, struct range_list **rl) +{ + struct call_back_list *call_backs; + struct fcall_back *tmp; + int handled = 0; + char *fn; + + *rl = NULL; + + expr = strip_expr(expr); + fn = get_variable_from_expr(expr->fn, NULL); + if (!fn) + goto out; + + call_backs = search_callback(func_hash, fn); + + FOR_EACH_PTR(call_backs, tmp) { + if (tmp->type == IMPLIED_RETURN) { + (tmp->u.implied_return)(expr, tmp->info, rl); + handled = 1; + } + } END_FOR_EACH_PTR(tmp); + +out: + free_string(fn); + return handled; +} + void create_function_hook_hash(void) { func_hash = create_function_hashtable(5000); -- 2.11.4.GIT