* [PATCH v6 bpf-next 1/2] bpf: Improve the general precision of tnum_mul
@ 2025-08-26 3:45 Nandakumar Edamana
2025-08-26 3:45 ` [PATCH v6 bpf-next 2/2] bpf: Add selftest to check the verifier's abstract multiplication Nandakumar Edamana
` (2 more replies)
0 siblings, 3 replies; 5+ messages in thread
From: Nandakumar Edamana @ 2025-08-26 3:45 UTC (permalink / raw)
To: alexei.starovoitov
Cc: Eduard Zingerman, bpf, Alexei Starovoitov, Daniel Borkmann,
Andrii Nakryiko, Jakub Sitnicki, Harishankar Vishwanathan,
Nandakumar Edamana
Drop the value-mask decomposition technique and adopt straightforward
long-multiplication with a twist: when LSB(a) is uncertain, find the
two partial products (for LSB(a) = known 0 and LSB(a) = known 1) and
take a union.
Experiment shows that applying this technique in long multiplication
improves the precision in a significant number of cases (at the cost
of losing precision in a relatively lower number of cases).
Signed-off-by: Nandakumar Edamana <nandakumar@nandakumar.co.in>
Acked-by: Eduard Zingerman <eddyz87@gmail.com>
Reviewed-by: Harishankar Vishwanathan <harishankar.vishwanathan@gmail.com>
---
include/linux/tnum.h | 3 +++
kernel/bpf/tnum.c | 55 +++++++++++++++++++++++++++++++++-----------
2 files changed, 45 insertions(+), 13 deletions(-)
diff --git a/include/linux/tnum.h b/include/linux/tnum.h
index 57ed3035cc30..68e9cdd0a2ab 100644
--- a/include/linux/tnum.h
+++ b/include/linux/tnum.h
@@ -54,6 +54,9 @@ struct tnum tnum_mul(struct tnum a, struct tnum b);
/* Return a tnum representing numbers satisfying both @a and @b */
struct tnum tnum_intersect(struct tnum a, struct tnum b);
+/* Returns a tnum representing numbers satisfying either @a or @b */
+struct tnum tnum_union(struct tnum t1, struct tnum t2);
+
/* Return @a with all but the lowest @size bytes cleared */
struct tnum tnum_cast(struct tnum a, u8 size);
diff --git a/kernel/bpf/tnum.c b/kernel/bpf/tnum.c
index fa353c5d550f..a47183ddbfdb 100644
--- a/kernel/bpf/tnum.c
+++ b/kernel/bpf/tnum.c
@@ -116,31 +116,47 @@ struct tnum tnum_xor(struct tnum a, struct tnum b)
return TNUM(v & ~mu, mu);
}
-/* Generate partial products by multiplying each bit in the multiplier (tnum a)
- * with the multiplicand (tnum b), and add the partial products after
- * appropriately bit-shifting them. Instead of directly performing tnum addition
- * on the generated partial products, equivalenty, decompose each partial
- * product into two tnums, consisting of the value-sum (acc_v) and the
- * mask-sum (acc_m) and then perform tnum addition on them. The following paper
- * explains the algorithm in more detail: https://arxiv.org/abs/2105.05398.
+/* Perform long multiplication, iterating through the bits in a using rshift:
+ * - if LSB(a) is a known 0, keep current accumulator
+ * - if LSB(a) is a known 1, add b to current accumulator
+ * - if LSB(a) is unknown, take a union of the above cases.
+ *
+ * For example:
+ *
+ * acc_0: acc_1:
+ *
+ * 11 * -> 11 * -> 11 * -> union(0011, 1001) == x0x1
+ * x1 01 11
+ * ------ ------ ------
+ * 11 11 11
+ * xx 00 11
+ * ------ ------ ------
+ * ???? 0011 1001
*/
struct tnum tnum_mul(struct tnum a, struct tnum b)
{
- u64 acc_v = a.value * b.value;
- struct tnum acc_m = TNUM(0, 0);
+ struct tnum acc = TNUM(0, 0);
while (a.value || a.mask) {
/* LSB of tnum a is a certain 1 */
if (a.value & 1)
- acc_m = tnum_add(acc_m, TNUM(0, b.mask));
+ acc = tnum_add(acc, b);
/* LSB of tnum a is uncertain */
- else if (a.mask & 1)
- acc_m = tnum_add(acc_m, TNUM(0, b.value | b.mask));
+ else if (a.mask & 1) {
+ /* acc = tnum_union(acc_0, acc_1), where acc_0 and
+ * acc_1 are partial accumulators for cases
+ * LSB(a) = certain 0 and LSB(a) = certain 1.
+ * acc_0 = acc + 0 * b = acc.
+ * acc_1 = acc + 1 * b = tnum_add(acc, b).
+ */
+
+ acc = tnum_union(acc, tnum_add(acc, b));
+ }
/* Note: no case for LSB is certain 0 */
a = tnum_rshift(a, 1);
b = tnum_lshift(b, 1);
}
- return tnum_add(TNUM(acc_v, 0), acc_m);
+ return acc;
}
/* Note that if a and b disagree - i.e. one has a 'known 1' where the other has
@@ -155,6 +171,19 @@ struct tnum tnum_intersect(struct tnum a, struct tnum b)
return TNUM(v & ~mu, mu);
}
+/* Returns a tnum with the uncertainty from both a and b, and in addition, new
+ * uncertainty at any position that a and b disagree. This represents a
+ * superset of the union of the concrete sets of both a and b. Despite the
+ * overapproximation, it is optimal.
+ */
+struct tnum tnum_union(struct tnum a, struct tnum b)
+{
+ u64 v = a.value & b.value;
+ u64 mu = (a.value ^ b.value) | a.mask | b.mask;
+
+ return TNUM(v & ~mu, mu);
+}
+
struct tnum tnum_cast(struct tnum a, u8 size)
{
a.value &= (1ULL << (size * 8)) - 1;
--
2.39.5
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH v6 bpf-next 2/2] bpf: Add selftest to check the verifier's abstract multiplication
2025-08-26 3:45 [PATCH v6 bpf-next 1/2] bpf: Improve the general precision of tnum_mul Nandakumar Edamana
@ 2025-08-26 3:45 ` Nandakumar Edamana
2025-08-26 11:33 ` [PATCH v6 bpf-next 1/2] bpf: Improve the general precision of tnum_mul Daniel Borkmann
2025-08-27 22:20 ` patchwork-bot+netdevbpf
2 siblings, 0 replies; 5+ messages in thread
From: Nandakumar Edamana @ 2025-08-26 3:45 UTC (permalink / raw)
To: alexei.starovoitov
Cc: Eduard Zingerman, bpf, Alexei Starovoitov, Daniel Borkmann,
Andrii Nakryiko, Jakub Sitnicki, Harishankar Vishwanathan,
Nandakumar Edamana
Add new selftest to test the abstract multiplication technique(s) used
by the verifier, following the recent improvement in tnum
multiplication (tnum_mul). One of the newly added programs,
verifier_mul/mul_precise, results in a false positive with the old
tnum_mul, while the program passes with the latest one.
Signed-off-by: Nandakumar Edamana <nandakumar@nandakumar.co.in>
Acked-by: Eduard Zingerman <eddyz87@gmail.com>
Reviewed-by: Harishankar Vishwanathan <harishankar.vishwanathan@gmail.com>
---
.../selftests/bpf/prog_tests/verifier.c | 2 +
.../selftests/bpf/progs/verifier_mul.c | 38 +++++++++++++++++++
2 files changed, 40 insertions(+)
create mode 100644 tools/testing/selftests/bpf/progs/verifier_mul.c
diff --git a/tools/testing/selftests/bpf/prog_tests/verifier.c b/tools/testing/selftests/bpf/prog_tests/verifier.c
index 77ec95d4ffaa..e35c216dbaf2 100644
--- a/tools/testing/selftests/bpf/prog_tests/verifier.c
+++ b/tools/testing/selftests/bpf/prog_tests/verifier.c
@@ -59,6 +59,7 @@
#include "verifier_meta_access.skel.h"
#include "verifier_movsx.skel.h"
#include "verifier_mtu.skel.h"
+#include "verifier_mul.skel.h"
#include "verifier_netfilter_ctx.skel.h"
#include "verifier_netfilter_retcode.skel.h"
#include "verifier_bpf_fastcall.skel.h"
@@ -194,6 +195,7 @@ void test_verifier_may_goto_1(void) { RUN(verifier_may_goto_1); }
void test_verifier_may_goto_2(void) { RUN(verifier_may_goto_2); }
void test_verifier_meta_access(void) { RUN(verifier_meta_access); }
void test_verifier_movsx(void) { RUN(verifier_movsx); }
+void test_verifier_mul(void) { RUN(verifier_mul); }
void test_verifier_netfilter_ctx(void) { RUN(verifier_netfilter_ctx); }
void test_verifier_netfilter_retcode(void) { RUN(verifier_netfilter_retcode); }
void test_verifier_bpf_fastcall(void) { RUN(verifier_bpf_fastcall); }
diff --git a/tools/testing/selftests/bpf/progs/verifier_mul.c b/tools/testing/selftests/bpf/progs/verifier_mul.c
new file mode 100644
index 000000000000..7145fe3351d5
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/verifier_mul.c
@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2025 Nandakumar Edamana */
+#include <linux/bpf.h>
+#include <bpf/bpf_helpers.h>
+#include <bpf/bpf_tracing.h>
+#include "bpf_misc.h"
+
+/* Intended to test the abstract multiplication technique(s) used by
+ * the verifier. Using assembly to avoid compiler optimizations.
+ */
+SEC("fentry/bpf_fentry_test1")
+void BPF_PROG(mul_precise, int x)
+{
+ /* First, force the verifier to be uncertain about the value:
+ * unsigned int a = (bpf_get_prandom_u32() & 0x2) | 0x1;
+ *
+ * Assuming the verifier is using tnum, a must be tnum{.v=0x1, .m=0x2}.
+ * Then a * 0x3 would be m0m1 (m for uncertain). Added imprecision
+ * would cause the following to fail, because the required return value
+ * is 0:
+ * return (a * 0x3) & 0x4);
+ */
+ asm volatile ("\
+ call %[bpf_get_prandom_u32];\
+ r0 &= 0x2;\
+ r0 |= 0x1;\
+ r0 *= 0x3;\
+ r0 &= 0x4;\
+ if r0 != 0 goto l0_%=;\
+ r0 = 0;\
+ goto l1_%=;\
+l0_%=:\
+ r0 = 1;\
+l1_%=:\
+" :
+ : __imm(bpf_get_prandom_u32)
+ : __clobber_all);
+}
--
2.39.5
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH v6 bpf-next 1/2] bpf: Improve the general precision of tnum_mul
2025-08-26 3:45 [PATCH v6 bpf-next 1/2] bpf: Improve the general precision of tnum_mul Nandakumar Edamana
2025-08-26 3:45 ` [PATCH v6 bpf-next 2/2] bpf: Add selftest to check the verifier's abstract multiplication Nandakumar Edamana
@ 2025-08-26 11:33 ` Daniel Borkmann
2025-08-26 16:59 ` Harishankar Vishwanathan
2025-08-27 22:20 ` patchwork-bot+netdevbpf
2 siblings, 1 reply; 5+ messages in thread
From: Daniel Borkmann @ 2025-08-26 11:33 UTC (permalink / raw)
To: Nandakumar Edamana, alexei.starovoitov
Cc: Eduard Zingerman, bpf, Alexei Starovoitov, Andrii Nakryiko,
Jakub Sitnicki, Harishankar Vishwanathan
On 8/26/25 5:45 AM, Nandakumar Edamana wrote:
> Drop the value-mask decomposition technique and adopt straightforward
> long-multiplication with a twist: when LSB(a) is uncertain, find the
> two partial products (for LSB(a) = known 0 and LSB(a) = known 1) and
> take a union.
>
> Experiment shows that applying this technique in long multiplication
> improves the precision in a significant number of cases (at the cost
> of losing precision in a relatively lower number of cases).
>
> Signed-off-by: Nandakumar Edamana <nandakumar@nandakumar.co.in>
> Acked-by: Eduard Zingerman <eddyz87@gmail.com>
> Reviewed-by: Harishankar Vishwanathan <harishankar.vishwanathan@gmail.com>
Hari, are you okay if we also add a ...
Tested-by: Harishankar Vishwanathan <harishankar.vishwanathan@gmail.com> # Agni
... to indicate in the commit log that you also ran the code through Agni?
Thanks,
Daniel
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH v6 bpf-next 1/2] bpf: Improve the general precision of tnum_mul
2025-08-26 11:33 ` [PATCH v6 bpf-next 1/2] bpf: Improve the general precision of tnum_mul Daniel Borkmann
@ 2025-08-26 16:59 ` Harishankar Vishwanathan
0 siblings, 0 replies; 5+ messages in thread
From: Harishankar Vishwanathan @ 2025-08-26 16:59 UTC (permalink / raw)
To: Daniel Borkmann
Cc: Nandakumar Edamana, alexei.starovoitov, Eduard Zingerman, bpf,
Alexei Starovoitov, Andrii Nakryiko, Jakub Sitnicki
On Tue, Aug 26, 2025 at 7:33 AM Daniel Borkmann <daniel@iogearbox.net> wrote:
>
> On 8/26/25 5:45 AM, Nandakumar Edamana wrote:
> > Drop the value-mask decomposition technique and adopt straightforward
> > long-multiplication with a twist: when LSB(a) is uncertain, find the
> > two partial products (for LSB(a) = known 0 and LSB(a) = known 1) and
> > take a union.
> >
> > Experiment shows that applying this technique in long multiplication
> > improves the precision in a significant number of cases (at the cost
> > of losing precision in a relatively lower number of cases).
> >
> > Signed-off-by: Nandakumar Edamana <nandakumar@nandakumar.co.in>
> > Acked-by: Eduard Zingerman <eddyz87@gmail.com>
> > Reviewed-by: Harishankar Vishwanathan <harishankar.vishwanathan@gmail.com>
>
> Hari, are you okay if we also add a ...
>
> Tested-by: Harishankar Vishwanathan <harishankar.vishwanathan@gmail.com> # Agni
>
> ... to indicate in the commit log that you also ran the code through Agni?
>
> Thanks,
> Daniel
Yes sure Daniel, I'm okay with adding the Tested-by.
Just to clarify: since tnum_mul has a loop, I didn't run this directly through
Agni, as Agni doesn't yet support loops. I tested this in Z3 via a
manual conversion
to logic by unrolling the loop for a limited bound.
Best,
Hari
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH v6 bpf-next 1/2] bpf: Improve the general precision of tnum_mul
2025-08-26 3:45 [PATCH v6 bpf-next 1/2] bpf: Improve the general precision of tnum_mul Nandakumar Edamana
2025-08-26 3:45 ` [PATCH v6 bpf-next 2/2] bpf: Add selftest to check the verifier's abstract multiplication Nandakumar Edamana
2025-08-26 11:33 ` [PATCH v6 bpf-next 1/2] bpf: Improve the general precision of tnum_mul Daniel Borkmann
@ 2025-08-27 22:20 ` patchwork-bot+netdevbpf
2 siblings, 0 replies; 5+ messages in thread
From: patchwork-bot+netdevbpf @ 2025-08-27 22:20 UTC (permalink / raw)
To: Nandakumar Edamana
Cc: alexei.starovoitov, eddyz87, bpf, ast, daniel, andrii, jakub,
harishankar.vishwanathan
Hello:
This series was applied to bpf/bpf-next.git (master)
by Andrii Nakryiko <andrii@kernel.org>:
On Tue, 26 Aug 2025 09:15:23 +0530 you wrote:
> Drop the value-mask decomposition technique and adopt straightforward
> long-multiplication with a twist: when LSB(a) is uncertain, find the
> two partial products (for LSB(a) = known 0 and LSB(a) = known 1) and
> take a union.
>
> Experiment shows that applying this technique in long multiplication
> improves the precision in a significant number of cases (at the cost
> of losing precision in a relatively lower number of cases).
>
> [...]
Here is the summary with links:
- [v6,bpf-next,1/2] bpf: Improve the general precision of tnum_mul
(no matching commit)
- [v6,bpf-next,2/2] bpf: Add selftest to check the verifier's abstract multiplication
https://git.kernel.org/bpf/bpf-next/c/2660b9d47750
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2025-08-27 22:20 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-08-26 3:45 [PATCH v6 bpf-next 1/2] bpf: Improve the general precision of tnum_mul Nandakumar Edamana
2025-08-26 3:45 ` [PATCH v6 bpf-next 2/2] bpf: Add selftest to check the verifier's abstract multiplication Nandakumar Edamana
2025-08-26 11:33 ` [PATCH v6 bpf-next 1/2] bpf: Improve the general precision of tnum_mul Daniel Borkmann
2025-08-26 16:59 ` Harishankar Vishwanathan
2025-08-27 22:20 ` patchwork-bot+netdevbpf
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).