mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Chen Zhongjin <chenzhongjin@huawei.com>
To: Yonghong Song <yhs@meta.com>, <bpf@vger.kernel.org>,
	<linux-kernel@vger.kernel.org>
Cc: <ast@kernel.org>, <daniel@iogearbox.net>,
	<john.fastabend@gmail.com>, <andrii@kernel.org>,
	<martin.lau@linux.dev>, <song@kernel.org>, <yhs@fb.com>,
	<kpsingh@kernel.org>, <sdf@google.com>, <haoluo@google.com>,
	<jolsa@kernel.org>
Subject: Re: [PATCH] bpf: Unregister fentry when bpf_trampoline_unlink_prog fails to update image
Date: Thu, 27 Apr 2023 09:40:50 +0800	[thread overview]
Message-ID: <be9efa60-14ec-ba46-91e1-9feb56c40fb8@huawei.com> (raw)
In-Reply-To: <b594a56f-5e1f-da7f-0ab1-71751bd0c5e2@meta.com>

On 2023/4/27 2:17, Yonghong Song wrote:
> 
> 
> On 4/26/23 2:55 AM, Chen Zhongjin wrote:
>> In bpf_link_free, bpf trampoline will update the image and remove the
>> unlinked prog.
>>
>> bpf_trampoline_unlink_prog is committed as 'never fail', however it 
>> depends
>> on the result of image update. It is possible to fail if memory 
>> allocation
>> fail in bpf_trampoline_update.
> 
> Could you give more details which memory allocation fail here?
> bpf_tramp_image_alloc()? Are you using some error injection or
> this happens in your production workload?
> 
I guess it's an error injection because syzkaller reported this.

>>
>> The error result of bpf_trampoline_update can't be passed to 
>> bpf_link_free
>> because link release callback returns void. Then it will free the prog
>> whether image updating is successful or not.
>> If the old image tries to call a freed prog, it makes kernel panic.
>>
>>      BUG: unable to handle page fault for address: ffffffffc04a8d20
>>      #PF: supervisor instruction fetch in kernel mode
>>      #PF: error_code(0x0010) - not-present page
>>      RIP: 0010:0xffffffffc04a8d20
>>      Code: Unable to access opcode bytes at RIP 0xffffffffc04a8cf6.
>>      ...
>>      Call Trace:
>>      ? bpf_trampoline_78223_0
>>      bpf_traced_function
>>      ...
> 
> Could you explain how 'the old image tries to call a freed prog'?
> IIUC, the previous bpf_link_free() should not be available to
> call the bpf prog, right?
> 
What I mean here is, if failed to update the image, the image keeps 
unchanged but the unlinked prog will be freed later.
Next time when it enter the trampoline the image will call freed prog.

>>
>> Fix this when bpf_trampoline_update failed in bpf_trampoline_unlink_prog,
>> unregister fentry to disable the trampoline. Then other progs on the
>> trampoline can be unlinked safely and finally the trampoline will be
>> released.
> 
> Do we still leak tr->cur_image here?
> 
No, bpf_tramp_image_put() will free everything when all progs_cnt 
decline to zero in bpf_trampoline_update(). It is a release function, 
but called 'put'.

>>
>> Fixes: 88fd9e5352fe ("bpf: Refactor trampoline update code")
> 
> If the above is a refactoring patch, you should not use that
> as 'Fixes' patch, you should pick one truely introduced the issue.
> 
>> Signed-off-by: Chen Zhongjin <chenzhongjin@huawei.com>
>> ---
>>   kernel/bpf/trampoline.c | 5 ++++-
>>   1 file changed, 4 insertions(+), 1 deletion(-)
>>
>> diff --git a/kernel/bpf/trampoline.c b/kernel/bpf/trampoline.c
>> index d0ed7d6f5eec..6daa93b30e81 100644
>> --- a/kernel/bpf/trampoline.c
>> +++ b/kernel/bpf/trampoline.c
>> @@ -604,7 +604,10 @@ static int __bpf_trampoline_unlink_prog(struct 
>> bpf_tramp_link *link, struct bpf_
>>       }
>>       hlist_del_init(&link->tramp_hlist);
>>       tr->progs_cnt[kind]--;
>> -    return bpf_trampoline_update(tr, true /* lock_direct_mutex */);
>> +    err =  bpf_trampoline_update(tr, true /* lock_direct_mutex */);
>> +    if (err && tr->cur_image)
>> +        unregister_fentry(tr, tr->cur_image->image);
> 
> If error happens for the all subsequent programs,
> unregister_fentry() will be called multiple times. Any side effect?
It will fail with no side effect. Actually if there is no error, 
modify_fentry() will fail in update() as well. The fentry is available 
until all progs are unlinked and the broken image is freed by 
bpf_tramp_image_put().

However with an extra state to record this happens, it's possible to 
re-register the fentry with new image when the next link/unlink calls 
update(). It will generate a new image and replace/free the error one.
> 
> Overall, I think this is an extreme corner case which happens
> when kernel memory is extreme tight. If this is the case, not
> sure whether it is worthwhile to fix it or not.
> 
Yes, it's a really rare case. I'm just not sure whether it needs some 
best-effort to avoid kernel panic at this point.

If you think it's not necessary. Just let it go.

Thanks for your time!

Best,
Chen
>> +    return err;
>>   }
>>   /* bpf_trampoline_unlink_prog() should never fail. */

  reply	other threads:[~2023-04-27  1:41 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-04-26  9:55 Chen Zhongjin
2023-04-26 18:17 ` Yonghong Song
2023-04-27  1:40   ` Chen Zhongjin [this message]
2023-04-27 18:54     ` Yonghong Song
2023-04-28  1:05       ` Chen Zhongjin

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=be9efa60-14ec-ba46-91e1-9feb56c40fb8@huawei.com \
    --to=chenzhongjin@huawei.com \
    --cc=andrii@kernel.org \
    --cc=ast@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=daniel@iogearbox.net \
    --cc=haoluo@google.com \
    --cc=john.fastabend@gmail.com \
    --cc=jolsa@kernel.org \
    --cc=kpsingh@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=martin.lau@linux.dev \
    --cc=sdf@google.com \
    --cc=song@kernel.org \
    --cc=yhs@fb.com \
    --cc=yhs@meta.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

all inboxes | Powered by JetHome®