All of lore.kernel.org
 help / color / mirror / Atom feed
From: Yonghong Song <yhs@fb.com>
To: Andrii Nakryiko <andrii.nakryiko@gmail.com>
Cc: Tal Lossos <tallossos@gmail.com>, bpf <bpf@vger.kernel.org>
Subject: Re: Verification error on bpf_map_lookup_elem with BPF_CORE_READ
Date: Wed, 5 Jan 2022 23:37:09 -0800	[thread overview]
Message-ID: <7199e14f-da44-bdbb-4cab-db802ce4f488@fb.com> (raw)
In-Reply-To: <CAEf4BzYHTLRarRrGK22JUsA6SO3HuvMfSgQVGGWmZdYeNE3RDA@mail.gmail.com>



On 1/5/22 8:36 PM, Andrii Nakryiko wrote:
> On Tue, Jan 4, 2022 at 9:18 PM Yonghong Song <yhs@fb.com> wrote:
>>
>>
>>
>> On 1/4/22 3:35 AM, Tal Lossos wrote:
>>> Hello!
>>> I’ve encountered a weird behaviour of verification error regarding
>>> using bpf_map_lookup_elem (specifically bpf_inode_storage_get in my
>>> use case) and BPF_CORE_READ as a key.
>>> For example, if I’m using an inode_storage map, and let’s say that I’m
>>> using a hook that has a dentry named “dentry” in the context, If I
>>> will try to use bpf_inode_storage_get, the only way I could do it is
>>> by passing dentry->d_inode as the key arg, and if I will try to do it
>>> in the CO-RE way by using BPF_CORE_READ(dentry, d_inode) as the key I
>>> will fail (because the key is a “inv” (scalar) and not “ptr_” -
>>> https://elixir.bootlin.com/linux/v5.11/source/kernel/bpf/bpf_inode_storage.c#L266  ):
>>> struct
>>> {
>>>       __uint(type, BPF_MAP_TYPE_INODE_STORAGE);
>>>       __uint(map_flags, BPF_F_NO_PREALLOC);
>>>       __type(key, int);
>>>       __type(value, value_t);
>>> } inode_storage_map SEC(".maps");
>>>
>>> SEC("lsm/inode_rename")
>>> int BPF_PROG(inode_rename, struct inode *old_dir, struct dentry *old_dentry,
>>>        struct inode *new_dir, struct dentry *new_dentry,
>>>        unsigned int flags)
>>> {
>>> struct value_t *storage;
>>>
>>> storage = bpf_inode_storage_get(&inode_storage_map,
>>> old_dentry->d_inode, 0, 0); // this will work
>>>     storage = bpf_inode_storage_get(&inode_storage_map,
>>> BPF_CORE_READ(old_dentry, d_inode), 0, 0); // this won't work
>>>       ...
>>> }
>>>   From a quick glimpse into the verifier sources I can assume that the
>>> BPF_CORE_READ macro (which calls bpf_core_read), returns a “scalar”
>>> (is it because ebpf helpers counts as “global functions”?) thus
>>> failing the verification.
>>> This behaviour is kind of weird because I would expect to be allowed
> 
> As Yonghong explained, BPF_CORE_READ() always returns unknown scalar
> that verifier cannot trust. All due to the underlying
> probe_read_kernel(). BPF_CORE_READ() was never supposed to work for
> such cases, it's not weird once you realize that BPF_CORE_READ() is
> able to probe read an arbitrary memory location.
> 
>>> to call bpf_inode_storage_get with the BPF_CORE_READ (’s output) as
>>> the key arg.
>>> May I have some clarification on this please?
>>
>> The reason is BPF_CORE_READ macro eventually used
>>     bpf_probe_read_kernel()
>> to read the the old_dentry->d_inode (adjusted after relocation).
>> The BTF_ID type information with read-result of bpf_probe_read_kernel()
>> is lost in verifier and that is why you hit the above verification
>> failure. CORE predates fentry/fexit so bpf_probe_read_kernel() is
>> used to relocatable kernel memory accesses.
>>
>> But now we have direct memory access.
>> To resolve the above issue, I think we might need libbpf to
>> directly modify the offset in the instruction based on
>> relocation records. For example, the original old_dentry->dinode
>> code looks like
>>       r1 = *(u64 *)(r2 + 32)
>> there will be a relocation against offset "32".
>> libbpf could directly adjust "32" based on relocation information.
> 
> I think libbpf supports that already. So if you use direct memory
> reads on dentry type marked with
> __attribute__((preserve_access_index)) it should work.

Oh, I missed this. If you use vmlinux.h, then CORE for 
old_dentry->d_inode is automatically covered since types in
vmlinux.h already have __attribute__((preserve_access_index)).
Otherwise, you need to define your own struct dentry with
added preserve_access_index attribute.

> 
>>
>>>
>>> Thanks.

      reply	other threads:[~2022-01-06  7:37 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-01-04 11:35 Verification error on bpf_map_lookup_elem with BPF_CORE_READ Tal Lossos
2022-01-04 18:24 ` Yonghong Song
2022-01-06  4:36   ` Andrii Nakryiko
2022-01-06  7:37     ` 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=7199e14f-da44-bdbb-4cab-db802ce4f488@fb.com \
    --to=yhs@fb.com \
    --cc=andrii.nakryiko@gmail.com \
    --cc=bpf@vger.kernel.org \
    --cc=tallossos@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 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.