* [PATCH bpf 0/2] bpf: Fix iterator link update target validation
@ 2026-10-08 16:13 Jan-Gerd Tenberge
2026-10-08 16:13 ` [PATCH bpf 1/2] bpf: Revalidate iterator programs on link update Jan-Gerd Tenberge
2026-10-08 16:13 ` [PATCH bpf 2/2] selftests/bpf: Test iterator link target validation Jan-Gerd Tenberge
0 siblings, 2 replies; 4+ messages in thread
From: Jan-Gerd Tenberge @ 2026-10-08 16:13 UTC (permalink / raw)
To: bpf
Cc: ast, daniel, andrii, eddyz87, memxor, martin.lau, song,
yonghong.song, jolsa, emil, ihor.solodrai, john.fastabend, davem,
edumazet, kuba, pabeni, horms, jakub, jiayuan.chen, kuniyu,
willemb, shuah, netdev, linux-kernel, linux-kselftest
BPF iterator link creation validates constraints that depend on both the
program and the selected target. BPF_LINK_UPDATE only compares program
type, expected attach type, and attach BTF ID, allowing those checks to be
bypassed by attaching a compatible program first and replacing it later.
Runtime testing in disposable QEMU guests confirmed that the resulting
out-of-bounds access can reach kernel-owned metadata of a separately
allocated live map and cause a deterministic kernel panic. Corrupting a
victim map's refcount caused it to be freed while a verified BPF program
retained a reference. A same-size replacement reused the slab slot, and
the live program read the replacement's marker through its stale map
pointer. A separate test obtained a selected-address eight-byte kernel
read by changing the victim to another valid in-kernel operations table.
These tests did not demonstrate code execution or privilege escalation.
The UAF/read tests and the identity-boundary tests were separate; no single
combined exploit was demonstrated.
In a split-UID test, a UID-1001 process with CAP_BPF and CAP_PERFMON, but
neither CAP_SYS_ADMIN nor CAP_SYS_PTRACE, corrupted a UID-1000-owned map
without possessing its FD. BPF_MAP_GET_FD_BY_ID and pidfd_getfd both
returned EPERM. In another test, a child user namespace mapped to host UID
1000 and given an administrator-delegated BPF token triggered a host kernel
panic; tokenless tracing-program load returned EPERM. There is no
demonstrated default-unprivileged trigger.
Patch 1 reruns both target-specific validation and the iterator
sleepability check before replacing the link's program. Patch 2 covers
rejected array and socket-storage value accesses, a rejected sleepable
hash program, preservation of the old program after a failed update, and
a valid update.
The flaw was introduced by commit d6c4503cc296 ("bpf: Implement bpf
iterator for hash maps") and remains present in bpf.git at ff47652a4b66
and bpf-next at e1d84a37cba9. A patched ff47652a4b66-based kernel rejected
the invalid updates with -EACCES before the programs could execute.
Source reproducers, build-specific layout details, and exploitability logs
are available privately to maintainers on request. They are intentionally
not included in this public posting under the kernel's guidance for bugs
found with AI assistance. The public regression tests do not execute an
out-of-bounds access.
Testing performed:
- Reproduced the bypass, cross-object metadata corruption, kernel panic,
stale-reference reuse, and selected-address read on Debian Linux
7.2.9+deb14-amd64 under isolated QEMU.
- Built bpf_iter.o, map_iter.o, bpf_sk_storage.o, and sock_map.o with
W=1.
- Built the affected BPF selftest objects and skeletons with clang 19.
- Compiled the bpf_iter host selftest with -Wall -Werror.
- Passed git diff --check and checkpatch.pl --strict --no-signoff.
- Verified that the series applies to bpf-next e1d84a37cba9.
- Booted the patched ff47652a4b66-based kernel with vmlinux BTF under
QEMU and confirmed that invalid updates return -EACCES.
An LLM assisted with discovery, analysis, fix implementation, test
development, and review.
Given the memory-safety impact and the Fixes tag, please consider patch 1
for applicable stable trees.
Jan-Gerd Tenberge (2):
bpf: Revalidate iterator programs on link update
selftests/bpf: Test iterator link target validation
include/linux/bpf.h | 3 +
kernel/bpf/bpf_iter.c | 15 +++++
kernel/bpf/map_iter.c | 58 +++++++++++--------
net/core/bpf_sk_storage.c | 24 +++++---
net/core/sock_map.c | 26 ++++++---
.../selftests/bpf/prog_tests/bpf_iter.c | 34 ++++++++++-
.../bpf/progs/bpf_iter_bpf_array_map.c | 17 ++++++
7 files changed, 136 insertions(+), 41 deletions(-)
base-commit: ff47652a4b66c067c765a7ad464d930b5a9367cc
--
2.54.0 (Apple Git-157)
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH bpf 1/2] bpf: Revalidate iterator programs on link update
2026-10-08 16:13 [PATCH bpf 0/2] bpf: Fix iterator link update target validation Jan-Gerd Tenberge
@ 2026-10-08 16:13 ` Jan-Gerd Tenberge
2026-10-08 17:13 ` bot+bpf-ci
2026-10-08 16:13 ` [PATCH bpf 2/2] selftests/bpf: Test iterator link target validation Jan-Gerd Tenberge
1 sibling, 1 reply; 4+ messages in thread
From: Jan-Gerd Tenberge @ 2026-10-08 16:13 UTC (permalink / raw)
To: bpf
Cc: ast, daniel, andrii, eddyz87, memxor, martin.lau, song,
yonghong.song, jolsa, emil, ihor.solodrai, john.fastabend, davem,
edumazet, kuba, pabeni, horms, jakub, jiayuan.chen, kuniyu,
willemb, shuah, netdev, linux-kernel, linux-kselftest
Iterator link creation validates constraints that depend on both the
program and the selected target. In particular, map iterators compare
program access sizes against the target map, and sleepable programs may
only attach to reschedulable iterators.
BPF_LINK_UPDATE only checks the program type, expected attach type and
attach BTF ID. A program rejected on direct attach can therefore be
installed by first attaching a compatible program and then replacing it.
For array maps, this allows an oversized value access to cross the source
map allocation. An isolated runtime test used the bypass to overwrite the
refcount of a separately allocated live map. Dropping one legitimate
reference then freed that map while a verified BPF program still held
another reference. After a same-size map reused the slab slot, the live
program accessed the replacement through its stale map pointer. The same
bypass can also corrupt a live map's ops pointer and panic the kernel.
Add an optional target validation callback and invoke it, together with
the sleepability check, before replacing the program. Factor the existing
map element, sk_storage and sockmap checks into validators shared by attach
and update. A failed validation leaves the old program attached.
Fixes: d6c4503cc296 ("bpf: Implement bpf iterator for hash maps")
Cc: stable@vger.kernel.org
Assisted-by: LLM
Signed-off-by: Jan-Gerd Tenberge <janten@gmail.com>
---
include/linux/bpf.h | 3 ++
kernel/bpf/bpf_iter.c | 15 ++++++++++
kernel/bpf/map_iter.c | 58 +++++++++++++++++++++++----------------
net/core/bpf_sk_storage.c | 24 +++++++++++-----
net/core/sock_map.c | 26 ++++++++++++------
5 files changed, 87 insertions(+), 39 deletions(-)
diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 0ecb9418dfbd..5aa786eba3ea 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -3007,6 +3007,8 @@ struct bpf_iter_aux_info {
typedef int (*bpf_iter_attach_target_t)(struct bpf_prog *prog,
union bpf_iter_link_info *linfo,
struct bpf_iter_aux_info *aux);
+typedef int (*bpf_iter_validate_target_t)(struct bpf_prog *prog,
+ const struct bpf_iter_aux_info *aux);
typedef void (*bpf_iter_detach_target_t)(struct bpf_iter_aux_info *aux);
typedef void (*bpf_iter_show_fdinfo_t) (const struct bpf_iter_aux_info *aux,
struct seq_file *seq);
@@ -3024,6 +3026,7 @@ enum bpf_iter_feature {
struct bpf_iter_reg {
const char *target;
bpf_iter_attach_target_t attach_target;
+ bpf_iter_validate_target_t validate_target;
bpf_iter_detach_target_t detach_target;
bpf_iter_show_fdinfo_t show_fdinfo;
bpf_iter_fill_link_info_t fill_link_info;
diff --git a/kernel/bpf/bpf_iter.c b/kernel/bpf/bpf_iter.c
index b40eb404adab..024419b3dd0a 100644
--- a/kernel/bpf/bpf_iter.c
+++ b/kernel/bpf/bpf_iter.c
@@ -409,6 +409,9 @@ static int bpf_iter_link_replace(struct bpf_link *link,
struct bpf_prog *new_prog,
struct bpf_prog *old_prog)
{
+ struct bpf_iter_link *iter_link =
+ container_of(link, struct bpf_iter_link, link);
+ const struct bpf_iter_reg *reg_info = iter_link->tinfo->reg_info;
int ret = 0;
mutex_lock(&link_mutex);
@@ -424,6 +427,18 @@ static int bpf_iter_link_replace(struct bpf_link *link,
goto out_unlock;
}
+ if (new_prog->sleepable &&
+ !bpf_iter_target_support_resched(iter_link->tinfo)) {
+ ret = -EINVAL;
+ goto out_unlock;
+ }
+
+ if (reg_info->validate_target) {
+ ret = reg_info->validate_target(new_prog, &iter_link->aux);
+ if (ret)
+ goto out_unlock;
+ }
+
old_prog = xchg(&link->prog, new_prog);
bpf_prog_put(old_prog);
diff --git a/kernel/bpf/map_iter.c b/kernel/bpf/map_iter.c
index c19b360bad9e..d038b795bf4e 100644
--- a/kernel/bpf/map_iter.c
+++ b/kernel/bpf/map_iter.c
@@ -97,13 +97,40 @@ static struct bpf_iter_reg bpf_map_reg_info = {
.seq_info = &bpf_map_seq_info,
};
+static int bpf_iter_validate_map(struct bpf_prog *prog,
+ const struct bpf_iter_aux_info *aux)
+{
+ struct bpf_map *map = aux->map;
+ u32 value_size;
+
+ switch (map->map_type) {
+ case BPF_MAP_TYPE_PERCPU_HASH:
+ case BPF_MAP_TYPE_LRU_PERCPU_HASH:
+ case BPF_MAP_TYPE_PERCPU_ARRAY:
+ value_size = round_up(map->value_size, 8) * num_possible_cpus();
+ break;
+ case BPF_MAP_TYPE_HASH:
+ case BPF_MAP_TYPE_LRU_HASH:
+ case BPF_MAP_TYPE_ARRAY:
+ case BPF_MAP_TYPE_RHASH:
+ value_size = map->value_size;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (prog->aux->max_rdonly_access > map->key_size ||
+ prog->aux->max_rdwr_access > value_size)
+ return -EACCES;
+
+ return 0;
+}
+
static int bpf_iter_attach_map(struct bpf_prog *prog,
union bpf_iter_link_info *linfo,
struct bpf_iter_aux_info *aux)
{
- u32 key_acc_size, value_acc_size, key_size, value_size;
struct bpf_map *map;
- bool is_percpu = false;
int err = -EINVAL;
if (!linfo->map.map_fd)
@@ -117,33 +144,15 @@ static int bpf_iter_attach_map(struct bpf_prog *prog,
goto put_map;
}
- if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH ||
- map->map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH ||
- map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY)
- is_percpu = true;
- else if (map->map_type != BPF_MAP_TYPE_HASH &&
- map->map_type != BPF_MAP_TYPE_LRU_HASH &&
- map->map_type != BPF_MAP_TYPE_ARRAY &&
- map->map_type != BPF_MAP_TYPE_RHASH)
- goto put_map;
-
- key_acc_size = prog->aux->max_rdonly_access;
- value_acc_size = prog->aux->max_rdwr_access;
- key_size = map->key_size;
- if (!is_percpu)
- value_size = map->value_size;
- else
- value_size = round_up(map->value_size, 8) * num_possible_cpus();
-
- if (key_acc_size > key_size || value_acc_size > value_size) {
- err = -EACCES;
+ aux->map = map;
+ err = bpf_iter_validate_map(prog, aux);
+ if (err)
goto put_map;
- }
- aux->map = map;
return 0;
put_map:
+ aux->map = NULL;
bpf_map_put_with_uref(map);
return err;
}
@@ -172,6 +181,7 @@ DEFINE_BPF_ITER_FUNC(bpf_map_elem, struct bpf_iter_meta *meta,
static const struct bpf_iter_reg bpf_map_elem_reg_info = {
.target = "bpf_map_elem",
.attach_target = bpf_iter_attach_map,
+ .validate_target = bpf_iter_validate_map,
.detach_target = bpf_iter_detach_map,
.show_fdinfo = bpf_iter_map_show_fdinfo,
.fill_link_info = bpf_iter_map_fill_link_info,
diff --git a/net/core/bpf_sk_storage.c b/net/core/bpf_sk_storage.c
index 1d295a8769fa..0cae873f3ceb 100644
--- a/net/core/bpf_sk_storage.c
+++ b/net/core/bpf_sk_storage.c
@@ -846,6 +846,18 @@ static void bpf_iter_fini_sk_storage_map(void *priv_data)
bpf_map_put_with_uref(seq_info->map);
}
+static int bpf_iter_validate_map(struct bpf_prog *prog,
+ const struct bpf_iter_aux_info *aux)
+{
+ if (aux->map->map_type != BPF_MAP_TYPE_SK_STORAGE)
+ return -EINVAL;
+
+ if (prog->aux->max_rdwr_access > aux->map->value_size)
+ return -EACCES;
+
+ return 0;
+}
+
static int bpf_iter_attach_map(struct bpf_prog *prog,
union bpf_iter_link_info *linfo,
struct bpf_iter_aux_info *aux)
@@ -860,18 +872,15 @@ static int bpf_iter_attach_map(struct bpf_prog *prog,
if (IS_ERR(map))
return PTR_ERR(map);
- if (map->map_type != BPF_MAP_TYPE_SK_STORAGE)
- goto put_map;
-
- if (prog->aux->max_rdwr_access > map->value_size) {
- err = -EACCES;
+ aux->map = map;
+ err = bpf_iter_validate_map(prog, aux);
+ if (err)
goto put_map;
- }
- aux->map = map;
return 0;
put_map:
+ aux->map = NULL;
bpf_map_put_with_uref(map);
return err;
}
@@ -898,6 +907,7 @@ static const struct bpf_iter_seq_info iter_seq_info = {
static struct bpf_iter_reg bpf_sk_storage_map_reg_info = {
.target = "bpf_sk_storage_map",
.attach_target = bpf_iter_attach_map,
+ .validate_target = bpf_iter_validate_map,
.detach_target = bpf_iter_detach_map,
.show_fdinfo = bpf_iter_map_show_fdinfo,
.fill_link_info = bpf_iter_map_fill_link_info,
diff --git a/net/core/sock_map.c b/net/core/sock_map.c
index 38df84284328..31f7c3a1667e 100644
--- a/net/core/sock_map.c
+++ b/net/core/sock_map.c
@@ -1933,6 +1933,19 @@ int sock_map_link_create(const union bpf_attr *attr, struct bpf_prog *prog)
return ret;
}
+static int sock_map_iter_validate_target(struct bpf_prog *prog,
+ const struct bpf_iter_aux_info *aux)
+{
+ if (aux->map->map_type != BPF_MAP_TYPE_SOCKMAP &&
+ aux->map->map_type != BPF_MAP_TYPE_SOCKHASH)
+ return -EINVAL;
+
+ if (prog->aux->max_rdonly_access > aux->map->key_size)
+ return -EACCES;
+
+ return 0;
+}
+
static int sock_map_iter_attach_target(struct bpf_prog *prog,
union bpf_iter_link_info *linfo,
struct bpf_iter_aux_info *aux)
@@ -1947,19 +1960,15 @@ static int sock_map_iter_attach_target(struct bpf_prog *prog,
if (IS_ERR(map))
return PTR_ERR(map);
- if (map->map_type != BPF_MAP_TYPE_SOCKMAP &&
- map->map_type != BPF_MAP_TYPE_SOCKHASH)
- goto put_map;
-
- if (prog->aux->max_rdonly_access > map->key_size) {
- err = -EACCES;
+ aux->map = map;
+ err = sock_map_iter_validate_target(prog, aux);
+ if (err)
goto put_map;
- }
- aux->map = map;
return 0;
put_map:
+ aux->map = NULL;
bpf_map_put_with_uref(map);
return err;
}
@@ -1972,6 +1981,7 @@ static void sock_map_iter_detach_target(struct bpf_iter_aux_info *aux)
static struct bpf_iter_reg sock_map_iter_reg = {
.target = "sockmap",
.attach_target = sock_map_iter_attach_target,
+ .validate_target = sock_map_iter_validate_target,
.detach_target = sock_map_iter_detach_target,
.show_fdinfo = bpf_iter_map_show_fdinfo,
.fill_link_info = bpf_iter_map_fill_link_info,
--
2.54.0 (Apple Git-157)
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH bpf 2/2] selftests/bpf: Test iterator link target validation
2026-10-08 16:13 [PATCH bpf 0/2] bpf: Fix iterator link update target validation Jan-Gerd Tenberge
2026-10-08 16:13 ` [PATCH bpf 1/2] bpf: Revalidate iterator programs on link update Jan-Gerd Tenberge
@ 2026-10-08 16:13 ` Jan-Gerd Tenberge
1 sibling, 0 replies; 4+ messages in thread
From: Jan-Gerd Tenberge @ 2026-10-08 16:13 UTC (permalink / raw)
To: bpf
Cc: ast, daniel, andrii, eddyz87, memxor, martin.lau, song,
yonghong.song, jolsa, emil, ihor.solodrai, john.fastabend, davem,
edumazet, kuba, pabeni, horms, jakub, jiayuan.chen, kuniyu,
willemb, shuah, netdev, linux-kernel, linux-kselftest
Exercise target-dependent iterator checks during BPF_LINK_UPDATE.
Verify that updates to a program with an oversized array or socket-storage
value access are rejected, as is an update to a sleepable program on a
non-reschedulable hash iterator.
Run each original program after the rejected update to ensure that it
remains attached. Also verify that a compatible array iterator update
succeeds.
Assisted-by: LLM
Signed-off-by: Jan-Gerd Tenberge <janten@gmail.com>
---
.../selftests/bpf/prog_tests/bpf_iter.c | 34 +++++++++++++++++--
.../bpf/progs/bpf_iter_bpf_array_map.c | 17 ++++++++++
2 files changed, 49 insertions(+), 2 deletions(-)
diff --git a/tools/testing/selftests/bpf/prog_tests/bpf_iter.c b/tools/testing/selftests/bpf/prog_tests/bpf_iter.c
index c69080ca14f5..3ae5203d3fac 100644
--- a/tools/testing/selftests/bpf/prog_tests/bpf_iter.c
+++ b/tools/testing/selftests/bpf/prog_tests/bpf_iter.c
@@ -897,14 +897,22 @@ static void test_bpf_hash_map(void)
/* Sleepable program is prohibited for hash map iterator */
linfo.map.map_fd = map_fd;
link = bpf_program__attach_iter(skel->progs.sleepable_dummy_dump, &opts);
- if (!ASSERT_ERR_PTR(link, "attach_sleepable_prog_to_iter"))
+ err = libbpf_get_error(link);
+ if (!ASSERT_EQ(err, -EINVAL, "attach_sleepable_prog_to_iter")) {
+ if (!err)
+ bpf_link__destroy(link);
goto out;
+ }
linfo.map.map_fd = map_fd;
link = bpf_program__attach_iter(skel->progs.dump_bpf_hash_map, &opts);
if (!ASSERT_OK_PTR(link, "attach_iter"))
goto out;
+ err = bpf_link__update_program(link, skel->progs.sleepable_dummy_dump);
+ if (!ASSERT_EQ(err, -EINVAL, "update_sleepable_prog"))
+ goto free_link;
+
iter_fd = bpf_iter_create(bpf_link__fd(link));
if (!ASSERT_GE(iter_fd, 0, "create_iter"))
goto free_link;
@@ -1023,7 +1031,7 @@ static void test_bpf_array_map(void)
int err, i, map_fd, hash_fd, iter_fd;
struct bpf_iter_bpf_array_map *skel;
union bpf_iter_link_info linfo;
- struct bpf_link *link;
+ struct bpf_link *link, *bad_link;
char buf[64] = {};
int len, start;
@@ -1049,10 +1057,24 @@ static void test_bpf_array_map(void)
linfo.map.map_fd = map_fd;
opts.link_info = &linfo;
opts.link_info_len = sizeof(linfo);
+ bad_link = bpf_program__attach_iter(skel->progs.oob_write_bpf_array_map,
+ &opts);
+ err = libbpf_get_error(bad_link);
+ if (!ASSERT_EQ(err, -EACCES, "attach_oob_write_iter")) {
+ if (!err)
+ bpf_link__destroy(bad_link);
+ goto out;
+ }
+
link = bpf_program__attach_iter(skel->progs.dump_bpf_array_map, &opts);
if (!ASSERT_OK_PTR(link, "attach_iter"))
goto out;
+ err = bpf_link__update_program(link, skel->progs.oob_write_bpf_array_map);
+ if (!ASSERT_EQ(err, -EACCES, "update_oob_write_iter"))
+ goto free_link;
+
+ /* The rejected update must leave dump_bpf_array_map attached. */
iter_fd = bpf_iter_create(bpf_link__fd(link));
if (!ASSERT_GE(iter_fd, 0, "create_iter"))
goto free_link;
@@ -1092,6 +1114,9 @@ static void test_bpf_array_map(void)
goto close_iter;
}
+ err = bpf_link__update_program(link, skel->progs.noop_bpf_array_map);
+ ASSERT_OK(err, "update_valid_iter");
+
close_iter:
close(iter_fd);
free_link:
@@ -1363,6 +1388,11 @@ static void test_bpf_sk_storage_map(void)
if (!ASSERT_OK_PTR(link, "attach_iter"))
goto out;
+ err = bpf_link__update_program(link,
+ skel->progs.oob_write_bpf_sk_storage_map);
+ if (!ASSERT_EQ(err, -EACCES, "update_oob_write_iter"))
+ goto free_link;
+
iter_fd = bpf_iter_create(bpf_link__fd(link));
if (!ASSERT_GE(iter_fd, 0, "create_iter"))
goto free_link;
diff --git a/tools/testing/selftests/bpf/progs/bpf_iter_bpf_array_map.c b/tools/testing/selftests/bpf/progs/bpf_iter_bpf_array_map.c
index 19710cc0f250..beb1b714f120 100644
--- a/tools/testing/selftests/bpf/progs/bpf_iter_bpf_array_map.c
+++ b/tools/testing/selftests/bpf/progs/bpf_iter_bpf_array_map.c
@@ -51,3 +51,20 @@ int dump_bpf_array_map(struct bpf_iter__bpf_map_elem *ctx)
*val = *key;
return 0;
}
+
+SEC("iter/bpf_map_elem")
+int noop_bpf_array_map(struct bpf_iter__bpf_map_elem *ctx)
+{
+ return 0;
+}
+
+SEC("iter/bpf_map_elem")
+int oob_write_bpf_array_map(struct bpf_iter__bpf_map_elem *ctx)
+{
+ __u64 *val = ctx->value;
+
+ if (val)
+ val[1] = 0;
+
+ return 0;
+}
--
2.54.0 (Apple Git-157)
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH bpf 1/2] bpf: Revalidate iterator programs on link update
2026-10-08 16:13 ` [PATCH bpf 1/2] bpf: Revalidate iterator programs on link update Jan-Gerd Tenberge
@ 2026-10-08 17:13 ` bot+bpf-ci
0 siblings, 0 replies; 4+ messages in thread
From: bot+bpf-ci @ 2026-10-08 17:13 UTC (permalink / raw)
To: janten, bpf
Cc: ast, daniel, andrii, eddyz87, memxor, martin.lau, song,
yonghong.song, jolsa, emil, ihor.solodrai, john.fastabend, davem,
edumazet, kuba, pabeni, horms, jakub, jiayuan.chen, kuniyu,
willemb, shuah, netdev, linux-kernel, linux-kselftest, ast,
andrii, daniel, martin.lau, eddyz87, yonghong.song, mason,
ihor.solodrai
[-- Attachment #1: Type: text/plain, Size: 2122 bytes --]
> bpf: Revalidate iterator programs on link update
TL;DR: Nit only: Documentation/bpf/bpf_iterators.rst may need updating for the
new validate_target callback in struct bpf_iter_reg and for when it is invoked
(BPF_LINK_UPDATE only). No code problems reported.
> diff --git a/include/linux/bpf.h b/include/linux/bpf.h
> index 0ecb9418dfbd..5aa786eba3ea 100644
> --- a/include/linux/bpf.h
> +++ b/include/linux/bpf.h
[ ... ]
> @@ -3024,6 +3026,7 @@ enum bpf_iter_feature {
> struct bpf_iter_reg {
> const char *target;
> bpf_iter_attach_target_t attach_target;
> + bpf_iter_validate_target_t validate_target;
> bpf_iter_detach_target_t detach_target;
> bpf_iter_show_fdinfo_t show_fdinfo;
> bpf_iter_fill_link_info_t fill_link_info;
This isn't a bug, but should Documentation/bpf/bpf_iterators.rst be updated
for the new member?
That file carries a copy of struct bpf_iter_reg that listed attach_target
and detach_target exactly as they appeared in this header before the patch:
bpf_iter_attach_target_t attach_target;
bpf_iter_detach_target_t detach_target;
It now lacks validate_target.
The field table in the same file also describes the callbacks as:
attach_target and detach_target
Allows for target specific link_create action since some targets may
need special processing. Called during the user space link_create
stage.
Nothing there says that validate_target is invoked only from
bpf_iter_link_replace() (BPF_LINK_UPDATE), and that a target's
attach_target has to call its validator itself at link_create time, since
bpf_iter_link_attach() does not call it generically.
A new iterator author working from the documentation would not learn that
program-dependent checks belong in validate_target as well as in
attach_target.
Should the struct listing and the field table describe validate_target and
when it is invoked?
---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md
CI run summary: https://github.com/kernel-patches/bpf/actions/runs/37809581821
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-10-08 17:13 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-08 16:13 [PATCH bpf 0/2] bpf: Fix iterator link update target validation Jan-Gerd Tenberge
2026-10-08 16:13 ` [PATCH bpf 1/2] bpf: Revalidate iterator programs on link update Jan-Gerd Tenberge
2026-10-08 17:13 ` bot+bpf-ci
2026-10-08 16:13 ` [PATCH bpf 2/2] selftests/bpf: Test iterator link target validation Jan-Gerd Tenberge
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®