diff options
| author | Eric Suen <ericsu@linux.microsoft.com> | 2025-12-04 18:42:59 -0800 |
|---|---|---|
| committer | Paul Moore <paul@paul-moore.com> | 2026-01-13 15:42:37 -0500 |
| commit | 5473a722f782f79f96b4691400d681c01fcacc2f (patch) | |
| tree | 143cab975e996a5a3744def77538a80e053d2455 /security/selinux/include | |
| parent | 27a7cef9c3646e36f56f48c0ad43df3b821ffc96 (diff) | |
selinux: add support for BPF token access control
BPF token support was introduced to allow a privileged process to delegate
limited BPF functionality—such as map creation and program loading—to
an unprivileged process:
https://lore.kernel.org/linux-security-module/20231130185229.2688956-1-andrii@kernel.org/
This patch adds SELinux support for controlling BPF token access. With
this change, SELinux policies can now enforce constraints on BPF token
usage based on both the delegating (privileged) process and the recipient
(unprivileged) process.
Supported operations currently include:
- map_create
- prog_load
High-level workflow:
1. An unprivileged process creates a VFS context via `fsopen()` and
obtains a file descriptor.
2. This descriptor is passed to a privileged process, which configures
BPF token delegation options and mounts a BPF filesystem.
3. SELinux records the `creator_sid` of the privileged process during
mount setup.
4. The unprivileged process then uses this BPF fs mount to create a
token and attach it to subsequent BPF syscalls.
5. During verification of `map_create` and `prog_load`, SELinux uses
`creator_sid` and the current SID to check policy permissions via:
avc_has_perm(creator_sid, current_sid, SECCLASS_BPF,
BPF__MAP_CREATE, NULL);
The implementation introduces two new permissions:
- map_create_as
- prog_load_as
At token creation time, SELinux verifies that the current process has the
appropriate `*_as` permission (depending on the `allowed_cmds` value in
the bpf_token) to act on behalf of the `creator_sid`.
Example SELinux policy:
allow test_bpf_t self:bpf {
map_create map_read map_write prog_load prog_run
map_create_as prog_load_as
};
Additionally, a new policy capability bpf_token_perms is added to ensure
backward compatibility. If disabled, previous behavior ((checks based on
current process SID)) is preserved.
Signed-off-by: Eric Suen <ericsu@linux.microsoft.com>
Tested-by: Daniel Durning <danieldurning.work@gmail.com>
Reviewed-by: Daniel Durning <danieldurning.work@gmail.com>
[PM: merge fuzz, subject tweaks, whitespace tweaks, line length tweaks]
Signed-off-by: Paul Moore <paul@paul-moore.com>
Diffstat (limited to 'security/selinux/include')
| -rw-r--r-- | security/selinux/include/classmap.h | 2 | ||||
| -rw-r--r-- | security/selinux/include/objsec.h | 3 | ||||
| -rw-r--r-- | security/selinux/include/policycap.h | 1 | ||||
| -rw-r--r-- | security/selinux/include/policycap_names.h | 1 | ||||
| -rw-r--r-- | security/selinux/include/security.h | 6 |
5 files changed, 12 insertions, 1 deletions
diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h index 3ec85142771f..90cb61b16425 100644 --- a/security/selinux/include/classmap.h +++ b/security/selinux/include/classmap.h @@ -171,7 +171,7 @@ const struct security_class_mapping secclass_map[] = { { "infiniband_endport", { "manage_subnet", NULL } }, { "bpf", { "map_create", "map_read", "map_write", "prog_load", "prog_run", - NULL } }, + "map_create_as", "prog_load_as", NULL } }, { "xdp_socket", { COMMON_SOCK_PERMS, NULL } }, { "mctp_socket", { COMMON_SOCK_PERMS, NULL } }, { "perf_event", diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h index 8fc3de5234ac..5bddd28ea5cb 100644 --- a/security/selinux/include/objsec.h +++ b/security/selinux/include/objsec.h @@ -92,6 +92,7 @@ struct superblock_security_struct { u32 sid; /* SID of file system superblock */ u32 def_sid; /* default SID for labeling */ u32 mntpoint_sid; /* SECURITY_FS_USE_MNTPOINT context for files */ + u32 creator_sid; /* SID of privileged process */ unsigned short behavior; /* labeling behavior */ unsigned short flags; /* which mount options were specified */ struct mutex lock; @@ -169,6 +170,8 @@ struct pkey_security_struct { struct bpf_security_struct { u32 sid; /* SID of bpf obj creator */ + u32 perms; /* permissions for allowed bpf token commands */ + u32 grantor_sid; /* SID of token grantor */ }; struct perf_event_security_struct { diff --git a/security/selinux/include/policycap.h b/security/selinux/include/policycap.h index 231d02227e59..dbf39358ae6a 100644 --- a/security/selinux/include/policycap.h +++ b/security/selinux/include/policycap.h @@ -19,6 +19,7 @@ enum { POLICYDB_CAP_GENFS_SECLABEL_WILDCARD, POLICYDB_CAP_FUNCTIONFS_SECLABEL, POLICYDB_CAP_MEMFD_CLASS, + POLICYDB_CAP_BPF_TOKEN_PERMS, __POLICYDB_CAP_MAX }; #define POLICYDB_CAP_MAX (__POLICYDB_CAP_MAX - 1) diff --git a/security/selinux/include/policycap_names.h b/security/selinux/include/policycap_names.h index 454dab37bda3..6e2b808e12e8 100644 --- a/security/selinux/include/policycap_names.h +++ b/security/selinux/include/policycap_names.h @@ -22,6 +22,7 @@ const char *const selinux_policycap_names[__POLICYDB_CAP_MAX] = { "genfs_seclabel_wildcard", "functionfs_seclabel", "memfd_class", + "bpf_token_perms", }; /* clang-format on */ diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index 5d1dad8058b1..d1f16d7f684d 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h @@ -214,6 +214,12 @@ static inline bool selinux_policycap_memfd_class(void) return READ_ONCE(selinux_state.policycap[POLICYDB_CAP_MEMFD_CLASS]); } +static inline bool selinux_policycap_bpf_token_perms(void) +{ + return READ_ONCE( + selinux_state.policycap[POLICYDB_CAP_BPF_TOKEN_PERMS]); +} + struct selinux_policy_convert_data; struct selinux_load_state { |
