1 /*
2  * Copyright (C) 2012 Oracle.
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  * This works together with smatch_clear_buffer.c.  This one is only for
20  * tracking the information and smatch_clear_buffer.c changes SMATCH_EXTRA.
21  *
22  * This tracks functions like memset() which clear out a chunk of memory.
23  * It fills in a gap that smatch_param_set.c can't handle.  It only handles
24  * void pointers because smatch_param_set.c should handle the rest.  Oh.  And
25  * also it handles arrays because Smatch sucks at handling arrays.
26  */
27 
28 #include "scope.h"
29 #include "smatch.h"
30 #include "smatch_slist.h"
31 #include "smatch_extra.h"
32 
33 static int my_id;
34 
35 STATE(cleared);
36 STATE(zeroed);
37 
db_param_cleared(struct expression * expr,int param,char * key,char * value)38 static void db_param_cleared(struct expression *expr, int param, char *key, char *value)
39 {
40 	struct expression *arg;
41 	char *name;
42 	struct symbol *sym;
43 
44 	while (expr->type == EXPR_ASSIGNMENT)
45 		expr = strip_expr(expr->right);
46 	if (expr->type != EXPR_CALL)
47 		return;
48 
49 	arg = get_argument_from_call_expr(expr->args, param);
50 	arg = strip_expr(arg);
51 	name = get_variable_from_key(arg, key, &sym);
52 	if (!name || !sym)
53 		goto free;
54 
55 	if (strcmp(value, "0") == 0)
56 		set_state(my_id, name, sym, &zeroed);
57 	else
58 		set_state(my_id, name, sym, &cleared);
59 free:
60 	free_string(name);
61 }
62 
match_memset(const char * fn,struct expression * expr,void * arg)63 static void match_memset(const char *fn, struct expression *expr, void *arg)
64 {
65 	db_param_cleared(expr, PTR_INT(arg), (char *)"$", (char *)"0");
66 }
67 
match_memcpy(const char * fn,struct expression * expr,void * arg)68 static void match_memcpy(const char *fn, struct expression *expr, void *arg)
69 {
70 	db_param_cleared(expr, PTR_INT(arg), (char *)"$", (char *)"");
71 }
72 
print_return_value_param(int return_id,char * return_ranges,struct expression * expr)73 static void print_return_value_param(int return_id, char *return_ranges, struct expression *expr)
74 {
75 	struct stree *stree;
76 	struct sm_state *sm;
77 	int param;
78 	const char *param_name;
79 
80 	stree = __get_cur_stree();
81 
82 	FOR_EACH_MY_SM(my_id, stree, sm) {
83 		param = get_param_num_from_sym(sm->sym);
84 		if (param < 0)
85 			continue;
86 
87 		param_name = get_param_name(sm);
88 		if (!param_name)
89 			continue;
90 
91 		if (sm->state == &zeroed) {
92 			sql_insert_return_states(return_id, return_ranges,
93 						 PARAM_CLEARED, param, param_name, "0");
94 		}
95 
96 		if (sm->state == &cleared) {
97 			sql_insert_return_states(return_id, return_ranges,
98 						 PARAM_CLEARED, param, param_name, "");
99 		}
100 	} END_FOR_EACH_SM(sm);
101 }
102 
register_clears_param(void)103 static void register_clears_param(void)
104 {
105 	struct token *token;
106 	char name[256];
107 	const char *function;
108 	int param;
109 
110 	if (option_project == PROJ_NONE)
111 		return;
112 
113 	snprintf(name, 256, "%s.clears_argument", option_project_str);
114 
115 	token = get_tokens_file(name);
116 	if (!token)
117 		return;
118 	if (token_type(token) != TOKEN_STREAMBEGIN)
119 		return;
120 	token = token->next;
121 	while (token_type(token) != TOKEN_STREAMEND) {
122 		if (token_type(token) != TOKEN_IDENT)
123 			return;
124 		function = show_ident(token->ident);
125 		token = token->next;
126 		if (token_type(token) != TOKEN_NUMBER)
127 			return;
128 		param = atoi(token->number);
129 		add_function_hook(function, &match_memcpy, INT_PTR(param));
130 		token = token->next;
131 	}
132 	clear_token_alloc();
133 }
134 
135 #define USB_DIR_IN 0x80
match_usb_control_msg(const char * fn,struct expression * expr,void * _size_arg)136 static void match_usb_control_msg(const char *fn, struct expression *expr, void *_size_arg)
137 {
138 	struct expression *inout;
139 	sval_t sval;
140 
141 	inout = get_argument_from_call_expr(expr->args, 3);
142 
143 	if (get_value(inout, &sval) && !(sval.uvalue & USB_DIR_IN))
144 		return;
145 
146 	db_param_cleared(expr, 6, (char *)"$", (char *)"");
147 }
148 
match_assign(struct expression * expr)149 static void match_assign(struct expression *expr)
150 {
151 	struct symbol *type;
152 
153 	/*
154 	 * If we have struct foo x, y; and we say that x = y; then it
155 	 * initializes the struct holes.  So we record that here.
156 	 */
157 	type = get_type(expr->left);
158 	if (!type || type->type != SYM_STRUCT)
159 		return;
160 	set_state_expr(my_id, expr->left, &cleared);
161 }
162 
match_array_assign(struct expression * expr)163 static void match_array_assign(struct expression *expr)
164 {
165 	struct expression *array_expr;
166 
167 	if (!is_array(expr->left))
168 		return;
169 
170 	array_expr = get_array_base(expr->left);
171 	set_state_expr(my_id, array_expr, &cleared);
172 }
173 
register_param_cleared(int id)174 void register_param_cleared(int id)
175 {
176 	my_id = id;
177 
178 	add_function_hook("memset", &match_memset, INT_PTR(0));
179 	add_function_hook("memzero", &match_memset, INT_PTR(0));
180 	add_function_hook("__memset", &match_memset, INT_PTR(0));
181 	add_function_hook("__memzero", &match_memset, INT_PTR(0));
182 
183 	add_function_hook("memcpy", &match_memcpy, INT_PTR(0));
184 	add_function_hook("memmove", &match_memcpy, INT_PTR(0));
185 	add_function_hook("__memcpy", &match_memcpy, INT_PTR(0));
186 	add_function_hook("__memmove", &match_memcpy, INT_PTR(0));
187 	add_function_hook("strcpy", &match_memcpy, INT_PTR(0));
188 	add_function_hook("strncpy", &match_memcpy, INT_PTR(0));
189 	add_function_hook("sprintf", &match_memcpy, INT_PTR(0));
190 	add_function_hook("snprintf", &match_memcpy, INT_PTR(0));
191 
192 	add_hook(&match_assign, ASSIGNMENT_HOOK);
193 	add_hook(&match_array_assign, ASSIGNMENT_HOOK);
194 
195 	register_clears_param();
196 
197 	select_return_states_hook(PARAM_CLEARED, &db_param_cleared);
198 	add_split_return_callback(&print_return_value_param);
199 
200 	if (option_project == PROJ_KERNEL) {
201 		add_function_hook("usb_control_msg", &match_usb_control_msg, NULL);
202 	}
203 
204 }
205 
206