projects/linux·commit 59c017ce

Merge tag 'selinux-pr-20250323' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux

59c017ce · Linus Torvalds <[email protected]> · 2025-03-25 15:52:32 -07:00

Pull selinux updates from Paul Moore:

 - Add additional SELinux access controls for kernel file reads/loads

   The SELinux kernel file read/load access controls were never updated
   beyond the initial kernel module support, this pull request adds
   support for firmware, kexec, policies, and x.509 certificates.

 - Add support for wildcards in network interface names

   There are a number of userspace tools which auto-generate network
   interface names using some pattern of <XXXX>-<NN> where <XXXX> is a
   fixed string, e.g. "podman", and <NN> is a increasing counter.
   Supporting wildcards in the SELinux policy for network interfaces
   simplifies the policy associted with these interfaces.

 - Fix a potential problem in the kernel read file SELinux code

   SELinux should always check the file label in the
   security_kernel_read_file() LSM hook, regardless of if the file is
   being read in chunks. Unfortunately, the existing code only
   considered the file label on the first chunk; this pull request fixes
   this problem.

   There is more detail in the individual commit, but thankfully the
   existing code didn't expose a bug due to multi-stage reads only
   taking place in one driver, and that driver loading a file type that
   isn't targeted by the SELinux policy.

 - Fix the subshell error handling in the example policy loader

   Minor fix to SELinux example policy loader in scripts/selinux due to
   an undesired interaction with subshells and errexit.

* tag 'selinux-pr-20250323' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux:
  selinux: get netif_wildcard policycap from policy instead of cache
  selinux: support wildcard network interface names
  selinux: Chain up tool resolving errors in install_policy.sh
  selinux: add permission checks for loading other kinds of kernel files
  selinux: always check the file label in selinux_kernel_read_file()
  selinux: fix spelling error
Commit
59c017ce9ec77953ca5198b41d4101f57dd4af0d
Parents
05457026 · a3d3043e

Merge commit. Changes below are compared with the first parent: 05457026.

Changes

8 files changed · +79 −25

scripts/selinux/install_policy.sh

View file
diff --git a/scripts/selinux/install_policy.sh b/scripts/selinux/install_policy.sh
index 2408679..db40237 100755
--- a/scripts/selinux/install_policy.sh
+++ b/scripts/selinux/install_policy.sh
@@ -6,27 +6,24 @@ if [ `id -u` -ne 0 ]; then
exit 1
fi
-SF=`which setfiles`
-if [ $? -eq 1 ]; then
+SF=`which setfiles` || {
echo "Could not find setfiles"
echo "Do you have policycoreutils installed?"
exit 1
-fi
+}
-CP=`which checkpolicy`
-if [ $? -eq 1 ]; then
+CP=`which checkpolicy` || {
echo "Could not find checkpolicy"
echo "Do you have checkpolicy installed?"
exit 1
-fi
+}
VERS=`$CP -V | awk '{print $1}'`
-ENABLED=`which selinuxenabled`
-if [ $? -eq 1 ]; then
+ENABLED=`which selinuxenabled` || {
echo "Could not find selinuxenabled"
echo "Do you have libselinux-utils installed?"
exit 1
-fi
+}
if selinuxenabled; then
echo "SELinux is already enabled"

security/selinux/avc.c

View file
diff --git a/security/selinux/avc.c b/security/selinux/avc.c
index 1f2680b..4b4837a 100644
--- a/security/selinux/avc.c
+++ b/security/selinux/avc.c
@@ -936,7 +936,7 @@ static void avc_flush(void)
spin_lock_irqsave(lock, flag);
/*
- * With preemptable RCU, the outer spinlock does not
+ * With preemptible RCU, the outer spinlock does not
* prevent RCU grace periods from ending.
*/
rcu_read_lock();

security/selinux/hooks.c

View file
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 60b1cbd..7150c95 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -4099,7 +4099,7 @@ static int selinux_kernel_module_request(char *kmod_name)
SYSTEM__MODULE_REQUEST, &ad);
}
-static int selinux_kernel_module_from_file(struct file *file)
+static int selinux_kernel_load_from_file(struct file *file, u32 requested)
{
struct common_audit_data ad;
struct inode_security_struct *isec;
@@ -4107,12 +4107,8 @@ static int selinux_kernel_module_from_file(struct file *file)
u32 sid = current_sid();
int rc;
- /* init_module */
if (file == NULL)
- return avc_has_perm(sid, sid, SECCLASS_SYSTEM,
- SYSTEM__MODULE_LOAD, NULL);
-
- /* finit_module */
+ return avc_has_perm(sid, sid, SECCLASS_SYSTEM, requested, NULL);
ad.type = LSM_AUDIT_DATA_FILE;
ad.u.file = file;
@@ -4125,8 +4121,7 @@ static int selinux_kernel_module_from_file(struct file *file)
}
isec = inode_security(file_inode(file));
- return avc_has_perm(sid, isec->sid, SECCLASS_SYSTEM,
- SYSTEM__MODULE_LOAD, &ad);
+ return avc_has_perm(sid, isec->sid, SECCLASS_SYSTEM, requested, &ad);
}
static int selinux_kernel_read_file(struct file *file,
@@ -4135,9 +4130,30 @@ static int selinux_kernel_read_file(struct file *file,
{
int rc = 0;
+ BUILD_BUG_ON_MSG(READING_MAX_ID > 7,
+ "New kernel_read_file_id introduced; update SELinux!");
+
switch (id) {
+ case READING_FIRMWARE:
+ rc = selinux_kernel_load_from_file(file, SYSTEM__FIRMWARE_LOAD);
+ break;
case READING_MODULE:
- rc = selinux_kernel_module_from_file(contents ? file : NULL);
+ rc = selinux_kernel_load_from_file(file, SYSTEM__MODULE_LOAD);
+ break;
+ case READING_KEXEC_IMAGE:
+ rc = selinux_kernel_load_from_file(file,
+ SYSTEM__KEXEC_IMAGE_LOAD);
+ break;
+ case READING_KEXEC_INITRAMFS:
+ rc = selinux_kernel_load_from_file(file,
+ SYSTEM__KEXEC_INITRAMFS_LOAD);
+ break;
+ case READING_POLICY:
+ rc = selinux_kernel_load_from_file(file, SYSTEM__POLICY_LOAD);
+ break;
+ case READING_X509_CERTIFICATE:
+ rc = selinux_kernel_load_from_file(file,
+ SYSTEM__X509_CERTIFICATE_LOAD);
break;
default:
break;
@@ -4150,9 +4166,31 @@ static int selinux_kernel_load_data(enum kernel_load_data_id id, bool contents)
{
int rc = 0;
+ BUILD_BUG_ON_MSG(LOADING_MAX_ID > 7,
+ "New kernel_load_data_id introduced; update SELinux!");
+
switch (id) {
+ case LOADING_FIRMWARE:
+ rc = selinux_kernel_load_from_file(NULL, SYSTEM__FIRMWARE_LOAD);
+ break;
case LOADING_MODULE:
- rc = selinux_kernel_module_from_file(NULL);
+ rc = selinux_kernel_load_from_file(NULL, SYSTEM__MODULE_LOAD);
+ break;
+ case LOADING_KEXEC_IMAGE:
+ rc = selinux_kernel_load_from_file(NULL,
+ SYSTEM__KEXEC_IMAGE_LOAD);
+ break;
+ case LOADING_KEXEC_INITRAMFS:
+ rc = selinux_kernel_load_from_file(NULL,
+ SYSTEM__KEXEC_INITRAMFS_LOAD);
+ break;
+ case LOADING_POLICY:
+ rc = selinux_kernel_load_from_file(NULL,
+ SYSTEM__POLICY_LOAD);
+ break;
+ case LOADING_X509_CERTIFICATE:
+ rc = selinux_kernel_load_from_file(NULL,
+ SYSTEM__X509_CERTIFICATE_LOAD);
break;
default:
break;

security/selinux/include/classmap.h

View file
diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h
index f897095..04a9b48 100644
--- a/security/selinux/include/classmap.h
+++ b/security/selinux/include/classmap.h
@@ -63,7 +63,9 @@ const struct security_class_mapping secclass_map[] = {
{ "process2", { "nnp_transition", "nosuid_transition", NULL } },
{ "system",
{ "ipc_info", "syslog_read", "syslog_mod", "syslog_console",
- "module_request", "module_load", NULL } },
+ "module_request", "module_load", "firmware_load",
+ "kexec_image_load", "kexec_initramfs_load", "policy_load",
+ "x509_certificate_load", NULL } },
{ "capability", { COMMON_CAP_PERMS, NULL } },
{ "filesystem",
{ "mount", "remount", "unmount", "getattr", "relabelfrom",

security/selinux/include/policycap.h

View file
diff --git a/security/selinux/include/policycap.h b/security/selinux/include/policycap.h
index 079679f..bd402d3 100644
--- a/security/selinux/include/policycap.h
+++ b/security/selinux/include/policycap.h
@@ -15,6 +15,7 @@ enum {
POLICYDB_CAP_IOCTL_SKIP_CLOEXEC,
POLICYDB_CAP_USERSPACE_INITIAL_CONTEXT,
POLICYDB_CAP_NETLINK_XPERM,
+ POLICYDB_CAP_NETIF_WILDCARD,
__POLICYDB_CAP_MAX
};
#define POLICYDB_CAP_MAX (__POLICYDB_CAP_MAX - 1)

security/selinux/include/policycap_names.h

View file
diff --git a/security/selinux/include/policycap_names.h b/security/selinux/include/policycap_names.h
index e080827..ac1342d 100644
--- a/security/selinux/include/policycap_names.h
+++ b/security/selinux/include/policycap_names.h
@@ -18,6 +18,7 @@ const char *const selinux_policycap_names[__POLICYDB_CAP_MAX] = {
"ioctl_skip_cloexec",
"userspace_initial_context",
"netlink_xperm",
+ "netif_wildcard",
};
/* clang-format on */

security/selinux/include/security.h

View file
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
index 8b4c2aa..e7827ed 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -202,6 +202,12 @@ static inline bool selinux_policycap_netlink_xperm(void)
selinux_state.policycap[POLICYDB_CAP_NETLINK_XPERM]);
}
+static inline bool selinux_policycap_netif_wildcard(void)
+{
+ return READ_ONCE(
+ selinux_state.policycap[POLICYDB_CAP_NETIF_WILDCARD]);
+}
+
struct selinux_policy_convert_data;
struct selinux_load_state {
@@ -301,7 +307,7 @@ int security_ib_pkey_sid(u64 subnet_prefix, u16 pkey_num, u32 *out_sid);
int security_ib_endport_sid(const char *dev_name, u8 port_num, u32 *out_sid);
-int security_netif_sid(char *name, u32 *if_sid);
+int security_netif_sid(const char *name, u32 *if_sid);
int security_node_sid(u16 domain, void *addr, u32 addrlen, u32 *out_sid);

security/selinux/ss/services.c

View file
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index 8478842..e431772 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -46,6 +46,7 @@
#include <linux/in.h>
#include <linux/sched.h>
#include <linux/audit.h>
+#include <linux/parser.h>
#include <linux/vmalloc.h>
#include <linux/lsm_hooks.h>
#include <net/netlabel.h>
@@ -2572,13 +2573,14 @@ out:
* @name: interface name
* @if_sid: interface SID
*/
-int security_netif_sid(char *name, u32 *if_sid)
+int security_netif_sid(const char *name, u32 *if_sid)
{
struct selinux_policy *policy;
struct policydb *policydb;
struct sidtab *sidtab;
int rc;
struct ocontext *c;
+ bool wildcard_support;
if (!selinux_initialized()) {
*if_sid = SECINITSID_NETIF;
@@ -2591,11 +2593,18 @@ retry:
policy = rcu_dereference(selinux_state.policy);
policydb = &policy->policydb;
sidtab = policy->sidtab;
+ wildcard_support = ebitmap_get_bit(&policydb->policycaps, POLICYDB_CAP_NETIF_WILDCARD);
c = policydb->ocontexts[OCON_NETIF];
while (c) {
- if (strcmp(name, c->u.name) == 0)
- break;
+ if (wildcard_support) {
+ if (match_wildcard(c->u.name, name))
+ break;
+ } else {
+ if (strcmp(c->u.name, name) == 0)
+ break;
+ }
+
c = c->next;
}