From: Gary Lin <glin@suse.com>
To: bpf <bpf@vger.kernel.org>
Cc: andreas.taschner@suse.com
Subject: x86 BPF JIT failed to load a program with continuous JMPs
Date: Tue, 3 Nov 2020 12:00:48 +0800 [thread overview]
Message-ID: <20201103040048.GN19552@GaryWorkstation> (raw)
Hi,
We recently got a bug report from a customer about the x86 BPF JIT, and
the bpf program is like this:
l0: ldh [4]
l1: jeq #0x537d, l2, l40
l2: ld [0]
l3: jeq #0xfa163e0d, l4, l40
l4: ldh [12]
l5: ldx #0xe
l6: jeq #0x86dd, l41, l7
l7: jeq #0x800, l8, l41
l8: ld [x+16]
l9: ja 41
[... repeated ja 41 ]
l40: ja 41
l41: ret #0
l42: ld #len
l43: ret a
They declared a sock_filter array with a lot of "ja 41" in order to
replace them dynamically with other BPF instructions and attached the
program to a socket with setsockopt(SO_ATTACH_FILTER). It worked fine
with BPF interpreter until upgrading to the kernel with
BPF_JIT_ALWAYS_ON.
In the beginning, I thought it's rejected by the verifier due to
unreachable instructions. However, the verifier didn't involve since
it's attached through SO_ATTACH_FILTER. The program was sent to BPF
JIT directly and rejected with ENOTSUPP. In the end, I found that it
failed in bpf_int_jit_compile()(*). Every time do_jit() was invoked,
it removed one "ja 41" right before "ret #0", so bpf_int_jit_compile()
failed to remove all "ja 41" within 20 runs. If I reduced the number of
JMPs to 19, BPF JIT accepted the program. It seems a corner case that
BPF JIT could not handle.
A quick "fix" might be iterating do_jit() until the image converges,
but I guess the limited iteration is designed to bound the compilation
time of BPF JIT, so I'm not sure if this is a good option.
BTW, as a workaround, I suggested the customer to replace the JMPs with
0 offset JMPs so that do_jit() can optimize them out in 1 pass. But I
still would like to know how to handle this kind of programs properly.
Thanks
Gary Lin
(*) https://github.com/torvalds/linux/blob/v5.9/arch/x86/net/bpf_jit_comp.c#L1876-L1921
reply other threads:[~2020-11-03 4:01 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
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=20201103040048.GN19552@GaryWorkstation \
--to=glin@suse.com \
--cc=andreas.taschner@suse.com \
--cc=bpf@vger.kernel.org \
/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