Merge tag 'for-netdev' of git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf
authorDavid S. Miller <davem@davemloft.net>
Sat, 24 Dec 2022 09:39:02 +0000 (09:39 +0000)
committerDavid S. Miller <davem@davemloft.net>
Sat, 24 Dec 2022 09:39:02 +0000 (09:39 +0000)
Daniel Borkmann says:

====================
The following pull-request contains BPF updates for your *net* tree.

We've added 7 non-merge commits during the last 5 day(s) which contain
a total of 11 files changed, 231 insertions(+), 3 deletions(-).

The main changes are:

1) Fix a splat in bpf_skb_generic_pop() under CHECKSUM_PARTIAL due to
   misuse of skb_postpull_rcsum(), from Jakub Kicinski with test case
   from Martin Lau.

2) Fix BPF verifier's nullness propagation when registers are of
   type PTR_TO_BTF_ID, from Hao Sun.

3) Fix bpftool build for JIT disassembler under statically built
   libllvm, from Anton Protopopov.

4) Fix warnings reported by resolve_btfids when building vmlinux
   with CONFIG_SECURITY_NETWORK disabled, from Hou Tao.

5) Minor fix up for BPF selftest gitignore, from Stanislav Fomichev.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
kernel/bpf/bpf_lsm.c
kernel/bpf/verifier.c
net/core/filter.c
tools/bpf/bpftool/Makefile
tools/testing/selftests/bpf/.gitignore
tools/testing/selftests/bpf/DENYLIST.s390x
tools/testing/selftests/bpf/prog_tests/decap_sanity.c [new file with mode: 0644]
tools/testing/selftests/bpf/prog_tests/jeq_infer_not_null.c [new file with mode: 0644]
tools/testing/selftests/bpf/progs/bpf_tracing_net.h
tools/testing/selftests/bpf/progs/decap_sanity.c [new file with mode: 0644]
tools/testing/selftests/bpf/progs/jeq_infer_not_null_fail.c [new file with mode: 0644]

index 9ea42a45da47037bdc198b7ac2be2adc67e01f49..a4a41ee3e80b5622d3f5292fb44fdee50d2fedc5 100644 (file)
@@ -351,8 +351,10 @@ BTF_ID(func, bpf_lsm_bpf_prog_alloc_security)
 BTF_ID(func, bpf_lsm_bpf_prog_free_security)
 BTF_ID(func, bpf_lsm_file_alloc_security)
 BTF_ID(func, bpf_lsm_file_free_security)
+#ifdef CONFIG_SECURITY_NETWORK
 BTF_ID(func, bpf_lsm_sk_alloc_security)
 BTF_ID(func, bpf_lsm_sk_free_security)
+#endif /* CONFIG_SECURITY_NETWORK */
 BTF_ID(func, bpf_lsm_task_free)
 BTF_SET_END(untrusted_lsm_hooks)
 
index a5255a0dcbb681f1e3681d1b7eac9694627095c1..243d06ce68426c8a50f476fc1d13c73e0fd55def 100644 (file)
@@ -11822,10 +11822,17 @@ static int check_cond_jmp_op(struct bpf_verifier_env *env,
         *      register B - not null
         * for JNE A, B, ... - A is not null in the false branch;
         * for JEQ A, B, ... - A is not null in the true branch.
+        *
+        * Since PTR_TO_BTF_ID points to a kernel struct that does
+        * not need to be null checked by the BPF program, i.e.,
+        * could be null even without PTR_MAYBE_NULL marking, so
+        * only propagate nullness when neither reg is that type.
         */
        if (!is_jmp32 && BPF_SRC(insn->code) == BPF_X &&
            __is_pointer_value(false, src_reg) && __is_pointer_value(false, dst_reg) &&
-           type_may_be_null(src_reg->type) != type_may_be_null(dst_reg->type)) {
+           type_may_be_null(src_reg->type) != type_may_be_null(dst_reg->type) &&
+           base_type(src_reg->type) != PTR_TO_BTF_ID &&
+           base_type(dst_reg->type) != PTR_TO_BTF_ID) {
                eq_branch_regs = NULL;
                switch (opcode) {
                case BPF_JEQ:
index 929358677183d5827b7cf2c54700cc34eb36544d..43cc1fe58a2c6e41d05db12ec6e992b8bf62a15e 100644 (file)
@@ -3180,15 +3180,18 @@ static int bpf_skb_generic_push(struct sk_buff *skb, u32 off, u32 len)
 
 static int bpf_skb_generic_pop(struct sk_buff *skb, u32 off, u32 len)
 {
+       void *old_data;
+
        /* skb_ensure_writable() is not needed here, as we're
         * already working on an uncloned skb.
         */
        if (unlikely(!pskb_may_pull(skb, off + len)))
                return -ENOMEM;
 
-       skb_postpull_rcsum(skb, skb->data + off, len);
-       memmove(skb->data + len, skb->data, off);
+       old_data = skb->data;
        __skb_pull(skb, len);
+       skb_postpull_rcsum(skb, old_data + off, len);
+       memmove(skb->data, old_data, off);
 
        return 0;
 }
index 787b857d3fb5fb4b8da5d86afce6e364d7721034..f610e184ce02abf6163c2863eb7bc63a7ec1eb9a 100644 (file)
@@ -145,6 +145,10 @@ ifeq ($(feature-llvm),1)
   LLVM_CONFIG_LIB_COMPONENTS := mcdisassembler all-targets
   CFLAGS  += $(shell $(LLVM_CONFIG) --cflags --libs $(LLVM_CONFIG_LIB_COMPONENTS))
   LIBS    += $(shell $(LLVM_CONFIG) --libs $(LLVM_CONFIG_LIB_COMPONENTS))
+  ifeq ($(shell $(LLVM_CONFIG) --shared-mode),static)
+    LIBS += $(shell $(LLVM_CONFIG) --system-libs $(LLVM_CONFIG_LIB_COMPONENTS))
+    LIBS += -lstdc++
+  endif
   LDFLAGS += $(shell $(LLVM_CONFIG) --ldflags)
 else
   # Fall back on libbfd
index 07d2d0a8c5cb4dae24dedd1e3b894d2dfa294197..401a75844cc0e71ce9fa4464433b5a45f4f38517 100644 (file)
@@ -36,6 +36,7 @@ test_cpp
 *.lskel.h
 /no_alu32
 /bpf_gcc
+/host-tools
 /tools
 /runqslower
 /bench
index 585fcf73c73146db5e8375a7ddc6eeddd43a5189..3fc3e54b19aad4d94b114f46532a8af3038f07f4 100644 (file)
@@ -14,6 +14,7 @@ cgrp_kfunc                               # JIT does not support calling kernel f
 cgrp_local_storage                       # prog_attach unexpected error: -524                                          (trampoline)
 core_read_macros                         # unknown func bpf_probe_read#4                                               (overlapping)
 d_path                                   # failed to auto-attach program 'prog_stat': -524                             (trampoline)
+decap_sanity                             # JIT does not support calling kernel function                                (kfunc)
 deny_namespace                           # failed to attach: ERROR: strerror_r(-524)=22                                (trampoline)
 dummy_st_ops                             # test_run unexpected error: -524 (errno 524)                                 (trampoline)
 fentry_fexit                             # fentry attach failed: -524                                                  (trampoline)
diff --git a/tools/testing/selftests/bpf/prog_tests/decap_sanity.c b/tools/testing/selftests/bpf/prog_tests/decap_sanity.c
new file mode 100644 (file)
index 0000000..0b2f73b
--- /dev/null
@@ -0,0 +1,85 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2022 Meta Platforms, Inc. and affiliates. */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <linux/in6.h>
+
+#include "test_progs.h"
+#include "network_helpers.h"
+#include "decap_sanity.skel.h"
+
+#define SYS(fmt, ...)                                          \
+       ({                                                      \
+               char cmd[1024];                                 \
+               snprintf(cmd, sizeof(cmd), fmt, ##__VA_ARGS__); \
+               if (!ASSERT_OK(system(cmd), cmd))               \
+                       goto fail;                              \
+       })
+
+#define NS_TEST "decap_sanity_ns"
+#define IPV6_IFACE_ADDR "face::1"
+#define UDP_TEST_PORT 7777
+
+void test_decap_sanity(void)
+{
+       LIBBPF_OPTS(bpf_tc_hook, qdisc_hook, .attach_point = BPF_TC_EGRESS);
+       LIBBPF_OPTS(bpf_tc_opts, tc_attach);
+       struct nstoken *nstoken = NULL;
+       struct decap_sanity *skel;
+       struct sockaddr_in6 addr;
+       socklen_t addrlen;
+       char buf[128] = {};
+       int sockfd, err;
+
+       skel = decap_sanity__open_and_load();
+       if (!ASSERT_OK_PTR(skel, "skel open_and_load"))
+               return;
+
+       SYS("ip netns add %s", NS_TEST);
+       SYS("ip -net %s -6 addr add %s/128 dev lo nodad", NS_TEST, IPV6_IFACE_ADDR);
+       SYS("ip -net %s link set dev lo up", NS_TEST);
+
+       nstoken = open_netns(NS_TEST);
+       if (!ASSERT_OK_PTR(nstoken, "open_netns"))
+               goto fail;
+
+       qdisc_hook.ifindex = if_nametoindex("lo");
+       if (!ASSERT_GT(qdisc_hook.ifindex, 0, "if_nametoindex lo"))
+               goto fail;
+
+       err = bpf_tc_hook_create(&qdisc_hook);
+       if (!ASSERT_OK(err, "create qdisc hook"))
+               goto fail;
+
+       tc_attach.prog_fd = bpf_program__fd(skel->progs.decap_sanity);
+       err = bpf_tc_attach(&qdisc_hook, &tc_attach);
+       if (!ASSERT_OK(err, "attach filter"))
+               goto fail;
+
+       addrlen = sizeof(addr);
+       err = make_sockaddr(AF_INET6, IPV6_IFACE_ADDR, UDP_TEST_PORT,
+                           (void *)&addr, &addrlen);
+       if (!ASSERT_OK(err, "make_sockaddr"))
+               goto fail;
+       sockfd = socket(AF_INET6, SOCK_DGRAM, 0);
+       if (!ASSERT_NEQ(sockfd, -1, "socket"))
+               goto fail;
+       err = sendto(sockfd, buf, sizeof(buf), 0, (void *)&addr, addrlen);
+       close(sockfd);
+       if (!ASSERT_EQ(err, sizeof(buf), "send"))
+               goto fail;
+
+       ASSERT_TRUE(skel->bss->init_csum_partial, "init_csum_partial");
+       ASSERT_TRUE(skel->bss->final_csum_none, "final_csum_none");
+       ASSERT_FALSE(skel->bss->broken_csum_start, "broken_csum_start");
+
+fail:
+       if (nstoken) {
+               bpf_tc_hook_destroy(&qdisc_hook);
+               close_netns(nstoken);
+       }
+       system("ip netns del " NS_TEST " >& /dev/null");
+       decap_sanity__destroy(skel);
+}
diff --git a/tools/testing/selftests/bpf/prog_tests/jeq_infer_not_null.c b/tools/testing/selftests/bpf/prog_tests/jeq_infer_not_null.c
new file mode 100644 (file)
index 0000000..3add34d
--- /dev/null
@@ -0,0 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <test_progs.h>
+#include "jeq_infer_not_null_fail.skel.h"
+
+void test_jeq_infer_not_null(void)
+{
+       RUN_TESTS(jeq_infer_not_null_fail);
+}
index b394817126cf9e5fe12afd30fc4ede4733522ea6..cfed4df490f35b23d808c6ae427d79ab2f3cee58 100644 (file)
 #define ICSK_TIME_LOSS_PROBE   5
 #define ICSK_TIME_REO_TIMEOUT  6
 
+#define ETH_HLEN               14
+#define ETH_P_IPV6             0x86DD
+
+#define CHECKSUM_NONE          0
+#define CHECKSUM_PARTIAL       3
+
 #define IFNAMSIZ               16
 
 #define RTF_GATEWAY            0x0002
diff --git a/tools/testing/selftests/bpf/progs/decap_sanity.c b/tools/testing/selftests/bpf/progs/decap_sanity.c
new file mode 100644 (file)
index 0000000..bd3c657
--- /dev/null
@@ -0,0 +1,68 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2022 Meta Platforms, Inc. and affiliates. */
+
+#include "vmlinux.h"
+#include "bpf_tracing_net.h"
+#include <bpf/bpf_helpers.h>
+#include <bpf/bpf_endian.h>
+
+#define UDP_TEST_PORT 7777
+
+void *bpf_cast_to_kern_ctx(void *) __ksym;
+bool init_csum_partial = false;
+bool final_csum_none = false;
+bool broken_csum_start = false;
+
+static unsigned int skb_headlen(const struct sk_buff *skb)
+{
+       return skb->len - skb->data_len;
+}
+
+static unsigned int skb_headroom(const struct sk_buff *skb)
+{
+       return skb->data - skb->head;
+}
+
+static int skb_checksum_start_offset(const struct sk_buff *skb)
+{
+       return skb->csum_start - skb_headroom(skb);
+}
+
+SEC("tc")
+int decap_sanity(struct __sk_buff *skb)
+{
+       struct sk_buff *kskb;
+       struct ipv6hdr ip6h;
+       struct udphdr udph;
+       int err;
+
+       if (skb->protocol != __bpf_constant_htons(ETH_P_IPV6))
+               return TC_ACT_SHOT;
+
+       if (bpf_skb_load_bytes(skb, ETH_HLEN, &ip6h, sizeof(ip6h)))
+               return TC_ACT_SHOT;
+
+       if (ip6h.nexthdr != IPPROTO_UDP)
+               return TC_ACT_SHOT;
+
+       if (bpf_skb_load_bytes(skb, ETH_HLEN + sizeof(ip6h), &udph, sizeof(udph)))
+               return TC_ACT_SHOT;
+
+       if (udph.dest != __bpf_constant_htons(UDP_TEST_PORT))
+               return TC_ACT_SHOT;
+
+       kskb = bpf_cast_to_kern_ctx(skb);
+       init_csum_partial = (kskb->ip_summed == CHECKSUM_PARTIAL);
+       err = bpf_skb_adjust_room(skb, -(s32)(ETH_HLEN + sizeof(ip6h) + sizeof(udph)),
+                                 1, BPF_F_ADJ_ROOM_FIXED_GSO);
+       if (err)
+               return TC_ACT_SHOT;
+       final_csum_none = (kskb->ip_summed == CHECKSUM_NONE);
+       if (kskb->ip_summed == CHECKSUM_PARTIAL &&
+           (unsigned int)skb_checksum_start_offset(kskb) >= skb_headlen(kskb))
+               broken_csum_start = true;
+
+       return TC_ACT_SHOT;
+}
+
+char __license[] SEC("license") = "GPL";
diff --git a/tools/testing/selftests/bpf/progs/jeq_infer_not_null_fail.c b/tools/testing/selftests/bpf/progs/jeq_infer_not_null_fail.c
new file mode 100644 (file)
index 0000000..f469650
--- /dev/null
@@ -0,0 +1,42 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include "vmlinux.h"
+#include <bpf/bpf_helpers.h>
+#include "bpf_misc.h"
+
+char _license[] SEC("license") = "GPL";
+
+struct {
+       __uint(type, BPF_MAP_TYPE_HASH);
+       __uint(max_entries, 1);
+       __type(key, u64);
+       __type(value, u64);
+} m_hash SEC(".maps");
+
+SEC("?raw_tp")
+__failure __msg("R8 invalid mem access 'map_value_or_null")
+int jeq_infer_not_null_ptr_to_btfid(void *ctx)
+{
+       struct bpf_map *map = (struct bpf_map *)&m_hash;
+       struct bpf_map *inner_map = map->inner_map_meta;
+       u64 key = 0, ret = 0, *val;
+
+       val = bpf_map_lookup_elem(map, &key);
+       /* Do not mark ptr as non-null if one of them is
+        * PTR_TO_BTF_ID (R9), reject because of invalid
+        * access to map value (R8).
+        *
+        * Here, we need to inline those insns to access
+        * R8 directly, since compiler may use other reg
+        * once it figures out val==inner_map.
+        */
+       asm volatile("r8 = %[val];\n"
+                    "r9 = %[inner_map];\n"
+                    "if r8 != r9 goto +1;\n"
+                    "%[ret] = *(u64 *)(r8 +0);\n"
+                    : [ret] "+r"(ret)
+                    : [inner_map] "r"(inner_map), [val] "r"(val)
+                    : "r8", "r9");
+
+       return ret;
+}