# \[PATCH v2 0/4\] Fix up bpf\_jit\_limit some more

- Subsystems: NETWORKING \[GENERAL\], ARM64 PORT (AARCH64 ARCHITECTURE), BPF JIT for ARM64, BPF JIT for RISC-V (32-bit), BPF JIT for RISC-V (64-bit), BPF \[CORE\], BPF \[GENERAL\] (Safe Dynamic Programs and Tools), DOCUMENTATION, RISC-V ARCHITECTURE, THE REST
- Maintainers: "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Catalin Marinas, Will Deacon, Daniel Borkmann, Alexei Starovoitov, Puranjay Mohan, Luke Nelson, Xi Wang, Pu Lehui, Björn Töpel, Andrii Nakryiko, Eduard Zingerman, Kumar Kartikeya Dwivedi, Jonathan Corbet, Paul Walmsley, Palmer Dabbelt, Albert Ou, Linus Torvalds
- Series: 4 patches touching 6 files, +47/-4
- Status: SUPERSEDED (Superseded by v3 posted 2021-10-14)
- Superseded by v3 (posted 2021-10-14).
- Revision v2 (3 revisions archived).
- List: netdev
- 10 messages, 3 authors
- Page: https://ratatoskr.run/netdev/2021/10/7782414/t

## \[PATCH v2 0/4\] Fix up bpf\_jit\_limit some more

- From: Lorenz Bauer \<hidden\>
- Date: 2021-10-12 13:59:46 
- Message: https://ratatoskr.run/netdev/2021/10/7782414.md

```text
Some more cleanups around bpf_jit_limit to make it readable via sysctl.

Jakub raised the point that a sysctl toggle is UAPI and therefore
can't be easily changed later on. I tried to find another place to stick
the info, but couldn't find a good one. All the current BPF knobs are in
sysctl.

There are examples of read only sysctls:
$ sudo find /proc/sys -perm 0444 | wc -l
90

There are no examples of sysctls with mode 0400 however:
$ sudo find /proc/sys -perm 0400 | wc -l
0

Thoughts?

Changes in v2:
* riscv not sparcv (Luke)
* Expose bpf_jit_current in bytes, not pages (Nicholas)

Lorenz Bauer (4):
  bpf: define bpf_jit_alloc_exec_limit for riscv JIT
  bpf: define bpf_jit_alloc_exec_limit for arm64 JIT
  bpf: prevent increasing bpf_jit_limit above max
  bpf: export bpf_jit_current

 Documentation/admin-guide/sysctl/net.rst |  6 ++++++
 arch/arm64/net/bpf_jit_comp.c            |  5 +++++
 arch/riscv/net/bpf_jit_core.c            |  5 +++++
 include/linux/filter.h                   |  2 ++
 kernel/bpf/core.c                        |  7 ++++---
 net/core/sysctl_net_core.c               | 26 +++++++++++++++++++++++-
 6 files changed, 47 insertions(+), 4 deletions(-)

-- 
2.30.2

```

## \[PATCH v2 1/4\] bpf: define bpf\_jit\_alloc\_exec\_limit for riscv JIT

- From: Lorenz Bauer \<hidden\>
- Date: 2021-10-12 13:59:49 
- Message: https://ratatoskr.run/netdev/2021/10/1539112.md

```text
Expose the maximum amount of useable memory from the riscv JIT.

Signed-off-by: Lorenz Bauer <redacted>
Acked-by: Luke Nelson <luke.r.nels@gmail.com>
---
 arch/riscv/net/bpf_jit_core.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/arch/riscv/net/bpf_jit_core.c b/arch/riscv/net/bpf_jit_core.c
index fed86f42dfbe..0fee2cbaaf53 100644
--- a/arch/riscv/net/bpf_jit_core.c
+++ b/arch/riscv/net/bpf_jit_core.c
@@ -166,6 +166,11 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
 	return prog;
 }
 
+u64 bpf_jit_alloc_exec_limit(void)
+{
+	return BPF_JIT_REGION_SIZE;
+}
+
 void *bpf_jit_alloc_exec(unsigned long size)
 {
 	return __vmalloc_node_range(size, PAGE_SIZE, BPF_JIT_REGION_START,
-- 
2.30.2

```

## \[PATCH v2 2/4\] bpf: define bpf\_jit\_alloc\_exec\_limit for arm64 JIT

- From: Lorenz Bauer \<hidden\>
- Date: 2021-10-12 13:59:51 
- Message: https://ratatoskr.run/netdev/2021/10/1539113.md

```text
Expose the maximum amount of useable memory from the arm64 JIT.

Signed-off-by: Lorenz Bauer <redacted>
---
 arch/arm64/net/bpf_jit_comp.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c
index 41c23f474ea6..803e7773fa86 100644
--- a/arch/arm64/net/bpf_jit_comp.c
+++ b/arch/arm64/net/bpf_jit_comp.c
@@ -1136,6 +1136,11 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
 	return prog;
 }
 
+u64 bpf_jit_alloc_exec_limit(void)
+{
+	return BPF_JIT_REGION_SIZE;
+}
+
 void *bpf_jit_alloc_exec(unsigned long size)
 {
 	return __vmalloc_node_range(size, PAGE_SIZE, BPF_JIT_REGION_START,
-- 
2.30.2

```

## \[PATCH v2 3/4\] bpf: prevent increasing bpf\_jit\_limit above max

- From: Lorenz Bauer \<hidden\>
- Date: 2021-10-12 13:59:53 
- Message: https://ratatoskr.run/netdev/2021/10/1539114.md

```text
Restrict bpf_jit_limit to the maximum supported by the arch's JIT.

Signed-off-by: Lorenz Bauer <redacted>
---
 include/linux/filter.h     | 1 +
 kernel/bpf/core.c          | 4 +++-
 net/core/sysctl_net_core.c | 2 +-
 3 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/include/linux/filter.h b/include/linux/filter.h
index 47f80adbe744..8231a6a257f6 100644
--- a/include/linux/filter.h
+++ b/include/linux/filter.h
@@ -1050,6 +1050,7 @@ extern int bpf_jit_enable;
 extern int bpf_jit_harden;
 extern int bpf_jit_kallsyms;
 extern long bpf_jit_limit;
+extern long bpf_jit_limit_max;
 
 typedef void (*bpf_jit_fill_hole_t)(void *area, unsigned int size);
 
diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
index b6c72af64d5d..ab84b3816339 100644
--- a/kernel/bpf/core.c
+++ b/kernel/bpf/core.c
@@ -525,6 +525,7 @@ int bpf_jit_enable   __read_mostly = IS_BUILTIN(CONFIG_BPF_JIT_DEFAULT_ON);
 int bpf_jit_kallsyms __read_mostly = IS_BUILTIN(CONFIG_BPF_JIT_DEFAULT_ON);
 int bpf_jit_harden   __read_mostly;
 long bpf_jit_limit   __read_mostly;
+long bpf_jit_limit_max __read_mostly;
 
 static void
 bpf_prog_ksym_set_addr(struct bpf_prog *prog)
@@ -818,7 +819,8 @@ u64 __weak bpf_jit_alloc_exec_limit(void)
 static int __init bpf_jit_charge_init(void)
 {
 	/* Only used as heuristic here to derive limit. */
-	bpf_jit_limit = min_t(u64, round_up(bpf_jit_alloc_exec_limit() >> 2,
+	bpf_jit_limit_max = bpf_jit_alloc_exec_limit();
+	bpf_jit_limit = min_t(u64, round_up(bpf_jit_limit_max >> 2,
 					    PAGE_SIZE), LONG_MAX);
 	return 0;
 }
diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c
index c8496c1142c9..5f88526ad61c 100644
--- a/net/core/sysctl_net_core.c
+++ b/net/core/sysctl_net_core.c
@@ -419,7 +419,7 @@ static struct ctl_table net_core_table[] = {
 		.mode		= 0600,
 		.proc_handler	= proc_dolongvec_minmax_bpf_restricted,
 		.extra1		= &long_one,
-		.extra2		= &long_max,
+		.extra2		= &bpf_jit_limit_max,
 	},
 #endif
 	{
-- 
2.30.2

```

## \[PATCH v2 4/4\] bpf: export bpf\_jit\_current

- From: Lorenz Bauer \<hidden\>
- Date: 2021-10-12 13:59:55 
- Message: https://ratatoskr.run/netdev/2021/10/1539115.md

```text
Expose bpf_jit_current as a read only value via sysctl.

Signed-off-by: Lorenz Bauer <redacted>
---
 Documentation/admin-guide/sysctl/net.rst |  6 ++++++
 include/linux/filter.h                   |  1 +
 kernel/bpf/core.c                        |  3 +--
 net/core/sysctl_net_core.c               | 24 ++++++++++++++++++++++++
 4 files changed, 32 insertions(+), 2 deletions(-)

diff --git a/Documentation/admin-guide/sysctl/net.rst b/Documentation/admin-guide/sysctl/net.rst
index 4150f74c521a..524e7db8d53f 100644
--- a/Documentation/admin-guide/sysctl/net.rst
+++ b/Documentation/admin-guide/sysctl/net.rst
@@ -123,6 +123,12 @@ compiler in order to reject unprivileged JIT requests once it has
 been surpassed. bpf_jit_limit contains the value of the global limit
 in bytes.
 
+bpf_jit_current
+---------------
+
+The amount of JIT memory currently allocated, in bytes. JITing of
+unprivileged BPF is rejected if this value is above bpf_jit_limit.
+
 dev_weight
 ----------
 
diff --git a/include/linux/filter.h b/include/linux/filter.h
index 8231a6a257f6..42c543a21cd8 100644
--- a/include/linux/filter.h
+++ b/include/linux/filter.h
@@ -1051,6 +1051,7 @@ extern int bpf_jit_harden;
 extern int bpf_jit_kallsyms;
 extern long bpf_jit_limit;
 extern long bpf_jit_limit_max;
+extern atomic_long_t bpf_jit_current;
 
 typedef void (*bpf_jit_fill_hole_t)(void *area, unsigned int size);
 
diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
index ab84b3816339..12aedab09222 100644
--- a/kernel/bpf/core.c
+++ b/kernel/bpf/core.c
@@ -526,6 +526,7 @@ int bpf_jit_kallsyms __read_mostly = IS_BUILTIN(CONFIG_BPF_JIT_DEFAULT_ON);
 int bpf_jit_harden   __read_mostly;
 long bpf_jit_limit   __read_mostly;
 long bpf_jit_limit_max __read_mostly;
+atomic_long_t bpf_jit_current __read_mostly;
 
 static void
 bpf_prog_ksym_set_addr(struct bpf_prog *prog)
@@ -801,8 +802,6 @@ int bpf_jit_add_poke_descriptor(struct bpf_prog *prog,
 	return slot;
 }
 
-static atomic_long_t bpf_jit_current;
-
 /* Can be overridden by an arch's JIT compiler if it has a custom,
  * dedicated BPF backend memory area, or if neither of the two
  * below apply.
diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c
index 5f88526ad61c..78603f561482 100644
--- a/net/core/sysctl_net_core.c
+++ b/net/core/sysctl_net_core.c
@@ -15,6 +15,7 @@
 #include <linux/vmalloc.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/atomic.h>
 
 #include <net/ip.h>
 #include <net/sock.h>
@@ -307,6 +308,22 @@ proc_dolongvec_minmax_bpf_restricted(struct ctl_table *table, int write,
 
 	return proc_doulongvec_minmax(table, write, buffer, lenp, ppos);
 }
+
+static int proc_bpf_jit_current(struct ctl_table *table, int write,
+				void *buffer, size_t *lenp, loff_t *ppos)
+{
+	long curr = atomic_long_read(&bpf_jit_current) << PAGE_SHIFT;
+	struct ctl_table ctl_entry = {
+		.data		= &curr,
+		.maxlen		= sizeof(long),
+	};
+
+
+	if (!capable(CAP_SYS_ADMIN) || write)
+		return -EPERM;
+
+	return proc_doulongvec_minmax(&ctl_entry, write, buffer, lenp, ppos);
+}
 #endif
 
 static struct ctl_table net_core_table[] = {
@@ -421,6 +438,13 @@ static struct ctl_table net_core_table[] = {
 		.extra1		= &long_one,
 		.extra2		= &bpf_jit_limit_max,
 	},
+	{
+		.procname	= "bpf_jit_current",
+		.data		= &bpf_jit_current,
+		.maxlen		= sizeof(long),
+		.mode		= 0400,
+		.proc_handler	= proc_bpf_jit_current,
+	},
 #endif
 	{
 		.procname	= "netdev_tstamp_prequeue",
-- 
2.30.2

```

## Re: \[PATCH v2 4/4\] bpf: export bpf\_jit\_current

- From: Nicolas Dichtel \<hidden\>
- Date: 2021-10-12 16:29:31 
- Message: https://ratatoskr.run/netdev/2021/10/1539246.md

```text
Le 12/10/2021 à 15:59, Lorenz Bauer a écrit :
> Expose bpf_jit_current as a read only value via sysctl.
> 
> Signed-off-by: Lorenz Bauer <redacted>
> ---

[snip]

> +	{
> +		.procname	= "bpf_jit_current",
> +		.data		= &bpf_jit_current,
> +		.maxlen		= sizeof(long),
> +		.mode		= 0400,
Why not 0444 ?


Regards,
Nicolas
```

## Re: \[PATCH v2 4/4\] bpf: export bpf\_jit\_current

- From: Lorenz Bauer \<hidden\>
- Date: 2021-10-13 08:35:20 
- Message: https://ratatoskr.run/netdev/2021/10/1540062.md

```text
On Tue, 12 Oct 2021 at 17:29, Nicolas Dichtel [ref] wrote:
>
> Le 12/10/2021 à 15:59, Lorenz Bauer a écrit :
> > Expose bpf_jit_current as a read only value via sysctl.
> >
> > Signed-off-by: Lorenz Bauer <redacted>
> > ---
>
> [snip]
>
> > +     {
> > +             .procname       = "bpf_jit_current",
> > +             .data           = &bpf_jit_current,
> > +             .maxlen         = sizeof(long),
> > +             .mode           = 0400,
> Why not 0444 ?

This mirrors what the other BPF related sysctls do, which only allow
access from root with CAP_SYS_ADMIN. I'd prefer 0444 as well, but
Daniel explicitly locked down these sysctls in
2e4a30983b0f9b19b59e38bbf7427d7fdd480d98.

Lorenz

--
Lorenz Bauer  |  Systems Engineer
6th Floor, County Hall/The Riverside Building, SE1 7PB, UK

www.cloudflare.com
```

## Re: \[PATCH v2 4/4\] bpf: export bpf\_jit\_current

- From: Nicolas Dichtel \<hidden\>
- Date: 2021-10-13 12:29:48 
- Message: https://ratatoskr.run/netdev/2021/10/1540308.md

```text
Le 13/10/2021 à 10:35, Lorenz Bauer a écrit :
> On Tue, 12 Oct 2021 at 17:29, Nicolas Dichtel [ref] wrote:
>>
>> Le 12/10/2021 à 15:59, Lorenz Bauer a écrit :
>>> Expose bpf_jit_current as a read only value via sysctl.
>>>
>>> Signed-off-by: Lorenz Bauer <redacted>
>>> ---
>>
>> [snip]
>>
>>> +     {
>>> +             .procname       = "bpf_jit_current",
>>> +             .data           = &bpf_jit_current,
>>> +             .maxlen         = sizeof(long),
>>> +             .mode           = 0400,
>> Why not 0444 ?
> 
> This mirrors what the other BPF related sysctls do, which only allow
> access from root with CAP_SYS_ADMIN. I'd prefer 0444 as well, but
> Daniel explicitly locked down these sysctls in
> 2e4a30983b0f9b19b59e38bbf7427d7fdd480d98.
Even after this patch, bpf_jit_enable is 0644.

In fact, if you have CAP_BPF or CAP_SYS_ADMIN, this value has no impact for your
programs. But I you don't have one of these capabilities, it may be rejected,
but you cannot read these values, which help to understand why.


Regards,
Nicolas
```

## Re: \[PATCH v2 0/4\] Fix up bpf\_jit\_limit some more

- From: Jakub Sitnicki \<jakub@cloudflare.com\>
- Date: 2021-10-13 19:56:13 
- Message: https://ratatoskr.run/netdev/2021/10/7782471.md

```text
On Tue, Oct 12, 2021 at 03:59 PM CEST, Lorenz Bauer wrote:
> Some more cleanups around bpf_jit_limit to make it readable via sysctl.
>
> Jakub raised the point that a sysctl toggle is UAPI and therefore
> can't be easily changed later on. I tried to find another place to stick
> the info, but couldn't find a good one. All the current BPF knobs are in
> sysctl.
>
> There are examples of read only sysctls:
> $ sudo find /proc/sys -perm 0444 | wc -l
> 90
>
> There are no examples of sysctls with mode 0400 however:
> $ sudo find /proc/sys -perm 0400 | wc -l
> 0
>
> Thoughts?

I threw this idea out there during LPC already, that it would be cool to
use BPF iterators for that. Pinned/preloaded iterators were made for
dumping kernel data on demand after all.

What is missing is a BPF iterator type that would run the program just
once (there is just one thing to print), and a BPF helper to lookup
symbol's address.

I thought this would require a bit of work, but actually getting a PoC
(see below) to work was rather pleasntly straightforward.

Perhaps a bit of a hack but I'd consider it as an alternative.

-- >8 --

From bef52bec926ea08ccd32a3421d195210ae7d3b38 Mon Sep 17 00:00:00 2001
From: Jakub Sitnicki <jakub@cloudflare.com>
Date: Wed, 13 Oct 2021 18:54:12 +0200
Subject: [PATCH] RFC: BPF iterator that always runs the program just once

The test iterator loads the value of bpf_jit_current kernel global:

 # bpftool iter pin tools/testing/selftests/bpf/bpf_iter_once.o /sys/fs/bpf/bpf_jit_current
 libbpf: elf: skipping unrecognized data section(6) .rodata.str1.1
 # cat /sys/fs/bpf/bpf_jit_current
 2
 # for ((i=0; i<10; i++)); do iptables -A OUTPUT -m bpf --bytecode '1,6 0 0 0' -j ACCEPT; done
 # cat /sys/fs/bpf/bpf_jit_current
 12
 # iptables -F OUTPUT
 # cat /sys/fs/bpf/bpf_jit_current
 2

Signed-off-by: Jakub Sitnicki <jakub@cloudflare.com>
---
 include/uapi/linux/bpf.h                      |  7 ++
 kernel/bpf/Makefile                           |  2 +-
 kernel/bpf/helpers.c                          | 22 ++++++
 kernel/bpf/once_iter.c                        | 76 +++++++++++++++++++
 tools/include/uapi/linux/bpf.h                |  7 ++
 .../selftests/bpf/progs/bpf_iter_once.c       | 33 ++++++++
 6 files changed, 146 insertions(+), 1 deletion(-)
 create mode 100644 kernel/bpf/once_iter.c
 create mode 100644 tools/testing/selftests/bpf/progs/bpf_iter_once.c

diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index 6fc59d61937a..ec117ebd3d58 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -4909,6 +4909,12 @@ union bpf_attr {
  *	Return
  *		The number of bytes written to the buffer, or a negative error
  *		in case of failure.
+ *
+ * long bpf_kallsyms_lookup_name(const char *name, u32 name_size)
+ *	Description
+ *		Lookup the address for a symbol.
+ *	Return
+ *		Returns 0 if not found.
  */
 #define __BPF_FUNC_MAPPER(FN)		\
 	FN(unspec),			\
@@ -5089,6 +5095,7 @@ union bpf_attr {
 	FN(task_pt_regs),		\
 	FN(get_branch_snapshot),	\
 	FN(trace_vprintk),		\
+	FN(kallsyms_lookup_name),	\
 	/* */

 /* integer value in 'imm' field of BPF_CALL instruction selects which helper
diff --git a/kernel/bpf/Makefile b/kernel/bpf/Makefile
index 7f33098ca63f..f2dc86ea0f2d 100644
--- a/kernel/bpf/Makefile
+++ b/kernel/bpf/Makefile
@@ -6,7 +6,7 @@ cflags-nogcse-$(CONFIG_X86)$(CONFIG_CC_IS_GCC) := -fno-gcse
 endif
 CFLAGS_core.o += $(call cc-disable-warning, override-init) $(cflags-nogcse-yy)

-obj-$(CONFIG_BPF_SYSCALL) += syscall.o verifier.o inode.o helpers.o tnum.o bpf_iter.o map_iter.o task_iter.o prog_iter.o
+obj-$(CONFIG_BPF_SYSCALL) += syscall.o verifier.o inode.o helpers.o tnum.o bpf_iter.o map_iter.o task_iter.o prog_iter.o once_iter.o
 obj-$(CONFIG_BPF_SYSCALL) += hashtab.o arraymap.o percpu_freelist.o bpf_lru_list.o lpm_trie.o map_in_map.o
 obj-$(CONFIG_BPF_SYSCALL) += local_storage.o queue_stack_maps.o ringbuf.o
 obj-$(CONFIG_BPF_SYSCALL) += bpf_local_storage.o bpf_task_storage.o
diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c
index 1ffd469c217f..d2524df54ab5 100644
--- a/kernel/bpf/helpers.c
+++ b/kernel/bpf/helpers.c
@@ -15,6 +15,7 @@
 #include <linux/pid_namespace.h>
 #include <linux/proc_ns.h>
 #include <linux/security.h>
+#include <linux/kallsyms.h>

 #include "../../lib/kstrtox.h"

@@ -1328,6 +1329,25 @@ void bpf_timer_cancel_and_free(void *val)
 	kfree(t);
 }

+BPF_CALL_2(bpf_kallsyms_lookup_name, const char *, name, u32, name_size)
+{
+	const char *name_end;
+
+	name_end = strnchr(name, name_size, 0);
+	if (!name_end)
+		return -EINVAL;
+
+	return kallsyms_lookup_name(name);
+}
+
+static const struct bpf_func_proto bpf_kallsyms_lookup_name_proto = {
+	.func		= bpf_kallsyms_lookup_name,
+	.gpl_only	= true,
+	.ret_type	= RET_INTEGER,
+	.arg1_type	= ARG_PTR_TO_MEM,
+	.arg2_type	= ARG_CONST_SIZE,
+};
+
 const struct bpf_func_proto bpf_get_current_task_proto __weak;
 const struct bpf_func_proto bpf_get_current_task_btf_proto __weak;
 const struct bpf_func_proto bpf_probe_read_user_proto __weak;
@@ -1404,6 +1424,8 @@ bpf_base_func_proto(enum bpf_func_id func_id)
 		return &bpf_timer_start_proto;
 	case BPF_FUNC_timer_cancel:
 		return &bpf_timer_cancel_proto;
+	case BPF_FUNC_kallsyms_lookup_name:
+		return &bpf_kallsyms_lookup_name_proto;
 	default:
 		break;
 	}
diff --git a/kernel/bpf/once_iter.c b/kernel/bpf/once_iter.c
new file mode 100644
index 000000000000..f2635f1b0043
--- /dev/null
+++ b/kernel/bpf/once_iter.c
@@ -0,0 +1,76 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (c) 2021 Cloudflare, Inc. */
+
+#include <linux/bpf.h>
+#include <linux/init.h>
+#include <linux/seq_file.h>
+
+static struct {} empty;
+
+static void *once_seq_start(struct seq_file *seq, loff_t *pos)
+{
+	if (*pos == 0)
+		++*pos;
+	return &empty;
+}
+
+static void *once_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+	++*pos;
+	return NULL;
+}
+
+struct bpf_iter__once {
+	__bpf_md_ptr(struct bpf_iter_meta *, meta);
+};
+
+DEFINE_BPF_ITER_FUNC(once, struct bpf_iter_meta *meta)
+
+static int once_seq_show(struct seq_file *seq, void *v)
+{
+	return 0;
+}
+
+static void once_seq_stop(struct seq_file *seq, void *v)
+{
+	struct bpf_iter_meta meta;
+	struct bpf_iter__once ctx;
+	struct bpf_prog *prog;
+
+	meta.seq = seq;
+	prog = bpf_iter_get_info(&meta, true);
+	if (!prog)
+		return;
+
+	meta.seq = seq;
+	ctx.meta = &meta;
+	bpf_iter_run_prog(prog, &ctx);
+}
+
+static const struct seq_operations once_seq_ops = {
+	.start	= once_seq_start,
+	.next	= once_seq_next,
+	.stop	= once_seq_stop,
+	.show	= once_seq_show,
+};
+
+static const struct bpf_iter_seq_info once_seq_info = {
+	.seq_ops		= &once_seq_ops,
+	.init_seq_private	= NULL,
+	.fini_seq_private	= NULL,
+	.seq_priv_size		= 0,
+};
+
+static struct bpf_iter_reg once_reg_info = {
+	.target			= "once",
+	.feature		= 0,
+	.ctx_arg_info_size	= 0,
+	.ctx_arg_info		= {},
+	.seq_info		= &once_seq_info,
+};
+
+static int __init once_iter_init(void)
+{
+	return bpf_iter_reg_target(&once_reg_info);
+}
+late_initcall(once_iter_init);
diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h
index 6fc59d61937a..ec117ebd3d58 100644
--- a/tools/include/uapi/linux/bpf.h
+++ b/tools/include/uapi/linux/bpf.h
@@ -4909,6 +4909,12 @@ union bpf_attr {
  *	Return
  *		The number of bytes written to the buffer, or a negative error
  *		in case of failure.
+ *
+ * long bpf_kallsyms_lookup_name(const char *name, u32 name_size)
+ *	Description
+ *		Lookup the address for a symbol.
+ *	Return
+ *		Returns 0 if not found.
  */
 #define __BPF_FUNC_MAPPER(FN)		\
 	FN(unspec),			\
@@ -5089,6 +5095,7 @@ union bpf_attr {
 	FN(task_pt_regs),		\
 	FN(get_branch_snapshot),	\
 	FN(trace_vprintk),		\
+	FN(kallsyms_lookup_name),	\
 	/* */

 /* integer value in 'imm' field of BPF_CALL instruction selects which helper
diff --git a/tools/testing/selftests/bpf/progs/bpf_iter_once.c b/tools/testing/selftests/bpf/progs/bpf_iter_once.c
new file mode 100644
index 000000000000..e5e6d779eb51
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/bpf_iter_once.c
@@ -0,0 +1,33 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2021 Cloudflare, Inc. */
+
+#include "bpf_iter.h"
+#include <bpf/bpf_helpers.h>
+
+char _license[] SEC("license") = "GPL";
+
+SEC("iter/once")
+int dump_once(struct bpf_iter__once *ctx)
+{
+	const char sym_name[] = "bpf_jit_current";
+	struct seq_file *seq = ctx->meta->seq;
+	unsigned long sym_addr;
+	s64 value = 0;
+	int err;
+
+	sym_addr = bpf_kallsyms_lookup_name(sym_name, sizeof(sym_name));
+	if (!sym_addr) {
+		BPF_SEQ_PRINTF(seq, "failed to find %s address\n", sym_name);
+		return 0;
+	}
+
+	err = bpf_probe_read_kernel(&value, sizeof(value), (void *)sym_addr);
+	if (err) {
+		BPF_SEQ_PRINTF(seq, "failed to read from %s address\n", sym_name);
+		return 0;
+	}
+
+	BPF_SEQ_PRINTF(seq, "%ld\n", value);
+
+	return 0;
+}
--
2.31.1
```

## Re: \[PATCH v2 0/4\] Fix up bpf\_jit\_limit some more

- From: Lorenz Bauer \<hidden\>
- Date: 2021-10-14 14:22:45 
- Message: https://ratatoskr.run/netdev/2021/10/7782492.md

```text
On Wed, 13 Oct 2021 at 20:56, Jakub Sitnicki [ref] wrote:
>
> On Tue, Oct 12, 2021 at 03:59 PM CEST, Lorenz Bauer wrote:
> > Some more cleanups around bpf_jit_limit to make it readable via sysctl.
> >
> > Jakub raised the point that a sysctl toggle is UAPI and therefore
> > can't be easily changed later on. I tried to find another place to stick
> > the info, but couldn't find a good one. All the current BPF knobs are in
> > sysctl.
> >
> > There are examples of read only sysctls:
> > $ sudo find /proc/sys -perm 0444 | wc -l
> > 90
> >
> > There are no examples of sysctls with mode 0400 however:
> > $ sudo find /proc/sys -perm 0400 | wc -l
> > 0
> >
> > Thoughts?
>
> I threw this idea out there during LPC already, that it would be cool to
> use BPF iterators for that. Pinned/preloaded iterators were made for
> dumping kernel data on demand after all.
>
> What is missing is a BPF iterator type that would run the program just
> once (there is just one thing to print), and a BPF helper to lookup
> symbol's address.
>
> I thought this would require a bit of work, but actually getting a PoC
> (see below) to work was rather pleasntly straightforward.
>
> Perhaps a bit of a hack but I'd consider it as an alternative.

I spoke to Jakub, I won't have time to work on this myself. So I'll
drop this patch from the series and send a v3 with just the fixes to
bpf_jit_limit.

-- 
Lorenz Bauer  |  Systems Engineer
6th Floor, County Hall/The Riverside Building, SE1 7PB, UK

www.cloudflare.com
```
