2 * Copyright (C) 2010 Dan Carpenter.
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.
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.
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
19 * This tries to find places which should probably return -EFAULT
20 * but return the number of bytes to copy instead.
25 #include "smatch_slist.h"
26 #include "smatch_extra.h"
33 static void ok_to_use(struct sm_state
*sm
, struct expression
*mod_expr
)
36 set_state(my_id
, sm
->name
, sm
->sym
, &ok
);
39 static void match_copy(const char *fn
, struct expression
*expr
, void *unused
)
41 if (expr
->op
== SPECIAL_SUB_ASSIGN
)
43 set_state_expr(my_id
, expr
->left
, &remaining
);
46 static void match_condition(struct expression
*expr
)
48 if (!get_state_expr(my_id
, expr
))
50 /* If the variable is zero that's ok */
51 set_true_false_states_expr(my_id
, expr
, NULL
, &ok
);
55 * This function is biased in favour of print out errors.
56 * The heuristic to print is:
57 * If we have a potentially positive return from copy_to_user
58 * and there is a possibility that we return negative as well
61 static void match_return_var(struct expression
*ret_value
)
63 struct smatch_state
*state
;
67 sm
= get_sm_state_expr(my_id
, ret_value
);
70 if (!slist_has_state(sm
->possible
, &remaining
))
72 state
= get_state_expr(SMATCH_EXTRA
, ret_value
);
75 if (!get_absolute_min(ret_value
, &min
))
79 sm_msg("warn: maybe return -EFAULT instead of the bytes remaining?");
82 static void match_return_call(struct expression
*ret_value
)
84 struct expression
*fn
;
85 struct range_list
*rl
;
89 if (!ret_value
|| ret_value
->type
!= EXPR_CALL
)
91 cur_func
= get_function();
94 if (strstr(cur_func
, "_to_user") ||
95 strstr(cur_func
, "_from_user"))
98 fn
= strip_expr(ret_value
->fn
);
99 if (fn
->type
!= EXPR_SYMBOL
)
101 if (!fn
->symbol_name
->name
)
103 fn_name
= fn
->symbol_name
->name
;
104 if (strcmp(fn_name
, "copy_to_user") != 0 &&
105 strcmp(fn_name
, "__copy_to_user") != 0 &&
106 strcmp(fn_name
, "copy_from_user") != 0 &&
107 strcmp(fn_name
, "__copy_from_user"))
110 rl
= db_return_vals_from_str(get_function());
114 if (!sval_is_negative(rl_min(rl
)))
116 sm_msg("warn: maybe return -EFAULT instead of the bytes remaining?");
119 void check_return_efault(int id
)
121 if (option_project
!= PROJ_KERNEL
)
125 add_function_assign_hook("copy_to_user", &match_copy
, NULL
);
126 add_function_assign_hook("__copy_to_user", &match_copy
, NULL
);
127 add_function_assign_hook("copy_from_user", &match_copy
, NULL
);
128 add_function_assign_hook("__copy_from_user", &match_copy
, NULL
);
129 add_function_assign_hook("clear_user", &match_copy
, NULL
);
130 add_hook(&match_condition
, CONDITION_HOOK
);
131 add_hook(&match_return_var
, RETURN_HOOK
);
132 add_hook(&match_return_call
, RETURN_HOOK
);
133 add_modification_hook(my_id
, &ok_to_use
);