From: Stephen Smalley <stephen.smalley.work@gmail.com>
To: selinux@vger.kernel.org
Cc: paul@paul-moore.com, omosnace@redhat.com,
Stephen Smalley <stephen.smalley.work@gmail.com>
Subject: [PATCH v2 06/49] selinux: support per-task/cred selinux namespace
Date: Thu, 15 May 2025 09:09:04 -0400 [thread overview]
Message-ID: <20250515130947.52806-7-stephen.smalley.work@gmail.com> (raw)
In-Reply-To: <20250515130947.52806-1-stephen.smalley.work@gmail.com>
Extend the task security structure to include a reference to
the associated selinux namespace, and to also contain a
pointer to the cred in the parent namespace. The current selinux
namespace is changed to the per-task/cred selinux namespace
for the current task/cred.
This change makes it possible to support per-cred selinux namespaces,
but does not yet introduce a mechanism for unsharing of the selinux
namespace. Thus, by itself, this change does not alter the existing
situation with respect to all processes still using a single init
selinux namespace.
An alternative would be to hang the selinux namespace off of the
user namespace, which itself is associated with the cred. This
seems undesirable however since DAC and MAC are orthogonal, and
there appear to be real use cases where one will want to use selinux
namespaces without user namespaces and vice versa. However, one
advantage of hanging off the user namespace would be that it is already
associated with other namespaces, such as the network namespace, thus
potentially facilitating looking up the relevant selinux namespace from
the network input/forward hooks. In most cases however, it appears that
we could instead copy a reference to the creating task selinux namespace
to sock security structures and use that in those hooks.
Introduce a task_security() helper to obtain the correct task/cred
security structure from the hooks, and update the hooks to use it.
This returns a pointer to the security structure for the task in
the same selinux namespace as the caller, or if there is none, a
fake security structure with the well-defined unlabeled SIDs. This
ensures that we return a valid result that can be used for permission
checks and for returning contexts from e.g. reading /proc/pid/attr files.
Signed-off-by: Stephen Smalley <stephen.smalley.work@gmail.com>
---
security/selinux/hooks.c | 53 +++++++++++++++++++++++++----
security/selinux/include/objsec.h | 37 --------------------
security/selinux/include/security.h | 46 ++++++++++++++++++++++++-
3 files changed, 92 insertions(+), 44 deletions(-)
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index fe4c65b132a4..b6c619ba5635 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -108,9 +108,6 @@
#define SELINUX_INODE_INIT_XATTRS 1
-static struct selinux_state *init_selinux_state;
-struct selinux_state *current_selinux_state;
-
/* SECMARK reference count */
static atomic_t selinux_secmark_refcount = ATOMIC_INIT(0);
@@ -207,6 +204,8 @@ static int selinux_lsm_notifier_avc_callback(u32 event)
return 0;
}
+static struct selinux_state *init_selinux_state;
+
/*
* initialise the security for the init task
*/
@@ -218,6 +217,7 @@ static void cred_init_security(void)
tsec = selinux_cred(unrcu_pointer(current->real_cred));
tsec->osid = tsec->sid = tsec->avdcache.sid = SECINITSID_KERNEL;
+ tsec->state = get_selinux_state(init_selinux_state);
}
/*
@@ -231,6 +231,27 @@ static inline u32 cred_sid(const struct cred *cred)
return tsec->sid;
}
+static struct task_security_struct unlabeled_task_security = {
+ .osid = SECINITSID_UNLABELED,
+ .sid = SECINITSID_UNLABELED,
+};
+
+/*
+ * Caller must hold RCU read lock.
+ */
+static const struct task_security_struct *task_security(
+ const struct task_struct *p)
+{
+ const struct task_security_struct *tsec;
+
+ tsec = selinux_cred(__task_cred(p));
+ while (tsec->state != current_selinux_state && tsec->parent_cred)
+ tsec = selinux_cred(tsec->parent_cred);
+ if (tsec->state != current_selinux_state)
+ return &unlabeled_task_security;
+ return tsec;
+}
+
static void __ad_net_init(struct common_audit_data *ad,
struct lsm_network_audit *net,
int ifindex, struct sock *sk, u16 family)
@@ -261,10 +282,12 @@ static void ad_net_init_from_iif(struct common_audit_data *ad,
*/
static inline u32 task_sid_obj(const struct task_struct *task)
{
+ const struct task_security_struct *tsec;
u32 sid;
rcu_read_lock();
- sid = cred_sid(__task_cred(task));
+ tsec = task_security(task);
+ sid = tsec->sid;
rcu_read_unlock();
return sid;
}
@@ -4193,6 +4216,18 @@ static int selinux_task_alloc(struct task_struct *task,
sid, sid, SECCLASS_PROCESS, PROCESS__FORK, NULL);
}
+/*
+ * free/release any cred memory other than the blob itself
+ */
+static void selinux_cred_free(struct cred *cred)
+{
+ struct task_security_struct *tsec = selinux_cred(cred);
+
+ put_selinux_state(tsec->state);
+ if (tsec->parent_cred)
+ put_cred(tsec->parent_cred);
+}
+
/*
* prepare a new set of credentials for modification
*/
@@ -4203,6 +4238,9 @@ static int selinux_cred_prepare(struct cred *new, const struct cred *old,
struct task_security_struct *tsec = selinux_cred(new);
*tsec = *old_tsec;
+ tsec->state = get_selinux_state(old_tsec->state);
+ if (old_tsec->parent_cred)
+ tsec->parent_cred = get_cred(old_tsec->parent_cred);
return 0;
}
@@ -4215,6 +4253,9 @@ static void selinux_cred_transfer(struct cred *new, const struct cred *old)
struct task_security_struct *tsec = selinux_cred(new);
*tsec = *old_tsec;
+ tsec->state = get_selinux_state(old_tsec->state);
+ if (old_tsec->parent_cred)
+ tsec->parent_cred = get_cred(old_tsec->parent_cred);
}
static void selinux_cred_getsecid(const struct cred *c, u32 *secid)
@@ -6665,7 +6706,7 @@ static int selinux_lsm_getattr(unsigned int attr, struct task_struct *p,
u32 len;
rcu_read_lock();
- tsec = selinux_cred(__task_cred(p));
+ tsec = task_security(p);
if (p != current) {
error = avc_has_perm(current_selinux_state,
current_sid(), tsec->sid,
@@ -7562,6 +7603,7 @@ static struct security_hook_list selinux_hooks[] __ro_after_init = {
LSM_HOOK_INIT(file_open, selinux_file_open),
LSM_HOOK_INIT(task_alloc, selinux_task_alloc),
+ LSM_HOOK_INIT(cred_free, selinux_cred_free),
LSM_HOOK_INIT(cred_prepare, selinux_cred_prepare),
LSM_HOOK_INIT(cred_transfer, selinux_cred_transfer),
LSM_HOOK_INIT(cred_getsecid, selinux_cred_getsecid),
@@ -7822,7 +7864,6 @@ static __init int selinux_init(void)
if (selinux_state_create(NULL, &init_selinux_state))
panic("SELinux: Could not create initial namespace\n");
enforcing_set(init_selinux_state, selinux_enforcing_boot);
- current_selinux_state = init_selinux_state;
/* Set the security state for the initial task. */
cred_init_security();
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h
index 6ee7dc4dfd6e..48cb69865a35 100644
--- a/security/selinux/include/objsec.h
+++ b/security/selinux/include/objsec.h
@@ -29,29 +29,6 @@
#include "flask.h"
#include "avc.h"
-struct avdc_entry {
- u32 isid; /* inode SID */
- u32 allowed; /* allowed permission bitmask */
- u32 audited; /* audited permission bitmask */
- bool permissive; /* AVC permissive flag */
-};
-
-struct task_security_struct {
- u32 osid; /* SID prior to last execve */
- u32 sid; /* current SID */
- u32 exec_sid; /* exec SID */
- u32 create_sid; /* fscreate SID */
- u32 keycreate_sid; /* keycreate SID */
- u32 sockcreate_sid; /* fscreate SID */
-#define TSEC_AVDC_DIR_SIZE (1 << 2)
- struct {
- u32 sid; /* current SID for cached entries */
- u32 seqno; /* AVC sequence number */
- unsigned int dir_spot; /* dir cache index to check first */
- struct avdc_entry dir[TSEC_AVDC_DIR_SIZE]; /* dir entries */
- } avdcache;
-} __randomize_layout;
-
enum label_initialized {
LABEL_INVALID, /* invalid or not initialized */
LABEL_INITIALIZED, /* initialized */
@@ -163,10 +140,6 @@ struct perf_event_security_struct {
};
extern struct lsm_blob_sizes selinux_blob_sizes;
-static inline struct task_security_struct *selinux_cred(const struct cred *cred)
-{
- return cred->security + selinux_blob_sizes.lbs_cred;
-}
static inline struct file_security_struct *selinux_file(const struct file *file)
{
@@ -193,16 +166,6 @@ selinux_ipc(const struct kern_ipc_perm *ipc)
return ipc->security + selinux_blob_sizes.lbs_ipc;
}
-/*
- * get the subjective security ID of the current task
- */
-static inline u32 current_sid(void)
-{
- const struct task_security_struct *tsec = selinux_cred(current_cred());
-
- return tsec->sid;
-}
-
static inline struct superblock_security_struct *
selinux_superblock(const struct super_block *superblock)
{
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
index eadef3f02c45..e628b66a1ed0 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -16,6 +16,8 @@
#include <linux/rcupdate.h>
#include <linux/refcount.h>
#include <linux/workqueue.h>
+#include <linux/cred.h>
+#include <linux/lsm_hooks.h>
#include <linux/delay.h>
#include <linux/printk.h>
#include "flask.h"
@@ -132,7 +134,49 @@ get_selinux_state(struct selinux_state *state)
return state;
}
-extern struct selinux_state *current_selinux_state;
+struct avdc_entry {
+ u32 isid; /* inode SID */
+ u32 allowed; /* allowed permission bitmask */
+ u32 audited; /* audited permission bitmask */
+ bool permissive; /* AVC permissive flag */
+};
+
+struct task_security_struct {
+ u32 osid; /* SID prior to last execve */
+ u32 sid; /* current SID */
+ u32 exec_sid; /* SID upon next execve */
+ u32 create_sid; /* SID for new files */
+ u32 keycreate_sid; /* SID for new keys */
+ u32 sockcreate_sid; /* SID for new sockets */
+#define TSEC_AVDC_DIR_SIZE (1 << 2)
+ struct {
+ u32 sid; /* current SID for cached entries */
+ u32 seqno; /* AVC sequence number */
+ unsigned int dir_spot; /* dir cache index to check first */
+ struct avdc_entry dir[TSEC_AVDC_DIR_SIZE]; /* dir entries */
+ } avdcache;
+ struct selinux_state *state; /* selinux namespace */
+ const struct cred *parent_cred; /* cred in parent ns */
+} __randomize_layout;
+
+extern struct lsm_blob_sizes selinux_blob_sizes;
+
+static inline struct task_security_struct *selinux_cred(const struct cred *cred)
+{
+ return cred->security + selinux_blob_sizes.lbs_cred;
+}
+
+/*
+ * get the subjective security ID of the current task
+ */
+static inline u32 current_sid(void)
+{
+ const struct task_security_struct *tsec = selinux_cred(current_cred());
+
+ return tsec->sid;
+}
+
+#define current_selinux_state (selinux_cred(current_cred())->state)
static inline bool selinux_initialized(const struct selinux_state *state)
{
--
2.49.0
next prev parent reply other threads:[~2025-05-15 13:10 UTC|newest]
Thread overview: 53+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-05-15 13:08 [PATCH v2 00/49] SELinux namespace support Stephen Smalley
2025-05-15 13:08 ` [PATCH v2 01/49] selinux: restore passing of selinux_state Stephen Smalley
2025-05-15 13:09 ` [PATCH v2 02/49] selinux: introduce current_selinux_state Stephen Smalley
2025-05-15 13:09 ` [PATCH v2 03/49] selinux: support multiple selinuxfs instances Stephen Smalley
2025-05-15 13:09 ` [PATCH v2 04/49] selinux: dynamically allocate selinux namespace Stephen Smalley
2025-05-15 13:09 ` [PATCH v2 05/49] netstate,selinux: create the selinux netlink socket per network namespace Stephen Smalley
2025-05-15 13:09 ` Stephen Smalley [this message]
2025-05-15 13:09 ` [PATCH v2 07/49] selinux: introduce cred_selinux_state() and use it Stephen Smalley
2025-05-15 13:09 ` [PATCH v2 08/49] selinux: add a selinuxfs interface to unshare selinux namespace Stephen Smalley
2025-05-15 13:09 ` [PATCH v2 09/49] selinuxfs: restrict write operations to the same " Stephen Smalley
2025-05-15 13:09 ` [PATCH v2 10/49] selinux: introduce a global SID table Stephen Smalley
2025-05-15 13:09 ` [PATCH v2 11/49] selinux: wrap security server interfaces to use the " Stephen Smalley
2025-05-15 13:09 ` [PATCH v2 12/49] selinux: update hook functions to use correct selinux namespace Stephen Smalley
2025-05-15 13:09 ` [PATCH v2 13/49] selinux: introduce cred_task_has_perm() Stephen Smalley
2025-05-15 13:09 ` [PATCH v2 14/49] selinux: introduce cred_has_extended_perms() Stephen Smalley
2025-05-15 13:09 ` [PATCH v2 15/49] selinux: introduce cred_self_has_perm() Stephen Smalley
2025-05-15 13:09 ` [PATCH v2 16/49] selinux: introduce cred_has_perm() Stephen Smalley
2025-05-15 13:09 ` [PATCH v2 17/49] selinux: introduce cred_ssid_has_perm() and cred_other_has_perm() Stephen Smalley
2025-05-15 13:09 ` [PATCH v2 18/49] selinux: introduce task_obj_perm() Stephen Smalley
2025-05-15 13:09 ` [PATCH v2 19/49] selinux: fix selinux_lsm_getattr() check Stephen Smalley
2025-05-15 13:09 ` [PATCH v2 20/49] selinux: update bprm hooks for selinux namespaces Stephen Smalley
2025-05-15 13:09 ` [PATCH v2 21/49] selinux: add kerneldoc to new permission checking functions Stephen Smalley
2025-05-15 13:09 ` [PATCH v2 22/49] selinux: convert selinux_file_send_sigiotask() to namespace-aware helper Stephen Smalley
2025-05-15 13:09 ` [PATCH v2 23/49] selinux: rename cred_has_perm*() to cred_tsid_has_perm*() Stephen Smalley
2025-05-15 13:09 ` [PATCH v2 24/49] selinux: convert additional checks to cred_ssid_has_perm() Stephen Smalley
2025-05-15 13:09 ` [PATCH v2 25/49] selinux: introduce selinux_state_has_perm() Stephen Smalley
2025-05-15 13:09 ` [PATCH v2 26/49] selinux: annotate selinuxfs permission checks Stephen Smalley
2025-05-15 13:09 ` [PATCH v2 27/49] selinux: annotate process transition " Stephen Smalley
2025-05-15 13:09 ` [PATCH v2 28/49] selinux: convert xfrm and netlabel " Stephen Smalley
2025-05-15 13:09 ` [PATCH v2 29/49] selinux: switch selinux_lsm_setattr() checks to current namespace Stephen Smalley
2025-05-15 13:09 ` [PATCH v2 30/49] selinux: add limits for SELinux namespaces Stephen Smalley
2025-05-15 13:09 ` [PATCH v2 31/49] selinux: fix namespace creation Stephen Smalley
2025-05-15 13:09 ` [PATCH v2 32/49] selinux: limit selinux netlink notifications to init namespace Stephen Smalley
2025-05-15 13:09 ` [PATCH v2 33/49] selinux: refactor selinux_state_create() Stephen Smalley
2025-05-15 13:09 ` [PATCH v2 34/49] selinux: make open_perms namespace-aware Stephen Smalley
2025-05-15 13:09 ` [PATCH v2 35/49] selinux: split cred_ssid_has_perm() into two cases Stephen Smalley
2025-05-15 13:09 ` [PATCH v2 36/49] selinux: set initial SID context for init to "kernel" in global SID table Stephen Smalley
2025-05-15 13:09 ` [PATCH v2 37/49] selinux: disallow writes to /sys/fs/selinux/user in non-init namespaces Stephen Smalley
2025-05-15 13:09 ` [PATCH v2 38/49] selinux: convert nlmsg_sock_has_extended_perms() to namespace-aware Stephen Smalley
2025-05-15 13:09 ` [PATCH v2 39/49] selinux: init inode from nearest initialized namespace Stephen Smalley
2025-05-15 13:09 ` [PATCH v2 40/49] selinux: allow userspace to detect non-init SELinux namespace Stephen Smalley
2025-05-15 13:09 ` [PATCH v2 41/49] selinux: exempt creation of init SELinux namespace from limits Stephen Smalley
2025-05-15 13:09 ` [PATCH v2 42/49] selinux: introduce a Kconfig option for SELinux namespaces Stephen Smalley
2025-05-15 13:09 ` [PATCH v2 43/49] selinux: eliminate global SID table if !CONFIG_SECURITY_SELINUX_NS Stephen Smalley
2025-05-15 13:09 ` [PATCH v2 44/49] selinux: maintain a small cache in the global SID table Stephen Smalley
2025-05-15 13:09 ` [PATCH v2 45/49] selinux: change /sys/fs/selinux/unshare to check current process state Stephen Smalley
2025-05-15 13:09 ` [PATCH v2 46/49] selinux: acquire/release SELinux state properly in socket hooks Stephen Smalley
2025-05-15 13:09 ` [PATCH v2 47/49] selinux: update cred_tsid_has_perm_noaudit() to return the combined avd Stephen Smalley
2025-05-15 13:09 ` [PATCH v2 48/49] selinux: repair security_fs_use() interface and its users Stephen Smalley
2025-05-15 13:09 ` [PATCH v2 49/49] selinux: style cleanups for node_sid prototypes Stephen Smalley
2025-05-15 13:35 ` [PATCH v2 00/49] SELinux namespace support Stephen Smalley
2025-05-15 13:59 ` Stephen Smalley
2025-05-20 12:06 ` Stephen Smalley
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250515130947.52806-7-stephen.smalley.work@gmail.com \
--to=stephen.smalley.work@gmail.com \
--cc=omosnace@redhat.com \
--cc=paul@paul-moore.com \
--cc=selinux@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).