1 /*
2  * Copyright (C) 2017 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 is to help create Trinity fuzzer templates.
20  *
21  */
22 
23 #include "smatch.h"
24 #include "smatch_slist.h"
25 
26 static int my_id;
27 
28 STATE(ARG_FD);
29 #if 0
30 STATE(arg_range);
31 STATE(arg_op);
32 STATE(arg_list);
33 STATE(arg_cpu);
34 STATE(arg_pathname);
35 #endif
36 // nr_segs * sizeof(struct iovec)
37 // if (nr_segs > UIO_MAXIOV)
38 #if 0
39 STATE(arg_ioveclen);
40 STATE(arg_sockaddrlen);
41 STATE(arg_socketinfo);
42 #endif
43 
merge_states(struct smatch_state * s1,struct smatch_state * s2)44 struct smatch_state *merge_states(struct smatch_state *s1, struct smatch_state *s2)
45 {
46 	if (s1 == &undefined)
47 		return s2;
48 	return s1;
49 }
50 
51 struct typedef_lookup {
52 	const char *name;
53 	struct symbol *sym;
54 	int failed;
55 };
56 
_typedef_lookup(const char * name)57 static struct symbol *_typedef_lookup(const char *name)
58 {
59 	struct ident *id;
60 	struct symbol *node;
61 
62 	id = built_in_ident(name);
63 	if (!id)
64 		return NULL;
65 	node = lookup_symbol(id, NS_TYPEDEF);
66 	if (!node || node->type != SYM_NODE)
67 		return NULL;
68 	return get_real_base_type(node);
69 }
70 
typedef_lookup(struct typedef_lookup * tl)71 static void typedef_lookup(struct typedef_lookup *tl)
72 {
73 	if (tl->sym || tl->failed)
74 		return;
75 	tl->sym = _typedef_lookup(tl->name);
76 	if (!tl->sym)
77 		tl->failed = 1;
78 }
79 
is_mode_t(struct symbol * sym)80 static int is_mode_t(struct symbol *sym)
81 {
82 	static struct typedef_lookup umode_t = { .name = "umode_t" };
83 	struct symbol *type;
84 
85 	typedef_lookup(&umode_t);
86 	if (!umode_t.sym)
87 		return 0;
88 	type = get_base_type(sym);
89 	if (type == umode_t.sym)
90 		return 1;
91 	return 0;
92 }
93 
is_pid_t(struct symbol * sym)94 static int is_pid_t(struct symbol *sym)
95 {
96 	static struct typedef_lookup pid_t = { .name = "pid_t" };
97 	struct symbol *type;
98 
99 	typedef_lookup(&pid_t);
100 	if (!pid_t.sym)
101 		return 0;
102 	type = get_base_type(sym);
103 	if (type == pid_t.sym)
104 		return 1;
105 	return 0;
106 }
107 
get_arg_type_from_type(struct symbol * sym)108 static const char *get_arg_type_from_type(struct symbol *sym)
109 {
110 	struct symbol *type;
111 
112 	if (is_mode_t(sym))
113 		return "ARG_MODE_T";
114 	if (is_pid_t(sym))
115 		return "ARG_PID";
116 
117 	type = get_real_base_type(sym);
118 	if (!type || type->type != SYM_PTR)
119 		return NULL;
120 	type = get_real_base_type(type);
121 	if (!type)
122 		return NULL;
123 	if (type == &char_ctype)
124 		return "ARG_MMAP";
125 	if (!type->ident)
126 		return NULL;
127 	if (strcmp(type->ident->name, "iovec") == 0)
128 		return "ARG_IOVEC";
129 	if (strcmp(type->ident->name, "sockaddr") == 0)
130 		return "ARG_SOCKADDR";
131 	return "ARG_ADDRESS";
132 }
133 
match_fdget(const char * fn,struct expression * expr,void * unused)134 static void match_fdget(const char *fn, struct expression *expr, void *unused)
135 {
136 	struct expression *arg;
137 
138 	arg = get_argument_from_call_expr(expr->args, 0);
139 	set_state_expr(my_id, arg, &ARG_FD);
140 }
141 
get_syscall_arg_type(struct symbol * sym)142 const char *get_syscall_arg_type(struct symbol *sym)
143 {
144 	struct smatch_state *state;
145 	const char *type;
146 
147 	if (!sym || !sym->ident)
148 		return "ARG_UNDEFINED";
149 	type = get_arg_type_from_type(sym);
150 	if (type)
151 		return type;
152 	state = get_state(my_id, sym->ident->name, sym);
153 	if (!state)
154 		return "ARG_UNDEFINED";
155 	return state->name;
156 }
157 
check_syscall_arg_type(int id)158 void check_syscall_arg_type(int id)
159 {
160 	my_id = id;
161 	if (option_project != PROJ_KERNEL)
162 		return;
163 
164 	set_dynamic_states(my_id);
165 	add_merge_hook(my_id, &merge_states);
166 	add_function_hook("fdget", &match_fdget, NULL);
167 }
168 
169 
170