From patchwork Wed Sep 13 12:25:15 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Luis Gerhorst X-Patchwork-Id: 722826 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 8984AEDEC4A for ; Wed, 13 Sep 2023 12:26:57 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240415AbjIMM1B (ORCPT ); Wed, 13 Sep 2023 08:27:01 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35310 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240320AbjIMM1A (ORCPT ); Wed, 13 Sep 2023 08:27:00 -0400 Received: from smtp-fw-6002.amazon.com (smtp-fw-6002.amazon.com [52.95.49.90]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 6298019AC; Wed, 13 Sep 2023 05:26:56 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amazon.de; i=@amazon.de; q=dns/txt; s=amazon201209; t=1694608017; x=1726144017; h=from:to:cc:subject:date:message-id:in-reply-to: references:reply-to:mime-version: content-transfer-encoding; bh=N31oCUU7CHkmI4vyS7k5OHuBwDNqQwrdeueOu92um7M=; b=ZDQA5bMnR1OzmVVyqQQv3X9SwULIjvfA//mLcN5pIf51AuOXefg3TM9P BZFq7GBRO5DfTY1D5baDzMuEdIbseRoJdZ19o017wnhVJWfMzKK6GNOoY fcgbJqvwnZRB0ueLEVtxOm8olPu7aTeEc8yCky6fYmrfF2VsYKWXecM5O k=; X-IronPort-AV: E=Sophos;i="6.02,143,1688428800"; d="scan'208";a="356058087" Received: from iad12-co-svc-p1-lb1-vlan3.amazon.com (HELO email-inbound-relay-iad-1a-m6i4x-96feee09.us-east-1.amazon.com) ([10.43.8.6]) by smtp-border-fw-6002.iad6.amazon.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 13 Sep 2023 12:26:54 +0000 Received: from EX19D017EUA004.ant.amazon.com (iad12-ws-svc-p26-lb9-vlan2.iad.amazon.com [10.40.163.34]) by email-inbound-relay-iad-1a-m6i4x-96feee09.us-east-1.amazon.com (Postfix) with ESMTPS id 4CF2C47E7A; Wed, 13 Sep 2023 12:26:49 +0000 (UTC) Received: from dev-dsk-gerhorst-1c-a6f23d20.eu-west-1.amazon.com (10.15.21.113) by EX19D017EUA004.ant.amazon.com (10.252.50.239) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1118.37; Wed, 13 Sep 2023 12:26:42 +0000 From: Luis Gerhorst To: CC: , , , , , , , , , , , , , , , , , , , Luis Gerhorst Subject: [PATCH 1/3] Revert "selftests/bpf: Add selftest for allow_ptr_leaks" Date: Wed, 13 Sep 2023 12:25:15 +0000 Message-ID: <20230913122514.89078-1-gerhorst@amazon.de> X-Mailer: git-send-email 2.40.1 In-Reply-To: References: Reply-To: MIME-Version: 1.0 X-Originating-IP: [10.15.21.113] X-ClientProxiedBy: EX19D040UWA002.ant.amazon.com (10.13.139.113) To EX19D017EUA004.ant.amazon.com (10.252.50.239) Precedence: bulk List-ID: X-Mailing-List: linux-kselftest@vger.kernel.org This reverts commit 0072e3624b463636c842ad8e261f1dc91deb8c78. The test tests behavior which can not be permitted because of Spectre v1. See the following commit Revert "bpf: Fix issue in verifying allow_ptr_leaks" which reverts commit d75e30dddf73449bc2d10bb8e2f1a2c446bc67a2 for a detailed description of the issue. Reported-by: Daniel Borkmann Signed-off-by: Luis Gerhorst Signed-off-by: Luis Gerhorst --- .../testing/selftests/bpf/prog_tests/tc_bpf.c | 36 +------------------ .../testing/selftests/bpf/progs/test_tc_bpf.c | 13 ------- 2 files changed, 1 insertion(+), 48 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/tc_bpf.c b/tools/testing/selftests/bpf/prog_tests/tc_bpf.c index 48b55539331e..e873766276d1 100644 --- a/tools/testing/selftests/bpf/prog_tests/tc_bpf.c +++ b/tools/testing/selftests/bpf/prog_tests/tc_bpf.c @@ -3,7 +3,6 @@ #include #include -#include "cap_helpers.h" #include "test_tc_bpf.skel.h" #define LO_IFINDEX 1 @@ -328,7 +327,7 @@ static int test_tc_bpf_api(struct bpf_tc_hook *hook, int fd) return 0; } -void tc_bpf_root(void) +void test_tc_bpf(void) { DECLARE_LIBBPF_OPTS(bpf_tc_hook, hook, .ifindex = LO_IFINDEX, .attach_point = BPF_TC_INGRESS); @@ -394,36 +393,3 @@ void tc_bpf_root(void) } test_tc_bpf__destroy(skel); } - -void tc_bpf_non_root(void) -{ - struct test_tc_bpf *skel = NULL; - __u64 caps = 0; - int ret; - - /* In case CAP_BPF and CAP_PERFMON is not set */ - ret = cap_enable_effective(1ULL << CAP_BPF | 1ULL << CAP_NET_ADMIN, &caps); - if (!ASSERT_OK(ret, "set_cap_bpf_cap_net_admin")) - return; - ret = cap_disable_effective(1ULL << CAP_SYS_ADMIN | 1ULL << CAP_PERFMON, NULL); - if (!ASSERT_OK(ret, "disable_cap_sys_admin")) - goto restore_cap; - - skel = test_tc_bpf__open_and_load(); - if (!ASSERT_OK_PTR(skel, "test_tc_bpf__open_and_load")) - goto restore_cap; - - test_tc_bpf__destroy(skel); - -restore_cap: - if (caps) - cap_enable_effective(caps, NULL); -} - -void test_tc_bpf(void) -{ - if (test__start_subtest("tc_bpf_root")) - tc_bpf_root(); - if (test__start_subtest("tc_bpf_non_root")) - tc_bpf_non_root(); -} diff --git a/tools/testing/selftests/bpf/progs/test_tc_bpf.c b/tools/testing/selftests/bpf/progs/test_tc_bpf.c index ef7da419632a..d28ca8d1f3d0 100644 --- a/tools/testing/selftests/bpf/progs/test_tc_bpf.c +++ b/tools/testing/selftests/bpf/progs/test_tc_bpf.c @@ -2,8 +2,6 @@ #include #include -#include -#include /* Dummy prog to test TC-BPF API */ @@ -12,14 +10,3 @@ int cls(struct __sk_buff *skb) { return 0; } - -/* Prog to verify tc-bpf without cap_sys_admin and cap_perfmon */ -SEC("tcx/ingress") -int pkt_ptr(struct __sk_buff *skb) -{ - struct iphdr *iph = (void *)(long)skb->data + sizeof(struct ethhdr); - - if ((long)(iph + 1) > (long)skb->data_end) - return 1; - return 0; -} From patchwork Wed Sep 13 12:28:28 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Luis Gerhorst X-Patchwork-Id: 722394 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 8E0BAEDEC4A for ; Wed, 13 Sep 2023 12:30:06 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240320AbjIMMaJ (ORCPT ); Wed, 13 Sep 2023 08:30:09 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38772 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240193AbjIMMaJ (ORCPT ); Wed, 13 Sep 2023 08:30:09 -0400 Received: from smtp-fw-9106.amazon.com (smtp-fw-9106.amazon.com [207.171.188.206]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id DC8F719AC; Wed, 13 Sep 2023 05:30:04 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amazon.de; i=@amazon.de; q=dns/txt; s=amazon201209; t=1694608205; x=1726144205; h=from:to:cc:subject:date:message-id:in-reply-to: references:reply-to:mime-version: content-transfer-encoding; bh=KwurXCQbHNZPBAhNsuzjlPwfomO/Yw3Mf9C+fqRMat8=; b=p+05Sm3Z30+cAAvptk0/c/lGOLFH34mbCEyWJwW4TTI8DpzBsRZJa5ZX lm5KxYhvLdMAajrAY6Z3sQYp+DhBd6rTJwuR4hENDtKYbpIE6l7AKWF8n eL8olpgR5Y9j7M9MlZyyBVhXoqY7aay64scMxK7Z0nr9coabTRjA30qBP U=; X-IronPort-AV: E=Sophos;i="6.02,143,1688428800"; d="scan'208";a="671219876" Received: from pdx4-co-svc-p1-lb2-vlan2.amazon.com (HELO email-inbound-relay-iad-1a-m6i4x-54a853e6.us-east-1.amazon.com) ([10.25.36.210]) by smtp-border-fw-9106.sea19.amazon.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 13 Sep 2023 12:29:56 +0000 Received: from EX19D017EUA004.ant.amazon.com (iad12-ws-svc-p26-lb9-vlan3.iad.amazon.com [10.40.163.38]) by email-inbound-relay-iad-1a-m6i4x-54a853e6.us-east-1.amazon.com (Postfix) with ESMTPS id 48BC047EC2; Wed, 13 Sep 2023 12:29:49 +0000 (UTC) Received: from dev-dsk-gerhorst-1c-a6f23d20.eu-west-1.amazon.com (10.15.21.113) by EX19D017EUA004.ant.amazon.com (10.252.50.239) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1118.37; Wed, 13 Sep 2023 12:29:42 +0000 From: Luis Gerhorst To: CC: , , , , , , , , , , , , , , , , , , , Luis Gerhorst , Hagar Gamal Halim Hemdan , Puranjay Mohan Subject: [PATCH 2/3] Revert "bpf: Fix issue in verifying allow_ptr_leaks" Date: Wed, 13 Sep 2023 12:28:28 +0000 Message-ID: <20230913122827.91591-1-gerhorst@amazon.de> X-Mailer: git-send-email 2.40.1 In-Reply-To: References: Reply-To: MIME-Version: 1.0 X-Originating-IP: [10.15.21.113] X-ClientProxiedBy: EX19D037UWC004.ant.amazon.com (10.13.139.254) To EX19D017EUA004.ant.amazon.com (10.252.50.239) Precedence: bulk List-ID: X-Mailing-List: linux-kselftest@vger.kernel.org This reverts commit d75e30dddf73449bc2d10bb8e2f1a2c446bc67a2. To mitigate Spectre v1, the verifier relies on static analysis to deduct constant pointer bounds, which can then be enforced by rewriting pointer arithmetic [1] or index masking [2]. This relies on the fact that every memory region to be accessed has a static upper bound and every date below that bound is accessible. The verifier can only rewrite pointer arithmetic or insert masking instructions to mitigate Spectre v1 if a static upper bound, below of which every access is valid, can be given. When allowing packet pointer comparisons, this introduces a way for the program to effectively construct an accessible pointer for which no static upper bound is known. Intuitively, this is obvious as a packet might be of any size and therefore 0 is the only statically known upper bound below of which every date is always accessible (i.e., none). To clarify, the problem is not that comparing two pointers can be used for pointer leaks in the same way in that comparing a pointer to a known scalar can be used for pointer leaks. That is because the "secret" components of the addresses cancel each other out if the pointers are into the same region. With [3] applied, the following malicious BPF program can be loaded into the kernel without CAP_PERFMON: r2 = *(u32 *)(r1 + 76) // data r3 = *(u32 *)(r1 + 80) // data_end r4 = r2 r4 += 1 if r4 > r3 goto exit r5 = *(u8 *)(r2 + 0) // speculatively read secret r5 &= 1 // choose bit to leak // ... side channel to leak secret bit exit: // ... This is jited to the following amd64 code which still contains the gadget: 0: endbr64 4: nopl 0x0(%rax,%rax,1) 9: xchg %ax,%ax b: push %rbp c: mov %rsp,%rbp f: endbr64 13: push %rbx 14: mov 0xc8(%rdi),%rsi // data 1b: mov 0x50(%rdi),%rdx // data_end 1f: mov %rsi,%rcx 22: add $0x1,%rcx 26: cmp %rdx,%rcx 29: ja 0x000000000000003f // branch to mispredict 2b: movzbq 0x0(%rsi),%r8 // speculative load of secret 30: and $0x1,%r8 // choose bit to leak 34: xor %ebx,%ebx 36: cmp %rbx,%r8 39: je 0x000000000000003f // branch based on secret 3b: imul $0x61,%r8,%r8 // leak using port contention side channel 3f: xor %eax,%eax 41: pop %rbx 42: leaveq 43: retq Here I'm using a port contention side channel because storing the secret to the stack causes the verifier to insert an lfence for unrelated reasons (SSB mitigation) which would terminate the speculation. As Daniel already pointed out to me, data_end is even attacker controlled as one could send many packets of sufficient length to train the branch prediction into assuming data_end >= data will never be true. When the attacker then sends a packet with insufficient data, the Spectre v1 gadget leaks the chosen bit of some value that lies behind data_end. To make it clear that the problem is not the pointer comparison but the missing masking instruction, it can be useful to transform the code above into the following equivalent pseudocode: r2 = data r3 = data_end r6 = ... // index to access, constant does not help r7 = data_end - data // only known at runtime, could be [0,PKT_MAX) if !(r6 < r7) goto exit // no masking of index in r6 happens r2 += r6 // addr. to access r5 = *(u8 *)(r2 + 0) // speculatively read secret // ... leak secret as above One idea to resolve this while still allowing for unprivileged packet access would be to always allocate a power of 2 for the packet data and then also pass the respective index mask in the skb structure. The verifier would then have to check that this index mask is always applied to the offset before a packet pointer is dereferenced. This patch does not implement this extension, but only reverts [3]. [1] 979d63d50c0c0f7bc537bf821e056cc9fe5abd38 ("bpf: prevent out of bounds speculation on pointer arithmetic") [2] b2157399cc9898260d6031c5bfe45fe137c1fbe7 ("bpf: prevent out-of-bounds speculation") [3] d75e30dddf73449bc2d10bb8e2f1a2c446bc67a2 ("bpf: Fix issue in verifying allow_ptr_leaks") Reported-by: Daniel Borkmann Signed-off-by: Luis Gerhorst Signed-off-by: Luis Gerhorst Acked-by: Hagar Gamal Halim Hemdan Cc: Puranjay Mohan --- kernel/bpf/verifier.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index bb78212fa5b2..b415a81149ed 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -14050,12 +14050,6 @@ static int check_cond_jmp_op(struct bpf_verifier_env *env, return -EINVAL; } - /* check src2 operand */ - err = check_reg_arg(env, insn->dst_reg, SRC_OP); - if (err) - return err; - - dst_reg = ®s[insn->dst_reg]; if (BPF_SRC(insn->code) == BPF_X) { if (insn->imm != 0) { verbose(env, "BPF_JMP/JMP32 uses reserved fields\n"); @@ -14067,13 +14061,12 @@ static int check_cond_jmp_op(struct bpf_verifier_env *env, if (err) return err; - src_reg = ®s[insn->src_reg]; - if (!(reg_is_pkt_pointer_any(dst_reg) && reg_is_pkt_pointer_any(src_reg)) && - is_pointer_value(env, insn->src_reg)) { + if (is_pointer_value(env, insn->src_reg)) { verbose(env, "R%d pointer comparison prohibited\n", insn->src_reg); return -EACCES; } + src_reg = ®s[insn->src_reg]; } else { if (insn->src_reg != BPF_REG_0) { verbose(env, "BPF_JMP/JMP32 uses reserved fields\n"); @@ -14081,6 +14074,12 @@ static int check_cond_jmp_op(struct bpf_verifier_env *env, } } + /* check src2 operand */ + err = check_reg_arg(env, insn->dst_reg, SRC_OP); + if (err) + return err; + + dst_reg = ®s[insn->dst_reg]; is_jmp32 = BPF_CLASS(insn->code) == BPF_JMP32; if (BPF_SRC(insn->code) == BPF_K) { From patchwork Wed Sep 13 12:31:54 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Luis Gerhorst X-Patchwork-Id: 722825 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 B8501EDEC4A for ; Wed, 13 Sep 2023 12:32:40 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233192AbjIMMcn (ORCPT ); Wed, 13 Sep 2023 08:32:43 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46768 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240502AbjIMMcn (ORCPT ); Wed, 13 Sep 2023 08:32:43 -0400 Received: from smtp-fw-80007.amazon.com (smtp-fw-80007.amazon.com [99.78.197.218]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 09C7019A8; Wed, 13 Sep 2023 05:32:38 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amazon.de; i=@amazon.de; q=dns/txt; s=amazon201209; t=1694608359; x=1726144359; h=from:to:cc:subject:date:message-id:in-reply-to: references:reply-to:mime-version: content-transfer-encoding; bh=5oIhYdCJEkownT50F9w6XGgNq4kRwDe875Odq22n3v0=; b=rj9DLiQpKgT1eW9AVJHWZadTQRzs3rqrqJhPFd/kAA7Eu0hcCLMYsS6i UpqvIMr6zd729bhQfiMYwSjjydHmFZOrcZx9jNFx1lQE0iGnJB8xMFil3 DsE1bSFcf71Oj9s4SdjelPmg0+8hurhOKP1ct2Dp4ZEQWi3v+2KTxIadT s=; X-IronPort-AV: E=Sophos;i="6.02,143,1688428800"; d="scan'208";a="238776791" Received: from pdx4-co-svc-p1-lb2-vlan2.amazon.com (HELO email-inbound-relay-iad-1e-m6i4x-3e1fab07.us-east-1.amazon.com) ([10.25.36.210]) by smtp-border-fw-80007.pdx80.corp.amazon.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 13 Sep 2023 12:32:35 +0000 Received: from EX19D017EUA004.ant.amazon.com (iad12-ws-svc-p26-lb9-vlan3.iad.amazon.com [10.40.163.38]) by email-inbound-relay-iad-1e-m6i4x-3e1fab07.us-east-1.amazon.com (Postfix) with ESMTPS id 61788805E0; Wed, 13 Sep 2023 12:32:29 +0000 (UTC) Received: from dev-dsk-gerhorst-1c-a6f23d20.eu-west-1.amazon.com (10.15.21.113) by EX19D017EUA004.ant.amazon.com (10.252.50.239) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1118.37; Wed, 13 Sep 2023 12:32:22 +0000 From: Luis Gerhorst To: CC: , , , , , , , , , , , , , , , , , , , Luis Gerhorst Subject: [PATCH 3/3] selftests/bpf: Add selftest for packet-pointer Spectre v1 gadget Date: Wed, 13 Sep 2023 12:31:54 +0000 Message-ID: <20230913123154.94264-1-gerhorst@amazon.de> X-Mailer: git-send-email 2.40.1 In-Reply-To: References: Reply-To: MIME-Version: 1.0 X-Originating-IP: [10.15.21.113] X-ClientProxiedBy: EX19D035UWB003.ant.amazon.com (10.13.138.85) To EX19D017EUA004.ant.amazon.com (10.252.50.239) Precedence: bulk List-ID: X-Mailing-List: linux-kselftest@vger.kernel.org When allowing speculative leaks by enabling packet pointer accesses without CAP_PERFMON (i.e., without having [1] reverted): $ tools/testing/selftests/bpf/test_progs --name=tc_bpf tc_bpf_non_root:PASS:set_cap_bpf_cap_net_admin 0 nsec tc_bpf_non_root:PASS:disable_cap_sys_admin 0 nsec tc_bpf_non_root:FAIL:test_tc_bpf__open_and_load unexpected pointer: 0x55bbd81969a0 Summary: 0/1 PASSED, 0 SKIPPED, 1 FAILED With [1] reverted: $ tools/testing/selftests/bpf/test_progs --name=tc_bpf #238/1 tc_bpf/tc_bpf_root:OK #238/2 tc_bpf/tc_bpf_non_root:OK #238 tc_bpf:OK Summary: 1/2 PASSED, 0 SKIPPED, 0 FAILED [1] d75e30dddf73449bc2d10bb8e2f1a2c446bc67a2 ("bpf: Fix issue in verifying allow_ptr_leaks") Signed-off-by: Luis Gerhorst Signed-off-by: Luis Gerhorst Based-on-patch-by: Yafang Shao --- .../testing/selftests/bpf/prog_tests/tc_bpf.c | 37 +++++++- .../testing/selftests/bpf/progs/test_tc_bpf.c | 95 +++++++++++++++++++ 2 files changed, 131 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/bpf/prog_tests/tc_bpf.c b/tools/testing/selftests/bpf/prog_tests/tc_bpf.c index e873766276d1..5319cb94a0ae 100644 --- a/tools/testing/selftests/bpf/prog_tests/tc_bpf.c +++ b/tools/testing/selftests/bpf/prog_tests/tc_bpf.c @@ -3,6 +3,7 @@ #include #include +#include "cap_helpers.h" #include "test_tc_bpf.skel.h" #define LO_IFINDEX 1 @@ -327,7 +328,7 @@ static int test_tc_bpf_api(struct bpf_tc_hook *hook, int fd) return 0; } -void test_tc_bpf(void) +void tc_bpf_root(void) { DECLARE_LIBBPF_OPTS(bpf_tc_hook, hook, .ifindex = LO_IFINDEX, .attach_point = BPF_TC_INGRESS); @@ -393,3 +394,37 @@ void test_tc_bpf(void) } test_tc_bpf__destroy(skel); } + +void tc_bpf_non_root(void) +{ + struct test_tc_bpf *skel = NULL; + __u64 caps = 0; + int ret; + + /* In case CAP_BPF and CAP_PERFMON is not set */ + ret = cap_enable_effective(1ULL << CAP_BPF | 1ULL << CAP_NET_ADMIN, &caps); + if (!ASSERT_OK(ret, "set_cap_bpf_cap_net_admin")) + return; + ret = cap_disable_effective(1ULL << CAP_SYS_ADMIN | 1ULL << CAP_PERFMON, NULL); + if (!ASSERT_OK(ret, "disable_cap_sys_admin")) + goto restore_cap; + + skel = test_tc_bpf__open_and_load(); + if (!ASSERT_ERR_PTR(skel, "test_tc_bpf__open_and_load")) + goto destroy; + + goto restore_cap; +destroy: + test_tc_bpf__destroy(skel); +restore_cap: + if (caps) + cap_enable_effective(caps, NULL); +} + +void test_tc_bpf(void) +{ + if (test__start_subtest("tc_bpf_root")) + tc_bpf_root(); + if (test__start_subtest("tc_bpf_non_root")) + tc_bpf_non_root(); +} diff --git a/tools/testing/selftests/bpf/progs/test_tc_bpf.c b/tools/testing/selftests/bpf/progs/test_tc_bpf.c index d28ca8d1f3d0..3b3f9ce6b9d4 100644 --- a/tools/testing/selftests/bpf/progs/test_tc_bpf.c +++ b/tools/testing/selftests/bpf/progs/test_tc_bpf.c @@ -2,6 +2,8 @@ #include #include +#include +#include /* Dummy prog to test TC-BPF API */ @@ -10,3 +12,96 @@ int cls(struct __sk_buff *skb) { return 0; } + +/* Prog to verify tc-bpf without cap_sys_admin and cap_perfmon is rejected as + * required to prevent Spectre v1 using CPU multiplication port contention + * side-channel. This is not a full exploit but rather a PoC for x86_64. With + * extensions to the verifier's mitigations this may become obsolete. + * + * This should compile to the following bytecode if the kernel would allow + * unprivileged packet pointer accesses: + * + +0000000000000000 : + 0: b4 00 00 00 00 00 00 00 w0 = 0 + 1: 61 12 50 00 00 00 00 00 r2 = *(u32 *)(r1 + 80) + 2: 61 11 4c 00 00 00 00 00 r1 = *(u32 *)(r1 + 76) + 3: bf 13 00 00 00 00 00 00 r3 = r1 + 4: 07 03 00 00 22 00 00 00 r3 += 34 + 5: bd 23 07 00 00 00 00 00 if r3 <= r2 goto +7 + 6: 71 10 0e 00 00 00 00 00 r0 = *(u8 *)(r1 + 14) + 7: 64 00 00 00 18 00 00 00 w0 <<= 24 + 8: c4 00 00 00 18 00 00 00 w0 s>>= 24 + 9: bc 01 00 00 00 00 00 00 w1 = w0 + 10: 54 01 00 00 01 00 00 00 w1 &= 1 + 11: 16 01 01 00 00 00 00 00 if w1 == 0 goto +1 + 12: 24 00 00 00 61 00 00 00 w0 *= 97 + +0000000000000068 : + 13: 95 00 00 00 00 00 00 00 exit + + * + * Which should in turn translate to this x86_64 assembly with !allow_ptr_leaks + * and !bypass_spec_v1: + * + +int pkt_ptr(struct __sk_buff * skb): +bpf_prog_7c3834bad32f2b0f_pkt_ptr: +; int pkt_ptr(struct __sk_buff *skb) + 0: endbr64 + 4: nopl 0x0(%rax,%rax,1) + 9: xchg %ax,%ax + b: push %rbp + c: mov %rsp,%rbp + f: endbr64 + 13: xor %eax,%eax +; if ((long)(iph + 1) > (long)skb->data_end) + 15: mov 0x50(%rdi),%rsi +; struct iphdr *iph = (void *)(long)skb->data + sizeof(struct ethhdr); + 19: mov 0xc8(%rdi),%rdi +; if ((long)(iph + 1) > (long)skb->data_end) + 20: mov %rdi,%rdx + 23: add $0x22,%rdx +; if ((long)(iph + 1) > (long)skb->data_end) + 27: cmp %rsi,%rdx + 2a: ja 0x0000000000000043 +; char secret = *((char *) iph); + 2c: movzbq 0xe(%rdi),%rax + 31: shl $0x18,%eax + 34: sar $0x18,%eax +; if (secret & 1) { + 37: mov %eax,%edi + 39: and $0x1,%edi +; if (secret & 1) { + 3c: test %edi,%edi + 3e: je 0x0000000000000043 + 40: imul $0x61,%eax,%eax +; } + 43: leaveq + 44: retq + + * + */ +SEC("tcx/ingress") +int pkt_ptr(struct __sk_buff *skb) +{ + struct iphdr *iph = (void *)(long)skb->data + sizeof(struct ethhdr); + + /* Branch to be speculatively bypassed. */ + if ((long)(iph + 1) > (long)skb->data_end) + return 0; + + /* Speculative access to be prevented. */ + char secret = *((char *) iph); + + /* Leak the first bit of the secret value that lies behind data_end to a + * SMP silbling thread that also executes imul instructions. If the bit + * is 1, the silbling will experience a slowdown. */ + long long x = secret; + if (secret & 1) { + x *= 97; + } + + /* To prevent optimization. */ + return x; +}