All of lore.kernel.org
 help / color / mirror / Atom feed
From: Yonghong Song <yonghong.song@linux.dev>
To: Eduard Zingerman <eddyz87@gmail.com>,
	bpf@vger.kernel.org, ast@kernel.org
Cc: andrii@kernel.org, daniel@iogearbox.net, martin.lau@linux.dev,
	kernel-team@fb.com, jose.marchesi@oracle.com
Subject: Re: [PATCH bpf-next 0/1] use preserve_static_offset in bpf uapi headers
Date: Thu, 7 Dec 2023 18:28:06 -0800	[thread overview]
Message-ID: <012efc61-e067-4c21-8cab-47dec9bbaf0c@linux.dev> (raw)
In-Reply-To: <20231208000531.19179-1-eddyz87@gmail.com>


On 12/7/23 4:05 PM, Eduard Zingerman wrote:
> For certain program context types, the verifier applies the
> verifier.c:convert_ctx_access() transformation.
> It modifies ST/STX/LDX instructions that access program context.
> convert_ctx_access() updates the offset field of these instructions
> changing "virtual" offset by offset corresponding to data
> representation in the running kernel.
>
> For this transformation to be applicable access to the context field
> shouldn't use pointer arithmetics. For example, consider the read of
> __sk_buff->pkt_type field.
> If translated as a single ST instruction:
>
>      r0 = *(u32 *)(r1 + 4);
>
> The verifier would accept such code and patch the offset in the
> instruction, however, if translated as a pair of instructions:
>
>      r1 += 4;
>      r0 = *(u32 *)(r1 + 0);
>
> The verifier would reject such code.
>
> Occasionally clang shuffling code during compilation might break
> verifier expectations and cause verification errors, e.g. as in [0].
> Technically, this happens because each field read/write represented in
> LLVM IR as two operations: address lookup + memory access,
> and the compiler is free to move and substitute those independently.
> For example, LLVM can rewrite C code below:
>
>      __u32 v;
>      if (...)
>        v = sk_buff->pkt_type;
>      else
>        v = sk_buff->mark;
>
> As if it was written as so:
>
>      __u32 v, *p;
>      if (...)
>        p = &sk_buff->pkt_type;  // r0 = 4; (offset of pkt_type)
>      else
>        p = &sk_buff->mark;      // r0 = 8; (offset of mark)
>      v = *p;                    // r1 += r0;
>                                 // r0 = *(u32 *)(r1 + 0)
>
> Which is a valid rewrite from the point of view of C semantics but won't
> pass verification, because convert_ctx_access() can no longer replace
> offset in 'r0 = *(u32 *)(r1 + 0)' with a constant.
>
> Recently, attribute preserve_static_offset was added to
> clang [1] to tackle this problem. From its documentation:
>
>    Clang supports the ``__attribute__((preserve_static_offset))``
>    attribute for the BPF target. This attribute may be attached to a
>    struct or union declaration. Reading or writing fields of types having
>    such annotation is guaranteed to generate LDX/ST/STX instruction with
>    an offset corresponding to the field.
>
> The convert_ctx_access() transformation is applied when the context
> parameter has one of the following types:
> - __sk_buff
> - bpf_cgroup_dev_ctx
> - bpf_perf_event_data
> - bpf_sk_lookup
> - bpf_sock
> - bpf_sock_addr
> - bpf_sock_ops
> - bpf_sockopt
> - bpf_sysctl
> - sk_msg_md
> - sk_reuseport_md
> - xdp_md

All context types are defined in include/linux/bpf_types.h.
The context type bpf_nf_ctx is missing.

>
>  From my understanding, BPF programs typically access definitions of
> these types in two ways:
> - via uapi headers linux/bpf.h and linux/bpf_perf_event.h;

and bpf_nf_ctx is defined in include/net/netfilter/nf_bpf_link.h
and rely on vmlinux.h to provide the ctx struct definition.

> - via vmlinux.h.
>
> This RFC seeks to mark with preserve_static_offset the definitions of
> the relevant context types within uapi headers.
>
> The attribute is abstracted by '__bpf_ctx' macro.
> As bpf.h and bpf_perf_event.h do not share any common include files,
> this RFC opts to copy the same definition of '__bpf_ctx' in both
> headers to avoid adding a new uapi header.
> (Another tempting location for '__bpf_ctx' is compiler_types.h /
>   compiler-clang.h, but these headers are not exported as uapi).

Previously I think we might use similar mechanism like vmlinux.h
with push/pop preserve_static_offset attributes. But looks like
there are many other structures in uapi bpf.h do not need
preserve_static_offset. So I think your approach sounds okay.

>
> How to add the same definitions in vmlinux.h is an open question,
> and most likely requires bpftool modification:
> - Hard code generation of __bpf_ctx based on type names?
> - Mark context types with some special
>    __attribute__((btf_decl_tag("preserve_static_offset")))
>    and convert it to __attribute__((preserve_static_offset))?

The number of context types is limited, I would just go through
the first approach with hard coding the list of ctx types and
mark them with preserve_static_offset attribute in vmlinux.h.

>
> Please suggest if any of the options above sound reasonable.
>
> [0] https://lore.kernel.org/bpf/CAA-VZPmxh8o8EBcJ=m-DH4ytcxDFmo0JKsm1p1gf40kS0CE3NQ@mail.gmail.com/T/#m4b9ce2ce73b34f34172328f975235fc6f19841b6
> [1] 030b8cb1561d ("[BPF] Attribute preserve_static_offset for structs")
>      git@github.com:llvm/llvm-project.git
>
> Eduard Zingerman (1):
>    bpf: Mark virtual BPF context structures as preserve_static_offset
>
>   include/uapi/linux/bpf.h                  | 28 ++++++++++++++---------
>   include/uapi/linux/bpf_perf_event.h       |  8 ++++++-
>   tools/include/uapi/linux/bpf.h            | 28 ++++++++++++++---------
>   tools/include/uapi/linux/bpf_perf_event.h |  8 ++++++-
>   4 files changed, 48 insertions(+), 24 deletions(-)
>

  parent reply	other threads:[~2023-12-08  2:28 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-12-08  0:05 [PATCH bpf-next 0/1] use preserve_static_offset in bpf uapi headers Eduard Zingerman
2023-12-08  0:05 ` [PATCH bpf-next 1/1] bpf: Mark virtual BPF context structures as preserve_static_offset Eduard Zingerman
2023-12-08  3:36   ` Yonghong Song
2023-12-08 14:23     ` Eduard Zingerman
2023-12-08  2:28 ` Yonghong Song [this message]
2023-12-08 14:34   ` [PATCH bpf-next 0/1] use preserve_static_offset in bpf uapi headers Eduard Zingerman
2023-12-08 17:19     ` Yonghong Song
2023-12-08 20:54       ` Eduard Zingerman
2023-12-08 17:30     ` Yonghong Song
2023-12-08 17:46       ` Alexei Starovoitov
2023-12-08 20:35         ` Eduard Zingerman
2023-12-08 12:27 ` Alan Maguire
2023-12-08 14:21   ` Eduard Zingerman
2023-12-08 15:35     ` Alan Maguire
2023-12-08 15:39       ` Eduard Zingerman

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=012efc61-e067-4c21-8cab-47dec9bbaf0c@linux.dev \
    --to=yonghong.song@linux.dev \
    --cc=andrii@kernel.org \
    --cc=ast@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=daniel@iogearbox.net \
    --cc=eddyz87@gmail.com \
    --cc=jose.marchesi@oracle.com \
    --cc=kernel-team@fb.com \
    --cc=martin.lau@linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.