From: Yonghong Song <yhs@fb.com>
To: Tony Ambardar <tony.ambardar@gmail.com>
Cc: bpf <bpf@vger.kernel.org>, <linux-mips@vger.kernel.org>,
Alexei Starovoitov <ast@kernel.org>,
Daniel Borkmann <daniel@iogearbox.net>,
Andrii Nakryiko <andrii@kernel.org>
Subject: Re: Kernel Oops in test_verifier "#828/p reference tracking: bpf_sk_release(btf_tcp_sock)"
Date: Tue, 15 Jun 2021 22:55:04 -0700 [thread overview]
Message-ID: <f888e1ef-acef-2b3d-3ac8-06a051f979d7@fb.com> (raw)
In-Reply-To: <CAPGftE8d03K4_S1pTyRVWZL7w67FukES_PV8SR=0_6DXhXzjQw@mail.gmail.com>
On 6/15/21 7:21 PM, Tony Ambardar wrote:
> On Sun, 13 Jun 2021 at 23:14, Yonghong Song <yhs@fb.com> wrote:
>>
>> On 6/12/21 5:07 PM, Tony Ambardar wrote:
>>> On Fri, 11 Jun 2021 at 08:57, Yonghong Song <yhs@fb.com> wrote:
>>>>
>>>> On 6/10/21 6:02 PM, Tony Ambardar wrote:
>>>>> Hello,
>>>>>
>>>>> I encountered an NPE and kernel Oops [1] while running the
>>>>> 'test_verifier' selftest on MIPS32 with LTS kernel 5.10.41. This was
>>>>> observed during development of a MIPS32 JIT but is verifier-related.
>>>>>
>>>>> Initial troubleshooting [2] points to an unchecked NULL dereference in
>>>>> btf_type_by_id(), with an unexpected BTF type ID. The root cause is
>>>>> unclear, whether source of the ID or a potential underlying BTF
>>>>> problem.
>>>>
>>>> Do you know what is the faulty btf ID number? What is the maximum id
>>>> for vmlinux BTF?
>>>
>>> Thanks for the suggestions, Yonghong.
>>>
>>> I had built/packaged bpftool for the target, which shows the maximum as:
>>>
>>> root@OpenWrt:~# bpftool btf dump file /sys/kernel/btf/vmlinux format
>>> raw|tail -5
>>> [43179] FUNC 'pci_load_of_ranges' type_id=43178 linkage=static
>>> [43180] ARRAY '(anon)' type_id=23 index_type_id=23 nr_elems=16
>>> [43181] FUNC 'pcibios_plat_dev_init' type_id=29264 linkage=static
>>> [43182] FUNC 'pcibios_map_irq' type_id=29815 linkage=static
>>> [43183] FUNC 'mips_pcibios_init' type_id=115 linkage=static
>>>
>>> After adding NULL handling and debug pr_err() to kernel_type_name(), I next see:
>>>
>>> root@OpenWrt:~# ./test_verifier_eb 828
>>> [ 87.196692] btf_type_by_id(btf_vmlinux, 3062497280) returns NULL
>>> [ 87.196958] btf_type_by_id(btf_vmlinux, 2936995840) returns NULL
>>> #828/p reference tracking: bpf_sk_release(btf_tcp_sock) FAIL
>>>
>>> Those large type ids make me suspect an endianness issue, even though bpftool
>>> can still properly access the vmlinux BTF. Changing byte order and
>>> looking up the
>>> resulting type ids seems to confirm this:
>>>
>>> Check endianness:
>>> 3062497280 -> 0xB68A0000 --swap endian--> 0x00008AB6 -> 35510
>>> bpftool btf dump file /sys/kernel/btf/vmlinux format raw|fgrep "[35510]":
>>> [35510] STRUCT 'tcp_sock' size=1752 vlen=136
>>>
>>> Check endianness:
>>> 2936995840 -> 0xAF0F0000 --swap endian--> 0x00000FAF -> 4015
>>> bpftool btf dump file /sys/kernel/btf/vmlinux format raw|fgrep "[4015]":
>>> [4015] STRUCT 'sock_common' size=112 vlen=25
>>>
>>> As a further test, I repeated "test_verifier 828" across mips{32,64}{be,le}
>>> systems and confirm seeing the problem only with the big-endian ones.
>>
>> From the above information, looks like vmlinux BTF is correct.
>> Below resolve_btfids command output seems indicating the btf_id list
>> is also correct.
>>
>> The kernel_type_name is used in a few places for verifier verbose output.
>>
>> $ grep kernel_type_name kernel/bpf/verifier.c
>> static const char *kernel_type_name(const struct btf* btf, u32 id)
>> verbose(env, "%s",
>> kernel_type_name(reg->btf, reg->btf_id));
>> regno, kernel_type_name(reg->btf,
>> reg->btf_id),
>> kernel_type_name(btf_vmlinux,
>> *arg_btf_id));
>>
>> The most suspicous target is reg->btf_id, which is propagated from
>> the result of bpf_sk_lookup_tcp() helper.
>>
>>>
>>>> The involved helper is bpf_sk_release.
>>>>
>>>> static const struct bpf_func_proto bpf_sk_release_proto = {
>>>> .func = bpf_sk_release,
>>>> .gpl_only = false,
>>>> .ret_type = RET_INTEGER,
>>>> .arg1_type = ARG_PTR_TO_BTF_ID_SOCK_COMMON,
>>>> };
>>>>
>>>> Eventually, the btf_id is taken from btf_sock_ids[6] where
>>>> btf_sock_ids is a kernel global variable.
>>>>
>>>> Could you check btf_sock_ids[6] to see whether the number
>>>> makes sense?
>>>
>>> What I see matches the second btf_type_by_id() NULL call above:
>>> [ 56.556121] btf_sock_ids[6]: 2936995840
>>>
>>>> The id is computed by resolve_btfids in
>>>> tools/bpf/resolve_btfids, you might add verbose mode to your linux build
>>>> to get more information.
>>>
>>> The verbose build didn't print any details of the btf ids. Was there anything
>>> special to do in invocation? I manually ran "resolve_btfids -v vmlinux" from
>>> the build dir and this, strangely, gave slightly different results than bpftool
>>> but not the huge endian-swapped type ids. Is this expected?
>>>
>>> # ./tools/bpf/resolve_btfids/resolve_btfids -v vmlinux
>>> ...
>>> patching addr 116: ID 35522 [tcp_sock]
>>> ...
>>> patching addr 112: ID 4021 [sock_common]
>>>
>>> Do any of the details above help narrow down things? What do you suggest
>>> for next steps?
>>
>> We need to identify issues by dumping detailed verifier logs.
>> Could you apply the following change?
>>
>> --- a/tools/testing/selftests/bpf/test_verifier.c
>> +++ b/tools/testing/selftests/bpf/test_verifier.c
>> @@ -1088,7 +1088,7 @@ static void do_test_single(struct bpf_test *test,
>> bool unpriv,
>> attr.insns_cnt = prog_len;
>> attr.license = "GPL";
>> if (verbose)
>> - attr.log_level = 1;
>> + attr.log_level = 3;
>> else if (expected_ret == VERBOSE_ACCEPT)
>> attr.log_level = 2;
>> else
>>
>> Run command like `./test_verifier -v 828 828`?
>>
>> I attached the verifier output for x86_64.
>> Maybe by comparing x86 output vs. mips32 output, you can
>> find which insn starts to have *wrong* verifier state
>> and then we can go from there.
>
> I realized too late your test output must be for a different kernel version as
> well as arch, as the test numbering is different and doesn't match my test:
> "reference tracking: bpf_sk_release(btf_tcp_sock)".
>
> Given the problem is seen on big-endian and not little-systems, I applied
> your patch for both mips32 variant systems and recaptured log output,
> which should make for a stricter A/B comparison. I also kept my earlier
> patches to catch the NULLs and print debug info.
>
> The logs are identical until insn #18, where the failing MIPS32BE shows:
>
> 18: R0_w=ptr_or_null_(null)(id=3,off=0,imm=0)
> R6_w=sock(id=0,ref_obj_id=2,off=0,imm=0) R10=fp0 fp-8=????0000
> fp-16=0000mmmm fp-24=mmmmmmmm fp-32=mmmmmmmm fp-40=mmmmmmmm
> fp-48=mmmmmmmm refs=2
>
> while the succeed MIPS32LE test shows:
>
> 18: R0_w=ptr_or_null_tcp_sock(id=3,off=0,imm=0)
> R6_w=sock(id=0,ref_obj_id=2,off=0,imm=0) R10=fp0 fp-8=????0000
> fp-16=0000mmmm fp-24=mmmmmmmm fp-32=mmmmmmmm fp-40=mmmmmmmm
> fp-48=mmmmmmmm refs=2
>
> There are then further differences you can see in the attached logs. It's
> not clear to me what these differences mean however. Any ideas?
The above R0_w is to capture the return value for bpf_skc_to_tcp_sock()
const struct bpf_func_proto bpf_skc_to_tcp_sock_proto = {
.func = bpf_skc_to_tcp_sock,
.gpl_only = false,
.ret_type = RET_PTR_TO_BTF_ID_OR_NULL,
.arg1_type = ARG_PTR_TO_BTF_ID_SOCK_COMMON,
.ret_btf_id = &btf_sock_ids[BTF_SOCK_TYPE_TCP],
};
From the above func_proto, it should return the btf_id for
btf_sock_ids[BTF_SOCK_TYPE_TCP].
It does like the root cause is still endianness of btf_sock_ids
written by resolve_btfids.
>
> Following your earlier comments on the large, endian-swapped values
> in btf_sock_ids[6], I noticed this is true of all btf_sock_ids[]
> elements, based on debug output:
>
> btf_sock_ids[0] = 2139684864
> btf_sock_ids[1] = 2794061824
> btf_sock_ids[2] = 2844459008
> btf_sock_ids[3] = 1234305024
> btf_sock_ids[4] = 3809411072
> btf_sock_ids[5] = 1946812416
> btf_sock_ids[6] = 2936995840
> btf_sock_ids[7] = 3062497280
> btf_sock_ids[8] = 2861236224
> btf_sock_ids[9] = 1251082240
> btf_sock_ids[10] = 1334968320
> btf_sock_ids[11] = 1267859456
> btf_sock_ids[12] = 1318191104
>
> If these are populated by resolve_btfids, how could we re-verify that
> it's being done properly?
>
>>>
>>> Thanks,
>>> Tony
>>>
[...]
prev parent reply other threads:[~2021-06-16 5:55 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-06-11 1:02 Kernel Oops in test_verifier "#828/p reference tracking: bpf_sk_release(btf_tcp_sock)" Tony Ambardar
2021-06-11 15:57 ` Yonghong Song
2021-06-13 0:07 ` Tony Ambardar
2021-06-14 6:14 ` Yonghong Song
2021-06-16 2:21 ` Tony Ambardar
2021-06-16 3:38 ` Tony Ambardar
2021-06-16 6:13 ` Yonghong Song
2021-06-16 5:55 ` Yonghong Song [this message]
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=f888e1ef-acef-2b3d-3ac8-06a051f979d7@fb.com \
--to=yhs@fb.com \
--cc=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=daniel@iogearbox.net \
--cc=linux-mips@vger.kernel.org \
--cc=tony.ambardar@gmail.com \
/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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox