diff options
Diffstat (limited to 'lib/test_kasan.c')
| -rw-r--r-- | lib/test_kasan.c | 62 | 
1 files changed, 35 insertions, 27 deletions
diff --git a/lib/test_kasan.c b/lib/test_kasan.c index e5647d147b35..dc05cfc2d12f 100644 --- a/lib/test_kasan.c +++ b/lib/test_kasan.c @@ -54,6 +54,10 @@ static int kasan_test_init(struct kunit *test)  	multishot = kasan_save_enable_multi_shot();  	kasan_set_tagging_report_once(false); +	fail_data.report_found = false; +	fail_data.report_expected = false; +	kunit_add_named_resource(test, NULL, NULL, &resource, +					"kasan_data", &fail_data);  	return 0;  } @@ -61,6 +65,7 @@ static void kasan_test_exit(struct kunit *test)  {  	kasan_set_tagging_report_once(true);  	kasan_restore_multi_shot(multishot); +	KUNIT_EXPECT_FALSE(test, fail_data.report_found);  }  /** @@ -69,37 +74,40 @@ static void kasan_test_exit(struct kunit *test)   * resource named "kasan_data". Do not use this name for KUnit resources   * outside of KASAN tests.   * - * For hardware tag-based KASAN, when a tag fault happens, tag checking is - * normally auto-disabled. When this happens, this test handler reenables - * tag checking. As tag checking can be only disabled or enabled per CPU, this - * handler disables migration (preemption). + * For hardware tag-based KASAN in sync mode, when a tag fault happens, tag + * checking is auto-disabled. When this happens, this test handler reenables + * tag checking. As tag checking can be only disabled or enabled per CPU, + * this handler disables migration (preemption).   *   * Since the compiler doesn't see that the expression can change the fail_data   * fields, it can reorder or optimize away the accesses to those fields.   * Use READ/WRITE_ONCE() for the accesses and compiler barriers around the   * expression to prevent that. + * + * In between KUNIT_EXPECT_KASAN_FAIL checks, fail_data.report_found is kept as + * false. This allows detecting KASAN reports that happen outside of the checks + * by asserting !fail_data.report_found at the start of KUNIT_EXPECT_KASAN_FAIL + * and in kasan_test_exit.   */ -#define KUNIT_EXPECT_KASAN_FAIL(test, expression) do {		\ -	if (IS_ENABLED(CONFIG_KASAN_HW_TAGS))			\ -		migrate_disable();				\ -	WRITE_ONCE(fail_data.report_expected, true);		\ -	WRITE_ONCE(fail_data.report_found, false);		\ -	kunit_add_named_resource(test,				\ -				NULL,				\ -				NULL,				\ -				&resource,			\ -				"kasan_data", &fail_data);	\ -	barrier();						\ -	expression;						\ -	barrier();						\ -	KUNIT_EXPECT_EQ(test,					\ -			READ_ONCE(fail_data.report_expected),	\ -			READ_ONCE(fail_data.report_found));	\ -	if (IS_ENABLED(CONFIG_KASAN_HW_TAGS)) {			\ -		if (READ_ONCE(fail_data.report_found))		\ -			kasan_enable_tagging();			\ -		migrate_enable();				\ -	}							\ +#define KUNIT_EXPECT_KASAN_FAIL(test, expression) do {			\ +	if (IS_ENABLED(CONFIG_KASAN_HW_TAGS) &&				\ +	    !kasan_async_mode_enabled())				\ +		migrate_disable();					\ +	KUNIT_EXPECT_FALSE(test, READ_ONCE(fail_data.report_found));	\ +	WRITE_ONCE(fail_data.report_expected, true);			\ +	barrier();							\ +	expression;							\ +	barrier();							\ +	KUNIT_EXPECT_EQ(test,						\ +			READ_ONCE(fail_data.report_expected),		\ +			READ_ONCE(fail_data.report_found));		\ +	if (IS_ENABLED(CONFIG_KASAN_HW_TAGS)) {				\ +		if (READ_ONCE(fail_data.report_found))			\ +			kasan_enable_tagging_sync();			\ +		migrate_enable();					\ +	}								\ +	WRITE_ONCE(fail_data.report_found, false);			\ +	WRITE_ONCE(fail_data.report_expected, false);			\  } while (0)  #define KASAN_TEST_NEEDS_CONFIG_ON(test, config) do {			\ @@ -1044,14 +1052,14 @@ static void match_all_mem_tag(struct kunit *test)  			continue;  		/* Mark the first memory granule with the chosen memory tag. */ -		kasan_poison(ptr, KASAN_GRANULE_SIZE, (u8)tag); +		kasan_poison(ptr, KASAN_GRANULE_SIZE, (u8)tag, false);  		/* This access must cause a KASAN report. */  		KUNIT_EXPECT_KASAN_FAIL(test, *ptr = 0);  	}  	/* Recover the memory tag and free. */ -	kasan_poison(ptr, KASAN_GRANULE_SIZE, get_tag(ptr)); +	kasan_poison(ptr, KASAN_GRANULE_SIZE, get_tag(ptr), false);  	kfree(ptr);  }  |