From 9453969d2d2b188c59644e37084ff3aee440d1b2 Mon Sep 17 00:00:00 2001 From: Norbert Manthey Date: Thu, 2 Aug 2018 14:50:03 +0200 Subject: [PATCH 01/16] math: increase bounds and buffers To get more out of the analysis, increase some buffers and limits. Signed-off-by: Norbert Manthey --- smatch_flow.c | 2 +- smatch_implied.c | 4 ++-- smatch_math.c | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/smatch_flow.c b/smatch_flow.c index 74c97b4f..26a462f0 100644 --- a/smatch_flow.c +++ b/smatch_flow.c @@ -910,7 +910,7 @@ int time_parsing_function(void) bool taking_too_long(void) { - if ((ms_since(&outer_fn_start_time) / 1000) > 60 * 5) /* five minutes */ + if ((ms_since(&outer_fn_start_time) / 1000) > 60 * 10) /* 10 minutes */ return 1; return 0; } diff --git a/smatch_implied.c b/smatch_implied.c index 9d4a3913..b74768ff 100644 --- a/smatch_implied.c +++ b/smatch_implied.c @@ -448,13 +448,13 @@ static int going_too_slow(void) return 1; } - if (time_parsing_function() < 60) { + if (time_parsing_function() < 180) { implications_off = false; return 0; } if (!__inline_fn && printed != cur_func_sym) { - sm_perror("turning off implications after 60 seconds"); + sm_perror("turning off implications after 180 seconds"); printed = cur_func_sym; } implications_off = true; diff --git a/smatch_math.c b/smatch_math.c index 55f5fcef..c8d00f21 100644 --- a/smatch_math.c +++ b/smatch_math.c @@ -1501,7 +1501,7 @@ static bool get_rl_sval(struct expression *expr, int implied, int *recurse_cnt, if (!expr) return false; - if (++(*recurse_cnt) >= 200) + if (++(*recurse_cnt) >= 500) return false; switch(expr->type) { @@ -1636,7 +1636,7 @@ static bool get_rl_helper(struct expression *expr, int implied, struct range_lis struct { struct expression *expr; sval_t sval; -} cached_results[24]; +} cached_results[72]; static int cache_idx; void clear_math_cache(void) From 6be127299ca35c3e4c9d9d4c6db8c4591f73fcd6 Mon Sep 17 00:00:00 2001 From: Norbert Manthey Date: Wed, 17 Feb 2021 22:36:35 +0100 Subject: [PATCH 02/16] build: fix clean target Cleanup all files that have been created. Signed-off-by: Norbert Manthey --- Makefile | 1 + cwchash/Makefile | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 8855c974..e1a4d52e 100644 --- a/Makefile +++ b/Makefile @@ -416,6 +416,7 @@ validation/%: $(PROGRAMS) FORCE clean: clean-check @rm -f *.[oa] .*.d $(PROGRAMS) version.h smatch + $(MAKE) clean -C cwchash clean-check: @echo " CLEAN" @find validation/ \( -name "*.c.output.*" \ diff --git a/cwchash/Makefile b/cwchash/Makefile index 5a1f65cd..1d4df66f 100644 --- a/cwchash/Makefile +++ b/cwchash/Makefile @@ -20,7 +20,7 @@ hashtable_itr.o: hashtable_itr.c gcc -g -Wall -O -c hashtable_itr.c -o hashtable_itr.o tidy: - rm *.o + rm -f *.o clean: tidy rm -f tester old_tester From 417c9193d83ddbeab17823d878194879d2571fee Mon Sep 17 00:00:00 2001 From: Norbert Manthey Date: Thu, 2 Aug 2018 15:24:14 +0200 Subject: [PATCH 03/16] spectre: show more candidates, with more info Instead of cutting gadgets off, report the information that would have been used to cut them off. Signed-off-by: Norbert Manthey --- check_spectre.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/check_spectre.c b/check_spectre.c index 16301a2e..8bf64131 100644 --- a/check_spectre.c +++ b/check_spectre.c @@ -154,16 +154,24 @@ static void array_check(struct expression *expr) struct expression_list *conditions; struct expression *array_expr, *offset; unsigned long long mask; + + int impossible = 0, harmless = 0; + int user = 0, array = 0; + int array_size; char *name; expr = strip_expr(expr); - if (!is_array(expr)) + array = is_array(expr); + if (!array) return; - if (is_impossible_path()) + impossible = is_impossible_path(); + if (suppress_multiple && impossible) return; - if (is_harmless(expr)) + + harmless = is_harmless(expr); + if (suppress_multiple && harmless) return; array_expr = get_array_base(expr); @@ -192,10 +200,12 @@ static void array_check(struct expression *expr) conditions = get_conditions(offset); name = expr_to_str(array_expr); - sm_warning("potential spectre issue '%s' [%s]%s", + sm_warning("potential spectre issue '%s' [%s]%s%s%s", name, is_read(expr) ? "r" : "w", - conditions ? " (local cap)" : ""); + conditions ? " (local cap)" : "", + impossible ? " (impossible)" : "", + harmless ? " (harmless)" : ""); set_spectre_first_half(expr); if (suppress_multiple) From 908c50ea71e14c0b0e75166daab72761b5549166 Mon Sep 17 00:00:00 2001 From: Norbert Manthey Date: Thu, 2 Aug 2018 14:52:52 +0200 Subject: [PATCH 04/16] user_data: add ends_with method This method is used to be able to decide whether a function name matched the "do_" ... "_op" structure of some Xen hypercalls. Signed-off-by: Norbert Manthey --- smatch_kernel_user_data.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/smatch_kernel_user_data.c b/smatch_kernel_user_data.c index 627f7f9a..df4d9a8a 100644 --- a/smatch_kernel_user_data.c +++ b/smatch_kernel_user_data.c @@ -1157,6 +1157,28 @@ static void set_called(const char *name, struct symbol *sym, char *key, char *va set_state(my_call_id, "this_function", NULL, &called); } +static int ends_with(const char *symbol, const char *suffix) +{ + if(!symbol || !suffix) + return 0; + + int l = strnlen(symbol, 128); + int e = strnlen(suffix, 16); + + /* Is the string smaller than the suffix? */ + if(l < e) + return 0; + + /* Check from the end whether the strings match */ + for(int i = 0; i <= e; ++ i) { + if( symbol[l-i] != suffix[e-i]) + return 0; + } + + /* The suffix matches */ + return 1; +} + static void match_syscall_definition(struct symbol *sym) { struct symbol *arg; From 6755fbf9b99feb2dc0ee0f99d15e0f665d5f984e Mon Sep 17 00:00:00 2001 From: Norbert Manthey Date: Thu, 2 Aug 2018 14:53:35 +0200 Subject: [PATCH 05/16] user_data: match some Xen hypercalls In case a function name matches the structure of a Xen hypercall, match it, and treat it as a kernel syscall. Currently, possible hypercalls are identified via string patterns, starting with "do_" or "hvm_" or "arch_", and ending with "_op", "_op_compat" or "_op_compat32", respectively. Signed-off-by: Norbert Manthey --- smatch_kernel_user_data.c | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/smatch_kernel_user_data.c b/smatch_kernel_user_data.c index df4d9a8a..2b5740c2 100644 --- a/smatch_kernel_user_data.c +++ b/smatch_kernel_user_data.c @@ -1184,7 +1184,7 @@ static void match_syscall_definition(struct symbol *sym) struct symbol *arg; char *macro; char *name; - int is_syscall = 0; + int is_syscall = 0, i; macro = get_macro_name(sym->pos); if (macro && @@ -1193,14 +1193,34 @@ static void match_syscall_definition(struct symbol *sym) is_syscall = 1; name = get_function(); + + /* Currently only works if there is a name */ + if (!name) + return; + if (!option_no_db && get_state(my_call_id, "this_function", NULL) != &called) { - if (name && strncmp(name, "sys_", 4) == 0) + if (strncmp(name, "sys_", 4) == 0) is_syscall = 1; } - if (name && strncmp(name, "compat_sys_", 11) == 0) + if (strncmp(name, "compat_sys_", 11) == 0) + is_syscall = 1; + + /* Check whether function heuristically matchs hypercalls */ + if (ends_with(name, "_op") && ( + strncmp(name, "do_", 3) == 0 || strncmp(name, "arch_", 5) || strncmp(name, "hvm_", 4) + )) + is_syscall = 1; + else if (strncmp(name, "do_", 3) == 0 && ends_with(name, "_op_compat")) + is_syscall = 1; + else if (strncmp(name, "hvm_", 4) == 0 && ends_with(name, "_op_compat32")) is_syscall = 1; + /* Check against today's list of hypervalls */ + for (i = 0; i < ARRAY_SIZE(xen_hypercalls); i++) + if(strncmp(xen_hypercalls[i], "hvm_", sizeof(xen_hypercalls[i]))) + is_syscall = 1; + if (!is_syscall) return; From 1cf90ad336a2ae1381ca683337e56a5713fd4a9e Mon Sep 17 00:00:00 2001 From: Norbert Manthey Date: Thu, 2 Aug 2018 14:56:15 +0200 Subject: [PATCH 06/16] user_data: match Xen copy_from_guest Add functions that access guest data, and teach smatch about the parameter that points to the user data. As there are multiple flavors, try to be exhaustive. Signed-off-by: Norbert Manthey --- smatch_kernel_user_data.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/smatch_kernel_user_data.c b/smatch_kernel_user_data.c index 2b5740c2..134bc690 100644 --- a/smatch_kernel_user_data.c +++ b/smatch_kernel_user_data.c @@ -48,6 +48,15 @@ static const char *returns_user_data[] = { "kvm_register_read", }; +/* In Xen, these functions are called "copy_from_guest" */ +static const char * xen_from_guest_funcs[] = { +"copy_from_guest", "__copy_from_guest", "copy_from_guest_offset", +"copy_from_user_hvm", "__raw_copy_from_guest", "__copy_from_user", +"__hvm_copy", "hvm_copy_from_guest_phys", "hvm_copy_from_guest_virt", +"hvm_fetch_from_guest_virt", "hvm_copy_from_guest_virt_nofault", +"hvm_fetch_from_guest_virt_nofault", +}; + static struct stree *start_states; static void save_start_states(struct statement *stmt) { @@ -1389,6 +1398,11 @@ void register_kernel_user_data(int id) add_function_hook("copy_from_user", &match_user_copy, INT_PTR(0)); add_function_hook("__copy_from_user", &match_user_copy, INT_PTR(0)); add_function_hook("memcpy_fromiovec", &match_user_copy, INT_PTR(0)); + + /* In Xen, these functions are called "copy_from_guest" */ + for (i = 0; i < ARRAY_SIZE(xen_from_guest_funcs); i++) + add_function_hook(xen_from_guest_funcs[i], &match_user_copy, INT_PTR(0)); + for (i = 0; i < ARRAY_SIZE(kstr_funcs); i++) add_function_hook_late(kstr_funcs[i], &match_user_copy, INT_PTR(2)); add_function_hook("usb_control_msg", &match_user_copy, INT_PTR(6)); From 8635f35d50762469c9459074b042e64fbba02215 Mon Sep 17 00:00:00 2001 From: Norbert Manthey Date: Thu, 2 Aug 2018 14:57:01 +0200 Subject: [PATCH 07/16] user_data: add register read function Signed-off-by: Norbert Manthey --- smatch_kernel_user_data.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/smatch_kernel_user_data.c b/smatch_kernel_user_data.c index 134bc690..8340a5aa 100644 --- a/smatch_kernel_user_data.c +++ b/smatch_kernel_user_data.c @@ -1403,6 +1403,9 @@ void register_kernel_user_data(int id) for (i = 0; i < ARRAY_SIZE(xen_from_guest_funcs); i++) add_function_hook(xen_from_guest_funcs[i], &match_user_copy, INT_PTR(0)); + /* Xen equivalent to kvm_register_read */ + add_function_assign_hook("acpi_hw_register_read", &match_user_copy, NULL); + for (i = 0; i < ARRAY_SIZE(kstr_funcs); i++) add_function_hook_late(kstr_funcs[i], &match_user_copy, INT_PTR(2)); add_function_hook("usb_control_msg", &match_user_copy, INT_PTR(6)); From 50eb0f440b2be107be136d8ca3cc8950a7da8383 Mon Sep 17 00:00:00 2001 From: Norbert Manthey Date: Thu, 16 Aug 2018 14:47:30 +0200 Subject: [PATCH 08/16] user data: hypercalls have user arguments The second argument of hypercalls is user controlled. Hence, register these functions as source of user data. Signed-off-by: Norbert Manthey --- smatch_kernel_user_data.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/smatch_kernel_user_data.c b/smatch_kernel_user_data.c index 8340a5aa..2652744c 100644 --- a/smatch_kernel_user_data.c +++ b/smatch_kernel_user_data.c @@ -57,6 +57,17 @@ static const char * xen_from_guest_funcs[] = { "hvm_fetch_from_guest_virt_nofault", }; +// in Xen, these functions have user data in their first argument +static const char * xen_hypercalls[] = { +"hvm_memory_op_compat32", "hvm_grant_table_op_compat32", "hvm_vcpu_op_compat32", +"hvm_physdev_op_compat32", "do_event_channel_op", "do_xen_version", +"compat_xen_version", "do_sched_op", "compat_sched_op", +"do_set_timer_op", "compat_set_timer_op", "do_hvm_op", "do_sysctl_op", +"do_tmem_op", "hvm_physdev_op", "hvm_vcpu_op", "hvm_grant_table_op", +"hvm_memory_op", "do_domctl", "arch_do_domctl", "do_sysctl", "arch_do_sysctl", +"do_multicall" +}; + static struct stree *start_states; static void save_start_states(struct statement *stmt) { @@ -1403,6 +1414,10 @@ void register_kernel_user_data(int id) for (i = 0; i < ARRAY_SIZE(xen_from_guest_funcs); i++) add_function_hook(xen_from_guest_funcs[i], &match_user_copy, INT_PTR(0)); + /* Extra functions where we know tainted data is passed */ + for (i = 0; i < ARRAY_SIZE(xen_hypercalls); i++) + add_function_hook(xen_hypercalls[i], &match_user_copy, INT_PTR(1)); + /* Xen equivalent to kvm_register_read */ add_function_assign_hook("acpi_hw_register_read", &match_user_copy, NULL); From 6e67bd91b21912f38e77926996e7d8acd3b0b2d4 Mon Sep 17 00:00:00 2001 From: Norbert Manthey Date: Thu, 16 Aug 2018 14:48:14 +0200 Subject: [PATCH 09/16] user data: add functions for emulation During instruction emulation, data from the guest context is brought into the hypervisor context in several ways. Teach smatch about these functions, so that the data can be tracked. Signed-off-by: Norbert Manthey --- smatch_kernel_user_data.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/smatch_kernel_user_data.c b/smatch_kernel_user_data.c index 2652744c..876d0cd5 100644 --- a/smatch_kernel_user_data.c +++ b/smatch_kernel_user_data.c @@ -1414,6 +1414,13 @@ void register_kernel_user_data(int id) for (i = 0; i < ARRAY_SIZE(xen_from_guest_funcs); i++) add_function_hook(xen_from_guest_funcs[i], &match_user_copy, INT_PTR(0)); + /* Xen hvm read functions */ + add_function_hook("hvmemul_do_mmio", &match_user_copy, INT_PTR(5)); + add_function_hook("hvmemul_do_direct_read", &match_user_copy, INT_PTR(4)); + add_function_hook("hvmemul_do_io", &match_user_copy, INT_PTR(8)); + add_function_hook("hvmemul_read_cr", &match_user_copy, INT_PTR(2)); + add_function_hook("hvm_msr_read_intercept", &match_user_copy, INT_PTR(2)); + /* Extra functions where we know tainted data is passed */ for (i = 0; i < ARRAY_SIZE(xen_hypercalls); i++) add_function_hook(xen_hypercalls[i], &match_user_copy, INT_PTR(1)); From f047931a17a2afbdbeaf5bc24a5d9b8552644ecd Mon Sep 17 00:00:00 2001 From: Norbert Manthey Date: Thu, 16 Aug 2018 14:49:35 +0200 Subject: [PATCH 10/16] user data: hvm guest registers During emulation, we might read from user registers. As those are controlled by the guest, also track them during taint analysis. Signed-off-by: Norbert Manthey --- smatch_kernel_user_data.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/smatch_kernel_user_data.c b/smatch_kernel_user_data.c index 876d0cd5..818f575f 100644 --- a/smatch_kernel_user_data.c +++ b/smatch_kernel_user_data.c @@ -45,7 +45,10 @@ static const char *kstr_funcs[] = { static const char *returns_user_data[] = { "simple_strtol", "simple_strtoll", "simple_strtoul", "simple_strtoull", - "kvm_register_read", + "kvm_register_read", "nlmsg_data", "nla_data", "memdup_user", + "kmap_atomic", "skb_network_header", + /* Xen */ + "hvmemul_get_seg_reg", "guest_cpu_user_regs", }; /* In Xen, these functions are called "copy_from_guest" */ From 6a5ba818299cdb7f3b860013f6bf60e91bcaaa2c Mon Sep 17 00:00:00 2001 From: Norbert Manthey Date: Fri, 3 Aug 2018 12:56:59 +0200 Subject: [PATCH 11/16] guest: use copy_from_guest consistently Make sure we use the copy_from_guest function everywhere we use copy_from_user, to get the same filtering functionality. Signed-off-by: Norbert Manthey --- check_memcpy_overflow.c | 6 ++++++ check_return_efault.c | 14 +++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/check_memcpy_overflow.c b/check_memcpy_overflow.c index dddc555a..bccb28d0 100644 --- a/check_memcpy_overflow.c +++ b/check_memcpy_overflow.c @@ -368,5 +368,11 @@ void check_memcpy_overflow(int id) add_function_hook("copy_from_user", &match_limited, &b0_l2); add_function_hook("_copy_from_user", &match_limited, &b0_l2); add_function_hook("__copy_from_user", &match_limited, &b0_l2); + add_function_hook("copy_from_guest", &match_limited, &b0_l2); + add_function_hook("_copy_from_guest", &match_limited, &b0_l2); + add_function_hook("__copy_from_guest", &match_limited, &b0_l2); + add_function_hook("copy_to_guest", &match_limited, &b0_l2); + add_function_hook("_copy_to_guest", &match_limited, &b0_l2); + add_function_hook("__copy_to_guest", &match_limited, &b0_l2); } } diff --git a/check_return_efault.c b/check_return_efault.c index b8ba52bc..4ffb3144 100644 --- a/check_return_efault.c +++ b/check_return_efault.c @@ -95,6 +95,10 @@ static void match_return_call(struct expression *ret_value) strstr(cur_func, "_from_user")) return; + if (strstr(cur_func, "_to_guest") || + strstr(cur_func, "_from_guest")) + return; + if (strncmp(cur_func, "copy_from_", 10) == 0 || strncmp(cur_func, "copy_to_", 8) == 0) return; @@ -106,7 +110,11 @@ static void match_return_call(struct expression *ret_value) if (strcmp(fn_name, "copy_to_user") != 0 && strcmp(fn_name, "__copy_to_user") != 0 && strcmp(fn_name, "copy_from_user") != 0 && - strcmp(fn_name, "__copy_from_user")) + strcmp(fn_name, "__copy_from_user") != 0 && + strcmp(fn_name, "copy_to_guest") != 0 && + strcmp(fn_name, "__copy_to_guest") != 0 && + strcmp(fn_name, "copy_from_guest") != 0 && + strcmp(fn_name, "__copy_from_guest") != 0) return; rl = db_return_vals_from_str(get_function()); @@ -128,6 +136,10 @@ void check_return_efault(int id) add_function_assign_hook("__copy_to_user", &match_copy, NULL); add_function_assign_hook("copy_from_user", &match_copy, NULL); add_function_assign_hook("__copy_from_user", &match_copy, NULL); + add_function_assign_hook("copy_from_guest", &match_copy, NULL); + add_function_assign_hook("__copy_from_guest", &match_copy, NULL); + add_function_assign_hook("copy_to_guest", &match_copy, NULL); + add_function_assign_hook("__copy_to_guest", &match_copy, NULL); add_function_assign_hook("clear_user", &match_copy, NULL); add_hook(&match_condition, CONDITION_HOOK); add_hook(&match_return_var, RETURN_HOOK); From 68a1539c6d431b650156c86db9476b2856ea9e77 Mon Sep 17 00:00:00 2001 From: Norbert Manthey Date: Thu, 2 Aug 2018 15:29:11 +0200 Subject: [PATCH 12/16] test_xen: add script to build xen Similarly to the kernel, add a script that analyzes Xen. This script uses one-line-scan to wrap smatch in the build process. The script is taken from the test_kernel script. Different version of Xen might be built with different compilers. Therefore, we allow to specify the environment variable SMATCH_ONE_LINE_SCAN_ARSG, which can be used to forward command line parameters to one-line-scan, for example compiler prefix or suffix. Signed-off-by: Norbert Manthey Signed-off-by: Dan Carpenter --- smatch_scripts/test_xen.sh | 76 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100755 smatch_scripts/test_xen.sh diff --git a/smatch_scripts/test_xen.sh b/smatch_scripts/test_xen.sh new file mode 100755 index 00000000..9fa11608 --- /dev/null +++ b/smatch_scripts/test_xen.sh @@ -0,0 +1,76 @@ +#!/bin/bash + +NR_CPU=$(cat /proc/cpuinfo | grep ^processor | wc -l) +WLOG="smatch_warns.txt" +LOG="smatch_compile.warns" + +function usage +{ + echo + echo "Usage: $0 [smatch options]" + echo "Compiles the xen with -j${NR_CPU}" + echo " available options:" + echo " --endian : enable endianess check" + echo " --log {FILE} : Output compile log to file, default is: $LOG" + echo " --wlog {FILE} : Output warnigs to file, default is: $WLOG" + echo " --help : Show this usage" + exit 1 +} + +while true; do + if [[ "$1" == "--endian" ]]; then + ENDIAN="CF=-D__CHECK_ENDIAN__" + shift + elif [[ "$1" == "--log" ]]; then + shift + LOG="$1" + shift + elif [[ "$1" == "--wlog" ]]; then + shift + WLOG="$1" + shift + elif [[ "$1" == "--help" ]]; then + usage + else + break + fi +done + +SCRIPT_DIR=$(dirname $0) +if [ -e $SCRIPT_DIR/../smatch ]; then + cp $SCRIPT_DIR/../smatch $SCRIPT_DIR/../bak.smatch + CMD=$SCRIPT_DIR/../bak.smatch +elif which smatch | grep smatch >/dev/null; then + CMD=smatch +else + echo "Smatch binary not found." + exit 1 +fi + +if ! command -v one-line-scan &>/dev/null; then + echo "one-line-scan binary not found." + exit 1 +fi + +# start fresh, remote .smatch files +make clean -C xen -j $NR_CPU +find -name \*.c.smatch -exec rm \{\} \; +rm -rf SMATCH + +# tell where the data base file resides +touch smatch/smatch_db.sqlite +export SMATCH_DB=$(readlink -e smatch/smatch_db.sqlite) + +# set kernel, file-output, and everything else passed to this script to smatch +export SMATCH_EXTRA_ARG="-p=kernel --file-output $*" + +# compile xen with one-line-scan +one-line-scan -o SMATCH --use-existing --smatch --no-gotocc --no-analysis \ + ${SMATCH_ONE_LINE_SCAN_ARSG:-} \ + -- make xen -j $NR_CPU -B | tee $LOG + +find -name \*.c.smatch -exec cat \{\} \; -exec rm \{\} \; >$WLOG +find -name \*.c.smatch.sql -exec cat \{\} \; -exec rm \{\} \; >$WLOG.sql +find -name \*.c.smatch.caller_info -exec cat \{\} \; -exec rm \{\} \; >$WLOG.caller_info + +echo "Done. The warnings are saved to $WLOG" From 596c5d6726ac535157b5e84d89f1b3c23fc3562b Mon Sep 17 00:00:00 2001 From: Norbert Manthey Date: Thu, 2 Aug 2018 15:31:44 +0200 Subject: [PATCH 13/16] build_xen_data: add full script for Xen This script is taken from the script for the kernel. The project name is kept as "kernel", as this project name enables many analysis techniques in smatch. The major difference is that the test_xen.sh script is called, instead of the test_kernel.sh script. Signed-off-by: Norbert Manthey Signed-off-by: Dan Carpenter --- smatch_scripts/build_xen_data.sh | 47 ++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100755 smatch_scripts/build_xen_data.sh diff --git a/smatch_scripts/build_xen_data.sh b/smatch_scripts/build_xen_data.sh new file mode 100755 index 00000000..f39cdc63 --- /dev/null +++ b/smatch_scripts/build_xen_data.sh @@ -0,0 +1,47 @@ +#!/bin/bash + +PROJECT=kernel + +function usage +{ + echo + echo "Usage: $0" + echo "Updates the smatch_data/ directory and builds the smatch database" + echo + exit 1 +} + +if [ "$1" = "-h" ] || [ "$1" = "--help" ]; then + usage +fi + +SCRIPT_DIR=$(dirname $0) +if [ -e $SCRIPT_DIR/../smatch -a -d xen ]; then + CMD=$SCRIPT_DIR/../smatch + DATA_DIR=$(readlink -e $SCRIPT_DIR/../smatch_data) +else + echo "This script should be located in the smatch_scripts/ subdirectory of the smatch source." + echo "It should be run from the root of a kernel source tree." + exit 1 +fi + +# If someone is building the database for the first time then make sure all the +# required packages are installed +if [ ! -e smatch_db.sqlite ]; then + [ -e smatch_warns.txt ] || touch smatch_warns.txt + if ! $DATA_DIR/db/create_db.sh -p=kernel smatch_warns.txt; then + echo "Hm... Not working. Make sure you have all the sqlite3 packages" + echo "And the sqlite3 libraries for Perl and Python" + exit 1 + fi +fi + +$SCRIPT_DIR/test_xen.sh --full-path --call-tree --info --spammy --data=$DATA_DIR + +for i in $SCRIPT_DIR/gen_*; do + $i smatch_warns.txt -p=kernel +done + +mv ${PROJECT}.* $DATA_DIR + +$DATA_DIR/db/create_db.sh -p=kernel smatch_warns.txt From f09b44f5ce675a2af82f14264dadecf62de89a98 Mon Sep 17 00:00:00 2001 From: Norbert Manthey Date: Tue, 16 Oct 2018 14:35:42 +0200 Subject: [PATCH 14/16] test: add copy_from_guest Similarly to copy_from_user, we want to make sure that smatch keeps the copy_from_guest feature working in the future. Signed-off-by: Norbert Manthey --- validation/sm_guest_data1.c | 30 +++++++++++++++++++++++++ validation/sm_guest_data2.c | 32 ++++++++++++++++++++++++++ validation/sm_guest_data3.c | 35 +++++++++++++++++++++++++++++ validation/sm_guest_data4.c | 45 +++++++++++++++++++++++++++++++++++++ 4 files changed, 142 insertions(+) create mode 100644 validation/sm_guest_data1.c create mode 100644 validation/sm_guest_data2.c create mode 100644 validation/sm_guest_data3.c create mode 100644 validation/sm_guest_data4.c diff --git a/validation/sm_guest_data1.c b/validation/sm_guest_data1.c new file mode 100644 index 00000000..0528c970 --- /dev/null +++ b/validation/sm_guest_data1.c @@ -0,0 +1,30 @@ +#include "check_debug.h" + +int copy_from_guest(void *dest, void *src, int size); + +struct my_struct { + int x, y; +}; + +void *pointer; + +void copy_stuff(struct my_struct *foo) +{ + copy_from_guest(foo, pointer, sizeof(*foo)); +} + +void test(void) +{ + struct my_struct foo; + + copy_stuff(&foo); + __smatch_user_rl(foo.x); +} +/* + * check-name: smatch user data #1 + * check-command: smatch -p=kernel -I.. sm_user_data1.c + * + * check-output-start +sm_user_data1.c:21 test() user rl: 'foo.x' = 's32min-s32max' + * check-output-end + */ diff --git a/validation/sm_guest_data2.c b/validation/sm_guest_data2.c new file mode 100644 index 00000000..5bf845d1 --- /dev/null +++ b/validation/sm_guest_data2.c @@ -0,0 +1,32 @@ +#include "check_debug.h" + +int copy_from_guest(void *dest, void *src, int size){} + +struct my_struct { + int x, y; +}; + +void *pointer; +struct my_struct *dest; + +struct my_struct *returns_copy(void) +{ + copy_from_guest(dest, pointer, sizeof(*dest)); + return dest; +} + +struct my_struct *a; +void test(void) +{ + a = returns_copy(); + __smatch_user_rl(a->x); +} + +/* + * check-name: smatch user data #2 + * check-command: smatch -p=kernel -I.. sm_user_data2.c + * + * check-output-start +sm_user_data2.c:22 test() user rl: 'a->x' = 's32min-s32max' + * check-output-end + */ diff --git a/validation/sm_guest_data3.c b/validation/sm_guest_data3.c new file mode 100644 index 00000000..f5b80f61 --- /dev/null +++ b/validation/sm_guest_data3.c @@ -0,0 +1,35 @@ +#include "check_debug.h" + +int copy_from_guest(void *dest, void *src, int size){} + +struct my_struct { + int x, y; +}; + +struct my_struct *returns_filter(struct my_struct *p) +{ + return p; +} + +struct my_struct *src, *a, *b; +void test(void) +{ + copy_from_guest(a, src, sizeof(*a)); + b = returns_filter(a); + __smatch_user_rl(b->y); + b = returns_filter(src); + __smatch_user_rl(b->y); + b = returns_filter(a); + __smatch_user_rl(b->y); +} + +/* + * check-name: smatch user data #3 + * check-command: smatch -p=kernel -I.. sm_user_data3.c + * + * check-output-start +sm_user_data3.c:19 test() user rl: 'b->y' = 's32min-s32max' +sm_user_data3.c:21 test() user rl: 'b->y' = '' +sm_user_data3.c:23 test() user rl: 'b->y' = 's32min-s32max' + * check-output-end + */ diff --git a/validation/sm_guest_data4.c b/validation/sm_guest_data4.c new file mode 100644 index 00000000..91ad6d11 --- /dev/null +++ b/validation/sm_guest_data4.c @@ -0,0 +1,45 @@ +#include "check_debug.h" + +int copy_from_guest(void *dest, void *src, int size); + +struct ear { + int x, y; +}; + +void *src; +int returns_user_data(void) +{ + int x; + + copy_from_guest(&x, src, sizeof(int)); + return x; +} + +struct ear *dest; +struct ear *returns_user_member(void) +{ + copy_from_guest(&dest->x, src, sizeof(int)); + return dest; +} +void test(void) +{ + struct ear *p; + int x; + + x = returns_user_data(); + __smatch_user_rl(x); + p = returns_user_member(); + __smatch_user_rl(p); + __smatch_user_rl(p->x); +} + +/* + * check-name: smatch user data #4 + * check-command: smatch -p=kernel -I.. sm_user_data4.c + * + * check-output-start +sm_user_data4.c:30 test() user rl: 'x' = 's32min-s32max' +sm_user_data4.c:32 test() user rl: 'p' = '' +sm_user_data4.c:33 test() user rl: 'p->x' = 's32min-s32max' + * check-output-end + */ From 47e73a4b6c992e55c86f3ea867339f1fa1c3d067 Mon Sep 17 00:00:00 2001 From: Norbert Manthey Date: Tue, 25 Sep 2018 10:44:58 +0200 Subject: [PATCH 15/16] linux: parameterize make command For special kernel builds, we are interested in parameterizing the build command, e.g. to specify different values for CC or HOSTCC. To allow this, adapt the script to consume such a variable. Signed-off-by: Norbert Manthey --- smatch_scripts/test_kernel.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/smatch_scripts/test_kernel.sh b/smatch_scripts/test_kernel.sh index d254c56a..4480716a 100755 --- a/smatch_scripts/test_kernel.sh +++ b/smatch_scripts/test_kernel.sh @@ -66,7 +66,7 @@ fi make $KERNEL_ARCH $KERNEL_CROSS_COMPILE clean find -name \*.c.smatch -exec rm \{\} \; make $KERNEL_ARCH $KERNEL_CROSS_COMPILE -j${NR_CPU} $ENDIAN -k CHECK="$CMD -p=kernel --file-output --succeed $*" \ - C=1 $BUILD_PARAM $TARGET 2>&1 | tee $LOG + C=1 $BUILD_PARAM $TARGET $SMATCH_MAKE_PARAMS 2>&1 | tee $LOG BUILD_STATUS=${PIPESTATUS[0]} find -name \*.c.smatch -exec cat \{\} \; -exec rm \{\} \; > $WLOG find -name \*.c.smatch.sql -exec cat \{\} \; -exec rm \{\} \; > $WLOG.sql From d96ebcc4bbc858df57f95f1517302d03f9d36365 Mon Sep 17 00:00:00 2001 From: Norbert Manthey Date: Thu, 25 Mar 2021 10:52:00 +0100 Subject: [PATCH 16/16] scripts: add xen script This script can be used to detect all candidates for speculative leak gadgets. This script only takes care of building the hypervisor with the smatch tool support. As long as new defect candidates are detected, the script will continue. Furthermore, an upper bound is set to stop the detection at some point. Note, smatch is tracking state locally, and miproves its results when being executed multiple times in a row. To detect newly introduced defects, this tool should be used on the old change and the new change, so that the differences in the output can be compared. Due to the time based behavior of smatch, there might be differences in the output that are not caused by code changes. Signed-off-by: Norbert Manthey --- .../xen/detect-xen-spectre-candidates.sh | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100755 smatch_scripts/xen/detect-xen-spectre-candidates.sh diff --git a/smatch_scripts/xen/detect-xen-spectre-candidates.sh b/smatch_scripts/xen/detect-xen-spectre-candidates.sh new file mode 100755 index 00000000..2286994c --- /dev/null +++ b/smatch_scripts/xen/detect-xen-spectre-candidates.sh @@ -0,0 +1,74 @@ +#!/bin/bash + +# Copyright (C) 2018 Amazon.com, Inc. or its affiliates. +# Author: Norbert Manthey +# +# This script show cases how smatch can be run for Xen. +# You want to run this on a big machine, as Xen will be recompiled many times +# This script writes a file last_smatch_spectre_warns.txt, which will contain +# the spectre v1 candidates of smatch. +# +# Keep this script in its directory, but call it from the Xen root directory! + +# Number of smatch iterations (guest taint improves per iteration) +MAX_ITERATIONS=8 + +# In case something breaks, we want to stop +set -e -u + +# Where is this script located +SCRIPT=$(readlink -e "$0") +SCRIPT_DIR=$(dirname "$SCRIPT") + +# Make sure we're in the Xen directory and Xen builds +echo "Check whether Xen builds ..." +make xen -j $(nproc) + +if [ ! -d one-line-scan ]; then + echo "Make one-line-scan tool available ..." + git clone https://github.com/awslabs/one-line-scan.git +fi + +# Tell environment about tools, and check whether they work +export PATH=$PATH:$(pwd)/smatch:$(pwd)/one-line-scan +echo "Test availability of smatch and one-line-scan ..." +for tool in smatch one-line-scan; do + if ! command -v "$tool" &>/dev/null; then + echo "Cannot find tool $tool, abort" + exit 1 + fi +done +echo "Found all required tools, continue." + +# Initialize variables for analysis +START=$SECONDS # start timestampe to print timing +OLD=0 # number of defects found in last iteration +NEW=0 # number of defects found in current iteration +I=0 # current iteration +BUILD_STATUS=0 # status of the analysis job + +# Repeat analysis at most $MAX_ITERATIONS times +echo "Start Xen analysis with smatch, use $MAX_ITERATIONS iterations" +while [ "$I" -lt $MAX_ITERATIONS ]; do + OLD=$NEW + I=$((I + 1)) + # Write a log per iteration + FULL_SPECTRE=1 ./smatch/smatch_scripts/build_xen_data.sh &>smatch-build-$I.log + BUILD_STATUS=$? + echo "build iteration $I with status $BUILD_STATUS" + [ "$BUILD_STATUS" -eq 0 ] || exit $BUILD_STATUS + + # Keep results of last iteration around, in case the script is stopped early + grep spectre smatch_warns.txt | sort -u >last_smatch_spectre_warns.txt + + # We are only interested in spectre issues for now + NEW=$(cat last_smatch_spectre_warns.txt | wc -l) + NOW=$SECONDS + echo "new amount of defects: $NEW (last: $OLD) at iter $I after $((NOW - START))" + + # Check whether we found more defects + [ "$NEW" -ne "$OLD" ] || break + +done |& tee full-smatch.log + +exit $BUILD_STATUS