From patchwork Sat Feb 5 01:33:42 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrii Nakryiko X-Patchwork-Id: 12735918 X-Patchwork-Delegate: bpf@iogearbox.net Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 0C3E3C433EF for ; Sat, 5 Feb 2022 01:33:57 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1349644AbiBEBd4 convert rfc822-to-8bit (ORCPT ); Fri, 4 Feb 2022 20:33:56 -0500 Received: from mx0a-00082601.pphosted.com ([67.231.145.42]:64808 "EHLO mx0a-00082601.pphosted.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1376402AbiBEBdz (ORCPT ); Fri, 4 Feb 2022 20:33:55 -0500 Received: from pps.filterd (m0109334.ppops.net [127.0.0.1]) by mx0a-00082601.pphosted.com (8.16.1.2/8.16.1.2) with ESMTP id 2150pV2M015508 for ; Fri, 4 Feb 2022 17:33:55 -0800 Received: from mail.thefacebook.com ([163.114.132.120]) by mx0a-00082601.pphosted.com (PPS) with ESMTPS id 3e0w2fxbp2-2 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128 verify=NOT) for ; Fri, 04 Feb 2022 17:33:55 -0800 Received: from twshared1259.42.prn1.facebook.com (2620:10d:c085:208::f) by mail.thefacebook.com (2620:10d:c085:21d::5) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2308.21; Fri, 4 Feb 2022 17:33:54 -0800 Received: by devbig019.vll3.facebook.com (Postfix, from userid 137359) id 3702E1051E260; Fri, 4 Feb 2022 17:33:51 -0800 (PST) From: Andrii Nakryiko To: , , CC: , , Alan Maguire Subject: [PATCH v2 bpf-next 3/3] selftests/bpf: add custom SEC() handling selftest Date: Fri, 4 Feb 2022 17:33:42 -0800 Message-ID: <20220205013342.1110746-4-andrii@kernel.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220205013342.1110746-1-andrii@kernel.org> References: <20220205013342.1110746-1-andrii@kernel.org> MIME-Version: 1.0 X-FB-Internal: Safe X-Proofpoint-GUID: 972MgPGgm22OfnUdNCV4cR61ew43CBXT X-Proofpoint-ORIG-GUID: 972MgPGgm22OfnUdNCV4cR61ew43CBXT X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.205,Aquarius:18.0.816,Hydra:6.0.425,FMLib:17.11.62.513 definitions=2022-02-04_07,2022-02-03_01,2021-12-02_01 X-Proofpoint-Spam-Details: rule=fb_outbound_notspam policy=fb_outbound score=0 lowpriorityscore=0 phishscore=0 adultscore=0 suspectscore=0 spamscore=0 mlxlogscore=999 impostorscore=0 mlxscore=0 priorityscore=1501 bulkscore=0 clxscore=1015 malwarescore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2201110000 definitions=main-2202050005 X-FB-Internal: deliver Precedence: bulk List-ID: X-Mailing-List: bpf@vger.kernel.org X-Patchwork-Delegate: bpf@iogearbox.net Add a selftest validating various aspects of libbpf's handling of custom SEC() handlers. It also demonstrates how libraries can ensure very early callbacks registration and unregistration using __attribute__((constructor))/__attribute__((destructor)) functions. Signed-off-by: Andrii Nakryiko --- .../bpf/prog_tests/custom_sec_handlers.c | 136 ++++++++++++++++++ .../bpf/progs/test_custom_sec_handlers.c | 51 +++++++ 2 files changed, 187 insertions(+) create mode 100644 tools/testing/selftests/bpf/prog_tests/custom_sec_handlers.c create mode 100644 tools/testing/selftests/bpf/progs/test_custom_sec_handlers.c diff --git a/tools/testing/selftests/bpf/prog_tests/custom_sec_handlers.c b/tools/testing/selftests/bpf/prog_tests/custom_sec_handlers.c new file mode 100644 index 000000000000..8e43c5f21878 --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/custom_sec_handlers.c @@ -0,0 +1,136 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2022 Facebook */ + +#include +#include "test_custom_sec_handlers.skel.h" + +#define COOKIE_ABC1 1 +#define COOKIE_ABC2 2 +#define COOKIE_CUSTOM 3 +#define COOKIE_FALLBACK 4 + +static int custom_init_prog(struct bpf_program *prog, long cookie) +{ + if (cookie == COOKIE_ABC1) + bpf_program__set_autoload(prog, false); + + return 0; +} + +static int custom_preload_prog(struct bpf_program *prog, + struct bpf_prog_load_opts *opts, long cookie) +{ + return 0; +} + +static int custom_attach_prog(const struct bpf_program *prog, long cookie, + struct bpf_link **link) +{ + switch (cookie) { + case COOKIE_ABC2: + *link = bpf_program__attach_raw_tracepoint(prog, "sys_enter"); + return libbpf_get_error(*link); + case COOKIE_CUSTOM: + *link = bpf_program__attach_tracepoint(prog, "syscalls", "sys_enter_nanosleep"); + return libbpf_get_error(*link); + case COOKIE_FALLBACK: + /* no auto-attach for SEC("xyz") */ + *link = NULL; + return 0; + default: + ASSERT_FALSE(true, "unexpected cookie"); + return -EINVAL; + } +} + +static int abc1_id; +static int abc2_id; +static int custom_id; +static int fallback_id; + +__attribute__((constructor)) +static void register_sec_handlers(void) +{ + abc1_id = libbpf_register_prog_handler("abc", + BPF_PROG_TYPE_RAW_TRACEPOINT, 0, + custom_init_prog, custom_preload_prog, + custom_attach_prog, + COOKIE_ABC1, NULL); + abc2_id = libbpf_register_prog_handler("abc/", + BPF_PROG_TYPE_RAW_TRACEPOINT, 0, + custom_init_prog, custom_preload_prog, + custom_attach_prog, + COOKIE_ABC2, NULL); + custom_id = libbpf_register_prog_handler("custom+", + BPF_PROG_TYPE_TRACEPOINT, 0, + custom_init_prog, custom_preload_prog, + custom_attach_prog, + COOKIE_CUSTOM, NULL); +} + +__attribute__((destructor)) +static void unregister_sec_handlers(void) +{ + libbpf_unregister_prog_handler(abc1_id); + libbpf_unregister_prog_handler(abc2_id); + libbpf_unregister_prog_handler(custom_id); +} + +void test_custom_sec_handlers(void) +{ + struct test_custom_sec_handlers* skel; + int err; + + ASSERT_GT(abc1_id, 0, "abc1_id"); + ASSERT_GT(abc2_id, 0, "abc2_id"); + ASSERT_GT(custom_id, 0, "custom_id"); + + fallback_id = libbpf_register_prog_handler(NULL, /* fallback handler */ + BPF_PROG_TYPE_KPROBE, 0, + custom_init_prog, custom_preload_prog, + custom_attach_prog, + COOKIE_FALLBACK, NULL); + if (!ASSERT_GT(fallback_id, 0, "fallback_id")) + return; + + /* open skeleton and validate assumptions */ + skel = test_custom_sec_handlers__open(); + if (!ASSERT_OK_PTR(skel, "skel_open")) + goto cleanup; + + ASSERT_EQ(bpf_program__type(skel->progs.abc1), BPF_PROG_TYPE_RAW_TRACEPOINT, "abc1_type"); + ASSERT_FALSE(bpf_program__autoload(skel->progs.abc1), "abc1_autoload"); + + ASSERT_EQ(bpf_program__type(skel->progs.abc2), BPF_PROG_TYPE_RAW_TRACEPOINT, "abc2_type"); + ASSERT_EQ(bpf_program__type(skel->progs.custom1), BPF_PROG_TYPE_TRACEPOINT, "custom1_type"); + ASSERT_EQ(bpf_program__type(skel->progs.custom2), BPF_PROG_TYPE_TRACEPOINT, "custom2_type"); + ASSERT_EQ(bpf_program__type(skel->progs.xyz), BPF_PROG_TYPE_KPROBE, "xyz_type"); + + skel->rodata->my_pid = getpid(); + + /* now attempt to load everything */ + err = test_custom_sec_handlers__load(skel); + if (!ASSERT_OK(err, "skel_load")) + goto cleanup; + + /* now try to auto-attach everything */ + err = test_custom_sec_handlers__attach(skel); + if (!ASSERT_OK(err, "skel_attach")) + goto cleanup; + + /* trigger programs */ + usleep(1); + + /* SEC("abc") is set to not auto-loaded */ + ASSERT_FALSE(skel->bss->abc1_called, "abc1_called"); + ASSERT_TRUE(skel->bss->abc2_called, "abc2_called"); + ASSERT_TRUE(skel->bss->custom1_called, "custom1_called"); + ASSERT_TRUE(skel->bss->custom2_called, "custom2_called"); + /* SEC("xyz") shouldn't be auto-attached */ + ASSERT_FALSE(skel->bss->xyz_called, "xyz_called"); + +cleanup: + test_custom_sec_handlers__destroy(skel); + + ASSERT_OK(libbpf_unregister_prog_handler(fallback_id), "unregister_fallback"); +} diff --git a/tools/testing/selftests/bpf/progs/test_custom_sec_handlers.c b/tools/testing/selftests/bpf/progs/test_custom_sec_handlers.c new file mode 100644 index 000000000000..2df368783678 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_custom_sec_handlers.c @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2022 Facebook */ + +#include "vmlinux.h" +#include +#include + +const volatile int my_pid; + +bool abc1_called; +bool abc2_called; +bool custom1_called; +bool custom2_called; +bool xyz_called; + +SEC("abc") +int abc1(void *ctx) +{ + abc1_called = true; + return 0; +} + +SEC("abc/whatever") +int abc2(void *ctx) +{ + abc2_called = true; + return 0; +} + +SEC("custom") +int custom1(void *ctx) +{ + custom1_called = true; + return 0; +} + +SEC("custom/something") +int custom2(void *ctx) +{ + custom2_called = true; + return 0; +} + +SEC("xyz/blah") +int xyz(void *ctx) +{ + xyz_called = true; + return 0; +} + +char _license[] SEC("license") = "GPL";