-
Notifications
You must be signed in to change notification settings - Fork 14
/
check_implicit_dependencies.c
307 lines (249 loc) · 7.47 KB
/
check_implicit_dependencies.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
#include "smatch.h"
#include "smatch_slist.h"
static int my_id;
/* If set, we ignore struct type symbols as implicit dependencies */
static int ignore_structs;
static struct symbol *cur_syscall;
/* note: cannot track return type and remove from implicit dependencies,
* because every syscall returns a long, and we don't have a good way to know
* whether or not this is a resource. The only example I can think of is open
* returning a filedescriptor, so in the implicit dep parsing, we will just
* blacklist struct fd --> file
*/
static struct symbol *cur_return_type;
static char *syscall_name;
static struct tracker_list *read_list; // what fields does syscall branch on?
static struct tracker_list *write_list; // what fields does syscall modify?
static struct tracker_list *arg_list; // what struct arguments does the syscall take?
static struct tracker_list *parsed_syscalls; // syscalls we have already checked
static inline void prefix(void)
{
printf("%s:%d %s() ", get_filename(), get_lineno(), get_function());
}
static void match_syscall_definition(struct symbol *sym)
{
struct symbol *arg;
struct tracker *tracker;
char *macro;
char *name;
int is_syscall = 0;
macro = get_macro_name(sym->pos);
if (macro &&
(strncmp("SYSCALL_DEFINE", macro, strlen("SYSCALL_DEFINE")) == 0 ||
strncmp("COMPAT_SYSCALL_DEFINE", macro, strlen("COMPAT_SYSCALL_DEFINE")) == 0))
is_syscall = 1;
name = get_function();
if (name && strncmp(name, "sys_", 4) == 0)
is_syscall = 1;
if (name && strncmp(name, "compat_sys_", 11) == 0)
is_syscall = 1;
if (!is_syscall)
return;
FOR_EACH_PTR(parsed_syscalls, tracker) {
if (tracker->sym == sym) // don't re-parse
return;
} END_FOR_EACH_PTR(tracker);
syscall_name = name;
cur_syscall = sym;
cur_return_type = cur_func_return_type();
if (cur_return_type && cur_return_type->ident)
sm_msg("return type: %s\n", cur_return_type->ident->name);
FOR_EACH_PTR(sym->ctype.base_type->arguments, arg) {
// set_state(my_id, arg->ident->name, arg, &user_data_set);
sm_msg("=======check_impl: arguments for call %s=========\n", syscall_name);
if (arg->type == SYM_STRUCT)
arg = get_real_base_type(arg);
if (cur_return_type && cur_return_type->ident)
sm_msg("arg type: %s\n", cur_return_type->ident->name);
// add_tracker(&arg_list, my_id, member, arg);
sm_msg("=================================\n");
} END_FOR_EACH_PTR(arg);
}
static void print_read_list(void)
{
struct tracker *tracker;
int i = 0;
FOR_EACH_PTR(read_list, tracker) {
if (i == 0)
sm_printf("%s read_list: [", syscall_name);
sm_printf("%s, ", tracker->name);
i++;
} END_FOR_EACH_PTR(tracker);
if (i > 0)
sm_printf("]\n");
}
static void print_write_list(void)
{
struct tracker *tracker;
int i = 0;
FOR_EACH_PTR(write_list, tracker) {
if (i == 0)
sm_printf("%s write_list: [", syscall_name);
sm_printf("%s, ", tracker->name);
i++;
} END_FOR_EACH_PTR(tracker);
if (i > 0)
sm_printf("]\n");
}
static void print_arg_list(void)
{
struct tracker *tracker;
int i = 0;
FOR_EACH_PTR(write_list, tracker) {
if (i == 0)
sm_printf("%s arg_list: [", syscall_name);
sm_printf("%s, ", tracker->name);
i++;
} END_FOR_EACH_PTR(tracker);
if (i > 0)
sm_printf("]\n");
}
static void match_after_syscall(struct symbol *sym)
{
if (!cur_syscall || sym != cur_syscall)
return;
// printf("\n"); prefix();
// printf("exiting scope of syscall %s\n", get_function());
// printf("-------------------------\n");
print_read_list();
print_write_list();
print_arg_list();
free_trackers_and_list(&read_list);
free_trackers_and_list(&write_list);
free_trackers_and_list(&arg_list);
add_tracker(&parsed_syscalls, my_id, syscall_name, sym);
cur_syscall = NULL;
cur_return_type = NULL;
syscall_name = NULL;
}
static void print_read_member_type(struct expression *expr)
{
char *member;
struct symbol *sym;
struct symbol *member_sym;
member = get_member_name(expr);
if (!member)
return;
sym = get_type(expr->deref);
member_sym = get_type(expr);
if (member_sym->type == SYM_PTR)
member_sym = get_real_base_type(member_sym);
/*
if (member_sym->type == SYM_STRUCT)
printf("found struct type %s\n", member);
else
printf("found non-struct type %s with enum value%d\n", member, member_sym->type);
*/
if (ignore_structs && member_sym->type == SYM_STRUCT) {
// printf("ignoring %s\n", member);
return;
}
add_tracker(&read_list, my_id, member, sym);
// sm_msg("info: uses %s", member);
// prefix();
// printf("info: uses %s\n", member);
}
static void print_write_member_type(struct expression *expr)
{
char *member;
struct symbol *sym;
struct symbol *member_sym;
member = get_member_name(expr);
if (!member)
return;
sym = get_type(expr->deref);
member_sym = get_type(expr);
if (member_sym->type == SYM_PTR)
member_sym = get_real_base_type(member_sym);
/*
if (member_sym->type == SYM_STRUCT)
printf("found struct type %s\n", member);
else
printf("found non-struct type %s with enum value%d\n", member, member_sym->type);
*/
if (ignore_structs && member_sym->type == SYM_STRUCT) {
// printf("ignoring %s\n", member);
return;
}
add_tracker(&write_list, my_id, member, sym);
}
static void match_condition(struct expression *expr)
{
struct expression *arg;
if (!cur_syscall)
return;
// prefix(); printf("-- condition found\n");
if (expr->type == EXPR_COMPARE ||
expr->type == EXPR_BINOP ||
expr->type == EXPR_LOGICAL ||
expr->type == EXPR_ASSIGNMENT ||
expr->type == EXPR_COMMA) {
match_condition(expr->left);
match_condition(expr->right);
return;
}
if (expr->type == EXPR_CALL) {
FOR_EACH_PTR(expr->args, arg) {
// if we find deref in conditional call,
// mark it as a read dependency
print_read_member_type(arg);
} END_FOR_EACH_PTR(arg);
return;
}
print_read_member_type(expr);
}
/* when we are parsing an inline function and can no longer nest,
* assume that all struct fields passed to nested inline functions
* are read dependencies
*/
static void match_call_info(struct expression *expr)
{
struct expression *arg;
int i;
if (!__inline_fn || !cur_syscall)
return;
// prefix(); printf("fn: %s\n", expr->fn->symbol->ident->name);
i = 0;
FOR_EACH_PTR(expr->args, arg) {
/*
if (arg->type == EXPR_DEREF)
printf("arg %d is deref\n", i);
*/
print_read_member_type(arg);
i++;
} END_FOR_EACH_PTR(arg);
}
static void match_assign_value(struct expression *expr)
{
if (!cur_syscall)
return;
print_write_member_type(expr->left);
}
static void unop_expr(struct expression *expr)
{
if (!cur_syscall)
return;
if (expr->op == SPECIAL_ADD_ASSIGN || expr->op == SPECIAL_INCREMENT ||
expr->op == SPECIAL_SUB_ASSIGN || expr->op == SPECIAL_DECREMENT ||
expr->op == SPECIAL_MUL_ASSIGN || expr->op == SPECIAL_DIV_ASSIGN ||
expr->op == SPECIAL_MOD_ASSIGN || expr->op == SPECIAL_AND_ASSIGN ||
expr->op == SPECIAL_OR_ASSIGN || expr->op == SPECIAL_XOR_ASSIGN ||
expr->op == SPECIAL_SHL_ASSIGN || expr->op == SPECIAL_SHR_ASSIGN)
print_write_member_type(strip_expr(expr->unop));
}
void check_implicit_dependencies(int id)
{
my_id = id;
ignore_structs = 0;
if (option_project != PROJ_KERNEL)
return;
if (!option_info)
return;
add_hook(&match_syscall_definition, AFTER_DEF_HOOK);
add_hook(&match_after_syscall, AFTER_FUNC_HOOK);
add_hook(&match_condition, CONDITION_HOOK);
add_hook(&match_call_info, FUNCTION_CALL_HOOK);
/* hooks to track written fields */
add_hook(&match_assign_value, ASSIGNMENT_HOOK_AFTER);
add_hook(&unop_expr, OP_HOOK);
}