From: Yonghong Song <yonghong.song@linux.dev>
To: Alexei Starovoitov <alexei.starovoitov@gmail.com>
Cc: Ihor Solodrai <ihor.solodrai@linux.dev>,
Andrii Nakryiko <andrii@kernel.org>, bpf <bpf@vger.kernel.org>,
Alexei Starovoitov <ast@kernel.org>,
Daniel Borkmann <daniel@iogearbox.net>,
Eduard <eddyz87@gmail.com>, Mykola Lysenko <mykolal@fb.com>,
Kernel Team <kernel-team@meta.com>
Subject: Re: [PATCH bpf-next v3 2/3] selftests/bpf: add cmp_map_pointer_with_const test
Date: Thu, 5 Jun 2025 23:24:45 -0700 [thread overview]
Message-ID: <70affb12-327b-4882-bd1d-afda8b8c6f56@linux.dev> (raw)
In-Reply-To: <CAADnVQJneX_rzcr-L0-yUwy38ffwwDqVq4E8byC+wpTMYTrT4Q@mail.gmail.com>
On 6/5/25 11:11 AM, Alexei Starovoitov wrote:
> On Thu, Jun 5, 2025 at 10:42 AM Yonghong Song <yonghong.song@linux.dev> wrote:
>>
>>
>> On 6/5/25 10:17 AM, Ihor Solodrai wrote:
>>> On 6/5/25 9:08 AM, Alexei Starovoitov wrote:
>>>> On Wed, Jun 4, 2025 at 8:04 PM Ihor Solodrai
>>>> <ihor.solodrai@linux.dev> wrote:
>>>>> On 6/4/25 3:41 PM, Alexei Starovoitov wrote:
>>>>>> On Wed, Jun 4, 2025 at 3:28 PM Ihor Solodrai <isolodrai@meta.com>
>>>>>> wrote:
>>>>>>> Add a test for CONST_PTR_TO_MAP comparison with a non-0 constant. A
>>>>>>> BPF program with this code must not pass verification in unpriv.
>>>>>>>
>>>>>>> Signed-off-by: Ihor Solodrai <isolodrai@meta.com>
>>>>>>> ---
>>>>>>> .../selftests/bpf/progs/verifier_unpriv.c | 17
>>>>>>> +++++++++++++++++
>>>>>>> 1 file changed, 17 insertions(+)
>>>>>>>
>>>>>>> diff --git a/tools/testing/selftests/bpf/progs/verifier_unpriv.c
>>>>>>> b/tools/testing/selftests/bpf/progs/verifier_unpriv.c
>>>>>>> index 28200f068ce5..c4a48b57e167 100644
>>>>>>> --- a/tools/testing/selftests/bpf/progs/verifier_unpriv.c
>>>>>>> +++ b/tools/testing/selftests/bpf/progs/verifier_unpriv.c
>>>>>>> @@ -634,6 +634,23 @@ l0_%=: r0 =
>>>>>>> 0; \
>>>>>>> : __clobber_all);
>>>>>>> }
>>>>>>>
>>>>>>> +SEC("socket")
>>>>>>> +__description("unpriv: cmp map pointer with const")
>>>>>>> +__success __failure_unpriv __msg_unpriv("R1 pointer comparison
>>>>>>> prohibited")
>>>>>>> +__retval(0)
>>>>>>> +__naked void cmp_map_pointer_with_const(void)
>>>>>>> +{
>>>>>>> + asm volatile (" \
>>>>>>> + r1 = 0; \
>>>>>>> + r1 = %[map_hash_8b] ll; \
>>>>>>> + if r1 == 0xdeadbeef goto l0_%=; \
>>>>>> I bet this doesn't fit into imm32 either.
>>>>>> It should fit into _signed_ imm32.
>>>>> Apparently it's fine both for gcc and clang:
>>>>> https://github.com/kernel-patches/bpf/actions/runs/15454151804
>>>> Both compilers are buggy then.
>>>>
>>>>> I guess the value from inline asm is just put into IMM bytes as
>>>>> is. llvm-objdump is exactly the same, although the value is pretty
>>>>> printed as negative:
>>>>>
>>>>> 0000000000000320 <cmp_map_pointer_with_const>:
>>>>> 100: b7 01 00 00 00 00 00 00 r1 = 0x0
>>>>> 101: 18 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 r1
>>>>> = 0x0 ll
>>>>> 103: 15 01 00 00 ef be ad de if r1 == -0x21524111 goto
>>>>> +0x0
>>>> It's 64-bit 0xFFFFffffdeadbeef
>>>> Not the same as 0xdeadbeef
>>> I am not sure what the issue is, would appreciate an explanation.
>>>
>>> Inline asm contains a 32bit literal (without a sign). Compiler takes
>>> this literal as is and puts it into imm field of the instruction,
>>> which is also 32bit. The instruction is valid and this value _means_
>>> signed integer, in particular for the verifier.
> Not quite. It's signed imm32 in _runtime_.
>
>>> Are you saying that compiler should check the sign of the literal and
>>> verify it's in signed 32bit range? In other words if you want
>>> 0xdeadbeef bytes in the imm, you must write -0x21524111 in the asm?
>>>
>>> AFAIU it'd be different from C then, because you can write:
>>>
>>> int k = 0xdeadbeef;
>>> printf("%d\n", k); // prints -559038737
>>>
>>> and it's fine.
>>>
>>> Looking at Yonghong's llvm pr [1], it will not error for 0xdeadbeef
>>> because it's less than UINT_MAX:
>>>
>>> if (MO.isImm()) {
>>> int64_t Imm = MO.getImm();
>>> if (MI.getOpcode() != BPF::LD_imm64 && (Imm < INT_MIN || Imm >
>>> UINT_MAX))
>>> Ctx.reportError(MI.getLoc(),
>>> "immediate out of range, shall fit in 32
>>> bits");
>>> return static_cast<unsigned>(Imm);
>>> }
>>>
>>> [1] https://github.com/llvm/llvm-project/pull/142989
>>>
>>>
>> If we have C code like
>> if (var == 0xdeadbeef) { ... }
>>
>> The compiler will actually convert 'var == imm' to 'rX == rY' and
>> rY will have content of 0xdeadbeef. This will happen during IR lowering
>> from middle end to machine instructions.
> ... and the compiler will use ld_imm64 insn to store 0xdeadbeef in rY.
>
>> The tricky thing is inline asm. I am debating myself whether we
>> should align with GCC or not to allow 'rX == 0xdeadbeef' in inline asm.
>> in llvm the inline asm code is processed at MC level (after all
>> optimizations).
>> Ultimately I aligned with GCC for compatibility. My first response to this
>> thread is to only allow in range or INT_MIN and INT_MAX.
>>
>> So the question is that we treat inline asm as the pure encoding
>> or it should have other semantics.
> I think both compilers should error (or warn) when imm32 doesn't fit
> into int_min/max, because the asm code for
> if r1 == 0xdeadbeef goto l0_%=;
> will not do what the author expects.
if we intend to use 'int' range instead then we will have more cases like below.
For example,
store with imm:
int foo(long *a, long *b) {
*a = 0xabababab;
*b = 0x76543210;
return 0;
}
In this example, using an inline asm to do
*(u64 *)(r1 + 0) = 0xabababab
will not be what user expected to get.
The same issue for conditional like 'long a; if (a > 0xabababab) ...', or
alu64 operations like 'long a; if (a & 0xabababab) ...'.
I can expand checking in llvm for the these patterns.
next prev parent reply other threads:[~2025-06-06 6:24 UTC|newest]
Thread overview: 21+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-06-04 22:27 [PATCH bpf-next v3 1/3] bpf: make reg_not_null() true for CONST_PTR_TO_MAP Ihor Solodrai
2025-06-04 22:27 ` [PATCH bpf-next v3 2/3] selftests/bpf: add cmp_map_pointer_with_const test Ihor Solodrai
2025-06-04 22:41 ` Alexei Starovoitov
2025-06-05 3:04 ` Ihor Solodrai
2025-06-05 16:08 ` Alexei Starovoitov
2025-06-05 17:17 ` Ihor Solodrai
2025-06-05 17:42 ` Yonghong Song
2025-06-05 18:11 ` Alexei Starovoitov
2025-06-06 6:24 ` Yonghong Song [this message]
2025-06-05 16:20 ` Andrii Nakryiko
2025-06-05 16:30 ` Ihor Solodrai
2025-06-04 22:27 ` [PATCH bpf-next v3 3/3] selftests/bpf: add test cases with CONST_PTR_TO_MAP null checks Ihor Solodrai
2025-06-05 16:24 ` Andrii Nakryiko
2025-06-05 16:42 ` Ihor Solodrai
2025-06-05 17:00 ` Alexei Starovoitov
2025-06-05 23:40 ` Ihor Solodrai
2025-06-06 0:25 ` Alexei Starovoitov
2025-06-06 23:37 ` Ihor Solodrai
2025-06-06 23:52 ` Alexei Starovoitov
2025-06-07 14:07 ` Alexei Starovoitov
2025-06-05 16:27 ` [PATCH bpf-next v3 1/3] bpf: make reg_not_null() true for CONST_PTR_TO_MAP Andrii Nakryiko
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=70affb12-327b-4882-bd1d-afda8b8c6f56@linux.dev \
--to=yonghong.song@linux.dev \
--cc=alexei.starovoitov@gmail.com \
--cc=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=daniel@iogearbox.net \
--cc=eddyz87@gmail.com \
--cc=ihor.solodrai@linux.dev \
--cc=kernel-team@meta.com \
--cc=mykolal@fb.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;
as well as URLs for NNTP newsgroup(s).