lkml.org 
[lkml]   [2020]   [Aug]   [31]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH kcsan 08/19] kcsan: Test support for compound instrumentation
    Date
    From: Marco Elver <elver@google.com>

    Changes kcsan-test module to support checking reports that include
    compound instrumentation. Since we should not fail the test if this
    support is unavailable, we have to add a config variable that the test
    can use to decide what to check for.

    Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
    Signed-off-by: Marco Elver <elver@google.com>
    Signed-off-by: Paul E. McKenney <paulmck@kernel.org>
    ---
    kernel/kcsan/kcsan-test.c | 65 +++++++++++++++++++++++++++++++++++++----------
    lib/Kconfig.kcsan | 5 ++++
    2 files changed, 56 insertions(+), 14 deletions(-)

    diff --git a/kernel/kcsan/kcsan-test.c b/kernel/kcsan/kcsan-test.c
    index 721180c..ebe7fd2 100644
    --- a/kernel/kcsan/kcsan-test.c
    +++ b/kernel/kcsan/kcsan-test.c
    @@ -27,6 +27,12 @@
    #include <linux/types.h>
    #include <trace/events/printk.h>

    +#ifdef CONFIG_CC_HAS_TSAN_COMPOUND_READ_BEFORE_WRITE
    +#define __KCSAN_ACCESS_RW(alt) (KCSAN_ACCESS_COMPOUND | KCSAN_ACCESS_WRITE)
    +#else
    +#define __KCSAN_ACCESS_RW(alt) (alt)
    +#endif
    +
    /* Points to current test-case memory access "kernels". */
    static void (*access_kernels[2])(void);

    @@ -186,20 +192,21 @@ static bool report_matches(const struct expect_report *r)

    /* Access 1 & 2 */
    for (i = 0; i < 2; ++i) {
    + const int ty = r->access[i].type;
    const char *const access_type =
    - (r->access[i].type & KCSAN_ACCESS_ASSERT) ?
    - ((r->access[i].type & KCSAN_ACCESS_WRITE) ?
    - "assert no accesses" :
    - "assert no writes") :
    - ((r->access[i].type & KCSAN_ACCESS_WRITE) ?
    - "write" :
    - "read");
    + (ty & KCSAN_ACCESS_ASSERT) ?
    + ((ty & KCSAN_ACCESS_WRITE) ?
    + "assert no accesses" :
    + "assert no writes") :
    + ((ty & KCSAN_ACCESS_WRITE) ?
    + ((ty & KCSAN_ACCESS_COMPOUND) ?
    + "read-write" :
    + "write") :
    + "read");
    const char *const access_type_aux =
    - (r->access[i].type & KCSAN_ACCESS_ATOMIC) ?
    - " (marked)" :
    - ((r->access[i].type & KCSAN_ACCESS_SCOPED) ?
    - " (scoped)" :
    - "");
    + (ty & KCSAN_ACCESS_ATOMIC) ?
    + " (marked)" :
    + ((ty & KCSAN_ACCESS_SCOPED) ? " (scoped)" : "");

    if (i == 1) {
    /* Access 2 */
    @@ -277,6 +284,12 @@ static noinline void test_kernel_write_atomic(void)
    WRITE_ONCE(test_var, READ_ONCE_NOCHECK(test_sink) + 1);
    }

    +static noinline void test_kernel_atomic_rmw(void)
    +{
    + /* Use builtin, so we can set up the "bad" atomic/non-atomic scenario. */
    + __atomic_fetch_add(&test_var, 1, __ATOMIC_RELAXED);
    +}
    +
    __no_kcsan
    static noinline void test_kernel_write_uninstrumented(void) { test_var++; }

    @@ -439,8 +452,8 @@ static void test_concurrent_races(struct kunit *test)
    const struct expect_report expect = {
    .access = {
    /* NULL will match any address. */
    - { test_kernel_rmw_array, NULL, 0, KCSAN_ACCESS_WRITE },
    - { test_kernel_rmw_array, NULL, 0, 0 },
    + { test_kernel_rmw_array, NULL, 0, __KCSAN_ACCESS_RW(KCSAN_ACCESS_WRITE) },
    + { test_kernel_rmw_array, NULL, 0, __KCSAN_ACCESS_RW(0) },
    },
    };
    static const struct expect_report never = {
    @@ -629,6 +642,29 @@ static void test_read_plain_atomic_write(struct kunit *test)
    KUNIT_EXPECT_TRUE(test, match_expect);
    }

    +/* Test that atomic RMWs generate correct report. */
    +__no_kcsan
    +static void test_read_plain_atomic_rmw(struct kunit *test)
    +{
    + const struct expect_report expect = {
    + .access = {
    + { test_kernel_read, &test_var, sizeof(test_var), 0 },
    + { test_kernel_atomic_rmw, &test_var, sizeof(test_var),
    + KCSAN_ACCESS_COMPOUND | KCSAN_ACCESS_WRITE | KCSAN_ACCESS_ATOMIC },
    + },
    + };
    + bool match_expect = false;
    +
    + if (IS_ENABLED(CONFIG_KCSAN_IGNORE_ATOMICS))
    + return;
    +
    + begin_test_checks(test_kernel_read, test_kernel_atomic_rmw);
    + do {
    + match_expect = report_matches(&expect);
    + } while (!end_test_checks(match_expect));
    + KUNIT_EXPECT_TRUE(test, match_expect);
    +}
    +
    /* Zero-sized accesses should never cause data race reports. */
    __no_kcsan
    static void test_zero_size_access(struct kunit *test)
    @@ -942,6 +978,7 @@ static struct kunit_case kcsan_test_cases[] = {
    KCSAN_KUNIT_CASE(test_write_write_struct_part),
    KCSAN_KUNIT_CASE(test_read_atomic_write_atomic),
    KCSAN_KUNIT_CASE(test_read_plain_atomic_write),
    + KCSAN_KUNIT_CASE(test_read_plain_atomic_rmw),
    KCSAN_KUNIT_CASE(test_zero_size_access),
    KCSAN_KUNIT_CASE(test_data_race),
    KCSAN_KUNIT_CASE(test_assert_exclusive_writer),
    diff --git a/lib/Kconfig.kcsan b/lib/Kconfig.kcsan
    index 3d282d5..f271ff5 100644
    --- a/lib/Kconfig.kcsan
    +++ b/lib/Kconfig.kcsan
    @@ -40,6 +40,11 @@ menuconfig KCSAN

    if KCSAN

    +# Compiler capabilities that should not fail the test if they are unavailable.
    +config CC_HAS_TSAN_COMPOUND_READ_BEFORE_WRITE
    + def_bool (CC_IS_CLANG && $(cc-option,-fsanitize=thread -mllvm -tsan-compound-read-before-write=1)) || \
    + (CC_IS_GCC && $(cc-option,-fsanitize=thread --param tsan-compound-read-before-write=1))
    +
    config KCSAN_VERBOSE
    bool "Show verbose reports with more information about system state"
    depends on PROVE_LOCKING
    --
    2.9.5
    \
     
     \ /
      Last update: 2020-08-31 20:19    [W:4.098 / U:0.144 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site