From patchwork Tue Dec 12 02:31:34 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eduard Zingerman X-Patchwork-Id: 13488402 X-Patchwork-Delegate: bpf@iogearbox.net Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="nVigoiXO" Received: from mail-wm1-x329.google.com (mail-wm1-x329.google.com [IPv6:2a00:1450:4864:20::329]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id F3D79268C for ; Mon, 11 Dec 2023 18:32:49 -0800 (PST) Received: by mail-wm1-x329.google.com with SMTP id 5b1f17b1804b1-40c2d50bfbfso24391735e9.0 for ; Mon, 11 Dec 2023 18:32:49 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1702348340; x=1702953140; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=Oqxt9UpM3lXEQA9Ql/9MZ7PSiBm36QeDH3GLKGuDpKA=; b=nVigoiXOQAU+TUEVozvMSl+sna8SJZmbh4OoIIDyVEBR3QY7xnp77KFgxekZXWDkBN tRhv04+ccfEOS99Cb8stqKaSt5GvY23hesluVkjhjEX5ICVbKjUDB33rEB67NTLUUpjR Jg9j/+b/RcV/GT3OiR3iMV3yRXsKb1GoG7kKeyllHWwIf1u67LqqRjCkMVsgY+1sOg4N CRXzOOSV5omHe6EhsJZLzqdgk7/DbZNQemxJ5MOZ2nbp3W7oSZ+rFgxzgMS6bQsMyqvj xQfqtFSOpPy/fKHKzyr0FsIScaoJ8Vc0fxxPS/5EHCfT/ChO/jxjCE2hAO1UXs+va+R3 GfTw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1702348340; x=1702953140; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=Oqxt9UpM3lXEQA9Ql/9MZ7PSiBm36QeDH3GLKGuDpKA=; b=PkSCiu14LcWpSS2s1u8QBwf7DEw/ED5oQzjR31cWxo/ZOPQhmjCgZYqQylsGwc/wsp tajD7HsP6inDAdmkDA0o1+v9/7KMzEZ/n06TaxOmHyX+zB54NwDp0vpaC5pLRlyFQhP8 RJkO+oIgneJMlMYT+znIMKC8mqdOsw2H47y6qXHQN+19rL4owP8uBcvSSfDMIIu6Huz8 gl9KTK4DNfYae0z45ne7S8BCQCR9qdbO7U6hDPjU2ZE/WXH8u6q9WXo+iWLRzZIkkqvu t3lIhbyDcvSOF7f9U0QV6pQetQ9UgHCRbCKLRhmE0CKU3UQ0R+ynyB1dkpG7srR72cqV yHVA== X-Gm-Message-State: AOJu0Yxi4Nz8jfB8tgRzg93gMwNEocE7B3Xm8wXJ15zGlVjFGFWkLia8 R0SG1AZPHDCKpim5XgK2jTmd/xd6tD4= X-Google-Smtp-Source: AGHT+IEIkgKglFHV6nuHuBoE6qvejl+RsIgDB7k3M93t2DutSWl2jUxcNDjEUEL2tXf3Yxw0nFEd9g== X-Received: by 2002:a05:600c:1910:b0:40c:2654:5704 with SMTP id j16-20020a05600c191000b0040c26545704mr2720719wmq.20.1702348339706; Mon, 11 Dec 2023 18:32:19 -0800 (PST) Received: from localhost.localdomain (host-176-36-0-241.b024.la.net.ua. [176.36.0.241]) by smtp.gmail.com with ESMTPSA id e12-20020adfe38c000000b003332fa77a0fsm9659900wrm.21.2023.12.11.18.32.18 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 11 Dec 2023 18:32:19 -0800 (PST) From: Eduard Zingerman To: bpf@vger.kernel.org, ast@kernel.org Cc: andrii@kernel.org, daniel@iogearbox.net, martin.lau@linux.dev, kernel-team@fb.com, yonghong.song@linux.dev, quentin@isovalent.com, alan.maguire@oracle.com, Eduard Zingerman Subject: [RFC v2 1/3] bpf: Mark virtual BPF context structures as preserve_static_offset Date: Tue, 12 Dec 2023 04:31:34 +0200 Message-ID: <20231212023136.7021-2-eddyz87@gmail.com> X-Mailer: git-send-email 2.42.1 In-Reply-To: <20231212023136.7021-1-eddyz87@gmail.com> References: <20231212023136.7021-1-eddyz87@gmail.com> Precedence: bulk X-Mailing-List: bpf@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Patchwork-Delegate: bpf@iogearbox.net X-Patchwork-State: RFC Add __attribute__((preserve_static_offset)) for the following BPF related structures: - __sk_buff (*) - bpf_cgroup_dev_ctx (*) - bpf_nf_ctx - bpf_perf_event_data (*) - bpf_raw_tracepoint_args - bpf_sk_lookup (*) - bpf_sock (*) - bpf_sock_addr (*) - bpf_sock_ops (*) - bpf_sockopt (*) - bpf_sysctl (*) - sk_msg_md (*) - sk_reuseport_md (*) - xdp_md (*) Access to structures marked with (*) is rewritten by BPF verifier. (See verifier.c:convert_ctx_access). The rewrite requires that offsets used in access to fields of these structures are constant values. For the rest of the structures verifier just disallows access via modified context pointer in the following code path: check_mem_access check_ptr_off_reg __check_ptr_off_reg if (!fixed_off_ok && reg->off) "dereference of modified %s ptr R%d off=%d disallowed\n" Attribute preserve_static_offset [0] is a hint to clang that ensures that constant offsets are used. Type 'pt_regs' is not handled yet. [0] https://clang.llvm.org/docs/AttributeReference.html#preserve-static-offset Signed-off-by: Eduard Zingerman --- include/net/netfilter/nf_bpf_link.h | 10 ++++++- include/uapi/linux/bpf.h | 32 ++++++++++++++--------- include/uapi/linux/bpf_perf_event.h | 10 ++++++- tools/include/uapi/linux/bpf.h | 32 ++++++++++++++--------- tools/include/uapi/linux/bpf_perf_event.h | 10 ++++++- 5 files changed, 67 insertions(+), 27 deletions(-) diff --git a/include/net/netfilter/nf_bpf_link.h b/include/net/netfilter/nf_bpf_link.h index 6c984b0ea838..e5555b1ac55d 100644 --- a/include/net/netfilter/nf_bpf_link.h +++ b/include/net/netfilter/nf_bpf_link.h @@ -1,9 +1,15 @@ /* SPDX-License-Identifier: GPL-2.0 */ +#if __has_attribute(preserve_static_offset) && defined(__bpf__) +#define __bpf_ctx __attribute__((preserve_static_offset)) +#else +#define __bpf_ctx +#endif + struct bpf_nf_ctx { const struct nf_hook_state *state; struct sk_buff *skb; -}; +} __bpf_ctx; #if IS_ENABLED(CONFIG_NETFILTER_BPF_LINK) int bpf_nf_link_attach(const union bpf_attr *attr, struct bpf_prog *prog); @@ -13,3 +19,5 @@ static inline int bpf_nf_link_attach(const union bpf_attr *attr, struct bpf_prog return -EOPNOTSUPP; } #endif + +#undef __bpf_ctx diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index e0545201b55f..f533301de5e4 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -69,6 +69,12 @@ enum { /* BPF has 10 general purpose 64-bit registers and stack frame. */ #define MAX_BPF_REG __MAX_BPF_REG +#if __has_attribute(preserve_static_offset) && defined(__bpf__) +#define __bpf_ctx __attribute__((preserve_static_offset)) +#else +#define __bpf_ctx +#endif + struct bpf_insn { __u8 code; /* opcode */ __u8 dst_reg:4; /* dest register */ @@ -6190,7 +6196,7 @@ struct __sk_buff { __u8 tstamp_type; __u32 :24; /* Padding, future use. */ __u64 hwtstamp; -}; +} __bpf_ctx; struct bpf_tunnel_key { __u32 tunnel_id; @@ -6271,7 +6277,7 @@ struct bpf_sock { __u32 dst_ip6[4]; __u32 state; __s32 rx_queue_mapping; -}; +} __bpf_ctx; struct bpf_tcp_sock { __u32 snd_cwnd; /* Sending congestion window */ @@ -6379,7 +6385,7 @@ struct xdp_md { __u32 rx_queue_index; /* rxq->queue_index */ __u32 egress_ifindex; /* txq->dev->ifindex */ -}; +} __bpf_ctx; /* DEVMAP map-value layout * @@ -6429,7 +6435,7 @@ struct sk_msg_md { __u32 size; /* Total size of sk_msg */ __bpf_md_ptr(struct bpf_sock *, sk); /* current socket */ -}; +} __bpf_ctx; struct sk_reuseport_md { /* @@ -6468,7 +6474,7 @@ struct sk_reuseport_md { */ __bpf_md_ptr(struct bpf_sock *, sk); __bpf_md_ptr(struct bpf_sock *, migrating_sk); -}; +} __bpf_ctx; #define BPF_TAG_SIZE 8 @@ -6678,7 +6684,7 @@ struct bpf_sock_addr { * Stored in network byte order. */ __bpf_md_ptr(struct bpf_sock *, sk); -}; +} __bpf_ctx; /* User bpf_sock_ops struct to access socket values and specify request ops * and their replies. @@ -6761,7 +6767,7 @@ struct bpf_sock_ops { * been written yet. */ __u64 skb_hwtstamp; -}; +} __bpf_ctx; /* Definitions for bpf_sock_ops_cb_flags */ enum { @@ -7034,11 +7040,11 @@ struct bpf_cgroup_dev_ctx { __u32 access_type; __u32 major; __u32 minor; -}; +} __bpf_ctx; struct bpf_raw_tracepoint_args { __u64 args[0]; -}; +} __bpf_ctx; /* DIRECT: Skip the FIB rules and go to FIB table associated with device * OUTPUT: Do lookup from egress perspective; default is ingress @@ -7245,7 +7251,7 @@ struct bpf_sysctl { __u32 file_pos; /* Sysctl file position to read from, write to. * Allows 1,2,4-byte read an 4-byte write. */ -}; +} __bpf_ctx; struct bpf_sockopt { __bpf_md_ptr(struct bpf_sock *, sk); @@ -7256,7 +7262,7 @@ struct bpf_sockopt { __s32 optname; __s32 optlen; __s32 retval; -}; +} __bpf_ctx; struct bpf_pidns_info { __u32 pid; @@ -7280,7 +7286,7 @@ struct bpf_sk_lookup { __u32 local_ip6[4]; /* Network byte order */ __u32 local_port; /* Host byte order */ __u32 ingress_ifindex; /* The arriving interface. Determined by inet_iif. */ -}; +} __bpf_ctx; /* * struct btf_ptr is used for typed pointer representation; the @@ -7406,4 +7412,6 @@ struct bpf_iter_num { __u64 __opaque[1]; } __attribute__((aligned(8))); +#undef __bpf_ctx + #endif /* _UAPI__LINUX_BPF_H__ */ diff --git a/include/uapi/linux/bpf_perf_event.h b/include/uapi/linux/bpf_perf_event.h index eb1b9d21250c..608e366877fc 100644 --- a/include/uapi/linux/bpf_perf_event.h +++ b/include/uapi/linux/bpf_perf_event.h @@ -10,10 +10,18 @@ #include +#if __has_attribute(preserve_static_offset) && defined(__bpf__) +#define __bpf_ctx __attribute__((preserve_static_offset)) +#else +#define __bpf_ctx +#endif + struct bpf_perf_event_data { bpf_user_pt_regs_t regs; __u64 sample_period; __u64 addr; -}; +} __bpf_ctx; + +#undef __bpf_ctx #endif /* _UAPI__LINUX_BPF_PERF_EVENT_H__ */ diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index e0545201b55f..f533301de5e4 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -69,6 +69,12 @@ enum { /* BPF has 10 general purpose 64-bit registers and stack frame. */ #define MAX_BPF_REG __MAX_BPF_REG +#if __has_attribute(preserve_static_offset) && defined(__bpf__) +#define __bpf_ctx __attribute__((preserve_static_offset)) +#else +#define __bpf_ctx +#endif + struct bpf_insn { __u8 code; /* opcode */ __u8 dst_reg:4; /* dest register */ @@ -6190,7 +6196,7 @@ struct __sk_buff { __u8 tstamp_type; __u32 :24; /* Padding, future use. */ __u64 hwtstamp; -}; +} __bpf_ctx; struct bpf_tunnel_key { __u32 tunnel_id; @@ -6271,7 +6277,7 @@ struct bpf_sock { __u32 dst_ip6[4]; __u32 state; __s32 rx_queue_mapping; -}; +} __bpf_ctx; struct bpf_tcp_sock { __u32 snd_cwnd; /* Sending congestion window */ @@ -6379,7 +6385,7 @@ struct xdp_md { __u32 rx_queue_index; /* rxq->queue_index */ __u32 egress_ifindex; /* txq->dev->ifindex */ -}; +} __bpf_ctx; /* DEVMAP map-value layout * @@ -6429,7 +6435,7 @@ struct sk_msg_md { __u32 size; /* Total size of sk_msg */ __bpf_md_ptr(struct bpf_sock *, sk); /* current socket */ -}; +} __bpf_ctx; struct sk_reuseport_md { /* @@ -6468,7 +6474,7 @@ struct sk_reuseport_md { */ __bpf_md_ptr(struct bpf_sock *, sk); __bpf_md_ptr(struct bpf_sock *, migrating_sk); -}; +} __bpf_ctx; #define BPF_TAG_SIZE 8 @@ -6678,7 +6684,7 @@ struct bpf_sock_addr { * Stored in network byte order. */ __bpf_md_ptr(struct bpf_sock *, sk); -}; +} __bpf_ctx; /* User bpf_sock_ops struct to access socket values and specify request ops * and their replies. @@ -6761,7 +6767,7 @@ struct bpf_sock_ops { * been written yet. */ __u64 skb_hwtstamp; -}; +} __bpf_ctx; /* Definitions for bpf_sock_ops_cb_flags */ enum { @@ -7034,11 +7040,11 @@ struct bpf_cgroup_dev_ctx { __u32 access_type; __u32 major; __u32 minor; -}; +} __bpf_ctx; struct bpf_raw_tracepoint_args { __u64 args[0]; -}; +} __bpf_ctx; /* DIRECT: Skip the FIB rules and go to FIB table associated with device * OUTPUT: Do lookup from egress perspective; default is ingress @@ -7245,7 +7251,7 @@ struct bpf_sysctl { __u32 file_pos; /* Sysctl file position to read from, write to. * Allows 1,2,4-byte read an 4-byte write. */ -}; +} __bpf_ctx; struct bpf_sockopt { __bpf_md_ptr(struct bpf_sock *, sk); @@ -7256,7 +7262,7 @@ struct bpf_sockopt { __s32 optname; __s32 optlen; __s32 retval; -}; +} __bpf_ctx; struct bpf_pidns_info { __u32 pid; @@ -7280,7 +7286,7 @@ struct bpf_sk_lookup { __u32 local_ip6[4]; /* Network byte order */ __u32 local_port; /* Host byte order */ __u32 ingress_ifindex; /* The arriving interface. Determined by inet_iif. */ -}; +} __bpf_ctx; /* * struct btf_ptr is used for typed pointer representation; the @@ -7406,4 +7412,6 @@ struct bpf_iter_num { __u64 __opaque[1]; } __attribute__((aligned(8))); +#undef __bpf_ctx + #endif /* _UAPI__LINUX_BPF_H__ */ diff --git a/tools/include/uapi/linux/bpf_perf_event.h b/tools/include/uapi/linux/bpf_perf_event.h index eb1b9d21250c..608e366877fc 100644 --- a/tools/include/uapi/linux/bpf_perf_event.h +++ b/tools/include/uapi/linux/bpf_perf_event.h @@ -10,10 +10,18 @@ #include +#if __has_attribute(preserve_static_offset) && defined(__bpf__) +#define __bpf_ctx __attribute__((preserve_static_offset)) +#else +#define __bpf_ctx +#endif + struct bpf_perf_event_data { bpf_user_pt_regs_t regs; __u64 sample_period; __u64 addr; -}; +} __bpf_ctx; + +#undef __bpf_ctx #endif /* _UAPI__LINUX_BPF_PERF_EVENT_H__ */ From patchwork Tue Dec 12 02:31:35 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eduard Zingerman X-Patchwork-Id: 13488403 X-Patchwork-Delegate: bpf@iogearbox.net Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="GLXBZtoH" Received: from mail-wr1-x42e.google.com (mail-wr1-x42e.google.com [IPv6:2a00:1450:4864:20::42e]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2578C2691 for ; Mon, 11 Dec 2023 18:32:50 -0800 (PST) Received: by mail-wr1-x42e.google.com with SMTP id ffacd0b85a97d-3333fbbeab9so4599173f8f.2 for ; Mon, 11 Dec 2023 18:32:50 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1702348341; x=1702953141; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=ymPQQ+vO77kJlYebMg54UIjrbNhoAxdhVYd/RJX0YcY=; b=GLXBZtoH46pYAIZnM9NmBKo54yMtkqTzyz+cbDct4wBzVBrKpGOeuXB1Q3Ojl3jIAw JXeNeLCtJ9ATe/zodLXmBYaUJIQEOp4itTvygTUCXMJGQ5aeTL+feBDc1PRUc7PYPvNg V6cLwlpnBVcSsEmRnKjf0MA3FBkvQ90eRKBEoX1dyOZ19OAzNl7rTI2PA2CWAOFgRUH7 rddlKbLKpz5vPyUVvX0QpG68TwDffBnj0IvUVF7fFm9L8iPujYE0rEAOHnI+v1742sMc s7zNRs6hsVtrFKDUrd6lpemTCzH7fzbeBeWNhsRtHQc++uW4kDZwSQ7mNOjdrR8xqPVc F+DA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1702348341; x=1702953141; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=ymPQQ+vO77kJlYebMg54UIjrbNhoAxdhVYd/RJX0YcY=; b=aXAbdYZIgMZnVoPv9pZaCWm7vmYu0Leirlw7DCT8mNENadMxh+XwKA85ac9YCSm0Sz EOiWUzOyTW/6eng+wvPrOcO1z1XZlV4zBO2By9lezEkK3A2Aqqj2El873eugfCy554fk m31poHDzvABJZcOZAMedEEr908BimairmE5YwivVcsimswCGLj4rEM5XlYNL6kER+ym8 PSnPG/v3i2LSFd0J/JXL6/uTBElKULzdc1J/HPesJUs5D5ypX4HnPFs6WkYn4LvKkDfT QXsLnTYiTXsdXFAjDhk65iePZ8jc5etHOGiDImGDmPqr+SYHxYHSxn4PoL7/VCEXzlz+ q3HQ== X-Gm-Message-State: AOJu0YzrTEk9GYwgKlVDRVeeg/wr6ORSYcdVpeOYAoGCsl1toEvFkmB4 7IHUwYW9nenNQZBY6KMfRRPbyDnvNC0= X-Google-Smtp-Source: AGHT+IG07vZhB90FQMuu9jjWiBbEriaj4Z98pw/FixYMsQpd9D/gE3C0bPK2q8ylRnrdDBlJd2U8rA== X-Received: by 2002:adf:fd04:0:b0:332:e3f1:9656 with SMTP id e4-20020adffd04000000b00332e3f19656mr2709395wrr.35.1702348341028; Mon, 11 Dec 2023 18:32:21 -0800 (PST) Received: from localhost.localdomain (host-176-36-0-241.b024.la.net.ua. [176.36.0.241]) by smtp.gmail.com with ESMTPSA id e12-20020adfe38c000000b003332fa77a0fsm9659900wrm.21.2023.12.11.18.32.19 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 11 Dec 2023 18:32:20 -0800 (PST) From: Eduard Zingerman To: bpf@vger.kernel.org, ast@kernel.org Cc: andrii@kernel.org, daniel@iogearbox.net, martin.lau@linux.dev, kernel-team@fb.com, yonghong.song@linux.dev, quentin@isovalent.com, alan.maguire@oracle.com, Eduard Zingerman Subject: [RFC v2 2/3] bpftool: add attribute preserve_static_offset for context types Date: Tue, 12 Dec 2023 04:31:35 +0200 Message-ID: <20231212023136.7021-3-eddyz87@gmail.com> X-Mailer: git-send-email 2.42.1 In-Reply-To: <20231212023136.7021-1-eddyz87@gmail.com> References: <20231212023136.7021-1-eddyz87@gmail.com> Precedence: bulk X-Mailing-List: bpf@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Patchwork-Delegate: bpf@iogearbox.net X-Patchwork-State: RFC When printing vmlinux.h emit attribute preserve_static_offset [0] for types that are used as context parameters for BPF programs. To avoid hacking libbpf dump logic emit forward declarations annotated with attribute. Such forward declarations have to come before structure definitions. Only emit such forward declarations when context types are present in target BTF (identified by name). C language standard wording in section "6.7.2.1 Structure and union specifiers" [1] is vague, but example in 6.7.2.1.21 explicitly allows such notation, and it matches clang behavior. Here is how 'bpftool btf gen ... format c' looks after this change: #ifndef __VMLINUX_H__ #define __VMLINUX_H__ #if !defined(BPF_NO_PRESERVE_STATIC_OFFSET) && \ __has_attribute(preserve_static_offset) #pragma clang attribute push \ (__attribute__((preserve_static_offset)), apply_to = record) struct bpf_cgroup_dev_ctx; ... #pragma clang attribute pop #endif ... rest of the output unchanged ... This is a follow up for discussion in thread [2]. [0] https://clang.llvm.org/docs/AttributeReference.html#preserve-static-offset [1] https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3088.pdf [2] https://lore.kernel.org/bpf/20231208000531.19179-1-eddyz87@gmail.com/ Signed-off-by: Eduard Zingerman --- tools/bpf/bpftool/btf.c | 131 +++++++++++++++++++++++++++++++++++----- 1 file changed, 116 insertions(+), 15 deletions(-) diff --git a/tools/bpf/bpftool/btf.c b/tools/bpf/bpftool/btf.c index 91fcb75babe3..2abe71194afb 100644 --- a/tools/bpf/bpftool/btf.c +++ b/tools/bpf/bpftool/btf.c @@ -460,11 +460,118 @@ static void __printf(2, 0) btf_dump_printf(void *ctx, vfprintf(stdout, fmt, args); } +static const char * const context_types[] = { + "bpf_cgroup_dev_ctx", + "bpf_nf_ctx", + "bpf_perf_event_data", + "bpf_raw_tracepoint_args", + "bpf_sk_lookup", + "bpf_sock", + "bpf_sock_addr", + "bpf_sock_ops", + "bpf_sockopt", + "bpf_sysctl", + "__sk_buff", + "sk_msg_md", + "sk_reuseport_md", + "xdp_md", + "pt_regs", +}; + +static bool is_context_type_name(const struct btf *btf, const char *name) +{ + __u32 i; + + for (i = 0; i < ARRAY_SIZE(context_types); ++i) + if (strcmp(name, context_types[i]) == 0) + return true; + + return false; +} + +/* When root_type_ids == NULL represents an iterator + * over all type ids in BTF: [1 .. btf__type_cnt(btf)]. + * + * When root_type_ids != NULL represents an iterator + * over all type ids in root_type_ids array. + */ +struct root_type_iter { + __u32 *root_type_ids; + __u32 cnt; + __u32 pos; +}; + +static struct root_type_iter make_root_type_iter(const struct btf *btf, + __u32 *root_type_ids, int root_type_cnt) +{ + if (root_type_cnt) + return (struct root_type_iter) { root_type_ids, root_type_cnt, 0 }; + + return (struct root_type_iter) { NULL, btf__type_cnt(btf), 1 }; +} + +static __u32 root_type_iter_next(struct root_type_iter *iter) +{ + if (iter->pos >= iter->cnt) + return 0; + + if (iter->root_type_ids) + return iter->root_type_ids[iter->pos++]; + + return iter->pos++; +} + +/* Iterate all types in 'btf', if there are types with name matching + * name of a BPF program context parameter type - emit a forward + * declaration for this type annotated with preserve_static_offset + * attribute [0]. + * + * [0] https://clang.llvm.org/docs/AttributeReference.html#preserve-static-offset + */ +static void emit_static_offset_protos(const struct btf *btf, struct root_type_iter iter) +{ + bool first = true; + __u32 id; + + while ((id = root_type_iter_next(&iter))) { + const struct btf_type *t; + const char *name; + + t = btf__type_by_id(btf, id); + if (!t) + continue; + + name = btf__name_by_offset(btf, t->name_off); + if (!name) + continue; + + if (!btf_is_struct(t) || !is_context_type_name(btf, name)) + continue; + + if (first) { + first = false; + printf("#if !defined(BPF_NO_PRESERVE_STATIC_OFFSET) && __has_attribute(preserve_static_offset)\n"); + printf("#pragma clang attribute push (__attribute__((preserve_static_offset)), apply_to = record)\n"); + printf("\n"); + } + + printf("struct %s;\n", name); + } + + if (!first) { + printf("\n"); + printf("#pragma clang attribute pop\n"); + printf("#endif /* BPF_NO_PRESERVE_STATIC_OFFSET */\n\n"); + } +} + static int dump_btf_c(const struct btf *btf, __u32 *root_type_ids, int root_type_cnt) { + struct root_type_iter iter; struct btf_dump *d; - int err = 0, i; + int err = 0; + __u32 id; d = btf_dump__new(btf, btf_dump_printf, NULL, NULL); if (!d) @@ -473,24 +580,18 @@ static int dump_btf_c(const struct btf *btf, printf("#ifndef __VMLINUX_H__\n"); printf("#define __VMLINUX_H__\n"); printf("\n"); + + emit_static_offset_protos(btf, make_root_type_iter(btf, root_type_ids, root_type_cnt)); + printf("#ifndef BPF_NO_PRESERVE_ACCESS_INDEX\n"); printf("#pragma clang attribute push (__attribute__((preserve_access_index)), apply_to = record)\n"); printf("#endif\n\n"); - if (root_type_cnt) { - for (i = 0; i < root_type_cnt; i++) { - err = btf_dump__dump_type(d, root_type_ids[i]); - if (err) - goto done; - } - } else { - int cnt = btf__type_cnt(btf); - - for (i = 1; i < cnt; i++) { - err = btf_dump__dump_type(d, i); - if (err) - goto done; - } + iter = make_root_type_iter(btf, root_type_ids, root_type_cnt); + while ((id = root_type_iter_next(&iter))) { + err = btf_dump__dump_type(d, id); + if (err) + goto done; } printf("#ifndef BPF_NO_PRESERVE_ACCESS_INDEX\n"); From patchwork Tue Dec 12 02:31:36 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eduard Zingerman X-Patchwork-Id: 13488405 X-Patchwork-Delegate: bpf@iogearbox.net Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="ZE07Pdcd" Received: from mail-wr1-x42d.google.com (mail-wr1-x42d.google.com [IPv6:2a00:1450:4864:20::42d]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 555722698 for ; Mon, 11 Dec 2023 18:32:50 -0800 (PST) Received: by mail-wr1-x42d.google.com with SMTP id ffacd0b85a97d-336121f93e3so1511158f8f.0 for ; Mon, 11 Dec 2023 18:32:50 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1702348342; x=1702953142; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=YDJhmzzuhJUDsa3iZIw/8V5aN0B8Hg7KTWSRn6k8TsY=; b=ZE07Pdcd50Uwa46SXflDkciy2xm/ZoFRNHWB3FvETErw+Y45eVB5ybncUUJOYoanPg gb/dHNi9epMNmO6ec5imGoagWuatRvtK9Uw58Ep+EcoJ/cjYvx3WfAyLDD3b34FXeayq AOt0cnDRP13PVC/i3OCsmRv3upjjEfJnZdiqkJGXvNw/e7BD/ULtj49zqmCK08ipC+il m5/XznVVDyTjof5ciFQnNZmh/EY9NDIWfs0TtCrff8D8/zjI6xpRlVFpfcD7/E3byNMM l/xr95jDLV1SNmitSaUk7tEwIwnAcrBmqw3uu5Z9rl0ra61VE8NHq8BVThfp0yGoamKB 4ltg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1702348342; x=1702953142; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=YDJhmzzuhJUDsa3iZIw/8V5aN0B8Hg7KTWSRn6k8TsY=; b=K0jIAie7r5asy7Jkv8fbB8sPehIQElSiww+cbZvI5h2C4WFY9tp5fZ3QC3vmPAirK8 d4ZrX+rKBguRzM1qjRA/bL9B2RkP6qdIFAVpAxHf0QrcThQDAO98GHfoc6T8zDyg+bqI cwKRDX/wEH2B/XKWuXqmv/NKUwDiBzQ3tB10g/LPs1UVsToJayctmsa54eRDMxy74XQt tCMwYyb/v0GuHc/qvgDY6pNnSOHUQBajFOx1odx2r0ukA4+9Y4xBy5KdluKD0kjjPPSL 6CEbRkO/GOlL4H84OyYxy+EgYEu7qou+ATORh6z8RoePWU2cZAy68uH6JyN1agFiT0OW +72w== X-Gm-Message-State: AOJu0YxDw97a8Q82Gm+79Aryz43DWXzuLoamJzZnEo/vdDZyFp9+Hp77 JI5T05ZRXQ4wmQUtZqX4g+YZfXyJaOY= X-Google-Smtp-Source: AGHT+IHJOJX6bb1yFvJwMrB4D1BG7ibfbu4sI+jzuX7914ZDclfoBOjYsEupKCiMlnrY9W5B1xLYYg== X-Received: by 2002:a5d:6351:0:b0:336:2a24:eb88 with SMTP id b17-20020a5d6351000000b003362a24eb88mr255854wrw.46.1702348342201; Mon, 11 Dec 2023 18:32:22 -0800 (PST) Received: from localhost.localdomain (host-176-36-0-241.b024.la.net.ua. [176.36.0.241]) by smtp.gmail.com with ESMTPSA id e12-20020adfe38c000000b003332fa77a0fsm9659900wrm.21.2023.12.11.18.32.21 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 11 Dec 2023 18:32:21 -0800 (PST) From: Eduard Zingerman To: bpf@vger.kernel.org, ast@kernel.org Cc: andrii@kernel.org, daniel@iogearbox.net, martin.lau@linux.dev, kernel-team@fb.com, yonghong.song@linux.dev, quentin@isovalent.com, alan.maguire@oracle.com, Eduard Zingerman Subject: [RFC v2 3/3] selftests/bpf: verify bpftool emits preserve_static_offset Date: Tue, 12 Dec 2023 04:31:36 +0200 Message-ID: <20231212023136.7021-4-eddyz87@gmail.com> X-Mailer: git-send-email 2.42.1 In-Reply-To: <20231212023136.7021-1-eddyz87@gmail.com> References: <20231212023136.7021-1-eddyz87@gmail.com> Precedence: bulk X-Mailing-List: bpf@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Patchwork-Delegate: bpf@iogearbox.net X-Patchwork-State: RFC Extend test_bpftool.py with following test cases: - Load a small program that has some context types in it's BTF, verify that "bpftool btf dump file ... format c" emits preserve_static_offset attribute. - Load a small program that has no context types in it's BTF, verify that "bpftool btf dump file ... format c" does not emit preserve_static_offset attribute. Signed-off-by: Eduard Zingerman --- .../bpf/progs/dummy_no_context_btf.c | 12 ++++ .../selftests/bpf/progs/dummy_sk_buff_user.c | 14 +++++ tools/testing/selftests/bpf/test_bpftool.py | 61 +++++++++++++++++++ 3 files changed, 87 insertions(+) create mode 100644 tools/testing/selftests/bpf/progs/dummy_no_context_btf.c create mode 100644 tools/testing/selftests/bpf/progs/dummy_sk_buff_user.c diff --git a/tools/testing/selftests/bpf/progs/dummy_no_context_btf.c b/tools/testing/selftests/bpf/progs/dummy_no_context_btf.c new file mode 100644 index 000000000000..5a1df4984dce --- /dev/null +++ b/tools/testing/selftests/bpf/progs/dummy_no_context_btf.c @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include + +/* A dummy program that does not reference context types in it's BTF */ +SEC("tc") +__u32 dummy_prog(void *ctx) +{ + return 0; +} + +char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/dummy_sk_buff_user.c b/tools/testing/selftests/bpf/progs/dummy_sk_buff_user.c new file mode 100644 index 000000000000..f271881bcbd0 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/dummy_sk_buff_user.c @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include + +/* A dummy program that references __sk_buff type in it's BTF, + * used by test_bpftool.py. + */ +SEC("tc") +int sk_buff_user(struct __sk_buff *skb) +{ + return 0; +} + +char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/test_bpftool.py b/tools/testing/selftests/bpf/test_bpftool.py index 1c2408ee1f5d..3117f431dd92 100644 --- a/tools/testing/selftests/bpf/test_bpftool.py +++ b/tools/testing/selftests/bpf/test_bpftool.py @@ -8,6 +8,7 @@ import os import socket import subprocess import unittest +import io # Add the source tree of bpftool and /usr/local/sbin to PATH @@ -25,6 +26,10 @@ class UnprivilegedUserError(Exception): pass +class MissingDependencyError(Exception): + pass + + def _bpftool(args, json=True): _args = ["bpftool"] if json: @@ -63,12 +68,22 @@ DMESG_EMITTING_HELPERS = [ "bpf_trace_vprintk", ] +DUMMY_SK_BUFF_USER_OBJ = cur_dir + "/dummy_sk_buff_user.bpf.o" +DUMMY_NO_CONTEXT_BTF_OBJ = cur_dir + "/dummy_no_context_btf.bpf.o" + class TestBpftool(unittest.TestCase): @classmethod def setUpClass(cls): if os.getuid() != 0: raise UnprivilegedUserError( "This test suite needs root privileges") + objs = [DUMMY_SK_BUFF_USER_OBJ, + DUMMY_NO_CONTEXT_BTF_OBJ] + for obj in objs: + if os.path.exists(obj): + continue + raise MissingDependencyError( + "File " + obj + " does not exist, make sure progs/*.c are compiled") @default_iface def test_feature_dev_json(self, iface): @@ -172,3 +187,49 @@ class TestBpftool(unittest.TestCase): res = bpftool(["feature", "probe", "macros"]) for pattern in expected_patterns: self.assertRegex(res, pattern) + + def assertStringsPresent(self, text, patterns): + pos = 0 + for i, pat in enumerate(patterns): + m = text.find(pat, pos) + if m == -1: + with io.StringIO() as msg: + print("Can't find expected string:", file=msg) + for s in patterns[0:i]: + print(" MATCHED: " + s, file=msg) + print("NOT MATCHED: " + pat, file=msg) + print("", file=msg) + print("Searching in:", file=msg) + print(text, file=msg) + self.fail(msg.getvalue()) + pos += len(pat) + + # Load a small program that has some context types in it's BTF, + # verify that "bpftool btf dump file ... format c" emits + # preserve_static_offset attribute. + def test_c_dump_preserve_static_offset_present(self): + res = bpftool(["btf", "dump", "file", DUMMY_SK_BUFF_USER_OBJ, "format", "c"]) + self.assertStringsPresent(res, [ + "#if !defined(BPF_NO_PRESERVE_STATIC_OFFSET) && " + + "__has_attribute(preserve_static_offset)", + "#pragma clang attribute push " + + "(__attribute__((preserve_static_offset)), apply_to = record)", + "struct __sk_buff;", + "struct bpf_sock;", + "#pragma clang attribute pop", + "#endif /* BPF_NO_PRESERVE_STATIC_OFFSET */", + "#pragma clang attribute push " + + "(__attribute__((preserve_access_index)), apply_to = record)", + "struct __sk_buff {", + ]) + + # Load a small program that has no context types in it's BTF, + # verify that "bpftool btf dump file ... format c" does not emit + # preserve_static_offset attribute. + def test_c_dump_no_preserve_static_offset(self): + res = bpftool(["btf", "dump", "file", DUMMY_NO_CONTEXT_BTF_OBJ, "format", "c"]) + self.assertNotRegex(res, "preserve_static_offset") + self.assertStringsPresent(res, [ + "preserve_access_index", + "typedef unsigned int __u32;" + ])