Skip to contentSkip to conversation

bpf: fix TCX/netkit detach permissions when prog FD isn't given

PATCH In review Guillaume GONNET 6 participants 16 messages Jan 24 – Jan 28 1 message not in the archive

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 bpf: fix TCX/netkit detach permissions when prog FD isn't given

Since c8644cd0e, BPF permissions are indirectly checked by having a program FD or bpffs ACL. When using BPF_PROG_DETACH command on TCX or netkit device, it's not required to provide a program FD. Instead, the program can be specified using a relative specifier (eg., BPF_F_AFTER).

In this case, there is no permission check as there is no FD involved, so any user can execute that detach command. This is problematic when BPF is used to filter out packets not intended to user as it can just remove the filter from the network interface.

For this reason, require CAP_NET_ADMIN or CAP_SYS_ADMIN in detach (only when the BPF program FD isn't provided).

---
 kernel/bpf/syscall.c | 2 ++
 1 file changed, 2 insertions(+)
kernel/bpf/syscall.c +2 -0
index 3c5c03d43f5f..d1600aef6e03 100644
@@ -4563,6 +4563,8 @@ static int bpf_prog_detach(const union bpf_attr *attr)
 			prog = bpf_prog_get_type(attr->attach_bpf_fd, ptype);
 			if (IS_ERR(prog))
 				return PTR_ERR(prog);
+		} else if (!bpf_net_capable()) {
+			return -EPERM;
 		}
 	} else if (is_cgroup_prog_type(ptype, 0, false)) {
 		if (attr->attach_flags || attr->relative_fd)
Signature · 1 line
2.34.1
#1 lore raw
commit f4c6314e5e1b2eb9762846d92b6a8169e25de6d7 Author: Guillaume GONNET <[email protected]>

commit f4c6314e5e1b2eb9762846d92b6a8169e25de6d7
Author: Guillaume GONNET <[email protected]>

bpf: fix TCX/netkit detach permissions when prog FD isn't given

This commit fixes a security issue where BPF_PROG_DETACH on TCX or netkit devices could be executed by any user when no program FD was provided, bypassing permission checks. The fix adds a capability check for CAP_NET_ADMIN or CAP_SYS_ADMIN in this case.

Quoted 10 lines

Since c8644cd0e, BPF permissions are indirectly checked by having a program FD or bpffs ACL. When using BPF_PROG_DETACH command on TCX or netkit device, it's not required to provide a program FD. Instead, the program can be specified using a relative specifier (eg., BPF_F_AFTER).

In this case, there is no permission check as there is no FD involved, so any user can execute that detach command. This is problematic when BPF is used to filter out packets not intended to user as it can just remove the filter from the network interface.

Quoted 4 lines

For this reason, require CAP_NET_ADMIN or CAP_SYS_ADMIN in detach (only when the BPF program FD isn't provided).

The commit message references "c8644cd0e" as the commit that introduced the behavior being fixed. Should this commit include a Fixes: tag pointing to that commit? This would help with tracking the bug origin and determining stable backport scope, particularly since this is a security fix.

Suggested addition:

    Fixes: c8644cd0e??? ("<subject of c8644cd0e>")

---
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/21322248996

maintainer
#2 lore raw
In reply to Guillaume GONNET
Quoted 10 lines · Guillaume GONNET

Since c8644cd0e, BPF permissions are indirectly checked by having a program FD or bpffs ACL. When using BPF_PROG_DETACH command on TCX or netkit device, it's not required to provide a program FD. Instead, the program can be specified using a relative specifier (eg., BPF_F_AFTER).

In this case, there is no permission check as there is no FD involved, so any user can execute that detach command. This is problematic when BPF is used to filter out packets not intended to user as it can just remove the filter from the network interface.

Quoted 5 lines

For this reason, require CAP_NET_ADMIN or CAP_SYS_ADMIN in detach (only when the BPF program FD isn't provided).

---

$subj should be [PATCH bpf] and as the AI review flagged, Fixes tag would make sense so that this also gets backported into stable.

Quoted 8 lines
  kernel/bpf/syscall.c | 2 ++
  1 file changed, 2 insertions(+)
kernel/bpf/syscall.c +0 -0
index 3c5c03d43f5f..d1600aef6e03 100644

kernel/bpf/syscall.c static int bpf_prog_detach(const union bpf_attr *attr) · line 4570

Quoted 8 lines
kernel/bpf/syscall.c +2 -0
@@ -4563,6 +4563,8 @@ static int bpf_prog_detach(const union bpf_attr *attr)
  			prog = bpf_prog_get_type(attr->attach_bpf_fd, ptype);
  			if (IS_ERR(prog))
  				return PTR_ERR(prog);
+		} else if (!bpf_net_capable()) {
+			return -EPERM;
  		}
  	} else if (is_cgroup_prog_type(ptype, 0, false)) {
  		if (attr->attach_flags || attr->relative_fd)

Looks reasonable to me. I looked at the other types as well, and as far as I can see for all the others you need to have a valid program fd in order to do anything in terms of modifications. Similar to BPF_LINK_{CREATE,UPDATE} and BPF_PROG_ATTACH. This assumes you either had a BPF token or CAP_NET_ADMIN at the time of the program creation or the correct permissions in BPF fs via BPF_OBJ_GET. Anyway, I would change this slightly into the below given the above makes assumptions that the detach is always about networking programs and it might not be in future.

include/linux/bpf.h +5 -0
index e5be698256d1..ffd22321aa63 100644
@@ -2623,6 +2623,11 @@ static inline bool bpf_bypass_spec_v4(const struct bpf_token *token)
 		bpf_token_capable(token, CAP_PERFMON);
 }
 
+static inline bool bpf_net_capable(void)
+{
+	return capable(CAP_NET_ADMIN) || capable(CAP_SYS_ADMIN);
+}
+
 int bpf_map_new_fd(struct bpf_map *map, int flags);
 int bpf_prog_new_fd(struct bpf_prog *prog);
 
include/linux/bpf_mprog.h +10 -0
index 929225f7b095..0b9f4caeeb0a 100644
@@ -340,4 +340,14 @@ static inline bool bpf_mprog_supported(enum bpf_prog_type type)
 		return false;
 	}
 }
+
+static inline bool bpf_mprog_detach_empty(enum bpf_prog_type type)
+{
+	switch (type) {
+	case BPF_PROG_TYPE_SCHED_CLS:
+		return bpf_net_capable();
+	default:
+		return false;
+	}
+}
 #endif /* __BPF_MPROG_H */
kernel/bpf/syscall.c +2 -6
index 4ff82144f885..4ca90020876f 100644
@@ -1366,11 +1366,6 @@ static int map_check_btf(struct bpf_map *map, struct bpf_token *token,
 	return ret;
 }
 
-static bool bpf_net_capable(void)
-{
-	return capable(CAP_NET_ADMIN) || capable(CAP_SYS_ADMIN);
-}
-
 #define BPF_MAP_CREATE_LAST_FIELD excl_prog_hash_size
 /* called via syscall */
 static int map_create(union bpf_attr *attr, bpfptr_t uattr)
@@ -4565,7 +4562,8 @@ static int bpf_prog_detach(const union bpf_attr *attr)
 			prog = bpf_prog_get_type(attr->attach_bpf_fd, ptype);
 			if (IS_ERR(prog))
 				return PTR_ERR(prog);
-		}
+		} else if (!bpf_mprog_detach_empty(ptype))
+			return -EPERM;
 	} else if (is_cgroup_prog_type(ptype, 0, false)) {
 		if (attr->attach_flags || attr->relative_fd)
 			return -EINVAL;
#3 lore raw
Quoted 11 lines · Daniel Borkmann

$subj should be [PATCH bpf] and as the AI review flagged, Fixes tag would make sense so that this also gets backported into stable.

Looks reasonable to me. I looked at the other types as well, and as far as I can see for all the others you need to have a valid program fd in order to do anything in terms of modifications. Similar to BPF_LINK_{CREATE,UPDATE} and BPF_PROG_ATTACH. This assumes you either had a BPF token or CAP_NET_ADMIN at the time of the program creation or the correct permissions in BPF fs via BPF_OBJ_GET. Anyway, I would change this slightly into the below given the above makes assumptions that the detach is always about networking programs and it might not be in future.

Ok, I will remake the patch integrating your suggestions. I also did look at the other program types and maybe there is also an issue with CGROUP program types, when BPF_F_ALLOW_MULTI flag isn't set. But you need a CGROUP FD and according to comments, it may be intentional to maintain backward compatibility. But I'm not sure as the commit af6eea574 with that CGROUP code is older than the one chaning BPF ACL (c8644cd0e).

Concerning Fixes tag, I will add one but refering to the right commit that introduced this detach code (e420bed02507), not the one that I mentioned in my first patch. I will also use the AI commit message, which is much simpler.

#4 lore raw

PATCH 1/1 bpf: fix TCX/netkit detach permissions when prog FD isn't given

In reply to Daniel Borkmann

This commit fixes a security issue where BPF_PROG_DETACH on TCX or netkit devices could be executed by any user when no program FD was provided, bypassing permission checks. The fix adds a capability check for CAP_NET_ADMIN or CAP_SYS_ADMIN in this case.

Fixes e420bed02507 ("bpf: Add fd-based tcx multi-prog infra with link support")
---
 include/linux/bpf.h       |  5 +++++
 include/linux/bpf_mprog.h | 10 ++++++++++
 kernel/bpf/syscall.c      |  7 ++-----
 3 files changed, 17 insertions(+), 5 deletions(-)
include/linux/bpf.h +5 -0
index 4427c6e98331..5f59d1f173a2 100644
@@ -2742,6 +2742,11 @@ static inline bool bpf_bypass_spec_v4(const struct bpf_token *token)
 		bpf_token_capable(token, CAP_PERFMON);
 }
 
+static inline bool bpf_net_capable(void)
+{
+	return capable(CAP_NET_ADMIN) || capable(CAP_SYS_ADMIN);
+}
+
 int bpf_map_new_fd(struct bpf_map *map, int flags);
 int bpf_prog_new_fd(struct bpf_prog *prog);
 
include/linux/bpf_mprog.h +10 -0
index 929225f7b095..0b9f4caeeb0a 100644
@@ -340,4 +340,14 @@ static inline bool bpf_mprog_supported(enum bpf_prog_type type)
 		return false;
 	}
 }
+
+static inline bool bpf_mprog_detach_empty(enum bpf_prog_type type)
+{
+	switch (type) {
+	case BPF_PROG_TYPE_SCHED_CLS:
+		return bpf_net_capable();
+	default:
+		return false;
+	}
+}
 #endif /* __BPF_MPROG_H */
kernel/bpf/syscall.c +2 -5
index b9184545c3fd..419d88bb5944 100644
@@ -1363,11 +1363,6 @@ static int map_check_btf(struct bpf_map *map, struct bpf_token *token,
 	return ret;
 }
 
-static bool bpf_net_capable(void)
-{
-	return capable(CAP_NET_ADMIN) || capable(CAP_SYS_ADMIN);
-}
-
 #define BPF_MAP_CREATE_LAST_FIELD excl_prog_hash_size
 /* called via syscall */
 static int map_create(union bpf_attr *attr, bpfptr_t uattr)
@@ -4579,6 +4574,8 @@ static int bpf_prog_detach(const union bpf_attr *attr)
 			prog = bpf_prog_get_type(attr->attach_bpf_fd, ptype);
 			if (IS_ERR(prog))
 				return PTR_ERR(prog);
+		} else if (!bpf_mprog_detach_empty(ptype))
+			return -EPERM;
 		}
 	} else if (is_cgroup_prog_type(ptype, 0, false)) {
 		if (attr->attach_flags || attr->relative_fd)
Signature · 1 line
2.34.1
#5 lore raw
There appears to be a brace mismatch here that would prevent compilation.
Quoted 4 lines
kernel/bpf/syscall.c +0 -0
index 4ff82144f885..9796fe5b9ab5 100644

[ ... ]

kernel/bpf/syscall.c static int bpf_prog_detach(const union bpf_attr *attr) · line 4566

Quoted 8 lines
kernel/bpf/syscall.c +2 -0
@@ -4565,6 +4560,8 @@ static int bpf_prog_detach(const union bpf_attr *attr)
 			prog = bpf_prog_get_type(attr->attach_bpf_fd, ptype);
 			if (IS_ERR(prog))
 				return PTR_ERR(prog);
+		} else if (!bpf_mprog_detach_empty(ptype))
+			return -EPERM;
 		}
 	} else if (is_cgroup_prog_type(ptype, 0, false)) {

There appears to be a brace mismatch here that would prevent compilation.

The original code structure was:

    if (attr->attach_bpf_fd) {
        prog = bpf_prog_get_type(attr->attach_bpf_fd, ptype);
        if (IS_ERR(prog))
            return PTR_ERR(prog);
    }

The closing brace on its own line closed the if (attr->attach_bpf_fd) block.

After this patch, the else-if clause closes that if block, but the original closing brace remains as a dangling brace:

    if (attr->attach_bpf_fd) {
        prog = bpf_prog_get_type(attr->attach_bpf_fd, ptype);
        if (IS_ERR(prog))
            return PTR_ERR(prog);
    } else if (!bpf_mprog_detach_empty(ptype))
        return -EPERM;
    }  <-- this brace has nothing to close

This creates a mismatch where there are two opening braces (outer bpf_mprog_supported and inner attr->attach_bpf_fd) but three closing constructs.

Was this patch tested to compile? The fix would be to remove the dangling closing brace on the context line, resulting in:

    if (attr->attach_bpf_fd) {
        prog = bpf_prog_get_type(attr->attach_bpf_fd, ptype);
        if (IS_ERR(prog))
            return PTR_ERR(prog);
    } else if (!bpf_mprog_detach_empty(ptype))
        return -EPERM;

---
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/21366799473

#6 lore raw

PATCH 1/1 bpf: fix TCX/netkit detach permissions when prog FD isn't given

This commit fixes a security issue where BPF_PROG_DETACH on TCX or netkit devices could be executed by any user when no program FD was provided, bypassing permission checks. The fix adds a capability check for CAP_NET_ADMIN or CAP_SYS_ADMIN in this case.

Fixes e420bed02507 ("bpf: Add fd-based tcx multi-prog infra with link support")
---
 include/linux/bpf.h       |  5 +++++
 include/linux/bpf_mprog.h | 10 ++++++++++
 kernel/bpf/syscall.c      |  7 ++-----
 3 files changed, 17 insertions(+), 5 deletions(-)
include/linux/bpf.h +5 -0
index 4427c6e98331..5f59d1f173a2 100644
@@ -2742,6 +2742,11 @@ static inline bool bpf_bypass_spec_v4(const struct bpf_token *token)
 		bpf_token_capable(token, CAP_PERFMON);
 }
 
+static inline bool bpf_net_capable(void)
+{
+	return capable(CAP_NET_ADMIN) || capable(CAP_SYS_ADMIN);
+}
+
 int bpf_map_new_fd(struct bpf_map *map, int flags);
 int bpf_prog_new_fd(struct bpf_prog *prog);
 
include/linux/bpf_mprog.h +10 -0
index 929225f7b095..0b9f4caeeb0a 100644
@@ -340,4 +340,14 @@ static inline bool bpf_mprog_supported(enum bpf_prog_type type)
 		return false;
 	}
 }
+
+static inline bool bpf_mprog_detach_empty(enum bpf_prog_type type)
+{
+	switch (type) {
+	case BPF_PROG_TYPE_SCHED_CLS:
+		return bpf_net_capable();
+	default:
+		return false;
+	}
+}
 #endif /* __BPF_MPROG_H */
kernel/bpf/syscall.c +2 -5
index b9184545c3fd..5f59dd47a5b1 100644
@@ -1363,11 +1363,6 @@ static int map_check_btf(struct bpf_map *map, struct bpf_token *token,
 	return ret;
 }
 
-static bool bpf_net_capable(void)
-{
-	return capable(CAP_NET_ADMIN) || capable(CAP_SYS_ADMIN);
-}
-
 #define BPF_MAP_CREATE_LAST_FIELD excl_prog_hash_size
 /* called via syscall */
 static int map_create(union bpf_attr *attr, bpfptr_t uattr)
@@ -4579,6 +4574,8 @@ static int bpf_prog_detach(const union bpf_attr *attr)
 			prog = bpf_prog_get_type(attr->attach_bpf_fd, ptype);
 			if (IS_ERR(prog))
 				return PTR_ERR(prog);
+		} else if (!bpf_mprog_detach_empty(ptype)) {
+			return -EPERM;
 		}
 	} else if (is_cgroup_prog_type(ptype, 0, false)) {
 		if (attr->attach_flags || attr->relative_fd)
Signature · 1 line
2.34.1
#7 lore raw
This patch was applied to bpf/bpf-next.git (master) by Daniel Borkmann <[email protected]>:

Hello:

This patch was applied to bpf/bpf-next.git (master) by Daniel Borkmann <[email protected]>:

Quoted 9 lines · On Mon, 26 Jan 2026 18:34:31 +0100 you wrote:

This commit fixes a security issue where BPF_PROG_DETACH on TCX or netkit devices could be executed by any user when no program FD was provided, bypassing permission checks. The fix adds a capability check for CAP_NET_ADMIN or CAP_SYS_ADMIN in this case.

Fixes e420bed02507 ("bpf: Add fd-based tcx multi-prog infra with link support")

[...]

Here is the summary with links:
- bpf: fix TCX/netkit detach permissions when prog FD isn't given

    https://git.kernel.org/bpf/bpf-next/c/95ffdbda5eec

You are awesome, thank you!

Signature · 2 lines
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
#8 lore raw
In reply to Guillaume GONNET
kernel test robot noticed the following build errors:

Hi Guillaume,

kernel test robot noticed the following build errors:

[auto build test ERROR on bpf-next/net]
[also build test ERROR on bpf/master linus/master v6.19-rc7 next-20260126] [cannot apply to bpf-next/master]
[If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Guillaume-GONNET/bpf-fix-TCX-netkit-detach-permissions-when-prog-FD-isn-t-given/20260127-013722
base:   https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git net
patch link:    https://lore.kernel.org/r/20260126173431.19825-1-ggonnet.linux%40gmail.com
patch subject: [PATCH] bpf: fix TCX/netkit detach permissions when prog FD isn't given
config: sh-defconfig (https://download.01.org/0day-ci/archive/20260127/[email protected]/config)
compiler: sh4-linux-gcc (GCC) 15.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260127/[email protected]/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/

All errors (new ones prefixed by >>):

In file included from include/net/tcx.h:7,

                    from net/core/dev.c:114:
   include/linux/bpf_mprog.h: In function 'bpf_mprog_detach_empty':
>> include/linux/bpf_mprog.h:348:24: error: implicit declaration of function 'bpf_net_capable'; did you mean 'sk_net_capable'? [-Wimplicit-function-declaration]
     348 |                 return bpf_net_capable();
         |                        ^~~~~~~~~~~~~~~
         |                        sk_net_capable

vim +348 include/linux/bpf_mprog.h

343
344 static inline bool bpf_mprog_detach_empty(enum bpf_prog_type type)
345 {
346 switch (type) {
347 case BPF_PROG_TYPE_SCHED_CLS:

 > 348			return bpf_net_capable();
Signature · 2 lines
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

A message that is not in the archive (sent off-list or not yet received): CAADnVQJNvx34irz6JYbmZvmaYU0AGRDcu8znsKjA_di798RisA@mail.gmail.com

#10 lore raw
Quoted 40 lines · Alexei Starovoitov
Quoted 36 lines · kernel test robot

Hi Guillaume,

kernel test robot noticed the following build errors:

[auto build test ERROR on bpf-next/net]
[also build test ERROR on bpf/master linus/master v6.19-rc7 next-20260126] [cannot apply to bpf-next/master]
[If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Guillaume-GONNET/bpf-fix-TCX-netkit-detach-permissions-when-prog-FD-isn-t-given/20260127-013722
base:   https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git net
patch link:    https://lore.kernel.org/r/20260126173431.19825-1-ggonnet.linux%40gmail.com
patch subject: [PATCH] bpf: fix TCX/netkit detach permissions when prog FD isn't given
config: sh-defconfig (https://download.01.org/0day-ci/archive/20260127/[email protected]/config)
compiler: sh4-linux-gcc (GCC) 15.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260127/[email protected]/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/

All errors (new ones prefixed by >>):

In file included from include/net/tcx.h:7,

                    from net/core/dev.c:114:

include/linux/bpf_mprog.h: In function 'bpf_mprog_detach_empty':

Quoted 1 line
Quoted 1 line

include/linux/bpf_mprog.h:348:24: error: implicit declaration of function 'bpf_net_capable'; did you mean 'sk_net_capable'? [-Wimplicit-function-declaration]

     348 |                 return bpf_net_capable();
         |                        ^~~~~~~~~~~~~~~
         |                        sk_net_capable
Quoted 9 lines
Quoted 8 lines

vim +348 include/linux/bpf_mprog.h

   343
   344  static inline bool bpf_mprog_detach_empty(enum bpf_prog_type type)
   345  {
   346          switch (type) {
   347          case BPF_PROG_TYPE_SCHED_CLS:
Quoted 1 line

348 return bpf_net_capable();

I dropped the patch from bpf-next.
Pls fix and resubmit.

#11 lore raw

PATCH v4 1/1 bpf: Fix tcx/netkit detach permissions when prog fd isn't given

This commit fixes a security issue where BPF_PROG_DETACH on tcx or netkit devices could be executed by any user when no program fd was provided, bypassing permission checks. The fix adds a capability check for CAP_NET_ADMIN or CAP_SYS_ADMIN in this case.

Fixes e420bed02507 ("bpf: Add fd-based tcx multi-prog infra with link support")
---
 include/linux/bpf.h       |  5 +++++
 include/linux/bpf_mprog.h | 12 ++++++++++++
 kernel/bpf/syscall.c      |  7 ++-----
 3 files changed, 19 insertions(+), 5 deletions(-)
include/linux/bpf.h +5 -0
index 4427c6e98331..5f59d1f173a2 100644
@@ -2742,6 +2742,11 @@ static inline bool bpf_bypass_spec_v4(const struct bpf_token *token)
 		bpf_token_capable(token, CAP_PERFMON);
 }
 
+static inline bool bpf_net_capable(void)
+{
+	return capable(CAP_NET_ADMIN) || capable(CAP_SYS_ADMIN);
+}
+
 int bpf_map_new_fd(struct bpf_map *map, int flags);
 int bpf_prog_new_fd(struct bpf_prog *prog);
 
include/linux/bpf_mprog.h +12 -0
index 929225f7b095..18d26ae6a5b6 100644
@@ -340,4 +340,16 @@ static inline bool bpf_mprog_supported(enum bpf_prog_type type)
 		return false;
 	}
 }
+
+#ifdef CONFIG_BPF_SYSCALL
+static inline bool bpf_mprog_detach_empty(enum bpf_prog_type type)
+{
+	switch (type) {
+	case BPF_PROG_TYPE_SCHED_CLS:
+		return bpf_net_capable();
+	default:
+		return false;
+	}
+}
+#endif /* CONFIG_BPF_SYSCALL */
 #endif /* __BPF_MPROG_H */
kernel/bpf/syscall.c +2 -5
index b9184545c3fd..5f59dd47a5b1 100644
@@ -1363,11 +1363,6 @@ static int map_check_btf(struct bpf_map *map, struct bpf_token *token,
 	return ret;
 }
 
-static bool bpf_net_capable(void)
-{
-	return capable(CAP_NET_ADMIN) || capable(CAP_SYS_ADMIN);
-}
-
 #define BPF_MAP_CREATE_LAST_FIELD excl_prog_hash_size
 /* called via syscall */
 static int map_create(union bpf_attr *attr, bpfptr_t uattr)
@@ -4579,6 +4574,8 @@ static int bpf_prog_detach(const union bpf_attr *attr)
 			prog = bpf_prog_get_type(attr->attach_bpf_fd, ptype);
 			if (IS_ERR(prog))
 				return PTR_ERR(prog);
+		} else if (!bpf_mprog_detach_empty(ptype)) {
+			return -EPERM;
 		}
 	} else if (is_cgroup_prog_type(ptype, 0, false)) {
 		if (attr->attach_flags || attr->relative_fd)
Signature · 1 line
2.34.1
maintainer
#12 lore raw

Re: [PATCH bpf v4] bpf: Fix tcx/netkit detach permissions when prog fd isn't given

Hi Guillaume,

Quoted 39 lines · Guillaume Gonnet

This commit fixes a security issue where BPF_PROG_DETACH on tcx or netkit devices could be executed by any user when no program fd was provided, bypassing permission checks. The fix adds a capability check for CAP_NET_ADMIN or CAP_SYS_ADMIN in this case.

Fixes e420bed02507 ("bpf: Add fd-based tcx multi-prog infra with link support")
---
  include/linux/bpf.h       |  5 +++++
  include/linux/bpf_mprog.h | 12 ++++++++++++
  kernel/bpf/syscall.c      |  7 ++-----
  3 files changed, 19 insertions(+), 5 deletions(-)
include/linux/bpf.h +5 -0
index 4427c6e98331..5f59d1f173a2 100644
@@ -2742,6 +2742,11 @@ static inline bool bpf_bypass_spec_v4(const struct bpf_token *token)
  		bpf_token_capable(token, CAP_PERFMON);
  }
 
+static inline bool bpf_net_capable(void)
+{
+	return capable(CAP_NET_ADMIN) || capable(CAP_SYS_ADMIN);
+}
+
  int bpf_map_new_fd(struct bpf_map *map, int flags);
  int bpf_prog_new_fd(struct bpf_prog *prog);
 
include/linux/bpf_mprog.h +2 -0
index 929225f7b095..18d26ae6a5b6 100644
@@ -340,4 +340,16 @@ static inline bool bpf_mprog_supported(enum bpf_prog_type type)
  		return false;
  	}
  }
+
+#ifdef CONFIG_BPF_SYSCALL

include/linux/bpf_mprog.h static inline bool bpf_mprog_supported(enum bpf_prog_type type) · line 354

Quoted 10 lines
include/linux/bpf_mprog.h +10 -0
+static inline bool bpf_mprog_detach_empty(enum bpf_prog_type type)
+{
+	switch (type) {
+	case BPF_PROG_TYPE_SCHED_CLS:
+		return bpf_net_capable();
+	default:
+		return false;
+	}
+}
+#endif /* CONFIG_BPF_SYSCALL */

While this silences the kbuild bot issue, it would be better to move the bpf_net_capable() outside the ifdef CONFIG_BPF_SYSCALL in the bpf.h header given this is the actual underlying cause. Then we don't need the ifdef above, e.g. bpf_mprog_supported() does not have it either.

Thanks,
Daniel

#13 lore raw

PATCH v5 1/1 bpf: Fix tcx/netkit detach permissions when prog fd isn't given

This commit fixes a security issue where BPF_PROG_DETACH on tcx or netkit devices could be executed by any user when no program fd was provided, bypassing permission checks. The fix adds a capability check for CAP_NET_ADMIN or CAP_SYS_ADMIN in this case.

Fixes e420bed02507 ("bpf: Add fd-based tcx multi-prog infra with link support")
---
 include/linux/bpf.h       |  5 +++++
 include/linux/bpf_mprog.h | 10 ++++++++++
 kernel/bpf/syscall.c      |  7 ++-----
 3 files changed, 17 insertions(+), 5 deletions(-)
include/linux/bpf.h +5 -0
index 4427c6e98331..9272a237cced 100644
@@ -3362,6 +3362,11 @@ static inline void bpf_prog_report_arena_violation(bool write, unsigned long add
 }
 #endif /* CONFIG_BPF_SYSCALL */
 
+static inline bool bpf_net_capable(void)
+{
+	return capable(CAP_NET_ADMIN) || capable(CAP_SYS_ADMIN);
+}
+
 static __always_inline int
 bpf_probe_read_kernel_common(void *dst, u32 size, const void *unsafe_ptr)
 {
include/linux/bpf_mprog.h +10 -0
index 929225f7b095..0b9f4caeeb0a 100644
@@ -340,4 +340,14 @@ static inline bool bpf_mprog_supported(enum bpf_prog_type type)
 		return false;
 	}
 }
+
+static inline bool bpf_mprog_detach_empty(enum bpf_prog_type type)
+{
+	switch (type) {
+	case BPF_PROG_TYPE_SCHED_CLS:
+		return bpf_net_capable();
+	default:
+		return false;
+	}
+}
 #endif /* __BPF_MPROG_H */
kernel/bpf/syscall.c +2 -5
index b9184545c3fd..5f59dd47a5b1 100644
@@ -1363,11 +1363,6 @@ static int map_check_btf(struct bpf_map *map, struct bpf_token *token,
 	return ret;
 }
 
-static bool bpf_net_capable(void)
-{
-	return capable(CAP_NET_ADMIN) || capable(CAP_SYS_ADMIN);
-}
-
 #define BPF_MAP_CREATE_LAST_FIELD excl_prog_hash_size
 /* called via syscall */
 static int map_create(union bpf_attr *attr, bpfptr_t uattr)
@@ -4579,6 +4574,8 @@ static int bpf_prog_detach(const union bpf_attr *attr)
 			prog = bpf_prog_get_type(attr->attach_bpf_fd, ptype);
 			if (IS_ERR(prog))
 				return PTR_ERR(prog);
+		} else if (!bpf_mprog_detach_empty(ptype)) {
+			return -EPERM;
 		}
 	} else if (is_cgroup_prog_type(ptype, 0, false)) {
 		if (attr->attach_flags || attr->relative_fd)
Signature · 1 line
2.34.1
#14 lore raw

Re: [PATCH bpf v5] bpf: Fix tcx/netkit detach permissions when prog fd isn't given

This patch was applied to bpf/bpf-next.git (master) by Alexei Starovoitov <[email protected]>:

Hello:

This patch was applied to bpf/bpf-next.git (master) by Alexei Starovoitov <[email protected]>:

Quoted 9 lines · On Tue, 27 Jan 2026 17:02:00 +0100 you wrote:

This commit fixes a security issue where BPF_PROG_DETACH on tcx or netkit devices could be executed by any user when no program fd was provided, bypassing permission checks. The fix adds a capability check for CAP_NET_ADMIN or CAP_SYS_ADMIN in this case.

Fixes e420bed02507 ("bpf: Add fd-based tcx multi-prog infra with link support")

[...]

Here is the summary with links:
- [bpf,v5] bpf: Fix tcx/netkit detach permissions when prog fd isn't given

    https://git.kernel.org/bpf/bpf-next/c/ae23bc81ddf7

You are awesome, thank you!

Signature · 2 lines
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
#15 lore raw
In reply to Guillaume GONNET
kernel test robot noticed the following build errors:

Hi Guillaume,

kernel test robot noticed the following build errors:

[auto build test ERROR on bpf-next/net]
[also build test ERROR on bpf/master linus/master v6.19-rc7 next-20260126] [cannot apply to bpf-next/master]
[If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Guillaume-GONNET/bpf-fix-TCX-netkit-detach-permissions-when-prog-FD-isn-t-given/20260127-013722
base:   https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git net
patch link:    https://lore.kernel.org/r/20260126173431.19825-1-ggonnet.linux%40gmail.com
patch subject: [PATCH] bpf: fix TCX/netkit detach permissions when prog FD isn't given
config: powerpc-pcm030_defconfig (https://download.01.org/0day-ci/archive/20260127/[email protected]/config)
compiler: clang version 22.0.0git (https://github.com/llvm/llvm-project 9b8addffa70cee5b2acc5454712d9cf78ce45710)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260127/[email protected]/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/

All errors (new ones prefixed by >>):

In file included from net/core/dev.c:114:
In file included from include/net/tcx.h:7:

>> include/linux/bpf_mprog.h:348:10: error: call to undeclared function 'bpf_net_capable'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
     348 |                 return bpf_net_capable();
         |                        ^
   include/linux/bpf_mprog.h:348:10: note: did you mean 'sk_net_capable'?
   include/net/sock.h:3024:6: note: 'sk_net_capable' declared here
    3024 | bool sk_net_capable(const struct sock *sk, int cap);
         |      ^

1 error generated.

vim +/bpf_net_capable +348 include/linux/bpf_mprog.h

343
344 static inline bool bpf_mprog_detach_empty(enum bpf_prog_type type)
345 {
346 switch (type) {
347 case BPF_PROG_TYPE_SCHED_CLS:

 > 348			return bpf_net_capable();
Signature · 2 lines
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
maintainer
#16 lore raw
In reply to [email protected]
Quoted 7 lines · On 1/26/26 6:23 PM, [email protected] wrote:
Quoted 4 lines
kernel/bpf/syscall.c +0 -0
index 4ff82144f885..9796fe5b9ab5 100644

[ ... ]

Quoted 7 lines

kernel/bpf/syscall.c static int bpf_prog_detach(const union bpf_attr *attr) · line 4565

Quoted 7 lines
kernel/bpf/syscall.c +2 -0
@@ -4565,6 +4560,8 @@ static int bpf_prog_detach(const union bpf_attr *attr)
  			prog = bpf_prog_get_type(attr->attach_bpf_fd, ptype);
  			if (IS_ERR(prog))
  				return PTR_ERR(prog);
+		} else if (!bpf_mprog_detach_empty(ptype))
+			return -EPERM;
  		}

Please never send untested code. I saw you sent a new version already so I'll toss this one - in future please properly label with [PATCH bpf v3] if you send a new revision.

Thanks,
Daniel