1 /*
2  * Copyright (C) 2018 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 #include "smatch.h"
19 #include "smatch_extra.h"
20 
21 static int my_id;
22 extern int second_half_id;
23 extern void set_spectre_first_half(struct expression *expr);
24 
25 static int suppress_multiple = 1;
26 
is_write(struct expression * expr)27 static int is_write(struct expression *expr)
28 {
29 	return 0;
30 }
31 
is_read(struct expression * expr)32 static int is_read(struct expression *expr)
33 {
34 	struct expression *parent, *last_parent;
35 	struct statement *stmt;
36 
37 	if (is_write(expr))
38 		return 0;
39 
40 	last_parent = expr;
41 	while ((parent = expr_get_parent_expr(expr))){
42 
43 		last_parent = parent;
44 
45 		/* If we pass a value as a parameter that's a read, probably? */
46 //		if (parent->type == EXPR_CALL)
47 //			return 1;
48 
49 		if (parent->type == EXPR_ASSIGNMENT) {
50 			if (parent->right == expr)
51 				return 1;
52 			if (parent->left == expr)
53 				return 0;
54 		}
55 		expr = parent;
56 	}
57 
58 	stmt = expr_get_parent_stmt(last_parent);
59 	if (stmt && stmt->type == STMT_RETURN)
60 		return 1;
61 
62 	return 0;
63 }
64 
is_harmless(struct expression * expr)65 static int is_harmless(struct expression *expr)
66 {
67 	struct expression *tmp, *parent;
68 	struct statement *stmt;
69 	int count = 0;
70 
71 	parent = expr;
72 	while ((tmp = expr_get_parent_expr(parent))) {
73 		if (tmp->type == EXPR_ASSIGNMENT || tmp->type == EXPR_CALL)
74 			return 0;
75 		parent = tmp;
76 		if (count++ > 4)
77 			break;
78 	}
79 
80 	stmt = expr_get_parent_stmt(parent);
81 	if (!stmt)
82 		return 0;
83 	if (stmt->type == STMT_IF && stmt->if_conditional == parent)
84 		return 1;
85 	if (stmt->type == STMT_ITERATOR &&
86 	    (stmt->iterator_pre_condition == parent ||
87 	     stmt->iterator_post_condition == parent))
88 		return 1;
89 
90 	return 0;
91 }
92 
get_max_by_type(struct expression * expr)93 static unsigned long long get_max_by_type(struct expression *expr)
94 {
95 	struct symbol *type;
96 	int cnt = 0;
97 	sval_t max;
98 
99 	max.type = &ullong_ctype;
100 	max.uvalue = -1ULL;
101 
102 	while (true) {
103 		expr = strip_parens(expr);
104 		type = get_type(expr);
105 		if (type && sval_type_max(type).uvalue < max.uvalue)
106 			max = sval_type_max(type);
107 		if (expr->type == EXPR_PREOP) {
108 			expr = expr->unop;
109 		} else if (expr->type == EXPR_BINOP) {
110 			if (expr->op == '%' || expr->op == '&')
111 				expr = expr->right;
112 			else
113 				return max.uvalue;
114 		} else {
115 			expr = get_assigned_expr(expr);
116 			if (!expr)
117 				return max.uvalue;
118 		}
119 		if (cnt++ > 5)
120 			return max.uvalue;
121 	}
122 
123 	return max.uvalue;
124 }
125 
get_mask(struct expression * expr)126 static unsigned long long get_mask(struct expression *expr)
127 {
128 	struct expression *tmp;
129 	sval_t mask;
130 	int cnt = 0;
131 
132 	expr = strip_expr(expr);
133 
134 	tmp = get_assigned_expr(expr);
135 	while (tmp) {
136 		expr = tmp;
137 		if (++cnt > 3)
138 			break;
139 		tmp = get_assigned_expr(expr);
140 	}
141 
142 	if (expr->type == EXPR_BINOP && expr->op == '&') {
143 		if (get_value(expr->right, &mask))  /* right is the common case */
144 			return mask.uvalue;
145 		if (get_value(expr->left, &mask))
146 			return mask.uvalue;
147 	}
148 
149 	return ULLONG_MAX;
150 }
151 
array_check(struct expression * expr)152 static void array_check(struct expression *expr)
153 {
154 	struct expression_list *conditions;
155 	struct expression *array_expr, *offset;
156 	unsigned long long mask;
157 	int array_size;
158 	char *name;
159 
160 	expr = strip_expr(expr);
161 	if (!is_array(expr))
162 		return;
163 
164 	if (is_impossible_path())
165 		return;
166 	if (is_harmless(expr))
167 		return;
168 
169 	array_expr = get_array_base(expr);
170 	if (suppress_multiple && is_ignored_expr(my_id, array_expr)) {
171 		set_spectre_first_half(expr);
172 		return;
173 	}
174 
175 	offset = get_array_offset(expr);
176 	if (!is_user_rl(offset))
177 		return;
178 	if (is_nospec(offset))
179 		return;
180 
181 	array_size = get_array_size(array_expr);
182 	if (array_size > 0 && get_max_by_type(offset) < array_size)
183 		return;
184 //	binfo = get_bit_info(offset);
185 //	if (array_size > 0 && binfo && binfo->possible < array_size)
186 //		return;
187 
188 	mask = get_mask(offset);
189 	if (mask <= array_size)
190 		return;
191 
192 	conditions = get_conditions(offset);
193 
194 	name = expr_to_str(array_expr);
195 	sm_warning("potential spectre issue '%s' [%s]%s",
196 	       name,
197 	       is_read(expr) ? "r" : "w",
198 	       conditions ? " (local cap)" : "");
199 
200 	set_spectre_first_half(expr);
201 	if (suppress_multiple)
202 		add_ignore_expr(my_id, array_expr);
203 	free_string(name);
204 }
205 
check_spectre(int id)206 void check_spectre(int id)
207 {
208 	my_id = id;
209 
210 	suppress_multiple = getenv("FULL_SPECTRE") == NULL;
211 
212 	if (option_project != PROJ_KERNEL)
213 		return;
214 
215 	add_hook(&array_check, OP_HOOK);
216 }
217