diff mbox series

[bpf,1/2] bpf: Add dummy type reference to nf_conn___init to fix type deduplication

Message ID 20221130144240.603803-1-toke@redhat.com (mailing list archive)
State Superseded
Delegated to: BPF
Headers show
Series [bpf,1/2] bpf: Add dummy type reference to nf_conn___init to fix type deduplication | expand

Checks

Context Check Description
bpf/vmtest-bpf-PR fail PR summary
bpf/vmtest-bpf-VM_Test-1 success Logs for ${{ matrix.test }} on ${{ matrix.arch }} with ${{ matrix.toolchain }}
bpf/vmtest-bpf-VM_Test-2 success Logs for ShellCheck
bpf/vmtest-bpf-VM_Test-3 fail Logs for build for aarch64 with gcc
bpf/vmtest-bpf-VM_Test-4 fail Logs for build for aarch64 with llvm-16
bpf/vmtest-bpf-VM_Test-5 fail Logs for build for s390x with gcc
bpf/vmtest-bpf-VM_Test-6 fail Logs for build for x86_64 with gcc
bpf/vmtest-bpf-VM_Test-7 fail Logs for build for x86_64 with llvm-16
bpf/vmtest-bpf-VM_Test-8 success Logs for llvm-toolchain
bpf/vmtest-bpf-VM_Test-9 success Logs for set-matrix
netdev/tree_selection success Clearly marked for bpf
netdev/fixes_present success Fixes tag present in non-next series
netdev/subject_prefix success Link
netdev/cover_letter success Single patches do not need cover letters
netdev/patch_count success Link
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 23 this patch: 23
netdev/cc_maintainers success CCed 19 of 19 maintainers
netdev/build_clang success Errors and warnings before: 5 this patch: 5
netdev/module_param success Was 0 now: 0
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success Fixes tag looks correct
netdev/build_allmodconfig_warn success Errors and warnings before: 23 this patch: 23
netdev/checkpatch success total: 0 errors, 0 warnings, 0 checks, 24 lines checked
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0

Commit Message

Toke Høiland-Jørgensen Nov. 30, 2022, 2:42 p.m. UTC
The bpf_ct_set_nat_info() kfunc is defined in the nf_nat.ko module, and
takes as a parameter the nf_conn___init struct, which is allocated through
the bpf_xdp_ct_alloc() helper defined in the nf_conntrack.ko module.
However, because kernel modules can't deduplicate BTF types between each
other, and the nf_conn___init struct is not referenced anywhere in vmlinux
BTF, this leads to two distinct BTF IDs for the same type (one in each
module). This confuses the verifier, as described here:

https://lore.kernel.org/all/87leoh372s.fsf@toke.dk/

As a workaround, add a dummy pointer to the type in net/filter.c, so the
type definition gets included in vmlinux BTF. This way, both modules can
refer to the same type ID (as they both build on top of vmlinux BTF), and
the verifier is no longer confused.

Fixes: 820dc0523e05 ("net: netfilter: move bpf_ct_set_nat_info kfunc in nf_nat_bpf.c")
Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com>
---
 net/core/filter.c | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

Comments

Yonghong Song Dec. 1, 2022, 1:16 a.m. UTC | #1
On 11/30/22 6:42 AM, Toke Høiland-Jørgensen wrote:
> The bpf_ct_set_nat_info() kfunc is defined in the nf_nat.ko module, and
> takes as a parameter the nf_conn___init struct, which is allocated through
> the bpf_xdp_ct_alloc() helper defined in the nf_conntrack.ko module.
> However, because kernel modules can't deduplicate BTF types between each
> other, and the nf_conn___init struct is not referenced anywhere in vmlinux
> BTF, this leads to two distinct BTF IDs for the same type (one in each
> module). This confuses the verifier, as described here:
> 
> https://lore.kernel.org/all/87leoh372s.fsf@toke.dk/

We might have similar issues later for other types.
Not sure whether the root cause is in libbpf or verifier. But we know
the kfunc from (module, btf_id), so for arguments, we could first
search the corresponding module and then vmlinux for btf_id matching?
This way we might fix potential other cases?

> 
> As a workaround, add a dummy pointer to the type in net/filter.c, so the
> type definition gets included in vmlinux BTF. This way, both modules can
> refer to the same type ID (as they both build on top of vmlinux BTF), and
> the verifier is no longer confused.
> 
> Fixes: 820dc0523e05 ("net: netfilter: move bpf_ct_set_nat_info kfunc in nf_nat_bpf.c")
> Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com>
> ---
>   net/core/filter.c | 15 +++++++++++++++
>   1 file changed, 15 insertions(+)
> 
> diff --git a/net/core/filter.c b/net/core/filter.c
> index bb0136e7a8e4..1bdf9efe8593 100644
> --- a/net/core/filter.c
> +++ b/net/core/filter.c
> @@ -80,6 +80,7 @@
>   #include <net/tls.h>
>   #include <net/xdp.h>
>   #include <net/mptcp.h>
> +#include <net/netfilter/nf_conntrack_bpf.h>
>   
>   static const struct bpf_func_proto *
>   bpf_sk_base_func_proto(enum bpf_func_id func_id);
> @@ -11531,3 +11532,17 @@ bpf_sk_base_func_proto(enum bpf_func_id func_id)
>   
>   	return func;
>   }
> +
> +#if IS_MODULE(CONFIG_NF_CONNTRACK) && IS_ENABLED(CONFIG_DEBUG_INFO_BTF_MODULES)
> +/* The nf_conn___init type is used in the NF_CONNTRACK kfuncs. The kfuncs are
> + * defined in two different modules, and we want to be able to use them
> + * interchangably with the same BTF type ID. Because modules can't de-duplicate
> + * BTF IDs between each other, we need the type to be referenced in the vmlinux
> + * BTF or the verifier will get confused about the different types. So we add
> + * this dummy pointer to serve as a type reference which will be included in
> + * vmlinux BTF, allowing both modules to refer to the same type ID.
> + *
> + * We use a pointer as that is smaller than an instance of the struct.
> + */
> +const struct nf_conn___init *ctinit;
> +#endif
Andrii Nakryiko Dec. 1, 2022, 1:16 a.m. UTC | #2
On Wed, Nov 30, 2022 at 6:42 AM Toke Høiland-Jørgensen <toke@redhat.com> wrote:
>
> The bpf_ct_set_nat_info() kfunc is defined in the nf_nat.ko module, and
> takes as a parameter the nf_conn___init struct, which is allocated through
> the bpf_xdp_ct_alloc() helper defined in the nf_conntrack.ko module.
> However, because kernel modules can't deduplicate BTF types between each
> other, and the nf_conn___init struct is not referenced anywhere in vmlinux
> BTF, this leads to two distinct BTF IDs for the same type (one in each
> module). This confuses the verifier, as described here:
>

Argh, shouldn't have wasted writing [1], but oh well.

  [1] https://lore.kernel.org/bpf/CAEf4Bza2xDZ45kxxa3dg1C_RWE=UB5UFYEuFp6rbXgX=LRHv-A@mail.gmail.com/

> https://lore.kernel.org/all/87leoh372s.fsf@toke.dk/
>
> As a workaround, add a dummy pointer to the type in net/filter.c, so the
> type definition gets included in vmlinux BTF. This way, both modules can
> refer to the same type ID (as they both build on top of vmlinux BTF), and
> the verifier is no longer confused.
>
> Fixes: 820dc0523e05 ("net: netfilter: move bpf_ct_set_nat_info kfunc in nf_nat_bpf.c")
> Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com>
> ---
>  net/core/filter.c | 15 +++++++++++++++
>  1 file changed, 15 insertions(+)
>
> diff --git a/net/core/filter.c b/net/core/filter.c
> index bb0136e7a8e4..1bdf9efe8593 100644
> --- a/net/core/filter.c
> +++ b/net/core/filter.c
> @@ -80,6 +80,7 @@
>  #include <net/tls.h>
>  #include <net/xdp.h>
>  #include <net/mptcp.h>
> +#include <net/netfilter/nf_conntrack_bpf.h>
>
>  static const struct bpf_func_proto *
>  bpf_sk_base_func_proto(enum bpf_func_id func_id);
> @@ -11531,3 +11532,17 @@ bpf_sk_base_func_proto(enum bpf_func_id func_id)
>
>         return func;
>  }
> +
> +#if IS_MODULE(CONFIG_NF_CONNTRACK) && IS_ENABLED(CONFIG_DEBUG_INFO_BTF_MODULES)
> +/* The nf_conn___init type is used in the NF_CONNTRACK kfuncs. The kfuncs are
> + * defined in two different modules, and we want to be able to use them
> + * interchangably with the same BTF type ID. Because modules can't de-duplicate
> + * BTF IDs between each other, we need the type to be referenced in the vmlinux
> + * BTF or the verifier will get confused about the different types. So we add
> + * this dummy pointer to serve as a type reference which will be included in
> + * vmlinux BTF, allowing both modules to refer to the same type ID.
> + *
> + * We use a pointer as that is smaller than an instance of the struct.
> + */
> +const struct nf_conn___init *ctinit;
> +#endif

Use BTF_TYPE_EMIT() instead maybe?

> --
> 2.38.1
>
Toke Høiland-Jørgensen Dec. 1, 2022, 11:06 a.m. UTC | #3
Andrii Nakryiko <andrii.nakryiko@gmail.com> writes:

> On Wed, Nov 30, 2022 at 6:42 AM Toke Høiland-Jørgensen <toke@redhat.com> wrote:
>>
>> The bpf_ct_set_nat_info() kfunc is defined in the nf_nat.ko module, and
>> takes as a parameter the nf_conn___init struct, which is allocated through
>> the bpf_xdp_ct_alloc() helper defined in the nf_conntrack.ko module.
>> However, because kernel modules can't deduplicate BTF types between each
>> other, and the nf_conn___init struct is not referenced anywhere in vmlinux
>> BTF, this leads to two distinct BTF IDs for the same type (one in each
>> module). This confuses the verifier, as described here:
>>
>
> Argh, shouldn't have wasted writing [1], but oh well.
>
>   [1] https://lore.kernel.org/bpf/CAEf4Bza2xDZ45kxxa3dg1C_RWE=UB5UFYEuFp6rbXgX=LRHv-A@mail.gmail.com/

Ah, yeah, crossed streams; as you can see I came to the same conclusion
wrt types being conceptually independent.

>> https://lore.kernel.org/all/87leoh372s.fsf@toke.dk/
>>
>> As a workaround, add a dummy pointer to the type in net/filter.c, so the
>> type definition gets included in vmlinux BTF. This way, both modules can
>> refer to the same type ID (as they both build on top of vmlinux BTF), and
>> the verifier is no longer confused.
>>
>> Fixes: 820dc0523e05 ("net: netfilter: move bpf_ct_set_nat_info kfunc in nf_nat_bpf.c")
>> Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com>
>> ---
>>  net/core/filter.c | 15 +++++++++++++++
>>  1 file changed, 15 insertions(+)
>>
>> diff --git a/net/core/filter.c b/net/core/filter.c
>> index bb0136e7a8e4..1bdf9efe8593 100644
>> --- a/net/core/filter.c
>> +++ b/net/core/filter.c
>> @@ -80,6 +80,7 @@
>>  #include <net/tls.h>
>>  #include <net/xdp.h>
>>  #include <net/mptcp.h>
>> +#include <net/netfilter/nf_conntrack_bpf.h>
>>
>>  static const struct bpf_func_proto *
>>  bpf_sk_base_func_proto(enum bpf_func_id func_id);
>> @@ -11531,3 +11532,17 @@ bpf_sk_base_func_proto(enum bpf_func_id func_id)
>>
>>         return func;
>>  }
>> +
>> +#if IS_MODULE(CONFIG_NF_CONNTRACK) && IS_ENABLED(CONFIG_DEBUG_INFO_BTF_MODULES)
>> +/* The nf_conn___init type is used in the NF_CONNTRACK kfuncs. The kfuncs are
>> + * defined in two different modules, and we want to be able to use them
>> + * interchangably with the same BTF type ID. Because modules can't de-duplicate
>> + * BTF IDs between each other, we need the type to be referenced in the vmlinux
>> + * BTF or the verifier will get confused about the different types. So we add
>> + * this dummy pointer to serve as a type reference which will be included in
>> + * vmlinux BTF, allowing both modules to refer to the same type ID.
>> + *
>> + * We use a pointer as that is smaller than an instance of the struct.
>> + */
>> +const struct nf_conn___init *ctinit;
>> +#endif
>
> Use BTF_TYPE_EMIT() instead maybe?

Ah, TIL about that macro; thanks, will fix!

-Toke
diff mbox series

Patch

diff --git a/net/core/filter.c b/net/core/filter.c
index bb0136e7a8e4..1bdf9efe8593 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -80,6 +80,7 @@ 
 #include <net/tls.h>
 #include <net/xdp.h>
 #include <net/mptcp.h>
+#include <net/netfilter/nf_conntrack_bpf.h>
 
 static const struct bpf_func_proto *
 bpf_sk_base_func_proto(enum bpf_func_id func_id);
@@ -11531,3 +11532,17 @@  bpf_sk_base_func_proto(enum bpf_func_id func_id)
 
 	return func;
 }
+
+#if IS_MODULE(CONFIG_NF_CONNTRACK) && IS_ENABLED(CONFIG_DEBUG_INFO_BTF_MODULES)
+/* The nf_conn___init type is used in the NF_CONNTRACK kfuncs. The kfuncs are
+ * defined in two different modules, and we want to be able to use them
+ * interchangably with the same BTF type ID. Because modules can't de-duplicate
+ * BTF IDs between each other, we need the type to be referenced in the vmlinux
+ * BTF or the verifier will get confused about the different types. So we add
+ * this dummy pointer to serve as a type reference which will be included in
+ * vmlinux BTF, allowing both modules to refer to the same type ID.
+ *
+ * We use a pointer as that is smaller than an instance of the struct.
+ */
+const struct nf_conn___init *ctinit;
+#endif