From f0adcfda7ea87fe821b894c01ce00b3ea9f8f169 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 17 Jun 2013 17:03:02 +0300 Subject: [PATCH] user_data, db: improve how returned user data is handled If we returned a pointer which held user data, that wasn't being tracked correctly. It didn't store the information properly and it didn't read the stored information properly. Now the we have the return_state_to_var_sym() function then reading the information from the database is easier. Signed-off-by: Dan Carpenter --- check_user_data.c | 30 +++++++++++------------------- validation/sm_user_data2.c | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 19 deletions(-) create mode 100644 validation/sm_user_data2.c diff --git a/check_user_data.c b/check_user_data.c index 844fd310..0642c58b 100644 --- a/check_user_data.c +++ b/check_user_data.c @@ -429,6 +429,13 @@ static void struct_member_callback(struct expression *call, int param, char *pri sql_insert_caller_info(call, USER_DATA, param, printed_name, ""); } +static void returned_member_callback(int return_id, char *return_ranges, char *printed_name, struct smatch_state *state) +{ + if (state == &capped) + return; + sql_insert_return_states(return_id, return_ranges, USER_DATA, -1, printed_name, ""); +} + int was_passed_in_user_data(struct expression *expr) { int ret; @@ -477,27 +484,12 @@ static void print_returned_user_data(int return_id, char *return_ranges, struct free_slist(&my_slist); } -static void db_param_is_now_userdata(struct expression *expr, int param, char *key, char *value) +static void db_return_states_userdata(struct expression *expr, int param, char *key, char *value) { - struct expression *arg; char *name; struct symbol *sym; - while (expr->type == EXPR_ASSIGNMENT) - expr = strip_expr(expr->right); - if (expr->type != EXPR_CALL) - return; - - arg = get_argument_from_call_expr(expr->args, param); - if (!arg) - return; - - if (strcmp(key, "$$") == 0 && arg->type == EXPR_PREOP && arg->op == '&') { - arg = strip_expr(arg->unop); - name = expr_to_var_sym(arg, &sym); - } else { - name = get_variable_from_key(arg, key, &sym); - } + name = return_state_to_var_sym(expr, param, key, &sym); if (!name || !sym) goto free; @@ -523,7 +515,7 @@ void check_user_data(int id) add_hook(&match_caller_info, FUNCTION_CALL_HOOK); add_member_info_callback(my_id, struct_member_callback); + add_returned_member_callback(my_id, returned_member_callback); add_returned_state_callback(print_returned_user_data); - add_db_return_states_callback(USER_DATA, &db_param_is_now_userdata); - + add_db_return_states_callback(USER_DATA, &db_return_states_userdata); } diff --git a/validation/sm_user_data2.c b/validation/sm_user_data2.c new file mode 100644 index 00000000..12cb4e69 --- /dev/null +++ b/validation/sm_user_data2.c @@ -0,0 +1,32 @@ +#include "check_debug.h" + +int copy_from_user(void *dest, void *src, int size){} + +struct my_struct { + int x, y; +}; + +void *pointer; +struct my_struct *dest; + +struct my_struct *returns_copy(void) +{ + copy_from_user(dest, pointer, sizeof(*dest)); + return dest; +} + +struct my_struct *a; +void test(void) +{ + a = returns_copy(); + __smatch_state("check_user_data", "a->x"); +} + +/* + * check-name: smatch user data #2 + * check-command: smatch -p=kernel -I.. sm_user_data2.c + * + * check-output-start +sm_user_data2.c:22 test() 'a->x' = 'user_data' + * check-output-end + */ -- 2.11.4.GIT