2 * Copyright (C) 2011 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
18 /* The below code is an adjustment of the smatch_kernel_user_data.c to
19 * track (untrusted and potentially malicious) data received by a guest
20 * kernel via various low-level port IO, MMIO, MSR, CPUID and PCI config
21 * space access functions (see func_table for a full list) from an
22 * untrusted host/VMM under confidential computing threat model
23 * (where a guest VM does not trust the host/VMM).
24 * We call this data as 'host' data here. Being able to track host data
25 * allows creating new smatch patterns that can perform various checks
26 * on such data, i.e. verify that that there are no spectre v1 gadgets
27 * on this attack surface or even simply report locations where host data
28 * is being processed in the kernel source code (useful for a targeted code
30 * Similar as smatch_kernel_user_data.c it works with
31 * smatch_points_to_host_input.c code.
33 * Copyright (C) 2022 Elena Reshetova Intel Corporation.
37 #include "smatch_slist.h"
38 #include "smatch_extra.h"
45 const sval_t
*implies_start
, *implies_end
;
49 static struct host_fn_info func_table
[] = {
50 /* Functions that return host data as return value */
51 { "inb", HOST_DATA
, -1, "$" },
52 { "inw", HOST_DATA
, -1, "$" },
53 { "inl", HOST_DATA
, -1, "$" },
54 { "__inb", HOST_DATA
, -1, "$" },
55 { "__inw", HOST_DATA
, -1, "$" },
56 { "__inl", HOST_DATA
, -1, "$" },
57 { "ioread8", HOST_DATA
, -1, "$" },
58 { "ioread16", HOST_DATA
, -1, "$" },
59 { "ioread32", HOST_DATA
, -1, "$" },
60 { "ioread16be", HOST_DATA
, -1, "$" },
61 { "ioread32be", HOST_DATA
, -1, "$" },
62 { "ioread64_lo_hi", HOST_DATA
, -1, "$" },
63 { "ioread64_hi_lo", HOST_DATA
, -1, "$" },
64 { "ioread64be_lo_hi", HOST_DATA
, -1, "$" },
65 { "ioread64be_hi_lo", HOST_DATA
, -1, "$" },
66 { "iomap_readq", HOST_DATA
, -1, "$" },
67 { "iomap_readb", HOST_DATA
, -1, "$" },
68 { "iomap_readw", HOST_DATA
, -1, "$" },
69 { "iomap_readl", HOST_DATA
, -1, "$" },
70 { "readb", HOST_DATA
, -1, "$" },
71 { "readw", HOST_DATA
, -1, "$" },
72 { "readl", HOST_DATA
, -1, "$" },
73 { "readq", HOST_DATA
, -1, "$" },
74 { "__raw_readb", HOST_DATA
, -1, "$" },
75 { "__raw_readw", HOST_DATA
, -1, "$" },
76 { "__raw_readl", HOST_DATA
, -1, "$" },
77 { "__raw_readq", HOST_DATA
, -1, "$" },
78 { "__readq", HOST_DATA
, -1, "$" },
79 { "__readl", HOST_DATA
, -1, "$" },
80 { "__readb", HOST_DATA
, -1, "$" },
81 { "__readw", HOST_DATA
, -1, "$" },
82 { "native_read_msr", HOST_DATA
, -1, "$" },
83 { "native_read_msr_safe", HOST_DATA
, -1, "$" },
84 { "__rdmsr", HOST_DATA
, -1, "$" },
85 { "paravirt_read_msr", HOST_DATA
, -1, "$" },
86 { "paravirt_read_msr_safe", HOST_DATA
, -1, "$" },
87 /* the below 3 apic funcs are needed
88 * since they unwrap to apic->read(reg),
89 * apic->icr_read() and *(APIC_BASE + reg) */
90 { "apic_read", HOST_DATA
, -1, "$" },
91 { "apic_icr_read", HOST_DATA
, -1, "$" },
92 { "native_apic_mem_read", HOST_DATA
, -1, "$" },
93 /* the below one is x86_apic_ops.io_apic_read */
94 { "io_apic_read", HOST_DATA
, -1, "$" },
95 /* virtio_cread8/16/32/64 funcs are needed
96 * since they call vdev->config->get */
97 { "virtio_cread8", HOST_DATA
, -1, "$" },
98 { "virtio_cread16", HOST_DATA
, -1, "$" },
99 { "virtio_cread32", HOST_DATA
, -1, "$" },
100 { "virtio_cread64", HOST_DATA
, -1, "$" },
101 { "__virtio16_to_cpu", HOST_DATA
, -1, "$" },
102 { "__virtio32_to_cpu", HOST_DATA
, -1, "$" },
103 { "__virtio64_to_cpu", HOST_DATA
, -1, "$" },
104 { "serial_dl_read", HOST_DATA
, -1, "$" },
105 { "serial_in", HOST_DATA
, -1, "$" },
106 { "serial_port_in", HOST_DATA
, -1, "$" },
107 { "cpuid_eax", HOST_DATA
, -1, "$" },
108 { "cpuid_ebx", HOST_DATA
, -1, "$" },
109 { "cpuid_ecx", HOST_DATA
, -1, "$" },
110 { "cpuid_edx", HOST_DATA
, -1, "$" },
111 /* Functions that return host data as argument 1 */
112 { "memcpy_fromio", HOST_DATA
, 0, "*$" },
113 /* Functions that return host data as argument 2 */
114 { "acpi_os_read_iomem", HOST_DATA
, 1, "*$" },
115 { "mmio_insb", HOST_DATA
, 1, "*$" },
116 { "mmio_insw", HOST_DATA
, 1, "*$" },
117 { "mmio_insl", HOST_DATA
, 1, "*$" },
118 { "acpi_read_bit_register", HOST_DATA
, 1, "*$" },
119 /* Functions that return host data as argument 3 */
120 { "rdmsrl_on_cpu", HOST_DATA
, 2, "*$" },
121 { "rdmsrl_safe_on_cpu", HOST_DATA
, 2, "*$" },
122 { "(struct virtio_config_ops)->get", HOST_DATA
, 2, "*$" },
123 { "__virtio_cread_many", HOST_DATA
, 2, "*$" },
124 { "pci_user_read_config_word", HOST_DATA
, 2, "*$" },
125 { "pci_user_read_config_dword", HOST_DATA
, 2, "*$" },
126 { "pci_user_read_config_byte", HOST_DATA
, 2, "*$" },
127 /* Functions that return host data as argument 4 */
128 { "pci_bus_read_config_byte", HOST_DATA
, 3, "*$" },
129 { "pci_bus_read_config_word", HOST_DATA
, 3, "*$" },
130 { "pci_bus_read_config_dword", HOST_DATA
, 3, "*$" },
131 /* Functions that return host data as arguments 3 and 4 */
132 { "rdmsr_on_cpu", HOST_DATA
, 2, "*$" },
133 { "rdmsr_on_cpu", HOST_DATA
, 3, "*$" },
134 { "rdmsr_safe_on_cpu", HOST_DATA
, 2, "*$" },
135 { "rdmsr_safe_on_cpu", HOST_DATA
, 3, "*$" },
136 /* Functions that return host data as argument 6 */
137 { "raw_pci_read", HOST_DATA
, 5, "*$" },
138 /* Functions that return host data as arguments 2-5 */
139 { "cpuid", HOST_DATA
, 1, "*$" },
140 { "cpuid", HOST_DATA
, 2, "*$" },
141 { "cpuid", HOST_DATA
, 3, "*$" },
142 { "cpuid", HOST_DATA
, 4, "*$" },
143 /* Functions that return host data as arguments 3-6 */
144 { "cpuid_count", HOST_DATA
, 2, "*$" },
145 { "cpuid_count", HOST_DATA
, 3, "*$" },
146 { "cpuid_count", HOST_DATA
, 4, "*$" },
147 { "cpuid_count", HOST_DATA
, 5, "*$" },
150 int get_host_data_fn_param(const char *fn
)
157 for (int i
= 0; i
< ARRAY_SIZE(func_table
); i
++) {
158 if (strcmp(fn
, func_table
[i
].name
) == 0) {
159 ret
= func_table
[i
].param
;
162 if ((!ret
) && (is_fn_points_to_host_data(fn
))) {
170 static unsigned long func_gets_host_data
;
171 static struct stree
*start_states
;
173 static struct smatch_state
*empty_state(struct sm_state
*sm
)
175 return alloc_estate_empty();
178 static struct smatch_state
*new_state(struct symbol
*type
)
180 struct smatch_state
*state
;
182 if (!type
|| type_is_ptr(type
))
185 state
= alloc_estate_whole(type
);
186 estate_set_new(state
);
190 static void pre_merge_hook(struct sm_state
*cur
, struct sm_state
*other
)
192 struct smatch_state
*kernel
= cur
->state
;
193 struct smatch_state
*extra
;
194 struct smatch_state
*state
;
195 struct range_list
*rl
;
197 extra
= __get_state(SMATCH_EXTRA
, cur
->name
, cur
->sym
);
200 rl
= rl_intersection(estate_rl(kernel
), estate_rl(extra
));
201 state
= alloc_estate_rl(clone_rl(rl
));
202 if (estate_capped(kernel
) || is_capped_var_sym(cur
->name
, cur
->sym
))
203 estate_set_capped(state
);
204 if (estates_equiv(state
, cur
->state
))
206 if (estate_new(cur
->state
))
207 estate_set_new(state
);
208 set_state(my_id
, cur
->name
, cur
->sym
, state
);
211 static void extra_nomod_hook(const char *name
, struct symbol
*sym
, struct expression
*expr
, struct smatch_state
*state
)
213 struct smatch_state
*host
, *new;
214 struct range_list
*rl
;
216 host
= __get_state(my_id
, name
, sym
);
220 rl
= rl_intersection(estate_rl(host
), estate_rl(state
));
221 if (rl_equiv(rl
, estate_rl(host
)))
223 new = alloc_estate_rl(rl
);
224 if (estate_capped(host
))
225 estate_set_capped(new);
226 set_state(my_id
, name
, sym
, new);
229 static void store_type_info(struct expression
*expr
, struct smatch_state
*state
)
232 char *type_str
, *member
;
234 if (__in_fake_assign
)
237 if (!estate_rl(state
))
240 expr
= strip_expr(expr
);
241 if (!expr
|| expr
->type
!= EXPR_DEREF
|| !expr
->member
)
244 type
= get_type(expr
->deref
);
245 if (!type
|| !type
->ident
)
248 type_str
= type_to_str(type
);
251 member
= get_member_name(expr
);
255 sql_insert_function_type_info(HOST_DATA
, type_str
, member
, state
->name
);
258 static void set_host_data(struct expression
*expr
, struct smatch_state
*state
)
260 store_type_info(expr
, state
);
261 set_state_expr(my_id
, expr
, state
);
264 static bool host_rl_known(struct expression
*expr
)
266 struct range_list
*rl
;
269 if (!get_host_rl(expr
, &rl
))
272 close_to_max
= sval_type_max(rl_type(rl
));
273 close_to_max
.value
-= 100;
275 if (sval_cmp(rl_max(rl
), close_to_max
) >= 0)
280 static bool is_array_index_mask_nospec(struct expression
*expr
)
282 struct expression
*orig
;
284 orig
= get_assigned_expr(expr
);
285 if (!orig
|| orig
->type
!= EXPR_CALL
)
287 return sym_name_is("array_index_mask_nospec", orig
->fn
);
290 static bool binop_capped(struct expression
*expr
)
292 struct range_list
*left_rl
;
296 if (expr
->op
== '-' && get_host_rl(expr
->left
, &left_rl
)) {
297 if (host_rl_capped(expr
->left
))
299 comparison
= get_comparison(expr
->left
, expr
->right
);
300 if (comparison
&& show_special(comparison
)[0] == '>')
305 if (expr
->op
== '&' || expr
->op
== '%') {
306 bool left_host
, left_capped
, right_host
, right_capped
;
308 if (!get_value(expr
->right
, &sval
) && is_capped(expr
->right
))
310 if (is_array_index_mask_nospec(expr
->right
))
312 if (is_capped(expr
->left
))
314 left_host
= is_host_rl(expr
->left
);
315 right_host
= is_host_rl(expr
->right
);
316 if (!left_host
&& !right_host
)
319 left_capped
= host_rl_capped(expr
->left
);
320 right_capped
= host_rl_capped(expr
->right
);
322 if (left_host
&& left_capped
) {
325 if (right_host
&& right_capped
)
329 if (right_host
&& right_capped
) {
338 * Generally "capped" means that we capped it to an unknown value.
339 * This is useful because if Smatch doesn't know what the value is then
340 * we have to trust that it is correct. But if we known cap value is
341 * 100 then we can check if 100 is correct and complain if it's wrong.
343 * So then the problem is with BINOP when we take a capped variable
344 * plus a host variable which is clamped to a known range (uncapped)
345 * the result should be capped.
347 if ((host_rl_capped(expr
->left
) || host_rl_known(expr
->left
)) &&
348 (host_rl_capped(expr
->right
) || host_rl_known(expr
->right
)))
353 bool host_rl_capped(struct expression
*expr
)
355 struct smatch_state
*state
;
356 struct range_list
*rl
;
359 expr
= strip_expr(expr
);
362 if (get_value(expr
, &sval
))
364 if (expr
->type
== EXPR_BINOP
)
365 return binop_capped(expr
);
366 if ((expr
->type
== EXPR_PREOP
|| expr
->type
== EXPR_POSTOP
) &&
367 (expr
->op
== SPECIAL_INCREMENT
|| expr
->op
== SPECIAL_DECREMENT
))
368 return host_rl_capped(expr
->unop
);
369 state
= get_state_expr(my_id
, expr
);
371 return estate_capped(state
);
373 if (!get_host_rl(expr
, &rl
)) {
375 * The non host data parts of a binop are capped and
376 * also empty host rl states are capped.
381 if (rl_to_sval(rl
, &sval
))
384 return false; /* uncapped host data */
387 static void tag_inner_struct_members(struct expression
*expr
, struct symbol
*member
)
389 struct expression
*edge_member
;
390 struct symbol
*base
= get_real_base_type(member
);
394 expr
= member_expression(expr
, '.', member
->ident
);
396 FOR_EACH_PTR(base
->symbol_list
, tmp
) {
399 type
= get_real_base_type(tmp
);
403 if (type
->type
== SYM_UNION
|| type
->type
== SYM_STRUCT
) {
404 tag_inner_struct_members(expr
, tmp
);
411 edge_member
= member_expression(expr
, '.', tmp
->ident
);
412 set_host_data(edge_member
, new_state(type
));
413 } END_FOR_EACH_PTR(tmp
);
416 static void tag_struct_members(struct symbol
*type
, struct expression
*expr
)
419 struct expression
*member
;
422 if (expr
->type
== EXPR_PREOP
&& expr
->op
== '&') {
423 expr
= strip_expr(expr
->unop
);
427 FOR_EACH_PTR(type
->symbol_list
, tmp
) {
428 type
= get_real_base_type(tmp
);
432 if (type
->type
== SYM_UNION
|| type
->type
== SYM_STRUCT
) {
433 tag_inner_struct_members(expr
, tmp
);
440 member
= member_expression(expr
, op
, tmp
->ident
);
441 if (type
->type
== SYM_ARRAY
) {
442 set_points_to_host_data(member
, true);
444 set_host_data(member
, new_state(get_type(member
)));
446 } END_FOR_EACH_PTR(tmp
);
449 static void tag_base_type(struct expression
*expr
)
451 if (expr
->type
== EXPR_PREOP
&& expr
->op
== '&')
452 expr
= strip_expr(expr
->unop
);
454 expr
= deref_expression(expr
);
455 set_host_data(expr
, new_state(get_type(expr
)));
458 static void tag_as_host_data(struct expression
*expr
)
462 expr
= strip_expr(expr
);
463 type
= get_type(expr
);
468 if (type
->type
== SYM_PTR
){
469 type
= get_real_base_type(type
);
472 if (type
== &void_ctype
) {
473 set_host_data(deref_expression(expr
), new_state(&ulong_ctype
));
476 if (type
->type
== SYM_BASETYPE
) {
477 if (expr
->type
!= EXPR_PREOP
&& expr
->op
!= '&')
478 set_points_to_host_data(expr
, true);
482 if (type
->type
== SYM_STRUCT
|| type
->type
== SYM_UNION
) {
483 if (expr
->type
!= EXPR_PREOP
|| expr
->op
!= '&')
484 expr
= deref_expression(expr
);
486 set_host_data(deref_expression(expr
), new_state(&ulong_ctype
));
487 tag_struct_members(type
, expr
);
492 if (expr
->type
== EXPR_DEREF
) {
493 type
= get_type(expr
->deref
);
494 expr
= strip_expr(expr
->deref
);
497 sm_msg("%s: no type\n", __func__
);
502 if (type
->type
== SYM_BASETYPE
) {
503 if (expr
->type
== EXPR_PREOP
&& expr
->op
== '*')
504 set_points_to_host_data(expr
->unop
, true);
505 set_host_data(expr
, new_state(get_type(expr
)));
508 if (type
->type
== SYM_STRUCT
|| type
->type
== SYM_UNION
) {
509 set_host_data(expr
, new_state(&ulong_ctype
));
510 tag_struct_members(type
, expr
);
514 static int get_rl_from_function(struct expression
*expr
, struct range_list
**rl
)
519 if (expr
->type
!= EXPR_CALL
|| expr
->fn
->type
!= EXPR_SYMBOL
||
520 !expr
->fn
->symbol_name
)
523 for (int i
= 0; i
< ARRAY_SIZE(func_table
); i
++) {
524 if ((strcmp(expr
->fn
->symbol_name
->name
, func_table
[i
].name
) == 0) &&
525 (func_table
[i
].param
== -1)) {
526 *rl
= alloc_whole_rl(get_type(expr
));
533 static bool state_is_new(struct expression
*expr
)
535 struct smatch_state
*state
;
537 state
= get_state_expr(my_id
, expr
);
538 if (estate_new(state
))
541 if (expr
->type
== EXPR_BINOP
) {
542 if (state_is_new(expr
->left
))
544 if (state_is_new(expr
->right
))
550 static void handle_derefed_pointers(struct expression
*expr
, bool is_new
)
552 expr
= strip_expr(expr
);
553 if (expr
->type
!= EXPR_PREOP
||
556 expr
= strip_expr(expr
->unop
);
557 set_points_to_host_data(expr
, is_new
);
560 static bool handle_op_assign(struct expression
*expr
)
562 struct expression
*binop_expr
;
563 struct smatch_state
*state
;
564 struct range_list
*rl
;
568 case SPECIAL_ADD_ASSIGN
:
569 case SPECIAL_SUB_ASSIGN
:
570 case SPECIAL_AND_ASSIGN
:
571 case SPECIAL_MOD_ASSIGN
:
572 case SPECIAL_SHL_ASSIGN
:
573 case SPECIAL_SHR_ASSIGN
:
574 case SPECIAL_OR_ASSIGN
:
575 case SPECIAL_XOR_ASSIGN
:
576 case SPECIAL_MUL_ASSIGN
:
577 case SPECIAL_DIV_ASSIGN
:
578 binop_expr
= binop_expression(expr
->left
,
579 op_remove_assign(expr
->op
),
581 if (!get_host_rl(binop_expr
, &rl
))
583 rl
= cast_rl(get_type(expr
->left
), rl
);
584 state
= alloc_estate_rl(rl
);
585 if (expr
->op
== SPECIAL_AND_ASSIGN
||
586 expr
->op
== SPECIAL_MOD_ASSIGN
||
587 host_rl_capped(binop_expr
))
588 estate_set_capped(state
);
589 is_new
= state_is_new(binop_expr
);
591 estate_set_new(state
);
592 estate_set_assigned(state
);
593 set_host_data(expr
->left
, state
);
594 handle_derefed_pointers(expr
->left
, is_new
);
600 static struct range_list
*strip_negatives(struct range_list
*rl
)
602 sval_t min
= rl_min(rl
);
603 sval_t minus_one
= { .type
= rl_type(rl
), .value
= -1 };
604 sval_t over
= { .type
= rl_type(rl
), .value
= INT_MAX
+ 1ULL };
605 sval_t max
= sval_type_max(rl_type(rl
));
610 if (type_unsigned(rl_type(rl
)) && type_bits(rl_type(rl
)) > 31)
611 return remove_range(rl
, over
, max
);
613 return remove_range(rl
, min
, minus_one
);
616 static void match_assign_host(struct expression
*expr
)
618 struct symbol
*left_type
, *right_type
;
619 struct range_list
*rl
= NULL
;
620 static struct expression
*handled
;
621 struct smatch_state
*state
;
622 struct expression
*faked
;
623 bool is_capped
= false;
629 left_type
= get_type(expr
->left
);
630 if (left_type
== &void_ctype
)
633 faked
= get_faked_expression();
635 /* FIXME: handle fake array assignments frob(&host_array[x]); */
638 faked
->type
== EXPR_ASSIGNMENT
&&
639 points_to_host_data(faked
->right
)) {
640 rl
= alloc_whole_rl(get_type(expr
->left
));
645 if (faked
&& faked
== handled
)
647 if (is_fake_call(expr
->right
))
648 goto clear_old_state
;
649 if (points_to_host_data(expr
->right
) &&
650 is_struct_ptr(get_type(expr
->left
))) {
652 // This should be handled by smatch_points_to_host_data.c
653 //set_points_to_host_data(expr->left);
656 if (handle_op_assign(expr
))
659 goto clear_old_state
;
661 /* Handled by DB code */
662 if (expr
->right
->type
== EXPR_CALL
)
666 disable_type_val_lookups();
667 get_host_rl(expr
->right
, &rl
);
669 enable_type_val_lookups();
671 goto clear_old_state
;
673 is_capped
= host_rl_capped(expr
->right
);
674 is_new
= state_is_new(expr
->right
);
677 right_type
= get_type(expr
->right
);
678 if (type_is_ptr(left_type
)) {
679 if (right_type
&& right_type
->type
== SYM_ARRAY
)
680 set_points_to_host_data(expr
->left
, is_new
);
684 rl
= cast_rl(left_type
, rl
);
685 if (is_capped
&& type_unsigned(right_type
) && type_signed(left_type
))
686 rl
= strip_negatives(rl
);
687 state
= alloc_estate_rl(rl
);
689 estate_set_new(state
);
691 estate_set_capped(state
);
692 estate_set_assigned(state
);
693 set_host_data(expr
->left
, state
);
694 handle_derefed_pointers(expr
->left
, is_new
);
700 * HACK ALERT!!! This should be at the start of the function. The
701 * the problem is that handling "pointer = array;" assignments is
702 * handled in this function instead of in kernel_points_to_host_data.c.
704 if (type_is_ptr(left_type
))
707 if (get_state_expr(my_id
, expr
->left
))
708 set_host_data(expr
->left
, alloc_estate_empty());
711 static void handle_eq_noteq(struct expression
*expr
)
713 struct smatch_state
*left_orig
, *right_orig
;
715 left_orig
= get_state_expr(my_id
, expr
->left
);
716 right_orig
= get_state_expr(my_id
, expr
->right
);
718 if (!left_orig
&& !right_orig
)
720 if (left_orig
&& right_orig
)
724 set_true_false_states_expr(my_id
, expr
->left
,
725 expr
->op
== SPECIAL_EQUAL
? alloc_estate_empty() : NULL
,
726 expr
->op
== SPECIAL_EQUAL
? NULL
: alloc_estate_empty());
728 set_true_false_states_expr(my_id
, expr
->right
,
729 expr
->op
== SPECIAL_EQUAL
? alloc_estate_empty() : NULL
,
730 expr
->op
== SPECIAL_EQUAL
? NULL
: alloc_estate_empty());
734 static void handle_compare(struct expression
*expr
)
736 struct expression
*left
, *right
;
737 struct range_list
*left_rl
= NULL
;
738 struct range_list
*right_rl
= NULL
;
739 struct range_list
*host_rl
;
740 struct smatch_state
*capped_state
;
741 struct smatch_state
*left_true
= NULL
;
742 struct smatch_state
*left_false
= NULL
;
743 struct smatch_state
*right_true
= NULL
;
744 struct smatch_state
*right_false
= NULL
;
748 left
= strip_expr(expr
->left
);
749 right
= strip_expr(expr
->right
);
751 while (left
->type
== EXPR_ASSIGNMENT
)
752 left
= strip_expr(left
->left
);
755 * Conditions are mostly handled by smatch_extra.c, but there are some
756 * times where the exact values are not known so we can't do that.
758 * Normally, we might consider using smatch_capped.c to supliment smatch
759 * extra but that doesn't work when we merge unknown uncapped kernel
760 * data with unknown capped host data. The result is uncapped host
761 * data. We need to keep it separate and say that the host data is
762 * capped. In the past, I would have marked this as just regular
763 * kernel data (not host data) but we can't do that these days because
764 * we need to track host data for Spectre.
766 * The other situation which we have to handle is when we do have an
767 * int and we compare against an unknown unsigned kernel variable. In
768 * that situation we assume that the kernel data is less than INT_MAX.
769 * Otherwise then we get all sorts of array underflow false positives.
773 /* Handled in smatch_extra.c */
774 if (get_implied_value(left
, &sval
) ||
775 get_implied_value(right
, &sval
))
778 get_host_rl(left
, &left_rl
);
779 get_host_rl(right
, &right_rl
);
782 if (!left_rl
&& !right_rl
)
784 /* if both sides are host data that's not a good limit */
785 if (left_rl
&& right_rl
)
793 type
= get_type(expr
);
794 if (type_unsigned(type
))
795 host_rl
= strip_negatives(host_rl
);
796 capped_state
= alloc_estate_rl(host_rl
);
797 estate_set_capped(capped_state
);
801 case SPECIAL_UNSIGNED_LT
:
803 case SPECIAL_UNSIGNED_LTE
:
805 left_true
= capped_state
;
807 right_false
= capped_state
;
810 case SPECIAL_UNSIGNED_GT
:
812 case SPECIAL_UNSIGNED_GTE
:
814 left_false
= capped_state
;
816 right_true
= capped_state
;
819 set_true_false_states_expr(my_id
, left
, left_true
, left_false
);
820 set_true_false_states_expr(my_id
, right
, right_true
, right_false
);
823 static void match_condition_host(struct expression
*expr
)
828 if (expr
->type
!= EXPR_COMPARE
)
831 if (expr
->op
== SPECIAL_EQUAL
||
832 expr
->op
== SPECIAL_NOTEQUAL
) {
833 handle_eq_noteq(expr
);
836 handle_compare(expr
);
839 static void match_returns_host_rl(const char *fn
, struct expression
*expr
, void *unused
)
841 func_gets_host_data
= true;
844 static int has_host_data(struct symbol
*sym
)
846 struct sm_state
*tmp
;
848 FOR_EACH_MY_SM(my_id
, __get_cur_stree(), tmp
) {
851 } END_FOR_EACH_SM(tmp
);
855 bool we_pass_host_data(struct expression
*call
)
857 struct expression
*arg
;
860 FOR_EACH_PTR(call
->args
, arg
) {
861 if (points_to_host_data(arg
))
863 sym
= expr_to_sym(arg
);
866 if (has_host_data(sym
))
868 } END_FOR_EACH_PTR(arg
);
873 static int db_returned_host_rl(struct expression
*call
, struct range_list
**rl
)
875 struct smatch_state
*state
;
878 if (is_fake_call(call
))
880 snprintf(buf
, sizeof(buf
), "return %p", call
);
881 state
= get_state(my_id
, buf
, NULL
);
882 if (!state
|| !estate_rl(state
))
884 *rl
= estate_rl(state
);
888 struct stree
*get_host_stree(void)
890 return get_all_states_stree(my_id
);
893 static int host_data_flag
;
894 static int no_host_data_flag
;
896 struct range_list
*var_host_rl(struct expression
*expr
)
898 struct smatch_state
*state
;
899 struct range_list
*rl
;
900 struct range_list
*absolute_rl
;
902 if (expr
->type
== EXPR_PREOP
&& expr
->op
== '&') {
903 no_host_data_flag
= 1;
907 if (expr
->type
== EXPR_BINOP
&& expr
->op
== '%') {
908 struct range_list
*left
, *right
;
910 if (!get_host_rl(expr
->right
, &right
))
912 get_absolute_rl(expr
->left
, &left
);
913 rl
= rl_binop(left
, '%', right
);
917 if (expr
->type
== EXPR_BINOP
&& expr
->op
== '/') {
918 struct range_list
*left
= NULL
;
919 struct range_list
*right
= NULL
;
920 struct range_list
*abs_right
;
922 get_host_rl(expr
->left
, &left
);
923 get_host_rl(expr
->right
, &right
);
924 get_absolute_rl(expr
->right
, &abs_right
);
926 if (left
&& !right
) {
927 rl
= rl_binop(left
, '/', abs_right
);
928 if (sval_cmp(rl_max(left
), rl_max(rl
)) < 0)
929 no_host_data_flag
= 1;
935 if (get_rl_from_function(expr
, &rl
))
938 state
= get_state_expr(my_id
, expr
);
939 if (state
&& estate_rl(state
)) {
940 rl
= estate_rl(state
);
944 if (expr
->type
== EXPR_CALL
&& db_returned_host_rl(expr
, &rl
))
947 if (expr
->type
== EXPR_PREOP
&& expr
->op
== '*' &&
948 points_to_host_data(expr
->unop
)) {
949 rl
= var_to_absolute_rl(expr
);
953 if (is_array(expr
)) {
954 struct expression
*array
= get_array_base(expr
);
956 if (!get_state_expr(my_id
, array
)) {
957 no_host_data_flag
= 1;
965 absolute_rl
= var_to_absolute_rl(expr
);
966 return clone_rl(rl_intersection(rl
, absolute_rl
));
969 static bool is_ptr_subtract(struct expression
*expr
)
971 expr
= strip_expr(expr
);
974 if (expr
->type
== EXPR_BINOP
&& expr
->op
== '-' &&
975 type_is_ptr(get_type(expr
->left
))) {
981 int get_host_rl(struct expression
*expr
, struct range_list
**rl
)
983 if (is_ptr_subtract(expr
))
987 no_host_data_flag
= 0;
988 custom_get_absolute_rl(expr
, &var_host_rl
, rl
);
989 if (!host_data_flag
|| no_host_data_flag
)
994 int is_host_rl(struct expression
*expr
)
996 struct range_list
*tmp
;
998 return get_host_rl(expr
, &tmp
) && tmp
;
1001 int get_host_rl_var_sym(const char *name
, struct symbol
*sym
, struct range_list
**rl
)
1003 struct smatch_state
*state
;
1005 state
= get_state(my_id
, name
, sym
);
1006 if (state
&& estate_rl(state
)) {
1007 *rl
= estate_rl(state
);
1013 static void return_info_callback_host(int return_id
, char *return_ranges
,
1014 struct expression
*returned_expr
,
1016 const char *printed_name
,
1017 struct sm_state
*sm
)
1019 struct smatch_state
*extra
;
1020 struct range_list
*rl
;
1023 if (is_ignored_kernel_data(printed_name
))
1027 if (strcmp(printed_name
, "$") == 0)
1029 if (!estate_assigned(sm
->state
) &&
1030 !estate_new(sm
->state
))
1033 rl
= estate_rl(sm
->state
);
1036 extra
= get_state(SMATCH_EXTRA
, sm
->name
, sm
->sym
);
1037 if (estate_rl(extra
))
1038 rl
= rl_intersection(estate_rl(sm
->state
), estate_rl(extra
));
1042 snprintf(buf
, sizeof(buf
), "%s%s%s",
1044 estate_capped(sm
->state
) ? "[c]" : "", "");
1045 sql_insert_return_states(return_id
, return_ranges
,
1046 estate_new(sm
->state
) ? HOST_DATA_SET
: HOST_DATA
,
1047 param
, printed_name
, buf
);
1051 static void caller_info_callback_host(struct expression
*call
, int param
, char *printed_name
, struct sm_state
*sm
)
1053 struct smatch_state
*state
;
1054 struct range_list
*rl
;
1055 struct symbol
*type
;
1059 * Smatch uses a hack where if we get an unsigned long we say it's
1060 * both host data and it points to host data. But if we pass it to a
1061 * function which takes an int, then it's just host data. There's not
1062 * enough bytes for it to be a pointer.
1065 type
= get_arg_type(call
->fn
, param
);
1066 if (strcmp(printed_name
, "$") != 0 && type
&& type_bits(type
) < type_bits(&ptr_ctype
))
1069 if (is_ignored_kernel_data(printed_name
))
1072 if (strcmp(sm
->state
->name
, "") == 0)
1075 state
= __get_state(SMATCH_EXTRA
, sm
->name
, sm
->sym
);
1076 if (!state
|| !estate_rl(state
))
1077 rl
= estate_rl(sm
->state
);
1079 rl
= rl_intersection(estate_rl(sm
->state
), estate_rl(state
));
1084 snprintf(buf
, sizeof(buf
), "%s%s%s", show_rl(rl
),
1085 estate_capped(sm
->state
) ? "[c]" : "", "");
1086 sql_insert_caller_info(call
, HOST_DATA
, param
, printed_name
, buf
);
1089 static void db_param_set(struct expression
*expr
, int param
, char *key
, char *value
)
1091 struct expression
*arg
;
1094 struct smatch_state
*state
;
1096 while (expr
->type
== EXPR_ASSIGNMENT
)
1097 expr
= strip_expr(expr
->right
);
1098 if (expr
->type
!= EXPR_CALL
)
1101 arg
= get_argument_from_call_expr(expr
->args
, param
);
1105 name
= get_variable_from_key(arg
, key
, &sym
);
1109 state
= get_state(my_id
, name
, sym
);
1113 set_state(my_id
, name
, sym
, alloc_estate_empty());
1118 static bool param_data_capped(const char *value
)
1120 if (strstr(value
, ",c") || strstr(value
, "[c"))
1125 static void set_param_host_data(const char *name
, struct symbol
*sym
, char *key
, char *value
)
1127 struct expression
*expr
;
1128 struct range_list
*rl
= NULL
;
1129 struct smatch_state
*state
;
1130 struct symbol
*type
;
1133 expr
= symbol_expression(sym
);
1134 fullname
= get_variable_from_key(expr
, key
, NULL
);
1138 type
= get_member_type_from_key(expr
, key
);
1139 if (type
&& type
->type
== SYM_STRUCT
)
1145 str_to_rl(type
, value
, &rl
);
1146 rl
= swap_mtag_seed(expr
, rl
);
1147 state
= alloc_estate_rl(rl
);
1148 if (param_data_capped(value
) || is_capped(expr
))
1149 estate_set_capped(state
);
1150 set_state(my_id
, fullname
, sym
, state
);
1156 static void store_host_data_return(struct expression
*expr
, char *key
, char *value
, bool is_new
)
1158 struct smatch_state
*state
;
1159 struct range_list
*rl
;
1160 struct symbol
*type
;
1166 type
= get_type(expr
);
1167 snprintf(buf
, sizeof(buf
), "return %p%s", expr
, key
+ 1);
1168 call_results_to_rl(expr
, type
, value
, &rl
);
1170 state
= alloc_estate_rl(rl
);
1172 estate_set_new(state
);
1173 set_state(my_id
, buf
, NULL
, state
);
1176 static void set_to_host_data(struct expression
*expr
, char *key
, char *value
, bool is_new
)
1178 struct smatch_state
*state
;
1181 struct symbol
*type
;
1182 struct range_list
*rl
= NULL
;
1184 type
= get_member_type_from_key(expr
, key
);
1185 name
= get_variable_from_key(expr
, key
, &sym
);
1189 call_results_to_rl(expr
, type
, value
, &rl
);
1191 state
= alloc_estate_rl(rl
);
1192 if (param_data_capped(value
))
1193 estate_set_capped(state
);
1195 estate_set_new(state
);
1196 estate_set_assigned(state
);
1197 set_state(my_id
, name
, sym
, state
);
1202 static void returns_param_host_data(struct expression
*expr
, int param
, char *key
, char *value
)
1204 struct expression
*arg
;
1205 struct expression
*call
;
1208 while (call
->type
== EXPR_ASSIGNMENT
)
1209 call
= strip_expr(call
->right
);
1210 if (call
->type
!= EXPR_CALL
)
1213 if (!we_pass_host_data(call
))
1217 if (expr
->type
!= EXPR_ASSIGNMENT
) {
1218 store_host_data_return(expr
, key
, value
, OLD
);
1221 set_to_host_data(expr
->left
, key
, value
, OLD
);
1225 arg
= get_argument_from_call_expr(call
->args
, param
);
1228 set_to_host_data(arg
, key
, value
, OLD
);
1231 static void returns_param_host_data_set(struct expression
*expr
, int param
, char *key
, char *value
)
1233 struct expression
*arg
;
1235 func_gets_host_data
= true;
1238 if (expr
->type
!= EXPR_ASSIGNMENT
) {
1239 store_host_data_return(expr
, key
, value
, NEW
);
1242 set_to_host_data(expr
->left
, key
, value
, NEW
);
1246 while (expr
->type
== EXPR_ASSIGNMENT
)
1247 expr
= strip_expr(expr
->right
);
1248 if (expr
->type
!= EXPR_CALL
)
1251 arg
= get_argument_from_call_expr(expr
->args
, param
);
1254 set_to_host_data(arg
, key
, value
, NEW
);
1257 static void returns_param_capped_host(struct expression
*expr
, int param
, char *key
, char *value
)
1259 struct smatch_state
*state
, *new;
1263 name
= get_name_sym_from_param_key(expr
, param
, key
, &sym
);
1267 state
= get_state(my_id
, name
, sym
);
1268 if (!state
|| estate_capped(state
))
1271 new = clone_estate(state
);
1272 estate_set_capped(new);
1274 set_state(my_id
, name
, sym
, new);
1279 struct param_key_data
{
1280 param_key_hook
*call_back
;
1286 static void match_function_def(struct symbol
*sym
)
1288 if (is_host_data_fn(sym
))
1289 func_gets_host_data
= true;
1292 static void set_param_host_input_data(struct expression
*expr
, const char *name
,
1293 struct symbol
*sym
, void *data
)
1295 struct expression
*arg
;
1297 func_gets_host_data
= true;
1298 arg
= gen_expression_from_name_sym(name
, sym
);
1299 tag_as_host_data(arg
);
1302 void register_kernel_host_data(int id
)
1305 struct host_fn_info
*info
;
1309 if (option_project
!= PROJ_KERNEL
)
1312 set_dynamic_states(my_id
);
1313 add_function_data(&func_gets_host_data
);
1314 add_hook(&match_function_def
, FUNC_DEF_HOOK
);
1316 add_function_data((unsigned long *)&start_states
);
1317 add_unmatched_state_hook(my_id
, &empty_state
);
1318 add_extra_nomod_hook(&extra_nomod_hook
);
1319 add_pre_merge_hook(my_id
, &pre_merge_hook
);
1320 add_merge_hook(my_id
, &merge_estates
);
1323 for (i
= 0; i
< ARRAY_SIZE(func_table
); i
++) {
1324 info
= &func_table
[i
];
1325 add_function_param_key_hook_late(info
->name
, &set_param_host_input_data
,
1326 info
->param
, info
->key
, info
);
1329 for (i
= 0; i
< ARRAY_SIZE(func_table
); i
++) {
1330 if (func_table
[i
].param
== -1)
1331 add_function_hook(func_table
[i
].name
, &match_returns_host_rl
, NULL
);
1334 add_hook(&match_assign_host
, ASSIGNMENT_HOOK
);
1335 select_return_states_hook(PARAM_SET
, &db_param_set
);
1336 add_hook(&match_condition_host
, CONDITION_HOOK
);
1338 add_caller_info_callback(my_id
, caller_info_callback_host
);
1339 add_return_info_callback(my_id
, return_info_callback_host
);
1340 select_caller_info_hook(set_param_host_data
, HOST_DATA
);
1341 select_return_states_hook(HOST_DATA
, &returns_param_host_data
);
1342 select_return_states_hook(HOST_DATA_SET
, &returns_param_host_data_set
);
1343 select_return_states_hook(CAPPED_DATA
, &returns_param_capped_host
);