* [PATCH bpf-next] bpf: add BPF_F_SEALED flag to seal BPF links at creation
@ 2026-08-03 2:16 David Windsor
2026-08-03 2:20 ` David Windsor
` (3 more replies)
0 siblings, 4 replies; 10+ messages in thread
From: David Windsor @ 2026-08-03 2:16 UTC (permalink / raw)
To: bpf, Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Eduard Zingerman, Kumar Kartikeya Dwivedi
Cc: Martin KaFai Lau, Song Liu, Yonghong Song, Jiri Olsa,
John Fastabend, Emil Tsalapatis, Ihor Solodrai, David Windsor
Introduce a new BPF_F_SEALED flag for BPF_LINK_CREATE that creates the
link permanently sealed. A sealed link can never have its program
replaced via BPF_LINK_UPDATE, can never be detached via BPF_LINK_DETACH,
and holds an extra self-reference that is never released, so the link and
its program attachment persist until the machine reboots, even after user
space closes every fd referring to it. There is no way to unseal a link.
The sealed state is tracked by a new bool field on struct bpf_link.
Signed-off-by: David Windsor <dwindsor@gmail.com>
---
include/linux/bpf.h | 2 ++
include/uapi/linux/bpf.h | 1 +
kernel/bpf/syscall.c | 41 +++++++++++++++++++++++++++++++---
tools/include/uapi/linux/bpf.h | 1 +
4 files changed, 42 insertions(+), 3 deletions(-)
diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 7bfc28673124..a9600a1483ec 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -1934,6 +1934,8 @@ struct bpf_link {
* link's semantics is determined by target attach hook
*/
bool sleepable;
+ /* set once by BPF_F_SEALED; blocks update/detach, pins link until reboot */
+ bool sealed;
};
struct bpf_link_ops {
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index ffd96e8b920b..8cb30d18fec7 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -1251,6 +1251,7 @@ enum bpf_perf_event_type {
#define BPF_F_AFTER (1U << 4)
#define BPF_F_ID (1U << 5)
#define BPF_F_PREORDER (1U << 6)
+#define BPF_F_SEALED (1U << 7)
#define BPF_F_LINK BPF_F_LINK /* 1 << 13 */
/* If BPF_F_STRICT_ALIGNMENT is used in BPF_PROG_LOAD command, the
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 94091130bcc5..e8bd57d5c907 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -3411,6 +3411,7 @@ static void bpf_link_show_fdinfo(struct seq_file *m, struct file *filp)
seq_printf(m, "link_type:\t<%u>\n", type);
}
seq_printf(m, "link_id:\t%u\n", link->id);
+ seq_printf(m, "sealed:\t%d\n", READ_ONCE(link->sealed) ? 1 : 0);
rcu_read_lock();
prog = READ_ONCE(link->prog);
@@ -5776,17 +5777,41 @@ static int bpf_map_do_batch(const union bpf_attr *attr,
return err;
}
+/* Seal the just-created link: take a self-reference that is never released. */
+static void link_seal_fd(int fd)
+{
+ struct bpf_link *link;
+
+ link = bpf_link_get_from_fd(fd);
+ if (IS_ERR(link))
+ return;
+
+ if (!READ_ONCE(link->sealed)) {
+ bpf_link_inc(link);
+ WRITE_ONCE(link->sealed, true);
+ }
+
+ bpf_link_put_direct(link);
+}
+
#define BPF_LINK_CREATE_LAST_FIELD link_create.uprobe_multi.path_fd
static int link_create(union bpf_attr *attr, bpfptr_t uattr)
{
struct bpf_prog *prog;
+ bool seal;
int ret;
if (CHECK_ATTR(BPF_LINK_CREATE))
return -EINVAL;
- if (attr->link_create.attach_type == BPF_STRUCT_OPS)
- return bpf_struct_ops_link_create(attr);
+ /* Strip BPF_F_SEALED before per-type flag validation. */
+ seal = attr->link_create.flags & BPF_F_SEALED;
+ attr->link_create.flags &= ~BPF_F_SEALED;
+
+ if (attr->link_create.attach_type == BPF_STRUCT_OPS) {
+ ret = bpf_struct_ops_link_create(attr);
+ goto out_seal;
+ }
prog = bpf_prog_get(attr->link_create.prog_fd);
if (IS_ERR(prog))
@@ -5880,6 +5905,9 @@ static int link_create(union bpf_attr *attr, bpfptr_t uattr)
out:
if (ret < 0)
bpf_prog_put(prog);
+out_seal:
+ if (ret >= 0 && seal)
+ link_seal_fd(ret);
return ret;
}
@@ -5932,6 +5960,11 @@ static int link_update(union bpf_attr *attr)
if (IS_ERR(link))
return PTR_ERR(link);
+ if (READ_ONCE(link->sealed)) {
+ ret = -EPERM;
+ goto out_put_link;
+ }
+
if (link->ops->update_map) {
ret = link_update_map(link, attr);
goto out_put_link;
@@ -5984,7 +6017,9 @@ static int link_detach(union bpf_attr *attr)
if (IS_ERR(link))
return PTR_ERR(link);
- if (link->ops->detach)
+ if (READ_ONCE(link->sealed))
+ ret = -EPERM;
+ else if (link->ops->detach)
ret = link->ops->detach(link);
else
ret = -EOPNOTSUPP;
diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h
index ffd96e8b920b..8cb30d18fec7 100644
--- a/tools/include/uapi/linux/bpf.h
+++ b/tools/include/uapi/linux/bpf.h
@@ -1251,6 +1251,7 @@ enum bpf_perf_event_type {
#define BPF_F_AFTER (1U << 4)
#define BPF_F_ID (1U << 5)
#define BPF_F_PREORDER (1U << 6)
+#define BPF_F_SEALED (1U << 7)
#define BPF_F_LINK BPF_F_LINK /* 1 << 13 */
/* If BPF_F_STRICT_ALIGNMENT is used in BPF_PROG_LOAD command, the
base-commit: 28e911d61d66b92a3bded8b54622ed3cd2795bf6
--
2.53.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH bpf-next] bpf: add BPF_F_SEALED flag to seal BPF links at creation
2026-08-03 2:16 [PATCH bpf-next] bpf: add BPF_F_SEALED flag to seal BPF links at creation David Windsor
@ 2026-08-03 2:20 ` David Windsor
2026-08-03 3:23 ` Kumar Kartikeya Dwivedi
2026-08-03 2:28 ` sashiko-bot
` (2 subsequent siblings)
3 siblings, 1 reply; 10+ messages in thread
From: David Windsor @ 2026-08-03 2:20 UTC (permalink / raw)
To: bpf, Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Eduard Zingerman, Kumar Kartikeya Dwivedi
Cc: Martin KaFai Lau, Song Liu, Yonghong Song, Jiri Olsa,
John Fastabend, Emil Tsalapatis, Ihor Solodrai
On Sun, Aug 2, 2026 at 10:16 PM David Windsor <dwindsor@gmail.com> wrote:
>
> Introduce a new BPF_F_SEALED flag for BPF_LINK_CREATE that creates the
> link permanently sealed. A sealed link can never have its program
> replaced via BPF_LINK_UPDATE, can never be detached via BPF_LINK_DETACH,
> and holds an extra self-reference that is never released, so the link and
> its program attachment persist until the machine reboots, even after user
> space closes every fd referring to it. There is no way to unseal a link.
>
> The sealed state is tracked by a new bool field on struct bpf_link.
>
> Signed-off-by: David Windsor <dwindsor@gmail.com>
> ---
> include/linux/bpf.h | 2 ++
> include/uapi/linux/bpf.h | 1 +
> kernel/bpf/syscall.c | 41 +++++++++++++++++++++++++++++++---
> tools/include/uapi/linux/bpf.h | 1 +
> 4 files changed, 42 insertions(+), 3 deletions(-)
>
There is deliberately no selftest for this, as running any such
selftest would necessarily create a sealed link, which cannot be
cleaned up.
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH bpf-next] bpf: add BPF_F_SEALED flag to seal BPF links at creation
2026-08-03 2:16 [PATCH bpf-next] bpf: add BPF_F_SEALED flag to seal BPF links at creation David Windsor
2026-08-03 2:20 ` David Windsor
@ 2026-08-03 2:28 ` sashiko-bot
2026-08-03 2:44 ` Leon Hwang
2026-08-03 3:18 ` Kumar Kartikeya Dwivedi
3 siblings, 0 replies; 10+ messages in thread
From: sashiko-bot @ 2026-08-03 2:28 UTC (permalink / raw)
To: David Windsor; +Cc: bpf
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] The BPF_F_SEALED flag is applied via a file descriptor lookup after the FD has been exposed to user space, creating a TOCTOU race that allows cross-object sabotage and unauthorized link sealing.
- [High] The implementation of BPF_F_SEALED introduces a permanent memory leak, enabling a Denial of Service (DoS) via kernel resource exhaustion.
- [Medium] Concurrent executions of `link_seal_fd` on the same link can leak multiple self-references due to a missing atomic read-modify-write.
--
--- Patch [1]: [PATCH bpf-next] bpf: add BPF_F_SEALED flag to seal BPF links at creation ---
commit f9d98fb378be461fdf9509562339b45a07b8d912
Author: David Windsor <dwindsor@gmail.com>
bpf: add BPF_F_SEALED flag to seal BPF links at creation
This commit introduces a new BPF_F_SEALED flag for BPF_LINK_CREATE that
creates a permanently sealed link. A sealed link cannot have its program
replaced, cannot be detached, and holds an extra self-reference so it
persists until reboot.
> diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
> index 94091130bcc50..e8bd57d5c907a 100644
> --- a/kernel/bpf/syscall.c
> +++ b/kernel/bpf/syscall.c
[ ... ]
> @@ -5776,17 +5777,41 @@ static int bpf_map_do_batch(const union bpf_attr *attr,
> return err;
> }
>
> +/* Seal the just-created link: take a self-reference that is never released. */
> +static void link_seal_fd(int fd)
> +{
> + struct bpf_link *link;
> +
> + link = bpf_link_get_from_fd(fd);
> + if (IS_ERR(link))
> + return;
> +
> + if (!READ_ONCE(link->sealed)) {
[Severity: Medium]
Is this flag check safe against concurrent execution?
If the file descriptor is raced via dup2(), multiple threads might enter
link_seal_fd() for the same victim link concurrently. Since the READ_ONCE()
and WRITE_ONCE() are not atomic, could multiple threads observe false and
increment the link reference count multiple times?
> + bpf_link_inc(link);
> + WRITE_ONCE(link->sealed, true);
[Severity: High]
Does taking a self-reference here without any release path allow users to
exhaust kernel memory?
Since link_detach() explicitly returns -EPERM for sealed links, a user could
repeatedly create sealed links and close the fds, leaking the bpf_link and
bpf_prog indefinitely. Is there an administrative way to reclaim this memory?
> + }
> +
> + bpf_link_put_direct(link);
> +}
[ ... ]
> @@ -5880,6 +5905,9 @@ static int link_create(union bpf_attr *attr, bpfptr_t uattr)
> out:
> if (ret < 0)
> bpf_prog_put(prog);
> +out_seal:
> + if (ret >= 0 && seal)
> + link_seal_fd(ret);
[Severity: High]
Does looking up the link from the file descriptor here create a race
condition?
By the time link_create() reaches this point, attach functions called
earlier have already installed the fd into the process's file descriptor
table.
Could a concurrent thread use dup2() to overwrite this fd with one pointing
to a different victim bpf_link before link_seal_fd() executes? This would
cause the system to permanently seal the victim link instead of the newly
created one.
> return ret;
> }
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260803021643.2189641-1-dwindsor@gmail.com?part=1
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH bpf-next] bpf: add BPF_F_SEALED flag to seal BPF links at creation
2026-08-03 2:16 [PATCH bpf-next] bpf: add BPF_F_SEALED flag to seal BPF links at creation David Windsor
2026-08-03 2:20 ` David Windsor
2026-08-03 2:28 ` sashiko-bot
@ 2026-08-03 2:44 ` Leon Hwang
2026-08-03 3:17 ` Kumar Kartikeya Dwivedi
2026-08-03 3:26 ` David Windsor
2026-08-03 3:18 ` Kumar Kartikeya Dwivedi
3 siblings, 2 replies; 10+ messages in thread
From: Leon Hwang @ 2026-08-03 2:44 UTC (permalink / raw)
To: David Windsor, bpf, Alexei Starovoitov, Daniel Borkmann,
Andrii Nakryiko, Eduard Zingerman, Kumar Kartikeya Dwivedi
Cc: Martin KaFai Lau, Song Liu, Yonghong Song, Jiri Olsa,
John Fastabend, Emil Tsalapatis, Ihor Solodrai
On 3/8/26 10:16, David Windsor wrote:
> Introduce a new BPF_F_SEALED flag for BPF_LINK_CREATE that creates the
> link permanently sealed. A sealed link can never have its program
> replaced via BPF_LINK_UPDATE, can never be detached via BPF_LINK_DETACH,
> and holds an extra self-reference that is never released, so the link and
> its program attachment persist until the machine reboots, even after user
> space closes every fd referring to it. There is no way to unseal a link.
>
> The sealed state is tracked by a new bool field on struct bpf_link.
Why do you want BPF_F_SEALED? What's your case for it?
I think 'sealed' should be set before allocating the FD to avoid the
race issues reported by Sashiko.
Thanks,
Leon
> [...]
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH bpf-next] bpf: add BPF_F_SEALED flag to seal BPF links at creation
2026-08-03 2:44 ` Leon Hwang
@ 2026-08-03 3:17 ` Kumar Kartikeya Dwivedi
2026-08-03 3:26 ` David Windsor
1 sibling, 0 replies; 10+ messages in thread
From: Kumar Kartikeya Dwivedi @ 2026-08-03 3:17 UTC (permalink / raw)
To: Leon Hwang, David Windsor, bpf, Alexei Starovoitov,
Daniel Borkmann, Andrii Nakryiko, Eduard Zingerman
Cc: Martin KaFai Lau, Song Liu, Yonghong Song, Jiri Olsa,
John Fastabend, Emil Tsalapatis, Ihor Solodrai
On Mon Aug 3, 2026 at 4:44 AM CEST, Leon Hwang wrote:
> On 3/8/26 10:16, David Windsor wrote:
>> Introduce a new BPF_F_SEALED flag for BPF_LINK_CREATE that creates the
>> link permanently sealed. A sealed link can never have its program
>> replaced via BPF_LINK_UPDATE, can never be detached via BPF_LINK_DETACH,
>> and holds an extra self-reference that is never released, so the link and
>> its program attachment persist until the machine reboots, even after user
>> space closes every fd referring to it. There is no way to unseal a link.
>>
>> The sealed state is tracked by a new bool field on struct bpf_link.
>
>
> Why do you want BPF_F_SEALED? What's your case for it?
>
> I think 'sealed' should be set before allocating the FD to avoid the
> race issues reported by Sashiko.
>
Agreed, then we would not need READ_ONCE() on the sealed bit either since the
it stays immutable through the lifetime of the link.
> Thanks,
> Leon
>
>> [...]
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH bpf-next] bpf: add BPF_F_SEALED flag to seal BPF links at creation
2026-08-03 2:16 [PATCH bpf-next] bpf: add BPF_F_SEALED flag to seal BPF links at creation David Windsor
` (2 preceding siblings ...)
2026-08-03 2:44 ` Leon Hwang
@ 2026-08-03 3:18 ` Kumar Kartikeya Dwivedi
3 siblings, 0 replies; 10+ messages in thread
From: Kumar Kartikeya Dwivedi @ 2026-08-03 3:18 UTC (permalink / raw)
To: David Windsor, bpf, Alexei Starovoitov, Daniel Borkmann,
Andrii Nakryiko, Eduard Zingerman
Cc: Martin KaFai Lau, Song Liu, Yonghong Song, Jiri Olsa,
John Fastabend, Emil Tsalapatis, Ihor Solodrai, Christian Brauner
+Cc Christian since he was involved in the discussion at LSF/MM/BPF.
On Mon Aug 3, 2026 at 4:16 AM CEST, David Windsor wrote:
> Introduce a new BPF_F_SEALED flag for BPF_LINK_CREATE that creates the
> link permanently sealed. A sealed link can never have its program
> replaced via BPF_LINK_UPDATE, can never be detached via BPF_LINK_DETACH,
> and holds an extra self-reference that is never released, so the link and
> its program attachment persist until the machine reboots, even after user
> space closes every fd referring to it. There is no way to unseal a link.
>
> The sealed state is tracked by a new bool field on struct bpf_link.
>
> Signed-off-by: David Windsor <dwindsor@gmail.com>
> ---
> include/linux/bpf.h | 2 ++
> include/uapi/linux/bpf.h | 1 +
> kernel/bpf/syscall.c | 41 +++++++++++++++++++++++++++++++---
> tools/include/uapi/linux/bpf.h | 1 +
> 4 files changed, 42 insertions(+), 3 deletions(-)
>
> diff --git a/include/linux/bpf.h b/include/linux/bpf.h
> index 7bfc28673124..a9600a1483ec 100644
> --- a/include/linux/bpf.h
> +++ b/include/linux/bpf.h
> @@ -1934,6 +1934,8 @@ struct bpf_link {
> * link's semantics is determined by target attach hook
> */
> bool sleepable;
> + /* set once by BPF_F_SEALED; blocks update/detach, pins link until reboot */
> + bool sealed;
> };
>
> struct bpf_link_ops {
> diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
> index ffd96e8b920b..8cb30d18fec7 100644
> --- a/include/uapi/linux/bpf.h
> +++ b/include/uapi/linux/bpf.h
> @@ -1251,6 +1251,7 @@ enum bpf_perf_event_type {
> #define BPF_F_AFTER (1U << 4)
> #define BPF_F_ID (1U << 5)
> #define BPF_F_PREORDER (1U << 6)
> +#define BPF_F_SEALED (1U << 7)
> #define BPF_F_LINK BPF_F_LINK /* 1 << 13 */
>
> /* If BPF_F_STRICT_ALIGNMENT is used in BPF_PROG_LOAD command, the
> diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
> index 94091130bcc5..e8bd57d5c907 100644
> --- a/kernel/bpf/syscall.c
> +++ b/kernel/bpf/syscall.c
> @@ -3411,6 +3411,7 @@ static void bpf_link_show_fdinfo(struct seq_file *m, struct file *filp)
> seq_printf(m, "link_type:\t<%u>\n", type);
> }
> seq_printf(m, "link_id:\t%u\n", link->id);
> + seq_printf(m, "sealed:\t%d\n", READ_ONCE(link->sealed) ? 1 : 0);
>
> rcu_read_lock();
> prog = READ_ONCE(link->prog);
> @@ -5776,17 +5777,41 @@ static int bpf_map_do_batch(const union bpf_attr *attr,
> return err;
> }
>
> +/* Seal the just-created link: take a self-reference that is never released. */
> +static void link_seal_fd(int fd)
> +{
> + struct bpf_link *link;
> +
> + link = bpf_link_get_from_fd(fd);
> + if (IS_ERR(link))
> + return;
> +
> + if (!READ_ONCE(link->sealed)) {
> + bpf_link_inc(link);
> + WRITE_ONCE(link->sealed, true);
> + }
> +
> + bpf_link_put_direct(link);
> +}
> +
> #define BPF_LINK_CREATE_LAST_FIELD link_create.uprobe_multi.path_fd
> static int link_create(union bpf_attr *attr, bpfptr_t uattr)
> {
> struct bpf_prog *prog;
> + bool seal;
> int ret;
>
> if (CHECK_ATTR(BPF_LINK_CREATE))
> return -EINVAL;
>
> - if (attr->link_create.attach_type == BPF_STRUCT_OPS)
> - return bpf_struct_ops_link_create(attr);
> + /* Strip BPF_F_SEALED before per-type flag validation. */
> + seal = attr->link_create.flags & BPF_F_SEALED;
> + attr->link_create.flags &= ~BPF_F_SEALED;
> +
> + if (attr->link_create.attach_type == BPF_STRUCT_OPS) {
> + ret = bpf_struct_ops_link_create(attr);
> + goto out_seal;
> + }
>
> prog = bpf_prog_get(attr->link_create.prog_fd);
> if (IS_ERR(prog))
> @@ -5880,6 +5905,9 @@ static int link_create(union bpf_attr *attr, bpfptr_t uattr)
> out:
> if (ret < 0)
> bpf_prog_put(prog);
> +out_seal:
> + if (ret >= 0 && seal)
> + link_seal_fd(ret);
> return ret;
> }
>
> @@ -5932,6 +5960,11 @@ static int link_update(union bpf_attr *attr)
> if (IS_ERR(link))
> return PTR_ERR(link);
>
> + if (READ_ONCE(link->sealed)) {
> + ret = -EPERM;
> + goto out_put_link;
> + }
> +
> if (link->ops->update_map) {
> ret = link_update_map(link, attr);
> goto out_put_link;
> @@ -5984,7 +6017,9 @@ static int link_detach(union bpf_attr *attr)
> if (IS_ERR(link))
> return PTR_ERR(link);
>
> - if (link->ops->detach)
> + if (READ_ONCE(link->sealed))
> + ret = -EPERM;
> + else if (link->ops->detach)
> ret = link->ops->detach(link);
> else
> ret = -EOPNOTSUPP;
> diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h
> index ffd96e8b920b..8cb30d18fec7 100644
> --- a/tools/include/uapi/linux/bpf.h
> +++ b/tools/include/uapi/linux/bpf.h
> @@ -1251,6 +1251,7 @@ enum bpf_perf_event_type {
> #define BPF_F_AFTER (1U << 4)
> #define BPF_F_ID (1U << 5)
> #define BPF_F_PREORDER (1U << 6)
> +#define BPF_F_SEALED (1U << 7)
> #define BPF_F_LINK BPF_F_LINK /* 1 << 13 */
>
> /* If BPF_F_STRICT_ALIGNMENT is used in BPF_PROG_LOAD command, the
>
> base-commit: 28e911d61d66b92a3bded8b54622ed3cd2795bf6
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH bpf-next] bpf: add BPF_F_SEALED flag to seal BPF links at creation
2026-08-03 2:20 ` David Windsor
@ 2026-08-03 3:23 ` Kumar Kartikeya Dwivedi
0 siblings, 0 replies; 10+ messages in thread
From: Kumar Kartikeya Dwivedi @ 2026-08-03 3:23 UTC (permalink / raw)
To: David Windsor, bpf, Alexei Starovoitov, Daniel Borkmann,
Andrii Nakryiko, Eduard Zingerman
Cc: Martin KaFai Lau, Song Liu, Yonghong Song, Jiri Olsa,
John Fastabend, Emil Tsalapatis, Ihor Solodrai
On Mon Aug 3, 2026 at 4:20 AM CEST, David Windsor wrote:
> On Sun, Aug 2, 2026 at 10:16 PM David Windsor <dwindsor@gmail.com> wrote:
>>
>> Introduce a new BPF_F_SEALED flag for BPF_LINK_CREATE that creates the
>> link permanently sealed. A sealed link can never have its program
>> replaced via BPF_LINK_UPDATE, can never be detached via BPF_LINK_DETACH,
>> and holds an extra self-reference that is never released, so the link and
>> its program attachment persist until the machine reboots, even after user
>> space closes every fd referring to it. There is no way to unseal a link.
>>
>> The sealed state is tracked by a new bool field on struct bpf_link.
>>
>> Signed-off-by: David Windsor <dwindsor@gmail.com>
>> ---
>> include/linux/bpf.h | 2 ++
>> include/uapi/linux/bpf.h | 1 +
>> kernel/bpf/syscall.c | 41 +++++++++++++++++++++++++++++++---
>> tools/include/uapi/linux/bpf.h | 1 +
>> 4 files changed, 42 insertions(+), 3 deletions(-)
>>
>
> There is deliberately no selftest for this, as running any such
> selftest would necessarily create a sealed link, which cannot be
> cleaned up.
Let's wait for more comments, esp. on whether this is useful or the right path
forward, but I'd still prefer adding selftests to verify various aspects of the
behavior if we proceed.
I think the point about a user being able to create many sealed links is
definitely valid too, so it might make sense to keep this gated behind more
privileged capabilities (if not already).
For tests, we might have to force decrement the link refcount (after verifying
it stays elevated after close(2)) from the test. It might involve some creative
use of a kfunc in bpf_testmod that can do the cleanup for us to avoid wedging
the system on repeated invocations of the test. It wouldn't be available on a
real system. It depends on whether we deem it important enough that leaking the
link on VMs running tests is important enough. You'd probably have to run it
thousands of time to exhaust memory unless the VM is provisioned with a tiny
amount of memory.
Anyway, let's get into all that after seeing how others feel about the concept.
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH bpf-next] bpf: add BPF_F_SEALED flag to seal BPF links at creation
2026-08-03 2:44 ` Leon Hwang
2026-08-03 3:17 ` Kumar Kartikeya Dwivedi
@ 2026-08-03 3:26 ` David Windsor
2026-08-07 22:30 ` Andrii Nakryiko
1 sibling, 1 reply; 10+ messages in thread
From: David Windsor @ 2026-08-03 3:26 UTC (permalink / raw)
To: Leon Hwang
Cc: bpf, Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Eduard Zingerman, Kumar Kartikeya Dwivedi, Martin KaFai Lau,
Song Liu, Yonghong Song, Jiri Olsa, John Fastabend,
Emil Tsalapatis, Ihor Solodrai
On Sun, Aug 2, 2026 at 10:44 PM Leon Hwang <leon.hwang@linux.dev> wrote:
>
> On 3/8/26 10:16, David Windsor wrote:
> > Introduce a new BPF_F_SEALED flag for BPF_LINK_CREATE that creates the
> > link permanently sealed. A sealed link can never have its program
> > replaced via BPF_LINK_UPDATE, can never be detached via BPF_LINK_DETACH,
> > and holds an extra self-reference that is never released, so the link and
> > its program attachment persist until the machine reboots, even after user
> > space closes every fd referring to it. There is no way to unseal a link.
> >
> > The sealed state is tracked by a new bool field on struct bpf_link.
>
>
> Why do you want BPF_F_SEALED? What's your case for it?
>
For the BPF LSM use case, mainly. There is some language in the
commitmsg about programs not being able to be unloaded until reboot,
but I will be more explicit in v2.
There was a presentation ("Securing BPF LSMs against tampering") [1]
at LSFMM+BPF about it.
[1]: https://lwn.net/Articles/1082111/
> I think 'sealed' should be set before allocating the FD to avoid the
> race issues reported by Sashiko.
>
Will do this in v2.
> Thanks,
> Leon
>
> > [...]
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH bpf-next] bpf: add BPF_F_SEALED flag to seal BPF links at creation
2026-08-03 3:26 ` David Windsor
@ 2026-08-07 22:30 ` Andrii Nakryiko
2026-08-11 21:23 ` David Windsor
0 siblings, 1 reply; 10+ messages in thread
From: Andrii Nakryiko @ 2026-08-07 22:30 UTC (permalink / raw)
To: David Windsor
Cc: Leon Hwang, bpf, Alexei Starovoitov, Daniel Borkmann,
Andrii Nakryiko, Eduard Zingerman, Kumar Kartikeya Dwivedi,
Martin KaFai Lau, Song Liu, Yonghong Song, Jiri Olsa,
John Fastabend, Emil Tsalapatis, Ihor Solodrai, Liam Wisehart
On Sun, Aug 2, 2026 at 8:26 PM David Windsor <dwindsor@gmail.com> wrote:
>
> On Sun, Aug 2, 2026 at 10:44 PM Leon Hwang <leon.hwang@linux.dev> wrote:
> >
> > On 3/8/26 10:16, David Windsor wrote:
> > > Introduce a new BPF_F_SEALED flag for BPF_LINK_CREATE that creates the
> > > link permanently sealed. A sealed link can never have its program
> > > replaced via BPF_LINK_UPDATE, can never be detached via BPF_LINK_DETACH,
> > > and holds an extra self-reference that is never released, so the link and
> > > its program attachment persist until the machine reboots, even after user
> > > space closes every fd referring to it. There is no way to unseal a link.
> > >
> > > The sealed state is tracked by a new bool field on struct bpf_link.
> >
> >
> > Why do you want BPF_F_SEALED? What's your case for it?
> >
>
> For the BPF LSM use case, mainly. There is some language in the
> commitmsg about programs not being able to be unloaded until reboot,
> but I will be more explicit in v2.
>
> There was a presentation ("Securing BPF LSMs against tampering") [1]
> at LSFMM+BPF about it.
>
> [1]: https://lwn.net/Articles/1082111/
I had to skim the articles to recall that it was me proposing
something like this :)
Anyways, as Kumar mentioned, a) link has to be crated as sealed before
FD is exposed, it's straightforward, and b) I do think that it would
be too easy to have syzbots of the world to accidentally or not create
tons of sealed links, so I'd require CAP_SYS_ADMIN for this, which I
assume won't be a problem for intended use cases?
But also, yeah, I wonder what Christian and other BPF LSM users think
about this.
pw-bot: cr
>
> > I think 'sealed' should be set before allocating the FD to avoid the
> > race issues reported by Sashiko.
> >
>
> Will do this in v2.
>
> > Thanks,
> > Leon
> >
> > > [...]
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH bpf-next] bpf: add BPF_F_SEALED flag to seal BPF links at creation
2026-08-07 22:30 ` Andrii Nakryiko
@ 2026-08-11 21:23 ` David Windsor
0 siblings, 0 replies; 10+ messages in thread
From: David Windsor @ 2026-08-11 21:23 UTC (permalink / raw)
To: Andrii Nakryiko
Cc: Leon Hwang, bpf, Alexei Starovoitov, Daniel Borkmann,
Andrii Nakryiko, Eduard Zingerman, Kumar Kartikeya Dwivedi,
Martin KaFai Lau, Song Liu, Yonghong Song, Jiri Olsa,
John Fastabend, Emil Tsalapatis, Ihor Solodrai, Liam Wisehart
On Fri, Aug 7, 2026 at 6:30 PM Andrii Nakryiko
<andrii.nakryiko@gmail.com> wrote:
>
> I had to skim the articles to recall that it was me proposing
> something like this :)
>
I wasn't actually there, but read about it on lwn. Happy to add your
Suggested-By if that makes sense here.
> Anyways, as Kumar mentioned, a) link has to be crated as sealed before
> FD is exposed, it's straightforward, and b) I do think that it would
> be too easy to have syzbots of the world to accidentally or not create
> tons of sealed links, so I'd require CAP_SYS_ADMIN for this, which I
> assume won't be a problem for intended use cases?
>
CAP_SYS_ADMIN makes sense.
> But also, yeah, I wonder what Christian and other BPF LSM users think
> about this.
>
I'll send v2 with the above changes.
The overall intent here is to follow up with another series for map
sealing. Currently, we're passing BPF_F_SEALED as a flag for
BPF_LINK_CREATE, but I wonder if we should decompose BPF_F_SEALED into
eg BPF_F_LINK_SEALED and BPF_F_MAPS_SEALED?
Link sealing is useful on its own, though, for preserving bpf-lsm
programs around even after all user fd's have been closed.
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2026-08-11 21:23 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-03 2:16 [PATCH bpf-next] bpf: add BPF_F_SEALED flag to seal BPF links at creation David Windsor
2026-08-03 2:20 ` David Windsor
2026-08-03 3:23 ` Kumar Kartikeya Dwivedi
2026-08-03 2:28 ` sashiko-bot
2026-08-03 2:44 ` Leon Hwang
2026-08-03 3:17 ` Kumar Kartikeya Dwivedi
2026-08-03 3:26 ` David Windsor
2026-08-07 22:30 ` Andrii Nakryiko
2026-08-11 21:23 ` David Windsor
2026-08-03 3:18 ` Kumar Kartikeya Dwivedi
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.