-
Notifications
You must be signed in to change notification settings - Fork 3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
bpf: open code mark_is_from_proxy to fix proxy error #2162
Conversation
On 4.14 kernel with llvm 4.0 or greater the current implementation of mark_is_from_proxy() is returning zero _always_ regardless of actual mark field. The result is "ingress" policy tests are failing. This can be seen with the 10-proxy.sh test, giving an "Internal Server Error" (error code 500). This is because if we do not mark the skb correctly it will be sent to the proxy repeatedly if the configuration/packet would have checked the skip bit and avoided forwarding to the proxy. At the moment its unclear to me why the original version is tripping up, but kicking through the testing cycle now. This should not change the logic any AFAICT but still it fixes the issue. Some ideas, arithmatic overflow (not seeing it now though), compiler bug, artifact of my bare metal ubuntu setup, ... Also for what its worth I like the open-coded version better anyways. We probably don't need an inline function for a single caller. Fixes: f89a22c ("proxy: Distinguish between proxy and other local processes") Signed-off-by: John Fastabend <john.fastabend@gmail.com>
|
some relevant snippets from new objdump: versus old |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Approving the agent (daemon/bpf.sha) change only, since I don't know enough about the rest.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Change looks good. Let me investigate the issue a bit, it feels there may be a disconnect between LLVM and kernel runtime on this wrt signed extension.
|
Below are the semantics of the kernel with regards to the issue. I think they are fine, imho. I would see the bug on LLVM side. I'm wondering for the patch, if you move the test to __u64 and the constants to ULL, would LLVM still tend to generate such code? |
|
Would it help anything in LLVM behaviour if the constants are defined as unsigned, meaning, would LLVM detect that they would have to be loaded into a register instead since signed extension cannot be applied here? |
|
The problem is caused by several reg/imm comparison through the first few insns, r2 will hold a value like However, since imm is 32-bit signed integer, when comparison This looks like a compiler issue as we should not use EQ/NE_ri In LLVM, we already only put i64immSExt32 into insn imm field. isInt<32> will check: So it does matter for how you define your constants. I tried the mimic the exact original program, but the compiler Could you tell me how to reproduce the issue? Following insns in https://github.com/cilium/cilium/blob/master/CONTRIBUTING.md to build? |
|
Thanks for the reply. Following the guide should get you the source code via, go get -d github.com/cilium/cilium If you don't have a go build environment you will need that. Then once you have the source doing a standard 'make' in the ciliium directory should work. In './bpf/' directory there will be './bpf/bpf_netdev..o' (after the make) which is the object file in question. Although in order to see the issue you will need to add a FROM_HOST define. I usually just modify ./bpf/Makefile for this. After doing this there will be a compile error. The following is the diff I used to resolve it, : |
|
Also let me know I can try patches and/or provide debug info if needed. |
|
Thanks, @jrfastab, I am able to reproduce the issue with 5.0, but not latest 6.0. After debugging 5.0 and then cross-check 6.0, I found the bug has been fixed. The fix commit is: This patch also prevents negative integer from using Select_Ri format since the where the compiler considers (0xFEFA << 16) as a value with 32-bit width and when it converts to int64, its value is 0xFEFA0000. |
|
Thanks @yonghong-song for looking into this! Do you see a reliable workaround to avoid silently running into this bug for clang versions < 6.0? Does this exist from the beginning of BPF backend or only clang 5.0 affected? Do you see a chance to get this fix into 5.0.1, since so far only clang 5.0.0 has been released? |
|
Ah dang my test script wasn't properly linking to the latest llvm and was
still using 5.0. Thanks a lot for tracking this down and the detailed
explanation very much appreciated.
Will this fix get pushed back into stable version of llvm?
…On Thu, Nov 30, 2017 at 10:03 PM, yonghong-song ***@***.***> wrote:
Thanks, @jrfastab <https://github.com/jrfastab>, I am able to reproduce
the issue with 5.0, but not latest 6.0. After debugging 5.0 and then
cross-check 6.0, I found the bug has been fixed. The fix commit is:
commit e53750e1e086f4e234f52041072e688abd79e22b
Author: Yonghong Song ***@***.***>
Date: Mon Oct 16 04:14:53 2017 +0000
bpf: fix bug on silently truncating 64-bit immediate
We came across an llvm bug when compiling some testcases that 64-bit
immediates are silently truncated into 32-bit and then packed into
BPF_JMP | BPF_K encoding. This caused comparison with wrong value.
This bug looks to be introduced by r308080. The Select_Ri pattern is
supposed to be lowered into J*_Ri while the latter only support 32-bit
immediate encoding, therefore Select_Ri should have similar immediate
predicate check as what J*_Ri are doing.
Reported-by: Jakub Kicinski ***@***.***>
Signed-off-by: Jiong Wang ***@***.***>
Reviewed-by: Yonghong Song ***@***.***>
This patch also prevents negative integer from using Select_Ri format
since the
negative value does not satisfy:
template <> constexpr inline bool isInt<32>(int64_t x) {
return static_cast<int32_t>(x) == x;
}
where the compiler considers (0xFEFA << 16) as a value with 32-bit width
and when it converts to int64, its value is 0xFEFA0000.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#2162 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/ABMI8PbDlst4rwqCKhpx4p-FzxiRILY0ks5s75bNgaJpZM4Qufy5>
.
|
|
The reliable way to fix the issue is to force the constant in the register through You only need to do this when constant is greater than 0x7FFFFFFF. This bug only affects 5.0. It does seem 5.0.1 is still open for business. This bug does look really bad and I will try to push into 5.0.1. |
|
pushed into llvm stable_50 release. It should appear in 5.0.1 llvm release. |
|
Great I'll keep a look out for the 5.01 release and test it when it's available. Thanks again.
… On Dec 3, 2017, at 5:27 PM, yonghong-song ***@***.***> wrote:
pushed into llvm stable_50 release. It should appear in 5.0.1 llvm release.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub, or mute the thread.
|
|
Thanks a lot @yonghong-song! |
|
@jrfastab I guess it would be better to switch to using volatile then for the constants, maybe with a comment pointing to here. |
Add a couple of test cases for interpreter and JIT that are
related to an issue we faced some time ago in Cilium [1],
which is fixed in LLVM with commit e53750e1e086 ("bpf: fix
bug on silently truncating 64-bit immediate").
Test cases were run-time checking kernel to behave as intended
which should also provide some guidance for current or new
JITs in case they should trip over this. Added for cBPF and
eBPF.
[1] cilium/cilium#2162
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
On 4.14 kernel with llvm 4.0 or greater the current implementation of
mark_is_from_proxy() is returning zero always regardless of actual
mark field.
The result is "ingress" policy tests are failing. This can be seen
with the 10-proxy.sh test, giving an "Internal Server Error" (error
code 500). This is because if we do not mark the skb correctly it
will be sent to the proxy repeatedly if the configuration/packet
would have checked the skip bit and avoided forwarding to the proxy.
At the moment its unclear to me why the original version is tripping
up, but kicking through the testing cycle now. This should not change
the logic any AFAICT but still it fixes the issue.
Some ideas, arithmatic overflow (not seeing it now though),
compiler bug, artifact of my bare metal ubuntu setup, ...
Also for what its worth I like the open-coded version better anyways.
We probably don't need an inline function for a single caller.
Fixes: f89a22c ("proxy: Distinguish between proxy and other local processes")
Signed-off-by: John Fastabend john.fastabend@gmail.com