When using the RCU mechanism and deferring memory reclamation, potential use-after-free due to incorrect use of RCU can be hidden.
Add a test triggering a UAF event. When the test suite is built with AddressSanitizer support, verify that the event triggers and the tool is usable with RCU. Signed-off-by: Gaetan Rivet <[email protected]> --- tests/automake.mk | 1 + tests/library.at | 33 +++++++++++++++ tests/test-rcu-uaf.c | 98 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 132 insertions(+) create mode 100644 tests/test-rcu-uaf.c diff --git a/tests/automake.mk b/tests/automake.mk index a32abd41c..4420a3f7f 100644 --- a/tests/automake.mk +++ b/tests/automake.mk @@ -472,6 +472,7 @@ tests_ovstest_SOURCES = \ tests/test-packets.c \ tests/test-random.c \ tests/test-rcu.c \ + tests/test-rcu-uaf.c \ tests/test-reconnect.c \ tests/test-rstp.c \ tests/test-sflow.c \ diff --git a/tests/library.at b/tests/library.at index 6e8a154e5..4a549f77e 100644 --- a/tests/library.at +++ b/tests/library.at @@ -261,6 +261,39 @@ AT_KEYWORDS([rcu]) AT_CHECK([ovstest test-rcu], [0], []) AT_CLEANUP +AT_SETUP([rcu quiesce use-after-free detection]) +AT_SKIP_IF([test "$IS_WIN32" = "yes"]) +AT_SKIP_IF([test "$ASAN_ENABLED" = "no"]) +# SIGABRT + 128 +exit_status=134 +AT_KEYWORDS([rcu asan]) +AT_CHECK([ovstest test-rcu-uaf quiesce], [$exit_status], [ignore], [ignore]) +# ASAN report is expected on success. +rm asan.* +AT_CLEANUP + +AT_SETUP([rcu try-quiesce use-after-free detection]) +AT_SKIP_IF([test "$IS_WIN32" = "yes"]) +AT_SKIP_IF([test "$ASAN_ENABLED" = "no"]) +# SIGABRT + 128 +exit_status=134 +AT_KEYWORDS([rcu asan]) +AT_CHECK([ovstest test-rcu-uaf try-quiesce], [$exit_status], [ignore], [ignore]) +# ASAN report is expected on success. +rm asan.* +AT_CLEANUP + +AT_SETUP([rcu quiesce-start-end use-after-free detection]) +AT_SKIP_IF([test "$IS_WIN32" = "yes"]) +AT_SKIP_IF([test "$ASAN_ENABLED" = "no"]) +AT_KEYWORDS([rcu asan]) +# SIGABRT + 128 +exit_status=134 +AT_CHECK([ovstest test-rcu-uaf quiesce-start-end], [$exit_status], [ignore], [ignore]) +# ASAN report is expected on success. +rm asan.* +AT_CLEANUP + AT_SETUP([stopwatch module]) AT_CHECK([ovstest test-stopwatch], [0], [...... ], [ignore]) diff --git a/tests/test-rcu-uaf.c b/tests/test-rcu-uaf.c new file mode 100644 index 000000000..f97738795 --- /dev/null +++ b/tests/test-rcu-uaf.c @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2021 NVIDIA Corporation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <getopt.h> + +#include <config.h> + +#include "ovs-thread.h" +#include "ovs-rcu.h" +#include "ovstest.h" +#include "util.h" + +enum ovsrcu_uaf_type { + OVSRCU_UAF_QUIESCE, + OVSRCU_UAF_TRY_QUIESCE, + OVSRCU_UAF_QUIESCE_START_END, +}; + +static void * +rcu_uaf_main(void *aux) +{ + enum ovsrcu_uaf_type *type = aux; + char *xx = xmalloc(2); + + xx[0] = 'a'; + ovsrcu_postpone(free, xx); + switch (*type) { + case OVSRCU_UAF_QUIESCE: + ovsrcu_quiesce(); + break; + case OVSRCU_UAF_TRY_QUIESCE: + while (ovsrcu_try_quiesce()) { + ; + } + break; + case OVSRCU_UAF_QUIESCE_START_END: + ovsrcu_quiesce_start(); + ovsrcu_quiesce_end(); + break; + default: + OVS_NOT_REACHED(); + } + xx[1] = 'b'; + + return NULL; +} + +static void +usage(char *test_name) +{ + fprintf(stderr, "Usage: %s <quiesce|try-quiesce|quiesce-start-end>\n", + test_name); +} + +static void +test_rcu_uaf(int argc, char *argv[]) +{ + char **args = argv + optind - 1; + enum ovsrcu_uaf_type type; + pthread_t quiescer; + + if (argc - optind != 1) { + usage(args[0]); + return; + } + + set_program_name(argv[0]); + + if (!strcmp(args[1], "quiesce")) { + type = OVSRCU_UAF_QUIESCE; + } else if (!strcmp(args[1], "try-quiesce")) { + type = OVSRCU_UAF_TRY_QUIESCE; + } else if (!strcmp(args[1], "quiesce-start-end")) { + type = OVSRCU_UAF_QUIESCE_START_END; + } else { + usage(args[0]); + return; + } + + /* Need to create a separate thread, to support try-quiesce. */ + quiescer = ovs_thread_create("rcu-uaf", rcu_uaf_main, &type); + xpthread_join(quiescer, NULL); +} + +OVSTEST_REGISTER("test-rcu-uaf", test_rcu_uaf); -- 2.31.1 _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
