Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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.*" \
Expand Down
6 changes: 6 additions & 0 deletions check_memcpy_overflow.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
14 changes: 13 additions & 1 deletion check_return_efault.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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());
Expand All @@ -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);
Expand Down
20 changes: 15 additions & 5 deletions check_spectre.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion cwchash/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
2 changes: 1 addition & 1 deletion smatch_flow.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
4 changes: 2 additions & 2 deletions smatch_implied.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
92 changes: 88 additions & 4 deletions smatch_kernel_user_data.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,30 @@ 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" */
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",
};

// 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;
Expand Down Expand Up @@ -1157,12 +1180,34 @@ 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;
char *macro;
char *name;
int is_syscall = 0;
int is_syscall = 0, i;

macro = get_macro_name(sym->pos);
if (macro &&
Expand All @@ -1171,14 +1216,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;

Expand Down Expand Up @@ -1347,6 +1412,25 @@ 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));

/* 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));

/* 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));
Expand Down
4 changes: 2 additions & 2 deletions smatch_math.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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)
Expand Down
47 changes: 47 additions & 0 deletions smatch_scripts/build_xen_data.sh
Original file line number Diff line number Diff line change
@@ -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
2 changes: 1 addition & 1 deletion smatch_scripts/test_kernel.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading