Received: by 2002:a05:6a10:413:0:0:0:0 with SMTP id 19csp3550887pxp; Tue, 8 Mar 2022 17:13:59 -0800 (PST) X-Google-Smtp-Source: ABdhPJxo/LQblYL8og4kSNhgWxPLMeYWpevjEKYMDBXWMnwnlN2VQUZI7i+LT7bnYBFgUMM9p1Ad X-Received: by 2002:a63:24c3:0:b0:37c:926d:daef with SMTP id k186-20020a6324c3000000b0037c926ddaefmr12216968pgk.280.1646788439096; Tue, 08 Mar 2022 17:13:59 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1646788439; cv=none; d=google.com; s=arc-20160816; b=GhzPmvcXib+/B1/qmJPpSLV3WNf9cmSewMWdXl5kEUXmWAovmmCcVg49IvCZeU8jY4 wuwkVjr6yrMHH+0AUfj2PbC+C5xx//Njmm0Vz/pQClNBHnBMY7wn1Ru23UySqSn24uKj DnfVJH442tbRMc8IbabwO1+TKtcm0yTlD0ujoN8z2iPvBnWb9MobuvdttwCnEwYHnJ6k jjI6HRmXkAjUeo9lz5/boD+ZK9iFvRMdBrbD9pw7WrmvV7Jys+VMuXWvCF0qvPNDIpL7 /x5LlaFQlOj8vfD70wRPQOKFt5Fy6zeTkNI4NE7wH+8wysXX6SYH3QgNj1R8od2lo+qG eglw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :user-agent:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=iXydDmJRiTvef/v2OUc8aOb0t/HBOoWZcwHNKurzwHQ=; b=tdfIEXvoLQUA1HuA6pYGGYTDZ35r/MaVZaxDp+Z14F9RKYOIiwxAsdVTJOWFDuxtoA RpI8Mt6e+xbtyR3tCFfOKquC9X3NCOh5EZTl76lvA3j8HVA/0qgcM7GccmE9V1O6vn/a xjmNOV67u0xFQ3/rd98+a6ufSNPIRSeDZxDwrBz4A4NTNgpL+cvme9YHezSHsuVSA+db 703xqPhcGun5pnaQsN6wmU4kpg/qh94R0SZoQKO6NdIZq4T8WhRgD0VmicXODxcE0wlR gcro5Y0Nbpa2yUK9sBWN/EuhHIw5PGM8coLPIuDKTkm8SJk+qdrLnS/TKgrU9lKj6my2 hpaQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=k20201202 header.b=KJdiVrA7; spf=softfail (google.com: domain of transitioning linux-kernel-owner@vger.kernel.org does not designate 23.128.96.19 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=kernel.org Return-Path: Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net. [23.128.96.19]) by mx.google.com with ESMTPS id s140-20020a632c92000000b0038081451114si440242pgs.47.2022.03.08.17.13.58 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 08 Mar 2022 17:13:59 -0800 (PST) Received-SPF: softfail (google.com: domain of transitioning linux-kernel-owner@vger.kernel.org does not designate 23.128.96.19 as permitted sender) client-ip=23.128.96.19; Authentication-Results: mx.google.com; dkim=pass header.i=@kernel.org header.s=k20201202 header.b=KJdiVrA7; spf=softfail (google.com: domain of transitioning linux-kernel-owner@vger.kernel.org does not designate 23.128.96.19 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=kernel.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 7D940B2393; Tue, 8 Mar 2022 16:10:24 -0800 (PST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1346351AbiCHLLz (ORCPT + 99 others); Tue, 8 Mar 2022 06:11:55 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51122 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1346350AbiCHLLx (ORCPT ); Tue, 8 Mar 2022 06:11:53 -0500 Received: from dfw.source.kernel.org (dfw.source.kernel.org [139.178.84.217]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5124946164; Tue, 8 Mar 2022 03:10:54 -0800 (PST) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dfw.source.kernel.org (Postfix) with ESMTPS id BD74461610; Tue, 8 Mar 2022 11:10:53 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 1FC7DC340EB; Tue, 8 Mar 2022 11:10:49 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1646737853; bh=33xTofm5tNJfVFvrdxFoHym3nFCdtF5+sqI7opLuv3M=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=KJdiVrA7Mqe36ZRoZERoqd3h/NxYvFBaLx0b53hKobKFtji4ZErxhGe7KjBwF5IMt PtOV2KwTZZpSQS6unB/5KOX/LU7xm+bbm5sobVEDhspTHtej4TEcZ3Hq9ke0dXjQ5T eKHxBEIpjX+iVziufdWai8rxjRfl7sOvl7JGraadQvsCjQTIfL4LkZtj7e/5T5ruDW 5HjCHAUWjIgChjNZAwFrkj3akmrsu/ioOBCAfMP3B7o0K6tIXwhwuwx8r6XTFfmJxy 1NAJcuUA702XU6rctbfoL5vMC4C8LHO24hV5DVKNFA0kDEm2Gl8EmTK9m8eqYcwl38 Nf1KefEMSjSSg== From: Masami Hiramatsu To: Jiri Olsa , Alexei Starovoitov Cc: Daniel Borkmann , Andrii Nakryiko , Masami Hiramatsu , netdev@vger.kernel.org, bpf@vger.kernel.org, lkml , Martin KaFai Lau , Song Liu , Yonghong Song , John Fastabend , KP Singh , Steven Rostedt , "Naveen N . Rao" , Anil S Keshavamurthy , "David S . Miller" Subject: [PATCH v10 12/12] fprobe: Add a selftest for fprobe Date: Tue, 8 Mar 2022 20:10:48 +0900 Message-Id: <164673784786.1984170.244480726272055433.stgit@devnote2> X-Mailer: git-send-email 2.25.1 In-Reply-To: <164673771096.1984170.8155877393151850116.stgit@devnote2> References: <164673771096.1984170.8155877393151850116.stgit@devnote2> User-Agent: StGit/0.19 MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-2.8 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,MAILING_LIST_MULTI, RDNS_NONE,SPF_HELO_NONE,T_SCC_BODY_TEXT_LINE autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Add a KUnit based selftest for fprobe interface. Signed-off-by: Masami Hiramatsu --- Changes in v9: - Rename fprobe_target* to fprobe_selftest_target*. - Find the correct expected ip by ftrace_location_range(). - Since the ftrace_location_range() is not exposed to module, make this test only for embedded. - Add entry only test. - Reset the fprobe structure before reuse it. --- lib/Kconfig.debug | 12 ++++ lib/Makefile | 2 + lib/test_fprobe.c | 174 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 188 insertions(+) create mode 100644 lib/test_fprobe.c diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 14b89aa37c5c..ffc469a12afc 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -2100,6 +2100,18 @@ config KPROBES_SANITY_TEST Say N if you are unsure. +config FPROBE_SANITY_TEST + bool "Self test for fprobe" + depends on DEBUG_KERNEL + depends on FPROBE + depends on KUNIT + help + This option will enable testing the fprobe when the system boot. + A series of tests are made to verify that the fprobe is functioning + properly. + + Say N if you are unsure. + config BACKTRACE_SELF_TEST tristate "Self test for the backtrace code" depends on DEBUG_KERNEL diff --git a/lib/Makefile b/lib/Makefile index 300f569c626b..154008764b16 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -103,6 +103,8 @@ obj-$(CONFIG_TEST_HMM) += test_hmm.o obj-$(CONFIG_TEST_FREE_PAGES) += test_free_pages.o obj-$(CONFIG_KPROBES_SANITY_TEST) += test_kprobes.o obj-$(CONFIG_TEST_REF_TRACKER) += test_ref_tracker.o +CFLAGS_test_fprobe.o += $(CC_FLAGS_FTRACE) +obj-$(CONFIG_FPROBE_SANITY_TEST) += test_fprobe.o # # CFLAGS for compiling floating point code inside the kernel. x86/Makefile turns # off the generation of FPU/SSE* instructions for kernel proper but FPU_FLAGS diff --git a/lib/test_fprobe.c b/lib/test_fprobe.c new file mode 100644 index 000000000000..ed70637a2ffa --- /dev/null +++ b/lib/test_fprobe.c @@ -0,0 +1,174 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * test_fprobe.c - simple sanity test for fprobe + */ + +#include +#include +#include +#include + +#define div_factor 3 + +static struct kunit *current_test; + +static u32 rand1, entry_val, exit_val; + +/* Use indirect calls to avoid inlining the target functions */ +static u32 (*target)(u32 value); +static u32 (*target2)(u32 value); +static unsigned long target_ip; +static unsigned long target2_ip; + +static noinline u32 fprobe_selftest_target(u32 value) +{ + return (value / div_factor); +} + +static noinline u32 fprobe_selftest_target2(u32 value) +{ + return (value / div_factor) + 1; +} + +static notrace void fp_entry_handler(struct fprobe *fp, unsigned long ip, struct pt_regs *regs) +{ + KUNIT_EXPECT_FALSE(current_test, preemptible()); + /* This can be called on the fprobe_selftest_target and the fprobe_selftest_target2 */ + if (ip != target_ip) + KUNIT_EXPECT_EQ(current_test, ip, target2_ip); + entry_val = (rand1 / div_factor); +} + +static notrace void fp_exit_handler(struct fprobe *fp, unsigned long ip, struct pt_regs *regs) +{ + unsigned long ret = regs_return_value(regs); + + KUNIT_EXPECT_FALSE(current_test, preemptible()); + if (ip != target_ip) { + KUNIT_EXPECT_EQ(current_test, ip, target2_ip); + KUNIT_EXPECT_EQ(current_test, ret, (rand1 / div_factor) + 1); + } else + KUNIT_EXPECT_EQ(current_test, ret, (rand1 / div_factor)); + KUNIT_EXPECT_EQ(current_test, entry_val, (rand1 / div_factor)); + exit_val = entry_val + div_factor; +} + +/* Test entry only (no rethook) */ +static void test_fprobe_entry(struct kunit *test) +{ + struct fprobe fp_entry = { + .entry_handler = fp_entry_handler, + }; + + current_test = test; + + /* Before register, unregister should be failed. */ + KUNIT_EXPECT_NE(test, 0, unregister_fprobe(&fp_entry)); + KUNIT_EXPECT_EQ(test, 0, register_fprobe(&fp_entry, "fprobe_selftest_target*", NULL)); + + entry_val = 0; + exit_val = 0; + target(rand1); + KUNIT_EXPECT_NE(test, 0, entry_val); + KUNIT_EXPECT_EQ(test, 0, exit_val); + + entry_val = 0; + exit_val = 0; + target2(rand1); + KUNIT_EXPECT_NE(test, 0, entry_val); + KUNIT_EXPECT_EQ(test, 0, exit_val); + + KUNIT_EXPECT_EQ(test, 0, unregister_fprobe(&fp_entry)); +} + +static void test_fprobe(struct kunit *test) +{ + struct fprobe fp = { + .entry_handler = fp_entry_handler, + .exit_handler = fp_exit_handler, + }; + + current_test = test; + KUNIT_EXPECT_EQ(test, 0, register_fprobe(&fp, "fprobe_selftest_target*", NULL)); + + entry_val = 0; + exit_val = 0; + target(rand1); + KUNIT_EXPECT_NE(test, 0, entry_val); + KUNIT_EXPECT_EQ(test, entry_val + div_factor, exit_val); + + entry_val = 0; + exit_val = 0; + target2(rand1); + KUNIT_EXPECT_NE(test, 0, entry_val); + KUNIT_EXPECT_EQ(test, entry_val + div_factor, exit_val); + + KUNIT_EXPECT_EQ(test, 0, unregister_fprobe(&fp)); +} + +static void test_fprobe_syms(struct kunit *test) +{ + static const char *syms[] = {"fprobe_selftest_target", "fprobe_selftest_target2"}; + struct fprobe fp = { + .entry_handler = fp_entry_handler, + .exit_handler = fp_exit_handler, + }; + + current_test = test; + KUNIT_EXPECT_EQ(test, 0, register_fprobe_syms(&fp, syms, 2)); + + entry_val = 0; + exit_val = 0; + target(rand1); + KUNIT_EXPECT_NE(test, 0, entry_val); + KUNIT_EXPECT_EQ(test, entry_val + div_factor, exit_val); + + entry_val = 0; + exit_val = 0; + target2(rand1); + KUNIT_EXPECT_NE(test, 0, entry_val); + KUNIT_EXPECT_EQ(test, entry_val + div_factor, exit_val); + + KUNIT_EXPECT_EQ(test, 0, unregister_fprobe(&fp)); +} + +static unsigned long get_ftrace_location(void *func) +{ + unsigned long size, addr = (unsigned long)func; + + if (!kallsyms_lookup_size_offset(addr, &size, NULL) || !size) + return 0; + + return ftrace_location_range(addr, addr + size - 1); +} + +static int fprobe_test_init(struct kunit *test) +{ + do { + rand1 = prandom_u32(); + } while (rand1 <= div_factor); + + target = fprobe_selftest_target; + target2 = fprobe_selftest_target2; + target_ip = get_ftrace_location(target); + target2_ip = get_ftrace_location(target2); + + return 0; +} + +static struct kunit_case fprobe_testcases[] = { + KUNIT_CASE(test_fprobe_entry), + KUNIT_CASE(test_fprobe), + KUNIT_CASE(test_fprobe_syms), + {} +}; + +static struct kunit_suite fprobe_test_suite = { + .name = "fprobe_test", + .init = fprobe_test_init, + .test_cases = fprobe_testcases, +}; + +kunit_test_suites(&fprobe_test_suite); + +MODULE_LICENSE("GPL");