* [PATCH v7 00/42] SELinux namespace support
@ 2025-08-14 13:25 Stephen Smalley
2025-08-14 13:25 ` [PATCH v7 01/42] selinux: restore passing of selinux_state Stephen Smalley
` (41 more replies)
0 siblings, 42 replies; 43+ messages in thread
From: Stephen Smalley @ 2025-08-14 13:25 UTC (permalink / raw)
To: selinux; +Cc: paul, omosnace, netdev, horms, Stephen Smalley
This series introduces support for SELinux namespaces, i.e. the
ability to create multiple SELinux namespaces each with its own
policy, AVC, and enforcing mode. This support can be leveraged by
Linux container runtimes to establish a private SELinux namespace for
each container, enabling the container to load and enforce its own
policy while still remaining bound by the host OS policy (if
any). Documentation and open issues can be found at
https://github.com/stephensmalley/selinuxns.
Performance data:
Baseline = v6.16-rc1 No NS = v6.16-rc1+this patch series with
SECURITY_SELINUX_NS=n Init NS = Same but with SECURITY_SELINUX_NS=y
from init SELinux namespace Child NS = Same but from a child SELinux
namespace
kcbench (automated kernel compilation benchmark packaged by Fedora,
run with 'kcbench -s 6.13' for 10 runs, computing average and standard
deviation): |CPUs|Baseline (sec)|StdDev|No NS (sec)|Init NS
(sec)|Child NS (sec)| | 16 | 123.88 | 0.24 | 121.85 | 121.67 | 121.93
| | 19 | 125.33 | 0.43 | 123.06 | 123.03 | 122.73 |
'perf record make –jN' on a fully built allmodconfig kernel tree,
followed by 'perf report --sort=symbol,dso' yields the following
percentages (only showing __d_lookup_rcu for reference and only
showing relevant SELinux functions): |Function |Baseline|NoNS
|InitNS|ChildNS| | __d_lookup_rcu | 1.74% | 1.72%| 1.72%| 1.82% | |
selinux_inode_permission | 0.71% | 0.55%| 0.58%| 0.56% | |
selinux_inode_getattr | 0.40% | 0.41%| 0.42%| 0.42% | | avc_lookup |
0.14% | 0.07%| 0.11%| 0.21% | | avc_has_perm/_noaudit (*)| 0.08% |
0.05%| 0.05%| 0.09% | | avc_policy_seqno | 0.02% | 0.17%| 0.16%| 0.16%
| | cred_tsid_has_perm | N/A | 0.07%| 0.07%| 0.10% | | Total SELinux |
1.35% | 1.32%| 1.39%| 1.54% | | SELinux/d_lookup_rcu | 0.776 | 0.767|
0.808| 0.846 | (*) Sum of avc_has_perm + avc_has_perm_noaudit
percentages.
NB perf record was done _without_ the separate neveraudit|permissive
types optimization [1], which would significantly reduce the SELinux
percentages for such types both with and without the SELinux namespace
patches.
ApacheBench (run with 'ab –n 100000 –c 1000 http://localhost/' for ten
runs, computing average and stddev): |Metric |Baseline|Std Dev|No NS
|Init NS |Child NS| |Time taken (sec) | 6.8071| 0.6764| 7.0198|
7.1344| 7.8451| |Reqs / sec | 14823.1| 1339.6|14353.2| 14163.3|
12858.4| |Time per req (ms) | 68.0721| 6.7646|70.1978| 71.3438|
78.4525| |Transfer rate (KB/sec) | 126691| 11499| 122675| 121052|
109899| |Connect time median (ms)| 27.8| 4.3| 27| 25.8| 30.5| |Total
time median (ms) | 62.6| 9.3| 67.6| 68.0| 77.0|
[1]
https://lore.kernel.org/selinux/20250521144123.199370-4-stephen.smalley.work@gmail.com/
v7 re-bases on latest selinux/dev, which is now 6.17-rc1 based.
No substantive changes.
I have not re-run the performance benchmarks again from the prior
version but could do so if required.
Stephen Smalley (42):
selinux: restore passing of selinux_state
selinux: introduce current_selinux_state
selinux: support multiple selinuxfs instances
selinux: dynamically allocate selinux namespace
netstate,selinux: create the selinux netlink socket per network
namespace
selinux: limit selinux netlink notifications to init namespace
selinux: support per-task/cred selinux namespace
selinux: introduce cred_selinux_state() and use it
selinux: init inode from nearest initialized namespace
selinux: add a selinuxfs interface to unshare selinux namespace
selinux: add limits for SELinux namespaces
selinux: exempt creation of init SELinux namespace from limits
selinux: refactor selinux_state_create()
selinux: allow userspace to detect non-init SELinux namespace
selinuxfs: restrict write operations to the same selinux namespace
selinux: introduce a global SID table
selinux: wrap security server interfaces to use the global SID table
selinux: introduce a Kconfig option for SELinux namespaces
selinux: eliminate global SID table if !CONFIG_SECURITY_SELINUX_NS
selinux: maintain a small cache in the global SID table
selinux: update hook functions to use correct selinux namespace
selinux: introduce cred_task_has_perm()
selinux: introduce cred_has_extended_perms()
selinux: introduce cred_self_has_perm()
selinux: introduce cred_has_perm()
selinux: introduce cred_ssid_has_perm() and cred_other_has_perm()
selinux: introduce task_obj_has_perm()
selinux: update bprm hooks for selinux namespaces
selinux: add kerneldoc to new permission checking functions
selinux: convert selinux_file_send_sigiotask() to namespace-aware
helper
selinux: rename cred_has_perm*() to cred_tsid_has_perm*()
selinux: update cred_tsid_has_perm_noaudit() to return the combined
avd
selinux: convert additional checks to cred_ssid_has_perm()
selinux: introduce selinux_state_has_perm()
selinux: annotate selinuxfs permission checks
selinux: annotate process transition permission checks
selinux: convert xfrm and netlabel permission checks
selinux: switch selinux_lsm_setattr() checks to current namespace
selinux: make open_perms namespace-aware
selinux: split cred_ssid_has_perm() into two cases
selinux: convert nlmsg_sock_has_extended_perms() to namespace-aware
selinux: disallow writes to /sys/fs/selinux/user in non-init
namespaces
include/net/net_namespace.h | 3 +
security/selinux/Kconfig | 65 +
security/selinux/Makefile | 1 +
security/selinux/avc.c | 783 ++++++++--
security/selinux/global_sidtab.c | 810 ++++++++++
security/selinux/hooks.c | 1339 +++++++++++------
security/selinux/ibpkey.c | 2 +-
security/selinux/ima.c | 37 +-
security/selinux/include/audit.h | 8 +
security/selinux/include/avc.h | 76 +-
security/selinux/include/avc_ss.h | 3 +-
security/selinux/{ss => include}/avtab.h | 0
security/selinux/include/classmap.h | 2 +-
security/selinux/include/conditional.h | 4 +-
security/selinux/{ss => include}/constraint.h | 0
security/selinux/{ss => include}/context.h | 0
security/selinux/{ss => include}/ebitmap.h | 0
security/selinux/include/global_sidtab.h | 26 +
security/selinux/{ss => include}/hashtab.h | 0
security/selinux/include/ima.h | 11 +-
security/selinux/{ss => include}/mls.h | 0
security/selinux/{ss => include}/mls_types.h | 0
security/selinux/include/netif.h | 4 +-
security/selinux/include/netlabel.h | 14 +-
security/selinux/include/netnode.h | 4 +-
security/selinux/include/objsec.h | 46 +-
security/selinux/{ss => include}/policydb.h | 0
security/selinux/include/security.h | 473 +++++-
security/selinux/include/selinux_ss.h | 119 ++
security/selinux/{ss => include}/sidtab.h | 34 +
security/selinux/{ss => include}/symtab.h | 0
security/selinux/include/xfrm.h | 8 +-
security/selinux/netif.c | 31 +-
security/selinux/netlabel.c | 32 +-
security/selinux/netlink.c | 42 +-
security/selinux/netnode.c | 26 +-
security/selinux/netport.c | 2 +-
security/selinux/selinuxfs.c | 553 ++++++-
security/selinux/ss/services.c | 468 +++---
security/selinux/ss/services.h | 1 +
security/selinux/ss/sidtab.c | 105 +-
security/selinux/status.c | 44 +-
security/selinux/xfrm.c | 47 +-
43 files changed, 4089 insertions(+), 1134 deletions(-)
create mode 100644 security/selinux/global_sidtab.c
rename security/selinux/{ss => include}/avtab.h (100%)
rename security/selinux/{ss => include}/constraint.h (100%)
rename security/selinux/{ss => include}/context.h (100%)
rename security/selinux/{ss => include}/ebitmap.h (100%)
create mode 100644 security/selinux/include/global_sidtab.h
rename security/selinux/{ss => include}/hashtab.h (100%)
rename security/selinux/{ss => include}/mls.h (100%)
rename security/selinux/{ss => include}/mls_types.h (100%)
rename security/selinux/{ss => include}/policydb.h (100%)
create mode 100644 security/selinux/include/selinux_ss.h
rename security/selinux/{ss => include}/sidtab.h (81%)
rename security/selinux/{ss => include}/symtab.h (100%)
--
2.50.1
^ permalink raw reply [flat|nested] 43+ messages in thread
* [PATCH v7 01/42] selinux: restore passing of selinux_state
2025-08-14 13:25 [PATCH v7 00/42] SELinux namespace support Stephen Smalley
@ 2025-08-14 13:25 ` Stephen Smalley
2025-08-14 13:25 ` [PATCH v7 02/42] selinux: introduce current_selinux_state Stephen Smalley
` (40 subsequent siblings)
41 siblings, 0 replies; 43+ messages in thread
From: Stephen Smalley @ 2025-08-14 13:25 UTC (permalink / raw)
To: selinux; +Cc: paul, omosnace, netdev, horms, Stephen Smalley
This reverts commit e67b79850fcc4eb5 ("selinux: stop passing selinux_state
pointers and their offspring"). This change is necessary in order to
support SELinux namespaces.
Signed-off-by: Stephen Smalley <stephen.smalley.work@gmail.com>
---
security/selinux/avc.c | 223 +++++-----
security/selinux/hooks.c | 569 +++++++++++++++----------
security/selinux/ibpkey.c | 2 +-
security/selinux/ima.c | 37 +-
security/selinux/include/avc.h | 42 +-
security/selinux/include/avc_ss.h | 3 +-
security/selinux/include/conditional.h | 4 +-
security/selinux/include/ima.h | 11 +-
security/selinux/include/objsec.h | 2 +-
security/selinux/include/security.h | 163 ++++---
security/selinux/netif.c | 2 +-
security/selinux/netlabel.c | 17 +-
security/selinux/netnode.c | 4 +-
security/selinux/netport.c | 2 +-
security/selinux/selinuxfs.c | 206 +++++----
security/selinux/ss/services.c | 349 +++++++++------
security/selinux/ss/services.h | 1 +
security/selinux/status.c | 44 +-
security/selinux/xfrm.c | 20 +-
19 files changed, 1022 insertions(+), 679 deletions(-)
diff --git a/security/selinux/avc.c b/security/selinux/avc.c
index 430b0e23ee00..32e1a116f2b7 100644
--- a/security/selinux/avc.c
+++ b/security/selinux/avc.c
@@ -93,7 +93,7 @@ struct selinux_avc {
static struct selinux_avc selinux_avc;
-void selinux_avc_init(void)
+void selinux_avc_init(struct selinux_avc **avc)
{
int i;
@@ -104,16 +104,18 @@ void selinux_avc_init(void)
}
atomic_set(&selinux_avc.avc_cache.active_nodes, 0);
atomic_set(&selinux_avc.avc_cache.lru_hint, 0);
+ *avc = &selinux_avc;
}
-unsigned int avc_get_cache_threshold(void)
+unsigned int avc_get_cache_threshold(struct selinux_avc *avc)
{
- return selinux_avc.avc_cache_threshold;
+ return avc->avc_cache_threshold;
}
-void avc_set_cache_threshold(unsigned int cache_threshold)
+void avc_set_cache_threshold(struct selinux_avc *avc,
+ unsigned int cache_threshold)
{
- selinux_avc.avc_cache_threshold = cache_threshold;
+ avc->avc_cache_threshold = cache_threshold;
}
static struct avc_callback_node *avc_callbacks __ro_after_init;
@@ -140,7 +142,7 @@ void __init avc_init(void)
avc_xperms_data_cachep = KMEM_CACHE(extended_perms_data, SLAB_PANIC);
}
-int avc_get_hash_stats(char *page)
+int avc_get_hash_stats(struct selinux_avc *avc, char *page)
{
int i, chain_len, max_chain_len, slots_used;
struct avc_node *node;
@@ -151,7 +153,7 @@ int avc_get_hash_stats(char *page)
slots_used = 0;
max_chain_len = 0;
for (i = 0; i < AVC_CACHE_SLOTS; i++) {
- head = &selinux_avc.avc_cache.slots[i];
+ head = &avc->avc_cache.slots[i];
if (!hlist_empty(head)) {
slots_used++;
chain_len = 0;
@@ -166,7 +168,7 @@ int avc_get_hash_stats(char *page)
return scnprintf(page, PAGE_SIZE, "entries: %d\nbuckets used: %d/%d\n"
"longest chain: %d\n",
- atomic_read(&selinux_avc.avc_cache.active_nodes),
+ atomic_read(&avc->avc_cache.active_nodes),
slots_used, AVC_CACHE_SLOTS, max_chain_len);
}
@@ -409,7 +411,8 @@ static inline u32 avc_xperms_audit_required(u32 requested,
return audited;
}
-static inline int avc_xperms_audit(u32 ssid, u32 tsid, u16 tclass,
+static inline int avc_xperms_audit(struct selinux_state *state,
+ u32 ssid, u32 tsid, u16 tclass,
u32 requested, struct av_decision *avd,
struct extended_perms_decision *xpd,
u8 perm, int result,
@@ -421,7 +424,7 @@ static inline int avc_xperms_audit(u32 ssid, u32 tsid, u16 tclass,
requested, avd, xpd, perm, result, &denied);
if (likely(!audited))
return 0;
- return slow_avc_audit(ssid, tsid, tclass, requested,
+ return slow_avc_audit(state, ssid, tsid, tclass, requested,
audited, denied, result, ad);
}
@@ -433,29 +436,30 @@ static void avc_node_free(struct rcu_head *rhead)
avc_cache_stats_incr(frees);
}
-static void avc_node_delete(struct avc_node *node)
+static void avc_node_delete(struct selinux_avc *avc, struct avc_node *node)
{
hlist_del_rcu(&node->list);
call_rcu(&node->rhead, avc_node_free);
- atomic_dec(&selinux_avc.avc_cache.active_nodes);
+ atomic_dec(&avc->avc_cache.active_nodes);
}
-static void avc_node_kill(struct avc_node *node)
+static void avc_node_kill(struct selinux_avc *avc, struct avc_node *node)
{
avc_xperms_free(node->ae.xp_node);
kmem_cache_free(avc_node_cachep, node);
avc_cache_stats_incr(frees);
- atomic_dec(&selinux_avc.avc_cache.active_nodes);
+ atomic_dec(&avc->avc_cache.active_nodes);
}
-static void avc_node_replace(struct avc_node *new, struct avc_node *old)
+static void avc_node_replace(struct selinux_avc *avc,
+ struct avc_node *new, struct avc_node *old)
{
hlist_replace_rcu(&old->list, &new->list);
call_rcu(&old->rhead, avc_node_free);
- atomic_dec(&selinux_avc.avc_cache.active_nodes);
+ atomic_dec(&avc->avc_cache.active_nodes);
}
-static inline int avc_reclaim_node(void)
+static inline int avc_reclaim_node(struct selinux_avc *avc)
{
struct avc_node *node;
int hvalue, try, ecx;
@@ -464,17 +468,17 @@ static inline int avc_reclaim_node(void)
spinlock_t *lock;
for (try = 0, ecx = 0; try < AVC_CACHE_SLOTS; try++) {
- hvalue = atomic_inc_return(&selinux_avc.avc_cache.lru_hint) &
+ hvalue = atomic_inc_return(&avc->avc_cache.lru_hint) &
(AVC_CACHE_SLOTS - 1);
- head = &selinux_avc.avc_cache.slots[hvalue];
- lock = &selinux_avc.avc_cache.slots_lock[hvalue];
+ head = &avc->avc_cache.slots[hvalue];
+ lock = &avc->avc_cache.slots_lock[hvalue];
if (!spin_trylock_irqsave(lock, flags))
continue;
rcu_read_lock();
hlist_for_each_entry(node, head, list) {
- avc_node_delete(node);
+ avc_node_delete(avc, node);
avc_cache_stats_incr(reclaims);
ecx++;
if (ecx >= AVC_CACHE_RECLAIM) {
@@ -490,7 +494,7 @@ static inline int avc_reclaim_node(void)
return ecx;
}
-static struct avc_node *avc_alloc_node(void)
+static struct avc_node *avc_alloc_node(struct selinux_avc *avc)
{
struct avc_node *node;
@@ -501,9 +505,9 @@ static struct avc_node *avc_alloc_node(void)
INIT_HLIST_NODE(&node->list);
avc_cache_stats_incr(allocations);
- if (atomic_inc_return(&selinux_avc.avc_cache.active_nodes) >
- selinux_avc.avc_cache_threshold)
- avc_reclaim_node();
+ if (atomic_inc_return(&avc->avc_cache.active_nodes) >
+ avc->avc_cache_threshold)
+ avc_reclaim_node(avc);
out:
return node;
@@ -517,14 +521,15 @@ static void avc_node_populate(struct avc_node *node, u32 ssid, u32 tsid, u16 tcl
memcpy(&node->ae.avd, avd, sizeof(node->ae.avd));
}
-static inline struct avc_node *avc_search_node(u32 ssid, u32 tsid, u16 tclass)
+static inline struct avc_node *avc_search_node(struct selinux_avc *avc,
+ u32 ssid, u32 tsid, u16 tclass)
{
struct avc_node *node, *ret = NULL;
u32 hvalue;
struct hlist_head *head;
hvalue = avc_hash(ssid, tsid, tclass);
- head = &selinux_avc.avc_cache.slots[hvalue];
+ head = &avc->avc_cache.slots[hvalue];
hlist_for_each_entry_rcu(node, head, list) {
if (ssid == node->ae.ssid &&
tclass == node->ae.tclass &&
@@ -539,6 +544,7 @@ static inline struct avc_node *avc_search_node(u32 ssid, u32 tsid, u16 tclass)
/**
* avc_lookup - Look up an AVC entry.
+ * @avc: the access vector cache
* @ssid: source security identifier
* @tsid: target security identifier
* @tclass: target security class
@@ -549,12 +555,13 @@ static inline struct avc_node *avc_search_node(u32 ssid, u32 tsid, u16 tclass)
* then this function returns the avc_node.
* Otherwise, this function returns NULL.
*/
-static struct avc_node *avc_lookup(u32 ssid, u32 tsid, u16 tclass)
+static struct avc_node *avc_lookup(struct selinux_avc *avc,
+ u32 ssid, u32 tsid, u16 tclass)
{
struct avc_node *node;
avc_cache_stats_incr(lookups);
- node = avc_search_node(ssid, tsid, tclass);
+ node = avc_search_node(avc, ssid, tsid, tclass);
if (node)
return node;
@@ -563,7 +570,8 @@ static struct avc_node *avc_lookup(u32 ssid, u32 tsid, u16 tclass)
return NULL;
}
-static int avc_latest_notif_update(u32 seqno, int is_insert)
+static int avc_latest_notif_update(struct selinux_avc *avc,
+ u32 seqno, int is_insert)
{
int ret = 0;
static DEFINE_SPINLOCK(notif_lock);
@@ -571,14 +579,14 @@ static int avc_latest_notif_update(u32 seqno, int is_insert)
spin_lock_irqsave(¬if_lock, flag);
if (is_insert) {
- if (seqno < selinux_avc.avc_cache.latest_notif) {
+ if (seqno < avc->avc_cache.latest_notif) {
pr_warn("SELinux: avc: seqno %d < latest_notif %d\n",
- seqno, selinux_avc.avc_cache.latest_notif);
+ seqno, avc->avc_cache.latest_notif);
ret = -EAGAIN;
}
} else {
- if (seqno > selinux_avc.avc_cache.latest_notif)
- selinux_avc.avc_cache.latest_notif = seqno;
+ if (seqno > avc->avc_cache.latest_notif)
+ avc->avc_cache.latest_notif = seqno;
}
spin_unlock_irqrestore(¬if_lock, flag);
@@ -587,6 +595,7 @@ static int avc_latest_notif_update(u32 seqno, int is_insert)
/**
* avc_insert - Insert an AVC entry.
+ * @avc: the access vector cache
* @ssid: source security identifier
* @tsid: target security identifier
* @tclass: target security class
@@ -602,7 +611,7 @@ static int avc_latest_notif_update(u32 seqno, int is_insert)
* revocation notification, then the function copies
* the access vectors into a cache entry.
*/
-static void avc_insert(u32 ssid, u32 tsid, u16 tclass,
+static void avc_insert(struct selinux_avc *avc, u32 ssid, u32 tsid, u16 tclass,
struct av_decision *avd, struct avc_xperms_node *xp_node)
{
struct avc_node *pos, *node = NULL;
@@ -611,28 +620,28 @@ static void avc_insert(u32 ssid, u32 tsid, u16 tclass,
spinlock_t *lock;
struct hlist_head *head;
- if (avc_latest_notif_update(avd->seqno, 1))
+ if (avc_latest_notif_update(avc, avd->seqno, 1))
return;
- node = avc_alloc_node();
+ node = avc_alloc_node(avc);
if (!node)
return;
avc_node_populate(node, ssid, tsid, tclass, avd);
if (avc_xperms_populate(node, xp_node)) {
- avc_node_kill(node);
+ avc_node_kill(avc, node);
return;
}
hvalue = avc_hash(ssid, tsid, tclass);
- head = &selinux_avc.avc_cache.slots[hvalue];
- lock = &selinux_avc.avc_cache.slots_lock[hvalue];
+ head = &avc->avc_cache.slots[hvalue];
+ lock = &avc->avc_cache.slots_lock[hvalue];
spin_lock_irqsave(lock, flag);
hlist_for_each_entry(pos, head, list) {
if (pos->ae.ssid == ssid &&
pos->ae.tsid == tsid &&
pos->ae.tclass == tclass) {
- avc_node_replace(node, pos);
+ avc_node_replace(avc, node, pos);
goto found;
}
}
@@ -699,14 +708,14 @@ static void avc_audit_post_callback(struct audit_buffer *ab, void *a)
u32 tcontext_len;
int rc;
- rc = security_sid_to_context(sad->ssid, &scontext,
+ rc = security_sid_to_context(sad->state, sad->ssid, &scontext,
&scontext_len);
if (rc)
audit_log_format(ab, " ssid=%d", sad->ssid);
else
audit_log_format(ab, " scontext=%s", scontext);
- rc = security_sid_to_context(sad->tsid, &tcontext,
+ rc = security_sid_to_context(sad->state, sad->tsid, &tcontext,
&tcontext_len);
if (rc)
audit_log_format(ab, " tsid=%d", sad->tsid);
@@ -724,7 +733,7 @@ static void avc_audit_post_callback(struct audit_buffer *ab, void *a)
kfree(scontext);
/* in case of invalid context report also the actual context string */
- rc = security_sid_to_context_inval(sad->ssid, &scontext,
+ rc = security_sid_to_context_inval(sad->state, sad->ssid, &scontext,
&scontext_len);
if (!rc && scontext) {
if (scontext_len && scontext[scontext_len - 1] == '\0')
@@ -734,7 +743,7 @@ static void avc_audit_post_callback(struct audit_buffer *ab, void *a)
kfree(scontext);
}
- rc = security_sid_to_context_inval(sad->tsid, &scontext,
+ rc = security_sid_to_context_inval(sad->state, sad->tsid, &scontext,
&scontext_len);
if (!rc && scontext) {
if (scontext_len && scontext[scontext_len - 1] == '\0')
@@ -750,7 +759,8 @@ static void avc_audit_post_callback(struct audit_buffer *ab, void *a)
* Note that it is non-blocking and can be called from under
* rcu_read_lock().
*/
-noinline int slow_avc_audit(u32 ssid, u32 tsid, u16 tclass,
+noinline int slow_avc_audit(struct selinux_state *state,
+ u32 ssid, u32 tsid, u16 tclass,
u32 requested, u32 audited, u32 denied, int result,
struct common_audit_data *a)
{
@@ -772,6 +782,7 @@ noinline int slow_avc_audit(u32 ssid, u32 tsid, u16 tclass,
sad.audited = audited;
sad.denied = denied;
sad.result = result;
+ sad.state = state;
a->selinux_audit_data = &sad;
@@ -809,6 +820,7 @@ int __init avc_add_callback(int (*callback)(u32 event), u32 events)
/**
* avc_update_node - Update an AVC entry
+ * @avc: the access vector cache
* @event : Updating event
* @perms : Permission mask bits
* @driver: xperm driver information
@@ -826,9 +838,12 @@ int __init avc_add_callback(int (*callback)(u32 event), u32 events)
* otherwise, this function updates the AVC entry. The original AVC-entry object
* will release later by RCU.
*/
-static int avc_update_node(u32 event, u32 perms, u8 driver, u8 base_perm,
- u8 xperm, u32 ssid, u32 tsid, u16 tclass, u32 seqno,
- struct extended_perms_decision *xpd, u32 flags)
+static int avc_update_node(struct selinux_avc *avc,
+ u32 event, u32 perms, u8 driver, u8 base_perm,
+ u8 xperm, u32 ssid,
+ u32 tsid, u16 tclass, u32 seqno,
+ struct extended_perms_decision *xpd,
+ u32 flags)
{
u32 hvalue;
int rc = 0;
@@ -837,7 +852,7 @@ static int avc_update_node(u32 event, u32 perms, u8 driver, u8 base_perm,
struct hlist_head *head;
spinlock_t *lock;
- node = avc_alloc_node();
+ node = avc_alloc_node(avc);
if (!node) {
rc = -ENOMEM;
goto out;
@@ -846,8 +861,8 @@ static int avc_update_node(u32 event, u32 perms, u8 driver, u8 base_perm,
/* Lock the target slot */
hvalue = avc_hash(ssid, tsid, tclass);
- head = &selinux_avc.avc_cache.slots[hvalue];
- lock = &selinux_avc.avc_cache.slots_lock[hvalue];
+ head = &avc->avc_cache.slots[hvalue];
+ lock = &avc->avc_cache.slots_lock[hvalue];
spin_lock_irqsave(lock, flag);
@@ -863,7 +878,7 @@ static int avc_update_node(u32 event, u32 perms, u8 driver, u8 base_perm,
if (!orig) {
rc = -ENOENT;
- avc_node_kill(node);
+ avc_node_kill(avc, node);
goto out_unlock;
}
@@ -876,7 +891,7 @@ static int avc_update_node(u32 event, u32 perms, u8 driver, u8 base_perm,
if (orig->ae.xp_node) {
rc = avc_xperms_populate(node, orig->ae.xp_node);
if (rc) {
- avc_node_kill(node);
+ avc_node_kill(avc, node);
goto out_unlock;
}
}
@@ -906,12 +921,12 @@ static int avc_update_node(u32 event, u32 perms, u8 driver, u8 base_perm,
case AVC_CALLBACK_ADD_XPERMS:
rc = avc_add_xperms_decision(node, xpd);
if (rc) {
- avc_node_kill(node);
+ avc_node_kill(avc, node);
goto out_unlock;
}
break;
}
- avc_node_replace(node, orig);
+ avc_node_replace(avc, node, orig);
out_unlock:
spin_unlock_irqrestore(lock, flag);
out:
@@ -920,8 +935,9 @@ static int avc_update_node(u32 event, u32 perms, u8 driver, u8 base_perm,
/**
* avc_flush - Flush the cache
+ * @avc: the access vector cache
*/
-static void avc_flush(void)
+static void avc_flush(struct selinux_avc *avc)
{
struct hlist_head *head;
struct avc_node *node;
@@ -930,8 +946,8 @@ static void avc_flush(void)
int i;
for (i = 0; i < AVC_CACHE_SLOTS; i++) {
- head = &selinux_avc.avc_cache.slots[i];
- lock = &selinux_avc.avc_cache.slots_lock[i];
+ head = &avc->avc_cache.slots[i];
+ lock = &avc->avc_cache.slots_lock[i];
spin_lock_irqsave(lock, flag);
/*
@@ -940,7 +956,7 @@ static void avc_flush(void)
*/
rcu_read_lock();
hlist_for_each_entry(node, head, list)
- avc_node_delete(node);
+ avc_node_delete(avc, node);
rcu_read_unlock();
spin_unlock_irqrestore(lock, flag);
}
@@ -948,14 +964,15 @@ static void avc_flush(void)
/**
* avc_ss_reset - Flush the cache and revalidate migrated permissions.
+ * @avc: the access vector cache
* @seqno: policy sequence number
*/
-int avc_ss_reset(u32 seqno)
+int avc_ss_reset(struct selinux_avc *avc, u32 seqno)
{
struct avc_callback_node *c;
int rc = 0, tmprc;
- avc_flush();
+ avc_flush(avc);
for (c = avc_callbacks; c; c = c->next) {
if (c->events & AVC_CALLBACK_RESET) {
@@ -967,12 +984,13 @@ int avc_ss_reset(u32 seqno)
}
}
- avc_latest_notif_update(seqno, 0);
+ avc_latest_notif_update(avc, seqno, 0);
return rc;
}
/**
* avc_compute_av - Add an entry to the AVC based on the security policy
+ * @state: SELinux state pointer
* @ssid: subject
* @tsid: object/target
* @tclass: object class
@@ -983,28 +1001,33 @@ int avc_ss_reset(u32 seqno)
* fails. Don't inline this, since it's the slow-path and just results in a
* bigger stack frame.
*/
-static noinline void avc_compute_av(u32 ssid, u32 tsid, u16 tclass,
+static noinline void avc_compute_av(struct selinux_state *state, u32 ssid,
+ u32 tsid, u16 tclass,
struct av_decision *avd,
struct avc_xperms_node *xp_node)
{
INIT_LIST_HEAD(&xp_node->xpd_head);
- security_compute_av(ssid, tsid, tclass, avd, &xp_node->xp);
- avc_insert(ssid, tsid, tclass, avd, xp_node);
+ security_compute_av(state, ssid, tsid, tclass, avd, &xp_node->xp);
+ avc_insert(state->avc, ssid, tsid, tclass, avd, xp_node);
}
-static noinline int avc_denied(u32 ssid, u32 tsid, u16 tclass, u32 requested,
+static noinline int avc_denied(struct selinux_state *state,
+ u32 ssid, u32 tsid,
+ u16 tclass, u32 requested,
u8 driver, u8 base_perm, u8 xperm,
- unsigned int flags, struct av_decision *avd)
+ unsigned int flags,
+ struct av_decision *avd)
{
if (flags & AVC_STRICT)
return -EACCES;
- if (enforcing_enabled() &&
+ if (enforcing_enabled(state) &&
!(avd->flags & AVD_FLAGS_PERMISSIVE))
return -EACCES;
- avc_update_node(AVC_CALLBACK_GRANT, requested, driver, base_perm,
- xperm, ssid, tsid, tclass, avd->seqno, NULL, flags);
+ avc_update_node(state->avc, AVC_CALLBACK_GRANT, requested, driver,
+ base_perm, xperm, ssid, tsid, tclass, avd->seqno,
+ NULL, flags);
return 0;
}
@@ -1015,7 +1038,8 @@ static noinline int avc_denied(u32 ssid, u32 tsid, u16 tclass, u32 requested,
* as-is the case with ioctls, then multiple may be chained together and the
* driver field is used to specify which set contains the permission.
*/
-int avc_has_extended_perms(u32 ssid, u32 tsid, u16 tclass, u32 requested,
+int avc_has_extended_perms(struct selinux_state *state,
+ u32 ssid, u32 tsid, u16 tclass, u32 requested,
u8 driver, u8 base_perm, u8 xperm,
struct common_audit_data *ad)
{
@@ -1037,9 +1061,9 @@ int avc_has_extended_perms(u32 ssid, u32 tsid, u16 tclass, u32 requested,
rcu_read_lock();
- node = avc_lookup(ssid, tsid, tclass);
+ node = avc_lookup(state->avc, ssid, tsid, tclass);
if (unlikely(!node)) {
- avc_compute_av(ssid, tsid, tclass, &avd, xp_node);
+ avc_compute_av(state, ssid, tsid, tclass, &avd, xp_node);
} else {
memcpy(&avd, &node->ae.avd, sizeof(avd));
xp_node = node->ae.xp_node;
@@ -1064,12 +1088,13 @@ int avc_has_extended_perms(u32 ssid, u32 tsid, u16 tclass, u32 requested,
goto decision;
}
rcu_read_unlock();
- security_compute_xperms_decision(ssid, tsid, tclass, driver,
- base_perm, &local_xpd);
+ security_compute_xperms_decision(state, ssid, tsid, tclass,
+ driver, base_perm,
+ &local_xpd);
rcu_read_lock();
- avc_update_node(AVC_CALLBACK_ADD_XPERMS, requested, driver,
- base_perm, xperm, ssid, tsid, tclass, avd.seqno,
- &local_xpd, 0);
+ avc_update_node(state->avc, AVC_CALLBACK_ADD_XPERMS, requested,
+ driver, base_perm, xperm, ssid, tsid, tclass,
+ avd.seqno, &local_xpd, 0);
} else {
avc_quick_copy_xperms_decision(xperm, &local_xpd, xpd);
}
@@ -1081,12 +1106,13 @@ int avc_has_extended_perms(u32 ssid, u32 tsid, u16 tclass, u32 requested,
decision:
denied = requested & ~(avd.allowed);
if (unlikely(denied))
- rc = avc_denied(ssid, tsid, tclass, requested, driver,
- base_perm, xperm, AVC_EXTENDED_PERMS, &avd);
+ rc = avc_denied(state, ssid, tsid, tclass, requested,
+ driver, base_perm, xperm, AVC_EXTENDED_PERMS,
+ &avd);
rcu_read_unlock();
- rc2 = avc_xperms_audit(ssid, tsid, tclass, requested,
+ rc2 = avc_xperms_audit(state, ssid, tsid, tclass, requested,
&avd, xpd, xperm, rc, ad);
if (rc2)
return rc2;
@@ -1095,6 +1121,7 @@ int avc_has_extended_perms(u32 ssid, u32 tsid, u16 tclass, u32 requested,
/**
* avc_perm_nonode - Add an entry to the AVC
+ * @state: SELinux state pointer
* @ssid: subject
* @tsid: object/target
* @tclass: object class
@@ -1106,23 +1133,25 @@ int avc_has_extended_perms(u32 ssid, u32 tsid, u16 tclass, u32 requested,
* unlikely and needs extra stack space for the new node that we generate, so
* don't inline it.
*/
-static noinline int avc_perm_nonode(u32 ssid, u32 tsid, u16 tclass,
+static noinline int avc_perm_nonode(struct selinux_state *state,
+ u32 ssid, u32 tsid, u16 tclass,
u32 requested, unsigned int flags,
struct av_decision *avd)
{
u32 denied;
struct avc_xperms_node xp_node;
- avc_compute_av(ssid, tsid, tclass, avd, &xp_node);
+ avc_compute_av(state, ssid, tsid, tclass, avd, &xp_node);
denied = requested & ~(avd->allowed);
if (unlikely(denied))
- return avc_denied(ssid, tsid, tclass, requested, 0, 0, 0,
- flags, avd);
+ return avc_denied(state, ssid, tsid, tclass, requested, 0, 0,
+ 0, flags, avd);
return 0;
}
/**
* avc_has_perm_noaudit - Check permissions but perform no auditing.
+ * @state: SELinux state
* @ssid: source security identifier
* @tsid: target security identifier
* @tclass: target security class
@@ -1141,7 +1170,8 @@ static noinline int avc_perm_nonode(u32 ssid, u32 tsid, u16 tclass,
* auditing, e.g. in cases where a lock must be held for the check but
* should be released for the auditing.
*/
-inline int avc_has_perm_noaudit(u32 ssid, u32 tsid,
+inline int avc_has_perm_noaudit(struct selinux_state *state,
+ u32 ssid, u32 tsid,
u16 tclass, u32 requested,
unsigned int flags,
struct av_decision *avd)
@@ -1153,10 +1183,10 @@ inline int avc_has_perm_noaudit(u32 ssid, u32 tsid,
return -EACCES;
rcu_read_lock();
- node = avc_lookup(ssid, tsid, tclass);
+ node = avc_lookup(state->avc, ssid, tsid, tclass);
if (unlikely(!node)) {
rcu_read_unlock();
- return avc_perm_nonode(ssid, tsid, tclass, requested,
+ return avc_perm_nonode(state, ssid, tsid, tclass, requested,
flags, avd);
}
denied = requested & ~node->ae.avd.allowed;
@@ -1164,13 +1194,14 @@ inline int avc_has_perm_noaudit(u32 ssid, u32 tsid,
rcu_read_unlock();
if (unlikely(denied))
- return avc_denied(ssid, tsid, tclass, requested, 0, 0, 0,
- flags, avd);
+ return avc_denied(state, ssid, tsid, tclass, requested, 0, 0,
+ 0, flags, avd);
return 0;
}
/**
* avc_has_perm - Check permissions and perform any appropriate auditing.
+ * @state: SELinux state
* @ssid: source security identifier
* @tsid: target security identifier
* @tclass: target security class
@@ -1185,23 +1216,23 @@ inline int avc_has_perm_noaudit(u32 ssid, u32 tsid,
* permissions are granted, -%EACCES if any permissions are denied, or
* another -errno upon other errors.
*/
-int avc_has_perm(u32 ssid, u32 tsid, u16 tclass,
+int avc_has_perm(struct selinux_state *state, u32 ssid, u32 tsid, u16 tclass,
u32 requested, struct common_audit_data *auditdata)
{
struct av_decision avd;
int rc, rc2;
- rc = avc_has_perm_noaudit(ssid, tsid, tclass, requested, 0,
+ rc = avc_has_perm_noaudit(state, ssid, tsid, tclass, requested, 0,
&avd);
- rc2 = avc_audit(ssid, tsid, tclass, requested, &avd, rc,
+ rc2 = avc_audit(state, ssid, tsid, tclass, requested, &avd, rc,
auditdata);
if (rc2)
return rc2;
return rc;
}
-u32 avc_policy_seqno(void)
+u32 avc_policy_seqno(struct selinux_state *state)
{
- return selinux_avc.avc_cache.latest_notif;
+ return state->avc->avc_cache.latest_notif;
}
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index e474cd7398ef..0c503700d1df 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -279,7 +279,7 @@ static int __inode_security_revalidate(struct inode *inode,
struct dentry *dentry,
bool may_sleep)
{
- if (!selinux_initialized())
+ if (!selinux_initialized(&selinux_state))
return 0;
if (may_sleep)
@@ -440,12 +440,14 @@ static int may_context_mount_sb_relabel(u32 sid,
const struct task_security_struct *tsec = selinux_cred(cred);
int rc;
- rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
+ rc = avc_has_perm(&selinux_state,
+ tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
FILESYSTEM__RELABELFROM, NULL);
if (rc)
return rc;
- rc = avc_has_perm(tsec->sid, sid, SECCLASS_FILESYSTEM,
+ rc = avc_has_perm(&selinux_state,
+ tsec->sid, sid, SECCLASS_FILESYSTEM,
FILESYSTEM__RELABELTO, NULL);
return rc;
}
@@ -456,12 +458,14 @@ static int may_context_mount_inode_relabel(u32 sid,
{
const struct task_security_struct *tsec = selinux_cred(cred);
int rc;
- rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
+ rc = avc_has_perm(&selinux_state,
+ tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
FILESYSTEM__RELABELFROM, NULL);
if (rc)
return rc;
- rc = avc_has_perm(sid, sbsec->sid, SECCLASS_FILESYSTEM,
+ rc = avc_has_perm(&selinux_state,
+ sid, sbsec->sid, SECCLASS_FILESYSTEM,
FILESYSTEM__ASSOCIATE, NULL);
return rc;
}
@@ -544,7 +548,7 @@ static int sb_check_xattr_support(struct super_block *sb)
fallback:
/* No xattr support - try to fallback to genfs if possible. */
- rc = security_genfs_sid(sb->s_type->name, "/",
+ rc = security_genfs_sid(&selinux_state, sb->s_type->name, "/",
SECCLASS_DIR, &sid);
if (rc)
return -EOPNOTSUPP;
@@ -655,7 +659,7 @@ static int selinux_set_mnt_opts(struct super_block *sb,
mutex_lock(&sbsec->lock);
- if (!selinux_initialized()) {
+ if (!selinux_initialized(&selinux_state)) {
if (!opts) {
/* Defer initialization until selinux_complete_init,
after the initial policy is loaded and the security
@@ -754,7 +758,7 @@ static int selinux_set_mnt_opts(struct super_block *sb,
* Determine the labeling behavior to use for this
* filesystem type.
*/
- rc = security_fs_use(sb);
+ rc = security_fs_use(&selinux_state, sb);
if (rc) {
pr_warn("%s: security_fs_use(%s) returned %d\n",
__func__, sb->s_type->name, rc);
@@ -779,7 +783,8 @@ static int selinux_set_mnt_opts(struct super_block *sb,
}
if (sbsec->behavior == SECURITY_FS_USE_XATTR) {
sbsec->behavior = SECURITY_FS_USE_MNTPOINT;
- rc = security_transition_sid(current_sid(),
+ rc = security_transition_sid(&selinux_state,
+ current_sid(),
current_sid(),
SECCLASS_FILE, NULL,
&sbsec->mntpoint_sid);
@@ -937,7 +942,7 @@ static int selinux_sb_clone_mnt_opts(const struct super_block *oldsb,
* if the parent was able to be mounted it clearly had no special lsm
* mount options. thus we can safely deal with this superblock later
*/
- if (!selinux_initialized()) {
+ if (!selinux_initialized(&selinux_state)) {
if (kern_flags & SECURITY_LSM_NATIVE_LABELS) {
newsbsec->flags |= SE_SBNATIVE;
*set_kern_flags |= SECURITY_LSM_NATIVE_LABELS;
@@ -964,7 +969,7 @@ static int selinux_sb_clone_mnt_opts(const struct super_block *oldsb,
if (newsbsec->behavior == SECURITY_FS_USE_NATIVE &&
!(kern_flags & SECURITY_LSM_NATIVE_LABELS) && !set_context) {
- rc = security_fs_use(newsb);
+ rc = security_fs_use(&selinux_state, newsb);
if (rc)
goto out;
}
@@ -1013,7 +1018,7 @@ static int selinux_add_opt(int token, const char *s, void **mnt_opts)
if (!s)
return -EINVAL;
- if (!selinux_initialized()) {
+ if (!selinux_initialized(&selinux_state)) {
pr_warn("SELinux: Unable to set superblock options before the security server is initialized\n");
return -EINVAL;
}
@@ -1050,7 +1055,7 @@ static int selinux_add_opt(int token, const char *s, void **mnt_opts)
WARN_ON(1);
return -EINVAL;
}
- rc = security_context_str_to_sid(s, dst_sid, GFP_KERNEL);
+ rc = security_context_str_to_sid(&selinux_state, s, dst_sid, GFP_KERNEL);
if (rc)
pr_warn("SELinux: security_context_str_to_sid (%s) failed with errno=%d\n",
s, rc);
@@ -1067,7 +1072,8 @@ static int show_sid(struct seq_file *m, u32 sid)
u32 len;
int rc;
- rc = security_sid_to_context(sid, &context, &len);
+ rc = security_sid_to_context(&selinux_state, sid,
+ &context, &len);
if (!rc) {
bool has_comma = strchr(context, ',');
@@ -1090,7 +1096,7 @@ static int selinux_sb_show_options(struct seq_file *m, struct super_block *sb)
if (!(sbsec->flags & SE_SBINITIALIZED))
return 0;
- if (!selinux_initialized())
+ if (!selinux_initialized(&selinux_state))
return 0;
if (sbsec->flags & FSCONTEXT_MNT) {
@@ -1342,7 +1348,7 @@ static int selinux_genfs_get_sid(struct dentry *dentry,
path++;
}
}
- rc = security_genfs_sid(sb->s_type->name,
+ rc = security_genfs_sid(&selinux_state, sb->s_type->name,
path, tclass, sid);
if (rc == -ENOENT) {
/* No match in policy, mark as unlabeled. */
@@ -1397,7 +1403,7 @@ static int inode_doinit_use_xattr(struct inode *inode, struct dentry *dentry,
return 0;
}
- rc = security_context_to_sid_default(context, rc, sid,
+ rc = security_context_to_sid_default(&selinux_state, context, rc, sid,
def_sid, GFP_NOFS);
if (rc) {
char *dev = inode->i_sb->s_id;
@@ -1507,7 +1513,7 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
sid = sbsec->sid;
/* Try to obtain a transition SID. */
- rc = security_transition_sid(task_sid, sid,
+ rc = security_transition_sid(&selinux_state, task_sid, sid,
sclass, NULL, &sid);
if (rc)
goto out;
@@ -1652,9 +1658,11 @@ static int cred_has_capability(const struct cred *cred,
return -EINVAL;
}
- rc = avc_has_perm_noaudit(sid, sid, sclass, av, 0, &avd);
+ rc = avc_has_perm_noaudit(&selinux_state,
+ sid, sid, sclass, av, 0, &avd);
if (!(opts & CAP_OPT_NOAUDIT)) {
- int rc2 = avc_audit(sid, sid, sclass, av, &avd, rc, &ad);
+ int rc2 = avc_audit(&selinux_state,
+ sid, sid, sclass, av, &avd, rc, &ad);
if (rc2)
return rc2;
}
@@ -1678,7 +1686,8 @@ static int inode_has_perm(const struct cred *cred,
sid = cred_sid(cred);
isec = selinux_inode(inode);
- return avc_has_perm(sid, isec->sid, isec->sclass, perms, adp);
+ return avc_has_perm(&selinux_state,
+ sid, isec->sid, isec->sclass, perms, adp);
}
/* Same as inode_has_perm, but pass explicit audit data containing
@@ -1757,7 +1766,8 @@ static int file_has_perm(const struct cred *cred,
ad.u.file = file;
if (sid != fsec->sid) {
- rc = avc_has_perm(sid, fsec->sid,
+ rc = avc_has_perm(&selinux_state,
+ sid, fsec->sid,
SECCLASS_FD,
FD__USE,
&ad);
@@ -1800,7 +1810,7 @@ selinux_determine_inode_label(const struct task_security_struct *tsec,
*_new_isid = tsec->create_sid;
} else {
const struct inode_security_struct *dsec = inode_security(dir);
- return security_transition_sid(tsec->sid,
+ return security_transition_sid(&selinux_state, tsec->sid,
dsec->sid, tclass,
name, _new_isid);
}
@@ -1828,7 +1838,8 @@ static int may_create(struct inode *dir,
ad.type = LSM_AUDIT_DATA_DENTRY;
ad.u.dentry = dentry;
- rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR,
+ rc = avc_has_perm(&selinux_state,
+ sid, dsec->sid, SECCLASS_DIR,
DIR__ADD_NAME | DIR__SEARCH,
&ad);
if (rc)
@@ -1839,11 +1850,13 @@ static int may_create(struct inode *dir,
if (rc)
return rc;
- rc = avc_has_perm(sid, newsid, tclass, FILE__CREATE, &ad);
+ rc = avc_has_perm(&selinux_state,
+ sid, newsid, tclass, FILE__CREATE, &ad);
if (rc)
return rc;
- return avc_has_perm(newsid, sbsec->sid,
+ return avc_has_perm(&selinux_state,
+ newsid, sbsec->sid,
SECCLASS_FILESYSTEM,
FILESYSTEM__ASSOCIATE, &ad);
}
@@ -1872,7 +1885,8 @@ static int may_link(struct inode *dir,
av = DIR__SEARCH;
av |= (kind ? DIR__REMOVE_NAME : DIR__ADD_NAME);
- rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR, av, &ad);
+ rc = avc_has_perm(&selinux_state,
+ sid, dsec->sid, SECCLASS_DIR, av, &ad);
if (rc)
return rc;
@@ -1892,7 +1906,8 @@ static int may_link(struct inode *dir,
return 0;
}
- rc = avc_has_perm(sid, isec->sid, isec->sclass, av, &ad);
+ rc = avc_has_perm(&selinux_state,
+ sid, isec->sid, isec->sclass, av, &ad);
return rc;
}
@@ -1916,16 +1931,19 @@ static inline int may_rename(struct inode *old_dir,
ad.type = LSM_AUDIT_DATA_DENTRY;
ad.u.dentry = old_dentry;
- rc = avc_has_perm(sid, old_dsec->sid, SECCLASS_DIR,
+ rc = avc_has_perm(&selinux_state,
+ sid, old_dsec->sid, SECCLASS_DIR,
DIR__REMOVE_NAME | DIR__SEARCH, &ad);
if (rc)
return rc;
- rc = avc_has_perm(sid, old_isec->sid,
+ rc = avc_has_perm(&selinux_state,
+ sid, old_isec->sid,
old_isec->sclass, FILE__RENAME, &ad);
if (rc)
return rc;
if (old_is_dir && new_dir != old_dir) {
- rc = avc_has_perm(sid, old_isec->sid,
+ rc = avc_has_perm(&selinux_state,
+ sid, old_isec->sid,
old_isec->sclass, DIR__REPARENT, &ad);
if (rc)
return rc;
@@ -1935,13 +1953,15 @@ static inline int may_rename(struct inode *old_dir,
av = DIR__ADD_NAME | DIR__SEARCH;
if (d_is_positive(new_dentry))
av |= DIR__REMOVE_NAME;
- rc = avc_has_perm(sid, new_dsec->sid, SECCLASS_DIR, av, &ad);
+ rc = avc_has_perm(&selinux_state,
+ sid, new_dsec->sid, SECCLASS_DIR, av, &ad);
if (rc)
return rc;
if (d_is_positive(new_dentry)) {
new_isec = backing_inode_security(new_dentry);
new_is_dir = d_is_dir(new_dentry);
- rc = avc_has_perm(sid, new_isec->sid,
+ rc = avc_has_perm(&selinux_state,
+ sid, new_isec->sid,
new_isec->sclass,
(new_is_dir ? DIR__RMDIR : FILE__UNLINK), &ad);
if (rc)
@@ -1961,7 +1981,8 @@ static int superblock_has_perm(const struct cred *cred,
u32 sid = cred_sid(cred);
sbsec = selinux_superblock(sb);
- return avc_has_perm(sid, sbsec->sid, SECCLASS_FILESYSTEM, perms, ad);
+ return avc_has_perm(&selinux_state,
+ sid, sbsec->sid, SECCLASS_FILESYSTEM, perms, ad);
}
/* Convert a Linux mode and permission mask to an access vector. */
@@ -2035,7 +2056,8 @@ static inline u32 open_file_to_av(struct file *file)
static int selinux_binder_set_context_mgr(const struct cred *mgr)
{
- return avc_has_perm(current_sid(), cred_sid(mgr), SECCLASS_BINDER,
+ return avc_has_perm(&selinux_state,
+ current_sid(), cred_sid(mgr), SECCLASS_BINDER,
BINDER__SET_CONTEXT_MGR, NULL);
}
@@ -2048,20 +2070,22 @@ static int selinux_binder_transaction(const struct cred *from,
int rc;
if (mysid != fromsid) {
- rc = avc_has_perm(mysid, fromsid, SECCLASS_BINDER,
+ rc = avc_has_perm(&selinux_state,
+ mysid, fromsid, SECCLASS_BINDER,
BINDER__IMPERSONATE, NULL);
if (rc)
return rc;
}
- return avc_has_perm(fromsid, tosid,
+ return avc_has_perm(&selinux_state, fromsid, tosid,
SECCLASS_BINDER, BINDER__CALL, NULL);
}
static int selinux_binder_transfer_binder(const struct cred *from,
const struct cred *to)
{
- return avc_has_perm(cred_sid(from), cred_sid(to),
+ return avc_has_perm(&selinux_state,
+ cred_sid(from), cred_sid(to),
SECCLASS_BINDER, BINDER__TRANSFER,
NULL);
}
@@ -2081,7 +2105,8 @@ static int selinux_binder_transfer_file(const struct cred *from,
ad.u.path = file->f_path;
if (sid != fsec->sid) {
- rc = avc_has_perm(sid, fsec->sid,
+ rc = avc_has_perm(&selinux_state,
+ sid, fsec->sid,
SECCLASS_FD,
FD__USE,
&ad);
@@ -2099,7 +2124,8 @@ static int selinux_binder_transfer_file(const struct cred *from,
return 0;
isec = backing_inode_security(dentry);
- return avc_has_perm(sid, isec->sid, isec->sclass, file_to_av(file),
+ return avc_has_perm(&selinux_state,
+ sid, isec->sid, isec->sclass, file_to_av(file),
&ad);
}
@@ -2110,24 +2136,26 @@ static int selinux_ptrace_access_check(struct task_struct *child,
u32 csid = task_sid_obj(child);
if (mode & PTRACE_MODE_READ)
- return avc_has_perm(sid, csid, SECCLASS_FILE, FILE__READ,
- NULL);
+ return avc_has_perm(&selinux_state,
+ sid, csid, SECCLASS_FILE, FILE__READ, NULL);
- return avc_has_perm(sid, csid, SECCLASS_PROCESS, PROCESS__PTRACE,
- NULL);
+ return avc_has_perm(&selinux_state,
+ sid, csid, SECCLASS_PROCESS, PROCESS__PTRACE, NULL);
}
static int selinux_ptrace_traceme(struct task_struct *parent)
{
- return avc_has_perm(task_sid_obj(parent), task_sid_obj(current),
+ return avc_has_perm(&selinux_state,
+ task_sid_obj(parent), task_sid_obj(current),
SECCLASS_PROCESS, PROCESS__PTRACE, NULL);
}
static int selinux_capget(const struct task_struct *target, kernel_cap_t *effective,
kernel_cap_t *inheritable, kernel_cap_t *permitted)
{
- return avc_has_perm(current_sid(), task_sid_obj(target),
- SECCLASS_PROCESS, PROCESS__GETCAP, NULL);
+ return avc_has_perm(&selinux_state,
+ current_sid(), task_sid_obj(target), SECCLASS_PROCESS,
+ PROCESS__GETCAP, NULL);
}
static int selinux_capset(struct cred *new, const struct cred *old,
@@ -2135,7 +2163,8 @@ static int selinux_capset(struct cred *new, const struct cred *old,
const kernel_cap_t *inheritable,
const kernel_cap_t *permitted)
{
- return avc_has_perm(cred_sid(old), cred_sid(new), SECCLASS_PROCESS,
+ return avc_has_perm(&selinux_state,
+ cred_sid(old), cred_sid(new), SECCLASS_PROCESS,
PROCESS__SETCAP, NULL);
}
@@ -2202,18 +2231,21 @@ static int selinux_syslog(int type)
switch (type) {
case SYSLOG_ACTION_READ_ALL: /* Read last kernel messages */
case SYSLOG_ACTION_SIZE_BUFFER: /* Return size of the log buffer */
- return avc_has_perm(current_sid(), SECINITSID_KERNEL,
+ return avc_has_perm(&selinux_state,
+ current_sid(), SECINITSID_KERNEL,
SECCLASS_SYSTEM, SYSTEM__SYSLOG_READ, NULL);
case SYSLOG_ACTION_CONSOLE_OFF: /* Disable logging to console */
case SYSLOG_ACTION_CONSOLE_ON: /* Enable logging to console */
/* Set level of messages printed to console */
case SYSLOG_ACTION_CONSOLE_LEVEL:
- return avc_has_perm(current_sid(), SECINITSID_KERNEL,
+ return avc_has_perm(&selinux_state,
+ current_sid(), SECINITSID_KERNEL,
SECCLASS_SYSTEM, SYSTEM__SYSLOG_CONSOLE,
NULL);
}
/* All other syslog types */
- return avc_has_perm(current_sid(), SECINITSID_KERNEL,
+ return avc_has_perm(&selinux_state,
+ current_sid(), SECINITSID_KERNEL,
SECCLASS_SYSTEM, SYSTEM__SYSLOG_MOD, NULL);
}
@@ -2273,7 +2305,8 @@ static int check_nnp_nosuid(const struct linux_binprm *bprm,
av |= PROCESS2__NNP_TRANSITION;
if (nosuid)
av |= PROCESS2__NOSUID_TRANSITION;
- rc = avc_has_perm(old_tsec->sid, new_tsec->sid,
+ rc = avc_has_perm(&selinux_state,
+ old_tsec->sid, new_tsec->sid,
SECCLASS_PROCESS2, av, NULL);
if (!rc)
return 0;
@@ -2284,7 +2317,7 @@ static int check_nnp_nosuid(const struct linux_binprm *bprm,
* i.e. SIDs that are guaranteed to only be allowed a subset
* of the permissions of the current SID.
*/
- rc = security_bounded_transition(old_tsec->sid,
+ rc = security_bounded_transition(&selinux_state, old_tsec->sid,
new_tsec->sid);
if (!rc)
return 0;
@@ -2330,7 +2363,7 @@ static int selinux_bprm_creds_for_exec(struct linux_binprm *bprm)
* early boot end up with a label different from SECINITSID_KERNEL
* (if the policy chooses to set SECINITSID_INIT != SECINITSID_KERNEL).
*/
- if (!selinux_initialized()) {
+ if (!selinux_initialized(&selinux_state)) {
new_tsec->sid = SECINITSID_INIT;
/* also clear the exec_sid just in case */
new_tsec->exec_sid = 0;
@@ -2348,7 +2381,7 @@ static int selinux_bprm_creds_for_exec(struct linux_binprm *bprm)
return rc;
} else {
/* Check for a default transition on this program. */
- rc = security_transition_sid(old_tsec->sid,
+ rc = security_transition_sid(&selinux_state, old_tsec->sid,
isec->sid, SECCLASS_PROCESS, NULL,
&new_tsec->sid);
if (rc)
@@ -2367,25 +2400,29 @@ static int selinux_bprm_creds_for_exec(struct linux_binprm *bprm)
ad.u.file = bprm->file;
if (new_tsec->sid == old_tsec->sid) {
- rc = avc_has_perm(old_tsec->sid, isec->sid,
+ rc = avc_has_perm(&selinux_state,
+ old_tsec->sid, isec->sid,
SECCLASS_FILE, FILE__EXECUTE_NO_TRANS, &ad);
if (rc)
return rc;
} else {
/* Check permissions for the transition. */
- rc = avc_has_perm(old_tsec->sid, new_tsec->sid,
+ rc = avc_has_perm(&selinux_state,
+ old_tsec->sid, new_tsec->sid,
SECCLASS_PROCESS, PROCESS__TRANSITION, &ad);
if (rc)
return rc;
- rc = avc_has_perm(new_tsec->sid, isec->sid,
+ rc = avc_has_perm(&selinux_state,
+ new_tsec->sid, isec->sid,
SECCLASS_FILE, FILE__ENTRYPOINT, &ad);
if (rc)
return rc;
/* Check for shared state */
if (bprm->unsafe & LSM_UNSAFE_SHARE) {
- rc = avc_has_perm(old_tsec->sid, new_tsec->sid,
+ rc = avc_has_perm(&selinux_state,
+ old_tsec->sid, new_tsec->sid,
SECCLASS_PROCESS, PROCESS__SHARE,
NULL);
if (rc)
@@ -2397,7 +2434,8 @@ static int selinux_bprm_creds_for_exec(struct linux_binprm *bprm)
if (bprm->unsafe & LSM_UNSAFE_PTRACE) {
u32 ptsid = ptrace_parent_sid();
if (ptsid != 0) {
- rc = avc_has_perm(ptsid, new_tsec->sid,
+ rc = avc_has_perm(&selinux_state,
+ ptsid, new_tsec->sid,
SECCLASS_PROCESS,
PROCESS__PTRACE, NULL);
if (rc)
@@ -2411,7 +2449,8 @@ static int selinux_bprm_creds_for_exec(struct linux_binprm *bprm)
/* Enable secure mode for SIDs transitions unless
the noatsecure permission is granted between
the two SIDs, i.e. ahp returns 0. */
- rc = avc_has_perm(old_tsec->sid, new_tsec->sid,
+ rc = avc_has_perm(&selinux_state,
+ old_tsec->sid, new_tsec->sid,
SECCLASS_PROCESS, PROCESS__NOATSECURE,
NULL);
bprm->secureexec |= !!rc;
@@ -2503,7 +2542,8 @@ static void selinux_bprm_committing_creds(const struct linux_binprm *bprm)
* higher than the default soft limit for cases where the default is
* lower than the hard limit, e.g. RLIMIT_CORE or RLIMIT_STACK.
*/
- rc = avc_has_perm(new_tsec->osid, new_tsec->sid, SECCLASS_PROCESS,
+ rc = avc_has_perm(&selinux_state,
+ new_tsec->osid, new_tsec->sid, SECCLASS_PROCESS,
PROCESS__RLIMITINH, NULL);
if (rc) {
/* protect against do_prlimit() */
@@ -2542,7 +2582,8 @@ static void selinux_bprm_committed_creds(const struct linux_binprm *bprm)
* This must occur _after_ the task SID has been updated so that any
* kill done after the flush will be checked against the new SID.
*/
- rc = avc_has_perm(osid, sid, SECCLASS_PROCESS, PROCESS__SIGINH, NULL);
+ rc = avc_has_perm(&selinux_state,
+ osid, sid, SECCLASS_PROCESS, PROCESS__SIGINH, NULL);
if (rc) {
clear_itimer();
@@ -2897,7 +2938,8 @@ static int selinux_dentry_init_security(struct dentry *dentry, int mode,
*xattr_name = XATTR_NAME_SELINUX;
cp->id = LSM_ID_SELINUX;
- return security_sid_to_context(newsid, &cp->context, &cp->len);
+ return security_sid_to_context(&selinux_state, newsid, &cp->context,
+ &cp->len);
}
static int selinux_dentry_create_files_as(struct dentry *dentry, int mode,
@@ -2949,12 +2991,12 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
isec->initialized = LABEL_INITIALIZED;
}
- if (!selinux_initialized() ||
+ if (!selinux_initialized(&selinux_state) ||
!(sbsec->flags & SBLABEL_MNT))
return -EOPNOTSUPP;
if (xattr) {
- rc = security_sid_to_context_force(newsid,
+ rc = security_sid_to_context_force(&selinux_state, newsid,
&context, &clen);
if (rc)
return rc;
@@ -2975,7 +3017,7 @@ static int selinux_inode_init_security_anon(struct inode *inode,
struct inode_security_struct *isec;
int rc;
- if (unlikely(!selinux_initialized()))
+ if (unlikely(!selinux_initialized(&selinux_state)))
return 0;
isec = selinux_inode(inode);
@@ -2999,7 +3041,7 @@ static int selinux_inode_init_security_anon(struct inode *inode,
} else {
isec->sclass = SECCLASS_ANON_INODE;
rc = security_transition_sid(
- sid, sid,
+ &selinux_state, sid, sid,
isec->sclass, name, &isec->sid);
if (rc)
return rc;
@@ -3014,7 +3056,8 @@ static int selinux_inode_init_security_anon(struct inode *inode,
ad.type = LSM_AUDIT_DATA_ANONINODE;
ad.u.anonclass = name ? (const char *)name->name : "?";
- return avc_has_perm(sid,
+ return avc_has_perm(&selinux_state,
+ sid,
isec->sid,
isec->sclass,
FILE__CREATE,
@@ -3082,7 +3125,8 @@ static int selinux_inode_follow_link(struct dentry *dentry, struct inode *inode,
if (IS_ERR(isec))
return PTR_ERR(isec);
- return avc_has_perm(sid, isec->sid, isec->sclass, FILE__READ, &ad);
+ return avc_has_perm(&selinux_state,
+ sid, isec->sid, isec->sclass, FILE__READ, &ad);
}
static noinline int audit_inode_permission(struct inode *inode,
@@ -3095,7 +3139,8 @@ static noinline int audit_inode_permission(struct inode *inode,
ad.type = LSM_AUDIT_DATA_INODE;
ad.u.inode = inode;
- return slow_avc_audit(current_sid(), isec->sid, isec->sclass, perms,
+ return slow_avc_audit(&selinux_state,
+ current_sid(), isec->sid, isec->sclass, perms,
audited, denied, result, &ad);
}
@@ -3110,7 +3155,7 @@ static inline void task_avdcache_reset(struct task_security_struct *tsec)
{
memset(&tsec->avdcache.dir, 0, sizeof(tsec->avdcache.dir));
tsec->avdcache.sid = tsec->sid;
- tsec->avdcache.seqno = avc_policy_seqno();
+ tsec->avdcache.seqno = avc_policy_seqno(&selinux_state);
tsec->avdcache.dir_spot = TSEC_AVDC_DIR_SIZE - 1;
}
@@ -3134,7 +3179,7 @@ static inline int task_avdcache_search(struct task_security_struct *tsec,
return -ENOENT;
if (unlikely(tsec->sid != tsec->avdcache.sid ||
- tsec->avdcache.seqno != avc_policy_seqno())) {
+ tsec->avdcache.seqno != avc_policy_seqno(&selinux_state))) {
task_avdcache_reset(tsec);
return -ENOENT;
}
@@ -3223,15 +3268,16 @@ static int selinux_inode_permission(struct inode *inode, int requested)
/* Cache hit. */
audited = perms & avdc->audited;
denied = perms & ~avdc->allowed;
- if (unlikely(denied && enforcing_enabled() &&
+ if (unlikely(denied && enforcing_enabled(&selinux_state) &&
!avdc->permissive))
rc = -EACCES;
} else {
struct av_decision avd;
/* Cache miss. */
- rc = avc_has_perm_noaudit(tsec->sid, isec->sid, isec->sclass,
- perms, 0, &avd);
+ rc = avc_has_perm_noaudit(&selinux_state, tsec->sid,
+ isec->sid, isec->sclass, perms, 0,
+ &avd);
audited = avc_audit_required(perms, &avd, rc,
(requested & MAY_ACCESS) ? FILE__AUDIT_ACCESS : 0,
&denied);
@@ -3333,7 +3379,7 @@ static int selinux_inode_setxattr(struct mnt_idmap *idmap,
if (strcmp(name, XATTR_NAME_SELINUX))
return dentry_has_perm(current_cred(), dentry, FILE__SETATTR);
- if (!selinux_initialized())
+ if (!selinux_initialized(&selinux_state))
return (inode_owner_or_capable(idmap, inode) ? 0 : -EPERM);
sbsec = selinux_superblock(inode->i_sb);
@@ -3347,12 +3393,13 @@ static int selinux_inode_setxattr(struct mnt_idmap *idmap,
ad.u.dentry = dentry;
isec = backing_inode_security(dentry);
- rc = avc_has_perm(sid, isec->sid, isec->sclass,
+ rc = avc_has_perm(&selinux_state,
+ sid, isec->sid, isec->sclass,
FILE__RELABELFROM, &ad);
if (rc)
return rc;
- rc = security_context_to_sid(value, size, &newsid,
+ rc = security_context_to_sid(&selinux_state, value, size, &newsid,
GFP_KERNEL);
if (rc == -EINVAL) {
if (!has_cap_mac_admin(true)) {
@@ -3381,23 +3428,25 @@ static int selinux_inode_setxattr(struct mnt_idmap *idmap,
return rc;
}
- rc = security_context_to_sid_force(value,
+ rc = security_context_to_sid_force(&selinux_state, value,
size, &newsid);
}
if (rc)
return rc;
- rc = avc_has_perm(sid, newsid, isec->sclass,
+ rc = avc_has_perm(&selinux_state,
+ sid, newsid, isec->sclass,
FILE__RELABELTO, &ad);
if (rc)
return rc;
- rc = security_validate_transition(isec->sid, newsid,
+ rc = security_validate_transition(&selinux_state, isec->sid, newsid,
sid, isec->sclass);
if (rc)
return rc;
- return avc_has_perm(newsid,
+ return avc_has_perm(&selinux_state,
+ newsid,
sbsec->sid,
SECCLASS_FILESYSTEM,
FILESYSTEM__ASSOCIATE,
@@ -3437,7 +3486,7 @@ static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name,
return;
}
- if (!selinux_initialized()) {
+ if (!selinux_initialized(&selinux_state)) {
/* If we haven't even been initialized, then we can't validate
* against a policy, so leave the label as invalid. It may
* resolve to a valid label on the next revalidation try if
@@ -3446,7 +3495,7 @@ static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name,
return;
}
- rc = security_context_to_sid_force(value, size,
+ rc = security_context_to_sid_force(&selinux_state, value, size,
&newsid);
if (rc) {
pr_err("SELinux: unable to map context to SID"
@@ -3484,7 +3533,7 @@ static int selinux_inode_removexattr(struct mnt_idmap *idmap,
if (strcmp(name, XATTR_NAME_SELINUX))
return dentry_has_perm(current_cred(), dentry, FILE__SETATTR);
- if (!selinux_initialized())
+ if (!selinux_initialized(&selinux_state))
return 0;
/* No one is allowed to remove a SELinux security label.
@@ -3570,7 +3619,7 @@ static int selinux_inode_getsecurity(struct mnt_idmap *idmap,
* If we're not initialized yet, then we can't validate contexts, so
* just let vfs_getxattr fall back to using the on-disk xattr.
*/
- if (!selinux_initialized() ||
+ if (!selinux_initialized(&selinux_state) ||
strcmp(name, XATTR_SELINUX_SUFFIX))
return -EOPNOTSUPP;
@@ -3585,10 +3634,11 @@ static int selinux_inode_getsecurity(struct mnt_idmap *idmap,
*/
isec = inode_security(inode);
if (has_cap_mac_admin(false))
- error = security_sid_to_context_force(isec->sid, &context,
+ error = security_sid_to_context_force(&selinux_state,
+ isec->sid, &context,
&size);
else
- error = security_sid_to_context(isec->sid,
+ error = security_sid_to_context(&selinux_state, isec->sid,
&context, &size);
if (error)
return error;
@@ -3620,7 +3670,7 @@ static int selinux_inode_setsecurity(struct inode *inode, const char *name,
if (!value || !size)
return -EACCES;
- rc = security_context_to_sid(value, size, &newsid,
+ rc = security_context_to_sid(&selinux_state, value, size, &newsid,
GFP_KERNEL);
if (rc)
return rc;
@@ -3637,7 +3687,7 @@ static int selinux_inode_listsecurity(struct inode *inode, char *buffer, size_t
{
const int len = sizeof(XATTR_NAME_SELINUX);
- if (!selinux_initialized())
+ if (!selinux_initialized(&selinux_state))
return 0;
if (buffer && len <= buffer_size)
@@ -3679,8 +3729,10 @@ static int selinux_inode_copy_up_xattr(struct dentry *dentry, const char *name)
* xattrs up. Instead, filter out SELinux-related xattrs following
* policy load.
*/
- if (selinux_initialized() && !strcmp(name, XATTR_NAME_SELINUX))
+ if (selinux_initialized(&selinux_state) &&
+ !strcmp(name, XATTR_NAME_SELINUX))
return -ECANCELED; /* Discard */
+
/*
* Any other attribute apart from SELINUX is not claimed, supported
* by selinux.
@@ -3715,7 +3767,7 @@ static int selinux_kernfs_init_security(struct kernfs_node *kn_dir,
return rc;
}
- rc = security_context_to_sid(context, clen, &parent_sid,
+ rc = security_context_to_sid(&selinux_state, context, clen, &parent_sid,
GFP_KERNEL);
kfree(context);
if (rc)
@@ -3733,14 +3785,14 @@ static int selinux_kernfs_init_security(struct kernfs_node *kn_dir,
q.name = kn_name;
q.hash_len = hashlen_string(kn_dir, kn_name);
- rc = security_transition_sid(tsec->sid,
+ rc = security_transition_sid(&selinux_state, tsec->sid,
parent_sid, secclass, &q,
&newsid);
if (rc)
return rc;
}
- rc = security_sid_to_context_force(newsid,
+ rc = security_sid_to_context_force(&selinux_state, newsid,
&context, &clen);
if (rc)
return rc;
@@ -3780,7 +3832,7 @@ static int selinux_file_permission(struct file *file, int mask)
isec = inode_security(inode);
if (sid == fsec->sid && fsec->isid == isec->sid &&
- fsec->pseqno == avc_policy_seqno())
+ fsec->pseqno == avc_policy_seqno(&selinux_state))
/* No change since file_open check. */
return 0;
@@ -3821,7 +3873,8 @@ static int ioctl_has_perm(const struct cred *cred, struct file *file,
ad.u.op->path = file->f_path;
if (ssid != fsec->sid) {
- rc = avc_has_perm(ssid, fsec->sid,
+ rc = avc_has_perm(&selinux_state,
+ ssid, fsec->sid,
SECCLASS_FD,
FD__USE,
&ad);
@@ -3833,8 +3886,10 @@ static int ioctl_has_perm(const struct cred *cred, struct file *file,
return 0;
isec = inode_security(inode);
- rc = avc_has_extended_perms(ssid, isec->sid, isec->sclass, requested,
- driver, AVC_EXT_IOCTL, xperm, &ad);
+ rc = avc_has_extended_perms(&selinux_state,
+ ssid, isec->sid, isec->sclass,
+ requested, driver, AVC_EXT_IOCTL, xperm,
+ &ad);
out:
return rc;
}
@@ -3929,7 +3984,8 @@ static int file_map_prot_check(struct file *file, unsigned long prot, int shared
* private file mapping that will also be writable.
* This has an additional check.
*/
- rc = avc_has_perm(sid, sid, SECCLASS_PROCESS,
+ rc = avc_has_perm(&selinux_state,
+ sid, sid, SECCLASS_PROCESS,
PROCESS__EXECMEM, NULL);
if (rc)
goto error;
@@ -3959,7 +4015,8 @@ static int selinux_mmap_addr(unsigned long addr)
if (addr < CONFIG_LSM_MMAP_MIN_ADDR) {
u32 sid = current_sid();
- rc = avc_has_perm(sid, sid, SECCLASS_MEMPROTECT,
+ rc = avc_has_perm(&selinux_state,
+ sid, sid, SECCLASS_MEMPROTECT,
MEMPROTECT__MMAP_ZERO, NULL);
}
@@ -4007,11 +4064,13 @@ static int selinux_file_mprotect(struct vm_area_struct *vma,
*/
if (vma->vm_start >= vma->vm_mm->start_brk &&
vma->vm_end <= vma->vm_mm->brk) {
- rc = avc_has_perm(sid, sid, SECCLASS_PROCESS,
+ rc = avc_has_perm(&selinux_state,
+ sid, sid, SECCLASS_PROCESS,
PROCESS__EXECHEAP, NULL);
} else if (!vma->vm_file && (vma_is_initial_stack(vma) ||
vma_is_stack_for_current(vma))) {
- rc = avc_has_perm(sid, sid, SECCLASS_PROCESS,
+ rc = avc_has_perm(&selinux_state,
+ sid, sid, SECCLASS_PROCESS,
PROCESS__EXECSTACK, NULL);
} else if (vma->vm_file && vma->anon_vma) {
/*
@@ -4103,7 +4162,8 @@ static int selinux_file_send_sigiotask(struct task_struct *tsk,
else
perm = signal_to_av(signum);
- return avc_has_perm(fsec->fown_sid, sid,
+ return avc_has_perm(&selinux_state,
+ fsec->fown_sid, sid,
SECCLASS_PROCESS, perm, NULL);
}
@@ -4129,7 +4189,7 @@ static int selinux_file_open(struct file *file)
* struct as its SID.
*/
fsec->isid = isec->sid;
- fsec->pseqno = avc_policy_seqno();
+ fsec->pseqno = avc_policy_seqno(&selinux_state);
/*
* Since the inode label or policy seqno may have changed
* between the selinux_inode_permission check and the saving
@@ -4148,7 +4208,8 @@ static int selinux_task_alloc(struct task_struct *task,
{
u32 sid = current_sid();
- return avc_has_perm(sid, sid, SECCLASS_PROCESS, PROCESS__FORK, NULL);
+ return avc_has_perm(&selinux_state,
+ sid, sid, SECCLASS_PROCESS, PROCESS__FORK, NULL);
}
/*
@@ -4195,7 +4256,8 @@ static int selinux_kernel_act_as(struct cred *new, u32 secid)
u32 sid = current_sid();
int ret;
- ret = avc_has_perm(sid, secid,
+ ret = avc_has_perm(&selinux_state,
+ sid, secid,
SECCLASS_KERNEL_SERVICE,
KERNEL_SERVICE__USE_AS_OVERRIDE,
NULL);
@@ -4219,7 +4281,8 @@ static int selinux_kernel_create_files_as(struct cred *new, struct inode *inode)
u32 sid = current_sid();
int ret;
- ret = avc_has_perm(sid, isec->sid,
+ ret = avc_has_perm(&selinux_state,
+ sid, isec->sid,
SECCLASS_KERNEL_SERVICE,
KERNEL_SERVICE__CREATE_FILES_AS,
NULL);
@@ -4236,7 +4299,8 @@ static int selinux_kernel_module_request(char *kmod_name)
ad.type = LSM_AUDIT_DATA_KMOD;
ad.u.kmod_name = kmod_name;
- return avc_has_perm(current_sid(), SECINITSID_KERNEL, SECCLASS_SYSTEM,
+ return avc_has_perm(&selinux_state,
+ current_sid(), SECINITSID_KERNEL, SECCLASS_SYSTEM,
SYSTEM__MODULE_REQUEST, &ad);
}
@@ -4249,20 +4313,25 @@ static int selinux_kernel_load_from_file(struct file *file, u32 requested)
int rc;
if (file == NULL)
- return avc_has_perm(sid, sid, SECCLASS_SYSTEM, requested, NULL);
+ return avc_has_perm(&selinux_state,
+ sid, sid, SECCLASS_SYSTEM, requested,
+ NULL);
+ /* finit_module */
ad.type = LSM_AUDIT_DATA_FILE;
ad.u.file = file;
fsec = selinux_file(file);
if (sid != fsec->sid) {
- rc = avc_has_perm(sid, fsec->sid, SECCLASS_FD, FD__USE, &ad);
+ rc = avc_has_perm(&selinux_state,
+ sid, fsec->sid, SECCLASS_FD, FD__USE, &ad);
if (rc)
return rc;
}
isec = inode_security(file_inode(file));
- return avc_has_perm(sid, isec->sid, SECCLASS_SYSTEM, requested, &ad);
+ return avc_has_perm(&selinux_state,
+ sid, isec->sid, SECCLASS_SYSTEM, requested, &ad);
}
static int selinux_kernel_read_file(struct file *file,
@@ -4342,19 +4411,22 @@ static int selinux_kernel_load_data(enum kernel_load_data_id id, bool contents)
static int selinux_task_setpgid(struct task_struct *p, pid_t pgid)
{
- return avc_has_perm(current_sid(), task_sid_obj(p), SECCLASS_PROCESS,
+ return avc_has_perm(&selinux_state,
+ current_sid(), task_sid_obj(p), SECCLASS_PROCESS,
PROCESS__SETPGID, NULL);
}
static int selinux_task_getpgid(struct task_struct *p)
{
- return avc_has_perm(current_sid(), task_sid_obj(p), SECCLASS_PROCESS,
+ return avc_has_perm(&selinux_state,
+ current_sid(), task_sid_obj(p), SECCLASS_PROCESS,
PROCESS__GETPGID, NULL);
}
static int selinux_task_getsid(struct task_struct *p)
{
- return avc_has_perm(current_sid(), task_sid_obj(p), SECCLASS_PROCESS,
+ return avc_has_perm(&selinux_state,
+ current_sid(), task_sid_obj(p), SECCLASS_PROCESS,
PROCESS__GETSESSION, NULL);
}
@@ -4371,19 +4443,22 @@ static void selinux_task_getlsmprop_obj(struct task_struct *p,
static int selinux_task_setnice(struct task_struct *p, int nice)
{
- return avc_has_perm(current_sid(), task_sid_obj(p), SECCLASS_PROCESS,
+ return avc_has_perm(&selinux_state,
+ current_sid(), task_sid_obj(p), SECCLASS_PROCESS,
PROCESS__SETSCHED, NULL);
}
static int selinux_task_setioprio(struct task_struct *p, int ioprio)
{
- return avc_has_perm(current_sid(), task_sid_obj(p), SECCLASS_PROCESS,
+ return avc_has_perm(&selinux_state,
+ current_sid(), task_sid_obj(p), SECCLASS_PROCESS,
PROCESS__SETSCHED, NULL);
}
static int selinux_task_getioprio(struct task_struct *p)
{
- return avc_has_perm(current_sid(), task_sid_obj(p), SECCLASS_PROCESS,
+ return avc_has_perm(&selinux_state,
+ current_sid(), task_sid_obj(p), SECCLASS_PROCESS,
PROCESS__GETSCHED, NULL);
}
@@ -4398,7 +4473,8 @@ static int selinux_task_prlimit(const struct cred *cred, const struct cred *tcre
av |= PROCESS__SETRLIMIT;
if (flags & LSM_PRLIMIT_READ)
av |= PROCESS__GETRLIMIT;
- return avc_has_perm(cred_sid(cred), cred_sid(tcred),
+ return avc_has_perm(&selinux_state,
+ cred_sid(cred), cred_sid(tcred),
SECCLASS_PROCESS, av, NULL);
}
@@ -4412,7 +4488,8 @@ static int selinux_task_setrlimit(struct task_struct *p, unsigned int resource,
later be used as a safe reset point for the soft limit
upon context transitions. See selinux_bprm_committing_creds. */
if (old_rlim->rlim_max != new_rlim->rlim_max)
- return avc_has_perm(current_sid(), task_sid_obj(p),
+ return avc_has_perm(&selinux_state,
+ current_sid(), task_sid_obj(p),
SECCLASS_PROCESS, PROCESS__SETRLIMIT, NULL);
return 0;
@@ -4420,19 +4497,22 @@ static int selinux_task_setrlimit(struct task_struct *p, unsigned int resource,
static int selinux_task_setscheduler(struct task_struct *p)
{
- return avc_has_perm(current_sid(), task_sid_obj(p), SECCLASS_PROCESS,
+ return avc_has_perm(&selinux_state,
+ current_sid(), task_sid_obj(p), SECCLASS_PROCESS,
PROCESS__SETSCHED, NULL);
}
static int selinux_task_getscheduler(struct task_struct *p)
{
- return avc_has_perm(current_sid(), task_sid_obj(p), SECCLASS_PROCESS,
+ return avc_has_perm(&selinux_state,
+ current_sid(), task_sid_obj(p), SECCLASS_PROCESS,
PROCESS__GETSCHED, NULL);
}
static int selinux_task_movememory(struct task_struct *p)
{
- return avc_has_perm(current_sid(), task_sid_obj(p), SECCLASS_PROCESS,
+ return avc_has_perm(&selinux_state,
+ current_sid(), task_sid_obj(p), SECCLASS_PROCESS,
PROCESS__SETSCHED, NULL);
}
@@ -4450,7 +4530,8 @@ static int selinux_task_kill(struct task_struct *p, struct kernel_siginfo *info,
secid = current_sid();
else
secid = cred_sid(cred);
- return avc_has_perm(secid, task_sid_obj(p), SECCLASS_PROCESS, perm, NULL);
+ return avc_has_perm(&selinux_state,
+ secid, task_sid_obj(p), SECCLASS_PROCESS, perm, NULL);
}
static void selinux_task_to_inode(struct task_struct *p,
@@ -4470,8 +4551,8 @@ static int selinux_userns_create(const struct cred *cred)
{
u32 sid = current_sid();
- return avc_has_perm(sid, sid, SECCLASS_USER_NAMESPACE,
- USER_NAMESPACE__CREATE, NULL);
+ return avc_has_perm(&selinux_state, sid, sid, SECCLASS_USER_NAMESPACE,
+ USER_NAMESPACE__CREATE, NULL);
}
/* Returns error only if unable to parse addresses */
@@ -4701,7 +4782,7 @@ static int selinux_skb_peerlbl_sid(struct sk_buff *skb, u16 family, u32 *sid)
if (unlikely(err))
return -EACCES;
- err = security_net_peersid_resolve(nlbl_sid,
+ err = security_net_peersid_resolve(&selinux_state, nlbl_sid,
nlbl_type, xfrm_sid, sid);
if (unlikely(err)) {
pr_warn(
@@ -4730,7 +4811,7 @@ static int selinux_conn_sid(u32 sk_sid, u32 skb_sid, u32 *conn_sid)
int err = 0;
if (skb_sid != SECSID_NULL)
- err = security_sid_mls_copy(sk_sid, skb_sid,
+ err = security_sid_mls_copy(&selinux_state, sk_sid, skb_sid,
conn_sid);
else
*conn_sid = sk_sid;
@@ -4748,7 +4829,7 @@ static int socket_sockcreate_sid(const struct task_security_struct *tsec,
return 0;
}
- return security_transition_sid(tsec->sid, tsec->sid,
+ return security_transition_sid(&selinux_state, tsec->sid, tsec->sid,
secclass, NULL, socksid);
}
@@ -4786,7 +4867,8 @@ static int sock_has_perm(struct sock *sk, u32 perms)
ad_net_init_from_sk(&ad, &net, sk);
- return avc_has_perm(current_sid(), sksec->sid, sksec->sclass, perms,
+ return avc_has_perm(&selinux_state,
+ current_sid(), sksec->sid, sksec->sclass, perms,
&ad);
}
@@ -4806,7 +4888,8 @@ static int selinux_socket_create(int family, int type,
if (rc)
return rc;
- return avc_has_perm(tsec->sid, newsid, secclass, SOCKET__CREATE, NULL);
+ return avc_has_perm(&selinux_state,
+ tsec->sid, newsid, secclass, SOCKET__CREATE, NULL);
}
static int selinux_socket_post_create(struct socket *sock, int family,
@@ -4942,7 +5025,8 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
snum, &sid);
if (err)
goto out;
- err = avc_has_perm(sksec->sid, sid,
+ err = avc_has_perm(&selinux_state,
+ sksec->sid, sid,
sksec->sclass,
SOCKET__NAME_BIND, &ad);
if (err)
@@ -4977,7 +5061,8 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
else
ad.u.net->v6info.saddr = addr6->sin6_addr;
- err = avc_has_perm(sksec->sid, sid,
+ err = avc_has_perm(&selinux_state,
+ sksec->sid, sid,
sksec->sclass, node_perm, &ad);
if (err)
goto out;
@@ -5071,7 +5156,8 @@ static int selinux_socket_connect_helper(struct socket *sock,
ad.u.net = &net;
ad.u.net->dport = htons(snum);
ad.u.net->family = address->sa_family;
- err = avc_has_perm(sksec->sid, sid, sksec->sclass, perm, &ad);
+ err = avc_has_perm(&selinux_state,
+ sksec->sid, sid, sksec->sclass, perm, &ad);
if (err)
return err;
}
@@ -5181,7 +5267,8 @@ static int selinux_socket_unix_stream_connect(struct sock *sock,
ad_net_init_from_sk(&ad, &net, other);
- err = avc_has_perm(sksec_sock->sid, sksec_other->sid,
+ err = avc_has_perm(&selinux_state,
+ sksec_sock->sid, sksec_other->sid,
sksec_other->sclass,
UNIX_STREAM_SOCKET__CONNECTTO, &ad);
if (err)
@@ -5189,7 +5276,7 @@ static int selinux_socket_unix_stream_connect(struct sock *sock,
/* server child socket */
sksec_new->peer_sid = sksec_sock->sid;
- err = security_sid_mls_copy(sksec_other->sid,
+ err = security_sid_mls_copy(&selinux_state, sksec_other->sid,
sksec_sock->sid, &sksec_new->sid);
if (err)
return err;
@@ -5210,7 +5297,8 @@ static int selinux_socket_unix_may_send(struct socket *sock,
ad_net_init_from_sk(&ad, &net, other->sk);
- return avc_has_perm(ssec->sid, osec->sid, osec->sclass, SOCKET__SENDTO,
+ return avc_has_perm(&selinux_state,
+ ssec->sid, osec->sid, osec->sclass, SOCKET__SENDTO,
&ad);
}
@@ -5225,7 +5313,8 @@ static int selinux_inet_sys_rcv_skb(struct net *ns, int ifindex,
err = sel_netif_sid(ns, ifindex, &if_sid);
if (err)
return err;
- err = avc_has_perm(peer_sid, if_sid,
+ err = avc_has_perm(&selinux_state,
+ peer_sid, if_sid,
SECCLASS_NETIF, NETIF__INGRESS, ad);
if (err)
return err;
@@ -5233,7 +5322,8 @@ static int selinux_inet_sys_rcv_skb(struct net *ns, int ifindex,
err = sel_netnode_sid(addrp, family, &node_sid);
if (err)
return err;
- return avc_has_perm(peer_sid, node_sid,
+ return avc_has_perm(&selinux_state,
+ peer_sid, node_sid,
SECCLASS_NODE, NODE__RECVFROM, ad);
}
@@ -5253,7 +5343,8 @@ static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
return err;
if (selinux_secmark_enabled()) {
- err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET,
+ err = avc_has_perm(&selinux_state,
+ sk_sid, skb->secmark, SECCLASS_PACKET,
PACKET__RECV, &ad);
if (err)
return err;
@@ -5313,7 +5404,8 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
selinux_netlbl_err(skb, family, err, 0);
return err;
}
- err = avc_has_perm(sk_sid, peer_sid, SECCLASS_PEER,
+ err = avc_has_perm(&selinux_state,
+ sk_sid, peer_sid, SECCLASS_PEER,
PEER__RECV, &ad);
if (err) {
selinux_netlbl_err(skb, family, err, 0);
@@ -5322,7 +5414,8 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
}
if (secmark_active) {
- err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET,
+ err = avc_has_perm(&selinux_state,
+ sk_sid, skb->secmark, SECCLASS_PACKET,
PACKET__RECV, &ad);
if (err)
return err;
@@ -5348,7 +5441,7 @@ static int selinux_socket_getpeersec_stream(struct socket *sock,
if (peer_sid == SECSID_NULL)
return -ENOPROTOOPT;
- err = security_sid_to_context(peer_sid, &scontext,
+ err = security_sid_to_context(&selinux_state, peer_sid, &scontext,
&scontext_len);
if (err)
return err;
@@ -5498,7 +5591,8 @@ static int selinux_sctp_process_new_assoc(struct sctp_association *asoc,
* consistency among the peer SIDs.
*/
ad_net_init_from_sk(&ad, &net, asoc->base.sk);
- err = avc_has_perm(sksec->peer_sid, asoc->peer_secid,
+ err = avc_has_perm(&selinux_state,
+ sksec->peer_sid, asoc->peer_secid,
sksec->sclass, SCTP_SOCKET__ASSOCIATION,
&ad);
if (err)
@@ -5728,8 +5822,9 @@ static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb)
static int selinux_secmark_relabel_packet(u32 sid)
{
- return avc_has_perm(current_sid(), sid, SECCLASS_PACKET, PACKET__RELABELTO,
- NULL);
+ return avc_has_perm(&selinux_state,
+ current_sid(), sid, SECCLASS_PACKET,
+ PACKET__RELABELTO, NULL);
}
static void selinux_secmark_refcount_inc(void)
@@ -5767,7 +5862,8 @@ static int selinux_tun_dev_create(void)
* connections unlike traditional sockets - check the TUN driver to
* get a better understanding of why this socket is special */
- return avc_has_perm(sid, sid, SECCLASS_TUN_SOCKET, TUN_SOCKET__CREATE,
+ return avc_has_perm(&selinux_state,
+ sid, sid, SECCLASS_TUN_SOCKET, TUN_SOCKET__CREATE,
NULL);
}
@@ -5775,7 +5871,8 @@ static int selinux_tun_dev_attach_queue(void *security)
{
struct tun_security_struct *tunsec = selinux_tun_dev(security);
- return avc_has_perm(current_sid(), tunsec->sid, SECCLASS_TUN_SOCKET,
+ return avc_has_perm(&selinux_state,
+ current_sid(), tunsec->sid, SECCLASS_TUN_SOCKET,
TUN_SOCKET__ATTACH_QUEUE, NULL);
}
@@ -5803,11 +5900,13 @@ static int selinux_tun_dev_open(void *security)
u32 sid = current_sid();
int err;
- err = avc_has_perm(sid, tunsec->sid, SECCLASS_TUN_SOCKET,
+ err = avc_has_perm(&selinux_state,
+ sid, tunsec->sid, SECCLASS_TUN_SOCKET,
TUN_SOCKET__RELABELFROM, NULL);
if (err)
return err;
- err = avc_has_perm(sid, sid, SECCLASS_TUN_SOCKET,
+ err = avc_has_perm(&selinux_state,
+ sid, sid, SECCLASS_TUN_SOCKET,
TUN_SOCKET__RELABELTO, NULL);
if (err)
return err;
@@ -5858,7 +5957,8 @@ static unsigned int selinux_ip_forward(void *priv, struct sk_buff *skb,
}
if (secmark_active)
- if (avc_has_perm(peer_sid, skb->secmark,
+ if (avc_has_perm(&selinux_state,
+ peer_sid, skb->secmark,
SECCLASS_PACKET, PACKET__FORWARD_IN, &ad))
return NF_DROP;
@@ -5935,7 +6035,8 @@ static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
return NF_DROP;
if (selinux_secmark_enabled())
- if (avc_has_perm(sksec->sid, skb->secmark,
+ if (avc_has_perm(&selinux_state,
+ sksec->sid, skb->secmark,
SECCLASS_PACKET, PACKET__SEND, &ad))
return NF_DROP_ERR(-ECONNREFUSED);
@@ -6057,7 +6158,8 @@ static unsigned int selinux_ip_postroute(void *priv,
return NF_DROP;
if (secmark_active)
- if (avc_has_perm(peer_sid, skb->secmark,
+ if (avc_has_perm(&selinux_state,
+ peer_sid, skb->secmark,
SECCLASS_PACKET, secmark_perm, &ad))
return NF_DROP_ERR(-ECONNREFUSED);
@@ -6067,13 +6169,15 @@ static unsigned int selinux_ip_postroute(void *priv,
if (sel_netif_sid(state->net, ifindex, &if_sid))
return NF_DROP;
- if (avc_has_perm(peer_sid, if_sid,
+ if (avc_has_perm(&selinux_state,
+ peer_sid, if_sid,
SECCLASS_NETIF, NETIF__EGRESS, &ad))
return NF_DROP_ERR(-ECONNREFUSED);
if (sel_netnode_sid(addrp, family, &node_sid))
return NF_DROP;
- if (avc_has_perm(peer_sid, node_sid,
+ if (avc_has_perm(&selinux_state,
+ peer_sid, node_sid,
SECCLASS_NODE, NODE__SENDTO, &ad))
return NF_DROP_ERR(-ECONNREFUSED);
}
@@ -6098,8 +6202,9 @@ static int nlmsg_sock_has_extended_perms(struct sock *sk, u32 perms, u16 nlmsg_t
driver = nlmsg_type >> 8;
xperm = nlmsg_type & 0xff;
- return avc_has_extended_perms(current_sid(), sksec->sid, sksec->sclass,
- perms, driver, AVC_EXT_NLMSG, xperm, &ad);
+ return avc_has_extended_perms(&selinux_state, current_sid(),
+ sksec->sid, sksec->sclass, perms,
+ driver, AVC_EXT_NLMSG, xperm, &ad);
}
static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb)
@@ -6143,8 +6248,8 @@ static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb)
sk->sk_protocol, nlh->nlmsg_type,
secclass_map[sclass - 1].name,
task_pid_nr(current), current->comm);
- if (enforcing_enabled() &&
- !security_get_allow_unknown())
+ if (enforcing_enabled(&selinux_state) &&
+ !security_get_allow_unknown(&selinux_state))
return rc;
rc = 0;
} else if (rc == -ENOENT) {
@@ -6183,7 +6288,8 @@ static int ipc_has_perm(struct kern_ipc_perm *ipc_perms,
ad.type = LSM_AUDIT_DATA_IPC;
ad.u.ipc_id = ipc_perms->key;
- return avc_has_perm(sid, isec->sid, isec->sclass, perms, &ad);
+ return avc_has_perm(&selinux_state,
+ sid, isec->sid, isec->sclass, perms, &ad);
}
static int selinux_msg_msg_alloc_security(struct msg_msg *msg)
@@ -6209,7 +6315,8 @@ static int selinux_msg_queue_alloc_security(struct kern_ipc_perm *msq)
ad.type = LSM_AUDIT_DATA_IPC;
ad.u.ipc_id = msq->key;
- return avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
+ return avc_has_perm(&selinux_state,
+ sid, isec->sid, SECCLASS_MSGQ,
MSGQ__CREATE, &ad);
}
@@ -6224,7 +6331,8 @@ static int selinux_msg_queue_associate(struct kern_ipc_perm *msq, int msqflg)
ad.type = LSM_AUDIT_DATA_IPC;
ad.u.ipc_id = msq->key;
- return avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
+ return avc_has_perm(&selinux_state,
+ sid, isec->sid, SECCLASS_MSGQ,
MSGQ__ASSOCIATE, &ad);
}
@@ -6236,7 +6344,8 @@ static int selinux_msg_queue_msgctl(struct kern_ipc_perm *msq, int cmd)
case IPC_INFO:
case MSG_INFO:
/* No specific object, just general system-wide information. */
- return avc_has_perm(current_sid(), SECINITSID_KERNEL,
+ return avc_has_perm(&selinux_state,
+ current_sid(), SECINITSID_KERNEL,
SECCLASS_SYSTEM, SYSTEM__IPC_INFO, NULL);
case IPC_STAT:
case MSG_STAT:
@@ -6275,7 +6384,7 @@ static int selinux_msg_queue_msgsnd(struct kern_ipc_perm *msq, struct msg_msg *m
* Compute new sid based on current process and
* message queue this message will be stored in
*/
- rc = security_transition_sid(sid, isec->sid,
+ rc = security_transition_sid(&selinux_state, sid, isec->sid,
SECCLASS_MSG, NULL, &msec->sid);
if (rc)
return rc;
@@ -6285,15 +6394,18 @@ static int selinux_msg_queue_msgsnd(struct kern_ipc_perm *msq, struct msg_msg *m
ad.u.ipc_id = msq->key;
/* Can this process write to the queue? */
- rc = avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
+ rc = avc_has_perm(&selinux_state,
+ sid, isec->sid, SECCLASS_MSGQ,
MSGQ__WRITE, &ad);
if (!rc)
/* Can this process send the message */
- rc = avc_has_perm(sid, msec->sid, SECCLASS_MSG,
+ rc = avc_has_perm(&selinux_state,
+ sid, msec->sid, SECCLASS_MSG,
MSG__SEND, &ad);
if (!rc)
/* Can the message be put in the queue? */
- rc = avc_has_perm(msec->sid, isec->sid, SECCLASS_MSGQ,
+ rc = avc_has_perm(&selinux_state,
+ msec->sid, isec->sid, SECCLASS_MSGQ,
MSGQ__ENQUEUE, &ad);
return rc;
@@ -6315,10 +6427,12 @@ static int selinux_msg_queue_msgrcv(struct kern_ipc_perm *msq, struct msg_msg *m
ad.type = LSM_AUDIT_DATA_IPC;
ad.u.ipc_id = msq->key;
- rc = avc_has_perm(sid, isec->sid,
+ rc = avc_has_perm(&selinux_state,
+ sid, isec->sid,
SECCLASS_MSGQ, MSGQ__READ, &ad);
if (!rc)
- rc = avc_has_perm(sid, msec->sid,
+ rc = avc_has_perm(&selinux_state,
+ sid, msec->sid,
SECCLASS_MSG, MSG__RECEIVE, &ad);
return rc;
}
@@ -6336,7 +6450,8 @@ static int selinux_shm_alloc_security(struct kern_ipc_perm *shp)
ad.type = LSM_AUDIT_DATA_IPC;
ad.u.ipc_id = shp->key;
- return avc_has_perm(sid, isec->sid, SECCLASS_SHM,
+ return avc_has_perm(&selinux_state,
+ sid, isec->sid, SECCLASS_SHM,
SHM__CREATE, &ad);
}
@@ -6351,7 +6466,8 @@ static int selinux_shm_associate(struct kern_ipc_perm *shp, int shmflg)
ad.type = LSM_AUDIT_DATA_IPC;
ad.u.ipc_id = shp->key;
- return avc_has_perm(sid, isec->sid, SECCLASS_SHM,
+ return avc_has_perm(&selinux_state,
+ sid, isec->sid, SECCLASS_SHM,
SHM__ASSOCIATE, &ad);
}
@@ -6364,7 +6480,8 @@ static int selinux_shm_shmctl(struct kern_ipc_perm *shp, int cmd)
case IPC_INFO:
case SHM_INFO:
/* No specific object, just general system-wide information. */
- return avc_has_perm(current_sid(), SECINITSID_KERNEL,
+ return avc_has_perm(&selinux_state,
+ current_sid(), SECINITSID_KERNEL,
SECCLASS_SYSTEM, SYSTEM__IPC_INFO, NULL);
case IPC_STAT:
case SHM_STAT:
@@ -6414,7 +6531,8 @@ static int selinux_sem_alloc_security(struct kern_ipc_perm *sma)
ad.type = LSM_AUDIT_DATA_IPC;
ad.u.ipc_id = sma->key;
- return avc_has_perm(sid, isec->sid, SECCLASS_SEM,
+ return avc_has_perm(&selinux_state,
+ sid, isec->sid, SECCLASS_SEM,
SEM__CREATE, &ad);
}
@@ -6429,7 +6547,8 @@ static int selinux_sem_associate(struct kern_ipc_perm *sma, int semflg)
ad.type = LSM_AUDIT_DATA_IPC;
ad.u.ipc_id = sma->key;
- return avc_has_perm(sid, isec->sid, SECCLASS_SEM,
+ return avc_has_perm(&selinux_state,
+ sid, isec->sid, SECCLASS_SEM,
SEM__ASSOCIATE, &ad);
}
@@ -6443,7 +6562,8 @@ static int selinux_sem_semctl(struct kern_ipc_perm *sma, int cmd)
case IPC_INFO:
case SEM_INFO:
/* No specific object, just general system-wide information. */
- return avc_has_perm(current_sid(), SECINITSID_KERNEL,
+ return avc_has_perm(&selinux_state,
+ current_sid(), SECINITSID_KERNEL,
SECCLASS_SYSTEM, SYSTEM__IPC_INFO, NULL);
case GETPID:
case GETNCNT:
@@ -6530,7 +6650,8 @@ static int selinux_lsm_getattr(unsigned int attr, struct task_struct *p,
rcu_read_lock();
tsec = selinux_cred(__task_cred(p));
if (p != current) {
- error = avc_has_perm(current_sid(), tsec->sid,
+ error = avc_has_perm(&selinux_state,
+ current_sid(), tsec->sid,
SECCLASS_PROCESS, PROCESS__GETATTR, NULL);
if (error)
goto err_unlock;
@@ -6565,7 +6686,7 @@ static int selinux_lsm_getattr(unsigned int attr, struct task_struct *p,
return 0;
}
- error = security_sid_to_context(sid, value, &len);
+ error = security_sid_to_context(&selinux_state, sid, value, &len);
if (error)
return error;
return len;
@@ -6588,23 +6709,28 @@ static int selinux_lsm_setattr(u64 attr, void *value, size_t size)
*/
switch (attr) {
case LSM_ATTR_EXEC:
- error = avc_has_perm(mysid, mysid, SECCLASS_PROCESS,
+ error = avc_has_perm(&selinux_state,
+ mysid, mysid, SECCLASS_PROCESS,
PROCESS__SETEXEC, NULL);
break;
case LSM_ATTR_FSCREATE:
- error = avc_has_perm(mysid, mysid, SECCLASS_PROCESS,
+ error = avc_has_perm(&selinux_state,
+ mysid, mysid, SECCLASS_PROCESS,
PROCESS__SETFSCREATE, NULL);
break;
case LSM_ATTR_KEYCREATE:
- error = avc_has_perm(mysid, mysid, SECCLASS_PROCESS,
+ error = avc_has_perm(&selinux_state,
+ mysid, mysid, SECCLASS_PROCESS,
PROCESS__SETKEYCREATE, NULL);
break;
case LSM_ATTR_SOCKCREATE:
- error = avc_has_perm(mysid, mysid, SECCLASS_PROCESS,
+ error = avc_has_perm(&selinux_state,
+ mysid, mysid, SECCLASS_PROCESS,
PROCESS__SETSOCKCREATE, NULL);
break;
case LSM_ATTR_CURRENT:
- error = avc_has_perm(mysid, mysid, SECCLASS_PROCESS,
+ error = avc_has_perm(&selinux_state,
+ mysid, mysid, SECCLASS_PROCESS,
PROCESS__SETCURRENT, NULL);
break;
default:
@@ -6620,7 +6746,7 @@ static int selinux_lsm_setattr(u64 attr, void *value, size_t size)
str[size-1] = 0;
size--;
}
- error = security_context_to_sid(value, size,
+ error = security_context_to_sid(&selinux_state, value, size,
&sid, GFP_KERNEL);
if (error == -EINVAL && attr == LSM_ATTR_FSCREATE) {
if (!has_cap_mac_admin(true)) {
@@ -6646,8 +6772,9 @@ static int selinux_lsm_setattr(u64 attr, void *value, size_t size)
return error;
}
- error = security_context_to_sid_force(value, size,
- &sid);
+ error = security_context_to_sid_force(
+ &selinux_state,
+ value, size, &sid);
}
if (error)
return error;
@@ -6670,7 +6797,7 @@ static int selinux_lsm_setattr(u64 attr, void *value, size_t size)
tsec->create_sid = sid;
} else if (attr == LSM_ATTR_KEYCREATE) {
if (sid) {
- error = avc_has_perm(mysid, sid,
+ error = avc_has_perm(&selinux_state, mysid, sid,
SECCLASS_KEY, KEY__CREATE, NULL);
if (error)
goto abort_change;
@@ -6684,13 +6811,15 @@ static int selinux_lsm_setattr(u64 attr, void *value, size_t size)
goto abort_change;
if (!current_is_single_threaded()) {
- error = security_bounded_transition(tsec->sid, sid);
+ error = security_bounded_transition(&selinux_state,
+ tsec->sid, sid);
if (error)
goto abort_change;
}
/* Check permissions for the transition. */
- error = avc_has_perm(tsec->sid, sid, SECCLASS_PROCESS,
+ error = avc_has_perm(&selinux_state,
+ tsec->sid, sid, SECCLASS_PROCESS,
PROCESS__DYNTRANSITION, NULL);
if (error)
goto abort_change;
@@ -6699,7 +6828,8 @@ static int selinux_lsm_setattr(u64 attr, void *value, size_t size)
Otherwise, leave SID unchanged and fail. */
ptsid = ptrace_parent_sid();
if (ptsid != 0) {
- error = avc_has_perm(ptsid, sid, SECCLASS_PROCESS,
+ error = avc_has_perm(&selinux_state,
+ ptsid, sid, SECCLASS_PROCESS,
PROCESS__PTRACE, NULL);
if (error)
goto abort_change;
@@ -6794,12 +6924,13 @@ static int selinux_secid_to_secctx(u32 secid, struct lsm_context *cp)
if (cp) {
cp->id = LSM_ID_SELINUX;
- ret = security_sid_to_context(secid, &cp->context, &cp->len);
+ ret = security_sid_to_context(&selinux_state, secid,
+ &cp->context, &cp->len);
if (ret < 0)
return ret;
return cp->len;
}
- ret = security_sid_to_context(secid, NULL, &seclen);
+ ret = security_sid_to_context(&selinux_state, secid, NULL, &seclen);
if (ret < 0)
return ret;
return seclen;
@@ -6813,7 +6944,7 @@ static int selinux_lsmprop_to_secctx(struct lsm_prop *prop,
static int selinux_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
{
- return security_context_to_sid(secdata, seclen,
+ return security_context_to_sid(&selinux_state, secdata, seclen,
secid, GFP_KERNEL);
}
@@ -6926,7 +7057,8 @@ static int selinux_key_permission(key_ref_t key_ref,
key = key_ref_to_ptr(key_ref);
ksec = selinux_key(key);
- return avc_has_perm(sid, ksec->sid, SECCLASS_KEY, perm, NULL);
+ return avc_has_perm(&selinux_state,
+ sid, ksec->sid, SECCLASS_KEY, perm, NULL);
}
static int selinux_key_getsecurity(struct key *key, char **_buffer)
@@ -6936,7 +7068,7 @@ static int selinux_key_getsecurity(struct key *key, char **_buffer)
unsigned len;
int rc;
- rc = security_sid_to_context(ksec->sid,
+ rc = security_sid_to_context(&selinux_state, ksec->sid,
&context, &len);
if (!rc)
rc = len;
@@ -6950,7 +7082,8 @@ static int selinux_watch_key(struct key *key)
struct key_security_struct *ksec = selinux_key(key);
u32 sid = current_sid();
- return avc_has_perm(sid, ksec->sid, SECCLASS_KEY, KEY__VIEW, NULL);
+ return avc_has_perm(&selinux_state,
+ sid, ksec->sid, SECCLASS_KEY, KEY__VIEW, NULL);
}
#endif
#endif
@@ -6972,7 +7105,8 @@ static int selinux_ib_pkey_access(void *ib_sec, u64 subnet_prefix, u16 pkey_val)
ibpkey.subnet_prefix = subnet_prefix;
ibpkey.pkey = pkey_val;
ad.u.ibpkey = &ibpkey;
- return avc_has_perm(sec->sid, sid,
+ return avc_has_perm(&selinux_state,
+ sec->sid, sid,
SECCLASS_INFINIBAND_PKEY,
INFINIBAND_PKEY__ACCESS, &ad);
}
@@ -6986,7 +7120,7 @@ static int selinux_ib_endport_manage_subnet(void *ib_sec, const char *dev_name,
struct ib_security_struct *sec = ib_sec;
struct lsm_ibendport_audit ibendport;
- err = security_ib_endport_sid(dev_name, port_num,
+ err = security_ib_endport_sid(&selinux_state, dev_name, port_num,
&sid);
if (err)
@@ -6996,7 +7130,8 @@ static int selinux_ib_endport_manage_subnet(void *ib_sec, const char *dev_name,
ibendport.dev_name = dev_name;
ibendport.port = port_num;
ad.u.ibendport = &ibendport;
- return avc_has_perm(sec->sid, sid,
+ return avc_has_perm(&selinux_state,
+ sec->sid, sid,
SECCLASS_INFINIBAND_ENDPORT,
INFINIBAND_ENDPORT__MANAGE_SUBNET, &ad);
}
@@ -7019,11 +7154,13 @@ static int selinux_bpf(int cmd, union bpf_attr *attr,
switch (cmd) {
case BPF_MAP_CREATE:
- ret = avc_has_perm(sid, sid, SECCLASS_BPF, BPF__MAP_CREATE,
+ ret = avc_has_perm(&selinux_state,
+ sid, sid, SECCLASS_BPF, BPF__MAP_CREATE,
NULL);
break;
case BPF_PROG_LOAD:
- ret = avc_has_perm(sid, sid, SECCLASS_BPF, BPF__PROG_LOAD,
+ ret = avc_has_perm(&selinux_state,
+ sid, sid, SECCLASS_BPF, BPF__PROG_LOAD,
NULL);
break;
default:
@@ -7063,14 +7200,16 @@ static int bpf_fd_pass(const struct file *file, u32 sid)
if (file->f_op == &bpf_map_fops) {
map = file->private_data;
bpfsec = map->security;
- ret = avc_has_perm(sid, bpfsec->sid, SECCLASS_BPF,
+ ret = avc_has_perm(&selinux_state,
+ sid, bpfsec->sid, SECCLASS_BPF,
bpf_map_fmode_to_av(file->f_mode), NULL);
if (ret)
return ret;
} else if (file->f_op == &bpf_prog_fops) {
prog = file->private_data;
bpfsec = prog->aux->security;
- ret = avc_has_perm(sid, bpfsec->sid, SECCLASS_BPF,
+ ret = avc_has_perm(&selinux_state,
+ sid, bpfsec->sid, SECCLASS_BPF,
BPF__PROG_RUN, NULL);
if (ret)
return ret;
@@ -7084,7 +7223,8 @@ static int selinux_bpf_map(struct bpf_map *map, fmode_t fmode)
struct bpf_security_struct *bpfsec;
bpfsec = map->security;
- return avc_has_perm(sid, bpfsec->sid, SECCLASS_BPF,
+ return avc_has_perm(&selinux_state,
+ sid, bpfsec->sid, SECCLASS_BPF,
bpf_map_fmode_to_av(fmode), NULL);
}
@@ -7094,7 +7234,8 @@ static int selinux_bpf_prog(struct bpf_prog *prog)
struct bpf_security_struct *bpfsec;
bpfsec = prog->aux->security;
- return avc_has_perm(sid, bpfsec->sid, SECCLASS_BPF,
+ return avc_has_perm(&selinux_state,
+ sid, bpfsec->sid, SECCLASS_BPF,
BPF__PROG_RUN, NULL);
}
@@ -7201,7 +7342,7 @@ static int selinux_perf_event_open(int type)
else
return -EINVAL;
- return avc_has_perm(sid, sid, SECCLASS_PERF_EVENT,
+ return avc_has_perm(&selinux_state, sid, sid, SECCLASS_PERF_EVENT,
requested, NULL);
}
@@ -7220,7 +7361,7 @@ static int selinux_perf_event_read(struct perf_event *event)
struct perf_event_security_struct *perfsec = event->security;
u32 sid = current_sid();
- return avc_has_perm(sid, perfsec->sid,
+ return avc_has_perm(&selinux_state, sid, perfsec->sid,
SECCLASS_PERF_EVENT, PERF_EVENT__READ, NULL);
}
@@ -7229,7 +7370,7 @@ static int selinux_perf_event_write(struct perf_event *event)
struct perf_event_security_struct *perfsec = event->security;
u32 sid = current_sid();
- return avc_has_perm(sid, perfsec->sid,
+ return avc_has_perm(&selinux_state, sid, perfsec->sid,
SECCLASS_PERF_EVENT, PERF_EVENT__WRITE, NULL);
}
#endif
@@ -7244,7 +7385,7 @@ static int selinux_perf_event_write(struct perf_event *event)
*/
static int selinux_uring_override_creds(const struct cred *new)
{
- return avc_has_perm(current_sid(), cred_sid(new),
+ return avc_has_perm(&selinux_state, current_sid(), cred_sid(new),
SECCLASS_IO_URING, IO_URING__OVERRIDE_CREDS, NULL);
}
@@ -7258,7 +7399,7 @@ static int selinux_uring_sqpoll(void)
{
u32 sid = current_sid();
- return avc_has_perm(sid, sid,
+ return avc_has_perm(&selinux_state, sid, sid,
SECCLASS_IO_URING, IO_URING__SQPOLL, NULL);
}
@@ -7280,7 +7421,7 @@ static int selinux_uring_cmd(struct io_uring_cmd *ioucmd)
ad.type = LSM_AUDIT_DATA_FILE;
ad.u.file = file;
- return avc_has_perm(current_sid(), isec->sid,
+ return avc_has_perm(&selinux_state, current_sid(), isec->sid,
SECCLASS_IO_URING, IO_URING__CMD, &ad);
}
@@ -7293,8 +7434,8 @@ static int selinux_uring_allowed(void)
{
u32 sid = current_sid();
- return avc_has_perm(sid, sid, SECCLASS_IO_URING, IO_URING__ALLOWED,
- NULL);
+ return avc_has_perm(&selinux_state, sid, sid, SECCLASS_IO_URING,
+ IO_URING__ALLOWED, NULL);
}
#endif /* CONFIG_IO_URING */
@@ -7610,8 +7751,8 @@ static __init int selinux_init(void)
pr_info("SELinux: Initializing.\n");
memset(&selinux_state, 0, sizeof(selinux_state));
- enforcing_set(selinux_enforcing_boot);
- selinux_avc_init();
+ enforcing_set(&selinux_state, selinux_enforcing_boot);
+ selinux_avc_init(&selinux_state.avc);
mutex_init(&selinux_state.status_lock);
mutex_init(&selinux_state.policy_mutex);
diff --git a/security/selinux/ibpkey.c b/security/selinux/ibpkey.c
index 470481cfe0e8..7406706582f5 100644
--- a/security/selinux/ibpkey.c
+++ b/security/selinux/ibpkey.c
@@ -141,7 +141,7 @@ static int sel_ib_pkey_sid_slow(u64 subnet_prefix, u16 pkey_num, u32 *sid)
return 0;
}
- ret = security_ib_pkey_sid(subnet_prefix, pkey_num,
+ ret = security_ib_pkey_sid(&selinux_state, subnet_prefix, pkey_num,
sid);
if (ret)
goto out;
diff --git a/security/selinux/ima.c b/security/selinux/ima.c
index aa34da9b0aeb..08f89f212422 100644
--- a/security/selinux/ima.c
+++ b/security/selinux/ima.c
@@ -15,10 +15,12 @@
/*
* selinux_ima_collect_state - Read selinux configuration settings
*
+ * @state: selinux_state
+ *
* On success returns the configuration settings string.
* On error, returns NULL.
*/
-static char *selinux_ima_collect_state(void)
+static char *selinux_ima_collect_state(struct selinux_state *state)
{
const char *on = "=1;", *off = "=0;";
char *buf;
@@ -37,27 +39,26 @@ static char *selinux_ima_collect_state(void)
rc = strscpy(buf, "initialized", buf_len);
WARN_ON(rc < 0);
- rc = strlcat(buf, selinux_initialized() ? on : off, buf_len);
+ rc = strlcat(buf, selinux_initialized(state) ? on : off, buf_len);
WARN_ON(rc >= buf_len);
rc = strlcat(buf, "enforcing", buf_len);
WARN_ON(rc >= buf_len);
- rc = strlcat(buf, enforcing_enabled() ? on : off, buf_len);
+ rc = strlcat(buf, enforcing_enabled(state) ? on : off, buf_len);
WARN_ON(rc >= buf_len);
rc = strlcat(buf, "checkreqprot", buf_len);
WARN_ON(rc >= buf_len);
- rc = strlcat(buf, checkreqprot_get() ? on : off, buf_len);
+ rc = strlcat(buf, checkreqprot_get(state) ? on : off, buf_len);
WARN_ON(rc >= buf_len);
for (i = 0; i < __POLICYDB_CAP_MAX; i++) {
rc = strlcat(buf, selinux_policycap_names[i], buf_len);
WARN_ON(rc >= buf_len);
- rc = strlcat(buf, selinux_state.policycap[i] ? on : off,
- buf_len);
+ rc = strlcat(buf, state->policycap[i] ? on : off, buf_len);
WARN_ON(rc >= buf_len);
}
@@ -66,17 +67,19 @@ static char *selinux_ima_collect_state(void)
/*
* selinux_ima_measure_state_locked - Measure SELinux state and hash of policy
+ *
+ * @state: selinux state struct
*/
-void selinux_ima_measure_state_locked(void)
+void selinux_ima_measure_state_locked(struct selinux_state *state)
{
char *state_str = NULL;
void *policy = NULL;
size_t policy_len;
int rc = 0;
- lockdep_assert_held(&selinux_state.policy_mutex);
+ lockdep_assert_held(&state->policy_mutex);
- state_str = selinux_ima_collect_state();
+ state_str = selinux_ima_collect_state(state);
if (!state_str) {
pr_err("SELinux: %s: failed to read state.\n", __func__);
return;
@@ -91,10 +94,10 @@ void selinux_ima_measure_state_locked(void)
/*
* Measure SELinux policy only after initialization is completed.
*/
- if (!selinux_initialized())
+ if (!selinux_initialized(state))
return;
- rc = security_read_state_kernel(&policy, &policy_len);
+ rc = security_read_state_kernel(state, &policy, &policy_len);
if (rc) {
pr_err("SELinux: %s: failed to read policy %d.\n", __func__, rc);
return;
@@ -109,12 +112,14 @@ void selinux_ima_measure_state_locked(void)
/*
* selinux_ima_measure_state - Measure SELinux state and hash of policy
+ *
+ * @state: selinux state struct
*/
-void selinux_ima_measure_state(void)
+void selinux_ima_measure_state(struct selinux_state *state)
{
- lockdep_assert_not_held(&selinux_state.policy_mutex);
+ lockdep_assert_not_held(&state->policy_mutex);
- mutex_lock(&selinux_state.policy_mutex);
- selinux_ima_measure_state_locked();
- mutex_unlock(&selinux_state.policy_mutex);
+ mutex_lock(&state->policy_mutex);
+ selinux_ima_measure_state_locked(state);
+ mutex_unlock(&state->policy_mutex);
}
diff --git a/security/selinux/include/avc.h b/security/selinux/include/avc.h
index 01b5167fee1a..f6a500e9d74d 100644
--- a/security/selinux/include/avc.h
+++ b/security/selinux/include/avc.h
@@ -53,6 +53,7 @@ struct selinux_audit_data {
u32 audited;
u32 denied;
int result;
+ struct selinux_state *state;
} __randomize_layout;
/*
@@ -98,11 +99,13 @@ static inline u32 avc_audit_required(u32 requested, struct av_decision *avd,
return audited;
}
-int slow_avc_audit(u32 ssid, u32 tsid, u16 tclass, u32 requested, u32 audited,
- u32 denied, int result, struct common_audit_data *a);
+int slow_avc_audit(struct selinux_state *state, u32 ssid, u32 tsid, u16 tclass,
+ u32 requested, u32 audited, u32 denied, int result,
+ struct common_audit_data *a);
/**
* avc_audit - Audit the granting or denial of permissions.
+ * @state: SELinux state
* @ssid: source security identifier
* @tsid: target security identifier
* @tclass: target security class
@@ -120,33 +123,34 @@ int slow_avc_audit(u32 ssid, u32 tsid, u16 tclass, u32 requested, u32 audited,
* be performed under a lock, to allow the lock to be released
* before calling the auditing code.
*/
-static inline int avc_audit(u32 ssid, u32 tsid, u16 tclass, u32 requested,
- struct av_decision *avd, int result,
- struct common_audit_data *a)
+static inline int avc_audit(struct selinux_state *state, u32 ssid, u32 tsid,
+ u16 tclass, u32 requested, struct av_decision *avd,
+ int result, struct common_audit_data *a)
{
u32 audited, denied;
audited = avc_audit_required(requested, avd, result, 0, &denied);
if (likely(!audited))
return 0;
- return slow_avc_audit(ssid, tsid, tclass, requested, audited, denied,
- result, a);
+ return slow_avc_audit(state, ssid, tsid, tclass, requested, audited,
+ denied, result, a);
}
#define AVC_STRICT 1 /* Ignore permissive mode. */
#define AVC_EXTENDED_PERMS 2 /* update extended permissions */
-int avc_has_perm_noaudit(u32 ssid, u32 tsid, u16 tclass, u32 requested,
- unsigned int flags, struct av_decision *avd);
+int avc_has_perm_noaudit(struct selinux_state *state, u32 ssid, u32 tsid,
+ u16 tclass, u32 requested, unsigned int flags,
+ struct av_decision *avd);
-int avc_has_perm(u32 ssid, u32 tsid, u16 tclass, u32 requested,
- struct common_audit_data *auditdata);
+int avc_has_perm(struct selinux_state *state, u32 ssid, u32 tsid, u16 tclass,
+ u32 requested, struct common_audit_data *auditdata);
#define AVC_EXT_IOCTL (1 << 0) /* Cache entry for an ioctl extended permission */
#define AVC_EXT_NLMSG (1 << 1) /* Cache entry for an nlmsg extended permission */
-int avc_has_extended_perms(u32 ssid, u32 tsid, u16 tclass, u32 requested,
- u8 driver, u8 base_perm, u8 perm,
- struct common_audit_data *ad);
+int avc_has_extended_perms(struct selinux_state *state, u32 ssid, u32 tsid,
+ u16 tclass, u32 requested, u8 driver, u8 base_perm,
+ u8 perm, struct common_audit_data *ad);
-u32 avc_policy_seqno(void);
+u32 avc_policy_seqno(struct selinux_state *state);
#define AVC_CALLBACK_GRANT 1
#define AVC_CALLBACK_TRY_REVOKE 2
@@ -161,9 +165,11 @@ u32 avc_policy_seqno(void);
int avc_add_callback(int (*callback)(u32 event), u32 events);
/* Exported to selinuxfs */
-int avc_get_hash_stats(char *page);
-unsigned int avc_get_cache_threshold(void);
-void avc_set_cache_threshold(unsigned int cache_threshold);
+struct selinux_avc;
+int avc_get_hash_stats(struct selinux_avc *avc, char *page);
+unsigned int avc_get_cache_threshold(struct selinux_avc *avc);
+void avc_set_cache_threshold(struct selinux_avc *avc,
+ unsigned int cache_threshold);
#ifdef CONFIG_SECURITY_SELINUX_AVC_STATS
DECLARE_PER_CPU(struct avc_cache_stats, avc_cache_stats);
diff --git a/security/selinux/include/avc_ss.h b/security/selinux/include/avc_ss.h
index 48ad64d54032..4dc2ddd0de7d 100644
--- a/security/selinux/include/avc_ss.h
+++ b/security/selinux/include/avc_ss.h
@@ -10,7 +10,8 @@
#include <linux/types.h>
-int avc_ss_reset(u32 seqno);
+struct selinux_avc;
+int avc_ss_reset(struct selinux_avc *avc, u32 seqno);
/* Class/perm mapping support */
struct security_class_mapping {
diff --git a/security/selinux/include/conditional.h b/security/selinux/include/conditional.h
index 060833e2dba2..5e59ef056726 100644
--- a/security/selinux/include/conditional.h
+++ b/security/selinux/include/conditional.h
@@ -16,8 +16,8 @@
int security_get_bools(struct selinux_policy *policy, u32 *len, char ***names,
int **values);
-int security_set_bools(u32 len, const int *values);
+int security_set_bools(struct selinux_state *state, u32 len, const int *values);
-int security_get_bool_value(u32 index);
+int security_get_bool_value(struct selinux_state *state, u32 index);
#endif
diff --git a/security/selinux/include/ima.h b/security/selinux/include/ima.h
index 38ab302f5946..37c7394de893 100644
--- a/security/selinux/include/ima.h
+++ b/security/selinux/include/ima.h
@@ -14,13 +14,16 @@
#include "security.h"
#ifdef CONFIG_IMA
-extern void selinux_ima_measure_state(void);
-extern void selinux_ima_measure_state_locked(void);
+extern void selinux_ima_measure_state(struct selinux_state *selinux_state);
+extern void
+selinux_ima_measure_state_locked(struct selinux_state *selinux_state);
#else
-static inline void selinux_ima_measure_state(void)
+static inline void
+selinux_ima_measure_state(struct selinux_state *selinux_state)
{
}
-static inline void selinux_ima_measure_state_locked(void)
+static inline void
+selinux_ima_measure_state_locked(struct selinux_state *selinux_state)
{
}
#endif
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h
index 1d7ac59015a1..55fe076cd609 100644
--- a/security/selinux/include/objsec.h
+++ b/security/selinux/include/objsec.h
@@ -57,7 +57,7 @@ static inline bool task_avdcache_permnoaudit(struct task_security_struct *tsec)
{
return (tsec->avdcache.permissive_neveraudit &&
tsec->sid == tsec->avdcache.sid &&
- tsec->avdcache.seqno == avc_policy_seqno());
+ tsec->avdcache.seqno == avc_policy_seqno(&selinux_state));
}
enum label_initialized {
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
index 7f19972f7922..a1e2d5e0da50 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -89,6 +89,7 @@ extern int selinux_enabled_boot;
/* limitation of boundary depth */
#define POLICYDB_BOUNDS_MAXDEPTH 4
+struct selinux_avc;
struct selinux_policy;
struct selinux_state {
@@ -101,48 +102,49 @@ struct selinux_state {
struct page *status_page;
struct mutex status_lock;
+ struct selinux_avc *avc;
struct selinux_policy __rcu *policy;
struct mutex policy_mutex;
} __randomize_layout;
-void selinux_avc_init(void);
+void selinux_avc_init(struct selinux_avc **avc);
extern struct selinux_state selinux_state;
-static inline bool selinux_initialized(void)
+static inline bool selinux_initialized(const struct selinux_state *state)
{
/* do a synchronized load to avoid race conditions */
- return smp_load_acquire(&selinux_state.initialized);
+ return smp_load_acquire(&state->initialized);
}
-static inline void selinux_mark_initialized(void)
+static inline void selinux_mark_initialized(struct selinux_state *state)
{
/* do a synchronized write to avoid race conditions */
- smp_store_release(&selinux_state.initialized, true);
+ smp_store_release(&state->initialized, true);
}
#ifdef CONFIG_SECURITY_SELINUX_DEVELOP
-static inline bool enforcing_enabled(void)
+static inline bool enforcing_enabled(struct selinux_state *state)
{
- return READ_ONCE(selinux_state.enforcing);
+ return READ_ONCE(state->enforcing);
}
-static inline void enforcing_set(bool value)
+static inline void enforcing_set(struct selinux_state *state, bool value)
{
- WRITE_ONCE(selinux_state.enforcing, value);
+ WRITE_ONCE(state->enforcing, value);
}
#else
-static inline bool enforcing_enabled(void)
+static inline bool enforcing_enabled(struct selinux_state *state)
{
return true;
}
-static inline void enforcing_set(bool value)
+static inline void enforcing_set(struct selinux_state *state, bool value)
{
}
#endif
-static inline bool checkreqprot_get(void)
+static inline bool checkreqprot_get(const struct selinux_state *state)
{
/* non-zero/true checkreqprot values are no longer supported */
return 0;
@@ -199,8 +201,7 @@ static inline bool selinux_policycap_userspace_initial_context(void)
static inline bool selinux_policycap_netlink_xperm(void)
{
- return READ_ONCE(
- selinux_state.policycap[POLICYDB_CAP_NETLINK_XPERM]);
+ return READ_ONCE(selinux_state.policycap[POLICYDB_CAP_NETLINK_XPERM]);
}
struct selinux_policy_convert_data;
@@ -210,14 +211,18 @@ struct selinux_load_state {
struct selinux_policy_convert_data *convert_data;
};
-int security_mls_enabled(void);
-int security_load_policy(void *data, size_t len,
+int security_mls_enabled(struct selinux_state *state);
+int security_load_policy(struct selinux_state *state, void *data, size_t len,
struct selinux_load_state *load_state);
-void selinux_policy_commit(struct selinux_load_state *load_state);
-void selinux_policy_cancel(struct selinux_load_state *load_state);
-int security_read_policy(void **data, size_t *len);
-int security_read_state_kernel(void **data, size_t *len);
-int security_policycap_supported(unsigned int req_cap);
+void selinux_policy_commit(struct selinux_state *state,
+ struct selinux_load_state *load_state);
+void selinux_policy_cancel(struct selinux_state *state,
+ struct selinux_load_state *load_state);
+int security_read_policy(struct selinux_state *state, void **data, size_t *len);
+int security_read_state_kernel(struct selinux_state *state, void **data,
+ size_t *len);
+int security_policycap_supported(struct selinux_state *state,
+ unsigned int req_cap);
#define SEL_VEC_MAX 32
struct av_decision {
@@ -257,75 +262,93 @@ struct extended_perms {
#define AVD_FLAGS_PERMISSIVE 0x0001
#define AVD_FLAGS_NEVERAUDIT 0x0002
-void security_compute_av(u32 ssid, u32 tsid, u16 tclass,
- struct av_decision *avd,
+void security_compute_av(struct selinux_state *state, u32 ssid, u32 tsid,
+ u16 tclass, struct av_decision *avd,
struct extended_perms *xperms);
-void security_compute_xperms_decision(u32 ssid, u32 tsid, u16 tclass, u8 driver,
+void security_compute_xperms_decision(struct selinux_state *state, u32 ssid,
+ u32 tsid, u16 tclass, u8 driver,
u8 base_perm,
struct extended_perms_decision *xpermd);
-void security_compute_av_user(u32 ssid, u32 tsid, u16 tclass,
- struct av_decision *avd);
+void security_compute_av_user(struct selinux_state *state, u32 ssid, u32 tsid,
+ u16 tclass, struct av_decision *avd);
-int security_transition_sid(u32 ssid, u32 tsid, u16 tclass,
- const struct qstr *qstr, u32 *out_sid);
+int security_transition_sid(struct selinux_state *state, u32 ssid, u32 tsid,
+ u16 tclass, const struct qstr *qstr, u32 *out_sid);
-int security_transition_sid_user(u32 ssid, u32 tsid, u16 tclass,
- const char *objname, u32 *out_sid);
+int security_transition_sid_user(struct selinux_state *state, u32 ssid,
+ u32 tsid, u16 tclass, const char *objname,
+ u32 *out_sid);
-int security_member_sid(u32 ssid, u32 tsid, u16 tclass, u32 *out_sid);
+int security_member_sid(struct selinux_state *state, u32 ssid, u32 tsid,
+ u16 tclass, u32 *out_sid);
-int security_change_sid(u32 ssid, u32 tsid, u16 tclass, u32 *out_sid);
+int security_change_sid(struct selinux_state *state, u32 ssid, u32 tsid,
+ u16 tclass, u32 *out_sid);
-int security_sid_to_context(u32 sid, char **scontext, u32 *scontext_len);
+int security_sid_to_context(struct selinux_state *state, u32 sid,
+ char **scontext, u32 *scontext_len);
-int security_sid_to_context_force(u32 sid, char **scontext, u32 *scontext_len);
+int security_sid_to_context_force(struct selinux_state *state, u32 sid,
+ char **scontext, u32 *scontext_len);
-int security_sid_to_context_inval(u32 sid, char **scontext, u32 *scontext_len);
+int security_sid_to_context_inval(struct selinux_state *state, u32 sid,
+ char **scontext, u32 *scontext_len);
-int security_context_to_sid(const char *scontext, u32 scontext_len,
- u32 *out_sid, gfp_t gfp);
+int security_context_to_sid(struct selinux_state *state, const char *scontext,
+ u32 scontext_len, u32 *out_sid, gfp_t gfp);
-int security_context_str_to_sid(const char *scontext, u32 *out_sid, gfp_t gfp);
+int security_context_str_to_sid(struct selinux_state *state,
+ const char *scontext, u32 *out_sid, gfp_t gfp);
-int security_context_to_sid_default(const char *scontext, u32 scontext_len,
+int security_context_to_sid_default(struct selinux_state *state,
+ const char *scontext, u32 scontext_len,
u32 *out_sid, u32 def_sid, gfp_t gfp_flags);
-int security_context_to_sid_force(const char *scontext, u32 scontext_len,
+int security_context_to_sid_force(struct selinux_state *state,
+ const char *scontext, u32 scontext_len,
u32 *sid);
-int security_get_user_sids(u32 fromsid, const char *username, u32 **sids, u32 *nel);
+int security_get_user_sids(struct selinux_state *state, u32 callsid,
+ const char *username, u32 **sids, u32 *nel);
-int security_port_sid(u8 protocol, u16 port, u32 *out_sid);
+int security_port_sid(struct selinux_state *state, u8 protocol, u16 port,
+ u32 *out_sid);
-int security_ib_pkey_sid(u64 subnet_prefix, u16 pkey_num, u32 *out_sid);
+int security_ib_pkey_sid(struct selinux_state *state, 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_ib_endport_sid(struct selinux_state *state, const char *dev_name,
+ u8 port_num, u32 *out_sid);
-int security_netif_sid(const char *name, u32 *if_sid);
+int security_netif_sid(struct selinux_state *state, const char *name,
+ u32 *if_sid);
-int security_node_sid(u16 domain, const void *addr, u32 addrlen, u32 *out_sid);
+int security_node_sid(struct selinux_state *state, u16 domain, const void *addr,
+ u32 addrlen, u32 *out_sid);
-int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid,
- u16 tclass);
+int security_validate_transition(struct selinux_state *state, u32 oldsid,
+ u32 newsid, u32 tasksid, u16 tclass);
-int security_validate_transition_user(u32 oldsid, u32 newsid, u32 tasksid,
- u16 tclass);
+int security_validate_transition_user(struct selinux_state *state, u32 oldsid,
+ u32 newsid, u32 tasksid, u16 tclass);
-int security_bounded_transition(u32 old_sid, u32 new_sid);
+int security_bounded_transition(struct selinux_state *state, u32 old_sid,
+ u32 new_sid);
-int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid);
+int security_sid_mls_copy(struct selinux_state *state, u32 sid, u32 mls_sid,
+ u32 *new_sid);
-int security_net_peersid_resolve(u32 nlbl_sid, u32 nlbl_type, u32 xfrm_sid,
- u32 *peer_sid);
+int security_net_peersid_resolve(struct selinux_state *state, u32 nlbl_sid,
+ u32 nlbl_type, u32 xfrm_sid, u32 *peer_sid);
int security_get_classes(struct selinux_policy *policy, char ***classes,
u32 *nclasses);
int security_get_permissions(struct selinux_policy *policy, const char *class,
char ***perms, u32 *nperms);
-int security_get_reject_unknown(void);
-int security_get_allow_unknown(void);
+int security_get_reject_unknown(struct selinux_state *state);
+int security_get_allow_unknown(struct selinux_state *state);
#define SECURITY_FS_USE_XATTR 1 /* use xattr */
#define SECURITY_FS_USE_TRANS 2 /* use transition SIDs, e.g. devpts/tmpfs */
@@ -336,28 +359,32 @@ int security_get_allow_unknown(void);
#define SECURITY_FS_USE_NATIVE 7 /* use native label support */
#define SECURITY_FS_USE_MAX 7 /* Highest SECURITY_FS_USE_XXX */
-int security_fs_use(struct super_block *sb);
+int security_fs_use(struct selinux_state *state, struct super_block *sb);
-int security_genfs_sid(const char *fstype, const char *path, u16 sclass,
- u32 *sid);
+int security_genfs_sid(struct selinux_state *state, const char *fstype,
+ const char *path, u16 sclass, u32 *sid);
int selinux_policy_genfs_sid(struct selinux_policy *policy, const char *fstype,
const char *path, u16 sclass, u32 *sid);
#ifdef CONFIG_NETLABEL
-int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr,
+int security_netlbl_secattr_to_sid(struct selinux_state *state,
+ struct netlbl_lsm_secattr *secattr,
u32 *sid);
-int security_netlbl_sid_to_secattr(u32 sid, struct netlbl_lsm_secattr *secattr);
+int security_netlbl_sid_to_secattr(struct selinux_state *state, u32 sid,
+ struct netlbl_lsm_secattr *secattr);
#else
static inline int
-security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr, u32 *sid)
+security_netlbl_secattr_to_sid(struct selinux_state *state,
+ struct netlbl_lsm_secattr *secattr, u32 *sid)
{
return -EIDRM;
}
static inline int
-security_netlbl_sid_to_secattr(u32 sid, struct netlbl_lsm_secattr *secattr)
+security_netlbl_sid_to_secattr(struct selinux_state *state, u32 sid,
+ struct netlbl_lsm_secattr *secattr)
{
return -ENOENT;
}
@@ -368,7 +395,7 @@ const char *security_get_initial_sid_context(u32 sid);
/*
* status notifier using mmap interface
*/
-extern struct page *selinux_kernel_status_page(void);
+extern struct page *selinux_kernel_status_page(struct selinux_state *state);
#define SELINUX_KERNEL_STATUS_VERSION 1
struct selinux_kernel_status {
@@ -382,8 +409,10 @@ struct selinux_kernel_status {
*/
} __packed;
-extern void selinux_status_update_setenforce(bool enforcing);
-extern void selinux_status_update_policyload(u32 seqno);
+extern void selinux_status_update_setenforce(struct selinux_state *state,
+ bool enforcing);
+extern void selinux_status_update_policyload(struct selinux_state *state,
+ u32 seqno);
extern void selinux_complete_init(void);
extern struct path selinux_null;
extern void selnl_notify_setenforce(int val);
@@ -393,6 +422,6 @@ extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm);
extern void avtab_cache_init(void);
extern void ebitmap_cache_init(void);
extern void hashtab_cache_init(void);
-extern int security_sidtab_hash_stats(char *page);
+extern int security_sidtab_hash_stats(struct selinux_state *state, char *page);
#endif /* _SELINUX_SECURITY_H_ */
diff --git a/security/selinux/netif.c b/security/selinux/netif.c
index 78afbecdbe57..52718a78f06c 100644
--- a/security/selinux/netif.c
+++ b/security/selinux/netif.c
@@ -153,7 +153,7 @@ static int sel_netif_sid_slow(struct net *ns, int ifindex, u32 *sid)
goto out;
}
- ret = security_netif_sid(dev->name, sid);
+ ret = security_netif_sid(&selinux_state, dev->name, sid);
if (ret != 0)
goto out;
diff --git a/security/selinux/netlabel.c b/security/selinux/netlabel.c
index d51dfe892312..b858b46fd4b4 100644
--- a/security/selinux/netlabel.c
+++ b/security/selinux/netlabel.c
@@ -47,7 +47,7 @@ static int selinux_netlbl_sidlookup_cached(struct sk_buff *skb,
{
int rc;
- rc = security_netlbl_secattr_to_sid(secattr, sid);
+ rc = security_netlbl_secattr_to_sid(&selinux_state, secattr, sid);
if (rc == 0 &&
(secattr->flags & NETLBL_SECATTR_CACHEABLE) &&
(secattr->flags & NETLBL_SECATTR_CACHE))
@@ -79,7 +79,8 @@ static struct netlbl_lsm_secattr *selinux_netlbl_sock_genattr(struct sock *sk)
if (secattr == NULL)
return ERR_PTR(-ENOMEM);
- rc = security_netlbl_sid_to_secattr(sksec->sid, secattr);
+ rc = security_netlbl_sid_to_secattr(&selinux_state, sksec->sid,
+ secattr);
if (rc != 0) {
netlbl_secattr_free(secattr);
return ERR_PTR(rc);
@@ -251,7 +252,8 @@ int selinux_netlbl_skbuff_setsid(struct sk_buff *skb,
if (secattr == NULL) {
secattr = &secattr_storage;
netlbl_secattr_init(secattr);
- rc = security_netlbl_sid_to_secattr(sid, secattr);
+ rc = security_netlbl_sid_to_secattr(&selinux_state, sid,
+ secattr);
if (rc != 0)
goto skbuff_setsid_return;
}
@@ -288,7 +290,8 @@ int selinux_netlbl_sctp_assoc_request(struct sctp_association *asoc,
return 0;
netlbl_secattr_init(&secattr);
- rc = security_netlbl_sid_to_secattr(asoc->secid, &secattr);
+ rc = security_netlbl_sid_to_secattr(&selinux_state,
+ asoc->secid, &secattr);
if (rc != 0)
goto assoc_request_return;
@@ -336,7 +339,8 @@ int selinux_netlbl_inet_conn_request(struct request_sock *req, u16 family)
return 0;
netlbl_secattr_init(&secattr);
- rc = security_netlbl_sid_to_secattr(req->secid, &secattr);
+ rc = security_netlbl_sid_to_secattr(&selinux_state, req->secid,
+ &secattr);
if (rc != 0)
goto inet_conn_request_return;
rc = netlbl_req_setattr(req, &secattr);
@@ -469,7 +473,8 @@ int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
perm = RAWIP_SOCKET__RECVFROM;
}
- rc = avc_has_perm(sksec->sid, nlbl_sid, sksec->sclass, perm, ad);
+ rc = avc_has_perm(&selinux_state,
+ sksec->sid, nlbl_sid, sksec->sclass, perm, ad);
if (rc == 0)
return 0;
diff --git a/security/selinux/netnode.c b/security/selinux/netnode.c
index 5d0ed08d46e5..48ba999eebfa 100644
--- a/security/selinux/netnode.c
+++ b/security/selinux/netnode.c
@@ -207,13 +207,13 @@ static int sel_netnode_sid_slow(const void *addr, u16 family, u32 *sid)
new = kmalloc(sizeof(*new), GFP_ATOMIC);
switch (family) {
case PF_INET:
- ret = security_node_sid(PF_INET,
+ ret = security_node_sid(&selinux_state, PF_INET,
addr, sizeof(struct in_addr), sid);
if (new)
new->nsec.addr.ipv4 = *(const __be32 *)addr;
break;
case PF_INET6:
- ret = security_node_sid(PF_INET6,
+ ret = security_node_sid(&selinux_state, PF_INET6,
addr, sizeof(struct in6_addr), sid);
if (new)
new->nsec.addr.ipv6 = *(const struct in6_addr *)addr;
diff --git a/security/selinux/netport.c b/security/selinux/netport.c
index 6fd7da4b3576..d7e57cd3ecba 100644
--- a/security/selinux/netport.c
+++ b/security/selinux/netport.c
@@ -142,7 +142,7 @@ static int sel_netport_sid_slow(u8 protocol, u16 pnum, u32 *sid)
return 0;
}
- ret = security_port_sid(protocol, pnum, sid);
+ ret = security_port_sid(&selinux_state, protocol, pnum, sid);
if (ret != 0)
goto out;
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index 9aa1d03ab612..a0bba61e3d3a 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -77,6 +77,7 @@ struct selinux_fs_info {
bool policy_opened;
struct dentry *policycap_dir;
unsigned long last_ino;
+ struct selinux_state *state;
struct super_block *sb;
};
@@ -89,6 +90,7 @@ static int selinux_fs_info_create(struct super_block *sb)
return -ENOMEM;
fsi->last_ino = SEL_INO_NEXT - 1;
+ fsi->state = &selinux_state;
fsi->sb = sb;
sb->s_fs_info = fsi;
return 0;
@@ -123,11 +125,12 @@ static void selinux_fs_info_free(struct super_block *sb)
static ssize_t sel_read_enforce(struct file *filp, char __user *buf,
size_t count, loff_t *ppos)
{
+ struct selinux_fs_info *fsi = file_inode(filp)->i_sb->s_fs_info;
char tmpbuf[TMPBUFLEN];
ssize_t length;
length = scnprintf(tmpbuf, TMPBUFLEN, "%d",
- enforcing_enabled());
+ enforcing_enabled(fsi->state));
return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
}
@@ -136,6 +139,8 @@ static ssize_t sel_write_enforce(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
+ struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
+ struct selinux_state *state = fsi->state;
char *page = NULL;
ssize_t length;
int scan_value;
@@ -158,9 +163,10 @@ static ssize_t sel_write_enforce(struct file *file, const char __user *buf,
new_value = !!scan_value;
- old_value = enforcing_enabled();
+ old_value = enforcing_enabled(state);
if (new_value != old_value) {
- length = avc_has_perm(current_sid(), SECINITSID_SECURITY,
+ length = avc_has_perm(&selinux_state,
+ current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__SETENFORCE,
NULL);
if (length)
@@ -171,15 +177,15 @@ static ssize_t sel_write_enforce(struct file *file, const char __user *buf,
new_value, old_value,
from_kuid(&init_user_ns, audit_get_loginuid(current)),
audit_get_sessionid(current));
- enforcing_set(new_value);
+ enforcing_set(state, new_value);
if (new_value)
- avc_ss_reset(0);
+ avc_ss_reset(state->avc, 0);
selnl_notify_setenforce(new_value);
- selinux_status_update_setenforce(new_value);
+ selinux_status_update_setenforce(state, new_value);
if (!new_value)
call_blocking_lsm_notifier(LSM_POLICY_CHANGE, NULL);
- selinux_ima_measure_state();
+ selinux_ima_measure_state(state);
}
length = count;
out:
@@ -199,12 +205,14 @@ static const struct file_operations sel_enforce_ops = {
static ssize_t sel_read_handle_unknown(struct file *filp, char __user *buf,
size_t count, loff_t *ppos)
{
+ struct selinux_fs_info *fsi = file_inode(filp)->i_sb->s_fs_info;
+ struct selinux_state *state = fsi->state;
char tmpbuf[TMPBUFLEN];
ssize_t length;
ino_t ino = file_inode(filp)->i_ino;
int handle_unknown = (ino == SEL_REJECT_UNKNOWN) ?
- security_get_reject_unknown() :
- !security_get_allow_unknown();
+ security_get_reject_unknown(state) :
+ !security_get_allow_unknown(state);
length = scnprintf(tmpbuf, TMPBUFLEN, "%d", handle_unknown);
return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
@@ -217,7 +225,8 @@ static const struct file_operations sel_handle_unknown_ops = {
static int sel_open_handle_status(struct inode *inode, struct file *filp)
{
- struct page *status = selinux_kernel_status_page();
+ struct selinux_fs_info *fsi = file_inode(filp)->i_sb->s_fs_info;
+ struct page *status = selinux_kernel_status_page(fsi->state);
if (!status)
return -ENOMEM;
@@ -342,11 +351,12 @@ static struct dentry *sel_make_swapover_dir(struct super_block *sb,
static ssize_t sel_read_mls(struct file *filp, char __user *buf,
size_t count, loff_t *ppos)
{
+ struct selinux_fs_info *fsi = file_inode(filp)->i_sb->s_fs_info;
char tmpbuf[TMPBUFLEN];
ssize_t length;
length = scnprintf(tmpbuf, TMPBUFLEN, "%d",
- security_mls_enabled());
+ security_mls_enabled(fsi->state));
return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
}
@@ -363,14 +373,16 @@ struct policy_load_memory {
static int sel_open_policy(struct inode *inode, struct file *filp)
{
struct selinux_fs_info *fsi = inode->i_sb->s_fs_info;
+ struct selinux_state *state = fsi->state;
struct policy_load_memory *plm = NULL;
int rc;
BUG_ON(filp->private_data);
- mutex_lock(&selinux_state.policy_mutex);
+ mutex_lock(&fsi->state->policy_mutex);
- rc = avc_has_perm(current_sid(), SECINITSID_SECURITY,
+ rc = avc_has_perm(&selinux_state,
+ current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__READ_POLICY, NULL);
if (rc)
goto err;
@@ -384,7 +396,7 @@ static int sel_open_policy(struct inode *inode, struct file *filp)
if (!plm)
goto err;
- rc = security_read_policy(&plm->data, &plm->len);
+ rc = security_read_policy(state, &plm->data, &plm->len);
if (rc)
goto err;
@@ -398,11 +410,11 @@ static int sel_open_policy(struct inode *inode, struct file *filp)
filp->private_data = plm;
- mutex_unlock(&selinux_state.policy_mutex);
+ mutex_unlock(&fsi->state->policy_mutex);
return 0;
err:
- mutex_unlock(&selinux_state.policy_mutex);
+ mutex_unlock(&fsi->state->policy_mutex);
if (plm)
vfree(plm->data);
@@ -431,7 +443,8 @@ static ssize_t sel_read_policy(struct file *filp, char __user *buf,
struct policy_load_memory *plm = filp->private_data;
int ret;
- ret = avc_has_perm(current_sid(), SECINITSID_SECURITY,
+ ret = avc_has_perm(&selinux_state,
+ current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__READ_POLICY, NULL);
if (ret)
return ret;
@@ -571,7 +584,7 @@ static ssize_t sel_write_load(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
- struct selinux_fs_info *fsi;
+ struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
struct selinux_load_state load_state;
ssize_t length;
void *data = NULL;
@@ -583,9 +596,9 @@ static ssize_t sel_write_load(struct file *file, const char __user *buf,
if (!count)
return -EINVAL;
- mutex_lock(&selinux_state.policy_mutex);
-
- length = avc_has_perm(current_sid(), SECINITSID_SECURITY,
+ mutex_lock(&fsi->state->policy_mutex);
+ length = avc_has_perm(&selinux_state,
+ current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__LOAD_POLICY, NULL);
if (length)
goto out;
@@ -600,7 +613,7 @@ static ssize_t sel_write_load(struct file *file, const char __user *buf,
goto out;
}
- length = security_load_policy(data, count, &load_state);
+ length = security_load_policy(fsi->state, data, count, &load_state);
if (length) {
pr_warn_ratelimited("SELinux: failed to load policy\n");
goto out;
@@ -609,11 +622,11 @@ static ssize_t sel_write_load(struct file *file, const char __user *buf,
length = sel_make_policy_nodes(fsi, load_state.policy);
if (length) {
pr_warn_ratelimited("SELinux: failed to initialize selinuxfs\n");
- selinux_policy_cancel(&load_state);
+ selinux_policy_cancel(fsi->state, &load_state);
goto out;
}
- selinux_policy_commit(&load_state);
+ selinux_policy_commit(fsi->state, &load_state);
length = count;
audit_log(audit_context(), GFP_KERNEL, AUDIT_MAC_POLICY_LOAD,
"auid=%u ses=%u lsm=selinux res=1",
@@ -621,7 +634,7 @@ static ssize_t sel_write_load(struct file *file, const char __user *buf,
audit_get_sessionid(current));
out:
- mutex_unlock(&selinux_state.policy_mutex);
+ mutex_unlock(&fsi->state->policy_mutex);
vfree(data);
return length;
}
@@ -633,20 +646,23 @@ static const struct file_operations sel_load_ops = {
static ssize_t sel_write_context(struct file *file, char *buf, size_t size)
{
+ struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
+ struct selinux_state *state = fsi->state;
char *canon = NULL;
u32 sid, len;
ssize_t length;
- length = avc_has_perm(current_sid(), SECINITSID_SECURITY,
+ length = avc_has_perm(&selinux_state,
+ current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__CHECK_CONTEXT, NULL);
if (length)
goto out;
- length = security_context_to_sid(buf, size, &sid, GFP_KERNEL);
+ length = security_context_to_sid(state, buf, size, &sid, GFP_KERNEL);
if (length)
goto out;
- length = security_sid_to_context(sid, &canon, &len);
+ length = security_sid_to_context(state, sid, &canon, &len);
if (length)
goto out;
@@ -667,22 +683,25 @@ static ssize_t sel_write_context(struct file *file, char *buf, size_t size)
static ssize_t sel_read_checkreqprot(struct file *filp, char __user *buf,
size_t count, loff_t *ppos)
{
+ struct selinux_fs_info *fsi = file_inode(filp)->i_sb->s_fs_info;
char tmpbuf[TMPBUFLEN];
ssize_t length;
length = scnprintf(tmpbuf, TMPBUFLEN, "%u",
- checkreqprot_get());
+ checkreqprot_get(fsi->state));
return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
}
static ssize_t sel_write_checkreqprot(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
+ struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
char *page;
ssize_t length;
unsigned int new_value;
- length = avc_has_perm(current_sid(), SECINITSID_SECURITY,
+ length = avc_has_perm(&selinux_state,
+ current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__SETCHECKREQPROT,
NULL);
if (length)
@@ -713,7 +732,7 @@ static ssize_t sel_write_checkreqprot(struct file *file, const char __user *buf,
comm, current->pid);
}
- selinux_ima_measure_state();
+ selinux_ima_measure_state(fsi->state);
out:
kfree(page);
@@ -729,13 +748,16 @@ static ssize_t sel_write_validatetrans(struct file *file,
const char __user *buf,
size_t count, loff_t *ppos)
{
+ struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
+ struct selinux_state *state = fsi->state;
char *oldcon = NULL, *newcon = NULL, *taskcon = NULL;
char *req = NULL;
u32 osid, nsid, tsid;
u16 tclass;
int rc;
- rc = avc_has_perm(current_sid(), SECINITSID_SECURITY,
+ rc = avc_has_perm(&selinux_state,
+ current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__VALIDATE_TRANS, NULL);
if (rc)
goto out;
@@ -773,19 +795,19 @@ static ssize_t sel_write_validatetrans(struct file *file,
if (sscanf(req, "%s %s %hu %s", oldcon, newcon, &tclass, taskcon) != 4)
goto out;
- rc = security_context_str_to_sid(oldcon, &osid, GFP_KERNEL);
+ rc = security_context_str_to_sid(state, oldcon, &osid, GFP_KERNEL);
if (rc)
goto out;
- rc = security_context_str_to_sid(newcon, &nsid, GFP_KERNEL);
+ rc = security_context_str_to_sid(state, newcon, &nsid, GFP_KERNEL);
if (rc)
goto out;
- rc = security_context_str_to_sid(taskcon, &tsid, GFP_KERNEL);
+ rc = security_context_str_to_sid(state, taskcon, &tsid, GFP_KERNEL);
if (rc)
goto out;
- rc = security_validate_transition_user(osid, nsid, tsid, tclass);
+ rc = security_validate_transition_user(state, osid, nsid, tsid, tclass);
if (!rc)
rc = count;
out:
@@ -855,13 +877,16 @@ static const struct file_operations transaction_ops = {
static ssize_t sel_write_access(struct file *file, char *buf, size_t size)
{
+ struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
+ struct selinux_state *state = fsi->state;
char *scon = NULL, *tcon = NULL;
u32 ssid, tsid;
u16 tclass;
struct av_decision avd;
ssize_t length;
- length = avc_has_perm(current_sid(), SECINITSID_SECURITY,
+ length = avc_has_perm(&selinux_state,
+ current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__COMPUTE_AV, NULL);
if (length)
goto out;
@@ -880,15 +905,15 @@ static ssize_t sel_write_access(struct file *file, char *buf, size_t size)
if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3)
goto out;
- length = security_context_str_to_sid(scon, &ssid, GFP_KERNEL);
+ length = security_context_str_to_sid(state, scon, &ssid, GFP_KERNEL);
if (length)
goto out;
- length = security_context_str_to_sid(tcon, &tsid, GFP_KERNEL);
+ length = security_context_str_to_sid(state, tcon, &tsid, GFP_KERNEL);
if (length)
goto out;
- security_compute_av_user(ssid, tsid, tclass, &avd);
+ security_compute_av_user(state, ssid, tsid, tclass, &avd);
length = scnprintf(buf, SIMPLE_TRANSACTION_LIMIT,
"%x %x %x %x %u %x",
@@ -903,6 +928,8 @@ static ssize_t sel_write_access(struct file *file, char *buf, size_t size)
static ssize_t sel_write_create(struct file *file, char *buf, size_t size)
{
+ struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
+ struct selinux_state *state = fsi->state;
char *scon = NULL, *tcon = NULL;
char *namebuf = NULL, *objname = NULL;
u32 ssid, tsid, newsid;
@@ -912,7 +939,8 @@ static ssize_t sel_write_create(struct file *file, char *buf, size_t size)
u32 len;
int nargs;
- length = avc_has_perm(current_sid(), SECINITSID_SECURITY,
+ length = avc_has_perm(&selinux_state,
+ current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__COMPUTE_CREATE,
NULL);
if (length)
@@ -968,20 +996,20 @@ static ssize_t sel_write_create(struct file *file, char *buf, size_t size)
objname = namebuf;
}
- length = security_context_str_to_sid(scon, &ssid, GFP_KERNEL);
+ length = security_context_str_to_sid(state, scon, &ssid, GFP_KERNEL);
if (length)
goto out;
- length = security_context_str_to_sid(tcon, &tsid, GFP_KERNEL);
+ length = security_context_str_to_sid(state, tcon, &tsid, GFP_KERNEL);
if (length)
goto out;
- length = security_transition_sid_user(ssid, tsid, tclass,
+ length = security_transition_sid_user(state, ssid, tsid, tclass,
objname, &newsid);
if (length)
goto out;
- length = security_sid_to_context(newsid, &newcon, &len);
+ length = security_sid_to_context(state, newsid, &newcon, &len);
if (length)
goto out;
@@ -1004,6 +1032,8 @@ static ssize_t sel_write_create(struct file *file, char *buf, size_t size)
static ssize_t sel_write_relabel(struct file *file, char *buf, size_t size)
{
+ struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
+ struct selinux_state *state = fsi->state;
char *scon = NULL, *tcon = NULL;
u32 ssid, tsid, newsid;
u16 tclass;
@@ -1011,7 +1041,8 @@ static ssize_t sel_write_relabel(struct file *file, char *buf, size_t size)
char *newcon = NULL;
u32 len;
- length = avc_has_perm(current_sid(), SECINITSID_SECURITY,
+ length = avc_has_perm(&selinux_state,
+ current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__COMPUTE_RELABEL,
NULL);
if (length)
@@ -1031,19 +1062,19 @@ static ssize_t sel_write_relabel(struct file *file, char *buf, size_t size)
if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3)
goto out;
- length = security_context_str_to_sid(scon, &ssid, GFP_KERNEL);
+ length = security_context_str_to_sid(state, scon, &ssid, GFP_KERNEL);
if (length)
goto out;
- length = security_context_str_to_sid(tcon, &tsid, GFP_KERNEL);
+ length = security_context_str_to_sid(state, tcon, &tsid, GFP_KERNEL);
if (length)
goto out;
- length = security_change_sid(ssid, tsid, tclass, &newsid);
+ length = security_change_sid(state, ssid, tsid, tclass, &newsid);
if (length)
goto out;
- length = security_sid_to_context(newsid, &newcon, &len);
+ length = security_sid_to_context(state, newsid, &newcon, &len);
if (length)
goto out;
@@ -1062,6 +1093,8 @@ static ssize_t sel_write_relabel(struct file *file, char *buf, size_t size)
static ssize_t sel_write_user(struct file *file, char *buf, size_t size)
{
+ struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
+ struct selinux_state *state = fsi->state;
char *con = NULL, *user = NULL, *ptr;
u32 sid, *sids = NULL;
ssize_t length;
@@ -1074,7 +1107,8 @@ static ssize_t sel_write_user(struct file *file, char *buf, size_t size)
" userspace.\n", current->comm, current->pid);
ssleep(5);
- length = avc_has_perm(current_sid(), SECINITSID_SECURITY,
+ length = avc_has_perm(&selinux_state,
+ current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__COMPUTE_USER,
NULL);
if (length)
@@ -1094,18 +1128,18 @@ static ssize_t sel_write_user(struct file *file, char *buf, size_t size)
if (sscanf(buf, "%s %s", con, user) != 2)
goto out;
- length = security_context_str_to_sid(con, &sid, GFP_KERNEL);
+ length = security_context_str_to_sid(state, con, &sid, GFP_KERNEL);
if (length)
goto out;
- length = security_get_user_sids(sid, user, &sids, &nsids);
+ length = security_get_user_sids(state, sid, user, &sids, &nsids);
if (length)
goto out;
length = sprintf(buf, "%u", nsids) + 1;
ptr = buf + length;
for (i = 0; i < nsids; i++) {
- rc = security_sid_to_context(sids[i], &newcon, &len);
+ rc = security_sid_to_context(state, sids[i], &newcon, &len);
if (rc) {
length = rc;
goto out;
@@ -1129,6 +1163,8 @@ static ssize_t sel_write_user(struct file *file, char *buf, size_t size)
static ssize_t sel_write_member(struct file *file, char *buf, size_t size)
{
+ struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
+ struct selinux_state *state = fsi->state;
char *scon = NULL, *tcon = NULL;
u32 ssid, tsid, newsid;
u16 tclass;
@@ -1136,7 +1172,8 @@ static ssize_t sel_write_member(struct file *file, char *buf, size_t size)
char *newcon = NULL;
u32 len;
- length = avc_has_perm(current_sid(), SECINITSID_SECURITY,
+ length = avc_has_perm(&selinux_state,
+ current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__COMPUTE_MEMBER,
NULL);
if (length)
@@ -1156,19 +1193,19 @@ static ssize_t sel_write_member(struct file *file, char *buf, size_t size)
if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3)
goto out;
- length = security_context_str_to_sid(scon, &ssid, GFP_KERNEL);
+ length = security_context_str_to_sid(state, scon, &ssid, GFP_KERNEL);
if (length)
goto out;
- length = security_context_str_to_sid(tcon, &tsid, GFP_KERNEL);
+ length = security_context_str_to_sid(state, tcon, &tsid, GFP_KERNEL);
if (length)
goto out;
- length = security_member_sid(ssid, tsid, tclass, &newsid);
+ length = security_member_sid(state, ssid, tsid, tclass, &newsid);
if (length)
goto out;
- length = security_sid_to_context(newsid, &newcon, &len);
+ length = security_sid_to_context(state, newsid, &newcon, &len);
if (length)
goto out;
@@ -1210,7 +1247,7 @@ static ssize_t sel_read_bool(struct file *filep, char __user *buf,
unsigned index = file_inode(filep)->i_ino & SEL_INO_MASK;
const char *name = filep->f_path.dentry->d_name.name;
- mutex_lock(&selinux_state.policy_mutex);
+ mutex_lock(&fsi->state->policy_mutex);
ret = -EINVAL;
if (index >= fsi->bool_num || strcmp(name,
@@ -1222,21 +1259,21 @@ static ssize_t sel_read_bool(struct file *filep, char __user *buf,
if (!page)
goto out_unlock;
- cur_enforcing = security_get_bool_value(index);
+ cur_enforcing = security_get_bool_value(fsi->state, index);
if (cur_enforcing < 0) {
ret = cur_enforcing;
goto out_unlock;
}
length = scnprintf(page, PAGE_SIZE, "%d %d", cur_enforcing,
fsi->bool_pending_values[index]);
- mutex_unlock(&selinux_state.policy_mutex);
+ mutex_unlock(&fsi->state->policy_mutex);
ret = simple_read_from_buffer(buf, count, ppos, page, length);
out_free:
free_page((unsigned long)page);
return ret;
out_unlock:
- mutex_unlock(&selinux_state.policy_mutex);
+ mutex_unlock(&fsi->state->policy_mutex);
goto out_free;
}
@@ -1261,9 +1298,10 @@ static ssize_t sel_write_bool(struct file *filep, const char __user *buf,
if (IS_ERR(page))
return PTR_ERR(page);
- mutex_lock(&selinux_state.policy_mutex);
+ mutex_lock(&fsi->state->policy_mutex);
- length = avc_has_perm(current_sid(), SECINITSID_SECURITY,
+ length = avc_has_perm(&selinux_state,
+ current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__SETBOOL,
NULL);
if (length)
@@ -1285,7 +1323,7 @@ static ssize_t sel_write_bool(struct file *filep, const char __user *buf,
length = count;
out:
- mutex_unlock(&selinux_state.policy_mutex);
+ mutex_unlock(&fsi->state->policy_mutex);
kfree(page);
return length;
}
@@ -1316,9 +1354,10 @@ static ssize_t sel_commit_bools_write(struct file *filep,
if (IS_ERR(page))
return PTR_ERR(page);
- mutex_lock(&selinux_state.policy_mutex);
+ mutex_lock(&fsi->state->policy_mutex);
- length = avc_has_perm(current_sid(), SECINITSID_SECURITY,
+ length = avc_has_perm(&selinux_state,
+ current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__SETBOOL,
NULL);
if (length)
@@ -1330,14 +1369,14 @@ static ssize_t sel_commit_bools_write(struct file *filep,
length = 0;
if (new_value && fsi->bool_pending_values)
- length = security_set_bools(fsi->bool_num,
+ length = security_set_bools(fsi->state, fsi->bool_num,
fsi->bool_pending_values);
if (!length)
length = count;
out:
- mutex_unlock(&selinux_state.policy_mutex);
+ mutex_unlock(&fsi->state->policy_mutex);
kfree(page);
return length;
}
@@ -1414,11 +1453,13 @@ static int sel_make_bools(struct selinux_policy *newpolicy, struct dentry *bool_
static ssize_t sel_read_avc_cache_threshold(struct file *filp, char __user *buf,
size_t count, loff_t *ppos)
{
+ struct selinux_fs_info *fsi = file_inode(filp)->i_sb->s_fs_info;
+ struct selinux_state *state = fsi->state;
char tmpbuf[TMPBUFLEN];
ssize_t length;
length = scnprintf(tmpbuf, TMPBUFLEN, "%u",
- avc_get_cache_threshold());
+ avc_get_cache_threshold(state->avc));
return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
}
@@ -1427,11 +1468,14 @@ static ssize_t sel_write_avc_cache_threshold(struct file *file,
size_t count, loff_t *ppos)
{
+ struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
+ struct selinux_state *state = fsi->state;
char *page;
ssize_t ret;
unsigned int new_value;
- ret = avc_has_perm(current_sid(), SECINITSID_SECURITY,
+ ret = avc_has_perm(&selinux_state,
+ current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__SETSECPARAM,
NULL);
if (ret)
@@ -1452,7 +1496,7 @@ static ssize_t sel_write_avc_cache_threshold(struct file *file,
if (sscanf(page, "%u", &new_value) != 1)
goto out;
- avc_set_cache_threshold(new_value);
+ avc_set_cache_threshold(state->avc, new_value);
ret = count;
out:
@@ -1463,6 +1507,8 @@ static ssize_t sel_write_avc_cache_threshold(struct file *file,
static ssize_t sel_read_avc_hash_stats(struct file *filp, char __user *buf,
size_t count, loff_t *ppos)
{
+ struct selinux_fs_info *fsi = file_inode(filp)->i_sb->s_fs_info;
+ struct selinux_state *state = fsi->state;
char *page;
ssize_t length;
@@ -1470,7 +1516,7 @@ static ssize_t sel_read_avc_hash_stats(struct file *filp, char __user *buf,
if (!page)
return -ENOMEM;
- length = avc_get_hash_stats(page);
+ length = avc_get_hash_stats(state->avc, page);
if (length >= 0)
length = simple_read_from_buffer(buf, count, ppos, page, length);
free_page((unsigned long)page);
@@ -1481,6 +1527,8 @@ static ssize_t sel_read_avc_hash_stats(struct file *filp, char __user *buf,
static ssize_t sel_read_sidtab_hash_stats(struct file *filp, char __user *buf,
size_t count, loff_t *ppos)
{
+ struct selinux_fs_info *fsi = file_inode(filp)->i_sb->s_fs_info;
+ struct selinux_state *state = fsi->state;
char *page;
ssize_t length;
@@ -1488,7 +1536,7 @@ static ssize_t sel_read_sidtab_hash_stats(struct file *filp, char __user *buf,
if (!page)
return -ENOMEM;
- length = security_sidtab_hash_stats(page);
+ length = security_sidtab_hash_stats(state, page);
if (length >= 0)
length = simple_read_from_buffer(buf, count, ppos, page,
length);
@@ -1654,12 +1702,13 @@ static int sel_make_ss_files(struct dentry *dir)
static ssize_t sel_read_initcon(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
+ struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
char *con;
u32 sid, len;
ssize_t ret;
sid = file_inode(file)->i_ino&SEL_INO_MASK;
- ret = security_sid_to_context(sid, &con, &len);
+ ret = security_sid_to_context(fsi->state, sid, &con, &len);
if (ret)
return ret;
@@ -1753,12 +1802,13 @@ static const struct file_operations sel_perm_ops = {
static ssize_t sel_read_policycap(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
+ struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
int value;
char tmpbuf[TMPBUFLEN];
ssize_t length;
unsigned long i_ino = file_inode(file)->i_ino;
- value = security_policycap_supported(i_ino & SEL_INO_MASK);
+ value = security_policycap_supported(fsi->state, i_ino & SEL_INO_MASK);
length = scnprintf(tmpbuf, TMPBUFLEN, "%d", value);
return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
@@ -2170,7 +2220,7 @@ static int __init init_sel_fs(void)
* Try to pre-allocate the status page, so the sequence number of the
* initial policy load can be stored.
*/
- (void) selinux_kernel_status_page();
+ (void) selinux_kernel_status_page(&selinux_state);
return err;
}
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index 713130bd43c4..724e0f4c6110 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -236,16 +236,16 @@ static void map_decision(struct selinux_map *map,
}
}
-int security_mls_enabled(void)
+int security_mls_enabled(struct selinux_state *state)
{
int mls_enabled;
struct selinux_policy *policy;
- if (!selinux_initialized())
+ if (!selinux_initialized(state))
return 0;
rcu_read_lock();
- policy = rcu_dereference(selinux_state.policy);
+ policy = rcu_dereference(state->policy);
mls_enabled = policy->policydb.mls_enabled;
rcu_read_unlock();
return mls_enabled;
@@ -722,7 +722,8 @@ static void context_struct_compute_av(struct policydb *policydb,
tclass, avd);
}
-static int security_validtrans_handle_fail(struct selinux_policy *policy,
+static int security_validtrans_handle_fail(struct selinux_state *state,
+ struct selinux_policy *policy,
struct sidtab_entry *oentry,
struct sidtab_entry *nentry,
struct sidtab_entry *tentry,
@@ -748,12 +749,13 @@ static int security_validtrans_handle_fail(struct selinux_policy *policy,
kfree(n);
kfree(t);
- if (!enforcing_enabled())
+ if (!enforcing_enabled(state))
return 0;
return -EPERM;
}
-static int security_compute_validatetrans(u32 oldsid, u32 newsid, u32 tasksid,
+static int security_compute_validatetrans(struct selinux_state *state,
+ u32 oldsid, u32 newsid, u32 tasksid,
u16 orig_tclass, bool user)
{
struct selinux_policy *policy;
@@ -768,12 +770,12 @@ static int security_compute_validatetrans(u32 oldsid, u32 newsid, u32 tasksid,
int rc = 0;
- if (!selinux_initialized())
+ if (!selinux_initialized(state))
return 0;
rcu_read_lock();
- policy = rcu_dereference(selinux_state.policy);
+ policy = rcu_dereference(state->policy);
policydb = &policy->policydb;
sidtab = policy->sidtab;
@@ -820,7 +822,8 @@ static int security_compute_validatetrans(u32 oldsid, u32 newsid, u32 tasksid,
if (user)
rc = -EPERM;
else
- rc = security_validtrans_handle_fail(policy,
+ rc = security_validtrans_handle_fail(state,
+ policy,
oentry,
nentry,
tentry,
@@ -835,17 +838,19 @@ static int security_compute_validatetrans(u32 oldsid, u32 newsid, u32 tasksid,
return rc;
}
-int security_validate_transition_user(u32 oldsid, u32 newsid, u32 tasksid,
+int security_validate_transition_user(struct selinux_state *state,
+ u32 oldsid, u32 newsid, u32 tasksid,
u16 tclass)
{
- return security_compute_validatetrans(oldsid, newsid, tasksid,
+ return security_compute_validatetrans(state, oldsid, newsid, tasksid,
tclass, true);
}
-int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid,
+int security_validate_transition(struct selinux_state *state,
+ u32 oldsid, u32 newsid, u32 tasksid,
u16 orig_tclass)
{
- return security_compute_validatetrans(oldsid, newsid, tasksid,
+ return security_compute_validatetrans(state, oldsid, newsid, tasksid,
orig_tclass, false);
}
@@ -855,10 +860,12 @@ int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid,
* It returns 0, if @newsid is bounded by @oldsid.
* Otherwise, it returns error code.
*
+ * @state: SELinux state
* @oldsid : current security identifier
* @newsid : destinated security identifier
*/
-int security_bounded_transition(u32 old_sid, u32 new_sid)
+int security_bounded_transition(struct selinux_state *state,
+ u32 old_sid, u32 new_sid)
{
struct selinux_policy *policy;
struct policydb *policydb;
@@ -868,11 +875,11 @@ int security_bounded_transition(u32 old_sid, u32 new_sid)
u32 index;
int rc;
- if (!selinux_initialized())
+ if (!selinux_initialized(state))
return 0;
rcu_read_lock();
- policy = rcu_dereference(selinux_state.policy);
+ policy = rcu_dereference(state->policy);
policydb = &policy->policydb;
sidtab = policy->sidtab;
@@ -1023,7 +1030,8 @@ void services_compute_xperms_decision(struct extended_perms_decision *xpermd,
}
}
-void security_compute_xperms_decision(u32 ssid,
+void security_compute_xperms_decision(struct selinux_state *state,
+ u32 ssid,
u32 tsid,
u16 orig_tclass,
u8 driver,
@@ -1049,10 +1057,10 @@ void security_compute_xperms_decision(u32 ssid,
memset(xpermd->dontaudit->p, 0, sizeof(xpermd->dontaudit->p));
rcu_read_lock();
- if (!selinux_initialized())
+ if (!selinux_initialized(state))
goto allow;
- policy = rcu_dereference(selinux_state.policy);
+ policy = rcu_dereference(state->policy);
policydb = &policy->policydb;
sidtab = policy->sidtab;
@@ -1111,6 +1119,7 @@ void security_compute_xperms_decision(u32 ssid,
/**
* security_compute_av - Compute access vector decisions.
+ * @state: SELinux state
* @ssid: source security identifier
* @tsid: target security identifier
* @orig_tclass: target security class
@@ -1120,7 +1129,8 @@ void security_compute_xperms_decision(u32 ssid,
* Compute a set of access vector decisions based on the
* SID pair (@ssid, @tsid) for the permissions in @tclass.
*/
-void security_compute_av(u32 ssid,
+void security_compute_av(struct selinux_state *state,
+ u32 ssid,
u32 tsid,
u16 orig_tclass,
struct av_decision *avd,
@@ -1133,10 +1143,10 @@ void security_compute_av(u32 ssid,
struct context *scontext = NULL, *tcontext = NULL;
rcu_read_lock();
- policy = rcu_dereference(selinux_state.policy);
+ policy = rcu_dereference(state->policy);
avd_init(policy, avd);
xperms->len = 0;
- if (!selinux_initialized())
+ if (!selinux_initialized(state))
goto allow;
policydb = &policy->policydb;
@@ -1188,7 +1198,8 @@ void security_compute_av(u32 ssid,
goto out;
}
-void security_compute_av_user(u32 ssid,
+void security_compute_av_user(struct selinux_state *state,
+ u32 ssid,
u32 tsid,
u16 tclass,
struct av_decision *avd)
@@ -1199,9 +1210,9 @@ void security_compute_av_user(u32 ssid,
struct context *scontext = NULL, *tcontext = NULL;
rcu_read_lock();
- policy = rcu_dereference(selinux_state.policy);
+ policy = rcu_dereference(state->policy);
avd_init(policy, avd);
- if (!selinux_initialized())
+ if (!selinux_initialized(state))
goto allow;
policydb = &policy->policydb;
@@ -1327,19 +1338,19 @@ static int sidtab_entry_to_string(struct policydb *p,
#include "initial_sid_to_string.h"
-int security_sidtab_hash_stats(char *page)
+int security_sidtab_hash_stats(struct selinux_state *state, char *page)
{
struct selinux_policy *policy;
int rc;
- if (!selinux_initialized()) {
+ if (!selinux_initialized(state)) {
pr_err("SELinux: %s: called before initial load_policy\n",
__func__);
return -EINVAL;
}
rcu_read_lock();
- policy = rcu_dereference(selinux_state.policy);
+ policy = rcu_dereference(state->policy);
rc = sidtab_hash_stats(policy->sidtab, page);
rcu_read_unlock();
@@ -1353,7 +1364,8 @@ const char *security_get_initial_sid_context(u32 sid)
return initial_sid_to_string[sid];
}
-static int security_sid_to_context_core(u32 sid, char **scontext,
+static int security_sid_to_context_core(struct selinux_state *state,
+ u32 sid, char **scontext,
u32 *scontext_len, int force,
int only_invalid)
{
@@ -1367,7 +1379,7 @@ static int security_sid_to_context_core(u32 sid, char **scontext,
*scontext = NULL;
*scontext_len = 0;
- if (!selinux_initialized()) {
+ if (!selinux_initialized(state)) {
if (sid <= SECINITSID_NUM) {
char *scontextp;
const char *s;
@@ -1399,7 +1411,7 @@ static int security_sid_to_context_core(u32 sid, char **scontext,
return -EINVAL;
}
rcu_read_lock();
- policy = rcu_dereference(selinux_state.policy);
+ policy = rcu_dereference(state->policy);
policydb = &policy->policydb;
sidtab = policy->sidtab;
@@ -1427,6 +1439,7 @@ static int security_sid_to_context_core(u32 sid, char **scontext,
/**
* security_sid_to_context - Obtain a context for a given SID.
+ * @state: SELinux state
* @sid: security identifier, SID
* @scontext: security context
* @scontext_len: length in bytes
@@ -1435,22 +1448,24 @@ static int security_sid_to_context_core(u32 sid, char **scontext,
* into a dynamically allocated string of the correct size. Set @scontext
* to point to this string and set @scontext_len to the length of the string.
*/
-int security_sid_to_context(u32 sid, char **scontext, u32 *scontext_len)
+int security_sid_to_context(struct selinux_state *state,
+ u32 sid, char **scontext, u32 *scontext_len)
{
- return security_sid_to_context_core(sid, scontext,
+ return security_sid_to_context_core(state, sid, scontext,
scontext_len, 0, 0);
}
-int security_sid_to_context_force(u32 sid,
+int security_sid_to_context_force(struct selinux_state *state, u32 sid,
char **scontext, u32 *scontext_len)
{
- return security_sid_to_context_core(sid, scontext,
+ return security_sid_to_context_core(state, sid, scontext,
scontext_len, 1, 0);
}
/**
* security_sid_to_context_inval - Obtain a context for a given SID if it
* is invalid.
+ * @state: SELinux state
* @sid: security identifier, SID
* @scontext: security context
* @scontext_len: length in bytes
@@ -1461,10 +1476,10 @@ int security_sid_to_context_force(u32 sid,
* this string (or NULL if the context is valid) and set @scontext_len to
* the length of the string (or 0 if the context is valid).
*/
-int security_sid_to_context_inval(u32 sid,
+int security_sid_to_context_inval(struct selinux_state *state, u32 sid,
char **scontext, u32 *scontext_len)
{
- return security_sid_to_context_core(sid, scontext,
+ return security_sid_to_context_core(state, sid, scontext,
scontext_len, 1, 1);
}
@@ -1549,7 +1564,8 @@ static int string_to_context_struct(struct policydb *pol,
return rc;
}
-static int security_context_to_sid_core(const char *scontext, u32 scontext_len,
+static int security_context_to_sid_core(struct selinux_state *state,
+ const char *scontext, u32 scontext_len,
u32 *sid, u32 def_sid, gfp_t gfp_flags,
int force)
{
@@ -1569,9 +1585,8 @@ static int security_context_to_sid_core(const char *scontext, u32 scontext_len,
if (!scontext2)
return -ENOMEM;
- if (!selinux_initialized()) {
+ if (!selinux_initialized(state)) {
u32 i;
-
for (i = 1; i < SECINITSID_NUM; i++) {
const char *s = initial_sid_to_string[i];
@@ -1594,7 +1609,7 @@ static int security_context_to_sid_core(const char *scontext, u32 scontext_len,
}
retry:
rcu_read_lock();
- policy = rcu_dereference(selinux_state.policy);
+ policy = rcu_dereference(state->policy);
policydb = &policy->policydb;
sidtab = policy->sidtab;
rc = string_to_context_struct(policydb, sidtab, scontext2,
@@ -1626,6 +1641,7 @@ static int security_context_to_sid_core(const char *scontext, u32 scontext_len,
/**
* security_context_to_sid - Obtain a SID for a given security context.
+ * @state: SELinux state
* @scontext: security context
* @scontext_len: length in bytes
* @sid: security identifier, SID
@@ -1636,16 +1652,18 @@ static int security_context_to_sid_core(const char *scontext, u32 scontext_len,
* Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient
* memory is available, or 0 on success.
*/
-int security_context_to_sid(const char *scontext, u32 scontext_len, u32 *sid,
+int security_context_to_sid(struct selinux_state *state,
+ const char *scontext, u32 scontext_len, u32 *sid,
gfp_t gfp)
{
- return security_context_to_sid_core(scontext, scontext_len,
+ return security_context_to_sid_core(state, scontext, scontext_len,
sid, SECSID_NULL, gfp, 0);
}
-int security_context_str_to_sid(const char *scontext, u32 *sid, gfp_t gfp)
+int security_context_str_to_sid(struct selinux_state *state,
+ const char *scontext, u32 *sid, gfp_t gfp)
{
- return security_context_to_sid(scontext, strlen(scontext),
+ return security_context_to_sid(state, scontext, strlen(scontext),
sid, gfp);
}
@@ -1653,6 +1671,7 @@ int security_context_str_to_sid(const char *scontext, u32 *sid, gfp_t gfp)
* security_context_to_sid_default - Obtain a SID for a given security context,
* falling back to specified default if needed.
*
+ * @state: SELinux state
* @scontext: security context
* @scontext_len: length in bytes
* @sid: security identifier, SID
@@ -1668,21 +1687,24 @@ int security_context_str_to_sid(const char *scontext, u32 *sid, gfp_t gfp)
* Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient
* memory is available, or 0 on success.
*/
-int security_context_to_sid_default(const char *scontext, u32 scontext_len,
+int security_context_to_sid_default(struct selinux_state *state,
+ const char *scontext, u32 scontext_len,
u32 *sid, u32 def_sid, gfp_t gfp_flags)
{
- return security_context_to_sid_core(scontext, scontext_len,
+ return security_context_to_sid_core(state, scontext, scontext_len,
sid, def_sid, gfp_flags, 1);
}
-int security_context_to_sid_force(const char *scontext, u32 scontext_len,
+int security_context_to_sid_force(struct selinux_state *state,
+ const char *scontext, u32 scontext_len,
u32 *sid)
{
- return security_context_to_sid_core(scontext, scontext_len,
+ return security_context_to_sid_core(state, scontext, scontext_len,
sid, SECSID_NULL, GFP_KERNEL, 1);
}
static int compute_sid_handle_invalid_context(
+ struct selinux_state *state,
struct selinux_policy *policy,
struct sidtab_entry *sentry,
struct sidtab_entry *tentry,
@@ -1715,7 +1737,7 @@ static int compute_sid_handle_invalid_context(
kfree(s);
kfree(t);
kfree(n);
- if (!enforcing_enabled())
+ if (!enforcing_enabled(state))
return 0;
return -EACCES;
}
@@ -1750,7 +1772,8 @@ static void filename_compute_type(struct policydb *policydb,
}
}
-static int security_compute_sid(u32 ssid,
+static int security_compute_sid(struct selinux_state *state,
+ u32 ssid,
u32 tsid,
u16 orig_tclass,
u16 specified,
@@ -1770,7 +1793,7 @@ static int security_compute_sid(u32 ssid,
int rc = 0;
bool sock;
- if (!selinux_initialized()) {
+ if (!selinux_initialized(state)) {
switch (orig_tclass) {
case SECCLASS_PROCESS: /* kernel value */
*out_sid = ssid;
@@ -1788,7 +1811,7 @@ static int security_compute_sid(u32 ssid,
rcu_read_lock();
- policy = rcu_dereference(selinux_state.policy);
+ policy = rcu_dereference(state->policy);
if (kern) {
tclass = unmap_class(&policy->map, orig_tclass);
@@ -1922,7 +1945,7 @@ static int security_compute_sid(u32 ssid,
/* Check the validity of the context. */
if (!policydb_context_isvalid(policydb, &newcontext)) {
- rc = compute_sid_handle_invalid_context(policy, sentry,
+ rc = compute_sid_handle_invalid_context(state, policy, sentry,
tentry, tclass,
&newcontext);
if (rc)
@@ -1950,6 +1973,7 @@ static int security_compute_sid(u32 ssid,
/**
* security_transition_sid - Compute the SID for a new subject/object.
+ * @state: SELinux state
* @ssid: source security identifier
* @tsid: target security identifier
* @tclass: target security class
@@ -1962,24 +1986,27 @@ static int security_compute_sid(u32 ssid,
* if insufficient memory is available, or %0 if the new SID was
* computed successfully.
*/
-int security_transition_sid(u32 ssid, u32 tsid, u16 tclass,
+int security_transition_sid(struct selinux_state *state,
+ u32 ssid, u32 tsid, u16 tclass,
const struct qstr *qstr, u32 *out_sid)
{
- return security_compute_sid(ssid, tsid, tclass,
+ return security_compute_sid(state, ssid, tsid, tclass,
AVTAB_TRANSITION,
qstr ? qstr->name : NULL, out_sid, true);
}
-int security_transition_sid_user(u32 ssid, u32 tsid, u16 tclass,
+int security_transition_sid_user(struct selinux_state *state,
+ u32 ssid, u32 tsid, u16 tclass,
const char *objname, u32 *out_sid)
{
- return security_compute_sid(ssid, tsid, tclass,
+ return security_compute_sid(state, ssid, tsid, tclass,
AVTAB_TRANSITION,
objname, out_sid, false);
}
/**
* security_member_sid - Compute the SID for member selection.
+ * @state: SELinux state
* @ssid: source security identifier
* @tsid: target security identifier
* @tclass: target security class
@@ -1991,18 +2018,20 @@ int security_transition_sid_user(u32 ssid, u32 tsid, u16 tclass,
* if insufficient memory is available, or %0 if the SID was
* computed successfully.
*/
-int security_member_sid(u32 ssid,
+int security_member_sid(struct selinux_state *state,
+ u32 ssid,
u32 tsid,
u16 tclass,
u32 *out_sid)
{
- return security_compute_sid(ssid, tsid, tclass,
+ return security_compute_sid(state, ssid, tsid, tclass,
AVTAB_MEMBER, NULL,
out_sid, false);
}
/**
* security_change_sid - Compute the SID for object relabeling.
+ * @state: SELinux state
* @ssid: source security identifier
* @tsid: target security identifier
* @tclass: target security class
@@ -2014,23 +2043,26 @@ int security_member_sid(u32 ssid,
* if insufficient memory is available, or %0 if the SID was
* computed successfully.
*/
-int security_change_sid(u32 ssid,
+int security_change_sid(struct selinux_state *state,
+ u32 ssid,
u32 tsid,
u16 tclass,
u32 *out_sid)
{
- return security_compute_sid(ssid, tsid, tclass, AVTAB_CHANGE, NULL,
+ return security_compute_sid(state,
+ ssid, tsid, tclass, AVTAB_CHANGE, NULL,
out_sid, false);
}
static inline int convert_context_handle_invalid_context(
+ struct selinux_state *state,
struct policydb *policydb,
struct context *context)
{
char *s;
u32 len;
- if (enforcing_enabled())
+ if (enforcing_enabled(state))
return -EINVAL;
if (!context_struct_to_string(policydb, context, &s, &len)) {
@@ -2148,7 +2180,8 @@ int services_convert_context(struct convert_context_args *args,
/* Check the validity of the new context. */
if (!policydb_context_isvalid(args->newp, newc)) {
- rc = convert_context_handle_invalid_context(args->oldp, oldc);
+ rc = convert_context_handle_invalid_context(args->state,
+ args->oldp, oldc);
if (rc)
goto bad;
}
@@ -2167,7 +2200,8 @@ int services_convert_context(struct convert_context_args *args,
return 0;
}
-static void security_load_policycaps(struct selinux_policy *policy)
+static void security_load_policycaps(struct selinux_state *state,
+ struct selinux_policy *policy)
{
struct policydb *p;
unsigned int i;
@@ -2175,8 +2209,8 @@ static void security_load_policycaps(struct selinux_policy *policy)
p = &policy->policydb;
- for (i = 0; i < ARRAY_SIZE(selinux_state.policycap); i++)
- WRITE_ONCE(selinux_state.policycap[i],
+ for (i = 0; i < ARRAY_SIZE(state->policycap); i++)
+ WRITE_ONCE(state->policycap[i],
ebitmap_get_bit(&p->policycaps, i));
for (i = 0; i < ARRAY_SIZE(selinux_policycap_names); i++)
@@ -2212,9 +2246,9 @@ static void selinux_policy_cond_free(struct selinux_policy *policy)
kfree(policy);
}
-void selinux_policy_cancel(struct selinux_load_state *load_state)
+void selinux_policy_cancel(struct selinux_state *state,
+ struct selinux_load_state *load_state)
{
- struct selinux_state *state = &selinux_state;
struct selinux_policy *oldpolicy;
oldpolicy = rcu_dereference_protected(state->policy,
@@ -2225,20 +2259,21 @@ void selinux_policy_cancel(struct selinux_load_state *load_state)
kfree(load_state->convert_data);
}
-static void selinux_notify_policy_change(u32 seqno)
+static void selinux_notify_policy_change(struct selinux_state *state,
+ u32 seqno)
{
/* Flush external caches and notify userspace of policy load */
- avc_ss_reset(seqno);
+ avc_ss_reset(state->avc, seqno);
selnl_notify_policyload(seqno);
- selinux_status_update_policyload(seqno);
+ selinux_status_update_policyload(state, seqno);
selinux_netlbl_cache_invalidate();
selinux_xfrm_notify_policyload();
- selinux_ima_measure_state_locked();
+ selinux_ima_measure_state_locked(state);
}
-void selinux_policy_commit(struct selinux_load_state *load_state)
+void selinux_policy_commit(struct selinux_state *state,
+ struct selinux_load_state *load_state)
{
- struct selinux_state *state = &selinux_state;
struct selinux_policy *oldpolicy, *newpolicy = load_state->policy;
unsigned long flags;
u32 seqno;
@@ -2271,15 +2306,15 @@ void selinux_policy_commit(struct selinux_load_state *load_state)
}
/* Load the policycaps from the new policy */
- security_load_policycaps(newpolicy);
+ security_load_policycaps(state, newpolicy);
- if (!selinux_initialized()) {
+ if (!selinux_initialized(state)) {
/*
* After first policy load, the security server is
* marked as initialized and ready to handle requests and
* any objects created prior to policy load are then labeled.
*/
- selinux_mark_initialized();
+ selinux_mark_initialized(state);
selinux_complete_init();
}
@@ -2289,11 +2324,12 @@ void selinux_policy_commit(struct selinux_load_state *load_state)
kfree(load_state->convert_data);
/* Notify others of the policy change */
- selinux_notify_policy_change(seqno);
+ selinux_notify_policy_change(state, seqno);
}
/**
* security_load_policy - Load a security policy configuration.
+ * @state: SELinux state
* @data: binary policy data
* @len: length of data in bytes
* @load_state: policy load state
@@ -2303,10 +2339,9 @@ void selinux_policy_commit(struct selinux_load_state *load_state)
* This function will flush the access vector cache after
* loading the new policy.
*/
-int security_load_policy(void *data, size_t len,
+int security_load_policy(struct selinux_state *state, void *data, size_t len,
struct selinux_load_state *load_state)
{
- struct selinux_state *state = &selinux_state;
struct selinux_policy *newpolicy, *oldpolicy;
struct selinux_policy_convert_data *convert_data;
int rc = 0;
@@ -2338,7 +2373,7 @@ int security_load_policy(void *data, size_t len,
goto err_mapping;
}
- if (!selinux_initialized()) {
+ if (!selinux_initialized(state)) {
/* First policy load, so no need to preserve state from old policy */
load_state->policy = newpolicy;
load_state->convert_data = NULL;
@@ -2366,6 +2401,7 @@ int security_load_policy(void *data, size_t len,
goto err_free_isids;
}
+ convert_data->args.state = state;
convert_data->args.oldp = &oldpolicy->policydb;
convert_data->args.newp = &newpolicy->policydb;
@@ -2439,11 +2475,13 @@ static int ocontext_to_sid(struct sidtab *sidtab, struct ocontext *c,
/**
* security_port_sid - Obtain the SID for a port.
+ * @state: SELinux state
* @protocol: protocol number
* @port: port number
* @out_sid: security identifier
*/
-int security_port_sid(u8 protocol, u16 port, u32 *out_sid)
+int security_port_sid(struct selinux_state *state,
+ u8 protocol, u16 port, u32 *out_sid)
{
struct selinux_policy *policy;
struct policydb *policydb;
@@ -2451,7 +2489,7 @@ int security_port_sid(u8 protocol, u16 port, u32 *out_sid)
struct ocontext *c;
int rc;
- if (!selinux_initialized()) {
+ if (!selinux_initialized(state)) {
*out_sid = SECINITSID_PORT;
return 0;
}
@@ -2459,7 +2497,7 @@ int security_port_sid(u8 protocol, u16 port, u32 *out_sid)
retry:
rc = 0;
rcu_read_lock();
- policy = rcu_dereference(selinux_state.policy);
+ policy = rcu_dereference(state->policy);
policydb = &policy->policydb;
sidtab = policy->sidtab;
@@ -2491,11 +2529,13 @@ int security_port_sid(u8 protocol, u16 port, u32 *out_sid)
/**
* security_ib_pkey_sid - Obtain the SID for a pkey.
+ * @state: SELinux state
* @subnet_prefix: Subnet Prefix
* @pkey_num: pkey number
* @out_sid: security identifier
*/
-int security_ib_pkey_sid(u64 subnet_prefix, u16 pkey_num, u32 *out_sid)
+int security_ib_pkey_sid(struct selinux_state *state,
+ u64 subnet_prefix, u16 pkey_num, u32 *out_sid)
{
struct selinux_policy *policy;
struct policydb *policydb;
@@ -2503,7 +2543,7 @@ int security_ib_pkey_sid(u64 subnet_prefix, u16 pkey_num, u32 *out_sid)
struct ocontext *c;
int rc;
- if (!selinux_initialized()) {
+ if (!selinux_initialized(state)) {
*out_sid = SECINITSID_UNLABELED;
return 0;
}
@@ -2511,7 +2551,7 @@ int security_ib_pkey_sid(u64 subnet_prefix, u16 pkey_num, u32 *out_sid)
retry:
rc = 0;
rcu_read_lock();
- policy = rcu_dereference(selinux_state.policy);
+ policy = rcu_dereference(state->policy);
policydb = &policy->policydb;
sidtab = policy->sidtab;
@@ -2543,11 +2583,13 @@ int security_ib_pkey_sid(u64 subnet_prefix, u16 pkey_num, u32 *out_sid)
/**
* security_ib_endport_sid - Obtain the SID for a subnet management interface.
+ * @state: SELinux state
* @dev_name: device name
* @port_num: port number
* @out_sid: security identifier
*/
-int security_ib_endport_sid(const char *dev_name, u8 port_num, u32 *out_sid)
+int security_ib_endport_sid(struct selinux_state *state,
+ const char *dev_name, u8 port_num, u32 *out_sid)
{
struct selinux_policy *policy;
struct policydb *policydb;
@@ -2555,7 +2597,7 @@ int security_ib_endport_sid(const char *dev_name, u8 port_num, u32 *out_sid)
struct ocontext *c;
int rc;
- if (!selinux_initialized()) {
+ if (!selinux_initialized(state)) {
*out_sid = SECINITSID_UNLABELED;
return 0;
}
@@ -2563,7 +2605,7 @@ int security_ib_endport_sid(const char *dev_name, u8 port_num, u32 *out_sid)
retry:
rc = 0;
rcu_read_lock();
- policy = rcu_dereference(selinux_state.policy);
+ policy = rcu_dereference(state->policy);
policydb = &policy->policydb;
sidtab = policy->sidtab;
@@ -2596,10 +2638,12 @@ int security_ib_endport_sid(const char *dev_name, u8 port_num, u32 *out_sid)
/**
* security_netif_sid - Obtain the SID for a network interface.
+ * @state: SELinux state
* @name: interface name
* @if_sid: interface SID
*/
-int security_netif_sid(const char *name, u32 *if_sid)
+int security_netif_sid(struct selinux_state *state,
+ const char *name, u32 *if_sid)
{
struct selinux_policy *policy;
struct policydb *policydb;
@@ -2608,7 +2652,7 @@ int security_netif_sid(const char *name, u32 *if_sid)
struct ocontext *c;
bool wildcard_support;
- if (!selinux_initialized()) {
+ if (!selinux_initialized(state)) {
*if_sid = SECINITSID_NETIF;
return 0;
}
@@ -2616,7 +2660,7 @@ int security_netif_sid(const char *name, u32 *if_sid)
retry:
rc = 0;
rcu_read_lock();
- policy = rcu_dereference(selinux_state.policy);
+ policy = rcu_dereference(state->policy);
policydb = &policy->policydb;
sidtab = policy->sidtab;
wildcard_support = ebitmap_get_bit(&policydb->policycaps, POLICYDB_CAP_NETIF_WILDCARD);
@@ -2663,12 +2707,14 @@ static bool match_ipv6_addrmask(const u32 input[4], const u32 addr[4], const u32
/**
* security_node_sid - Obtain the SID for a node (host).
+ * @state: SELinux state
* @domain: communication domain aka address family
* @addrp: address
* @addrlen: address length in bytes
* @out_sid: security identifier
*/
-int security_node_sid(u16 domain,
+int security_node_sid(struct selinux_state *state,
+ u16 domain,
const void *addrp,
u32 addrlen,
u32 *out_sid)
@@ -2679,14 +2725,14 @@ int security_node_sid(u16 domain,
int rc;
struct ocontext *c;
- if (!selinux_initialized()) {
+ if (!selinux_initialized(state)) {
*out_sid = SECINITSID_NODE;
return 0;
}
retry:
rcu_read_lock();
- policy = rcu_dereference(selinux_state.policy);
+ policy = rcu_dereference(state->policy);
policydb = &policy->policydb;
sidtab = policy->sidtab;
@@ -2750,6 +2796,7 @@ int security_node_sid(u16 domain,
/**
* security_get_user_sids - Obtain reachable SIDs for a user.
+ * @state: SELinux state
* @fromsid: starting SID
* @username: username
* @sids: array of reachable SIDs for user
@@ -2762,7 +2809,9 @@ int security_node_sid(u16 domain,
* number of elements in the array.
*/
-int security_get_user_sids(u32 fromsid,
+
+int security_get_user_sids(struct selinux_state *state,
+ u32 fromsid,
const char *username,
u32 **sids,
u32 *nel)
@@ -2781,7 +2830,7 @@ int security_get_user_sids(u32 fromsid,
*sids = NULL;
*nel = 0;
- if (!selinux_initialized())
+ if (!selinux_initialized(state))
return 0;
mysids = kcalloc(maxnel, sizeof(*mysids), GFP_KERNEL);
@@ -2791,7 +2840,7 @@ int security_get_user_sids(u32 fromsid,
retry:
mynel = 0;
rcu_read_lock();
- policy = rcu_dereference(selinux_state.policy);
+ policy = rcu_dereference(state->policy);
policydb = &policy->policydb;
sidtab = policy->sidtab;
@@ -2857,7 +2906,8 @@ int security_get_user_sids(u32 fromsid,
}
for (i = 0, j = 0; i < mynel; i++) {
struct av_decision dummy_avd;
- rc = avc_has_perm_noaudit(fromsid, mysids[i],
+ rc = avc_has_perm_noaudit(state,
+ fromsid, mysids[i],
SECCLASS_PROCESS, /* kernel value */
PROCESS__TRANSITION, AVC_STRICT,
&dummy_avd);
@@ -2939,6 +2989,7 @@ static inline int __security_genfs_sid(struct selinux_policy *policy,
/**
* security_genfs_sid - Obtain a SID for a file in a filesystem
+ * @state: SELinux state
* @fstype: filesystem type
* @path: path from root of mount
* @orig_sclass: file security class
@@ -2947,7 +2998,8 @@ static inline int __security_genfs_sid(struct selinux_policy *policy,
* Acquire policy_rwlock before calling __security_genfs_sid() and release
* it afterward.
*/
-int security_genfs_sid(const char *fstype,
+int security_genfs_sid(struct selinux_state *state,
+ const char *fstype,
const char *path,
u16 orig_sclass,
u32 *sid)
@@ -2955,14 +3007,14 @@ int security_genfs_sid(const char *fstype,
struct selinux_policy *policy;
int retval;
- if (!selinux_initialized()) {
+ if (!selinux_initialized(state)) {
*sid = SECINITSID_UNLABELED;
return 0;
}
do {
rcu_read_lock();
- policy = rcu_dereference(selinux_state.policy);
+ policy = rcu_dereference(state->policy);
retval = __security_genfs_sid(policy, fstype, path,
orig_sclass, sid);
rcu_read_unlock();
@@ -2982,9 +3034,10 @@ int selinux_policy_genfs_sid(struct selinux_policy *policy,
/**
* security_fs_use - Determine how to handle labeling for a filesystem.
+ * @state: SELinux state
* @sb: superblock in question
*/
-int security_fs_use(struct super_block *sb)
+int security_fs_use(struct selinux_state *state, struct super_block *sb)
{
struct selinux_policy *policy;
struct policydb *policydb;
@@ -2994,7 +3047,7 @@ int security_fs_use(struct super_block *sb)
struct superblock_security_struct *sbsec = selinux_superblock(sb);
const char *fstype = sb->s_type->name;
- if (!selinux_initialized()) {
+ if (!selinux_initialized(state)) {
sbsec->behavior = SECURITY_FS_USE_NONE;
sbsec->sid = SECINITSID_UNLABELED;
return 0;
@@ -3002,7 +3055,7 @@ int security_fs_use(struct super_block *sb)
retry:
rcu_read_lock();
- policy = rcu_dereference(selinux_state.policy);
+ policy = rcu_dereference(state->policy);
policydb = &policy->policydb;
sidtab = policy->sidtab;
@@ -3095,14 +3148,14 @@ int security_get_bools(struct selinux_policy *policy,
}
-int security_set_bools(u32 len, const int *values)
+int security_set_bools(struct selinux_state *state, u32 len,
+ const int *values)
{
- struct selinux_state *state = &selinux_state;
struct selinux_policy *newpolicy, *oldpolicy;
int rc;
u32 i, seqno = 0;
- if (!selinux_initialized())
+ if (!selinux_initialized(state))
return -EINVAL;
oldpolicy = rcu_dereference_protected(state->policy,
@@ -3163,22 +3216,23 @@ int security_set_bools(u32 len, const int *values)
selinux_policy_cond_free(oldpolicy);
/* Notify others of the policy change */
- selinux_notify_policy_change(seqno);
+ selinux_notify_policy_change(state, seqno);
return 0;
}
-int security_get_bool_value(u32 index)
+int security_get_bool_value(struct selinux_state *state,
+ u32 index)
{
struct selinux_policy *policy;
struct policydb *policydb;
int rc;
u32 len;
- if (!selinux_initialized())
+ if (!selinux_initialized(state))
return 0;
rcu_read_lock();
- policy = rcu_dereference(selinux_state.policy);
+ policy = rcu_dereference(state->policy);
policydb = &policy->policydb;
rc = -EFAULT;
@@ -3225,7 +3279,8 @@ static int security_preserve_bools(struct selinux_policy *oldpolicy,
* security_sid_mls_copy() - computes a new sid based on the given
* sid and the mls portion of mls_sid.
*/
-int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid)
+int security_sid_mls_copy(struct selinux_state *state,
+ u32 sid, u32 mls_sid, u32 *new_sid)
{
struct selinux_policy *policy;
struct policydb *policydb;
@@ -3237,7 +3292,7 @@ int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid)
u32 len;
int rc;
- if (!selinux_initialized()) {
+ if (!selinux_initialized(state)) {
*new_sid = sid;
return 0;
}
@@ -3247,7 +3302,7 @@ int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid)
context_init(&newcon);
rcu_read_lock();
- policy = rcu_dereference(selinux_state.policy);
+ policy = rcu_dereference(state->policy);
policydb = &policy->policydb;
sidtab = policy->sidtab;
@@ -3281,7 +3336,7 @@ int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid)
/* Check the validity of the new context. */
if (!policydb_context_isvalid(policydb, &newcon)) {
- rc = convert_context_handle_invalid_context(policydb,
+ rc = convert_context_handle_invalid_context(state, policydb,
&newcon);
if (rc) {
if (!context_struct_to_string(policydb, &newcon, &s,
@@ -3315,6 +3370,7 @@ int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid)
/**
* security_net_peersid_resolve - Compare and resolve two network peer SIDs
+ * @state: SELinux state
* @nlbl_sid: NetLabel SID
* @nlbl_type: NetLabel labeling protocol type
* @xfrm_sid: XFRM SID
@@ -3334,7 +3390,8 @@ int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid)
* multiple, inconsistent labels | -<errno> | SECSID_NULL
*
*/
-int security_net_peersid_resolve(u32 nlbl_sid, u32 nlbl_type,
+int security_net_peersid_resolve(struct selinux_state *state,
+ u32 nlbl_sid, u32 nlbl_type,
u32 xfrm_sid,
u32 *peer_sid)
{
@@ -3362,11 +3419,11 @@ int security_net_peersid_resolve(u32 nlbl_sid, u32 nlbl_type,
return 0;
}
- if (!selinux_initialized())
+ if (!selinux_initialized(state))
return 0;
rcu_read_lock();
- policy = rcu_dereference(selinux_state.policy);
+ policy = rcu_dereference(state->policy);
policydb = &policy->policydb;
sidtab = policy->sidtab;
@@ -3509,31 +3566,31 @@ int security_get_permissions(struct selinux_policy *policy,
return rc;
}
-int security_get_reject_unknown(void)
+int security_get_reject_unknown(struct selinux_state *state)
{
struct selinux_policy *policy;
int value;
- if (!selinux_initialized())
+ if (!selinux_initialized(state))
return 0;
rcu_read_lock();
- policy = rcu_dereference(selinux_state.policy);
+ policy = rcu_dereference(state->policy);
value = policy->policydb.reject_unknown;
rcu_read_unlock();
return value;
}
-int security_get_allow_unknown(void)
+int security_get_allow_unknown(struct selinux_state *state)
{
struct selinux_policy *policy;
int value;
- if (!selinux_initialized())
+ if (!selinux_initialized(state))
return 0;
rcu_read_lock();
- policy = rcu_dereference(selinux_state.policy);
+ policy = rcu_dereference(state->policy);
value = policy->policydb.allow_unknown;
rcu_read_unlock();
return value;
@@ -3541,6 +3598,7 @@ int security_get_allow_unknown(void)
/**
* security_policycap_supported - Check for a specific policy capability
+ * @state: SELinux state
* @req_cap: capability
*
* Description:
@@ -3549,16 +3607,17 @@ int security_get_allow_unknown(void)
* supported, false (0) if it isn't supported.
*
*/
-int security_policycap_supported(unsigned int req_cap)
+int security_policycap_supported(struct selinux_state *state,
+ unsigned int req_cap)
{
struct selinux_policy *policy;
int rc;
- if (!selinux_initialized())
+ if (!selinux_initialized(state))
return 0;
rcu_read_lock();
- policy = rcu_dereference(selinux_state.policy);
+ policy = rcu_dereference(state->policy);
rc = ebitmap_get_bit(&policy->policydb.policycaps, req_cap);
rcu_read_unlock();
@@ -3595,7 +3654,7 @@ int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule,
*rule = NULL;
- if (!selinux_initialized())
+ if (!selinux_initialized(state))
return -EOPNOTSUPP;
switch (field) {
@@ -3720,7 +3779,7 @@ int selinux_audit_rule_match(struct lsm_prop *prop, u32 field, u32 op, void *vru
return -ENOENT;
}
- if (!selinux_initialized())
+ if (!selinux_initialized(state))
return 0;
rcu_read_lock();
@@ -3873,6 +3932,7 @@ static void security_netlbl_cache_add(struct netlbl_lsm_secattr *secattr,
/**
* security_netlbl_secattr_to_sid - Convert a NetLabel secattr to a SELinux SID
+ * @state: SELinux state
* @secattr: the NetLabel packet security attributes
* @sid: the SELinux SID
*
@@ -3886,7 +3946,8 @@ static void security_netlbl_cache_add(struct netlbl_lsm_secattr *secattr,
* failure.
*
*/
-int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr,
+int security_netlbl_secattr_to_sid(struct selinux_state *state,
+ struct netlbl_lsm_secattr *secattr,
u32 *sid)
{
struct selinux_policy *policy;
@@ -3896,7 +3957,7 @@ int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr,
struct context *ctx;
struct context ctx_new;
- if (!selinux_initialized()) {
+ if (!selinux_initialized(state)) {
*sid = SECSID_NULL;
return 0;
}
@@ -3904,7 +3965,7 @@ int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr,
retry:
rc = 0;
rcu_read_lock();
- policy = rcu_dereference(selinux_state.policy);
+ policy = rcu_dereference(state->policy);
policydb = &policy->policydb;
sidtab = policy->sidtab;
@@ -3954,6 +4015,7 @@ int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr,
/**
* security_netlbl_sid_to_secattr - Convert a SELinux SID to a NetLabel secattr
+ * @state: SELinux state
* @sid: the SELinux SID
* @secattr: the NetLabel packet security attributes
*
@@ -3962,18 +4024,19 @@ int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr,
* Returns zero on success, negative values on failure.
*
*/
-int security_netlbl_sid_to_secattr(u32 sid, struct netlbl_lsm_secattr *secattr)
+int security_netlbl_sid_to_secattr(struct selinux_state *state,
+ u32 sid, struct netlbl_lsm_secattr *secattr)
{
struct selinux_policy *policy;
struct policydb *policydb;
int rc;
struct context *ctx;
- if (!selinux_initialized())
+ if (!selinux_initialized(state))
return 0;
rcu_read_lock();
- policy = rcu_dereference(selinux_state.policy);
+ policy = rcu_dereference(state->policy);
policydb = &policy->policydb;
rc = -ENOENT;
@@ -4023,13 +4086,14 @@ static int __security_read_policy(struct selinux_policy *policy,
/**
* security_read_policy - read the policy.
+ * @state: selinux_state
* @data: binary policy data
* @len: length of data in bytes
*
*/
-int security_read_policy(void **data, size_t *len)
+int security_read_policy(struct selinux_state *state,
+ void **data, size_t *len)
{
- struct selinux_state *state = &selinux_state;
struct selinux_policy *policy;
policy = rcu_dereference_protected(
@@ -4047,6 +4111,7 @@ int security_read_policy(void **data, size_t *len)
/**
* security_read_state_kernel - read the policy.
+ * @state: selinux_state
* @data: binary policy data
* @len: length of data in bytes
*
@@ -4056,10 +4121,10 @@ int security_read_policy(void **data, size_t *len)
*
* This function must be called with policy_mutex held.
*/
-int security_read_state_kernel(void **data, size_t *len)
+int security_read_state_kernel(struct selinux_state *state,
+ void **data, size_t *len)
{
int err;
- struct selinux_state *state = &selinux_state;
struct selinux_policy *policy;
policy = rcu_dereference_protected(
diff --git a/security/selinux/ss/services.h b/security/selinux/ss/services.h
index 93358e7a649c..8696f9300529 100644
--- a/security/selinux/ss/services.h
+++ b/security/selinux/ss/services.h
@@ -31,6 +31,7 @@ struct selinux_policy {
} __randomize_layout;
struct convert_context_args {
+ struct selinux_state *state;
struct policydb *oldp;
struct policydb *newp;
};
diff --git a/security/selinux/status.c b/security/selinux/status.c
index dffca22ce6f7..e9ba1dae06e1 100644
--- a/security/selinux/status.c
+++ b/security/selinux/status.c
@@ -39,21 +39,21 @@
* It returns a reference to selinux_status_page. If the status page is
* not allocated yet, it also tries to allocate it at the first time.
*/
-struct page *selinux_kernel_status_page(void)
+struct page *selinux_kernel_status_page(struct selinux_state *state)
{
struct selinux_kernel_status *status;
struct page *result = NULL;
- mutex_lock(&selinux_state.status_lock);
- if (!selinux_state.status_page) {
- selinux_state.status_page = alloc_page(GFP_KERNEL|__GFP_ZERO);
+ mutex_lock(&state->status_lock);
+ if (!state->status_page) {
+ state->status_page = alloc_page(GFP_KERNEL|__GFP_ZERO);
- if (selinux_state.status_page) {
- status = page_address(selinux_state.status_page);
+ if (state->status_page) {
+ status = page_address(state->status_page);
status->version = SELINUX_KERNEL_STATUS_VERSION;
status->sequence = 0;
- status->enforcing = enforcing_enabled();
+ status->enforcing = enforcing_enabled(state);
/*
* NOTE: the next policyload event shall set
* a positive value on the status->policyload,
@@ -62,11 +62,11 @@ struct page *selinux_kernel_status_page(void)
*/
status->policyload = 0;
status->deny_unknown =
- !security_get_allow_unknown();
+ !security_get_allow_unknown(state);
}
}
- result = selinux_state.status_page;
- mutex_unlock(&selinux_state.status_lock);
+ result = state->status_page;
+ mutex_unlock(&state->status_lock);
return result;
}
@@ -76,13 +76,14 @@ struct page *selinux_kernel_status_page(void)
*
* It updates status of the current enforcing/permissive mode.
*/
-void selinux_status_update_setenforce(bool enforcing)
+void selinux_status_update_setenforce(struct selinux_state *state,
+ bool enforcing)
{
struct selinux_kernel_status *status;
- mutex_lock(&selinux_state.status_lock);
- if (selinux_state.status_page) {
- status = page_address(selinux_state.status_page);
+ mutex_lock(&state->status_lock);
+ if (state->status_page) {
+ status = page_address(state->status_page);
status->sequence++;
smp_wmb();
@@ -92,7 +93,7 @@ void selinux_status_update_setenforce(bool enforcing)
smp_wmb();
status->sequence++;
}
- mutex_unlock(&selinux_state.status_lock);
+ mutex_unlock(&state->status_lock);
}
/*
@@ -101,22 +102,23 @@ void selinux_status_update_setenforce(bool enforcing)
* It updates status of the times of policy reloaded, and current
* setting of deny_unknown.
*/
-void selinux_status_update_policyload(u32 seqno)
+void selinux_status_update_policyload(struct selinux_state *state,
+ u32 seqno)
{
struct selinux_kernel_status *status;
- mutex_lock(&selinux_state.status_lock);
- if (selinux_state.status_page) {
- status = page_address(selinux_state.status_page);
+ mutex_lock(&state->status_lock);
+ if (state->status_page) {
+ status = page_address(state->status_page);
status->sequence++;
smp_wmb();
status->policyload = seqno;
- status->deny_unknown = !security_get_allow_unknown();
+ status->deny_unknown = !security_get_allow_unknown(state);
smp_wmb();
status->sequence++;
}
- mutex_unlock(&selinux_state.status_lock);
+ mutex_unlock(&state->status_lock);
}
diff --git a/security/selinux/xfrm.c b/security/selinux/xfrm.c
index 61d56b0c2be1..47db3522a2ce 100644
--- a/security/selinux/xfrm.c
+++ b/security/selinux/xfrm.c
@@ -97,12 +97,13 @@ static int selinux_xfrm_alloc_user(struct xfrm_sec_ctx **ctxp,
ctx->ctx_len = str_len + 1;
memcpy(ctx->ctx_str, &uctx[1], str_len);
ctx->ctx_str[str_len] = '\0';
- rc = security_context_to_sid(ctx->ctx_str, str_len,
+ rc = security_context_to_sid(&selinux_state, ctx->ctx_str, str_len,
&ctx->ctx_sid, gfp);
if (rc)
goto err;
- rc = avc_has_perm(current_sid(), ctx->ctx_sid,
+ rc = avc_has_perm(&selinux_state,
+ current_sid(), ctx->ctx_sid,
SECCLASS_ASSOCIATION, ASSOCIATION__SETCONTEXT, NULL);
if (rc)
goto err;
@@ -136,7 +137,8 @@ static int selinux_xfrm_delete(struct xfrm_sec_ctx *ctx)
if (!ctx)
return 0;
- return avc_has_perm(current_sid(), ctx->ctx_sid,
+ return avc_has_perm(&selinux_state,
+ current_sid(), ctx->ctx_sid,
SECCLASS_ASSOCIATION, ASSOCIATION__SETCONTEXT,
NULL);
}
@@ -158,7 +160,8 @@ int selinux_xfrm_policy_lookup(struct xfrm_sec_ctx *ctx, u32 fl_secid)
if (!selinux_authorizable_ctx(ctx))
return -EINVAL;
- rc = avc_has_perm(fl_secid, ctx->ctx_sid,
+ rc = avc_has_perm(&selinux_state,
+ fl_secid, ctx->ctx_sid,
SECCLASS_ASSOCIATION, ASSOCIATION__POLMATCH, NULL);
return (rc == -EACCES ? -ESRCH : rc);
}
@@ -199,7 +202,7 @@ int selinux_xfrm_state_pol_flow_match(struct xfrm_state *x,
/* We don't need a separate SA Vs. policy polmatch check since the SA
* is now of the same label as the flow and a flow Vs. policy polmatch
* check had already happened in selinux_xfrm_policy_lookup() above. */
- return (avc_has_perm(flic_sid, state_sid,
+ return (avc_has_perm(&selinux_state, flic_sid, state_sid,
SECCLASS_ASSOCIATION, ASSOCIATION__SENDTO,
NULL) ? 0 : 1);
}
@@ -349,7 +352,7 @@ int selinux_xfrm_state_alloc_acquire(struct xfrm_state *x,
if (secid == 0)
return -EINVAL;
- rc = security_sid_to_context(secid, &ctx_str,
+ rc = security_sid_to_context(&selinux_state, secid, &ctx_str,
&str_len);
if (rc)
return rc;
@@ -418,7 +421,8 @@ int selinux_xfrm_sock_rcv_skb(u32 sk_sid, struct sk_buff *skb,
/* This check even when there's no association involved is intended,
* according to Trent Jaeger, to make sure a process can't engage in
* non-IPsec communication unless explicitly allowed by policy. */
- return avc_has_perm(sk_sid, peer_sid,
+ return avc_has_perm(&selinux_state,
+ sk_sid, peer_sid,
SECCLASS_ASSOCIATION, ASSOCIATION__RECVFROM, ad);
}
@@ -461,6 +465,6 @@ int selinux_xfrm_postroute_last(u32 sk_sid, struct sk_buff *skb,
/* This check even when there's no association involved is intended,
* according to Trent Jaeger, to make sure a process can't engage in
* non-IPsec communication unless explicitly allowed by policy. */
- return avc_has_perm(sk_sid, SECINITSID_UNLABELED,
+ return avc_has_perm(&selinux_state, sk_sid, SECINITSID_UNLABELED,
SECCLASS_ASSOCIATION, ASSOCIATION__SENDTO, ad);
}
--
2.50.1
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [PATCH v7 02/42] selinux: introduce current_selinux_state
2025-08-14 13:25 [PATCH v7 00/42] SELinux namespace support Stephen Smalley
2025-08-14 13:25 ` [PATCH v7 01/42] selinux: restore passing of selinux_state Stephen Smalley
@ 2025-08-14 13:25 ` Stephen Smalley
2025-08-14 13:25 ` [PATCH v7 03/42] selinux: support multiple selinuxfs instances Stephen Smalley
` (39 subsequent siblings)
41 siblings, 0 replies; 43+ messages in thread
From: Stephen Smalley @ 2025-08-14 13:25 UTC (permalink / raw)
To: selinux; +Cc: paul, omosnace, netdev, horms, Stephen Smalley
Rename selinux_state to init_selinux_state, make it static, and
introduce a current_selinux_state pointer initialized to it that
can be used everywhere we were previously directly referencing
selinux_state. This is in preparation for future changes where
multiple selinux states (aka namespaces) will be supported and
current_selinux_state will refer to the correct one for the current
process.
Note that passing the current selinux state is not correct for
all hooks; some hooks will need to be adjusted to pass the selinux
state associated with an open file, a network namespace or socket,
etc, since not all hooks are invoked in process context and some
hooks operate in the context of a cred that may differ from current's
cred. Fixing all of these cases is left to future changes, once
we introduce the support for multiple selinux namespaces.
This change by itself should have no effect on SELinux behavior or
APIs (userspace or LSM).
Signed-off-by: Stephen Smalley <stephen.smalley.work@gmail.com>
---
security/selinux/hooks.c | 428 ++++++++++++++--------------
security/selinux/ibpkey.c | 2 +-
security/selinux/include/objsec.h | 3 +-
security/selinux/include/security.h | 33 ++-
security/selinux/netif.c | 2 +-
security/selinux/netlabel.c | 12 +-
security/selinux/netnode.c | 4 +-
security/selinux/netport.c | 2 +-
security/selinux/selinuxfs.c | 36 +--
security/selinux/ss/services.c | 4 +-
security/selinux/xfrm.c | 16 +-
11 files changed, 278 insertions(+), 264 deletions(-)
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 0c503700d1df..d45a3ac9ded6 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -107,7 +107,8 @@
#define SELINUX_INODE_INIT_XATTRS 1
-struct selinux_state selinux_state;
+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);
@@ -279,7 +280,7 @@ static int __inode_security_revalidate(struct inode *inode,
struct dentry *dentry,
bool may_sleep)
{
- if (!selinux_initialized(&selinux_state))
+ if (!selinux_initialized(current_selinux_state))
return 0;
if (may_sleep)
@@ -440,13 +441,13 @@ static int may_context_mount_sb_relabel(u32 sid,
const struct task_security_struct *tsec = selinux_cred(cred);
int rc;
- rc = avc_has_perm(&selinux_state,
+ rc = avc_has_perm(current_selinux_state,
tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
FILESYSTEM__RELABELFROM, NULL);
if (rc)
return rc;
- rc = avc_has_perm(&selinux_state,
+ rc = avc_has_perm(current_selinux_state,
tsec->sid, sid, SECCLASS_FILESYSTEM,
FILESYSTEM__RELABELTO, NULL);
return rc;
@@ -458,13 +459,13 @@ static int may_context_mount_inode_relabel(u32 sid,
{
const struct task_security_struct *tsec = selinux_cred(cred);
int rc;
- rc = avc_has_perm(&selinux_state,
+ rc = avc_has_perm(current_selinux_state,
tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
FILESYSTEM__RELABELFROM, NULL);
if (rc)
return rc;
- rc = avc_has_perm(&selinux_state,
+ rc = avc_has_perm(current_selinux_state,
sid, sbsec->sid, SECCLASS_FILESYSTEM,
FILESYSTEM__ASSOCIATE, NULL);
return rc;
@@ -548,7 +549,7 @@ static int sb_check_xattr_support(struct super_block *sb)
fallback:
/* No xattr support - try to fallback to genfs if possible. */
- rc = security_genfs_sid(&selinux_state, sb->s_type->name, "/",
+ rc = security_genfs_sid(current_selinux_state, sb->s_type->name, "/",
SECCLASS_DIR, &sid);
if (rc)
return -EOPNOTSUPP;
@@ -659,7 +660,7 @@ static int selinux_set_mnt_opts(struct super_block *sb,
mutex_lock(&sbsec->lock);
- if (!selinux_initialized(&selinux_state)) {
+ if (!selinux_initialized(current_selinux_state)) {
if (!opts) {
/* Defer initialization until selinux_complete_init,
after the initial policy is loaded and the security
@@ -758,7 +759,7 @@ static int selinux_set_mnt_opts(struct super_block *sb,
* Determine the labeling behavior to use for this
* filesystem type.
*/
- rc = security_fs_use(&selinux_state, sb);
+ rc = security_fs_use(current_selinux_state, sb);
if (rc) {
pr_warn("%s: security_fs_use(%s) returned %d\n",
__func__, sb->s_type->name, rc);
@@ -783,7 +784,7 @@ static int selinux_set_mnt_opts(struct super_block *sb,
}
if (sbsec->behavior == SECURITY_FS_USE_XATTR) {
sbsec->behavior = SECURITY_FS_USE_MNTPOINT;
- rc = security_transition_sid(&selinux_state,
+ rc = security_transition_sid(current_selinux_state,
current_sid(),
current_sid(),
SECCLASS_FILE, NULL,
@@ -942,7 +943,7 @@ static int selinux_sb_clone_mnt_opts(const struct super_block *oldsb,
* if the parent was able to be mounted it clearly had no special lsm
* mount options. thus we can safely deal with this superblock later
*/
- if (!selinux_initialized(&selinux_state)) {
+ if (!selinux_initialized(current_selinux_state)) {
if (kern_flags & SECURITY_LSM_NATIVE_LABELS) {
newsbsec->flags |= SE_SBNATIVE;
*set_kern_flags |= SECURITY_LSM_NATIVE_LABELS;
@@ -969,7 +970,7 @@ static int selinux_sb_clone_mnt_opts(const struct super_block *oldsb,
if (newsbsec->behavior == SECURITY_FS_USE_NATIVE &&
!(kern_flags & SECURITY_LSM_NATIVE_LABELS) && !set_context) {
- rc = security_fs_use(&selinux_state, newsb);
+ rc = security_fs_use(current_selinux_state, newsb);
if (rc)
goto out;
}
@@ -1018,7 +1019,7 @@ static int selinux_add_opt(int token, const char *s, void **mnt_opts)
if (!s)
return -EINVAL;
- if (!selinux_initialized(&selinux_state)) {
+ if (!selinux_initialized(current_selinux_state)) {
pr_warn("SELinux: Unable to set superblock options before the security server is initialized\n");
return -EINVAL;
}
@@ -1055,7 +1056,8 @@ static int selinux_add_opt(int token, const char *s, void **mnt_opts)
WARN_ON(1);
return -EINVAL;
}
- rc = security_context_str_to_sid(&selinux_state, s, dst_sid, GFP_KERNEL);
+ rc = security_context_str_to_sid(current_selinux_state, s, dst_sid,
+ GFP_KERNEL);
if (rc)
pr_warn("SELinux: security_context_str_to_sid (%s) failed with errno=%d\n",
s, rc);
@@ -1072,7 +1074,7 @@ static int show_sid(struct seq_file *m, u32 sid)
u32 len;
int rc;
- rc = security_sid_to_context(&selinux_state, sid,
+ rc = security_sid_to_context(current_selinux_state, sid,
&context, &len);
if (!rc) {
bool has_comma = strchr(context, ',');
@@ -1096,7 +1098,7 @@ static int selinux_sb_show_options(struct seq_file *m, struct super_block *sb)
if (!(sbsec->flags & SE_SBINITIALIZED))
return 0;
- if (!selinux_initialized(&selinux_state))
+ if (!selinux_initialized(current_selinux_state))
return 0;
if (sbsec->flags & FSCONTEXT_MNT) {
@@ -1348,7 +1350,7 @@ static int selinux_genfs_get_sid(struct dentry *dentry,
path++;
}
}
- rc = security_genfs_sid(&selinux_state, sb->s_type->name,
+ rc = security_genfs_sid(current_selinux_state, sb->s_type->name,
path, tclass, sid);
if (rc == -ENOENT) {
/* No match in policy, mark as unlabeled. */
@@ -1403,8 +1405,8 @@ static int inode_doinit_use_xattr(struct inode *inode, struct dentry *dentry,
return 0;
}
- rc = security_context_to_sid_default(&selinux_state, context, rc, sid,
- def_sid, GFP_NOFS);
+ rc = security_context_to_sid_default(current_selinux_state, context, rc,
+ sid, def_sid, GFP_NOFS);
if (rc) {
char *dev = inode->i_sb->s_id;
unsigned long ino = inode->i_ino;
@@ -1513,7 +1515,7 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
sid = sbsec->sid;
/* Try to obtain a transition SID. */
- rc = security_transition_sid(&selinux_state, task_sid, sid,
+ rc = security_transition_sid(current_selinux_state, task_sid, sid,
sclass, NULL, &sid);
if (rc)
goto out;
@@ -1658,10 +1660,10 @@ static int cred_has_capability(const struct cred *cred,
return -EINVAL;
}
- rc = avc_has_perm_noaudit(&selinux_state,
+ rc = avc_has_perm_noaudit(current_selinux_state,
sid, sid, sclass, av, 0, &avd);
if (!(opts & CAP_OPT_NOAUDIT)) {
- int rc2 = avc_audit(&selinux_state,
+ int rc2 = avc_audit(current_selinux_state,
sid, sid, sclass, av, &avd, rc, &ad);
if (rc2)
return rc2;
@@ -1686,7 +1688,7 @@ static int inode_has_perm(const struct cred *cred,
sid = cred_sid(cred);
isec = selinux_inode(inode);
- return avc_has_perm(&selinux_state,
+ return avc_has_perm(current_selinux_state,
sid, isec->sid, isec->sclass, perms, adp);
}
@@ -1766,7 +1768,7 @@ static int file_has_perm(const struct cred *cred,
ad.u.file = file;
if (sid != fsec->sid) {
- rc = avc_has_perm(&selinux_state,
+ rc = avc_has_perm(current_selinux_state,
sid, fsec->sid,
SECCLASS_FD,
FD__USE,
@@ -1810,7 +1812,7 @@ selinux_determine_inode_label(const struct task_security_struct *tsec,
*_new_isid = tsec->create_sid;
} else {
const struct inode_security_struct *dsec = inode_security(dir);
- return security_transition_sid(&selinux_state, tsec->sid,
+ return security_transition_sid(current_selinux_state, tsec->sid,
dsec->sid, tclass,
name, _new_isid);
}
@@ -1838,7 +1840,7 @@ static int may_create(struct inode *dir,
ad.type = LSM_AUDIT_DATA_DENTRY;
ad.u.dentry = dentry;
- rc = avc_has_perm(&selinux_state,
+ rc = avc_has_perm(current_selinux_state,
sid, dsec->sid, SECCLASS_DIR,
DIR__ADD_NAME | DIR__SEARCH,
&ad);
@@ -1850,12 +1852,12 @@ static int may_create(struct inode *dir,
if (rc)
return rc;
- rc = avc_has_perm(&selinux_state,
+ rc = avc_has_perm(current_selinux_state,
sid, newsid, tclass, FILE__CREATE, &ad);
if (rc)
return rc;
- return avc_has_perm(&selinux_state,
+ return avc_has_perm(current_selinux_state,
newsid, sbsec->sid,
SECCLASS_FILESYSTEM,
FILESYSTEM__ASSOCIATE, &ad);
@@ -1885,7 +1887,7 @@ static int may_link(struct inode *dir,
av = DIR__SEARCH;
av |= (kind ? DIR__REMOVE_NAME : DIR__ADD_NAME);
- rc = avc_has_perm(&selinux_state,
+ rc = avc_has_perm(current_selinux_state,
sid, dsec->sid, SECCLASS_DIR, av, &ad);
if (rc)
return rc;
@@ -1906,7 +1908,7 @@ static int may_link(struct inode *dir,
return 0;
}
- rc = avc_has_perm(&selinux_state,
+ rc = avc_has_perm(current_selinux_state,
sid, isec->sid, isec->sclass, av, &ad);
return rc;
}
@@ -1931,18 +1933,18 @@ static inline int may_rename(struct inode *old_dir,
ad.type = LSM_AUDIT_DATA_DENTRY;
ad.u.dentry = old_dentry;
- rc = avc_has_perm(&selinux_state,
+ rc = avc_has_perm(current_selinux_state,
sid, old_dsec->sid, SECCLASS_DIR,
DIR__REMOVE_NAME | DIR__SEARCH, &ad);
if (rc)
return rc;
- rc = avc_has_perm(&selinux_state,
+ rc = avc_has_perm(current_selinux_state,
sid, old_isec->sid,
old_isec->sclass, FILE__RENAME, &ad);
if (rc)
return rc;
if (old_is_dir && new_dir != old_dir) {
- rc = avc_has_perm(&selinux_state,
+ rc = avc_has_perm(current_selinux_state,
sid, old_isec->sid,
old_isec->sclass, DIR__REPARENT, &ad);
if (rc)
@@ -1953,14 +1955,14 @@ static inline int may_rename(struct inode *old_dir,
av = DIR__ADD_NAME | DIR__SEARCH;
if (d_is_positive(new_dentry))
av |= DIR__REMOVE_NAME;
- rc = avc_has_perm(&selinux_state,
+ rc = avc_has_perm(current_selinux_state,
sid, new_dsec->sid, SECCLASS_DIR, av, &ad);
if (rc)
return rc;
if (d_is_positive(new_dentry)) {
new_isec = backing_inode_security(new_dentry);
new_is_dir = d_is_dir(new_dentry);
- rc = avc_has_perm(&selinux_state,
+ rc = avc_has_perm(current_selinux_state,
sid, new_isec->sid,
new_isec->sclass,
(new_is_dir ? DIR__RMDIR : FILE__UNLINK), &ad);
@@ -1981,7 +1983,7 @@ static int superblock_has_perm(const struct cred *cred,
u32 sid = cred_sid(cred);
sbsec = selinux_superblock(sb);
- return avc_has_perm(&selinux_state,
+ return avc_has_perm(current_selinux_state,
sid, sbsec->sid, SECCLASS_FILESYSTEM, perms, ad);
}
@@ -2056,7 +2058,7 @@ static inline u32 open_file_to_av(struct file *file)
static int selinux_binder_set_context_mgr(const struct cred *mgr)
{
- return avc_has_perm(&selinux_state,
+ return avc_has_perm(current_selinux_state,
current_sid(), cred_sid(mgr), SECCLASS_BINDER,
BINDER__SET_CONTEXT_MGR, NULL);
}
@@ -2070,21 +2072,21 @@ static int selinux_binder_transaction(const struct cred *from,
int rc;
if (mysid != fromsid) {
- rc = avc_has_perm(&selinux_state,
+ rc = avc_has_perm(current_selinux_state,
mysid, fromsid, SECCLASS_BINDER,
BINDER__IMPERSONATE, NULL);
if (rc)
return rc;
}
- return avc_has_perm(&selinux_state, fromsid, tosid,
+ return avc_has_perm(current_selinux_state, fromsid, tosid,
SECCLASS_BINDER, BINDER__CALL, NULL);
}
static int selinux_binder_transfer_binder(const struct cred *from,
const struct cred *to)
{
- return avc_has_perm(&selinux_state,
+ return avc_has_perm(current_selinux_state,
cred_sid(from), cred_sid(to),
SECCLASS_BINDER, BINDER__TRANSFER,
NULL);
@@ -2105,7 +2107,7 @@ static int selinux_binder_transfer_file(const struct cred *from,
ad.u.path = file->f_path;
if (sid != fsec->sid) {
- rc = avc_has_perm(&selinux_state,
+ rc = avc_has_perm(current_selinux_state,
sid, fsec->sid,
SECCLASS_FD,
FD__USE,
@@ -2124,7 +2126,7 @@ static int selinux_binder_transfer_file(const struct cred *from,
return 0;
isec = backing_inode_security(dentry);
- return avc_has_perm(&selinux_state,
+ return avc_has_perm(current_selinux_state,
sid, isec->sid, isec->sclass, file_to_av(file),
&ad);
}
@@ -2136,16 +2138,16 @@ static int selinux_ptrace_access_check(struct task_struct *child,
u32 csid = task_sid_obj(child);
if (mode & PTRACE_MODE_READ)
- return avc_has_perm(&selinux_state,
+ return avc_has_perm(current_selinux_state,
sid, csid, SECCLASS_FILE, FILE__READ, NULL);
- return avc_has_perm(&selinux_state,
+ return avc_has_perm(current_selinux_state,
sid, csid, SECCLASS_PROCESS, PROCESS__PTRACE, NULL);
}
static int selinux_ptrace_traceme(struct task_struct *parent)
{
- return avc_has_perm(&selinux_state,
+ return avc_has_perm(current_selinux_state,
task_sid_obj(parent), task_sid_obj(current),
SECCLASS_PROCESS, PROCESS__PTRACE, NULL);
}
@@ -2153,7 +2155,7 @@ static int selinux_ptrace_traceme(struct task_struct *parent)
static int selinux_capget(const struct task_struct *target, kernel_cap_t *effective,
kernel_cap_t *inheritable, kernel_cap_t *permitted)
{
- return avc_has_perm(&selinux_state,
+ return avc_has_perm(current_selinux_state,
current_sid(), task_sid_obj(target), SECCLASS_PROCESS,
PROCESS__GETCAP, NULL);
}
@@ -2163,7 +2165,7 @@ static int selinux_capset(struct cred *new, const struct cred *old,
const kernel_cap_t *inheritable,
const kernel_cap_t *permitted)
{
- return avc_has_perm(&selinux_state,
+ return avc_has_perm(current_selinux_state,
cred_sid(old), cred_sid(new), SECCLASS_PROCESS,
PROCESS__SETCAP, NULL);
}
@@ -2231,20 +2233,20 @@ static int selinux_syslog(int type)
switch (type) {
case SYSLOG_ACTION_READ_ALL: /* Read last kernel messages */
case SYSLOG_ACTION_SIZE_BUFFER: /* Return size of the log buffer */
- return avc_has_perm(&selinux_state,
+ return avc_has_perm(current_selinux_state,
current_sid(), SECINITSID_KERNEL,
SECCLASS_SYSTEM, SYSTEM__SYSLOG_READ, NULL);
case SYSLOG_ACTION_CONSOLE_OFF: /* Disable logging to console */
case SYSLOG_ACTION_CONSOLE_ON: /* Enable logging to console */
/* Set level of messages printed to console */
case SYSLOG_ACTION_CONSOLE_LEVEL:
- return avc_has_perm(&selinux_state,
+ return avc_has_perm(current_selinux_state,
current_sid(), SECINITSID_KERNEL,
SECCLASS_SYSTEM, SYSTEM__SYSLOG_CONSOLE,
NULL);
}
/* All other syslog types */
- return avc_has_perm(&selinux_state,
+ return avc_has_perm(current_selinux_state,
current_sid(), SECINITSID_KERNEL,
SECCLASS_SYSTEM, SYSTEM__SYSLOG_MOD, NULL);
}
@@ -2305,7 +2307,7 @@ static int check_nnp_nosuid(const struct linux_binprm *bprm,
av |= PROCESS2__NNP_TRANSITION;
if (nosuid)
av |= PROCESS2__NOSUID_TRANSITION;
- rc = avc_has_perm(&selinux_state,
+ rc = avc_has_perm(current_selinux_state,
old_tsec->sid, new_tsec->sid,
SECCLASS_PROCESS2, av, NULL);
if (!rc)
@@ -2317,7 +2319,7 @@ static int check_nnp_nosuid(const struct linux_binprm *bprm,
* i.e. SIDs that are guaranteed to only be allowed a subset
* of the permissions of the current SID.
*/
- rc = security_bounded_transition(&selinux_state, old_tsec->sid,
+ rc = security_bounded_transition(current_selinux_state, old_tsec->sid,
new_tsec->sid);
if (!rc)
return 0;
@@ -2363,7 +2365,7 @@ static int selinux_bprm_creds_for_exec(struct linux_binprm *bprm)
* early boot end up with a label different from SECINITSID_KERNEL
* (if the policy chooses to set SECINITSID_INIT != SECINITSID_KERNEL).
*/
- if (!selinux_initialized(&selinux_state)) {
+ if (!selinux_initialized(current_selinux_state)) {
new_tsec->sid = SECINITSID_INIT;
/* also clear the exec_sid just in case */
new_tsec->exec_sid = 0;
@@ -2381,7 +2383,7 @@ static int selinux_bprm_creds_for_exec(struct linux_binprm *bprm)
return rc;
} else {
/* Check for a default transition on this program. */
- rc = security_transition_sid(&selinux_state, old_tsec->sid,
+ rc = security_transition_sid(current_selinux_state, old_tsec->sid,
isec->sid, SECCLASS_PROCESS, NULL,
&new_tsec->sid);
if (rc)
@@ -2400,20 +2402,20 @@ static int selinux_bprm_creds_for_exec(struct linux_binprm *bprm)
ad.u.file = bprm->file;
if (new_tsec->sid == old_tsec->sid) {
- rc = avc_has_perm(&selinux_state,
+ rc = avc_has_perm(current_selinux_state,
old_tsec->sid, isec->sid,
SECCLASS_FILE, FILE__EXECUTE_NO_TRANS, &ad);
if (rc)
return rc;
} else {
/* Check permissions for the transition. */
- rc = avc_has_perm(&selinux_state,
+ rc = avc_has_perm(current_selinux_state,
old_tsec->sid, new_tsec->sid,
SECCLASS_PROCESS, PROCESS__TRANSITION, &ad);
if (rc)
return rc;
- rc = avc_has_perm(&selinux_state,
+ rc = avc_has_perm(current_selinux_state,
new_tsec->sid, isec->sid,
SECCLASS_FILE, FILE__ENTRYPOINT, &ad);
if (rc)
@@ -2421,7 +2423,7 @@ static int selinux_bprm_creds_for_exec(struct linux_binprm *bprm)
/* Check for shared state */
if (bprm->unsafe & LSM_UNSAFE_SHARE) {
- rc = avc_has_perm(&selinux_state,
+ rc = avc_has_perm(current_selinux_state,
old_tsec->sid, new_tsec->sid,
SECCLASS_PROCESS, PROCESS__SHARE,
NULL);
@@ -2434,7 +2436,7 @@ static int selinux_bprm_creds_for_exec(struct linux_binprm *bprm)
if (bprm->unsafe & LSM_UNSAFE_PTRACE) {
u32 ptsid = ptrace_parent_sid();
if (ptsid != 0) {
- rc = avc_has_perm(&selinux_state,
+ rc = avc_has_perm(current_selinux_state,
ptsid, new_tsec->sid,
SECCLASS_PROCESS,
PROCESS__PTRACE, NULL);
@@ -2449,7 +2451,7 @@ static int selinux_bprm_creds_for_exec(struct linux_binprm *bprm)
/* Enable secure mode for SIDs transitions unless
the noatsecure permission is granted between
the two SIDs, i.e. ahp returns 0. */
- rc = avc_has_perm(&selinux_state,
+ rc = avc_has_perm(current_selinux_state,
old_tsec->sid, new_tsec->sid,
SECCLASS_PROCESS, PROCESS__NOATSECURE,
NULL);
@@ -2542,7 +2544,7 @@ static void selinux_bprm_committing_creds(const struct linux_binprm *bprm)
* higher than the default soft limit for cases where the default is
* lower than the hard limit, e.g. RLIMIT_CORE or RLIMIT_STACK.
*/
- rc = avc_has_perm(&selinux_state,
+ rc = avc_has_perm(current_selinux_state,
new_tsec->osid, new_tsec->sid, SECCLASS_PROCESS,
PROCESS__RLIMITINH, NULL);
if (rc) {
@@ -2582,7 +2584,7 @@ static void selinux_bprm_committed_creds(const struct linux_binprm *bprm)
* This must occur _after_ the task SID has been updated so that any
* kill done after the flush will be checked against the new SID.
*/
- rc = avc_has_perm(&selinux_state,
+ rc = avc_has_perm(current_selinux_state,
osid, sid, SECCLASS_PROCESS, PROCESS__SIGINH, NULL);
if (rc) {
clear_itimer();
@@ -2938,8 +2940,8 @@ static int selinux_dentry_init_security(struct dentry *dentry, int mode,
*xattr_name = XATTR_NAME_SELINUX;
cp->id = LSM_ID_SELINUX;
- return security_sid_to_context(&selinux_state, newsid, &cp->context,
- &cp->len);
+ return security_sid_to_context(current_selinux_state, newsid,
+ &cp->context, &cp->len);
}
static int selinux_dentry_create_files_as(struct dentry *dentry, int mode,
@@ -2991,12 +2993,12 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
isec->initialized = LABEL_INITIALIZED;
}
- if (!selinux_initialized(&selinux_state) ||
+ if (!selinux_initialized(current_selinux_state) ||
!(sbsec->flags & SBLABEL_MNT))
return -EOPNOTSUPP;
if (xattr) {
- rc = security_sid_to_context_force(&selinux_state, newsid,
+ rc = security_sid_to_context_force(current_selinux_state, newsid,
&context, &clen);
if (rc)
return rc;
@@ -3017,7 +3019,7 @@ static int selinux_inode_init_security_anon(struct inode *inode,
struct inode_security_struct *isec;
int rc;
- if (unlikely(!selinux_initialized(&selinux_state)))
+ if (unlikely(!selinux_initialized(current_selinux_state)))
return 0;
isec = selinux_inode(inode);
@@ -3041,7 +3043,7 @@ static int selinux_inode_init_security_anon(struct inode *inode,
} else {
isec->sclass = SECCLASS_ANON_INODE;
rc = security_transition_sid(
- &selinux_state, sid, sid,
+ current_selinux_state, sid, sid,
isec->sclass, name, &isec->sid);
if (rc)
return rc;
@@ -3056,7 +3058,7 @@ static int selinux_inode_init_security_anon(struct inode *inode,
ad.type = LSM_AUDIT_DATA_ANONINODE;
ad.u.anonclass = name ? (const char *)name->name : "?";
- return avc_has_perm(&selinux_state,
+ return avc_has_perm(current_selinux_state,
sid,
isec->sid,
isec->sclass,
@@ -3125,7 +3127,7 @@ static int selinux_inode_follow_link(struct dentry *dentry, struct inode *inode,
if (IS_ERR(isec))
return PTR_ERR(isec);
- return avc_has_perm(&selinux_state,
+ return avc_has_perm(current_selinux_state,
sid, isec->sid, isec->sclass, FILE__READ, &ad);
}
@@ -3139,7 +3141,7 @@ static noinline int audit_inode_permission(struct inode *inode,
ad.type = LSM_AUDIT_DATA_INODE;
ad.u.inode = inode;
- return slow_avc_audit(&selinux_state,
+ return slow_avc_audit(current_selinux_state,
current_sid(), isec->sid, isec->sclass, perms,
audited, denied, result, &ad);
}
@@ -3155,7 +3157,7 @@ static inline void task_avdcache_reset(struct task_security_struct *tsec)
{
memset(&tsec->avdcache.dir, 0, sizeof(tsec->avdcache.dir));
tsec->avdcache.sid = tsec->sid;
- tsec->avdcache.seqno = avc_policy_seqno(&selinux_state);
+ tsec->avdcache.seqno = avc_policy_seqno(current_selinux_state);
tsec->avdcache.dir_spot = TSEC_AVDC_DIR_SIZE - 1;
}
@@ -3179,7 +3181,7 @@ static inline int task_avdcache_search(struct task_security_struct *tsec,
return -ENOENT;
if (unlikely(tsec->sid != tsec->avdcache.sid ||
- tsec->avdcache.seqno != avc_policy_seqno(&selinux_state))) {
+ tsec->avdcache.seqno != avc_policy_seqno(current_selinux_state))) {
task_avdcache_reset(tsec);
return -ENOENT;
}
@@ -3268,14 +3270,14 @@ static int selinux_inode_permission(struct inode *inode, int requested)
/* Cache hit. */
audited = perms & avdc->audited;
denied = perms & ~avdc->allowed;
- if (unlikely(denied && enforcing_enabled(&selinux_state) &&
+ if (unlikely(denied && enforcing_enabled(current_selinux_state) &&
!avdc->permissive))
rc = -EACCES;
} else {
struct av_decision avd;
/* Cache miss. */
- rc = avc_has_perm_noaudit(&selinux_state, tsec->sid,
+ rc = avc_has_perm_noaudit(current_selinux_state, tsec->sid,
isec->sid, isec->sclass, perms, 0,
&avd);
audited = avc_audit_required(perms, &avd, rc,
@@ -3379,7 +3381,7 @@ static int selinux_inode_setxattr(struct mnt_idmap *idmap,
if (strcmp(name, XATTR_NAME_SELINUX))
return dentry_has_perm(current_cred(), dentry, FILE__SETATTR);
- if (!selinux_initialized(&selinux_state))
+ if (!selinux_initialized(current_selinux_state))
return (inode_owner_or_capable(idmap, inode) ? 0 : -EPERM);
sbsec = selinux_superblock(inode->i_sb);
@@ -3393,13 +3395,13 @@ static int selinux_inode_setxattr(struct mnt_idmap *idmap,
ad.u.dentry = dentry;
isec = backing_inode_security(dentry);
- rc = avc_has_perm(&selinux_state,
+ rc = avc_has_perm(current_selinux_state,
sid, isec->sid, isec->sclass,
FILE__RELABELFROM, &ad);
if (rc)
return rc;
- rc = security_context_to_sid(&selinux_state, value, size, &newsid,
+ rc = security_context_to_sid(current_selinux_state, value, size, &newsid,
GFP_KERNEL);
if (rc == -EINVAL) {
if (!has_cap_mac_admin(true)) {
@@ -3428,24 +3430,24 @@ static int selinux_inode_setxattr(struct mnt_idmap *idmap,
return rc;
}
- rc = security_context_to_sid_force(&selinux_state, value,
+ rc = security_context_to_sid_force(current_selinux_state, value,
size, &newsid);
}
if (rc)
return rc;
- rc = avc_has_perm(&selinux_state,
+ rc = avc_has_perm(current_selinux_state,
sid, newsid, isec->sclass,
FILE__RELABELTO, &ad);
if (rc)
return rc;
- rc = security_validate_transition(&selinux_state, isec->sid, newsid,
+ rc = security_validate_transition(current_selinux_state, isec->sid, newsid,
sid, isec->sclass);
if (rc)
return rc;
- return avc_has_perm(&selinux_state,
+ return avc_has_perm(current_selinux_state,
newsid,
sbsec->sid,
SECCLASS_FILESYSTEM,
@@ -3486,7 +3488,7 @@ static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name,
return;
}
- if (!selinux_initialized(&selinux_state)) {
+ if (!selinux_initialized(current_selinux_state)) {
/* If we haven't even been initialized, then we can't validate
* against a policy, so leave the label as invalid. It may
* resolve to a valid label on the next revalidation try if
@@ -3495,7 +3497,7 @@ static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name,
return;
}
- rc = security_context_to_sid_force(&selinux_state, value, size,
+ rc = security_context_to_sid_force(current_selinux_state, value, size,
&newsid);
if (rc) {
pr_err("SELinux: unable to map context to SID"
@@ -3533,7 +3535,7 @@ static int selinux_inode_removexattr(struct mnt_idmap *idmap,
if (strcmp(name, XATTR_NAME_SELINUX))
return dentry_has_perm(current_cred(), dentry, FILE__SETATTR);
- if (!selinux_initialized(&selinux_state))
+ if (!selinux_initialized(current_selinux_state))
return 0;
/* No one is allowed to remove a SELinux security label.
@@ -3619,7 +3621,7 @@ static int selinux_inode_getsecurity(struct mnt_idmap *idmap,
* If we're not initialized yet, then we can't validate contexts, so
* just let vfs_getxattr fall back to using the on-disk xattr.
*/
- if (!selinux_initialized(&selinux_state) ||
+ if (!selinux_initialized(current_selinux_state) ||
strcmp(name, XATTR_SELINUX_SUFFIX))
return -EOPNOTSUPP;
@@ -3634,11 +3636,11 @@ static int selinux_inode_getsecurity(struct mnt_idmap *idmap,
*/
isec = inode_security(inode);
if (has_cap_mac_admin(false))
- error = security_sid_to_context_force(&selinux_state,
+ error = security_sid_to_context_force(current_selinux_state,
isec->sid, &context,
&size);
else
- error = security_sid_to_context(&selinux_state, isec->sid,
+ error = security_sid_to_context(current_selinux_state, isec->sid,
&context, &size);
if (error)
return error;
@@ -3670,7 +3672,7 @@ static int selinux_inode_setsecurity(struct inode *inode, const char *name,
if (!value || !size)
return -EACCES;
- rc = security_context_to_sid(&selinux_state, value, size, &newsid,
+ rc = security_context_to_sid(current_selinux_state, value, size, &newsid,
GFP_KERNEL);
if (rc)
return rc;
@@ -3687,7 +3689,7 @@ static int selinux_inode_listsecurity(struct inode *inode, char *buffer, size_t
{
const int len = sizeof(XATTR_NAME_SELINUX);
- if (!selinux_initialized(&selinux_state))
+ if (!selinux_initialized(current_selinux_state))
return 0;
if (buffer && len <= buffer_size)
@@ -3729,7 +3731,7 @@ static int selinux_inode_copy_up_xattr(struct dentry *dentry, const char *name)
* xattrs up. Instead, filter out SELinux-related xattrs following
* policy load.
*/
- if (selinux_initialized(&selinux_state) &&
+ if (selinux_initialized(current_selinux_state) &&
!strcmp(name, XATTR_NAME_SELINUX))
return -ECANCELED; /* Discard */
@@ -3767,8 +3769,8 @@ static int selinux_kernfs_init_security(struct kernfs_node *kn_dir,
return rc;
}
- rc = security_context_to_sid(&selinux_state, context, clen, &parent_sid,
- GFP_KERNEL);
+ rc = security_context_to_sid(current_selinux_state, context, clen,
+ &parent_sid, GFP_KERNEL);
kfree(context);
if (rc)
return rc;
@@ -3785,14 +3787,14 @@ static int selinux_kernfs_init_security(struct kernfs_node *kn_dir,
q.name = kn_name;
q.hash_len = hashlen_string(kn_dir, kn_name);
- rc = security_transition_sid(&selinux_state, tsec->sid,
+ rc = security_transition_sid(current_selinux_state, tsec->sid,
parent_sid, secclass, &q,
&newsid);
if (rc)
return rc;
}
- rc = security_sid_to_context_force(&selinux_state, newsid,
+ rc = security_sid_to_context_force(current_selinux_state, newsid,
&context, &clen);
if (rc)
return rc;
@@ -3832,7 +3834,7 @@ static int selinux_file_permission(struct file *file, int mask)
isec = inode_security(inode);
if (sid == fsec->sid && fsec->isid == isec->sid &&
- fsec->pseqno == avc_policy_seqno(&selinux_state))
+ fsec->pseqno == avc_policy_seqno(current_selinux_state))
/* No change since file_open check. */
return 0;
@@ -3873,7 +3875,7 @@ static int ioctl_has_perm(const struct cred *cred, struct file *file,
ad.u.op->path = file->f_path;
if (ssid != fsec->sid) {
- rc = avc_has_perm(&selinux_state,
+ rc = avc_has_perm(current_selinux_state,
ssid, fsec->sid,
SECCLASS_FD,
FD__USE,
@@ -3886,7 +3888,7 @@ static int ioctl_has_perm(const struct cred *cred, struct file *file,
return 0;
isec = inode_security(inode);
- rc = avc_has_extended_perms(&selinux_state,
+ rc = avc_has_extended_perms(current_selinux_state,
ssid, isec->sid, isec->sclass,
requested, driver, AVC_EXT_IOCTL, xperm,
&ad);
@@ -3984,7 +3986,7 @@ static int file_map_prot_check(struct file *file, unsigned long prot, int shared
* private file mapping that will also be writable.
* This has an additional check.
*/
- rc = avc_has_perm(&selinux_state,
+ rc = avc_has_perm(current_selinux_state,
sid, sid, SECCLASS_PROCESS,
PROCESS__EXECMEM, NULL);
if (rc)
@@ -4015,7 +4017,7 @@ static int selinux_mmap_addr(unsigned long addr)
if (addr < CONFIG_LSM_MMAP_MIN_ADDR) {
u32 sid = current_sid();
- rc = avc_has_perm(&selinux_state,
+ rc = avc_has_perm(current_selinux_state,
sid, sid, SECCLASS_MEMPROTECT,
MEMPROTECT__MMAP_ZERO, NULL);
}
@@ -4064,12 +4066,12 @@ static int selinux_file_mprotect(struct vm_area_struct *vma,
*/
if (vma->vm_start >= vma->vm_mm->start_brk &&
vma->vm_end <= vma->vm_mm->brk) {
- rc = avc_has_perm(&selinux_state,
+ rc = avc_has_perm(current_selinux_state,
sid, sid, SECCLASS_PROCESS,
PROCESS__EXECHEAP, NULL);
} else if (!vma->vm_file && (vma_is_initial_stack(vma) ||
vma_is_stack_for_current(vma))) {
- rc = avc_has_perm(&selinux_state,
+ rc = avc_has_perm(current_selinux_state,
sid, sid, SECCLASS_PROCESS,
PROCESS__EXECSTACK, NULL);
} else if (vma->vm_file && vma->anon_vma) {
@@ -4162,7 +4164,7 @@ static int selinux_file_send_sigiotask(struct task_struct *tsk,
else
perm = signal_to_av(signum);
- return avc_has_perm(&selinux_state,
+ return avc_has_perm(current_selinux_state,
fsec->fown_sid, sid,
SECCLASS_PROCESS, perm, NULL);
}
@@ -4189,7 +4191,7 @@ static int selinux_file_open(struct file *file)
* struct as its SID.
*/
fsec->isid = isec->sid;
- fsec->pseqno = avc_policy_seqno(&selinux_state);
+ fsec->pseqno = avc_policy_seqno(current_selinux_state);
/*
* Since the inode label or policy seqno may have changed
* between the selinux_inode_permission check and the saving
@@ -4208,7 +4210,7 @@ static int selinux_task_alloc(struct task_struct *task,
{
u32 sid = current_sid();
- return avc_has_perm(&selinux_state,
+ return avc_has_perm(current_selinux_state,
sid, sid, SECCLASS_PROCESS, PROCESS__FORK, NULL);
}
@@ -4256,7 +4258,7 @@ static int selinux_kernel_act_as(struct cred *new, u32 secid)
u32 sid = current_sid();
int ret;
- ret = avc_has_perm(&selinux_state,
+ ret = avc_has_perm(current_selinux_state,
sid, secid,
SECCLASS_KERNEL_SERVICE,
KERNEL_SERVICE__USE_AS_OVERRIDE,
@@ -4281,7 +4283,7 @@ static int selinux_kernel_create_files_as(struct cred *new, struct inode *inode)
u32 sid = current_sid();
int ret;
- ret = avc_has_perm(&selinux_state,
+ ret = avc_has_perm(current_selinux_state,
sid, isec->sid,
SECCLASS_KERNEL_SERVICE,
KERNEL_SERVICE__CREATE_FILES_AS,
@@ -4299,7 +4301,7 @@ static int selinux_kernel_module_request(char *kmod_name)
ad.type = LSM_AUDIT_DATA_KMOD;
ad.u.kmod_name = kmod_name;
- return avc_has_perm(&selinux_state,
+ return avc_has_perm(current_selinux_state,
current_sid(), SECINITSID_KERNEL, SECCLASS_SYSTEM,
SYSTEM__MODULE_REQUEST, &ad);
}
@@ -4313,7 +4315,7 @@ static int selinux_kernel_load_from_file(struct file *file, u32 requested)
int rc;
if (file == NULL)
- return avc_has_perm(&selinux_state,
+ return avc_has_perm(current_selinux_state,
sid, sid, SECCLASS_SYSTEM, requested,
NULL);
@@ -4323,14 +4325,14 @@ static int selinux_kernel_load_from_file(struct file *file, u32 requested)
fsec = selinux_file(file);
if (sid != fsec->sid) {
- rc = avc_has_perm(&selinux_state,
+ rc = avc_has_perm(current_selinux_state,
sid, fsec->sid, SECCLASS_FD, FD__USE, &ad);
if (rc)
return rc;
}
isec = inode_security(file_inode(file));
- return avc_has_perm(&selinux_state,
+ return avc_has_perm(current_selinux_state,
sid, isec->sid, SECCLASS_SYSTEM, requested, &ad);
}
@@ -4411,21 +4413,21 @@ static int selinux_kernel_load_data(enum kernel_load_data_id id, bool contents)
static int selinux_task_setpgid(struct task_struct *p, pid_t pgid)
{
- return avc_has_perm(&selinux_state,
+ return avc_has_perm(current_selinux_state,
current_sid(), task_sid_obj(p), SECCLASS_PROCESS,
PROCESS__SETPGID, NULL);
}
static int selinux_task_getpgid(struct task_struct *p)
{
- return avc_has_perm(&selinux_state,
+ return avc_has_perm(current_selinux_state,
current_sid(), task_sid_obj(p), SECCLASS_PROCESS,
PROCESS__GETPGID, NULL);
}
static int selinux_task_getsid(struct task_struct *p)
{
- return avc_has_perm(&selinux_state,
+ return avc_has_perm(current_selinux_state,
current_sid(), task_sid_obj(p), SECCLASS_PROCESS,
PROCESS__GETSESSION, NULL);
}
@@ -4443,21 +4445,21 @@ static void selinux_task_getlsmprop_obj(struct task_struct *p,
static int selinux_task_setnice(struct task_struct *p, int nice)
{
- return avc_has_perm(&selinux_state,
+ return avc_has_perm(current_selinux_state,
current_sid(), task_sid_obj(p), SECCLASS_PROCESS,
PROCESS__SETSCHED, NULL);
}
static int selinux_task_setioprio(struct task_struct *p, int ioprio)
{
- return avc_has_perm(&selinux_state,
+ return avc_has_perm(current_selinux_state,
current_sid(), task_sid_obj(p), SECCLASS_PROCESS,
PROCESS__SETSCHED, NULL);
}
static int selinux_task_getioprio(struct task_struct *p)
{
- return avc_has_perm(&selinux_state,
+ return avc_has_perm(current_selinux_state,
current_sid(), task_sid_obj(p), SECCLASS_PROCESS,
PROCESS__GETSCHED, NULL);
}
@@ -4473,7 +4475,7 @@ static int selinux_task_prlimit(const struct cred *cred, const struct cred *tcre
av |= PROCESS__SETRLIMIT;
if (flags & LSM_PRLIMIT_READ)
av |= PROCESS__GETRLIMIT;
- return avc_has_perm(&selinux_state,
+ return avc_has_perm(current_selinux_state,
cred_sid(cred), cred_sid(tcred),
SECCLASS_PROCESS, av, NULL);
}
@@ -4488,7 +4490,7 @@ static int selinux_task_setrlimit(struct task_struct *p, unsigned int resource,
later be used as a safe reset point for the soft limit
upon context transitions. See selinux_bprm_committing_creds. */
if (old_rlim->rlim_max != new_rlim->rlim_max)
- return avc_has_perm(&selinux_state,
+ return avc_has_perm(current_selinux_state,
current_sid(), task_sid_obj(p),
SECCLASS_PROCESS, PROCESS__SETRLIMIT, NULL);
@@ -4497,21 +4499,21 @@ static int selinux_task_setrlimit(struct task_struct *p, unsigned int resource,
static int selinux_task_setscheduler(struct task_struct *p)
{
- return avc_has_perm(&selinux_state,
+ return avc_has_perm(current_selinux_state,
current_sid(), task_sid_obj(p), SECCLASS_PROCESS,
PROCESS__SETSCHED, NULL);
}
static int selinux_task_getscheduler(struct task_struct *p)
{
- return avc_has_perm(&selinux_state,
+ return avc_has_perm(current_selinux_state,
current_sid(), task_sid_obj(p), SECCLASS_PROCESS,
PROCESS__GETSCHED, NULL);
}
static int selinux_task_movememory(struct task_struct *p)
{
- return avc_has_perm(&selinux_state,
+ return avc_has_perm(current_selinux_state,
current_sid(), task_sid_obj(p), SECCLASS_PROCESS,
PROCESS__SETSCHED, NULL);
}
@@ -4530,7 +4532,7 @@ static int selinux_task_kill(struct task_struct *p, struct kernel_siginfo *info,
secid = current_sid();
else
secid = cred_sid(cred);
- return avc_has_perm(&selinux_state,
+ return avc_has_perm(current_selinux_state,
secid, task_sid_obj(p), SECCLASS_PROCESS, perm, NULL);
}
@@ -4551,7 +4553,7 @@ static int selinux_userns_create(const struct cred *cred)
{
u32 sid = current_sid();
- return avc_has_perm(&selinux_state, sid, sid, SECCLASS_USER_NAMESPACE,
+ return avc_has_perm(current_selinux_state, sid, sid, SECCLASS_USER_NAMESPACE,
USER_NAMESPACE__CREATE, NULL);
}
@@ -4782,7 +4784,7 @@ static int selinux_skb_peerlbl_sid(struct sk_buff *skb, u16 family, u32 *sid)
if (unlikely(err))
return -EACCES;
- err = security_net_peersid_resolve(&selinux_state, nlbl_sid,
+ err = security_net_peersid_resolve(current_selinux_state, nlbl_sid,
nlbl_type, xfrm_sid, sid);
if (unlikely(err)) {
pr_warn(
@@ -4811,7 +4813,7 @@ static int selinux_conn_sid(u32 sk_sid, u32 skb_sid, u32 *conn_sid)
int err = 0;
if (skb_sid != SECSID_NULL)
- err = security_sid_mls_copy(&selinux_state, sk_sid, skb_sid,
+ err = security_sid_mls_copy(current_selinux_state, sk_sid, skb_sid,
conn_sid);
else
*conn_sid = sk_sid;
@@ -4829,7 +4831,7 @@ static int socket_sockcreate_sid(const struct task_security_struct *tsec,
return 0;
}
- return security_transition_sid(&selinux_state, tsec->sid, tsec->sid,
+ return security_transition_sid(current_selinux_state, tsec->sid, tsec->sid,
secclass, NULL, socksid);
}
@@ -4867,7 +4869,7 @@ static int sock_has_perm(struct sock *sk, u32 perms)
ad_net_init_from_sk(&ad, &net, sk);
- return avc_has_perm(&selinux_state,
+ return avc_has_perm(current_selinux_state,
current_sid(), sksec->sid, sksec->sclass, perms,
&ad);
}
@@ -4888,7 +4890,7 @@ static int selinux_socket_create(int family, int type,
if (rc)
return rc;
- return avc_has_perm(&selinux_state,
+ return avc_has_perm(current_selinux_state,
tsec->sid, newsid, secclass, SOCKET__CREATE, NULL);
}
@@ -5025,7 +5027,7 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
snum, &sid);
if (err)
goto out;
- err = avc_has_perm(&selinux_state,
+ err = avc_has_perm(current_selinux_state,
sksec->sid, sid,
sksec->sclass,
SOCKET__NAME_BIND, &ad);
@@ -5061,7 +5063,7 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
else
ad.u.net->v6info.saddr = addr6->sin6_addr;
- err = avc_has_perm(&selinux_state,
+ err = avc_has_perm(current_selinux_state,
sksec->sid, sid,
sksec->sclass, node_perm, &ad);
if (err)
@@ -5156,7 +5158,7 @@ static int selinux_socket_connect_helper(struct socket *sock,
ad.u.net = &net;
ad.u.net->dport = htons(snum);
ad.u.net->family = address->sa_family;
- err = avc_has_perm(&selinux_state,
+ err = avc_has_perm(current_selinux_state,
sksec->sid, sid, sksec->sclass, perm, &ad);
if (err)
return err;
@@ -5267,7 +5269,7 @@ static int selinux_socket_unix_stream_connect(struct sock *sock,
ad_net_init_from_sk(&ad, &net, other);
- err = avc_has_perm(&selinux_state,
+ err = avc_has_perm(current_selinux_state,
sksec_sock->sid, sksec_other->sid,
sksec_other->sclass,
UNIX_STREAM_SOCKET__CONNECTTO, &ad);
@@ -5276,7 +5278,7 @@ static int selinux_socket_unix_stream_connect(struct sock *sock,
/* server child socket */
sksec_new->peer_sid = sksec_sock->sid;
- err = security_sid_mls_copy(&selinux_state, sksec_other->sid,
+ err = security_sid_mls_copy(current_selinux_state, sksec_other->sid,
sksec_sock->sid, &sksec_new->sid);
if (err)
return err;
@@ -5297,7 +5299,7 @@ static int selinux_socket_unix_may_send(struct socket *sock,
ad_net_init_from_sk(&ad, &net, other->sk);
- return avc_has_perm(&selinux_state,
+ return avc_has_perm(current_selinux_state,
ssec->sid, osec->sid, osec->sclass, SOCKET__SENDTO,
&ad);
}
@@ -5313,7 +5315,7 @@ static int selinux_inet_sys_rcv_skb(struct net *ns, int ifindex,
err = sel_netif_sid(ns, ifindex, &if_sid);
if (err)
return err;
- err = avc_has_perm(&selinux_state,
+ err = avc_has_perm(current_selinux_state,
peer_sid, if_sid,
SECCLASS_NETIF, NETIF__INGRESS, ad);
if (err)
@@ -5322,7 +5324,7 @@ static int selinux_inet_sys_rcv_skb(struct net *ns, int ifindex,
err = sel_netnode_sid(addrp, family, &node_sid);
if (err)
return err;
- return avc_has_perm(&selinux_state,
+ return avc_has_perm(current_selinux_state,
peer_sid, node_sid,
SECCLASS_NODE, NODE__RECVFROM, ad);
}
@@ -5343,7 +5345,7 @@ static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
return err;
if (selinux_secmark_enabled()) {
- err = avc_has_perm(&selinux_state,
+ err = avc_has_perm(current_selinux_state,
sk_sid, skb->secmark, SECCLASS_PACKET,
PACKET__RECV, &ad);
if (err)
@@ -5404,7 +5406,7 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
selinux_netlbl_err(skb, family, err, 0);
return err;
}
- err = avc_has_perm(&selinux_state,
+ err = avc_has_perm(current_selinux_state,
sk_sid, peer_sid, SECCLASS_PEER,
PEER__RECV, &ad);
if (err) {
@@ -5414,7 +5416,7 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
}
if (secmark_active) {
- err = avc_has_perm(&selinux_state,
+ err = avc_has_perm(current_selinux_state,
sk_sid, skb->secmark, SECCLASS_PACKET,
PACKET__RECV, &ad);
if (err)
@@ -5441,7 +5443,7 @@ static int selinux_socket_getpeersec_stream(struct socket *sock,
if (peer_sid == SECSID_NULL)
return -ENOPROTOOPT;
- err = security_sid_to_context(&selinux_state, peer_sid, &scontext,
+ err = security_sid_to_context(current_selinux_state, peer_sid, &scontext,
&scontext_len);
if (err)
return err;
@@ -5591,7 +5593,7 @@ static int selinux_sctp_process_new_assoc(struct sctp_association *asoc,
* consistency among the peer SIDs.
*/
ad_net_init_from_sk(&ad, &net, asoc->base.sk);
- err = avc_has_perm(&selinux_state,
+ err = avc_has_perm(current_selinux_state,
sksec->peer_sid, asoc->peer_secid,
sksec->sclass, SCTP_SOCKET__ASSOCIATION,
&ad);
@@ -5822,7 +5824,7 @@ static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb)
static int selinux_secmark_relabel_packet(u32 sid)
{
- return avc_has_perm(&selinux_state,
+ return avc_has_perm(current_selinux_state,
current_sid(), sid, SECCLASS_PACKET,
PACKET__RELABELTO, NULL);
}
@@ -5862,7 +5864,7 @@ static int selinux_tun_dev_create(void)
* connections unlike traditional sockets - check the TUN driver to
* get a better understanding of why this socket is special */
- return avc_has_perm(&selinux_state,
+ return avc_has_perm(current_selinux_state,
sid, sid, SECCLASS_TUN_SOCKET, TUN_SOCKET__CREATE,
NULL);
}
@@ -5871,7 +5873,7 @@ static int selinux_tun_dev_attach_queue(void *security)
{
struct tun_security_struct *tunsec = selinux_tun_dev(security);
- return avc_has_perm(&selinux_state,
+ return avc_has_perm(current_selinux_state,
current_sid(), tunsec->sid, SECCLASS_TUN_SOCKET,
TUN_SOCKET__ATTACH_QUEUE, NULL);
}
@@ -5900,12 +5902,12 @@ static int selinux_tun_dev_open(void *security)
u32 sid = current_sid();
int err;
- err = avc_has_perm(&selinux_state,
+ err = avc_has_perm(current_selinux_state,
sid, tunsec->sid, SECCLASS_TUN_SOCKET,
TUN_SOCKET__RELABELFROM, NULL);
if (err)
return err;
- err = avc_has_perm(&selinux_state,
+ err = avc_has_perm(current_selinux_state,
sid, sid, SECCLASS_TUN_SOCKET,
TUN_SOCKET__RELABELTO, NULL);
if (err)
@@ -5957,7 +5959,7 @@ static unsigned int selinux_ip_forward(void *priv, struct sk_buff *skb,
}
if (secmark_active)
- if (avc_has_perm(&selinux_state,
+ if (avc_has_perm(current_selinux_state,
peer_sid, skb->secmark,
SECCLASS_PACKET, PACKET__FORWARD_IN, &ad))
return NF_DROP;
@@ -6035,7 +6037,7 @@ static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
return NF_DROP;
if (selinux_secmark_enabled())
- if (avc_has_perm(&selinux_state,
+ if (avc_has_perm(current_selinux_state,
sksec->sid, skb->secmark,
SECCLASS_PACKET, PACKET__SEND, &ad))
return NF_DROP_ERR(-ECONNREFUSED);
@@ -6158,7 +6160,7 @@ static unsigned int selinux_ip_postroute(void *priv,
return NF_DROP;
if (secmark_active)
- if (avc_has_perm(&selinux_state,
+ if (avc_has_perm(current_selinux_state,
peer_sid, skb->secmark,
SECCLASS_PACKET, secmark_perm, &ad))
return NF_DROP_ERR(-ECONNREFUSED);
@@ -6169,14 +6171,14 @@ static unsigned int selinux_ip_postroute(void *priv,
if (sel_netif_sid(state->net, ifindex, &if_sid))
return NF_DROP;
- if (avc_has_perm(&selinux_state,
+ if (avc_has_perm(current_selinux_state,
peer_sid, if_sid,
SECCLASS_NETIF, NETIF__EGRESS, &ad))
return NF_DROP_ERR(-ECONNREFUSED);
if (sel_netnode_sid(addrp, family, &node_sid))
return NF_DROP;
- if (avc_has_perm(&selinux_state,
+ if (avc_has_perm(current_selinux_state,
peer_sid, node_sid,
SECCLASS_NODE, NODE__SENDTO, &ad))
return NF_DROP_ERR(-ECONNREFUSED);
@@ -6202,7 +6204,7 @@ static int nlmsg_sock_has_extended_perms(struct sock *sk, u32 perms, u16 nlmsg_t
driver = nlmsg_type >> 8;
xperm = nlmsg_type & 0xff;
- return avc_has_extended_perms(&selinux_state, current_sid(),
+ return avc_has_extended_perms(current_selinux_state, current_sid(),
sksec->sid, sksec->sclass, perms,
driver, AVC_EXT_NLMSG, xperm, &ad);
}
@@ -6248,8 +6250,8 @@ static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb)
sk->sk_protocol, nlh->nlmsg_type,
secclass_map[sclass - 1].name,
task_pid_nr(current), current->comm);
- if (enforcing_enabled(&selinux_state) &&
- !security_get_allow_unknown(&selinux_state))
+ if (enforcing_enabled(current_selinux_state) &&
+ !security_get_allow_unknown(current_selinux_state))
return rc;
rc = 0;
} else if (rc == -ENOENT) {
@@ -6288,7 +6290,7 @@ static int ipc_has_perm(struct kern_ipc_perm *ipc_perms,
ad.type = LSM_AUDIT_DATA_IPC;
ad.u.ipc_id = ipc_perms->key;
- return avc_has_perm(&selinux_state,
+ return avc_has_perm(current_selinux_state,
sid, isec->sid, isec->sclass, perms, &ad);
}
@@ -6315,7 +6317,7 @@ static int selinux_msg_queue_alloc_security(struct kern_ipc_perm *msq)
ad.type = LSM_AUDIT_DATA_IPC;
ad.u.ipc_id = msq->key;
- return avc_has_perm(&selinux_state,
+ return avc_has_perm(current_selinux_state,
sid, isec->sid, SECCLASS_MSGQ,
MSGQ__CREATE, &ad);
}
@@ -6331,7 +6333,7 @@ static int selinux_msg_queue_associate(struct kern_ipc_perm *msq, int msqflg)
ad.type = LSM_AUDIT_DATA_IPC;
ad.u.ipc_id = msq->key;
- return avc_has_perm(&selinux_state,
+ return avc_has_perm(current_selinux_state,
sid, isec->sid, SECCLASS_MSGQ,
MSGQ__ASSOCIATE, &ad);
}
@@ -6344,7 +6346,7 @@ static int selinux_msg_queue_msgctl(struct kern_ipc_perm *msq, int cmd)
case IPC_INFO:
case MSG_INFO:
/* No specific object, just general system-wide information. */
- return avc_has_perm(&selinux_state,
+ return avc_has_perm(current_selinux_state,
current_sid(), SECINITSID_KERNEL,
SECCLASS_SYSTEM, SYSTEM__IPC_INFO, NULL);
case IPC_STAT:
@@ -6384,7 +6386,7 @@ static int selinux_msg_queue_msgsnd(struct kern_ipc_perm *msq, struct msg_msg *m
* Compute new sid based on current process and
* message queue this message will be stored in
*/
- rc = security_transition_sid(&selinux_state, sid, isec->sid,
+ rc = security_transition_sid(current_selinux_state, sid, isec->sid,
SECCLASS_MSG, NULL, &msec->sid);
if (rc)
return rc;
@@ -6394,17 +6396,17 @@ static int selinux_msg_queue_msgsnd(struct kern_ipc_perm *msq, struct msg_msg *m
ad.u.ipc_id = msq->key;
/* Can this process write to the queue? */
- rc = avc_has_perm(&selinux_state,
+ rc = avc_has_perm(current_selinux_state,
sid, isec->sid, SECCLASS_MSGQ,
MSGQ__WRITE, &ad);
if (!rc)
/* Can this process send the message */
- rc = avc_has_perm(&selinux_state,
+ rc = avc_has_perm(current_selinux_state,
sid, msec->sid, SECCLASS_MSG,
MSG__SEND, &ad);
if (!rc)
/* Can the message be put in the queue? */
- rc = avc_has_perm(&selinux_state,
+ rc = avc_has_perm(current_selinux_state,
msec->sid, isec->sid, SECCLASS_MSGQ,
MSGQ__ENQUEUE, &ad);
@@ -6427,11 +6429,11 @@ static int selinux_msg_queue_msgrcv(struct kern_ipc_perm *msq, struct msg_msg *m
ad.type = LSM_AUDIT_DATA_IPC;
ad.u.ipc_id = msq->key;
- rc = avc_has_perm(&selinux_state,
+ rc = avc_has_perm(current_selinux_state,
sid, isec->sid,
SECCLASS_MSGQ, MSGQ__READ, &ad);
if (!rc)
- rc = avc_has_perm(&selinux_state,
+ rc = avc_has_perm(current_selinux_state,
sid, msec->sid,
SECCLASS_MSG, MSG__RECEIVE, &ad);
return rc;
@@ -6450,7 +6452,7 @@ static int selinux_shm_alloc_security(struct kern_ipc_perm *shp)
ad.type = LSM_AUDIT_DATA_IPC;
ad.u.ipc_id = shp->key;
- return avc_has_perm(&selinux_state,
+ return avc_has_perm(current_selinux_state,
sid, isec->sid, SECCLASS_SHM,
SHM__CREATE, &ad);
}
@@ -6466,7 +6468,7 @@ static int selinux_shm_associate(struct kern_ipc_perm *shp, int shmflg)
ad.type = LSM_AUDIT_DATA_IPC;
ad.u.ipc_id = shp->key;
- return avc_has_perm(&selinux_state,
+ return avc_has_perm(current_selinux_state,
sid, isec->sid, SECCLASS_SHM,
SHM__ASSOCIATE, &ad);
}
@@ -6480,7 +6482,7 @@ static int selinux_shm_shmctl(struct kern_ipc_perm *shp, int cmd)
case IPC_INFO:
case SHM_INFO:
/* No specific object, just general system-wide information. */
- return avc_has_perm(&selinux_state,
+ return avc_has_perm(current_selinux_state,
current_sid(), SECINITSID_KERNEL,
SECCLASS_SYSTEM, SYSTEM__IPC_INFO, NULL);
case IPC_STAT:
@@ -6531,7 +6533,7 @@ static int selinux_sem_alloc_security(struct kern_ipc_perm *sma)
ad.type = LSM_AUDIT_DATA_IPC;
ad.u.ipc_id = sma->key;
- return avc_has_perm(&selinux_state,
+ return avc_has_perm(current_selinux_state,
sid, isec->sid, SECCLASS_SEM,
SEM__CREATE, &ad);
}
@@ -6547,7 +6549,7 @@ static int selinux_sem_associate(struct kern_ipc_perm *sma, int semflg)
ad.type = LSM_AUDIT_DATA_IPC;
ad.u.ipc_id = sma->key;
- return avc_has_perm(&selinux_state,
+ return avc_has_perm(current_selinux_state,
sid, isec->sid, SECCLASS_SEM,
SEM__ASSOCIATE, &ad);
}
@@ -6562,7 +6564,7 @@ static int selinux_sem_semctl(struct kern_ipc_perm *sma, int cmd)
case IPC_INFO:
case SEM_INFO:
/* No specific object, just general system-wide information. */
- return avc_has_perm(&selinux_state,
+ return avc_has_perm(current_selinux_state,
current_sid(), SECINITSID_KERNEL,
SECCLASS_SYSTEM, SYSTEM__IPC_INFO, NULL);
case GETPID:
@@ -6650,7 +6652,7 @@ static int selinux_lsm_getattr(unsigned int attr, struct task_struct *p,
rcu_read_lock();
tsec = selinux_cred(__task_cred(p));
if (p != current) {
- error = avc_has_perm(&selinux_state,
+ error = avc_has_perm(current_selinux_state,
current_sid(), tsec->sid,
SECCLASS_PROCESS, PROCESS__GETATTR, NULL);
if (error)
@@ -6686,7 +6688,7 @@ static int selinux_lsm_getattr(unsigned int attr, struct task_struct *p,
return 0;
}
- error = security_sid_to_context(&selinux_state, sid, value, &len);
+ error = security_sid_to_context(current_selinux_state, sid, value, &len);
if (error)
return error;
return len;
@@ -6709,27 +6711,27 @@ static int selinux_lsm_setattr(u64 attr, void *value, size_t size)
*/
switch (attr) {
case LSM_ATTR_EXEC:
- error = avc_has_perm(&selinux_state,
+ error = avc_has_perm(current_selinux_state,
mysid, mysid, SECCLASS_PROCESS,
PROCESS__SETEXEC, NULL);
break;
case LSM_ATTR_FSCREATE:
- error = avc_has_perm(&selinux_state,
+ error = avc_has_perm(current_selinux_state,
mysid, mysid, SECCLASS_PROCESS,
PROCESS__SETFSCREATE, NULL);
break;
case LSM_ATTR_KEYCREATE:
- error = avc_has_perm(&selinux_state,
+ error = avc_has_perm(current_selinux_state,
mysid, mysid, SECCLASS_PROCESS,
PROCESS__SETKEYCREATE, NULL);
break;
case LSM_ATTR_SOCKCREATE:
- error = avc_has_perm(&selinux_state,
+ error = avc_has_perm(current_selinux_state,
mysid, mysid, SECCLASS_PROCESS,
PROCESS__SETSOCKCREATE, NULL);
break;
case LSM_ATTR_CURRENT:
- error = avc_has_perm(&selinux_state,
+ error = avc_has_perm(current_selinux_state,
mysid, mysid, SECCLASS_PROCESS,
PROCESS__SETCURRENT, NULL);
break;
@@ -6746,7 +6748,7 @@ static int selinux_lsm_setattr(u64 attr, void *value, size_t size)
str[size-1] = 0;
size--;
}
- error = security_context_to_sid(&selinux_state, value, size,
+ error = security_context_to_sid(current_selinux_state, value, size,
&sid, GFP_KERNEL);
if (error == -EINVAL && attr == LSM_ATTR_FSCREATE) {
if (!has_cap_mac_admin(true)) {
@@ -6773,7 +6775,7 @@ static int selinux_lsm_setattr(u64 attr, void *value, size_t size)
return error;
}
error = security_context_to_sid_force(
- &selinux_state,
+ current_selinux_state,
value, size, &sid);
}
if (error)
@@ -6797,7 +6799,7 @@ static int selinux_lsm_setattr(u64 attr, void *value, size_t size)
tsec->create_sid = sid;
} else if (attr == LSM_ATTR_KEYCREATE) {
if (sid) {
- error = avc_has_perm(&selinux_state, mysid, sid,
+ error = avc_has_perm(current_selinux_state, mysid, sid,
SECCLASS_KEY, KEY__CREATE, NULL);
if (error)
goto abort_change;
@@ -6811,14 +6813,14 @@ static int selinux_lsm_setattr(u64 attr, void *value, size_t size)
goto abort_change;
if (!current_is_single_threaded()) {
- error = security_bounded_transition(&selinux_state,
+ error = security_bounded_transition(current_selinux_state,
tsec->sid, sid);
if (error)
goto abort_change;
}
/* Check permissions for the transition. */
- error = avc_has_perm(&selinux_state,
+ error = avc_has_perm(current_selinux_state,
tsec->sid, sid, SECCLASS_PROCESS,
PROCESS__DYNTRANSITION, NULL);
if (error)
@@ -6828,7 +6830,7 @@ static int selinux_lsm_setattr(u64 attr, void *value, size_t size)
Otherwise, leave SID unchanged and fail. */
ptsid = ptrace_parent_sid();
if (ptsid != 0) {
- error = avc_has_perm(&selinux_state,
+ error = avc_has_perm(current_selinux_state,
ptsid, sid, SECCLASS_PROCESS,
PROCESS__PTRACE, NULL);
if (error)
@@ -6924,13 +6926,14 @@ static int selinux_secid_to_secctx(u32 secid, struct lsm_context *cp)
if (cp) {
cp->id = LSM_ID_SELINUX;
- ret = security_sid_to_context(&selinux_state, secid,
+ ret = security_sid_to_context(current_selinux_state, secid,
&cp->context, &cp->len);
if (ret < 0)
return ret;
return cp->len;
}
- ret = security_sid_to_context(&selinux_state, secid, NULL, &seclen);
+ ret = security_sid_to_context(current_selinux_state, secid, NULL,
+ &seclen);
if (ret < 0)
return ret;
return seclen;
@@ -6944,7 +6947,7 @@ static int selinux_lsmprop_to_secctx(struct lsm_prop *prop,
static int selinux_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
{
- return security_context_to_sid(&selinux_state, secdata, seclen,
+ return security_context_to_sid(current_selinux_state, secdata, seclen,
secid, GFP_KERNEL);
}
@@ -7057,7 +7060,7 @@ static int selinux_key_permission(key_ref_t key_ref,
key = key_ref_to_ptr(key_ref);
ksec = selinux_key(key);
- return avc_has_perm(&selinux_state,
+ return avc_has_perm(current_selinux_state,
sid, ksec->sid, SECCLASS_KEY, perm, NULL);
}
@@ -7068,7 +7071,7 @@ static int selinux_key_getsecurity(struct key *key, char **_buffer)
unsigned len;
int rc;
- rc = security_sid_to_context(&selinux_state, ksec->sid,
+ rc = security_sid_to_context(current_selinux_state, ksec->sid,
&context, &len);
if (!rc)
rc = len;
@@ -7082,7 +7085,7 @@ static int selinux_watch_key(struct key *key)
struct key_security_struct *ksec = selinux_key(key);
u32 sid = current_sid();
- return avc_has_perm(&selinux_state,
+ return avc_has_perm(current_selinux_state,
sid, ksec->sid, SECCLASS_KEY, KEY__VIEW, NULL);
}
#endif
@@ -7105,7 +7108,7 @@ static int selinux_ib_pkey_access(void *ib_sec, u64 subnet_prefix, u16 pkey_val)
ibpkey.subnet_prefix = subnet_prefix;
ibpkey.pkey = pkey_val;
ad.u.ibpkey = &ibpkey;
- return avc_has_perm(&selinux_state,
+ return avc_has_perm(current_selinux_state,
sec->sid, sid,
SECCLASS_INFINIBAND_PKEY,
INFINIBAND_PKEY__ACCESS, &ad);
@@ -7120,7 +7123,7 @@ static int selinux_ib_endport_manage_subnet(void *ib_sec, const char *dev_name,
struct ib_security_struct *sec = ib_sec;
struct lsm_ibendport_audit ibendport;
- err = security_ib_endport_sid(&selinux_state, dev_name, port_num,
+ err = security_ib_endport_sid(current_selinux_state, dev_name, port_num,
&sid);
if (err)
@@ -7130,7 +7133,7 @@ static int selinux_ib_endport_manage_subnet(void *ib_sec, const char *dev_name,
ibendport.dev_name = dev_name;
ibendport.port = port_num;
ad.u.ibendport = &ibendport;
- return avc_has_perm(&selinux_state,
+ return avc_has_perm(current_selinux_state,
sec->sid, sid,
SECCLASS_INFINIBAND_ENDPORT,
INFINIBAND_ENDPORT__MANAGE_SUBNET, &ad);
@@ -7154,12 +7157,12 @@ static int selinux_bpf(int cmd, union bpf_attr *attr,
switch (cmd) {
case BPF_MAP_CREATE:
- ret = avc_has_perm(&selinux_state,
+ ret = avc_has_perm(current_selinux_state,
sid, sid, SECCLASS_BPF, BPF__MAP_CREATE,
NULL);
break;
case BPF_PROG_LOAD:
- ret = avc_has_perm(&selinux_state,
+ ret = avc_has_perm(current_selinux_state,
sid, sid, SECCLASS_BPF, BPF__PROG_LOAD,
NULL);
break;
@@ -7200,7 +7203,7 @@ static int bpf_fd_pass(const struct file *file, u32 sid)
if (file->f_op == &bpf_map_fops) {
map = file->private_data;
bpfsec = map->security;
- ret = avc_has_perm(&selinux_state,
+ ret = avc_has_perm(current_selinux_state,
sid, bpfsec->sid, SECCLASS_BPF,
bpf_map_fmode_to_av(file->f_mode), NULL);
if (ret)
@@ -7208,7 +7211,7 @@ static int bpf_fd_pass(const struct file *file, u32 sid)
} else if (file->f_op == &bpf_prog_fops) {
prog = file->private_data;
bpfsec = prog->aux->security;
- ret = avc_has_perm(&selinux_state,
+ ret = avc_has_perm(current_selinux_state,
sid, bpfsec->sid, SECCLASS_BPF,
BPF__PROG_RUN, NULL);
if (ret)
@@ -7223,7 +7226,7 @@ static int selinux_bpf_map(struct bpf_map *map, fmode_t fmode)
struct bpf_security_struct *bpfsec;
bpfsec = map->security;
- return avc_has_perm(&selinux_state,
+ return avc_has_perm(current_selinux_state,
sid, bpfsec->sid, SECCLASS_BPF,
bpf_map_fmode_to_av(fmode), NULL);
}
@@ -7234,7 +7237,7 @@ static int selinux_bpf_prog(struct bpf_prog *prog)
struct bpf_security_struct *bpfsec;
bpfsec = prog->aux->security;
- return avc_has_perm(&selinux_state,
+ return avc_has_perm(current_selinux_state,
sid, bpfsec->sid, SECCLASS_BPF,
BPF__PROG_RUN, NULL);
}
@@ -7342,7 +7345,7 @@ static int selinux_perf_event_open(int type)
else
return -EINVAL;
- return avc_has_perm(&selinux_state, sid, sid, SECCLASS_PERF_EVENT,
+ return avc_has_perm(current_selinux_state, sid, sid, SECCLASS_PERF_EVENT,
requested, NULL);
}
@@ -7361,7 +7364,7 @@ static int selinux_perf_event_read(struct perf_event *event)
struct perf_event_security_struct *perfsec = event->security;
u32 sid = current_sid();
- return avc_has_perm(&selinux_state, sid, perfsec->sid,
+ return avc_has_perm(current_selinux_state, sid, perfsec->sid,
SECCLASS_PERF_EVENT, PERF_EVENT__READ, NULL);
}
@@ -7370,7 +7373,7 @@ static int selinux_perf_event_write(struct perf_event *event)
struct perf_event_security_struct *perfsec = event->security;
u32 sid = current_sid();
- return avc_has_perm(&selinux_state, sid, perfsec->sid,
+ return avc_has_perm(current_selinux_state, sid, perfsec->sid,
SECCLASS_PERF_EVENT, PERF_EVENT__WRITE, NULL);
}
#endif
@@ -7385,7 +7388,7 @@ static int selinux_perf_event_write(struct perf_event *event)
*/
static int selinux_uring_override_creds(const struct cred *new)
{
- return avc_has_perm(&selinux_state, current_sid(), cred_sid(new),
+ return avc_has_perm(current_selinux_state, current_sid(), cred_sid(new),
SECCLASS_IO_URING, IO_URING__OVERRIDE_CREDS, NULL);
}
@@ -7399,7 +7402,7 @@ static int selinux_uring_sqpoll(void)
{
u32 sid = current_sid();
- return avc_has_perm(&selinux_state, sid, sid,
+ return avc_has_perm(current_selinux_state, sid, sid,
SECCLASS_IO_URING, IO_URING__SQPOLL, NULL);
}
@@ -7421,7 +7424,7 @@ static int selinux_uring_cmd(struct io_uring_cmd *ioucmd)
ad.type = LSM_AUDIT_DATA_FILE;
ad.u.file = file;
- return avc_has_perm(&selinux_state, current_sid(), isec->sid,
+ return avc_has_perm(current_selinux_state, current_sid(), isec->sid,
SECCLASS_IO_URING, IO_URING__CMD, &ad);
}
@@ -7434,8 +7437,8 @@ static int selinux_uring_allowed(void)
{
u32 sid = current_sid();
- return avc_has_perm(&selinux_state, sid, sid, SECCLASS_IO_URING,
- IO_URING__ALLOWED, NULL);
+ return avc_has_perm(current_selinux_state, sid, sid,
+ SECCLASS_IO_URING, IO_URING__ALLOWED, NULL);
}
#endif /* CONFIG_IO_URING */
@@ -7750,11 +7753,12 @@ static __init int selinux_init(void)
{
pr_info("SELinux: Initializing.\n");
- memset(&selinux_state, 0, sizeof(selinux_state));
- enforcing_set(&selinux_state, selinux_enforcing_boot);
- selinux_avc_init(&selinux_state.avc);
- mutex_init(&selinux_state.status_lock);
- mutex_init(&selinux_state.policy_mutex);
+ memset(&init_selinux_state, 0, sizeof(init_selinux_state));
+ enforcing_set(&init_selinux_state, selinux_enforcing_boot);
+ selinux_avc_init(&init_selinux_state.avc);
+ mutex_init(&init_selinux_state.status_lock);
+ mutex_init(&init_selinux_state.policy_mutex);
+ current_selinux_state = &init_selinux_state;
/* Set the security state for the initial task. */
cred_init_security();
diff --git a/security/selinux/ibpkey.c b/security/selinux/ibpkey.c
index 7406706582f5..47739b88f172 100644
--- a/security/selinux/ibpkey.c
+++ b/security/selinux/ibpkey.c
@@ -141,7 +141,7 @@ static int sel_ib_pkey_sid_slow(u64 subnet_prefix, u16 pkey_num, u32 *sid)
return 0;
}
- ret = security_ib_pkey_sid(&selinux_state, subnet_prefix, pkey_num,
+ ret = security_ib_pkey_sid(current_selinux_state, subnet_prefix, pkey_num,
sid);
if (ret)
goto out;
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h
index 55fe076cd609..a4376a0ce032 100644
--- a/security/selinux/include/objsec.h
+++ b/security/selinux/include/objsec.h
@@ -57,7 +57,8 @@ static inline bool task_avdcache_permnoaudit(struct task_security_struct *tsec)
{
return (tsec->avdcache.permissive_neveraudit &&
tsec->sid == tsec->avdcache.sid &&
- tsec->avdcache.seqno == avc_policy_seqno(&selinux_state));
+ tsec->avdcache.seqno ==
+ avc_policy_seqno(current_selinux_state));
}
enum label_initialized {
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
index a1e2d5e0da50..168bd75f9cdf 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -109,7 +109,7 @@ struct selinux_state {
void selinux_avc_init(struct selinux_avc **avc);
-extern struct selinux_state selinux_state;
+extern struct selinux_state *current_selinux_state;
static inline bool selinux_initialized(const struct selinux_state *state)
{
@@ -152,56 +152,65 @@ static inline bool checkreqprot_get(const struct selinux_state *state)
static inline bool selinux_policycap_netpeer(void)
{
- return READ_ONCE(selinux_state.policycap[POLICYDB_CAP_NETPEER]);
+ return READ_ONCE(
+ current_selinux_state->policycap[POLICYDB_CAP_NETPEER]);
}
static inline bool selinux_policycap_openperm(void)
{
- return READ_ONCE(selinux_state.policycap[POLICYDB_CAP_OPENPERM]);
+ return READ_ONCE(
+ current_selinux_state->policycap[POLICYDB_CAP_OPENPERM]);
}
static inline bool selinux_policycap_extsockclass(void)
{
- return READ_ONCE(selinux_state.policycap[POLICYDB_CAP_EXTSOCKCLASS]);
+ return READ_ONCE(
+ current_selinux_state->policycap[POLICYDB_CAP_EXTSOCKCLASS]);
}
static inline bool selinux_policycap_alwaysnetwork(void)
{
- return READ_ONCE(selinux_state.policycap[POLICYDB_CAP_ALWAYSNETWORK]);
+ return READ_ONCE(
+ current_selinux_state->policycap[POLICYDB_CAP_ALWAYSNETWORK]);
}
static inline bool selinux_policycap_cgroupseclabel(void)
{
- return READ_ONCE(selinux_state.policycap[POLICYDB_CAP_CGROUPSECLABEL]);
+ return READ_ONCE(
+ current_selinux_state->policycap[POLICYDB_CAP_CGROUPSECLABEL]);
}
static inline bool selinux_policycap_nnp_nosuid_transition(void)
{
return READ_ONCE(
- selinux_state.policycap[POLICYDB_CAP_NNP_NOSUID_TRANSITION]);
+ current_selinux_state
+ ->policycap[POLICYDB_CAP_NNP_NOSUID_TRANSITION]);
}
static inline bool selinux_policycap_genfs_seclabel_symlinks(void)
{
return READ_ONCE(
- selinux_state.policycap[POLICYDB_CAP_GENFS_SECLABEL_SYMLINKS]);
+ current_selinux_state
+ ->policycap[POLICYDB_CAP_GENFS_SECLABEL_SYMLINKS]);
}
static inline bool selinux_policycap_ioctl_skip_cloexec(void)
{
- return READ_ONCE(
- selinux_state.policycap[POLICYDB_CAP_IOCTL_SKIP_CLOEXEC]);
+ return READ_ONCE(current_selinux_state
+ ->policycap[POLICYDB_CAP_IOCTL_SKIP_CLOEXEC]);
}
static inline bool selinux_policycap_userspace_initial_context(void)
{
return READ_ONCE(
- selinux_state.policycap[POLICYDB_CAP_USERSPACE_INITIAL_CONTEXT]);
+ current_selinux_state
+ ->policycap[POLICYDB_CAP_USERSPACE_INITIAL_CONTEXT]);
}
static inline bool selinux_policycap_netlink_xperm(void)
{
- return READ_ONCE(selinux_state.policycap[POLICYDB_CAP_NETLINK_XPERM]);
+ return READ_ONCE(
+ current_selinux_state->policycap[POLICYDB_CAP_NETLINK_XPERM]);
}
struct selinux_policy_convert_data;
diff --git a/security/selinux/netif.c b/security/selinux/netif.c
index 52718a78f06c..6bd8c434a37a 100644
--- a/security/selinux/netif.c
+++ b/security/selinux/netif.c
@@ -153,7 +153,7 @@ static int sel_netif_sid_slow(struct net *ns, int ifindex, u32 *sid)
goto out;
}
- ret = security_netif_sid(&selinux_state, dev->name, sid);
+ ret = security_netif_sid(current_selinux_state, dev->name, sid);
if (ret != 0)
goto out;
diff --git a/security/selinux/netlabel.c b/security/selinux/netlabel.c
index b858b46fd4b4..e35c224145a4 100644
--- a/security/selinux/netlabel.c
+++ b/security/selinux/netlabel.c
@@ -47,7 +47,7 @@ static int selinux_netlbl_sidlookup_cached(struct sk_buff *skb,
{
int rc;
- rc = security_netlbl_secattr_to_sid(&selinux_state, secattr, sid);
+ rc = security_netlbl_secattr_to_sid(current_selinux_state, secattr, sid);
if (rc == 0 &&
(secattr->flags & NETLBL_SECATTR_CACHEABLE) &&
(secattr->flags & NETLBL_SECATTR_CACHE))
@@ -79,7 +79,7 @@ static struct netlbl_lsm_secattr *selinux_netlbl_sock_genattr(struct sock *sk)
if (secattr == NULL)
return ERR_PTR(-ENOMEM);
- rc = security_netlbl_sid_to_secattr(&selinux_state, sksec->sid,
+ rc = security_netlbl_sid_to_secattr(current_selinux_state, sksec->sid,
secattr);
if (rc != 0) {
netlbl_secattr_free(secattr);
@@ -252,7 +252,7 @@ int selinux_netlbl_skbuff_setsid(struct sk_buff *skb,
if (secattr == NULL) {
secattr = &secattr_storage;
netlbl_secattr_init(secattr);
- rc = security_netlbl_sid_to_secattr(&selinux_state, sid,
+ rc = security_netlbl_sid_to_secattr(current_selinux_state, sid,
secattr);
if (rc != 0)
goto skbuff_setsid_return;
@@ -290,7 +290,7 @@ int selinux_netlbl_sctp_assoc_request(struct sctp_association *asoc,
return 0;
netlbl_secattr_init(&secattr);
- rc = security_netlbl_sid_to_secattr(&selinux_state,
+ rc = security_netlbl_sid_to_secattr(current_selinux_state,
asoc->secid, &secattr);
if (rc != 0)
goto assoc_request_return;
@@ -339,7 +339,7 @@ int selinux_netlbl_inet_conn_request(struct request_sock *req, u16 family)
return 0;
netlbl_secattr_init(&secattr);
- rc = security_netlbl_sid_to_secattr(&selinux_state, req->secid,
+ rc = security_netlbl_sid_to_secattr(current_selinux_state, req->secid,
&secattr);
if (rc != 0)
goto inet_conn_request_return;
@@ -473,7 +473,7 @@ int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
perm = RAWIP_SOCKET__RECVFROM;
}
- rc = avc_has_perm(&selinux_state,
+ rc = avc_has_perm(current_selinux_state,
sksec->sid, nlbl_sid, sksec->sclass, perm, ad);
if (rc == 0)
return 0;
diff --git a/security/selinux/netnode.c b/security/selinux/netnode.c
index 48ba999eebfa..502aefcf2d77 100644
--- a/security/selinux/netnode.c
+++ b/security/selinux/netnode.c
@@ -207,13 +207,13 @@ static int sel_netnode_sid_slow(const void *addr, u16 family, u32 *sid)
new = kmalloc(sizeof(*new), GFP_ATOMIC);
switch (family) {
case PF_INET:
- ret = security_node_sid(&selinux_state, PF_INET,
+ ret = security_node_sid(current_selinux_state, PF_INET,
addr, sizeof(struct in_addr), sid);
if (new)
new->nsec.addr.ipv4 = *(const __be32 *)addr;
break;
case PF_INET6:
- ret = security_node_sid(&selinux_state, PF_INET6,
+ ret = security_node_sid(current_selinux_state, PF_INET6,
addr, sizeof(struct in6_addr), sid);
if (new)
new->nsec.addr.ipv6 = *(const struct in6_addr *)addr;
diff --git a/security/selinux/netport.c b/security/selinux/netport.c
index d7e57cd3ecba..ca07023f3d5a 100644
--- a/security/selinux/netport.c
+++ b/security/selinux/netport.c
@@ -142,7 +142,7 @@ static int sel_netport_sid_slow(u8 protocol, u16 pnum, u32 *sid)
return 0;
}
- ret = security_port_sid(&selinux_state, protocol, pnum, sid);
+ ret = security_port_sid(current_selinux_state, protocol, pnum, sid);
if (ret != 0)
goto out;
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index a0bba61e3d3a..221149e95dea 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -90,7 +90,7 @@ static int selinux_fs_info_create(struct super_block *sb)
return -ENOMEM;
fsi->last_ino = SEL_INO_NEXT - 1;
- fsi->state = &selinux_state;
+ fsi->state = current_selinux_state;
fsi->sb = sb;
sb->s_fs_info = fsi;
return 0;
@@ -165,7 +165,7 @@ static ssize_t sel_write_enforce(struct file *file, const char __user *buf,
old_value = enforcing_enabled(state);
if (new_value != old_value) {
- length = avc_has_perm(&selinux_state,
+ length = avc_has_perm(current_selinux_state,
current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__SETENFORCE,
NULL);
@@ -381,7 +381,7 @@ static int sel_open_policy(struct inode *inode, struct file *filp)
mutex_lock(&fsi->state->policy_mutex);
- rc = avc_has_perm(&selinux_state,
+ rc = avc_has_perm(current_selinux_state,
current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__READ_POLICY, NULL);
if (rc)
@@ -443,9 +443,9 @@ static ssize_t sel_read_policy(struct file *filp, char __user *buf,
struct policy_load_memory *plm = filp->private_data;
int ret;
- ret = avc_has_perm(&selinux_state,
+ ret = avc_has_perm(current_selinux_state,
current_sid(), SECINITSID_SECURITY,
- SECCLASS_SECURITY, SECURITY__READ_POLICY, NULL);
+ SECCLASS_SECURITY, SECURITY__READ_POLICY, NULL);
if (ret)
return ret;
@@ -597,7 +597,7 @@ static ssize_t sel_write_load(struct file *file, const char __user *buf,
return -EINVAL;
mutex_lock(&fsi->state->policy_mutex);
- length = avc_has_perm(&selinux_state,
+ length = avc_has_perm(current_selinux_state,
current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__LOAD_POLICY, NULL);
if (length)
@@ -652,7 +652,7 @@ static ssize_t sel_write_context(struct file *file, char *buf, size_t size)
u32 sid, len;
ssize_t length;
- length = avc_has_perm(&selinux_state,
+ length = avc_has_perm(current_selinux_state,
current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__CHECK_CONTEXT, NULL);
if (length)
@@ -700,7 +700,7 @@ static ssize_t sel_write_checkreqprot(struct file *file, const char __user *buf,
ssize_t length;
unsigned int new_value;
- length = avc_has_perm(&selinux_state,
+ length = avc_has_perm(current_selinux_state,
current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__SETCHECKREQPROT,
NULL);
@@ -756,7 +756,7 @@ static ssize_t sel_write_validatetrans(struct file *file,
u16 tclass;
int rc;
- rc = avc_has_perm(&selinux_state,
+ rc = avc_has_perm(current_selinux_state,
current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__VALIDATE_TRANS, NULL);
if (rc)
@@ -885,7 +885,7 @@ static ssize_t sel_write_access(struct file *file, char *buf, size_t size)
struct av_decision avd;
ssize_t length;
- length = avc_has_perm(&selinux_state,
+ length = avc_has_perm(current_selinux_state,
current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__COMPUTE_AV, NULL);
if (length)
@@ -939,7 +939,7 @@ static ssize_t sel_write_create(struct file *file, char *buf, size_t size)
u32 len;
int nargs;
- length = avc_has_perm(&selinux_state,
+ length = avc_has_perm(current_selinux_state,
current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__COMPUTE_CREATE,
NULL);
@@ -1041,7 +1041,7 @@ static ssize_t sel_write_relabel(struct file *file, char *buf, size_t size)
char *newcon = NULL;
u32 len;
- length = avc_has_perm(&selinux_state,
+ length = avc_has_perm(current_selinux_state,
current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__COMPUTE_RELABEL,
NULL);
@@ -1107,7 +1107,7 @@ static ssize_t sel_write_user(struct file *file, char *buf, size_t size)
" userspace.\n", current->comm, current->pid);
ssleep(5);
- length = avc_has_perm(&selinux_state,
+ length = avc_has_perm(current_selinux_state,
current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__COMPUTE_USER,
NULL);
@@ -1172,7 +1172,7 @@ static ssize_t sel_write_member(struct file *file, char *buf, size_t size)
char *newcon = NULL;
u32 len;
- length = avc_has_perm(&selinux_state,
+ length = avc_has_perm(current_selinux_state,
current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__COMPUTE_MEMBER,
NULL);
@@ -1300,7 +1300,7 @@ static ssize_t sel_write_bool(struct file *filep, const char __user *buf,
mutex_lock(&fsi->state->policy_mutex);
- length = avc_has_perm(&selinux_state,
+ length = avc_has_perm(current_selinux_state,
current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__SETBOOL,
NULL);
@@ -1356,7 +1356,7 @@ static ssize_t sel_commit_bools_write(struct file *filep,
mutex_lock(&fsi->state->policy_mutex);
- length = avc_has_perm(&selinux_state,
+ length = avc_has_perm(current_selinux_state,
current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__SETBOOL,
NULL);
@@ -1474,7 +1474,7 @@ static ssize_t sel_write_avc_cache_threshold(struct file *file,
ssize_t ret;
unsigned int new_value;
- ret = avc_has_perm(&selinux_state,
+ ret = avc_has_perm(current_selinux_state,
current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__SETSECPARAM,
NULL);
@@ -2220,7 +2220,7 @@ static int __init init_sel_fs(void)
* Try to pre-allocate the status page, so the sequence number of the
* initial policy load can be stored.
*/
- (void) selinux_kernel_status_page(&selinux_state);
+ (void) selinux_kernel_status_page(current_selinux_state);
return err;
}
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index 724e0f4c6110..430a654b42a5 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -3642,7 +3642,7 @@ void selinux_audit_rule_free(void *vrule)
int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule,
gfp_t gfp)
{
- struct selinux_state *state = &selinux_state;
+ struct selinux_state *state = current_selinux_state;
struct selinux_policy *policy;
struct policydb *policydb;
struct selinux_audit_rule *tmprule;
@@ -3767,7 +3767,7 @@ int selinux_audit_rule_known(struct audit_krule *rule)
int selinux_audit_rule_match(struct lsm_prop *prop, u32 field, u32 op, void *vrule)
{
- struct selinux_state *state = &selinux_state;
+ struct selinux_state *state = current_selinux_state;
struct selinux_policy *policy;
struct context *ctxt;
struct mls_level *level;
diff --git a/security/selinux/xfrm.c b/security/selinux/xfrm.c
index 47db3522a2ce..4ad8b610eb77 100644
--- a/security/selinux/xfrm.c
+++ b/security/selinux/xfrm.c
@@ -97,12 +97,12 @@ static int selinux_xfrm_alloc_user(struct xfrm_sec_ctx **ctxp,
ctx->ctx_len = str_len + 1;
memcpy(ctx->ctx_str, &uctx[1], str_len);
ctx->ctx_str[str_len] = '\0';
- rc = security_context_to_sid(&selinux_state, ctx->ctx_str, str_len,
+ rc = security_context_to_sid(current_selinux_state, ctx->ctx_str, str_len,
&ctx->ctx_sid, gfp);
if (rc)
goto err;
- rc = avc_has_perm(&selinux_state,
+ rc = avc_has_perm(current_selinux_state,
current_sid(), ctx->ctx_sid,
SECCLASS_ASSOCIATION, ASSOCIATION__SETCONTEXT, NULL);
if (rc)
@@ -137,7 +137,7 @@ static int selinux_xfrm_delete(struct xfrm_sec_ctx *ctx)
if (!ctx)
return 0;
- return avc_has_perm(&selinux_state,
+ return avc_has_perm(current_selinux_state,
current_sid(), ctx->ctx_sid,
SECCLASS_ASSOCIATION, ASSOCIATION__SETCONTEXT,
NULL);
@@ -160,7 +160,7 @@ int selinux_xfrm_policy_lookup(struct xfrm_sec_ctx *ctx, u32 fl_secid)
if (!selinux_authorizable_ctx(ctx))
return -EINVAL;
- rc = avc_has_perm(&selinux_state,
+ rc = avc_has_perm(current_selinux_state,
fl_secid, ctx->ctx_sid,
SECCLASS_ASSOCIATION, ASSOCIATION__POLMATCH, NULL);
return (rc == -EACCES ? -ESRCH : rc);
@@ -202,7 +202,7 @@ int selinux_xfrm_state_pol_flow_match(struct xfrm_state *x,
/* We don't need a separate SA Vs. policy polmatch check since the SA
* is now of the same label as the flow and a flow Vs. policy polmatch
* check had already happened in selinux_xfrm_policy_lookup() above. */
- return (avc_has_perm(&selinux_state, flic_sid, state_sid,
+ return (avc_has_perm(current_selinux_state, flic_sid, state_sid,
SECCLASS_ASSOCIATION, ASSOCIATION__SENDTO,
NULL) ? 0 : 1);
}
@@ -352,7 +352,7 @@ int selinux_xfrm_state_alloc_acquire(struct xfrm_state *x,
if (secid == 0)
return -EINVAL;
- rc = security_sid_to_context(&selinux_state, secid, &ctx_str,
+ rc = security_sid_to_context(current_selinux_state, secid, &ctx_str,
&str_len);
if (rc)
return rc;
@@ -421,7 +421,7 @@ int selinux_xfrm_sock_rcv_skb(u32 sk_sid, struct sk_buff *skb,
/* This check even when there's no association involved is intended,
* according to Trent Jaeger, to make sure a process can't engage in
* non-IPsec communication unless explicitly allowed by policy. */
- return avc_has_perm(&selinux_state,
+ return avc_has_perm(current_selinux_state,
sk_sid, peer_sid,
SECCLASS_ASSOCIATION, ASSOCIATION__RECVFROM, ad);
}
@@ -465,6 +465,6 @@ int selinux_xfrm_postroute_last(u32 sk_sid, struct sk_buff *skb,
/* This check even when there's no association involved is intended,
* according to Trent Jaeger, to make sure a process can't engage in
* non-IPsec communication unless explicitly allowed by policy. */
- return avc_has_perm(&selinux_state, sk_sid, SECINITSID_UNLABELED,
+ return avc_has_perm(current_selinux_state, sk_sid, SECINITSID_UNLABELED,
SECCLASS_ASSOCIATION, ASSOCIATION__SENDTO, ad);
}
--
2.50.1
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [PATCH v7 03/42] selinux: support multiple selinuxfs instances
2025-08-14 13:25 [PATCH v7 00/42] SELinux namespace support Stephen Smalley
2025-08-14 13:25 ` [PATCH v7 01/42] selinux: restore passing of selinux_state Stephen Smalley
2025-08-14 13:25 ` [PATCH v7 02/42] selinux: introduce current_selinux_state Stephen Smalley
@ 2025-08-14 13:25 ` Stephen Smalley
2025-08-14 13:25 ` [PATCH v7 04/42] selinux: dynamically allocate selinux namespace Stephen Smalley
` (38 subsequent siblings)
41 siblings, 0 replies; 43+ messages in thread
From: Stephen Smalley @ 2025-08-14 13:25 UTC (permalink / raw)
To: selinux; +Cc: paul, omosnace, netdev, horms, Stephen Smalley
Support multiple selinuxfs instances, one per selinux namespace.
The expected usage would be to unshare the SELinux namespace and
the mount namespace, and then mount a new selinuxfs instance. The
new instance would then provide an interface for viewing and manipulating
the state of the new SELinux namespace and would not affect the parent
namespace in any manner.
This change by itself should have no effect on SELinux behavior or
APIs (userspace or LSM).
Signed-off-by: Stephen Smalley <stephen.smalley.work@gmail.com>
---
security/selinux/selinuxfs.c | 26 +++++++++++++++++++++++++-
1 file changed, 25 insertions(+), 1 deletion(-)
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index 221149e95dea..d07d585fa401 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -2151,9 +2151,33 @@ static int sel_fill_super(struct super_block *sb, struct fs_context *fc)
return ret;
}
+static int selinuxfs_compare(struct super_block *sb, struct fs_context *fc)
+{
+ struct selinux_fs_info *fsi = sb->s_fs_info;
+
+ return (current_selinux_state == fsi->state);
+}
+
static int sel_get_tree(struct fs_context *fc)
{
- return get_tree_single(fc, sel_fill_super);
+ struct super_block *sb;
+ int err;
+
+ sb = sget_fc(fc, selinuxfs_compare, set_anon_super_fc);
+ if (IS_ERR(sb))
+ return PTR_ERR(sb);
+
+ if (!sb->s_root) {
+ err = sel_fill_super(sb, fc);
+ if (err) {
+ deactivate_locked_super(sb);
+ return err;
+ }
+ sb->s_flags |= SB_ACTIVE;
+ }
+
+ fc->root = dget(sb->s_root);
+ return 0;
}
static const struct fs_context_operations sel_context_ops = {
--
2.50.1
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [PATCH v7 04/42] selinux: dynamically allocate selinux namespace
2025-08-14 13:25 [PATCH v7 00/42] SELinux namespace support Stephen Smalley
` (2 preceding siblings ...)
2025-08-14 13:25 ` [PATCH v7 03/42] selinux: support multiple selinuxfs instances Stephen Smalley
@ 2025-08-14 13:25 ` Stephen Smalley
2025-08-14 13:25 ` [PATCH v7 05/42] netstate,selinux: create the selinux netlink socket per network namespace Stephen Smalley
` (37 subsequent siblings)
41 siblings, 0 replies; 43+ messages in thread
From: Stephen Smalley @ 2025-08-14 13:25 UTC (permalink / raw)
To: selinux; +Cc: paul, omosnace, netdev, horms, Stephen Smalley
Move from static allocation of a single selinux namespace to
dynamic allocation. Include necessary support for lifecycle management
of the selinux namespace, modeled after the user namespace support.
Signed-off-by: Stephen Smalley <stephen.smalley.work@gmail.com>
---
security/selinux/avc.c | 32 ++++++++++----
security/selinux/hooks.c | 65 +++++++++++++++++++++++++----
security/selinux/include/security.h | 27 +++++++++++-
security/selinux/selinuxfs.c | 3 +-
security/selinux/ss/services.c | 17 +++++++-
5 files changed, 125 insertions(+), 19 deletions(-)
diff --git a/security/selinux/avc.c b/security/selinux/avc.c
index 32e1a116f2b7..056e597912ec 100644
--- a/security/selinux/avc.c
+++ b/security/selinux/avc.c
@@ -91,20 +91,34 @@ struct selinux_avc {
struct avc_cache avc_cache;
};
-static struct selinux_avc selinux_avc;
-
-void selinux_avc_init(struct selinux_avc **avc)
+int selinux_avc_create(struct selinux_avc **avc)
{
+ struct selinux_avc *newavc;
int i;
- selinux_avc.avc_cache_threshold = AVC_DEF_CACHE_THRESHOLD;
+ newavc = kzalloc(sizeof(*newavc), GFP_KERNEL);
+ if (!newavc)
+ return -ENOMEM;
+
+ newavc->avc_cache_threshold = AVC_DEF_CACHE_THRESHOLD;
+
for (i = 0; i < AVC_CACHE_SLOTS; i++) {
- INIT_HLIST_HEAD(&selinux_avc.avc_cache.slots[i]);
- spin_lock_init(&selinux_avc.avc_cache.slots_lock[i]);
+ INIT_HLIST_HEAD(&newavc->avc_cache.slots[i]);
+ spin_lock_init(&newavc->avc_cache.slots_lock[i]);
}
- atomic_set(&selinux_avc.avc_cache.active_nodes, 0);
- atomic_set(&selinux_avc.avc_cache.lru_hint, 0);
- *avc = &selinux_avc;
+ atomic_set(&newavc->avc_cache.active_nodes, 0);
+ atomic_set(&newavc->avc_cache.lru_hint, 0);
+
+ *avc = newavc;
+ return 0;
+}
+
+static void avc_flush(struct selinux_avc *avc);
+
+void selinux_avc_free(struct selinux_avc *avc)
+{
+ avc_flush(avc);
+ kfree(avc);
}
unsigned int avc_get_cache_threshold(struct selinux_avc *avc)
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index d45a3ac9ded6..7c405f3289db 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -107,7 +107,7 @@
#define SELINUX_INODE_INIT_XATTRS 1
-static struct selinux_state init_selinux_state;
+static struct selinux_state *init_selinux_state;
struct selinux_state *current_selinux_state;
/* SECMARK reference count */
@@ -7749,16 +7749,67 @@ static struct security_hook_list selinux_hooks[] __ro_after_init = {
#endif
};
+static void selinux_state_free(struct work_struct *work);
+
+int selinux_state_create(struct selinux_state *parent,
+ struct selinux_state **state)
+{
+ struct selinux_state *newstate;
+ int rc;
+
+ newstate = kzalloc(sizeof(*newstate), GFP_KERNEL);
+ if (!newstate)
+ return -ENOMEM;
+
+ refcount_set(&newstate->count, 1);
+ INIT_WORK(&newstate->work, selinux_state_free);
+
+ mutex_init(&newstate->status_lock);
+ mutex_init(&newstate->policy_mutex);
+
+ rc = selinux_avc_create(&newstate->avc);
+ if (rc)
+ goto err;
+
+ if (parent)
+ newstate->parent = get_selinux_state(parent);
+
+ *state = newstate;
+ return 0;
+err:
+ kfree(newstate);
+ return rc;
+}
+
+static void selinux_state_free(struct work_struct *work)
+{
+ struct selinux_state *parent, *state =
+ container_of(work, struct selinux_state, work);
+
+ do {
+ parent = state->parent;
+ if (state->status_page)
+ __free_page(state->status_page);
+ selinux_state_policy_free(state);
+ selinux_avc_free(state->avc);
+ kfree(state);
+ state = parent;
+ } while (state && refcount_dec_and_test(&state->count));
+}
+
+void __put_selinux_state(struct selinux_state *state)
+{
+ schedule_work(&state->work);
+}
+
static __init int selinux_init(void)
{
pr_info("SELinux: Initializing.\n");
- memset(&init_selinux_state, 0, sizeof(init_selinux_state));
- enforcing_set(&init_selinux_state, selinux_enforcing_boot);
- selinux_avc_init(&init_selinux_state.avc);
- mutex_init(&init_selinux_state.status_lock);
- mutex_init(&init_selinux_state.policy_mutex);
- current_selinux_state = &init_selinux_state;
+ 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/security.h b/security/selinux/include/security.h
index 168bd75f9cdf..d733d2dabb9f 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -105,9 +105,34 @@ struct selinux_state {
struct selinux_avc *avc;
struct selinux_policy __rcu *policy;
struct mutex policy_mutex;
+ struct selinux_state *parent;
+
+ refcount_t count;
+ struct work_struct work;
} __randomize_layout;
-void selinux_avc_init(struct selinux_avc **avc);
+int selinux_state_create(struct selinux_state *parent,
+ struct selinux_state **state);
+void __put_selinux_state(struct selinux_state *state);
+
+void selinux_policy_free(struct selinux_policy *policy);
+void selinux_state_policy_free(struct selinux_state *state);
+
+int selinux_avc_create(struct selinux_avc **avc);
+void selinux_avc_free(struct selinux_avc *avc);
+
+static inline void put_selinux_state(struct selinux_state *state)
+{
+ if (state && refcount_dec_and_test(&state->count))
+ __put_selinux_state(state);
+}
+
+static inline struct selinux_state *
+get_selinux_state(struct selinux_state *state)
+{
+ refcount_inc(&state->count);
+ return state;
+}
extern struct selinux_state *current_selinux_state;
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index d07d585fa401..28d0fe3b3244 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -90,7 +90,7 @@ static int selinux_fs_info_create(struct super_block *sb)
return -ENOMEM;
fsi->last_ino = SEL_INO_NEXT - 1;
- fsi->state = current_selinux_state;
+ fsi->state = get_selinux_state(current_selinux_state);
fsi->sb = sb;
sb->s_fs_info = fsi;
return 0;
@@ -102,6 +102,7 @@ static void selinux_fs_info_free(struct super_block *sb)
unsigned int i;
if (fsi) {
+ put_selinux_state(fsi->state);
for (i = 0; i < fsi->bool_num; i++)
kfree(fsi->bool_pending_names[i]);
kfree(fsi->bool_pending_names);
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index 430a654b42a5..90a73bc627ca 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -2228,7 +2228,7 @@ static void security_load_policycaps(struct selinux_state *state,
static int security_preserve_bools(struct selinux_policy *oldpolicy,
struct selinux_policy *newpolicy);
-static void selinux_policy_free(struct selinux_policy *policy)
+void selinux_policy_free(struct selinux_policy *policy)
{
if (!policy)
return;
@@ -2240,6 +2240,21 @@ static void selinux_policy_free(struct selinux_policy *policy)
kfree(policy);
}
+void selinux_state_policy_free(struct selinux_state *state)
+{
+ struct selinux_policy *policy;
+
+ /*
+ * This is only called from selinux_state_free() when the
+ * refcount for the state drops to zero, i.e. there are no
+ * remaining references to the state and hence no remaining
+ * references to its policy.
+ */
+ policy = rcu_dereference_protected(state->policy,
+ refcount_read(&state->count) == 0);
+ selinux_policy_free(policy);
+}
+
static void selinux_policy_cond_free(struct selinux_policy *policy)
{
cond_policydb_destroy_dup(&policy->policydb);
--
2.50.1
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [PATCH v7 05/42] netstate,selinux: create the selinux netlink socket per network namespace
2025-08-14 13:25 [PATCH v7 00/42] SELinux namespace support Stephen Smalley
` (3 preceding siblings ...)
2025-08-14 13:25 ` [PATCH v7 04/42] selinux: dynamically allocate selinux namespace Stephen Smalley
@ 2025-08-14 13:25 ` Stephen Smalley
2025-08-14 13:25 ` [PATCH v7 06/42] selinux: limit selinux netlink notifications to init namespace Stephen Smalley
` (36 subsequent siblings)
41 siblings, 0 replies; 43+ messages in thread
From: Stephen Smalley @ 2025-08-14 13:25 UTC (permalink / raw)
To: selinux; +Cc: paul, omosnace, netdev, horms, Stephen Smalley
The selinux netlink socket is used to notify userspace of changes to
the enforcing mode and policy reloads. At present, these notifications
are always sent to the initial network namespace. In order to support
multiple selinux namespaces, each with its own enforcing mode and
policy, we need to create and use a separate selinux netlink socket
for each network namespace.
Without this change, a policy reload in a child selinux namespace
causes a notification to be sent to processes in the init namespace
with a sequence number that may be higher than the policy sequence
number for that namespace. As a result, userspace AVC instances in
the init namespace will then end up rejecting any further access
vector results from its own security server instance due to the
policy sequence number appearing to regress, which in turn causes
all subsequent uncached access checks to fail. Similarly,
without this change, changing enforcing mode in the child selinux
namespace triggers a notification to all userspace AVC instances
in the init namespace that will switch their enforcing modes.
This change does alter SELinux behavior, since previously reloading
policy or changing enforcing mode in a non-init network namespace would
trigger a notification to processes in the init network namespace.
However, this behavior is not being relied upon by existing userspace
AFAICT and is arguably wrong regardless.
Signed-off-by: Stephen Smalley <stephen.smalley.work@gmail.com>
---
include/net/net_namespace.h | 3 +++
security/selinux/netlink.c | 31 +++++++++++++++++++++++++------
2 files changed, 28 insertions(+), 6 deletions(-)
diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h
index 025a7574b275..06f2501ad9a9 100644
--- a/include/net/net_namespace.h
+++ b/include/net/net_namespace.h
@@ -196,6 +196,9 @@ struct net {
/* Move to a better place when the config guard is removed. */
struct mutex rtnl_mutex;
#endif
+#if IS_ENABLED(CONFIG_SECURITY_SELINUX)
+ struct sock *selnl;
+#endif
} __randomize_layout;
#include <linux/seq_file_net.h>
diff --git a/security/selinux/netlink.c b/security/selinux/netlink.c
index 1760aee712fd..03678a76f4bb 100644
--- a/security/selinux/netlink.c
+++ b/security/selinux/netlink.c
@@ -19,8 +19,6 @@
#include "security.h"
-static struct sock *selnl __ro_after_init;
-
static int selnl_msglen(int msgtype)
{
int ret = 0;
@@ -66,6 +64,7 @@ static void selnl_add_payload(struct nlmsghdr *nlh, int len, int msgtype, void *
static void selnl_notify(int msgtype, void *data)
{
+ struct sock *selnl = current->nsproxy->net_ns->selnl;
int len;
sk_buff_data_t tmp;
struct sk_buff *skb;
@@ -105,16 +104,36 @@ void selnl_notify_policyload(u32 seqno)
selnl_notify(SELNL_MSG_POLICYLOAD, &seqno);
}
-static int __init selnl_init(void)
+static int __net_init selnl_net_init(struct net *net)
{
+ struct sock *sk;
struct netlink_kernel_cfg cfg = {
.groups = SELNLGRP_MAX,
.flags = NL_CFG_F_NONROOT_RECV,
};
- selnl = netlink_kernel_create(&init_net, NETLINK_SELINUX, &cfg);
- if (selnl == NULL)
- panic("SELinux: Cannot create netlink socket.");
+ sk = netlink_kernel_create(net, NETLINK_SELINUX, &cfg);
+ if (!sk)
+ return -ENOMEM;
+ net->selnl = sk;
+ return 0;
+}
+
+static void __net_exit selnl_net_exit(struct net *net)
+{
+ netlink_kernel_release(net->selnl);
+ net->selnl = NULL;
+}
+
+static struct pernet_operations selnl_net_ops = {
+ .init = selnl_net_init,
+ .exit = selnl_net_exit,
+};
+
+static int __init selnl_init(void)
+{
+ if (register_pernet_subsys(&selnl_net_ops))
+ panic("Could not register selinux netlink operations\n");
return 0;
}
--
2.50.1
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [PATCH v7 06/42] selinux: limit selinux netlink notifications to init namespace
2025-08-14 13:25 [PATCH v7 00/42] SELinux namespace support Stephen Smalley
` (4 preceding siblings ...)
2025-08-14 13:25 ` [PATCH v7 05/42] netstate,selinux: create the selinux netlink socket per network namespace Stephen Smalley
@ 2025-08-14 13:25 ` Stephen Smalley
2025-08-14 13:25 ` [PATCH v7 07/42] selinux: support per-task/cred selinux namespace Stephen Smalley
` (35 subsequent siblings)
41 siblings, 0 replies; 43+ messages in thread
From: Stephen Smalley @ 2025-08-14 13:25 UTC (permalink / raw)
To: selinux; +Cc: paul, omosnace, netdev, horms, Stephen Smalley
To prevent modifying the enforcing status or resetting the AVC
in the userspace policy enforcers, do not deliver SELinux netlink
notifications to the init network namespace unless they were
generated by the init SELinux namespace. If you want to receive
SELinux netlink notifications in a non-init SELinux namespace,
then unshare your network namespace too. Otherwise, just map
the SELinux status page (/sys/fs/selinux/status) to check the
enforcing status and to detect policy reloads which is now the
default behavior in libselinux on any kernels that support it.
Signed-off-by: Stephen Smalley <stephen.smalley.work@gmail.com>
---
security/selinux/hooks.c | 2 +-
security/selinux/include/security.h | 1 +
security/selinux/netlink.c | 11 +++++++++++
3 files changed, 13 insertions(+), 1 deletion(-)
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 7c405f3289db..0d9ec74b6144 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -107,7 +107,7 @@
#define SELINUX_INODE_INIT_XATTRS 1
-static struct selinux_state *init_selinux_state;
+struct selinux_state *init_selinux_state;
struct selinux_state *current_selinux_state;
/* SECMARK reference count */
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
index d733d2dabb9f..950601a28cd5 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -134,6 +134,7 @@ get_selinux_state(struct selinux_state *state)
return state;
}
+extern struct selinux_state *init_selinux_state;
extern struct selinux_state *current_selinux_state;
static inline bool selinux_initialized(const struct selinux_state *state)
diff --git a/security/selinux/netlink.c b/security/selinux/netlink.c
index 03678a76f4bb..fb55d3ba25f5 100644
--- a/security/selinux/netlink.c
+++ b/security/selinux/netlink.c
@@ -70,6 +70,17 @@ static void selnl_notify(int msgtype, void *data)
struct sk_buff *skb;
struct nlmsghdr *nlh;
+ /*
+ * Do not deliver SELinux netlink notifications to the
+ * init network namespace if they were not generated
+ * by the init selinux namespace. Unshare network
+ * namespace if you want to receive them; otherwise,
+ * just get updates via the SELinux status page.
+ */
+ if (current_selinux_state != init_selinux_state &&
+ net_eq(current->nsproxy->net_ns, &init_net))
+ return;
+
len = selnl_msglen(msgtype);
skb = nlmsg_new(len, GFP_USER);
--
2.50.1
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [PATCH v7 07/42] selinux: support per-task/cred selinux namespace
2025-08-14 13:25 [PATCH v7 00/42] SELinux namespace support Stephen Smalley
` (5 preceding siblings ...)
2025-08-14 13:25 ` [PATCH v7 06/42] selinux: limit selinux netlink notifications to init namespace Stephen Smalley
@ 2025-08-14 13:25 ` Stephen Smalley
2025-08-14 13:25 ` [PATCH v7 08/42] selinux: introduce cred_selinux_state() and use it Stephen Smalley
` (34 subsequent siblings)
41 siblings, 0 replies; 43+ messages in thread
From: Stephen Smalley @ 2025-08-14 13:25 UTC (permalink / raw)
To: selinux; +Cc: paul, omosnace, netdev, horms, Stephen Smalley
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 | 41 +---------------------
security/selinux/include/security.h | 48 +++++++++++++++++++++++++-
3 files changed, 95 insertions(+), 47 deletions(-)
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 0d9ec74b6144..6a21c39cfa91 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -107,9 +107,6 @@
#define SELINUX_INODE_INIT_XATTRS 1
-struct selinux_state *init_selinux_state;
-struct selinux_state *current_selinux_state;
-
/* SECMARK reference count */
static atomic_t selinux_secmark_refcount = ATOMIC_INIT(0);
@@ -206,6 +203,8 @@ static int selinux_lsm_notifier_avc_callback(u32 event)
return 0;
}
+struct selinux_state *init_selinux_state;
+
/*
* initialise the security for the init task
*/
@@ -217,6 +216,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);
}
/*
@@ -230,6 +230,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)
@@ -260,10 +281,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;
}
@@ -4214,6 +4237,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
*/
@@ -4224,6 +4259,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;
}
@@ -4236,6 +4274,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)
@@ -6650,7 +6691,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,
@@ -7549,6 +7590,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),
@@ -7809,7 +7851,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 a4376a0ce032..cfac79df617b 100644
--- a/security/selinux/include/objsec.h
+++ b/security/selinux/include/objsec.h
@@ -29,36 +29,11 @@
#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 */
- bool permissive_neveraudit; /* permissive and neveraudit */
- } avdcache;
-} __randomize_layout;
-
static inline bool task_avdcache_permnoaudit(struct task_security_struct *tsec)
{
return (tsec->avdcache.permissive_neveraudit &&
tsec->sid == tsec->avdcache.sid &&
- tsec->avdcache.seqno ==
- avc_policy_seqno(current_selinux_state));
+ tsec->avdcache.seqno == avc_policy_seqno(tsec->state));
}
enum label_initialized {
@@ -172,10 +147,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)
{
@@ -202,16 +173,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 950601a28cd5..ae22ef45321e 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"
@@ -135,7 +137,51 @@ get_selinux_state(struct selinux_state *state)
}
extern struct selinux_state *init_selinux_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 */
+ bool permissive_neveraudit; /* permissive and neveraudit */
+ } 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.50.1
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [PATCH v7 08/42] selinux: introduce cred_selinux_state() and use it
2025-08-14 13:25 [PATCH v7 00/42] SELinux namespace support Stephen Smalley
` (6 preceding siblings ...)
2025-08-14 13:25 ` [PATCH v7 07/42] selinux: support per-task/cred selinux namespace Stephen Smalley
@ 2025-08-14 13:25 ` Stephen Smalley
2025-08-14 13:26 ` [PATCH v7 09/42] selinux: init inode from nearest initialized namespace Stephen Smalley
` (33 subsequent siblings)
41 siblings, 0 replies; 43+ messages in thread
From: Stephen Smalley @ 2025-08-14 13:25 UTC (permalink / raw)
To: selinux; +Cc: paul, omosnace, netdev, horms, Stephen Smalley
When using the SID from a cred, we should pass the selinux
namespace associated with the cred on security server calls
rather than the current selinux namespace, since they could differ.
In some of these cases, the cred is always obtained from the current
task so there is no real change, but this is cleaner and hopefully
less fragile. In other cases, the cred could in fact differ.
Signed-off-by: Stephen Smalley <stephen.smalley.work@gmail.com>
---
security/selinux/hooks.c | 44 ++++++++++++++---------------
security/selinux/include/security.h | 2 ++
2 files changed, 24 insertions(+), 22 deletions(-)
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 6a21c39cfa91..3135378e9229 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -464,13 +464,13 @@ static int may_context_mount_sb_relabel(u32 sid,
const struct task_security_struct *tsec = selinux_cred(cred);
int rc;
- rc = avc_has_perm(current_selinux_state,
+ rc = avc_has_perm(cred_selinux_state(cred),
tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
FILESYSTEM__RELABELFROM, NULL);
if (rc)
return rc;
- rc = avc_has_perm(current_selinux_state,
+ rc = avc_has_perm(cred_selinux_state(cred),
tsec->sid, sid, SECCLASS_FILESYSTEM,
FILESYSTEM__RELABELTO, NULL);
return rc;
@@ -482,13 +482,13 @@ static int may_context_mount_inode_relabel(u32 sid,
{
const struct task_security_struct *tsec = selinux_cred(cred);
int rc;
- rc = avc_has_perm(current_selinux_state,
+ rc = avc_has_perm(cred_selinux_state(cred),
tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
FILESYSTEM__RELABELFROM, NULL);
if (rc)
return rc;
- rc = avc_has_perm(current_selinux_state,
+ rc = avc_has_perm(cred_selinux_state(cred),
sid, sbsec->sid, SECCLASS_FILESYSTEM,
FILESYSTEM__ASSOCIATE, NULL);
return rc;
@@ -1683,10 +1683,10 @@ static int cred_has_capability(const struct cred *cred,
return -EINVAL;
}
- rc = avc_has_perm_noaudit(current_selinux_state,
+ rc = avc_has_perm_noaudit(cred_selinux_state(cred),
sid, sid, sclass, av, 0, &avd);
if (!(opts & CAP_OPT_NOAUDIT)) {
- int rc2 = avc_audit(current_selinux_state,
+ int rc2 = avc_audit(cred_selinux_state(cred),
sid, sid, sclass, av, &avd, rc, &ad);
if (rc2)
return rc2;
@@ -1711,7 +1711,7 @@ static int inode_has_perm(const struct cred *cred,
sid = cred_sid(cred);
isec = selinux_inode(inode);
- return avc_has_perm(current_selinux_state,
+ return avc_has_perm(cred_selinux_state(cred),
sid, isec->sid, isec->sclass, perms, adp);
}
@@ -1791,7 +1791,7 @@ static int file_has_perm(const struct cred *cred,
ad.u.file = file;
if (sid != fsec->sid) {
- rc = avc_has_perm(current_selinux_state,
+ rc = avc_has_perm(cred_selinux_state(cred),
sid, fsec->sid,
SECCLASS_FD,
FD__USE,
@@ -2006,7 +2006,7 @@ static int superblock_has_perm(const struct cred *cred,
u32 sid = cred_sid(cred);
sbsec = selinux_superblock(sb);
- return avc_has_perm(current_selinux_state,
+ return avc_has_perm(cred_selinux_state(cred),
sid, sbsec->sid, SECCLASS_FILESYSTEM, perms, ad);
}
@@ -2188,7 +2188,7 @@ static int selinux_capset(struct cred *new, const struct cred *old,
const kernel_cap_t *inheritable,
const kernel_cap_t *permitted)
{
- return avc_has_perm(current_selinux_state,
+ return avc_has_perm(cred_selinux_state(old),
cred_sid(old), cred_sid(new), SECCLASS_PROCESS,
PROCESS__SETCAP, NULL);
}
@@ -3898,7 +3898,7 @@ static int ioctl_has_perm(const struct cred *cred, struct file *file,
ad.u.op->path = file->f_path;
if (ssid != fsec->sid) {
- rc = avc_has_perm(current_selinux_state,
+ rc = avc_has_perm(cred_selinux_state(cred),
ssid, fsec->sid,
SECCLASS_FD,
FD__USE,
@@ -4009,7 +4009,7 @@ static int file_map_prot_check(struct file *file, unsigned long prot, int shared
* private file mapping that will also be writable.
* This has an additional check.
*/
- rc = avc_has_perm(current_selinux_state,
+ rc = avc_has_perm(cred_selinux_state(cred),
sid, sid, SECCLASS_PROCESS,
PROCESS__EXECMEM, NULL);
if (rc)
@@ -4089,14 +4089,14 @@ static int selinux_file_mprotect(struct vm_area_struct *vma,
*/
if (vma->vm_start >= vma->vm_mm->start_brk &&
vma->vm_end <= vma->vm_mm->brk) {
- rc = avc_has_perm(current_selinux_state,
- sid, sid, SECCLASS_PROCESS,
- PROCESS__EXECHEAP, NULL);
+ rc = avc_has_perm(cred_selinux_state(cred), sid, sid,
+ SECCLASS_PROCESS, PROCESS__EXECHEAP,
+ NULL);
} else if (!vma->vm_file && (vma_is_initial_stack(vma) ||
vma_is_stack_for_current(vma))) {
- rc = avc_has_perm(current_selinux_state,
- sid, sid, SECCLASS_PROCESS,
- PROCESS__EXECSTACK, NULL);
+ rc = avc_has_perm(cred_selinux_state(cred), sid, sid,
+ SECCLASS_PROCESS, PROCESS__EXECSTACK,
+ NULL);
} else if (vma->vm_file && vma->anon_vma) {
/*
* We are making executable a file mapping that has
@@ -4299,7 +4299,7 @@ static int selinux_kernel_act_as(struct cred *new, u32 secid)
u32 sid = current_sid();
int ret;
- ret = avc_has_perm(current_selinux_state,
+ ret = avc_has_perm(tsec->state,
sid, secid,
SECCLASS_KERNEL_SERVICE,
KERNEL_SERVICE__USE_AS_OVERRIDE,
@@ -4324,7 +4324,7 @@ static int selinux_kernel_create_files_as(struct cred *new, struct inode *inode)
u32 sid = current_sid();
int ret;
- ret = avc_has_perm(current_selinux_state,
+ ret = avc_has_perm(tsec->state,
sid, isec->sid,
SECCLASS_KERNEL_SERVICE,
KERNEL_SERVICE__CREATE_FILES_AS,
@@ -4516,7 +4516,7 @@ static int selinux_task_prlimit(const struct cred *cred, const struct cred *tcre
av |= PROCESS__SETRLIMIT;
if (flags & LSM_PRLIMIT_READ)
av |= PROCESS__GETRLIMIT;
- return avc_has_perm(current_selinux_state,
+ return avc_has_perm(cred_selinux_state(cred),
cred_sid(cred), cred_sid(tcred),
SECCLASS_PROCESS, av, NULL);
}
@@ -7101,7 +7101,7 @@ static int selinux_key_permission(key_ref_t key_ref,
key = key_ref_to_ptr(key_ref);
ksec = selinux_key(key);
- return avc_has_perm(current_selinux_state,
+ return avc_has_perm(cred_selinux_state(cred),
sid, ksec->sid, SECCLASS_KEY, perm, NULL);
}
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
index ae22ef45321e..329b1fe48057 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -183,6 +183,8 @@ static inline u32 current_sid(void)
#define current_selinux_state (selinux_cred(current_cred())->state)
+#define cred_selinux_state(cred) (selinux_cred(cred)->state)
+
static inline bool selinux_initialized(const struct selinux_state *state)
{
/* do a synchronized load to avoid race conditions */
--
2.50.1
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [PATCH v7 09/42] selinux: init inode from nearest initialized namespace
2025-08-14 13:25 [PATCH v7 00/42] SELinux namespace support Stephen Smalley
` (7 preceding siblings ...)
2025-08-14 13:25 ` [PATCH v7 08/42] selinux: introduce cred_selinux_state() and use it Stephen Smalley
@ 2025-08-14 13:26 ` Stephen Smalley
2025-08-14 13:26 ` [PATCH v7 10/42] selinux: add a selinuxfs interface to unshare selinux namespace Stephen Smalley
` (32 subsequent siblings)
41 siblings, 0 replies; 43+ messages in thread
From: Stephen Smalley @ 2025-08-14 13:26 UTC (permalink / raw)
To: selinux; +Cc: paul, omosnace, netdev, horms, Stephen Smalley
Previously inode_doinit_with_dentry() was only checking sbsec->flags
to see if it should defer the inode security blob initialization,
which was fine when there was only a single SELinux state/namespace
since that could only be set if the state was initialized. However,
with the introduction of SELinux namespaces, the superblock could be
initialized in the parent (or other ancestor) namespace but the
current namespace may not yet be initialized (i.e. the namespace was
unshared but no policy has yet been loaded into it). Check for this
case, and if uninitialized, find the nearest ancestor SELinux
namespace that is initialized and use it instead. In the case where
the init SELinux namespace was never initialized (i.e. no policy
loaded on the host), then defer initialization of the inode.
Signed-off-by: Stephen Smalley <stephen.smalley.work@gmail.com>
---
security/selinux/hooks.c | 45 +++++++++++++++++------------
security/selinux/include/security.h | 6 ++--
2 files changed, 30 insertions(+), 21 deletions(-)
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 3135378e9229..65d9762b992a 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -1347,10 +1347,9 @@ static inline u16 socket_type_to_security_class(int family, int type, int protoc
return SECCLASS_SOCKET;
}
-static int selinux_genfs_get_sid(struct dentry *dentry,
- u16 tclass,
- u16 flags,
- u32 *sid)
+static int selinux_genfs_get_sid(struct selinux_state *state,
+ struct dentry *dentry, u16 tclass,
+ u16 flags, u32 *sid)
{
int rc;
struct super_block *sb = dentry->d_sb;
@@ -1373,8 +1372,8 @@ static int selinux_genfs_get_sid(struct dentry *dentry,
path++;
}
}
- rc = security_genfs_sid(current_selinux_state, sb->s_type->name,
- path, tclass, sid);
+ rc = security_genfs_sid(state, sb->s_type->name, path,
+ tclass, sid);
if (rc == -ENOENT) {
/* No match in policy, mark as unlabeled. */
*sid = SECINITSID_UNLABELED;
@@ -1385,7 +1384,9 @@ static int selinux_genfs_get_sid(struct dentry *dentry,
return rc;
}
-static int inode_doinit_use_xattr(struct inode *inode, struct dentry *dentry,
+static int inode_doinit_use_xattr(struct selinux_state *state,
+ struct inode *inode,
+ struct dentry *dentry,
u32 def_sid, u32 *sid)
{
#define INITCONTEXTLEN 255
@@ -1428,8 +1429,8 @@ static int inode_doinit_use_xattr(struct inode *inode, struct dentry *dentry,
return 0;
}
- rc = security_context_to_sid_default(current_selinux_state, context, rc,
- sid, def_sid, GFP_NOFS);
+ rc = security_context_to_sid_default(state, context, rc, sid,
+ def_sid, GFP_NOFS);
if (rc) {
char *dev = inode->i_sb->s_id;
unsigned long ino = inode->i_ino;
@@ -1449,6 +1450,7 @@ static int inode_doinit_use_xattr(struct inode *inode, struct dentry *dentry,
/* The inode's security attributes must be initialized before first use. */
static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentry)
{
+ struct selinux_state *state = current_selinux_state;
struct superblock_security_struct *sbsec = NULL;
struct inode_security_struct *isec = selinux_inode(inode);
u32 task_sid, sid = 0;
@@ -1466,8 +1468,14 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
if (isec->sclass == SECCLASS_FILE)
isec->sclass = inode_mode_to_security_class(inode->i_mode);
+ /*
+ * Find an initialized state to use.
+ */
+ while (state && !selinux_initialized(state))
+ state = state->parent;
+
sbsec = selinux_superblock(inode->i_sb);
- if (!(sbsec->flags & SE_SBINITIALIZED)) {
+ if (!state || !(sbsec->flags & SE_SBINITIALIZED)) {
/* Defer initialization until selinux_complete_init,
after the initial policy is loaded and the security
server is ready to handle calls. */
@@ -1524,8 +1532,8 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
goto out_invalid;
}
- rc = inode_doinit_use_xattr(inode, dentry, sbsec->def_sid,
- &sid);
+ rc = inode_doinit_use_xattr(state, inode, dentry,
+ sbsec->def_sid, &sid);
dput(dentry);
if (rc)
goto out;
@@ -1538,8 +1546,8 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
sid = sbsec->sid;
/* Try to obtain a transition SID. */
- rc = security_transition_sid(current_selinux_state, task_sid, sid,
- sclass, NULL, &sid);
+ rc = security_transition_sid(state, task_sid, sid, sclass,
+ NULL, &sid);
if (rc)
goto out;
break;
@@ -1552,7 +1560,7 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
if ((sbsec->flags & SE_SBGENFS) &&
(!S_ISLNK(inode->i_mode) ||
- selinux_policycap_genfs_seclabel_symlinks())) {
+ selinux_policycap_genfs_seclabel_symlinks(state))) {
/* We must have a dentry to determine the label on
* procfs inodes */
if (opt_dentry) {
@@ -1579,7 +1587,7 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
*/
if (!dentry)
goto out_invalid;
- rc = selinux_genfs_get_sid(dentry, sclass,
+ rc = selinux_genfs_get_sid(state, dentry, sclass,
sbsec->flags, &sid);
if (rc) {
dput(dentry);
@@ -1588,8 +1596,9 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
if ((sbsec->flags & SE_SBGENFS_XATTR) &&
(inode->i_opflags & IOP_XATTR)) {
- rc = inode_doinit_use_xattr(inode, dentry,
- sid, &sid);
+ rc = inode_doinit_use_xattr(state, inode,
+ dentry, sid,
+ &sid);
if (rc) {
dput(dentry);
goto out;
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
index 329b1fe48057..c4a0766aa24e 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -261,11 +261,11 @@ static inline bool selinux_policycap_nnp_nosuid_transition(void)
->policycap[POLICYDB_CAP_NNP_NOSUID_TRANSITION]);
}
-static inline bool selinux_policycap_genfs_seclabel_symlinks(void)
+static inline bool
+selinux_policycap_genfs_seclabel_symlinks(struct selinux_state *state)
{
return READ_ONCE(
- current_selinux_state
- ->policycap[POLICYDB_CAP_GENFS_SECLABEL_SYMLINKS]);
+ state->policycap[POLICYDB_CAP_GENFS_SECLABEL_SYMLINKS]);
}
static inline bool selinux_policycap_ioctl_skip_cloexec(void)
--
2.50.1
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [PATCH v7 10/42] selinux: add a selinuxfs interface to unshare selinux namespace
2025-08-14 13:25 [PATCH v7 00/42] SELinux namespace support Stephen Smalley
` (8 preceding siblings ...)
2025-08-14 13:26 ` [PATCH v7 09/42] selinux: init inode from nearest initialized namespace Stephen Smalley
@ 2025-08-14 13:26 ` Stephen Smalley
2025-08-14 13:26 ` [PATCH v7 11/42] selinux: add limits for SELinux namespaces Stephen Smalley
` (31 subsequent siblings)
41 siblings, 0 replies; 43+ messages in thread
From: Stephen Smalley @ 2025-08-14 13:26 UTC (permalink / raw)
To: selinux; +Cc: paul, omosnace, netdev, horms, Stephen Smalley
Provide a userspace API to unshare the selinux namespace.
Currently implemented via a selinuxfs node. This could be
coupled with unsharing of other namespaces (e.g. mount namespace,
network namespace) that will always be needed or left independent.
Don't get hung up on the interface itself, it is just to allow
experimentation and testing.
Sample usage:
sudo bash
echo 1 > /sys/fs/selinux/unshare # unshare SELinux namespace
unshare -m -n # unshare mount and network namespaces
umount /sys/fs/selinux # unmount parent selinuxns
mount -t selinuxfs none /sys/fs/selinux # mount child selinuxns
id # view initial SID in child namespace, now kernel/init
load_policy # load a policy into child namespace
id # view context in child namespace after policy load
getenforce # check enforcing status of child namespace
The above will show that the process now views itself as running in the
kernel/init domain in permissive mode, as would be the case at boot.
From a different shell on the host system, running ps -eZ or
cat /proc/<pid>/attr/current will show that the process that
unshared its selinux namespace is still running in its original
context in the initial namespace, and getenforce will show the
the initial namespace remains enforcing. Enforcing mode or policy
changes in the child will not affect the parent.
Signed-off-by: Stephen Smalley <stephen.smalley.work@gmail.com>
---
security/selinux/include/classmap.h | 2 +-
security/selinux/selinuxfs.c | 66 +++++++++++++++++++++++++++++
2 files changed, 67 insertions(+), 1 deletion(-)
diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h
index 5665aa5e7853..55903f68e285 100644
--- a/security/selinux/include/classmap.h
+++ b/security/selinux/include/classmap.h
@@ -50,7 +50,7 @@ const struct security_class_mapping secclass_map[] = {
{ "compute_av", "compute_create", "compute_member", "check_context",
"load_policy", "compute_relabel", "compute_user", "setenforce",
"setbool", "setsecparam", "setcheckreqprot", "read_policy",
- "validate_trans", NULL } },
+ "validate_trans", "unshare", NULL } },
{ "process",
{ "fork", "transition", "sigchld", "sigkill",
"sigstop", "signull", "signal", "ptrace",
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index 28d0fe3b3244..70dc9fb3269e 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -64,6 +64,7 @@ enum sel_inos {
SEL_STATUS, /* export current status using mmap() */
SEL_POLICY, /* allow userspace to read the in kernel policy */
SEL_VALIDATE_TRANS, /* compute validatetrans decision */
+ SEL_UNSHARE, /* unshare selinux namespace */
SEL_INO_NEXT, /* The next inode number to use */
};
@@ -318,6 +319,70 @@ static const struct file_operations sel_disable_ops = {
.llseek = generic_file_llseek,
};
+static ssize_t sel_write_unshare(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+
+{
+ struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
+ struct selinux_state *state = fsi->state;
+ char *page;
+ ssize_t length;
+ bool set;
+ int rc;
+
+ if (count >= PAGE_SIZE)
+ return -ENOMEM;
+
+ /* No partial writes. */
+ if (*ppos != 0)
+ return -EINVAL;
+
+ rc = avc_has_perm(current_selinux_state, current_sid(),
+ SECINITSID_SECURITY, SECCLASS_SECURITY,
+ SECURITY__UNSHARE, NULL);
+ if (rc)
+ return rc;
+
+ page = memdup_user_nul(buf, count);
+ if (IS_ERR(page))
+ return PTR_ERR(page);
+
+ length = -EINVAL;
+ if (kstrtobool(page, &set))
+ goto out;
+
+ if (set) {
+ struct cred *cred = prepare_creds();
+ struct task_security_struct *tsec;
+
+ if (!cred) {
+ length = -ENOMEM;
+ goto out;
+ }
+ tsec = selinux_cred(cred);
+ if (selinux_state_create(state, &tsec->state)) {
+ abort_creds(cred);
+ length = -ENOMEM;
+ goto out;
+ }
+ tsec->osid = tsec->sid = SECINITSID_INIT;
+ tsec->exec_sid = tsec->create_sid = tsec->keycreate_sid =
+ tsec->sockcreate_sid = SECSID_NULL;
+ tsec->parent_cred = get_current_cred();
+ commit_creds(cred);
+ }
+
+ length = count;
+out:
+ kfree(page);
+ return length;
+}
+
+static const struct file_operations sel_unshare_ops = {
+ .write = sel_write_unshare,
+ .llseek = generic_file_llseek,
+};
+
static ssize_t sel_read_policyvers(struct file *filp, char __user *buf,
size_t count, loff_t *ppos)
{
@@ -2053,6 +2118,7 @@ static int sel_fill_super(struct super_block *sb, struct fs_context *fc)
[SEL_POLICY] = {"policy", &sel_policy_ops, S_IRUGO},
[SEL_VALIDATE_TRANS] = {"validatetrans", &sel_transition_ops,
S_IWUGO},
+ [SEL_UNSHARE] = {"unshare", &sel_unshare_ops, 0200},
/* last one */ {"", NULL, 0}
};
--
2.50.1
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [PATCH v7 11/42] selinux: add limits for SELinux namespaces
2025-08-14 13:25 [PATCH v7 00/42] SELinux namespace support Stephen Smalley
` (9 preceding siblings ...)
2025-08-14 13:26 ` [PATCH v7 10/42] selinux: add a selinuxfs interface to unshare selinux namespace Stephen Smalley
@ 2025-08-14 13:26 ` Stephen Smalley
2025-08-14 13:26 ` [PATCH v7 12/42] selinux: exempt creation of init SELinux namespace from limits Stephen Smalley
` (30 subsequent siblings)
41 siblings, 0 replies; 43+ messages in thread
From: Stephen Smalley @ 2025-08-14 13:26 UTC (permalink / raw)
To: selinux; +Cc: paul, omosnace, netdev, horms, Stephen Smalley
Add maxns and maxnsdepth limits for SELinux namespaces
to enable control over the max number of SELinux namespaces
and the max depth to which one can nest SELinux namespaces.
Provide Kconfig options to control the default values for both
limits, and allow them to be overridden via selinuxfs in the
init SELinux namespace only.
Signed-off-by: Stephen Smalley <stephen.smalley.work@gmail.com>
---
security/selinux/Kconfig | 18 ++++
security/selinux/hooks.c | 18 +++-
security/selinux/include/classmap.h | 2 +-
security/selinux/include/security.h | 6 +-
security/selinux/selinuxfs.c | 129 ++++++++++++++++++++++++++++
5 files changed, 169 insertions(+), 4 deletions(-)
diff --git a/security/selinux/Kconfig b/security/selinux/Kconfig
index 61abc1e094a8..82db54462253 100644
--- a/security/selinux/Kconfig
+++ b/security/selinux/Kconfig
@@ -87,3 +87,21 @@ config SECURITY_SELINUX_DEBUG
echo -n 'file "security/selinux/*" +p' > \
/proc/dynamic_debug/control
+
+config SECURITY_SELINUX_MAXNS
+ int "SELinux default maximum number of namespaces"
+ depends on SECURITY_SELINUX
+ range 0 65535
+ default 65535
+ help
+ This option sets the default maximum number of SELinux namespaces.
+ The value may be viewed or modified via /sys/fs/selinux/maxns.
+
+config SECURITY_SELINUX_MAXNSDEPTH
+ int "SELinux default maximum depth of namespaces"
+ depends on SECURITY_SELINUX
+ range 0 32
+ default 32
+ help
+ This option sets the default maximum depth of SELinux namespaces.
+ The value may be viewed or modified via /sys/fs/selinux/maxnsdepth.
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 65d9762b992a..739f58b134ed 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -7802,12 +7802,23 @@ static struct security_hook_list selinux_hooks[] __ro_after_init = {
static void selinux_state_free(struct work_struct *work);
+unsigned int selinux_maxns = CONFIG_SECURITY_SELINUX_MAXNS;
+unsigned int selinux_maxnsdepth = CONFIG_SECURITY_SELINUX_MAXNSDEPTH;
+
+static atomic_t selinux_nsnum = ATOMIC_INIT(0);
+
int selinux_state_create(struct selinux_state *parent,
struct selinux_state **state)
{
struct selinux_state *newstate;
int rc;
+ if (atomic_read(&selinux_nsnum) >= selinux_maxns)
+ return -ENOSPC;
+
+ if (parent && parent->depth >= selinux_maxnsdepth)
+ return -ENOSPC;
+
newstate = kzalloc(sizeof(*newstate), GFP_KERNEL);
if (!newstate)
return -ENOMEM;
@@ -7822,8 +7833,12 @@ int selinux_state_create(struct selinux_state *parent,
if (rc)
goto err;
- if (parent)
+ if (parent) {
newstate->parent = get_selinux_state(parent);
+ newstate->depth = parent->depth + 1;
+ }
+
+ atomic_inc(&selinux_nsnum);
*state = newstate;
return 0;
@@ -7843,6 +7858,7 @@ static void selinux_state_free(struct work_struct *work)
__free_page(state->status_page);
selinux_state_policy_free(state);
selinux_avc_free(state->avc);
+ atomic_dec(&selinux_nsnum);
kfree(state);
state = parent;
} while (state && refcount_dec_and_test(&state->count));
diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h
index 55903f68e285..be52ebb6b94a 100644
--- a/security/selinux/include/classmap.h
+++ b/security/selinux/include/classmap.h
@@ -50,7 +50,7 @@ const struct security_class_mapping secclass_map[] = {
{ "compute_av", "compute_create", "compute_member", "check_context",
"load_policy", "compute_relabel", "compute_user", "setenforce",
"setbool", "setsecparam", "setcheckreqprot", "read_policy",
- "validate_trans", "unshare", NULL } },
+ "validate_trans", "unshare", "setmaxns", "setmaxnsdepth", NULL } },
{ "process",
{ "fork", "transition", "sigchld", "sigkill",
"sigstop", "signull", "signal", "ptrace",
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
index c4a0766aa24e..d8312a39a265 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -111,8 +111,12 @@ struct selinux_state {
refcount_t count;
struct work_struct work;
+ unsigned short depth;
} __randomize_layout;
+extern struct selinux_state *init_selinux_state;
+
+extern unsigned int selinux_maxns, selinux_maxnsdepth;
int selinux_state_create(struct selinux_state *parent,
struct selinux_state **state);
void __put_selinux_state(struct selinux_state *state);
@@ -136,8 +140,6 @@ get_selinux_state(struct selinux_state *state)
return state;
}
-extern struct selinux_state *init_selinux_state;
-
struct avdc_entry {
u32 isid; /* inode SID */
u32 allowed; /* allowed permission bitmask */
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index 70dc9fb3269e..06e2aeb478cd 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -65,6 +65,8 @@ enum sel_inos {
SEL_POLICY, /* allow userspace to read the in kernel policy */
SEL_VALIDATE_TRANS, /* compute validatetrans decision */
SEL_UNSHARE, /* unshare selinux namespace */
+ SEL_MAXNS, /* maximum number of SELinux namespaces */
+ SEL_MAXNSDEPTH, /* maximum depth of SELinux namespaces */
SEL_INO_NEXT, /* The next inode number to use */
};
@@ -383,6 +385,131 @@ static const struct file_operations sel_unshare_ops = {
.llseek = generic_file_llseek,
};
+static ssize_t sel_read_maxns(struct file *filp, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ char tmpbuf[TMPBUFLEN];
+ ssize_t length;
+
+ length = scnprintf(tmpbuf, TMPBUFLEN, "%u", selinux_maxns);
+ return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
+}
+
+
+static ssize_t sel_write_maxns(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+
+{
+ struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
+ struct selinux_state *state = fsi->state;
+ char *page = NULL;
+ ssize_t length;
+
+ /*
+ * Only permit setting from the init SELinux namespace, and only
+ * on the init SELinux namespace.
+ */
+ if (current_selinux_state != init_selinux_state ||
+ state != init_selinux_state)
+ return -EPERM;
+
+ length = avc_has_perm(current_selinux_state,
+ current_sid(), SECINITSID_SECURITY,
+ SECCLASS_SECURITY, SECURITY__SETMAXNS,
+ NULL);
+ if (length)
+ return length;
+
+ if (count >= PAGE_SIZE)
+ return -ENOMEM;
+
+ /* No partial writes. */
+ if (*ppos != 0)
+ return -EINVAL;
+
+ page = memdup_user_nul(buf, count);
+ if (IS_ERR(page))
+ return PTR_ERR(page);
+
+ length = kstrtouint(page, 0, &selinux_maxns);
+ if (length)
+ goto out;
+
+ length = count;
+out:
+ kfree(page);
+ return length;
+}
+
+static const struct file_operations sel_maxns_ops = {
+ .read = sel_read_maxns,
+ .write = sel_write_maxns,
+ .llseek = generic_file_llseek,
+};
+
+static ssize_t sel_read_maxnsdepth(struct file *filp, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ char tmpbuf[TMPBUFLEN];
+ ssize_t length;
+
+ length = scnprintf(tmpbuf, TMPBUFLEN, "%u", selinux_maxnsdepth);
+ return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
+}
+
+
+static ssize_t sel_write_maxnsdepth(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+
+{
+ struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
+ struct selinux_state *state = fsi->state;
+ char *page = NULL;
+ ssize_t length;
+
+ /*
+ * Only permit setting from the init SELinux namespace, and only
+ * on the init SELinux namespace.
+ */
+ if (current_selinux_state != init_selinux_state ||
+ state != init_selinux_state)
+ return -EPERM;
+
+ length = avc_has_perm(current_selinux_state,
+ current_sid(), SECINITSID_SECURITY,
+ SECCLASS_SECURITY, SECURITY__SETMAXNSDEPTH,
+ NULL);
+ if (length)
+ return length;
+
+ if (count >= PAGE_SIZE)
+ return -ENOMEM;
+
+ /* No partial writes. */
+ if (*ppos != 0)
+ return -EINVAL;
+
+ page = memdup_user_nul(buf, count);
+ if (IS_ERR(page))
+ return PTR_ERR(page);
+
+ length = kstrtouint(page, 0, &selinux_maxnsdepth);
+ if (length)
+ goto out;
+
+ length = count;
+out:
+ kfree(page);
+ return length;
+}
+
+static const struct file_operations sel_maxnsdepth_ops = {
+ .read = sel_read_maxnsdepth,
+ .write = sel_write_maxnsdepth,
+ .llseek = generic_file_llseek,
+};
+
+
static ssize_t sel_read_policyvers(struct file *filp, char __user *buf,
size_t count, loff_t *ppos)
{
@@ -2119,6 +2246,8 @@ static int sel_fill_super(struct super_block *sb, struct fs_context *fc)
[SEL_VALIDATE_TRANS] = {"validatetrans", &sel_transition_ops,
S_IWUGO},
[SEL_UNSHARE] = {"unshare", &sel_unshare_ops, 0200},
+ [SEL_MAXNS] = {"maxns", &sel_maxns_ops, 0600},
+ [SEL_MAXNSDEPTH] = {"maxnsdepth", &sel_maxnsdepth_ops, 0600},
/* last one */ {"", NULL, 0}
};
--
2.50.1
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [PATCH v7 12/42] selinux: exempt creation of init SELinux namespace from limits
2025-08-14 13:25 [PATCH v7 00/42] SELinux namespace support Stephen Smalley
` (10 preceding siblings ...)
2025-08-14 13:26 ` [PATCH v7 11/42] selinux: add limits for SELinux namespaces Stephen Smalley
@ 2025-08-14 13:26 ` Stephen Smalley
2025-08-14 13:26 ` [PATCH v7 13/42] selinux: refactor selinux_state_create() Stephen Smalley
` (29 subsequent siblings)
41 siblings, 0 replies; 43+ messages in thread
From: Stephen Smalley @ 2025-08-14 13:26 UTC (permalink / raw)
To: selinux; +Cc: paul, omosnace, netdev, horms, Stephen Smalley
Exempt the creation of the init SELinux namespace from the
maxns limit. It was already exempted from the maxnsdepth
limit by virtue of only applying that check when there
is a parent namespace. Otherwise, if one were to set
CONFIG_SECURITY_SELINUX_MAXNS to 0, the creation of the
init SELinux namespace would fail.
Signed-off-by: Stephen Smalley <stephen.smalley.work@gmail.com>
---
security/selinux/hooks.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 739f58b134ed..bb053445a086 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -7813,7 +7813,7 @@ int selinux_state_create(struct selinux_state *parent,
struct selinux_state *newstate;
int rc;
- if (atomic_read(&selinux_nsnum) >= selinux_maxns)
+ if (parent && atomic_read(&selinux_nsnum) >= selinux_maxns)
return -ENOSPC;
if (parent && parent->depth >= selinux_maxnsdepth)
--
2.50.1
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [PATCH v7 13/42] selinux: refactor selinux_state_create()
2025-08-14 13:25 [PATCH v7 00/42] SELinux namespace support Stephen Smalley
` (11 preceding siblings ...)
2025-08-14 13:26 ` [PATCH v7 12/42] selinux: exempt creation of init SELinux namespace from limits Stephen Smalley
@ 2025-08-14 13:26 ` Stephen Smalley
2025-08-14 13:26 ` [PATCH v7 14/42] selinux: allow userspace to detect non-init SELinux namespace Stephen Smalley
` (28 subsequent siblings)
41 siblings, 0 replies; 43+ messages in thread
From: Stephen Smalley @ 2025-08-14 13:26 UTC (permalink / raw)
To: selinux; +Cc: paul, omosnace, netdev, horms, Stephen Smalley
Refactor selinux_state_create() to be more like create_user_ns()
after which it was originally modeled. In particular, pass in
a single cred argument and update the cred SELinux blob with
the new state. This makes the reference counting situation
clearer with regard to the old state / parent reference and
simplifies the callers.
Signed-off-by: Stephen Smalley <stephen.smalley.work@gmail.com>
---
security/selinux/hooks.c | 79 ++++++++++++++++++++---------
security/selinux/include/security.h | 3 +-
security/selinux/selinuxfs.c | 10 +---
3 files changed, 57 insertions(+), 35 deletions(-)
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index bb053445a086..145432020575 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -203,22 +203,6 @@ static int selinux_lsm_notifier_avc_callback(u32 event)
return 0;
}
-struct selinux_state *init_selinux_state;
-
-/*
- * initialise the security for the init task
- */
-static void cred_init_security(void)
-{
- struct task_security_struct *tsec;
-
- /* NOTE: the lsm framework zeros out the buffer on allocation */
-
- 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);
-}
-
/*
* get the security ID of a set of credentials
*/
@@ -7807,9 +7791,10 @@ unsigned int selinux_maxnsdepth = CONFIG_SECURITY_SELINUX_MAXNSDEPTH;
static atomic_t selinux_nsnum = ATOMIC_INIT(0);
-int selinux_state_create(struct selinux_state *parent,
- struct selinux_state **state)
+int selinux_state_create(const struct cred *cred)
{
+ struct task_security_struct *tsec = selinux_cred(cred);
+ struct selinux_state *parent = tsec->state;
struct selinux_state *newstate;
int rc;
@@ -7834,13 +7819,40 @@ int selinux_state_create(struct selinux_state *parent,
goto err;
if (parent) {
- newstate->parent = get_selinux_state(parent);
+ /*
+ * The reference to the new state replaces the reference
+ * to the old state (parent) in the cred security blob;
+ * hence, we do not need to use get_selinux_state() below
+ * to increment the parent reference count.
+ */
+ newstate->parent = parent;
newstate->depth = parent->depth + 1;
}
atomic_inc(&selinux_nsnum);
- *state = newstate;
+ /*
+ * Set the new namespace.
+ * The reference count was initialized to 1 and
+ * this is that reference.
+ */
+ tsec->state = newstate;
+
+ /* Reset the SIDs for the new namespace. */
+ if (parent)
+ tsec->osid = tsec->sid = tsec->avdcache.sid = SECINITSID_INIT;
+ tsec->exec_sid = tsec->create_sid = tsec->keycreate_sid =
+ tsec->sockcreate_sid = SECSID_NULL;
+
+ /*
+ * Save the credential in the parent namespace
+ * for later use in checks in that namespace.
+ */
+ if (parent) {
+ put_cred(tsec->parent_cred);
+ tsec->parent_cred = get_current_cred();
+ }
+
return 0;
err:
kfree(newstate);
@@ -7869,16 +7881,35 @@ void __put_selinux_state(struct selinux_state *state)
schedule_work(&state->work);
}
+struct selinux_state *init_selinux_state;
+
static __init int selinux_init(void)
{
+ const struct cred *cred = unrcu_pointer(current->real_cred);
+ struct task_security_struct *tsec = selinux_cred(cred);
+
pr_info("SELinux: Initializing.\n");
- if (selinux_state_create(NULL, &init_selinux_state))
+ /*
+ * Initialize the first cred with the kernel SID and
+ * NULL state since selinux_state_create() expects
+ * these two fields to be set. The rest is handled by
+ * selinux_state_create(), which will update the state
+ * field to refer to the new state and set the parent
+ * pointer to the old state value (NULL).
+ */
+ tsec->osid = tsec->sid = tsec->avdcache.sid = SECINITSID_KERNEL;
+ tsec->state = NULL;
+ if (selinux_state_create(cred))
panic("SELinux: Could not create initial namespace\n");
- enforcing_set(init_selinux_state, selinux_enforcing_boot);
- /* Set the security state for the initial task. */
- cred_init_security();
+ /*
+ * Save a reference to the initial SELinux namespace
+ * for use in various other functions.
+ */
+ init_selinux_state = get_selinux_state(tsec->state);
+
+ enforcing_set(init_selinux_state, selinux_enforcing_boot);
default_noexec = !(VM_DATA_DEFAULT_FLAGS & VM_EXEC);
if (!default_noexec)
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
index d8312a39a265..04325259c44f 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -117,8 +117,7 @@ struct selinux_state {
extern struct selinux_state *init_selinux_state;
extern unsigned int selinux_maxns, selinux_maxnsdepth;
-int selinux_state_create(struct selinux_state *parent,
- struct selinux_state **state);
+int selinux_state_create(const struct cred *cred);
void __put_selinux_state(struct selinux_state *state);
void selinux_policy_free(struct selinux_policy *policy);
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index 06e2aeb478cd..3c2e828e0967 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -325,8 +325,6 @@ static ssize_t sel_write_unshare(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
- struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
- struct selinux_state *state = fsi->state;
char *page;
ssize_t length;
bool set;
@@ -355,22 +353,16 @@ static ssize_t sel_write_unshare(struct file *file, const char __user *buf,
if (set) {
struct cred *cred = prepare_creds();
- struct task_security_struct *tsec;
if (!cred) {
length = -ENOMEM;
goto out;
}
- tsec = selinux_cred(cred);
- if (selinux_state_create(state, &tsec->state)) {
+ if (selinux_state_create(cred)) {
abort_creds(cred);
length = -ENOMEM;
goto out;
}
- tsec->osid = tsec->sid = SECINITSID_INIT;
- tsec->exec_sid = tsec->create_sid = tsec->keycreate_sid =
- tsec->sockcreate_sid = SECSID_NULL;
- tsec->parent_cred = get_current_cred();
commit_creds(cred);
}
--
2.50.1
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [PATCH v7 14/42] selinux: allow userspace to detect non-init SELinux namespace
2025-08-14 13:25 [PATCH v7 00/42] SELinux namespace support Stephen Smalley
` (12 preceding siblings ...)
2025-08-14 13:26 ` [PATCH v7 13/42] selinux: refactor selinux_state_create() Stephen Smalley
@ 2025-08-14 13:26 ` Stephen Smalley
2025-08-14 13:26 ` [PATCH v7 15/42] selinuxfs: restrict write operations to the same selinux namespace Stephen Smalley
` (27 subsequent siblings)
41 siblings, 0 replies; 43+ messages in thread
From: Stephen Smalley @ 2025-08-14 13:26 UTC (permalink / raw)
To: selinux; +Cc: paul, omosnace, netdev, horms, Stephen Smalley
Enable reading of /sys/fs/selinux/unshare as a way to detect
whether a process is in a non-init SELinux namespace. This is
to allow the selinux-testsuite to adapt based on whether it is
run within a child SELinux namespace. Whether or not we want
to retain this as a userspace API is an open question.
Signed-off-by: Stephen Smalley <stephen.smalley.work@gmail.com>
---
security/selinux/selinuxfs.c | 16 +++++++++++++++-
1 file changed, 15 insertions(+), 1 deletion(-)
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index 3c2e828e0967..c8bc0c34a248 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -321,6 +321,19 @@ static const struct file_operations sel_disable_ops = {
.llseek = generic_file_llseek,
};
+static ssize_t sel_read_unshare(struct file *filp, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ const struct task_security_struct *tsec = selinux_cred(current_cred());
+ char tmpbuf[1];
+
+ if (tsec->state == init_selinux_state)
+ tmpbuf[0] = '0';
+ else
+ tmpbuf[0] = '1';
+ return simple_read_from_buffer(buf, count, ppos, tmpbuf, 1);
+}
+
static ssize_t sel_write_unshare(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
@@ -373,6 +386,7 @@ static ssize_t sel_write_unshare(struct file *file, const char __user *buf,
}
static const struct file_operations sel_unshare_ops = {
+ .read = sel_read_unshare,
.write = sel_write_unshare,
.llseek = generic_file_llseek,
};
@@ -2237,7 +2251,7 @@ static int sel_fill_super(struct super_block *sb, struct fs_context *fc)
[SEL_POLICY] = {"policy", &sel_policy_ops, S_IRUGO},
[SEL_VALIDATE_TRANS] = {"validatetrans", &sel_transition_ops,
S_IWUGO},
- [SEL_UNSHARE] = {"unshare", &sel_unshare_ops, 0200},
+ [SEL_UNSHARE] = {"unshare", &sel_unshare_ops, 0600},
[SEL_MAXNS] = {"maxns", &sel_maxns_ops, 0600},
[SEL_MAXNSDEPTH] = {"maxnsdepth", &sel_maxnsdepth_ops, 0600},
/* last one */ {"", NULL, 0}
--
2.50.1
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [PATCH v7 15/42] selinuxfs: restrict write operations to the same selinux namespace
2025-08-14 13:25 [PATCH v7 00/42] SELinux namespace support Stephen Smalley
` (13 preceding siblings ...)
2025-08-14 13:26 ` [PATCH v7 14/42] selinux: allow userspace to detect non-init SELinux namespace Stephen Smalley
@ 2025-08-14 13:26 ` Stephen Smalley
2025-08-14 13:26 ` [PATCH v7 16/42] selinux: introduce a global SID table Stephen Smalley
` (26 subsequent siblings)
41 siblings, 0 replies; 43+ messages in thread
From: Stephen Smalley @ 2025-08-14 13:26 UTC (permalink / raw)
To: selinux; +Cc: paul, omosnace, netdev, horms, Stephen Smalley
This ensures that once a process unshares its selinux namespace,
it can no longer act on the parent namespace's selinuxfs instance,
irrespective of policy. This is a safety measure so that even if
an otherwise unconfined process unshares its selinux namespace, it
won't be able to subsequently affect the enforcing mode or policy of the
parent. This also helps avoid common mistakes like failing to create
a mount namespace and mount a new selinuxfs instance in order to act
on one's own selinux namespace after unsharing.
Signed-off-by: Stephen Smalley <stephen.smalley.work@gmail.com>
---
security/selinux/selinuxfs.c | 30 ++++++++++++++++++++++++++++++
1 file changed, 30 insertions(+)
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index c8bc0c34a248..d6c8d8245c3c 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -150,6 +150,9 @@ static ssize_t sel_write_enforce(struct file *file, const char __user *buf,
int scan_value;
bool old_value, new_value;
+ if (state != current_selinux_state)
+ return -EPERM;
+
if (count >= PAGE_SIZE)
return -ENOMEM;
@@ -338,11 +341,16 @@ static ssize_t sel_write_unshare(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
+ struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
+ struct selinux_state *state = fsi->state;
char *page;
ssize_t length;
bool set;
int rc;
+ if (state != current_selinux_state)
+ return -EPERM;
+
if (count >= PAGE_SIZE)
return -ENOMEM;
@@ -795,6 +803,9 @@ static ssize_t sel_write_load(struct file *file, const char __user *buf,
if (!count)
return -EINVAL;
+ if (fsi->state != current_selinux_state)
+ return -EPERM;
+
mutex_lock(&fsi->state->policy_mutex);
length = avc_has_perm(current_selinux_state,
current_sid(), SECINITSID_SECURITY,
@@ -899,6 +910,9 @@ static ssize_t sel_write_checkreqprot(struct file *file, const char __user *buf,
ssize_t length;
unsigned int new_value;
+ if (fsi->state != current_selinux_state)
+ return -EPERM;
+
length = avc_has_perm(current_selinux_state,
current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__SETCHECKREQPROT,
@@ -955,6 +969,9 @@ static ssize_t sel_write_validatetrans(struct file *file,
u16 tclass;
int rc;
+ if (state != current_selinux_state)
+ return -EPERM;
+
rc = avc_has_perm(current_selinux_state,
current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__VALIDATE_TRANS, NULL);
@@ -1042,10 +1059,14 @@ static ssize_t (*const write_op[])(struct file *, char *, size_t) = {
static ssize_t selinux_transaction_write(struct file *file, const char __user *buf, size_t size, loff_t *pos)
{
+ struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
ino_t ino = file_inode(file)->i_ino;
char *data;
ssize_t rv;
+ if (fsi->state != current_selinux_state)
+ return -EPERM;
+
if (ino >= ARRAY_SIZE(write_op) || !write_op[ino])
return -EINVAL;
@@ -1486,6 +1507,9 @@ static ssize_t sel_write_bool(struct file *filep, const char __user *buf,
unsigned index = file_inode(filep)->i_ino & SEL_INO_MASK;
const char *name = filep->f_path.dentry->d_name.name;
+ if (fsi->state != current_selinux_state)
+ return -EPERM;
+
if (count >= PAGE_SIZE)
return -ENOMEM;
@@ -1542,6 +1566,9 @@ static ssize_t sel_commit_bools_write(struct file *filep,
ssize_t length;
int new_value;
+ if (fsi->state != current_selinux_state)
+ return -EPERM;
+
if (count >= PAGE_SIZE)
return -ENOMEM;
@@ -1673,6 +1700,9 @@ static ssize_t sel_write_avc_cache_threshold(struct file *file,
ssize_t ret;
unsigned int new_value;
+ if (state != current_selinux_state)
+ return -EPERM;
+
ret = avc_has_perm(current_selinux_state,
current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__SETSECPARAM,
--
2.50.1
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [PATCH v7 16/42] selinux: introduce a global SID table
2025-08-14 13:25 [PATCH v7 00/42] SELinux namespace support Stephen Smalley
` (14 preceding siblings ...)
2025-08-14 13:26 ` [PATCH v7 15/42] selinuxfs: restrict write operations to the same selinux namespace Stephen Smalley
@ 2025-08-14 13:26 ` Stephen Smalley
2025-08-14 13:26 ` [PATCH v7 17/42] selinux: wrap security server interfaces to use the " Stephen Smalley
` (25 subsequent siblings)
41 siblings, 0 replies; 43+ messages in thread
From: Stephen Smalley @ 2025-08-14 13:26 UTC (permalink / raw)
To: selinux; +Cc: paul, omosnace, netdev, horms, Stephen Smalley
Introduce a global SID table to provide stable global SID values
independent of any particular policy or namespace. This table will only
map between global SIDs and security context strings since it must
remain policy-independent. Internally each of these global SIDs can then
be mapped on a per-policy/namespace basis to per-namespace SIDs and
context structures. The LSM interfaces and blob structures will only use
the global SID values and thus remain namespace-neutral.
Note that this required moving the SID table header and its dependencies
out of the security server subdirectory. While we could re-factor it to
to reduce the scope of this change, doing so does not seem worthwhile.
The security server abstraction is largely obsoleted by LSM, no one has
contributed any other security server implementation for SELinux, and
over time there has been an increasing blurring of the boundary between the
security server and the rest of the SELinux module. Eventually, I
anticipate fully moving the security server files out of the ss
subdirectory but that is left for a future change.
Signed-off-by: Stephen Smalley <stephen.smalley.work@gmail.com>
---
security/selinux/Makefile | 2 +-
security/selinux/global_sidtab.c | 109 ++++++++++++++++++
security/selinux/hooks.c | 4 +
security/selinux/{ss => include}/avtab.h | 0
security/selinux/{ss => include}/constraint.h | 0
security/selinux/{ss => include}/context.h | 0
security/selinux/{ss => include}/ebitmap.h | 0
security/selinux/include/global_sidtab.h | 19 +++
security/selinux/{ss => include}/hashtab.h | 0
security/selinux/{ss => include}/mls.h | 0
security/selinux/{ss => include}/mls_types.h | 0
security/selinux/{ss => include}/policydb.h | 0
security/selinux/{ss => include}/sidtab.h | 0
security/selinux/{ss => include}/symtab.h | 0
14 files changed, 133 insertions(+), 1 deletion(-)
create mode 100644 security/selinux/global_sidtab.c
rename security/selinux/{ss => include}/avtab.h (100%)
rename security/selinux/{ss => include}/constraint.h (100%)
rename security/selinux/{ss => include}/context.h (100%)
rename security/selinux/{ss => include}/ebitmap.h (100%)
create mode 100644 security/selinux/include/global_sidtab.h
rename security/selinux/{ss => include}/hashtab.h (100%)
rename security/selinux/{ss => include}/mls.h (100%)
rename security/selinux/{ss => include}/mls_types.h (100%)
rename security/selinux/{ss => include}/policydb.h (100%)
rename security/selinux/{ss => include}/sidtab.h (100%)
rename security/selinux/{ss => include}/symtab.h (100%)
diff --git a/security/selinux/Makefile b/security/selinux/Makefile
index 66e56e9011df..fe5f6f4bb0ea 100644
--- a/security/selinux/Makefile
+++ b/security/selinux/Makefile
@@ -15,7 +15,7 @@ ccflags-y := -I$(srctree)/security/selinux -I$(srctree)/security/selinux/include
ccflags-$(CONFIG_SECURITY_SELINUX_DEBUG) += -DDEBUG
selinux-y := avc.o hooks.o selinuxfs.o netlink.o nlmsgtab.o netif.o \
- netnode.o netport.o status.o \
+ netnode.o netport.o status.o global_sidtab.o \
ss/ebitmap.o ss/hashtab.o ss/symtab.o ss/sidtab.o ss/avtab.o \
ss/policydb.o ss/services.o ss/conditional.o ss/mls.o ss/context.o
diff --git a/security/selinux/global_sidtab.c b/security/selinux/global_sidtab.c
new file mode 100644
index 000000000000..57866a2d4cc2
--- /dev/null
+++ b/security/selinux/global_sidtab.c
@@ -0,0 +1,109 @@
+// SPDX-License-Identifier: GPL-2.0
+#include "global_sidtab.h"
+#include "sidtab.h"
+
+static struct sidtab global_sidtab;
+
+int global_sidtab_init(void)
+{
+ struct context ctx;
+ int rc, sid;
+
+ rc = sidtab_init(&global_sidtab);
+ if (rc)
+ return rc;
+
+ memset(&ctx, 0, sizeof(ctx));
+ for (sid = 1; sid <= SECINITSID_NUM; sid++) {
+ const char *str = security_get_initial_sid_context(sid);
+
+ if (!str)
+ continue;
+ /*
+ * Before the policy is loaded, translate
+ * SECINITSID_INIT to "kernel", because systemd and
+ * libselinux < 2.6 take a getcon_raw() result that is
+ * both non-null and not "kernel" to mean that a policy
+ * is already loaded.
+ */
+ if (sid == SECINITSID_INIT)
+ str = "kernel";
+ ctx.str = (char *)str;
+ ctx.len = strlen(str)+1;
+ rc = sidtab_set_initial(&global_sidtab, sid, &ctx);
+ if (rc)
+ return rc;
+ }
+
+ return 0;
+}
+
+int global_sid_to_context(u32 sid, char **scontext, u32 *scontext_len)
+{
+ struct context *ctx;
+
+ rcu_read_lock();
+ ctx = sidtab_search_force(&global_sidtab, sid);
+ if (!ctx) {
+ rcu_read_unlock();
+ *scontext = NULL;
+ *scontext_len = 0;
+ return -EINVAL;
+ }
+ *scontext_len = ctx->len;
+ /*
+ * Could eliminate allocation + copy if callers do not free
+ * since the global sidtab entries are never freed.
+ * This however would not match the current expectation
+ * of callers of security_sid_to_context().
+ * TODO: Update all callers and get rid of this copy.
+ */
+ *scontext = kstrdup(ctx->str, GFP_ATOMIC);
+ if (!(*scontext)) {
+ rcu_read_unlock();
+ *scontext_len = 0;
+ return -ENOMEM;
+ }
+
+ rcu_read_unlock();
+ return 0;
+}
+
+int global_context_to_sid(const char *scontext, u32 scontext_len, u32 *out_sid,
+ gfp_t gfp)
+{
+ char *str;
+ struct context ctx;
+ int rc;
+
+ if (!scontext_len)
+ return -EINVAL;
+
+ /*
+ * Could eliminate allocation + copy if callers were required to
+ * pass in a NUL-terminated string or if the context_cmp/cpy()
+ * functions did not assume that ctx.str is NUL-terminated.
+ * This however would not match the current expectation of
+ * callers of security_context_to_sid, particularly contexts
+ * fetched from xattr values or provided by the xattr APIs.
+ * TODO: Change context_cmp/cpy() or update all callers and
+ * get rid of this copy.
+ */
+ str = kmemdup_nul(scontext, scontext_len, gfp);
+ if (!str)
+ return -ENOMEM;
+
+ ctx.str = str;
+ ctx.len = strlen(str)+1;
+
+retry:
+ rcu_read_lock();
+ rc = sidtab_context_to_sid(&global_sidtab, &ctx, out_sid);
+ if (rc == -ESTALE) {
+ rcu_read_unlock();
+ goto retry;
+ }
+ rcu_read_unlock();
+ kfree(str);
+ return rc;
+}
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 145432020575..e84f3a1e3e12 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -104,6 +104,7 @@
#include "netlabel.h"
#include "audit.h"
#include "avc_ss.h"
+#include "global_sidtab.h"
#define SELINUX_INODE_INIT_XATTRS 1
@@ -7911,6 +7912,9 @@ static __init int selinux_init(void)
enforcing_set(init_selinux_state, selinux_enforcing_boot);
+ if (global_sidtab_init())
+ panic("SELinux: Could not create global SID table\n");
+
default_noexec = !(VM_DATA_DEFAULT_FLAGS & VM_EXEC);
if (!default_noexec)
pr_notice("SELinux: virtual memory is executable by default\n");
diff --git a/security/selinux/ss/avtab.h b/security/selinux/include/avtab.h
similarity index 100%
rename from security/selinux/ss/avtab.h
rename to security/selinux/include/avtab.h
diff --git a/security/selinux/ss/constraint.h b/security/selinux/include/constraint.h
similarity index 100%
rename from security/selinux/ss/constraint.h
rename to security/selinux/include/constraint.h
diff --git a/security/selinux/ss/context.h b/security/selinux/include/context.h
similarity index 100%
rename from security/selinux/ss/context.h
rename to security/selinux/include/context.h
diff --git a/security/selinux/ss/ebitmap.h b/security/selinux/include/ebitmap.h
similarity index 100%
rename from security/selinux/ss/ebitmap.h
rename to security/selinux/include/ebitmap.h
diff --git a/security/selinux/include/global_sidtab.h b/security/selinux/include/global_sidtab.h
new file mode 100644
index 000000000000..f62a9165d26a
--- /dev/null
+++ b/security/selinux/include/global_sidtab.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * A global security identifier table (sidtab) is a lookup table
+ * of security context strings indexed by SID value.
+ */
+
+#ifndef _GLOBAL_SIDTAB_H_
+#define _GLOBAL_SIDTAB_H_
+
+#include <linux/types.h>
+
+extern int global_sidtab_init(void);
+
+extern int global_sid_to_context(u32 sid, char **scontext, u32 *scontext_len);
+
+extern int global_context_to_sid(const char *scontext, u32 scontext_len,
+ u32 *out_sid, gfp_t gfp);
+
+#endif /* _GLOBAL_SIDTAB_H_ */
diff --git a/security/selinux/ss/hashtab.h b/security/selinux/include/hashtab.h
similarity index 100%
rename from security/selinux/ss/hashtab.h
rename to security/selinux/include/hashtab.h
diff --git a/security/selinux/ss/mls.h b/security/selinux/include/mls.h
similarity index 100%
rename from security/selinux/ss/mls.h
rename to security/selinux/include/mls.h
diff --git a/security/selinux/ss/mls_types.h b/security/selinux/include/mls_types.h
similarity index 100%
rename from security/selinux/ss/mls_types.h
rename to security/selinux/include/mls_types.h
diff --git a/security/selinux/ss/policydb.h b/security/selinux/include/policydb.h
similarity index 100%
rename from security/selinux/ss/policydb.h
rename to security/selinux/include/policydb.h
diff --git a/security/selinux/ss/sidtab.h b/security/selinux/include/sidtab.h
similarity index 100%
rename from security/selinux/ss/sidtab.h
rename to security/selinux/include/sidtab.h
diff --git a/security/selinux/ss/symtab.h b/security/selinux/include/symtab.h
similarity index 100%
rename from security/selinux/ss/symtab.h
rename to security/selinux/include/symtab.h
--
2.50.1
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [PATCH v7 17/42] selinux: wrap security server interfaces to use the global SID table
2025-08-14 13:25 [PATCH v7 00/42] SELinux namespace support Stephen Smalley
` (15 preceding siblings ...)
2025-08-14 13:26 ` [PATCH v7 16/42] selinux: introduce a global SID table Stephen Smalley
@ 2025-08-14 13:26 ` Stephen Smalley
2025-08-14 13:26 ` [PATCH v7 18/42] selinux: introduce a Kconfig option for SELinux namespaces Stephen Smalley
` (24 subsequent siblings)
41 siblings, 0 replies; 43+ messages in thread
From: Stephen Smalley @ 2025-08-14 13:26 UTC (permalink / raw)
To: selinux; +Cc: paul, omosnace, netdev, horms, Stephen Smalley
Wrap the security server interfaces to use the global SID table,
transparently mapping between global SIDs and per-policy SIDs.
Rename the existing security server functions with a selinux_ss
prefix.
The selinuxfs implementation directly uses the underlying
selinux_ss interfaces since its functions are always acting
relative to a particular SELinux namespace. In contrast,
the hook function implementations always use the new
wrapper functions to support the use of global SIDs.
Since the global SID table always stores security context strings
unmapped, this change removes the informational printk about
unmapped contexts to avoid filling the logs with noise. If/when
we split the global SID table and per-policy SID table implementations,
this could be restored to the per-policy SID tables if desired.
The implementation leaves a lot to be desired in efficiency,
but optimizing the global SID mapping, splitting the global SID
and per-policy SID table data structures to avoid wasting unused
space in the sidtab entries of each, and/or eliminating the use
of per-policy SIDs entirely is left to future changes. It would be
good if we could further optimize for the case where there is only
a single SELinux namespace and avoid imposing extra overhead on it.
The security server interfaces were meant to be independent of
the core kernel data structures and security blobs. Originally
security_fs_use() passed the fstype, behavior, and sid parameters
explicitly, but this was later simplified to just pass the
superblock structure and set fields in the superblock security
blob directly, breaking this layering. With the introduction of
the global SID table, we need to map the SID returned by the
security server to a global SID, which is less straightforward
in the absence of proper layering. Revert the security_fs_use()
interface and implementation to its original form and update the
callers. This is not a performance-critical path regardless and
any small benefit from passing the single superblock pointer
instead of the three separate parameters is not worth the
maintainability cost.
Signed-off-by: Stephen Smalley <stephen.smalley.work@gmail.com>
---
security/selinux/global_sidtab.c | 651 ++++++++++++++++++++++-
security/selinux/hooks.c | 9 +-
security/selinux/include/global_sidtab.h | 7 -
security/selinux/include/security.h | 25 +-
security/selinux/include/selinux_ss.h | 119 +++++
security/selinux/include/sidtab.h | 5 +
security/selinux/selinuxfs.c | 51 +-
security/selinux/ss/services.c | 174 +++---
security/selinux/ss/sidtab.c | 14 +-
9 files changed, 902 insertions(+), 153 deletions(-)
create mode 100644 security/selinux/include/selinux_ss.h
diff --git a/security/selinux/global_sidtab.c b/security/selinux/global_sidtab.c
index 57866a2d4cc2..48934b429c8c 100644
--- a/security/selinux/global_sidtab.c
+++ b/security/selinux/global_sidtab.c
@@ -1,6 +1,8 @@
// SPDX-License-Identifier: GPL-2.0
#include "global_sidtab.h"
#include "sidtab.h"
+#include "selinux_ss.h"
+#include "audit.h"
static struct sidtab global_sidtab;
@@ -38,7 +40,7 @@ int global_sidtab_init(void)
return 0;
}
-int global_sid_to_context(u32 sid, char **scontext, u32 *scontext_len)
+static int global_sid_to_context(u32 sid, char **scontext, u32 *scontext_len)
{
struct context *ctx;
@@ -69,8 +71,9 @@ int global_sid_to_context(u32 sid, char **scontext, u32 *scontext_len)
return 0;
}
-int global_context_to_sid(const char *scontext, u32 scontext_len, u32 *out_sid,
- gfp_t gfp)
+static int global_context_to_sid(struct selinux_state *state, u32 ss_sid,
+ const char *scontext, u32 scontext_len,
+ u32 *out_sid, gfp_t gfp)
{
char *str;
struct context ctx;
@@ -98,7 +101,8 @@ int global_context_to_sid(const char *scontext, u32 scontext_len, u32 *out_sid,
retry:
rcu_read_lock();
- rc = sidtab_context_to_sid(&global_sidtab, &ctx, out_sid);
+ rc = sidtab_context_ss_to_sid(&global_sidtab, &ctx, state, ss_sid,
+ out_sid);
if (rc == -ESTALE) {
rcu_read_unlock();
goto retry;
@@ -107,3 +111,642 @@ int global_context_to_sid(const char *scontext, u32 scontext_len, u32 *out_sid,
kfree(str);
return rc;
}
+
+static int map_global_sid_to_ss(struct selinux_state *state, u32 sid,
+ u32 *ss_sid, gfp_t gfp)
+{
+ struct sidtab_entry *entry;
+ int rc;
+ char *scontext;
+ u32 scontext_len;
+
+ if (sid <= SECINITSID_NUM) {
+ *ss_sid = sid;
+ return 0;
+ }
+
+ rcu_read_lock();
+ entry = sidtab_search_entry_force(&global_sidtab, sid);
+ if (!entry) {
+ rcu_read_unlock();
+ return -EINVAL;
+ }
+ if (entry->state == state && entry->ss_sid) {
+ *ss_sid = entry->ss_sid;
+ rcu_read_unlock();
+ return 0;
+ }
+ rcu_read_unlock();
+
+ rc = global_sid_to_context(sid, &scontext, &scontext_len);
+ if (rc)
+ return rc;
+
+ rc = selinux_ss_context_to_sid_force(state, scontext,
+ scontext_len, ss_sid, gfp);
+ kfree(scontext);
+ return rc;
+}
+
+static int map_ss_sid_to_global(struct selinux_state *state, u32 ss_sid,
+ u32 *out_sid, gfp_t gfp)
+{
+ char *scontext;
+ u32 scontext_len;
+ int rc;
+
+ if (ss_sid <= SECINITSID_NUM) {
+ *out_sid = ss_sid;
+ return 0;
+ }
+
+ rc = selinux_ss_sid_to_context_force(state, ss_sid, &scontext,
+ &scontext_len);
+ if (rc)
+ return rc;
+
+ rc = global_context_to_sid(state, ss_sid, scontext, scontext_len,
+ out_sid, GFP_ATOMIC);
+ kfree(scontext);
+ return rc;
+}
+
+int security_sid_to_context(struct selinux_state *state, u32 sid,
+ char **scontext, u32 *scontext_len)
+{
+ // initial SID contexts have to be obtained from the policy, if initialized
+ if (sid <= SECINITSID_NUM && selinux_initialized(state))
+ return selinux_ss_sid_to_context(state, sid, scontext, scontext_len);
+
+ return global_sid_to_context(sid, scontext, scontext_len);
+}
+
+int security_sid_to_context_valid(struct selinux_state *state, u32 sid,
+ char **scontext, u32 *scontext_len)
+{
+ int rc;
+ u32 ss_sid;
+
+ // Valid SID contexts have to be obtained from the policy, if initialized
+ if (selinux_initialized(state)) {
+ rc = map_global_sid_to_ss(state, sid, &ss_sid, GFP_ATOMIC);
+ if (rc)
+ return rc;
+ return selinux_ss_sid_to_context(state, ss_sid, scontext,
+ scontext_len);
+ }
+
+ return global_sid_to_context(sid, scontext, scontext_len);
+}
+
+int security_sid_to_context_force(struct selinux_state *state, u32 sid,
+ char **scontext, u32 *scontext_len)
+{
+ // initial SID contexts have to be obtained from the policy, if initialized
+ if (sid <= SECINITSID_NUM && selinux_initialized(state))
+ return selinux_ss_sid_to_context_force(state, sid, scontext, scontext_len);
+
+ return global_sid_to_context(sid, scontext, scontext_len);
+}
+
+int security_sid_to_context_inval(struct selinux_state *state, u32 sid,
+ char **scontext, u32 *scontext_len)
+{
+ int rc;
+ u32 ss_sid;
+
+ // TODO Cache invalid bit in global SID table so we do not need
+ // to lookup in the per-policy one each time.
+ if (selinux_initialized(state)) {
+ rc = map_global_sid_to_ss(state, sid, &ss_sid, GFP_ATOMIC);
+ if (rc)
+ return rc;
+ return selinux_ss_sid_to_context_inval(state, ss_sid, scontext,
+ scontext_len);
+ }
+ return global_sid_to_context(sid, scontext, scontext_len);
+}
+
+int security_context_to_sid(struct selinux_state *state, const char *scontext,
+ u32 scontext_len, u32 *out_sid, gfp_t gfp)
+{
+ int rc;
+ u32 sid, ss_sid = 0;
+ char *ctx = NULL;
+
+ /*
+ * If initialized, validate and canonicalize the context against
+ * the policy.
+ */
+ if (selinux_initialized(state)) {
+ rc = selinux_ss_context_to_sid(state, scontext, scontext_len,
+ &ss_sid, gfp);
+ if (rc)
+ return rc;
+
+ rc = selinux_ss_sid_to_context(state, ss_sid, &ctx,
+ &scontext_len);
+ if (rc)
+ return rc;
+ scontext = ctx;
+ }
+
+ // allocate or lookup a SID in the global SID table
+ rc = global_context_to_sid(state, ss_sid, scontext, scontext_len,
+ &sid, gfp);
+ if (rc)
+ goto out;
+
+ *out_sid = sid;
+
+out:
+ kfree(ctx);
+ return rc;
+}
+
+int security_context_str_to_sid(struct selinux_state *state,
+ const char *scontext, u32 *out_sid, gfp_t gfp)
+{
+ size_t scontext_len = strlen(scontext) + 1;
+
+ return security_context_to_sid(state, scontext, scontext_len, out_sid,
+ gfp);
+}
+
+int security_context_to_sid_default(struct selinux_state *state,
+ const char *scontext, u32 scontext_len,
+ u32 *out_sid, u32 def_sid, gfp_t gfp)
+{
+ int rc;
+ u32 sid, ss_sid = 0;
+ char *ctx = NULL;
+
+ /*
+ * If initialized, validate and canonicalize the context against
+ * the policy.
+ */
+ if (selinux_initialized(state)) {
+ rc = selinux_ss_context_to_sid_default(state, scontext,
+ scontext_len, &ss_sid,
+ def_sid, gfp);
+ if (rc)
+ return rc;
+
+ rc = selinux_ss_sid_to_context(state, ss_sid, &ctx,
+ &scontext_len);
+ if (rc)
+ return rc;
+ scontext = ctx;
+ }
+
+ // allocate or lookup a SID in the global SID table
+ rc = global_context_to_sid(state, ss_sid, scontext, scontext_len,
+ &sid, gfp);
+ if (rc)
+ goto out;
+
+ *out_sid = sid;
+
+out:
+ kfree(ctx);
+ return rc;
+}
+
+int security_context_to_sid_force(struct selinux_state *state,
+ const char *scontext, u32 scontext_len,
+ u32 *out_sid)
+{
+ int rc;
+ u32 sid, ss_sid = 0;
+ char *ctx = NULL;
+
+ /*
+ * If initialized, validate and canonicalize the context against
+ * the policy.
+ */
+ if (selinux_initialized(state)) {
+ rc = selinux_ss_context_to_sid_force(state, scontext,
+ scontext_len, &ss_sid,
+ GFP_KERNEL);
+ if (rc)
+ return rc;
+
+ rc = selinux_ss_sid_to_context_force(state, ss_sid, &ctx,
+ &scontext_len);
+ if (rc)
+ return rc;
+ scontext = ctx;
+ }
+
+ // allocate or lookup a SID in the global SID table
+ rc = global_context_to_sid(state, ss_sid, scontext, scontext_len,
+ &sid, GFP_KERNEL);
+ if (rc)
+ goto out;
+
+ *out_sid = sid;
+
+out:
+ kfree(ctx);
+ return rc;
+}
+
+void security_compute_av(struct selinux_state *state, u32 ssid, u32 tsid,
+ u16 tclass, struct av_decision *avd,
+ struct extended_perms *xperms)
+{
+ u32 ss_ssid, ss_tsid;
+ int rc;
+
+ if (!selinux_initialized(state))
+ goto allow;
+
+ rc = map_global_sid_to_ss(state, ssid, &ss_ssid, GFP_ATOMIC);
+ if (rc)
+ goto deny;
+ rc = map_global_sid_to_ss(state, tsid, &ss_tsid, GFP_ATOMIC);
+ if (rc)
+ goto deny;
+ selinux_ss_compute_av(state, ss_ssid, ss_tsid, tclass, avd, xperms);
+ return;
+allow:
+ avd->allowed = ~0U;
+ goto out;
+deny:
+ avd->allowed = 0;
+out:
+ avd->auditallow = 0;
+ avd->auditdeny = ~0U;
+ avd->seqno = 0;
+ avd->flags = 0;
+ xperms->len = 0;
+}
+
+void security_compute_xperms_decision(struct selinux_state *state, u32 ssid,
+ u32 tsid, u16 tclass, u8 driver,
+ u8 base_perm,
+ struct extended_perms_decision *xpermd)
+{
+ u32 ss_ssid, ss_tsid;
+ int rc;
+
+ if (!selinux_initialized(state))
+ goto allow;
+
+ rc = map_global_sid_to_ss(state, ssid, &ss_ssid, GFP_ATOMIC);
+ if (rc)
+ goto deny;
+ rc = map_global_sid_to_ss(state, tsid, &ss_tsid, GFP_ATOMIC);
+ if (rc)
+ goto deny;
+ selinux_ss_compute_xperms_decision(state, ss_ssid, ss_tsid, tclass,
+ driver, base_perm, xpermd);
+ return;
+allow:
+ memset(xpermd->allowed->p, 0xff, sizeof(xpermd->allowed->p));
+ goto out;
+deny:
+ memset(xpermd->allowed->p, 0, sizeof(xpermd->allowed->p));
+out:
+ xpermd->driver = driver;
+ xpermd->used = 0;
+ memset(xpermd->auditallow->p, 0, sizeof(xpermd->auditallow->p));
+ memset(xpermd->dontaudit->p, 0, sizeof(xpermd->dontaudit->p));
+}
+
+int security_transition_sid(struct selinux_state *state, u32 ssid, u32 tsid,
+ u16 tclass, const struct qstr *qstr, u32 *out_sid)
+{
+ u32 ss_ssid, ss_tsid, ss_outsid;
+ int rc;
+
+ if (!selinux_initialized(state)) {
+ switch (tclass) {
+ case SECCLASS_PROCESS:
+ *out_sid = ssid;
+ break;
+ default:
+ *out_sid = tsid;
+ break;
+ }
+ return 0;
+ }
+
+ rc = map_global_sid_to_ss(state, ssid, &ss_ssid, GFP_ATOMIC);
+ if (rc)
+ return rc;
+ rc = map_global_sid_to_ss(state, tsid, &ss_tsid, GFP_ATOMIC);
+ if (rc)
+ return rc;
+ rc = selinux_ss_transition_sid(state, ss_ssid, ss_tsid, tclass, qstr,
+ &ss_outsid);
+ if (rc)
+ return rc;
+
+ return map_ss_sid_to_global(state, ss_outsid, out_sid, GFP_ATOMIC);
+}
+
+int security_port_sid(struct selinux_state *state, u8 protocol, u16 port,
+ u32 *out_sid)
+{
+ u32 ss_outsid;
+ int rc;
+
+ if (!selinux_initialized(state)) {
+ *out_sid = SECINITSID_PORT;
+ return 0;
+ }
+
+ rc = selinux_ss_port_sid(state, protocol, port, &ss_outsid);
+ if (rc)
+ return rc;
+
+ return map_ss_sid_to_global(state, ss_outsid, out_sid, GFP_ATOMIC);
+}
+
+int security_ib_pkey_sid(struct selinux_state *state, u64 subnet_prefix,
+ u16 pkey_num, u32 *out_sid)
+{
+ u32 ss_outsid;
+ int rc;
+
+ if (!selinux_initialized(state)) {
+ *out_sid = SECINITSID_UNLABELED;
+ return 0;
+ }
+
+ rc = selinux_ss_ib_pkey_sid(state, subnet_prefix, pkey_num, &ss_outsid);
+ if (rc)
+ return rc;
+
+ return map_ss_sid_to_global(state, ss_outsid, out_sid, GFP_ATOMIC);
+}
+
+int security_ib_endport_sid(struct selinux_state *state, const char *dev_name,
+ u8 port_num, u32 *out_sid)
+{
+ u32 ss_outsid;
+ int rc;
+
+ if (!selinux_initialized(state)) {
+ *out_sid = SECINITSID_UNLABELED;
+ return 0;
+ }
+
+ rc = selinux_ss_ib_endport_sid(state, dev_name, port_num, &ss_outsid);
+ if (rc)
+ return rc;
+
+ return map_ss_sid_to_global(state, ss_outsid, out_sid, GFP_ATOMIC);
+}
+
+int security_netif_sid(struct selinux_state *state, const char *name, u32 *out_sid)
+{
+ u32 ss_outsid;
+ int rc;
+
+ if (!selinux_initialized(state)) {
+ *out_sid = SECINITSID_NETIF;
+ return 0;
+ }
+
+ rc = selinux_ss_netif_sid(state, name, &ss_outsid);
+ if (rc)
+ return rc;
+
+ return map_ss_sid_to_global(state, ss_outsid, out_sid, GFP_ATOMIC);
+}
+
+int security_node_sid(struct selinux_state *state, u16 domain, const void *addr,
+ u32 addrlen, u32 *out_sid)
+{
+ u32 ss_outsid;
+ int rc;
+
+ if (!selinux_initialized(state)) {
+ *out_sid = SECINITSID_NODE;
+ return 0;
+ }
+
+ rc = selinux_ss_node_sid(state, domain, addr, addrlen, &ss_outsid);
+ if (rc)
+ return rc;
+
+ return map_ss_sid_to_global(state, ss_outsid, out_sid, GFP_ATOMIC);
+}
+
+int security_validate_transition(struct selinux_state *state, u32 oldsid,
+ u32 newsid, u32 tasksid, u16 tclass)
+{
+ u32 ss_oldsid, ss_newsid, ss_tasksid;
+ int rc;
+
+ if (!selinux_initialized(state))
+ return 0;
+
+ rc = map_global_sid_to_ss(state, oldsid, &ss_oldsid, GFP_ATOMIC);
+ if (rc)
+ return -EINVAL;
+ rc = map_global_sid_to_ss(state, newsid, &ss_newsid, GFP_ATOMIC);
+ if (rc)
+ return -EINVAL;
+ rc = map_global_sid_to_ss(state, tasksid, &ss_tasksid, GFP_ATOMIC);
+ if (rc)
+ return -EINVAL;
+ return selinux_ss_validate_transition(state, ss_oldsid, ss_newsid,
+ ss_tasksid, tclass);
+}
+
+int security_bounded_transition(struct selinux_state *state, u32 oldsid,
+ u32 newsid)
+{
+ u32 ss_oldsid, ss_newsid;
+ int rc;
+
+ if (!selinux_initialized(state))
+ return 0;
+
+ rc = map_global_sid_to_ss(state, oldsid, &ss_oldsid, GFP_ATOMIC);
+ if (rc)
+ return -EINVAL;
+ rc = map_global_sid_to_ss(state, newsid, &ss_newsid, GFP_ATOMIC);
+ if (rc)
+ return -EINVAL;
+ return selinux_ss_bounded_transition(state, ss_oldsid, ss_newsid);
+}
+
+int security_sid_mls_copy(struct selinux_state *state, u32 sid, u32 mls_sid,
+ u32 *out_sid)
+{
+ u32 ss_sid, ss_mlssid, ss_outsid;
+ int rc;
+
+ if (!selinux_initialized(state)) {
+ *out_sid = sid;
+ return 0;
+ }
+
+ rc = map_global_sid_to_ss(state, sid, &ss_sid, GFP_ATOMIC);
+ if (rc)
+ return rc;
+ rc = map_global_sid_to_ss(state, mls_sid, &ss_mlssid, GFP_ATOMIC);
+ if (rc)
+ return rc;
+
+ rc = selinux_ss_sid_mls_copy(state, ss_sid, ss_mlssid, &ss_outsid);
+ if (rc)
+ return rc;
+
+ return map_ss_sid_to_global(state, ss_outsid, out_sid, GFP_ATOMIC);
+}
+
+int security_net_peersid_resolve(struct selinux_state *state, u32 nlbl_sid,
+ u32 nlbl_type, u32 xfrm_sid, u32 *out_sid)
+{
+ u32 ss_nlblsid, ss_xfrmsid, ss_outsid;
+ int rc;
+
+ if (!selinux_initialized(state)) {
+ if (xfrm_sid == SECSID_NULL) {
+ *out_sid = nlbl_sid;
+ return 0;
+ }
+ if (nlbl_sid == SECSID_NULL || nlbl_type == NETLBL_NLTYPE_UNLABELED) {
+ *out_sid = xfrm_sid;
+ return 0;
+ }
+ *out_sid = SECSID_NULL;
+ return 0;
+ }
+
+ rc = map_global_sid_to_ss(state, nlbl_sid, &ss_nlblsid, GFP_ATOMIC);
+ if (rc)
+ return rc;
+ rc = map_global_sid_to_ss(state, xfrm_sid, &ss_xfrmsid, GFP_ATOMIC);
+ if (rc)
+ return rc;
+
+ rc = selinux_ss_net_peersid_resolve(state, ss_nlblsid, nlbl_type, ss_xfrmsid, &ss_outsid);
+ if (rc)
+ return rc;
+
+ return map_ss_sid_to_global(state, ss_outsid, out_sid, GFP_ATOMIC);
+}
+
+int security_fs_use(struct selinux_state *state, const char *fstype,
+ unsigned short *behavior, u32 *sid)
+{
+ int rc;
+
+ if (!selinux_initialized(state)) {
+ *behavior = SECURITY_FS_USE_NONE;
+ *sid = SECINITSID_UNLABELED;
+ return 0;
+ }
+
+ rc = selinux_ss_fs_use(state, fstype, behavior, sid);
+ if (rc)
+ return rc;
+
+ if (*sid <= SECINITSID_NUM)
+ return 0;
+
+ return map_ss_sid_to_global(state, *sid, sid, GFP_ATOMIC);
+}
+
+int security_genfs_sid(struct selinux_state *state, const char *fstype,
+ const char *path, u16 sclass, u32 *out_sid)
+{
+ int rc;
+ u32 ss_outsid;
+
+ if (!selinux_initialized(state)) {
+ *out_sid = SECINITSID_UNLABELED;
+ return 0;
+ }
+
+ rc = selinux_ss_genfs_sid(state, fstype, path, sclass, &ss_outsid);
+ if (rc)
+ return rc;
+
+ return map_ss_sid_to_global(state, ss_outsid, out_sid, GFP_ATOMIC);
+}
+
+int selinux_policy_genfs_sid(struct selinux_policy *policy, const char *fstype,
+ const char *path, u16 sclass, u32 *out_sid)
+{
+ int rc;
+ u32 ss_outsid;
+
+ rc = selinux_ss_policy_genfs_sid(policy, fstype, path, sclass, &ss_outsid);
+ if (rc)
+ return rc;
+
+ return map_ss_sid_to_global(current_selinux_state, ss_outsid, out_sid,
+ GFP_ATOMIC);
+}
+
+int selinux_audit_rule_match(struct lsm_prop *prop, u32 field, u32 op, void *vrule)
+{
+ int rc;
+ struct lsm_prop local_prop;
+ struct selinux_state *state = current_selinux_state;
+
+ if (!selinux_initialized(state))
+ return 0;
+
+ rc = map_global_sid_to_ss(state, prop->selinux.secid,
+ &local_prop.selinux.secid, GFP_ATOMIC);
+ if (rc)
+ return -ENOENT;
+ return selinux_ss_audit_rule_match(&local_prop, field, op, vrule);
+}
+
+#ifdef CONFIG_NETLABEL
+int security_netlbl_secattr_to_sid(struct selinux_state *state,
+ struct netlbl_lsm_secattr *secattr,
+ u32 *out_sid)
+{
+ int rc;
+ u32 ss_outsid;
+
+ if (!selinux_initialized(state)) {
+ *out_sid = SECSID_NULL;
+ return 0;
+ }
+
+ // The secattr secid is a global SID
+ if (secattr->flags & NETLBL_SECATTR_SECID) {
+ *out_sid = secattr->attr.secid;
+ return 0;
+ }
+
+ rc = selinux_ss_netlbl_secattr_to_sid(state, secattr, &ss_outsid);
+ if (rc)
+ return rc;
+
+ return map_ss_sid_to_global(state, ss_outsid, out_sid, GFP_ATOMIC);
+}
+
+int security_netlbl_sid_to_secattr(struct selinux_state *state, u32 sid,
+ struct netlbl_lsm_secattr *secattr)
+{
+ int rc;
+ u32 ss_sid;
+
+ if (!selinux_initialized(state))
+ return 0;
+
+ rc = map_global_sid_to_ss(state, sid, &ss_sid, GFP_ATOMIC);
+ if (rc)
+ return rc;
+ rc = selinux_ss_netlbl_sid_to_secattr(state, ss_sid, secattr);
+ if (rc)
+ return rc;
+
+ // The secattr secid is a global SID.
+ secattr->attr.secid = sid;
+ secattr->flags |= NETLBL_SECATTR_SECID;
+ return 0;
+}
+#endif
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index e84f3a1e3e12..471992376507 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -767,7 +767,8 @@ static int selinux_set_mnt_opts(struct super_block *sb,
* Determine the labeling behavior to use for this
* filesystem type.
*/
- rc = security_fs_use(current_selinux_state, sb);
+ rc = security_fs_use(current_selinux_state, sb->s_type->name,
+ &sbsec->behavior, &sbsec->sid);
if (rc) {
pr_warn("%s: security_fs_use(%s) returned %d\n",
__func__, sb->s_type->name, rc);
@@ -978,7 +979,9 @@ static int selinux_sb_clone_mnt_opts(const struct super_block *oldsb,
if (newsbsec->behavior == SECURITY_FS_USE_NATIVE &&
!(kern_flags & SECURITY_LSM_NATIVE_LABELS) && !set_context) {
- rc = security_fs_use(current_selinux_state, newsb);
+ rc = security_fs_use(current_selinux_state,
+ newsb->s_type->name,
+ &newsbsec->behavior, &newsbsec->sid);
if (rc)
goto out;
}
@@ -3657,7 +3660,7 @@ static int selinux_inode_getsecurity(struct mnt_idmap *idmap,
isec->sid, &context,
&size);
else
- error = security_sid_to_context(current_selinux_state, isec->sid,
+ error = security_sid_to_context_valid(current_selinux_state, isec->sid,
&context, &size);
if (error)
return error;
diff --git a/security/selinux/include/global_sidtab.h b/security/selinux/include/global_sidtab.h
index f62a9165d26a..a47cebecc944 100644
--- a/security/selinux/include/global_sidtab.h
+++ b/security/selinux/include/global_sidtab.h
@@ -7,13 +7,6 @@
#ifndef _GLOBAL_SIDTAB_H_
#define _GLOBAL_SIDTAB_H_
-#include <linux/types.h>
-
extern int global_sidtab_init(void);
-extern int global_sid_to_context(u32 sid, char **scontext, u32 *scontext_len);
-
-extern int global_context_to_sid(const char *scontext, u32 scontext_len,
- u32 *out_sid, gfp_t gfp);
-
#endif /* _GLOBAL_SIDTAB_H_ */
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
index 04325259c44f..079a5544d05c 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -355,25 +355,15 @@ void security_compute_xperms_decision(struct selinux_state *state, u32 ssid,
u8 base_perm,
struct extended_perms_decision *xpermd);
-void security_compute_av_user(struct selinux_state *state, u32 ssid, u32 tsid,
- u16 tclass, struct av_decision *avd);
-
int security_transition_sid(struct selinux_state *state, u32 ssid, u32 tsid,
u16 tclass, const struct qstr *qstr, u32 *out_sid);
-int security_transition_sid_user(struct selinux_state *state, u32 ssid,
- u32 tsid, u16 tclass, const char *objname,
- u32 *out_sid);
-
-int security_member_sid(struct selinux_state *state, u32 ssid, u32 tsid,
- u16 tclass, u32 *out_sid);
-
-int security_change_sid(struct selinux_state *state, u32 ssid, u32 tsid,
- u16 tclass, u32 *out_sid);
-
int security_sid_to_context(struct selinux_state *state, u32 sid,
char **scontext, u32 *scontext_len);
+int security_sid_to_context_valid(struct selinux_state *state, u32 sid,
+ char **scontext, u32 *scontext_len);
+
int security_sid_to_context_force(struct selinux_state *state, u32 sid,
char **scontext, u32 *scontext_len);
@@ -394,9 +384,6 @@ int security_context_to_sid_force(struct selinux_state *state,
const char *scontext, u32 scontext_len,
u32 *sid);
-int security_get_user_sids(struct selinux_state *state, u32 callsid,
- const char *username, u32 **sids, u32 *nel);
-
int security_port_sid(struct selinux_state *state, u8 protocol, u16 port,
u32 *out_sid);
@@ -415,9 +402,6 @@ int security_node_sid(struct selinux_state *state, u16 domain, const void *addr,
int security_validate_transition(struct selinux_state *state, u32 oldsid,
u32 newsid, u32 tasksid, u16 tclass);
-int security_validate_transition_user(struct selinux_state *state, u32 oldsid,
- u32 newsid, u32 tasksid, u16 tclass);
-
int security_bounded_transition(struct selinux_state *state, u32 old_sid,
u32 new_sid);
@@ -443,7 +427,8 @@ int security_get_allow_unknown(struct selinux_state *state);
#define SECURITY_FS_USE_NATIVE 7 /* use native label support */
#define SECURITY_FS_USE_MAX 7 /* Highest SECURITY_FS_USE_XXX */
-int security_fs_use(struct selinux_state *state, struct super_block *sb);
+int security_fs_use(struct selinux_state *state, const char *fstype,
+ unsigned short *behavior, u32 *sid);
int security_genfs_sid(struct selinux_state *state, const char *fstype,
const char *path, u16 sclass, u32 *sid);
diff --git a/security/selinux/include/selinux_ss.h b/security/selinux/include/selinux_ss.h
new file mode 100644
index 000000000000..0c3c6df88f5d
--- /dev/null
+++ b/security/selinux/include/selinux_ss.h
@@ -0,0 +1,119 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef _SELINUX_SS_H_
+#define _SELINUX_SS_H_
+
+/*
+ * SELinux security server policy-dependent interfaces.
+ * Most callers should use the corresponding security_*() interfaces
+ * from security.h instead in order to transparently map to/from
+ * global SIDs.
+ */
+
+void selinux_ss_compute_av(struct selinux_state *state, u32 ssid, u32 tsid,
+ u16 tclass, struct av_decision *avd,
+ struct extended_perms *xperms);
+
+void selinux_ss_compute_xperms_decision(struct selinux_state *state, u32 ssid,
+ u32 tsid, u16 tclass, u8 driver,
+ u8 base_perm,
+ struct extended_perms_decision *xpermd);
+
+void selinux_ss_compute_av_user(struct selinux_state *state, u32 ssid, u32 tsid,
+ u16 tclass, struct av_decision *avd);
+
+int selinux_ss_transition_sid(struct selinux_state *state, u32 ssid, u32 tsid,
+ u16 tclass, const struct qstr *qstr,
+ u32 *out_sid);
+
+int selinux_ss_transition_sid_user(struct selinux_state *state, u32 ssid,
+ u32 tsid, u16 tclass, const char *objname,
+ u32 *out_sid);
+
+int selinux_ss_member_sid(struct selinux_state *state, u32 ssid, u32 tsid,
+ u16 tclass, u32 *out_sid);
+
+int selinux_ss_change_sid(struct selinux_state *state, u32 ssid, u32 tsid,
+ u16 tclass, u32 *out_sid);
+
+int selinux_ss_sid_to_context(struct selinux_state *state, u32 sid,
+ char **scontext, u32 *scontext_len);
+
+int selinux_ss_sid_to_context_force(struct selinux_state *state, u32 sid,
+ char **scontext, u32 *scontext_len);
+
+int selinux_ss_sid_to_context_inval(struct selinux_state *state, u32 sid,
+ char **scontext, u32 *scontext_len);
+
+int selinux_ss_context_to_sid(struct selinux_state *state, const char *scontext,
+ u32 scontext_len, u32 *out_sid, gfp_t gfp);
+
+int selinux_ss_context_str_to_sid(struct selinux_state *state,
+ const char *scontext, u32 *out_sid,
+ gfp_t gfp);
+
+int selinux_ss_context_to_sid_default(struct selinux_state *state,
+ const char *scontext, u32 scontext_len,
+ u32 *out_sid, u32 def_sid,
+ gfp_t gfp_flags);
+
+int selinux_ss_context_to_sid_force(struct selinux_state *state,
+ const char *scontext, u32 scontext_len,
+ u32 *sid, gfp_t gfp);
+
+int selinux_ss_get_user_sids(struct selinux_state *state, u32 callsid,
+ const char *username, u32 **sids, u32 *nel);
+
+int selinux_ss_port_sid(struct selinux_state *state, u8 protocol, u16 port,
+ u32 *out_sid);
+
+int selinux_ss_ib_pkey_sid(struct selinux_state *state, u64 subnet_prefix,
+ u16 pkey_num, u32 *out_sid);
+
+int selinux_ss_ib_endport_sid(struct selinux_state *state, const char *dev_name,
+ u8 port_num, u32 *out_sid);
+
+int selinux_ss_netif_sid(struct selinux_state *state, const char *name,
+ u32 *if_sid);
+
+int selinux_ss_node_sid(struct selinux_state *state, u16 domain,
+ const void *addr, u32 addrlen, u32 *out_sid);
+
+int selinux_ss_validate_transition(struct selinux_state *state, u32 oldsid,
+ u32 newsid, u32 tasksid, u16 tclass);
+
+int selinux_ss_validate_transition_user(struct selinux_state *state, u32 oldsid,
+ u32 newsid, u32 tasksid, u16 tclass);
+
+int selinux_ss_bounded_transition(struct selinux_state *state, u32 oldsid,
+ u32 newsid);
+
+int selinux_ss_sid_mls_copy(struct selinux_state *state, u32 sid, u32 mls_sid,
+ u32 *new_sid);
+
+int selinux_ss_net_peersid_resolve(struct selinux_state *state, u32 nlbl_sid,
+ u32 nlbl_type, u32 xfrm_sid, u32 *peer_sid);
+
+int selinux_ss_fs_use(struct selinux_state *state, const char *fstype,
+ unsigned short *behavior, u32 *sid);
+
+int selinux_ss_genfs_sid(struct selinux_state *state, const char *fstype,
+ const char *path, u16 sclass, u32 *sid);
+
+int selinux_ss_policy_genfs_sid(struct selinux_policy *policy,
+ const char *fstype, const char *path,
+ u16 sclass, u32 *sid);
+
+int selinux_ss_audit_rule_match(struct lsm_prop *prop, u32 field, u32 op,
+ void *rule);
+
+#ifdef CONFIG_NETLABEL
+int selinux_ss_netlbl_secattr_to_sid(struct selinux_state *state,
+ struct netlbl_lsm_secattr *secattr,
+ u32 *sid);
+
+int selinux_ss_netlbl_sid_to_secattr(struct selinux_state *state, u32 sid,
+ struct netlbl_lsm_secattr *secattr);
+#endif
+
+#endif /* _SELINUX_SS_H_ */
diff --git a/security/selinux/include/sidtab.h b/security/selinux/include/sidtab.h
index 832c85c70d83..1d40e1a7fa42 100644
--- a/security/selinux/include/sidtab.h
+++ b/security/selinux/include/sidtab.h
@@ -26,6 +26,8 @@ struct sidtab_entry {
struct sidtab_str_cache __rcu *cache;
#endif
struct hlist_node list;
+ u32 ss_sid; // global SID table only
+ struct selinux_state *state; // global SID table only
};
union sidtab_entry_inner {
@@ -134,6 +136,9 @@ void sidtab_freeze_end(struct sidtab *s, unsigned long *flags)
int sidtab_context_to_sid(struct sidtab *s, struct context *context, u32 *sid);
+int sidtab_context_ss_to_sid(struct sidtab *s, struct context *context,
+ struct selinux_state *state, u32 ss_sid, u32 *sid);
+
void sidtab_destroy(struct sidtab *s);
int sidtab_hash_stats(struct sidtab *sidtab, char *page);
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index d6c8d8245c3c..46933452f961 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -39,6 +39,7 @@
#include "avc.h"
#include "avc_ss.h"
#include "security.h"
+#include "selinux_ss.h"
#include "objsec.h"
#include "conditional.h"
#include "ima.h"
@@ -868,11 +869,11 @@ static ssize_t sel_write_context(struct file *file, char *buf, size_t size)
if (length)
goto out;
- length = security_context_to_sid(state, buf, size, &sid, GFP_KERNEL);
+ length = selinux_ss_context_to_sid(state, buf, size, &sid, GFP_KERNEL);
if (length)
goto out;
- length = security_sid_to_context(state, sid, &canon, &len);
+ length = selinux_ss_sid_to_context(state, sid, &canon, &len);
if (length)
goto out;
@@ -1011,19 +1012,19 @@ static ssize_t sel_write_validatetrans(struct file *file,
if (sscanf(req, "%s %s %hu %s", oldcon, newcon, &tclass, taskcon) != 4)
goto out;
- rc = security_context_str_to_sid(state, oldcon, &osid, GFP_KERNEL);
+ rc = selinux_ss_context_str_to_sid(state, oldcon, &osid, GFP_KERNEL);
if (rc)
goto out;
- rc = security_context_str_to_sid(state, newcon, &nsid, GFP_KERNEL);
+ rc = selinux_ss_context_str_to_sid(state, newcon, &nsid, GFP_KERNEL);
if (rc)
goto out;
- rc = security_context_str_to_sid(state, taskcon, &tsid, GFP_KERNEL);
+ rc = selinux_ss_context_str_to_sid(state, taskcon, &tsid, GFP_KERNEL);
if (rc)
goto out;
- rc = security_validate_transition_user(state, osid, nsid, tsid, tclass);
+ rc = selinux_ss_validate_transition_user(state, osid, nsid, tsid, tclass);
if (!rc)
rc = count;
out:
@@ -1125,15 +1126,15 @@ static ssize_t sel_write_access(struct file *file, char *buf, size_t size)
if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3)
goto out;
- length = security_context_str_to_sid(state, scon, &ssid, GFP_KERNEL);
+ length = selinux_ss_context_str_to_sid(state, scon, &ssid, GFP_KERNEL);
if (length)
goto out;
- length = security_context_str_to_sid(state, tcon, &tsid, GFP_KERNEL);
+ length = selinux_ss_context_str_to_sid(state, tcon, &tsid, GFP_KERNEL);
if (length)
goto out;
- security_compute_av_user(state, ssid, tsid, tclass, &avd);
+ selinux_ss_compute_av_user(state, ssid, tsid, tclass, &avd);
length = scnprintf(buf, SIMPLE_TRANSACTION_LIMIT,
"%x %x %x %x %u %x",
@@ -1216,20 +1217,20 @@ static ssize_t sel_write_create(struct file *file, char *buf, size_t size)
objname = namebuf;
}
- length = security_context_str_to_sid(state, scon, &ssid, GFP_KERNEL);
+ length = selinux_ss_context_str_to_sid(state, scon, &ssid, GFP_KERNEL);
if (length)
goto out;
- length = security_context_str_to_sid(state, tcon, &tsid, GFP_KERNEL);
+ length = selinux_ss_context_str_to_sid(state, tcon, &tsid, GFP_KERNEL);
if (length)
goto out;
- length = security_transition_sid_user(state, ssid, tsid, tclass,
+ length = selinux_ss_transition_sid_user(state, ssid, tsid, tclass,
objname, &newsid);
if (length)
goto out;
- length = security_sid_to_context(state, newsid, &newcon, &len);
+ length = selinux_ss_sid_to_context(state, newsid, &newcon, &len);
if (length)
goto out;
@@ -1282,19 +1283,19 @@ static ssize_t sel_write_relabel(struct file *file, char *buf, size_t size)
if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3)
goto out;
- length = security_context_str_to_sid(state, scon, &ssid, GFP_KERNEL);
+ length = selinux_ss_context_str_to_sid(state, scon, &ssid, GFP_KERNEL);
if (length)
goto out;
- length = security_context_str_to_sid(state, tcon, &tsid, GFP_KERNEL);
+ length = selinux_ss_context_str_to_sid(state, tcon, &tsid, GFP_KERNEL);
if (length)
goto out;
- length = security_change_sid(state, ssid, tsid, tclass, &newsid);
+ length = selinux_ss_change_sid(state, ssid, tsid, tclass, &newsid);
if (length)
goto out;
- length = security_sid_to_context(state, newsid, &newcon, &len);
+ length = selinux_ss_sid_to_context(state, newsid, &newcon, &len);
if (length)
goto out;
@@ -1348,18 +1349,18 @@ static ssize_t sel_write_user(struct file *file, char *buf, size_t size)
if (sscanf(buf, "%s %s", con, user) != 2)
goto out;
- length = security_context_str_to_sid(state, con, &sid, GFP_KERNEL);
+ length = selinux_ss_context_str_to_sid(state, con, &sid, GFP_KERNEL);
if (length)
goto out;
- length = security_get_user_sids(state, sid, user, &sids, &nsids);
+ length = selinux_ss_get_user_sids(state, sid, user, &sids, &nsids);
if (length)
goto out;
length = sprintf(buf, "%u", nsids) + 1;
ptr = buf + length;
for (i = 0; i < nsids; i++) {
- rc = security_sid_to_context(state, sids[i], &newcon, &len);
+ rc = selinux_ss_sid_to_context(state, sids[i], &newcon, &len);
if (rc) {
length = rc;
goto out;
@@ -1413,19 +1414,19 @@ static ssize_t sel_write_member(struct file *file, char *buf, size_t size)
if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3)
goto out;
- length = security_context_str_to_sid(state, scon, &ssid, GFP_KERNEL);
+ length = selinux_ss_context_str_to_sid(state, scon, &ssid, GFP_KERNEL);
if (length)
goto out;
- length = security_context_str_to_sid(state, tcon, &tsid, GFP_KERNEL);
+ length = selinux_ss_context_str_to_sid(state, tcon, &tsid, GFP_KERNEL);
if (length)
goto out;
- length = security_member_sid(state, ssid, tsid, tclass, &newsid);
+ length = selinux_ss_member_sid(state, ssid, tsid, tclass, &newsid);
if (length)
goto out;
- length = security_sid_to_context(state, newsid, &newcon, &len);
+ length = selinux_ss_sid_to_context(state, newsid, &newcon, &len);
if (length)
goto out;
@@ -1937,7 +1938,7 @@ static ssize_t sel_read_initcon(struct file *file, char __user *buf,
ssize_t ret;
sid = file_inode(file)->i_ino&SEL_INO_MASK;
- ret = security_sid_to_context(fsi->state, sid, &con, &len);
+ ret = selinux_ss_sid_to_context(fsi->state, sid, &con, &len);
if (ret)
return ret;
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index 90a73bc627ca..acbb91e18b38 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -55,13 +55,13 @@
#include "avc.h"
#include "avc_ss.h"
#include "security.h"
+#include "selinux_ss.h"
#include "context.h"
#include "policydb.h"
#include "sidtab.h"
#include "services.h"
#include "conditional.h"
#include "mls.h"
-#include "objsec.h"
#include "netlabel.h"
#include "xfrm.h"
#include "ebitmap.h"
@@ -838,7 +838,7 @@ static int security_compute_validatetrans(struct selinux_state *state,
return rc;
}
-int security_validate_transition_user(struct selinux_state *state,
+int selinux_ss_validate_transition_user(struct selinux_state *state,
u32 oldsid, u32 newsid, u32 tasksid,
u16 tclass)
{
@@ -846,7 +846,7 @@ int security_validate_transition_user(struct selinux_state *state,
tclass, true);
}
-int security_validate_transition(struct selinux_state *state,
+int selinux_ss_validate_transition(struct selinux_state *state,
u32 oldsid, u32 newsid, u32 tasksid,
u16 orig_tclass)
{
@@ -855,7 +855,7 @@ int security_validate_transition(struct selinux_state *state,
}
/*
- * security_bounded_transition - check whether the given
+ * selinux_ss_bounded_transition - check whether the given
* transition is directed to bounded, or not.
* It returns 0, if @newsid is bounded by @oldsid.
* Otherwise, it returns error code.
@@ -864,7 +864,7 @@ int security_validate_transition(struct selinux_state *state,
* @oldsid : current security identifier
* @newsid : destinated security identifier
*/
-int security_bounded_transition(struct selinux_state *state,
+int selinux_ss_bounded_transition(struct selinux_state *state,
u32 old_sid, u32 new_sid)
{
struct selinux_policy *policy;
@@ -1030,7 +1030,7 @@ void services_compute_xperms_decision(struct extended_perms_decision *xpermd,
}
}
-void security_compute_xperms_decision(struct selinux_state *state,
+void selinux_ss_compute_xperms_decision(struct selinux_state *state,
u32 ssid,
u32 tsid,
u16 orig_tclass,
@@ -1118,7 +1118,7 @@ void security_compute_xperms_decision(struct selinux_state *state,
}
/**
- * security_compute_av - Compute access vector decisions.
+ * selinux_ss_compute_av - Compute access vector decisions.
* @state: SELinux state
* @ssid: source security identifier
* @tsid: target security identifier
@@ -1129,7 +1129,7 @@ void security_compute_xperms_decision(struct selinux_state *state,
* Compute a set of access vector decisions based on the
* SID pair (@ssid, @tsid) for the permissions in @tclass.
*/
-void security_compute_av(struct selinux_state *state,
+void selinux_ss_compute_av(struct selinux_state *state,
u32 ssid,
u32 tsid,
u16 orig_tclass,
@@ -1198,7 +1198,7 @@ void security_compute_av(struct selinux_state *state,
goto out;
}
-void security_compute_av_user(struct selinux_state *state,
+void selinux_ss_compute_av_user(struct selinux_state *state,
u32 ssid,
u32 tsid,
u16 tclass,
@@ -1438,7 +1438,7 @@ static int security_sid_to_context_core(struct selinux_state *state,
}
/**
- * security_sid_to_context - Obtain a context for a given SID.
+ * selinux_ss_sid_to_context - Obtain a context for a given SID.
* @state: SELinux state
* @sid: security identifier, SID
* @scontext: security context
@@ -1448,23 +1448,23 @@ static int security_sid_to_context_core(struct selinux_state *state,
* into a dynamically allocated string of the correct size. Set @scontext
* to point to this string and set @scontext_len to the length of the string.
*/
-int security_sid_to_context(struct selinux_state *state,
- u32 sid, char **scontext, u32 *scontext_len)
+int selinux_ss_sid_to_context(struct selinux_state *state,
+ u32 sid, char **scontext, u32 *scontext_len)
{
return security_sid_to_context_core(state, sid, scontext,
scontext_len, 0, 0);
}
-int security_sid_to_context_force(struct selinux_state *state, u32 sid,
- char **scontext, u32 *scontext_len)
+int selinux_ss_sid_to_context_force(struct selinux_state *state, u32 sid,
+ char **scontext, u32 *scontext_len)
{
return security_sid_to_context_core(state, sid, scontext,
scontext_len, 1, 0);
}
/**
- * security_sid_to_context_inval - Obtain a context for a given SID if it
- * is invalid.
+ * selinux_ss_sid_to_context_inval - Obtain a context for a given SID if it
+ * is invalid.
* @state: SELinux state
* @sid: security identifier, SID
* @scontext: security context
@@ -1476,8 +1476,8 @@ int security_sid_to_context_force(struct selinux_state *state, u32 sid,
* this string (or NULL if the context is valid) and set @scontext_len to
* the length of the string (or 0 if the context is valid).
*/
-int security_sid_to_context_inval(struct selinux_state *state, u32 sid,
- char **scontext, u32 *scontext_len)
+int selinux_ss_sid_to_context_inval(struct selinux_state *state, u32 sid,
+ char **scontext, u32 *scontext_len)
{
return security_sid_to_context_core(state, sid, scontext,
scontext_len, 1, 1);
@@ -1640,7 +1640,7 @@ static int security_context_to_sid_core(struct selinux_state *state,
}
/**
- * security_context_to_sid - Obtain a SID for a given security context.
+ * selinux_ss_context_to_sid - Obtain a SID for a given security context.
* @state: SELinux state
* @scontext: security context
* @scontext_len: length in bytes
@@ -1652,23 +1652,23 @@ static int security_context_to_sid_core(struct selinux_state *state,
* Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient
* memory is available, or 0 on success.
*/
-int security_context_to_sid(struct selinux_state *state,
- const char *scontext, u32 scontext_len, u32 *sid,
- gfp_t gfp)
+int selinux_ss_context_to_sid(struct selinux_state *state,
+ const char *scontext, u32 scontext_len, u32 *sid,
+ gfp_t gfp)
{
return security_context_to_sid_core(state, scontext, scontext_len,
sid, SECSID_NULL, gfp, 0);
}
-int security_context_str_to_sid(struct selinux_state *state,
- const char *scontext, u32 *sid, gfp_t gfp)
+int selinux_ss_context_str_to_sid(struct selinux_state *state,
+ const char *scontext, u32 *sid, gfp_t gfp)
{
- return security_context_to_sid(state, scontext, strlen(scontext),
- sid, gfp);
+ return security_context_to_sid_core(state, scontext, strlen(scontext),
+ sid, SECSID_NULL, gfp, 0);
}
/**
- * security_context_to_sid_default - Obtain a SID for a given security context,
+ * selinux_ss_context_to_sid_default - Obtain a SID for a given security context,
* falling back to specified default if needed.
*
* @state: SELinux state
@@ -1687,20 +1687,20 @@ int security_context_str_to_sid(struct selinux_state *state,
* Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient
* memory is available, or 0 on success.
*/
-int security_context_to_sid_default(struct selinux_state *state,
- const char *scontext, u32 scontext_len,
- u32 *sid, u32 def_sid, gfp_t gfp_flags)
+int selinux_ss_context_to_sid_default(struct selinux_state *state,
+ const char *scontext, u32 scontext_len,
+ u32 *sid, u32 def_sid, gfp_t gfp_flags)
{
return security_context_to_sid_core(state, scontext, scontext_len,
sid, def_sid, gfp_flags, 1);
}
-int security_context_to_sid_force(struct selinux_state *state,
- const char *scontext, u32 scontext_len,
- u32 *sid)
+int selinux_ss_context_to_sid_force(struct selinux_state *state,
+ const char *scontext, u32 scontext_len,
+ u32 *sid, gfp_t gfp)
{
return security_context_to_sid_core(state, scontext, scontext_len,
- sid, SECSID_NULL, GFP_KERNEL, 1);
+ sid, SECSID_NULL, gfp, 1);
}
static int compute_sid_handle_invalid_context(
@@ -1972,7 +1972,7 @@ static int security_compute_sid(struct selinux_state *state,
}
/**
- * security_transition_sid - Compute the SID for a new subject/object.
+ * selinux_ss_transition_sid - Compute the SID for a new subject/object.
* @state: SELinux state
* @ssid: source security identifier
* @tsid: target security identifier
@@ -1986,7 +1986,7 @@ static int security_compute_sid(struct selinux_state *state,
* if insufficient memory is available, or %0 if the new SID was
* computed successfully.
*/
-int security_transition_sid(struct selinux_state *state,
+int selinux_ss_transition_sid(struct selinux_state *state,
u32 ssid, u32 tsid, u16 tclass,
const struct qstr *qstr, u32 *out_sid)
{
@@ -1995,7 +1995,7 @@ int security_transition_sid(struct selinux_state *state,
qstr ? qstr->name : NULL, out_sid, true);
}
-int security_transition_sid_user(struct selinux_state *state,
+int selinux_ss_transition_sid_user(struct selinux_state *state,
u32 ssid, u32 tsid, u16 tclass,
const char *objname, u32 *out_sid)
{
@@ -2005,7 +2005,7 @@ int security_transition_sid_user(struct selinux_state *state,
}
/**
- * security_member_sid - Compute the SID for member selection.
+ * selinux_ss_member_sid - Compute the SID for member selection.
* @state: SELinux state
* @ssid: source security identifier
* @tsid: target security identifier
@@ -2018,7 +2018,7 @@ int security_transition_sid_user(struct selinux_state *state,
* if insufficient memory is available, or %0 if the SID was
* computed successfully.
*/
-int security_member_sid(struct selinux_state *state,
+int selinux_ss_member_sid(struct selinux_state *state,
u32 ssid,
u32 tsid,
u16 tclass,
@@ -2030,7 +2030,7 @@ int security_member_sid(struct selinux_state *state,
}
/**
- * security_change_sid - Compute the SID for object relabeling.
+ * selinux_ss_change_sid - Compute the SID for object relabeling.
* @state: SELinux state
* @ssid: source security identifier
* @tsid: target security identifier
@@ -2043,7 +2043,7 @@ int security_member_sid(struct selinux_state *state,
* if insufficient memory is available, or %0 if the SID was
* computed successfully.
*/
-int security_change_sid(struct selinux_state *state,
+int selinux_ss_change_sid(struct selinux_state *state,
u32 ssid,
u32 tsid,
u16 tclass,
@@ -2489,13 +2489,13 @@ static int ocontext_to_sid(struct sidtab *sidtab, struct ocontext *c,
}
/**
- * security_port_sid - Obtain the SID for a port.
+ * selinux_ss_port_sid - Obtain the SID for a port.
* @state: SELinux state
* @protocol: protocol number
* @port: port number
* @out_sid: security identifier
*/
-int security_port_sid(struct selinux_state *state,
+int selinux_ss_port_sid(struct selinux_state *state,
u8 protocol, u16 port, u32 *out_sid)
{
struct selinux_policy *policy;
@@ -2543,13 +2543,13 @@ int security_port_sid(struct selinux_state *state,
}
/**
- * security_ib_pkey_sid - Obtain the SID for a pkey.
+ * selinux_ss_ib_pkey_sid - Obtain the SID for a pkey.
* @state: SELinux state
* @subnet_prefix: Subnet Prefix
* @pkey_num: pkey number
* @out_sid: security identifier
*/
-int security_ib_pkey_sid(struct selinux_state *state,
+int selinux_ss_ib_pkey_sid(struct selinux_state *state,
u64 subnet_prefix, u16 pkey_num, u32 *out_sid)
{
struct selinux_policy *policy;
@@ -2597,13 +2597,13 @@ int security_ib_pkey_sid(struct selinux_state *state,
}
/**
- * security_ib_endport_sid - Obtain the SID for a subnet management interface.
+ * selinux_ss_ib_endport_sid - Obtain the SID for a subnet management interface.
* @state: SELinux state
* @dev_name: device name
* @port_num: port number
* @out_sid: security identifier
*/
-int security_ib_endport_sid(struct selinux_state *state,
+int selinux_ss_ib_endport_sid(struct selinux_state *state,
const char *dev_name, u8 port_num, u32 *out_sid)
{
struct selinux_policy *policy;
@@ -2652,13 +2652,13 @@ int security_ib_endport_sid(struct selinux_state *state,
}
/**
- * security_netif_sid - Obtain the SID for a network interface.
+ * selinux_ss_netif_sid - Obtain the SID for a network interface.
* @state: SELinux state
* @name: interface name
* @if_sid: interface SID
*/
-int security_netif_sid(struct selinux_state *state,
- const char *name, u32 *if_sid)
+int selinux_ss_netif_sid(struct selinux_state *state,
+ const char *name, u32 *if_sid)
{
struct selinux_policy *policy;
struct policydb *policydb;
@@ -2721,14 +2721,14 @@ static bool match_ipv6_addrmask(const u32 input[4], const u32 addr[4], const u32
}
/**
- * security_node_sid - Obtain the SID for a node (host).
+ * selinux_ss_node_sid - Obtain the SID for a node (host).
* @state: SELinux state
* @domain: communication domain aka address family
* @addrp: address
* @addrlen: address length in bytes
* @out_sid: security identifier
*/
-int security_node_sid(struct selinux_state *state,
+int selinux_ss_node_sid(struct selinux_state *state,
u16 domain,
const void *addrp,
u32 addrlen,
@@ -2810,7 +2810,7 @@ int security_node_sid(struct selinux_state *state,
#define SIDS_NEL 25
/**
- * security_get_user_sids - Obtain reachable SIDs for a user.
+ * selinux_ss_get_user_sids - Obtain reachable SIDs for a user.
* @state: SELinux state
* @fromsid: starting SID
* @username: username
@@ -2823,13 +2823,11 @@ int security_node_sid(struct selinux_state *state,
* array containing the set of SIDs. Set *@nel to the
* number of elements in the array.
*/
-
-
-int security_get_user_sids(struct selinux_state *state,
- u32 fromsid,
- const char *username,
- u32 **sids,
- u32 *nel)
+int selinux_ss_get_user_sids(struct selinux_state *state,
+ u32 fromsid,
+ const char *username,
+ u32 **sids,
+ u32 *nel)
{
struct selinux_policy *policy;
struct policydb *policydb;
@@ -3003,7 +3001,7 @@ static inline int __security_genfs_sid(struct selinux_policy *policy,
}
/**
- * security_genfs_sid - Obtain a SID for a file in a filesystem
+ * selinux_ss_genfs_sid - Obtain a SID for a file in a filesystem
* @state: SELinux state
* @fstype: filesystem type
* @path: path from root of mount
@@ -3013,7 +3011,7 @@ static inline int __security_genfs_sid(struct selinux_policy *policy,
* Acquire policy_rwlock before calling __security_genfs_sid() and release
* it afterward.
*/
-int security_genfs_sid(struct selinux_state *state,
+int selinux_ss_genfs_sid(struct selinux_state *state,
const char *fstype,
const char *path,
u16 orig_sclass,
@@ -3037,7 +3035,7 @@ int security_genfs_sid(struct selinux_state *state,
return retval;
}
-int selinux_policy_genfs_sid(struct selinux_policy *policy,
+int selinux_ss_policy_genfs_sid(struct selinux_policy *policy,
const char *fstype,
const char *path,
u16 orig_sclass,
@@ -3048,23 +3046,24 @@ int selinux_policy_genfs_sid(struct selinux_policy *policy,
}
/**
- * security_fs_use - Determine how to handle labeling for a filesystem.
+ * selinux_ss_fs_use - Determine how to handle labeling for a filesystem.
* @state: SELinux state
- * @sb: superblock in question
+ * @fstype: filesystem type
+ * @behavior: labeling behavior to apply
+ * @sid: SID for superblock
*/
-int security_fs_use(struct selinux_state *state, struct super_block *sb)
+int selinux_ss_fs_use(struct selinux_state *state, const char *fstype,
+ unsigned short *behavior, u32 *sid)
{
struct selinux_policy *policy;
struct policydb *policydb;
struct sidtab *sidtab;
int rc;
struct ocontext *c;
- struct superblock_security_struct *sbsec = selinux_superblock(sb);
- const char *fstype = sb->s_type->name;
if (!selinux_initialized(state)) {
- sbsec->behavior = SECURITY_FS_USE_NONE;
- sbsec->sid = SECINITSID_UNLABELED;
+ *behavior = SECURITY_FS_USE_NONE;
+ *sid = SECINITSID_UNLABELED;
return 0;
}
@@ -3082,8 +3081,8 @@ int security_fs_use(struct selinux_state *state, struct super_block *sb)
}
if (c) {
- sbsec->behavior = c->v.behavior;
- rc = ocontext_to_sid(sidtab, c, 0, &sbsec->sid);
+ *behavior = c->v.behavior;
+ rc = ocontext_to_sid(sidtab, c, 0, sid);
if (rc == -ESTALE) {
rcu_read_unlock();
goto retry;
@@ -3092,16 +3091,16 @@ int security_fs_use(struct selinux_state *state, struct super_block *sb)
goto out;
} else {
rc = __security_genfs_sid(policy, fstype, "/",
- SECCLASS_DIR, &sbsec->sid);
+ SECCLASS_DIR, sid);
if (rc == -ESTALE) {
rcu_read_unlock();
goto retry;
}
if (rc) {
- sbsec->behavior = SECURITY_FS_USE_NONE;
+ *behavior = SECURITY_FS_USE_NONE;
rc = 0;
} else {
- sbsec->behavior = SECURITY_FS_USE_GENFS;
+ *behavior = SECURITY_FS_USE_GENFS;
}
}
@@ -3291,10 +3290,10 @@ static int security_preserve_bools(struct selinux_policy *oldpolicy,
}
/*
- * security_sid_mls_copy() - computes a new sid based on the given
+ * selinux_ss_sid_mls_copy() - computes a new sid based on the given
* sid and the mls portion of mls_sid.
*/
-int security_sid_mls_copy(struct selinux_state *state,
+int selinux_ss_sid_mls_copy(struct selinux_state *state,
u32 sid, u32 mls_sid, u32 *new_sid)
{
struct selinux_policy *policy;
@@ -3384,7 +3383,7 @@ int security_sid_mls_copy(struct selinux_state *state,
}
/**
- * security_net_peersid_resolve - Compare and resolve two network peer SIDs
+ * selinux_ss_net_peersid_resolve - Compare and resolve two network peer SIDs
* @state: SELinux state
* @nlbl_sid: NetLabel SID
* @nlbl_type: NetLabel labeling protocol type
@@ -3405,7 +3404,7 @@ int security_sid_mls_copy(struct selinux_state *state,
* multiple, inconsistent labels | -<errno> | SECSID_NULL
*
*/
-int security_net_peersid_resolve(struct selinux_state *state,
+int selinux_ss_net_peersid_resolve(struct selinux_state *state,
u32 nlbl_sid, u32 nlbl_type,
u32 xfrm_sid,
u32 *peer_sid)
@@ -3655,7 +3654,7 @@ void selinux_audit_rule_free(void *vrule)
}
int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule,
- gfp_t gfp)
+ gfp_t gfp)
{
struct selinux_state *state = current_selinux_state;
struct selinux_policy *policy;
@@ -3780,7 +3779,7 @@ int selinux_audit_rule_known(struct audit_krule *rule)
return 0;
}
-int selinux_audit_rule_match(struct lsm_prop *prop, u32 field, u32 op, void *vrule)
+int selinux_ss_audit_rule_match(struct lsm_prop *prop, u32 field, u32 op, void *vrule)
{
struct selinux_state *state = current_selinux_state;
struct selinux_policy *policy;
@@ -3946,7 +3945,7 @@ static void security_netlbl_cache_add(struct netlbl_lsm_secattr *secattr,
}
/**
- * security_netlbl_secattr_to_sid - Convert a NetLabel secattr to a SELinux SID
+ * selinux_ss_netlbl_secattr_to_sid - Convert a NetLabel secattr to a SELinux SID
* @state: SELinux state
* @secattr: the NetLabel packet security attributes
* @sid: the SELinux SID
@@ -3961,7 +3960,7 @@ static void security_netlbl_cache_add(struct netlbl_lsm_secattr *secattr,
* failure.
*
*/
-int security_netlbl_secattr_to_sid(struct selinux_state *state,
+int selinux_ss_netlbl_secattr_to_sid(struct selinux_state *state,
struct netlbl_lsm_secattr *secattr,
u32 *sid)
{
@@ -3986,8 +3985,6 @@ int security_netlbl_secattr_to_sid(struct selinux_state *state,
if (secattr->flags & NETLBL_SECATTR_CACHE)
*sid = *(u32 *)secattr->cache->data;
- else if (secattr->flags & NETLBL_SECATTR_SECID)
- *sid = secattr->attr.secid;
else if (secattr->flags & NETLBL_SECATTR_MLS_LVL) {
rc = -EIDRM;
ctx = sidtab_search(sidtab, SECINITSID_NETMSG);
@@ -4029,7 +4026,7 @@ int security_netlbl_secattr_to_sid(struct selinux_state *state,
}
/**
- * security_netlbl_sid_to_secattr - Convert a SELinux SID to a NetLabel secattr
+ * selinux_ss_netlbl_sid_to_secattr - Convert a SELinux SID to a NetLabel secattr
* @state: SELinux state
* @sid: the SELinux SID
* @secattr: the NetLabel packet security attributes
@@ -4039,7 +4036,7 @@ int security_netlbl_secattr_to_sid(struct selinux_state *state,
* Returns zero on success, negative values on failure.
*
*/
-int security_netlbl_sid_to_secattr(struct selinux_state *state,
+int selinux_ss_netlbl_sid_to_secattr(struct selinux_state *state,
u32 sid, struct netlbl_lsm_secattr *secattr)
{
struct selinux_policy *policy;
@@ -4065,8 +4062,7 @@ int security_netlbl_sid_to_secattr(struct selinux_state *state,
if (secattr->domain == NULL)
goto out;
- secattr->attr.secid = sid;
- secattr->flags |= NETLBL_SECATTR_DOMAIN_CPY | NETLBL_SECATTR_SECID;
+ secattr->flags |= NETLBL_SECATTR_DOMAIN_CPY;
mls_export_netlbl_lvl(policydb, ctx, secattr);
rc = mls_export_netlbl_cat(policydb, ctx, secattr);
out:
diff --git a/security/selinux/ss/sidtab.c b/security/selinux/ss/sidtab.c
index 59f8c09158ef..da8d19ce5866 100644
--- a/security/selinux/ss/sidtab.c
+++ b/security/selinux/ss/sidtab.c
@@ -265,7 +265,8 @@ struct sidtab_entry *sidtab_search_entry_force(struct sidtab *s, u32 sid)
return sidtab_search_core(s, sid, 1);
}
-int sidtab_context_to_sid(struct sidtab *s, struct context *context, u32 *sid)
+int sidtab_context_ss_to_sid(struct sidtab *s, struct context *context,
+ struct selinux_state *state, u32 ss_sid, u32 *sid)
{
unsigned long flags;
u32 count, hash = context_compute_hash(context);
@@ -308,6 +309,8 @@ int sidtab_context_to_sid(struct sidtab *s, struct context *context, u32 *sid)
goto out_unlock;
dst->sid = index_to_sid(count);
+ dst->state = state;
+ dst->ss_sid = ss_sid;
dst->hash = hash;
rc = context_cpy(&dst->context, context);
@@ -344,10 +347,6 @@ int sidtab_context_to_sid(struct sidtab *s, struct context *context, u32 *sid)
dst_convert->hash);
}
- if (context->len)
- pr_info("SELinux: Context %s is not valid (left unmapped).\n",
- context->str);
-
*sid = index_to_sid(count);
/* write entries before updating count */
@@ -360,6 +359,11 @@ int sidtab_context_to_sid(struct sidtab *s, struct context *context, u32 *sid)
return rc;
}
+int sidtab_context_to_sid(struct sidtab *s, struct context *context, u32 *sid)
+{
+ return sidtab_context_ss_to_sid(s, context, NULL, 0, sid);
+}
+
static void sidtab_convert_hashtable(struct sidtab *s, u32 count)
{
struct sidtab_entry *entry;
--
2.50.1
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [PATCH v7 18/42] selinux: introduce a Kconfig option for SELinux namespaces
2025-08-14 13:25 [PATCH v7 00/42] SELinux namespace support Stephen Smalley
` (16 preceding siblings ...)
2025-08-14 13:26 ` [PATCH v7 17/42] selinux: wrap security server interfaces to use the " Stephen Smalley
@ 2025-08-14 13:26 ` Stephen Smalley
2025-08-14 13:26 ` [PATCH v7 19/42] selinux: eliminate global SID table if !CONFIG_SECURITY_SELINUX_NS Stephen Smalley
` (23 subsequent siblings)
41 siblings, 0 replies; 43+ messages in thread
From: Stephen Smalley @ 2025-08-14 13:26 UTC (permalink / raw)
To: selinux; +Cc: paul, omosnace, netdev, horms, Stephen Smalley
Introduce a separate SECURITY_SELINUX_NS Kconfig option for enabling
SELinux namespaces and have it default to n since it is experimental.
Make the SECURITY_SELINUX_MAXNS and SECURITY_SELINUX_MAXNSDEPTH Kconfig
options depend on this new option.
This option only controls whether the SELinux namespace support is
exposed to userspace, not the underlying infrastructure support.
When set to n, the kernel APIs for unsharing the SELinux namespace
(/sys/fs/selinux/unshare) and for setting limits on SELinux namespaces
(/sys/fs/selinux/{maxns,maxnsdepth}) are not created and only a
single initial SELinux namespace is created during startup and
associated with all tasks. When set to y, the kernel APIs are created
and userspace can use them (if permitted by policy and constrained by
the limits) to unshare the SELinux namespace.
Signed-off-by: Stephen Smalley <stephen.smalley.work@gmail.com>
---
security/selinux/Kconfig | 42 +++++++++++++++++++++++++++++++++---
security/selinux/hooks.c | 4 ++++
security/selinux/selinuxfs.c | 7 +++++-
3 files changed, 49 insertions(+), 4 deletions(-)
diff --git a/security/selinux/Kconfig b/security/selinux/Kconfig
index 82db54462253..aa25da389c46 100644
--- a/security/selinux/Kconfig
+++ b/security/selinux/Kconfig
@@ -88,10 +88,46 @@ config SECURITY_SELINUX_DEBUG
echo -n 'file "security/selinux/*" +p' > \
/proc/dynamic_debug/control
+config SECURITY_SELINUX_NS
+ bool "SELinux namespace support (experimental)"
+ depends on SECURITY_SELINUX
+ default n
+ help
+ This enables (experimental) support for SELinux namespaces,
+ i.e the ability to create multiple SELinux namespaces where
+ each namespace has its own independent enforcing mode,
+ AVC, and policy, accessible through its own independent
+ selinuxfs instance. When a task unshares its SELinux namespace,
+ it is associated with a new child namespace whose initial
+ state is permissive with no policy loaded, and the task is assigned
+ a separate SID in the new namespace, initially the kernel SID,
+ which is likewise independent of its SID in ancestor namespaces.
+ Subsequent actions by the task and its descendants are checked
+ against the new namespace and all ancestor namespaces, using the
+ SID it has in each namespace for that namespace's checks. Objects
+ like inodes only have a single SID irrespective of the namespace
+ in which they are created or accessed. If the context associated
+ with a SID is not defined in a namespace, then it is treated as
+ the unlabeled SID for access checking purposes in that namespace.
+ The current kernel API for unsharing the SELinux namespace is to
+ write a "1" to /sys/fs/selinux/unshare; this is likely to change
+ before upstreaming. Experimental patches for libselinux and
+ systemd to use this support can be found in the selinuxns
+ branches of https://github.com/stephensmalley/selinux, which
+ provides a selinux_unshare() API that wraps the kernel interface,
+ and https://github.com/stephensmalley/systemd, which has
+ a modified systemd-nspawn that uses this API when called
+ with --selinux-namespace and a modified systemd to perform
+ SELinux initialization when started within a container that
+ has its own SELinux namespace. Userspace can also detect
+ whether it is running in a non-init SELinux namespace by
+ reading /sys/fs/selinux/unshare ("1" means it has been unshared,
+ "0" means it has not) but an API for this might not be retained.
+
config SECURITY_SELINUX_MAXNS
int "SELinux default maximum number of namespaces"
- depends on SECURITY_SELINUX
- range 0 65535
+ depends on SECURITY_SELINUX_NS
+ range 1 65535
default 65535
help
This option sets the default maximum number of SELinux namespaces.
@@ -99,7 +135,7 @@ config SECURITY_SELINUX_MAXNS
config SECURITY_SELINUX_MAXNSDEPTH
int "SELinux default maximum depth of namespaces"
- depends on SECURITY_SELINUX
+ depends on SECURITY_SELINUX_NS
range 0 32
default 32
help
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 471992376507..98347ddae2e9 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -7790,8 +7790,10 @@ static struct security_hook_list selinux_hooks[] __ro_after_init = {
static void selinux_state_free(struct work_struct *work);
+#ifdef CONFIG_SECURITY_SELINUX_NS
unsigned int selinux_maxns = CONFIG_SECURITY_SELINUX_MAXNS;
unsigned int selinux_maxnsdepth = CONFIG_SECURITY_SELINUX_MAXNSDEPTH;
+#endif
static atomic_t selinux_nsnum = ATOMIC_INIT(0);
@@ -7802,11 +7804,13 @@ int selinux_state_create(const struct cred *cred)
struct selinux_state *newstate;
int rc;
+#ifdef CONFIG_SECURITY_SELINUX_NS
if (parent && atomic_read(&selinux_nsnum) >= selinux_maxns)
return -ENOSPC;
if (parent && parent->depth >= selinux_maxnsdepth)
return -ENOSPC;
+#endif
newstate = kzalloc(sizeof(*newstate), GFP_KERNEL);
if (!newstate)
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index 46933452f961..be78b71b7fcd 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -65,9 +65,11 @@ enum sel_inos {
SEL_STATUS, /* export current status using mmap() */
SEL_POLICY, /* allow userspace to read the in kernel policy */
SEL_VALIDATE_TRANS, /* compute validatetrans decision */
+#ifdef CONFIG_SECURITY_SELINUX_NS
SEL_UNSHARE, /* unshare selinux namespace */
SEL_MAXNS, /* maximum number of SELinux namespaces */
SEL_MAXNSDEPTH, /* maximum depth of SELinux namespaces */
+#endif
SEL_INO_NEXT, /* The next inode number to use */
};
@@ -325,6 +327,7 @@ static const struct file_operations sel_disable_ops = {
.llseek = generic_file_llseek,
};
+#ifdef CONFIG_SECURITY_SELINUX_NS
static ssize_t sel_read_unshare(struct file *filp, char __user *buf,
size_t count, loff_t *ppos)
{
@@ -523,7 +526,7 @@ static const struct file_operations sel_maxnsdepth_ops = {
.write = sel_write_maxnsdepth,
.llseek = generic_file_llseek,
};
-
+#endif
static ssize_t sel_read_policyvers(struct file *filp, char __user *buf,
size_t count, loff_t *ppos)
@@ -2282,9 +2285,11 @@ static int sel_fill_super(struct super_block *sb, struct fs_context *fc)
[SEL_POLICY] = {"policy", &sel_policy_ops, S_IRUGO},
[SEL_VALIDATE_TRANS] = {"validatetrans", &sel_transition_ops,
S_IWUGO},
+#ifdef CONFIG_SECURITY_SELINUX_NS
[SEL_UNSHARE] = {"unshare", &sel_unshare_ops, 0600},
[SEL_MAXNS] = {"maxns", &sel_maxns_ops, 0600},
[SEL_MAXNSDEPTH] = {"maxnsdepth", &sel_maxnsdepth_ops, 0600},
+#endif
/* last one */ {"", NULL, 0}
};
--
2.50.1
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [PATCH v7 19/42] selinux: eliminate global SID table if !CONFIG_SECURITY_SELINUX_NS
2025-08-14 13:25 [PATCH v7 00/42] SELinux namespace support Stephen Smalley
` (17 preceding siblings ...)
2025-08-14 13:26 ` [PATCH v7 18/42] selinux: introduce a Kconfig option for SELinux namespaces Stephen Smalley
@ 2025-08-14 13:26 ` Stephen Smalley
2025-08-14 13:26 ` [PATCH v7 20/42] selinux: maintain a small cache in the global SID table Stephen Smalley
` (22 subsequent siblings)
41 siblings, 0 replies; 43+ messages in thread
From: Stephen Smalley @ 2025-08-14 13:26 UTC (permalink / raw)
To: selinux; +Cc: paul, omosnace, netdev, horms, Stephen Smalley
Completely eliminate the global SID table and its wrapper functions
when CONFIG_SECURITY_SELINUX_NS=n to avoid imposing overhead on
systems that do not enable SELinux namespaces.
Signed-off-by: Stephen Smalley <stephen.smalley.work@gmail.com>
---
security/selinux/Makefile | 3 +-
security/selinux/include/audit.h | 8 +
security/selinux/include/global_sidtab.h | 7 +
security/selinux/include/security.h | 213 ++++++++++++++++++++++-
security/selinux/include/sidtab.h | 4 +
security/selinux/ss/sidtab.c | 8 +
6 files changed, 241 insertions(+), 2 deletions(-)
diff --git a/security/selinux/Makefile b/security/selinux/Makefile
index fe5f6f4bb0ea..e6b9628ab800 100644
--- a/security/selinux/Makefile
+++ b/security/selinux/Makefile
@@ -15,7 +15,7 @@ ccflags-y := -I$(srctree)/security/selinux -I$(srctree)/security/selinux/include
ccflags-$(CONFIG_SECURITY_SELINUX_DEBUG) += -DDEBUG
selinux-y := avc.o hooks.o selinuxfs.o netlink.o nlmsgtab.o netif.o \
- netnode.o netport.o status.o global_sidtab.o \
+ netnode.o netport.o status.o \
ss/ebitmap.o ss/hashtab.o ss/symtab.o ss/sidtab.o ss/avtab.o \
ss/policydb.o ss/services.o ss/conditional.o ss/mls.o ss/context.o
@@ -23,6 +23,7 @@ selinux-$(CONFIG_SECURITY_NETWORK_XFRM) += xfrm.o
selinux-$(CONFIG_NETLABEL) += netlabel.o
selinux-$(CONFIG_SECURITY_INFINIBAND) += ibpkey.o
selinux-$(CONFIG_IMA) += ima.o
+selinux-$(CONFIG_SECURITY_SELINUX_NS) += global_sidtab.o
genhdrs := flask.h av_permissions.h
diff --git a/security/selinux/include/audit.h b/security/selinux/include/audit.h
index d5b0425055e4..9dbddc6262c3 100644
--- a/security/selinux/include/audit.h
+++ b/security/selinux/include/audit.h
@@ -49,8 +49,16 @@ void selinux_audit_rule_free(void *rule);
* Returns 1 if the context id matches the rule, 0 if it does not, and
* -errno on failure.
*/
+#ifdef CONFIG_SECURITY_SELINUX_NS
int selinux_audit_rule_match(struct lsm_prop *prop, u32 field, u32 op,
void *rule);
+#else
+static inline int selinux_audit_rule_match(struct lsm_prop *prop, u32 field,
+ u32 op, void *rule)
+{
+ return selinux_ss_audit_rule_match(prop, field, op, rule);
+}
+#endif
/**
* selinux_audit_rule_known - check to see if rule contains selinux fields.
diff --git a/security/selinux/include/global_sidtab.h b/security/selinux/include/global_sidtab.h
index a47cebecc944..2e06bb865326 100644
--- a/security/selinux/include/global_sidtab.h
+++ b/security/selinux/include/global_sidtab.h
@@ -7,6 +7,13 @@
#ifndef _GLOBAL_SIDTAB_H_
#define _GLOBAL_SIDTAB_H_
+#ifdef CONFIG_SECURITY_SELINUX_NS
extern int global_sidtab_init(void);
+#else
+static inline int global_sidtab_init(void)
+{
+ return 0;
+}
+#endif /* CONFIG_SECURITY_SELINUX_NS */
#endif /* _GLOBAL_SIDTAB_H_ */
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
index 079a5544d05c..f6b6482301fc 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -346,6 +346,8 @@ struct extended_perms {
#define AVD_FLAGS_PERMISSIVE 0x0001
#define AVD_FLAGS_NEVERAUDIT 0x0002
+#ifdef CONFIG_SECURITY_SELINUX_NS
+
void security_compute_av(struct selinux_state *state, u32 ssid, u32 tsid,
u16 tclass, struct av_decision *avd,
struct extended_perms *xperms);
@@ -411,6 +413,160 @@ int security_sid_mls_copy(struct selinux_state *state, u32 sid, u32 mls_sid,
int security_net_peersid_resolve(struct selinux_state *state, u32 nlbl_sid,
u32 nlbl_type, u32 xfrm_sid, u32 *peer_sid);
+#else
+
+#include "selinux_ss.h"
+
+static inline void security_compute_av(struct selinux_state *state, u32 ssid,
+ u32 tsid, u16 tclass,
+ struct av_decision *avd,
+ struct extended_perms *xperms)
+{
+ selinux_ss_compute_av(state, ssid, tsid, tclass, avd, xperms);
+}
+
+static inline void
+security_compute_xperms_decision(struct selinux_state *state, u32 ssid,
+ u32 tsid, u16 tclass, u8 driver, u8 base_perm,
+ struct extended_perms_decision *xpermd)
+{
+ selinux_ss_compute_xperms_decision(state, ssid, tsid, tclass, driver,
+ base_perm, xpermd);
+}
+
+static inline int security_transition_sid(struct selinux_state *state, u32 ssid,
+ u32 tsid, u16 tclass,
+ const struct qstr *qstr, u32 *out_sid)
+{
+ return selinux_ss_transition_sid(state, ssid, tsid, tclass, qstr,
+ out_sid);
+}
+
+static inline int security_sid_to_context(struct selinux_state *state, u32 sid,
+ char **scontext, u32 *scontext_len)
+{
+ return selinux_ss_sid_to_context(state, sid, scontext, scontext_len);
+}
+
+static inline int security_sid_to_context_valid(struct selinux_state *state,
+ u32 sid, char **scontext,
+ u32 *scontext_len)
+{
+ return selinux_ss_sid_to_context(state, sid, scontext, scontext_len);
+}
+
+static inline int security_sid_to_context_force(struct selinux_state *state,
+ u32 sid, char **scontext,
+ u32 *scontext_len)
+{
+ return selinux_ss_sid_to_context_force(state, sid, scontext,
+ scontext_len);
+}
+
+static inline int security_sid_to_context_inval(struct selinux_state *state,
+ u32 sid, char **scontext,
+ u32 *scontext_len)
+{
+ return selinux_ss_sid_to_context_inval(state, sid, scontext,
+ scontext_len);
+}
+
+static inline int security_context_to_sid(struct selinux_state *state,
+ const char *scontext,
+ u32 scontext_len, u32 *out_sid,
+ gfp_t gfp)
+{
+ return selinux_ss_context_to_sid(state, scontext, scontext_len, out_sid,
+ gfp);
+}
+
+static inline int security_context_str_to_sid(struct selinux_state *state,
+ const char *scontext,
+ u32 *out_sid, gfp_t gfp)
+{
+ return selinux_ss_context_str_to_sid(state, scontext, out_sid, gfp);
+}
+
+static inline int security_context_to_sid_default(struct selinux_state *state,
+ const char *scontext,
+ u32 scontext_len,
+ u32 *out_sid, u32 def_sid,
+ gfp_t gfp_flags)
+{
+ return selinux_ss_context_to_sid_default(state, scontext, scontext_len,
+ out_sid, def_sid, gfp_flags);
+}
+
+static inline int security_context_to_sid_force(struct selinux_state *state,
+ const char *scontext,
+ u32 scontext_len, u32 *sid)
+{
+ return selinux_ss_context_to_sid_force(state, scontext, scontext_len,
+ sid, GFP_KERNEL);
+}
+
+static inline int security_port_sid(struct selinux_state *state, u8 protocol,
+ u16 port, u32 *out_sid)
+{
+ return selinux_ss_port_sid(state, protocol, port, out_sid);
+}
+
+static inline int security_ib_pkey_sid(struct selinux_state *state,
+ u64 subnet_prefix, u16 pkey_num,
+ u32 *out_sid)
+{
+ return selinux_ss_ib_pkey_sid(state, subnet_prefix, pkey_num, out_sid);
+}
+
+static inline int security_ib_endport_sid(struct selinux_state *state,
+ const char *dev_name, u8 port_num,
+ u32 *out_sid)
+{
+ return selinux_ss_ib_endport_sid(state, dev_name, port_num, out_sid);
+}
+
+static inline int security_netif_sid(struct selinux_state *state,
+ const char *name, u32 *if_sid)
+{
+ return selinux_ss_netif_sid(state, name, if_sid);
+}
+
+static inline int security_node_sid(struct selinux_state *state, u16 domain,
+ const void *addr, u32 addrlen, u32 *out_sid)
+{
+ return selinux_ss_node_sid(state, domain, addr, addrlen, out_sid);
+}
+
+static inline int security_validate_transition(struct selinux_state *state,
+ u32 oldsid, u32 newsid,
+ u32 tasksid, u16 tclass)
+{
+ return selinux_ss_validate_transition(state, oldsid, newsid, tasksid,
+ tclass);
+}
+
+static inline int security_bounded_transition(struct selinux_state *state,
+ u32 old_sid, u32 new_sid)
+{
+ return selinux_ss_bounded_transition(state, old_sid, new_sid);
+}
+
+static inline int security_sid_mls_copy(struct selinux_state *state, u32 sid,
+ u32 mls_sid, u32 *new_sid)
+{
+ return selinux_ss_sid_mls_copy(state, sid, mls_sid, new_sid);
+}
+
+static inline int security_net_peersid_resolve(struct selinux_state *state,
+ u32 nlbl_sid, u32 nlbl_type,
+ u32 xfrm_sid, u32 *peer_sid)
+{
+ return selinux_ss_net_peersid_resolve(state, nlbl_sid, nlbl_type,
+ xfrm_sid, peer_sid);
+}
+
+#endif /* CONFIG_SECURITY_SELINUX_NS */
+
int security_get_classes(struct selinux_policy *policy, char ***classes,
u32 *nclasses);
int security_get_permissions(struct selinux_policy *policy, const char *class,
@@ -427,6 +583,7 @@ int security_get_allow_unknown(struct selinux_state *state);
#define SECURITY_FS_USE_NATIVE 7 /* use native label support */
#define SECURITY_FS_USE_MAX 7 /* Highest SECURITY_FS_USE_XXX */
+#ifdef CONFIG_SECURITY_SELINUX_NS
int security_fs_use(struct selinux_state *state, const char *fstype,
unsigned short *behavior, u32 *sid);
@@ -435,15 +592,69 @@ int security_genfs_sid(struct selinux_state *state, const char *fstype,
int selinux_policy_genfs_sid(struct selinux_policy *policy, const char *fstype,
const char *path, u16 sclass, u32 *sid);
+#else
+static inline int security_fs_use(struct selinux_state *state,
+ const char *fstype, unsigned short *behavior,
+ u32 *sid)
+{
+ return selinux_ss_fs_use(state, fstype, behavior, sid);
+}
+
+static inline int security_genfs_sid(struct selinux_state *state,
+ const char *fstype, const char *path,
+ u16 sclass, u32 *sid)
+{
+ return selinux_ss_genfs_sid(state, fstype, path, sclass, sid);
+}
+
+static inline int selinux_policy_genfs_sid(struct selinux_policy *policy,
+ const char *fstype, const char *path,
+ u16 sclass, u32 *sid)
+{
+ return selinux_ss_policy_genfs_sid(policy, fstype, path, sclass, sid);
+}
+#endif
#ifdef CONFIG_NETLABEL
+#ifdef CONFIG_SECURITY_SELINUX_NS
int security_netlbl_secattr_to_sid(struct selinux_state *state,
struct netlbl_lsm_secattr *secattr,
u32 *sid);
int security_netlbl_sid_to_secattr(struct selinux_state *state, u32 sid,
struct netlbl_lsm_secattr *secattr);
-#else
+#else /* CONFIG_SECURITY_SELINUX_NS */
+#include <net/netlabel.h>
+
+static inline int
+security_netlbl_secattr_to_sid(struct selinux_state *state,
+ struct netlbl_lsm_secattr *secattr, u32 *sid)
+{
+ if (secattr->flags & NETLBL_SECATTR_SECID) {
+ *sid = secattr->attr.secid;
+ return 0;
+ }
+
+ return selinux_ss_netlbl_secattr_to_sid(state, secattr, sid);
+}
+
+static inline int
+security_netlbl_sid_to_secattr(struct selinux_state *state, u32 sid,
+ struct netlbl_lsm_secattr *secattr)
+{
+ int rc;
+
+ rc = selinux_ss_netlbl_sid_to_secattr(state, sid, secattr);
+ if (rc)
+ return rc;
+
+ secattr->attr.secid = sid;
+ secattr->flags |= NETLBL_SECATTR_SECID;
+ return 0;
+}
+
+#endif /* CONFIG_SECURITY_SELINUX_NS */
+#else /* CONFIG_NETLABEL */
static inline int
security_netlbl_secattr_to_sid(struct selinux_state *state,
struct netlbl_lsm_secattr *secattr, u32 *sid)
diff --git a/security/selinux/include/sidtab.h b/security/selinux/include/sidtab.h
index 1d40e1a7fa42..61389c588775 100644
--- a/security/selinux/include/sidtab.h
+++ b/security/selinux/include/sidtab.h
@@ -26,8 +26,10 @@ struct sidtab_entry {
struct sidtab_str_cache __rcu *cache;
#endif
struct hlist_node list;
+#ifdef CONFIG_SECURITY_SELINUX_NS
u32 ss_sid; // global SID table only
struct selinux_state *state; // global SID table only
+#endif
};
union sidtab_entry_inner {
@@ -136,8 +138,10 @@ void sidtab_freeze_end(struct sidtab *s, unsigned long *flags)
int sidtab_context_to_sid(struct sidtab *s, struct context *context, u32 *sid);
+#ifdef CONFIG_SECURITY_SELINUX_NS
int sidtab_context_ss_to_sid(struct sidtab *s, struct context *context,
struct selinux_state *state, u32 ss_sid, u32 *sid);
+#endif
void sidtab_destroy(struct sidtab *s);
diff --git a/security/selinux/ss/sidtab.c b/security/selinux/ss/sidtab.c
index da8d19ce5866..19991f01cd20 100644
--- a/security/selinux/ss/sidtab.c
+++ b/security/selinux/ss/sidtab.c
@@ -265,8 +265,12 @@ struct sidtab_entry *sidtab_search_entry_force(struct sidtab *s, u32 sid)
return sidtab_search_core(s, sid, 1);
}
+#ifdef CONFIG_SECURITY_SELINUX_NS
int sidtab_context_ss_to_sid(struct sidtab *s, struct context *context,
struct selinux_state *state, u32 ss_sid, u32 *sid)
+#else
+int sidtab_context_to_sid(struct sidtab *s, struct context *context, u32 *sid)
+#endif
{
unsigned long flags;
u32 count, hash = context_compute_hash(context);
@@ -309,8 +313,10 @@ int sidtab_context_ss_to_sid(struct sidtab *s, struct context *context,
goto out_unlock;
dst->sid = index_to_sid(count);
+#ifdef CONFIG_SECURITY_SELINUX_NS
dst->state = state;
dst->ss_sid = ss_sid;
+#endif
dst->hash = hash;
rc = context_cpy(&dst->context, context);
@@ -359,10 +365,12 @@ int sidtab_context_ss_to_sid(struct sidtab *s, struct context *context,
return rc;
}
+#ifdef CONFIG_SECURITY_SELINUX_NS
int sidtab_context_to_sid(struct sidtab *s, struct context *context, u32 *sid)
{
return sidtab_context_ss_to_sid(s, context, NULL, 0, sid);
}
+#endif
static void sidtab_convert_hashtable(struct sidtab *s, u32 count)
{
--
2.50.1
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [PATCH v7 20/42] selinux: maintain a small cache in the global SID table
2025-08-14 13:25 [PATCH v7 00/42] SELinux namespace support Stephen Smalley
` (18 preceding siblings ...)
2025-08-14 13:26 ` [PATCH v7 19/42] selinux: eliminate global SID table if !CONFIG_SECURITY_SELINUX_NS Stephen Smalley
@ 2025-08-14 13:26 ` Stephen Smalley
2025-08-14 13:26 ` [PATCH v7 21/42] selinux: update hook functions to use correct selinux namespace Stephen Smalley
` (21 subsequent siblings)
41 siblings, 0 replies; 43+ messages in thread
From: Stephen Smalley @ 2025-08-14 13:26 UTC (permalink / raw)
To: selinux; +Cc: paul, omosnace, netdev, horms, Stephen Smalley
Maintain a small cache in the global SID table to avoid needing
to map the context string each time we use a given SID in a different
namespace than the original one.
Signed-off-by: Stephen Smalley <stephen.smalley.work@gmail.com>
---
security/selinux/Kconfig | 11 +++
security/selinux/global_sidtab.c | 58 ++++++++++++++++
security/selinux/hooks.c | 1 +
security/selinux/include/global_sidtab.h | 7 ++
security/selinux/include/sidtab.h | 29 +++++++-
security/selinux/ss/sidtab.c | 85 ++++++++++++++++++++++++
6 files changed, 189 insertions(+), 2 deletions(-)
diff --git a/security/selinux/Kconfig b/security/selinux/Kconfig
index aa25da389c46..f7bd54aa136c 100644
--- a/security/selinux/Kconfig
+++ b/security/selinux/Kconfig
@@ -141,3 +141,14 @@ config SECURITY_SELINUX_MAXNSDEPTH
help
This option sets the default maximum depth of SELinux namespaces.
The value may be viewed or modified via /sys/fs/selinux/maxnsdepth.
+
+config SECURITY_SELINUX_SS_SID_CACHE_SIZE
+ int "Global SID to security server SID translation cache size"
+ depends on SECURITY_SELINUX_NS
+ default 4
+ help
+ This option defines the size of the global SID -> security server
+ SID cache, which improves the performance of mapping global SIDs.
+ Setting this option to 0 disables the cache completely.
+
+ If unsure, keep the default value.
diff --git a/security/selinux/global_sidtab.c b/security/selinux/global_sidtab.c
index 48934b429c8c..e1acf6607788 100644
--- a/security/selinux/global_sidtab.c
+++ b/security/selinux/global_sidtab.c
@@ -119,6 +119,11 @@ static int map_global_sid_to_ss(struct selinux_state *state, u32 sid,
int rc;
char *scontext;
u32 scontext_len;
+#if CONFIG_SECURITY_SELINUX_SS_SID_CACHE_SIZE > 0
+ struct sidtab_ss_sid_cache *cache;
+ unsigned long flags;
+ int i, first, last;
+#endif
if (sid <= SECINITSID_NUM) {
*ss_sid = sid;
@@ -136,6 +141,16 @@ static int map_global_sid_to_ss(struct selinux_state *state, u32 sid,
rcu_read_unlock();
return 0;
}
+#if CONFIG_SECURITY_SELINUX_SS_SID_CACHE_SIZE > 0
+ cache = &entry->ss_sid_cache;
+ for (i = cache->first; i >= 0 && i <= cache->last; i++) {
+ if (cache->state[i] == state && cache->ss_sid[i]) {
+ *ss_sid = cache->ss_sid[i];
+ rcu_read_unlock();
+ return 0;
+ }
+ }
+#endif
rcu_read_unlock();
rc = global_sid_to_context(sid, &scontext, &scontext_len);
@@ -144,10 +159,53 @@ static int map_global_sid_to_ss(struct selinux_state *state, u32 sid,
rc = selinux_ss_context_to_sid_force(state, scontext,
scontext_len, ss_sid, gfp);
+#if CONFIG_SECURITY_SELINUX_SS_SID_CACHE_SIZE > 0
+ if (rc == 0) {
+ spin_lock_irqsave(&global_sidtab.lock, flags);
+ entry = sidtab_search_entry_force(&global_sidtab, sid);
+ if (!entry) {
+ spin_unlock_irqrestore(&global_sidtab.lock, flags);
+ return -EINVAL;
+ }
+ cache = &entry->ss_sid_cache;
+ first = cache->first;
+ last = cache->last;
+ for (i = 0; i < ARRAY_SIZE(cache->ss_sid) && cache->ss_sid[i];
+ i++)
+ ;
+ if (i < ARRAY_SIZE(cache->ss_sid)) {
+ WRITE_ONCE(cache->ss_sid[i], *ss_sid);
+ /* ensure that the SID is written before the state */
+ smp_wmb();
+ WRITE_ONCE(cache->state[i], state);
+ } else {
+ if (first == -1)
+ i = 0;
+ else
+ i = first;
+ WRITE_ONCE(cache->ss_sid[i], *ss_sid);
+ /* ensure that the SID is written before the state */
+ smp_wmb();
+ WRITE_ONCE(cache->state[i], state);
+ }
+ /* ensure that state is updated before indices */
+ smp_wmb();
+ if (first == -1 || i < first)
+ WRITE_ONCE(cache->first, i);
+ if (last == -1 || i > last)
+ WRITE_ONCE(cache->last, i);
+ spin_unlock_irqrestore(&global_sidtab.lock, flags);
+ }
+#endif
kfree(scontext);
return rc;
}
+void global_sidtab_invalidate_state(struct selinux_state *state)
+{
+ sidtab_invalidate_state(&global_sidtab, state);
+}
+
static int map_ss_sid_to_global(struct selinux_state *state, u32 ss_sid,
u32 *out_sid, gfp_t gfp)
{
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 98347ddae2e9..e8cfd18a1cb1 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -7874,6 +7874,7 @@ static void selinux_state_free(struct work_struct *work)
do {
parent = state->parent;
+ global_sidtab_invalidate_state(state);
if (state->status_page)
__free_page(state->status_page);
selinux_state_policy_free(state);
diff --git a/security/selinux/include/global_sidtab.h b/security/selinux/include/global_sidtab.h
index 2e06bb865326..bf450d775b66 100644
--- a/security/selinux/include/global_sidtab.h
+++ b/security/selinux/include/global_sidtab.h
@@ -9,11 +9,18 @@
#ifdef CONFIG_SECURITY_SELINUX_NS
extern int global_sidtab_init(void);
+
+struct selinux_state;
+void global_sidtab_invalidate_state(struct selinux_state *state);
#else
static inline int global_sidtab_init(void)
{
return 0;
}
+
+static inline void global_sidtab_invalidate_state(struct selinux_state *state)
+{
+}
#endif /* CONFIG_SECURITY_SELINUX_NS */
#endif /* _GLOBAL_SIDTAB_H_ */
diff --git a/security/selinux/include/sidtab.h b/security/selinux/include/sidtab.h
index 61389c588775..2df3ac0df935 100644
--- a/security/selinux/include/sidtab.h
+++ b/security/selinux/include/sidtab.h
@@ -18,6 +18,16 @@
#include "context.h"
+#ifdef CONFIG_SECURITY_SELINUX_NS
+#if CONFIG_SECURITY_SELINUX_SS_SID_CACHE_SIZE > 0
+struct sidtab_ss_sid_cache {
+ u32 ss_sid[CONFIG_SECURITY_SELINUX_SS_SID_CACHE_SIZE];
+ struct selinux_state *state[CONFIG_SECURITY_SELINUX_SS_SID_CACHE_SIZE];
+ int first, last;
+};
+#endif
+#endif
+
struct sidtab_entry {
u32 sid;
u32 hash;
@@ -27,8 +37,11 @@ struct sidtab_entry {
#endif
struct hlist_node list;
#ifdef CONFIG_SECURITY_SELINUX_NS
- u32 ss_sid; // global SID table only
- struct selinux_state *state; // global SID table only
+ u32 ss_sid;
+ struct selinux_state *state;
+#if CONFIG_SECURITY_SELINUX_SS_SID_CACHE_SIZE > 0
+ struct sidtab_ss_sid_cache ss_sid_cache;
+#endif
#endif
};
@@ -166,4 +179,16 @@ static inline int sidtab_sid2str_get(struct sidtab *s,
}
#endif /* CONFIG_SECURITY_SELINUX_SID2STR_CACHE_SIZE > 0 */
+#ifdef CONFIG_SECURITY_SELINUX_NS
+#if CONFIG_SECURITY_SELINUX_SS_SID_CACHE_SIZE > 0
+extern void sidtab_invalidate_state(struct sidtab *s,
+ struct selinux_state *state);
+#else
+static inline void sidtab_invalidate_state(struct sidtab *s,
+ struct selinux_state *state)
+{
+}
+#endif /* CONFIG_SECURITY_SELINUX_SS_SID_CACHE_SIZE > 0 */
+#endif /* CONFIG_SECURITY_SELINUX_NS */
+
#endif /* _SS_SIDTAB_H_ */
diff --git a/security/selinux/ss/sidtab.c b/security/selinux/ss/sidtab.c
index 19991f01cd20..eea37f78bec9 100644
--- a/security/selinux/ss/sidtab.c
+++ b/security/selinux/ss/sidtab.c
@@ -648,3 +648,88 @@ int sidtab_sid2str_get(struct sidtab *s, struct sidtab_entry *entry, char **out,
}
#endif /* CONFIG_SECURITY_SELINUX_SID2STR_CACHE_SIZE > 0 */
+
+#ifdef CONFIG_SECURITY_SELINUX_NS
+#if CONFIG_SECURITY_SELINUX_SS_SID_CACHE_SIZE > 0
+static void sidtab_invalidate_state_entry(struct sidtab_entry *entry,
+ struct selinux_state *state)
+{
+ struct sidtab_ss_sid_cache *cache;
+ int i, first, last;
+
+ cache = &entry->ss_sid_cache;
+ first = cache->first;
+ last = cache->last;
+ for (i = first; i >= 0 && i <= last; i++) {
+ if (cache->state[i] == state) {
+ WRITE_ONCE(cache->ss_sid[i], 0);
+ WRITE_ONCE(cache->state[i], NULL);
+ if (first == i) {
+ for (first = i + 1; first <= last &&
+ !cache->ss_sid[first]; first++)
+ ;
+ if (first == (i+1))
+ first = -1;
+ WRITE_ONCE(cache->first, first);
+ }
+ if (last == i) {
+ for (last = i - 1; last >= first &&
+ last >= 0 &&
+ !cache->ss_sid[last]; last--)
+ ;
+ if (last == (i-1))
+ last = -1;
+ WRITE_ONCE(cache->last, last);
+ }
+ return;
+ }
+ }
+}
+
+static void sidtab_invalidate_state_tree(union sidtab_entry_inner entry,
+ u32 level,
+ struct selinux_state *state)
+{
+ u32 i;
+
+ if (level != 0) {
+ struct sidtab_node_inner *node = entry.ptr_inner;
+
+ if (!node)
+ return;
+
+ for (i = 0; i < SIDTAB_INNER_ENTRIES; i++)
+ sidtab_invalidate_state_tree(node->entries[i],
+ level - 1, state);
+ } else {
+ struct sidtab_node_leaf *node = entry.ptr_leaf;
+
+ if (!node)
+ return;
+
+ for (i = 0; i < SIDTAB_LEAF_ENTRIES; i++)
+ sidtab_invalidate_state_entry(&node->entries[i], state);
+ }
+}
+
+void sidtab_invalidate_state(struct sidtab *s, struct selinux_state *state)
+{
+ u32 i, level;
+ unsigned long flags;
+
+ spin_lock_irqsave(&s->lock, flags);
+
+ for (i = 0; i < SECINITSID_NUM; i++)
+ if (s->isids[i].set)
+ sidtab_invalidate_state_entry(&s->isids[i].entry, state);
+
+ level = SIDTAB_MAX_LEVEL;
+ while (level && !s->roots[level].ptr_inner)
+ --level;
+
+ sidtab_invalidate_state_tree(s->roots[level], level, state);
+
+ spin_unlock_irqrestore(&s->lock, flags);
+}
+#endif /* CONFIG_SECURITY_SELINUX_SS_SID_CACHE_SIZE > 0 */
+#endif /* CONFIG_SECURITY_SELINUX_NS */
--
2.50.1
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [PATCH v7 21/42] selinux: update hook functions to use correct selinux namespace
2025-08-14 13:25 [PATCH v7 00/42] SELinux namespace support Stephen Smalley
` (19 preceding siblings ...)
2025-08-14 13:26 ` [PATCH v7 20/42] selinux: maintain a small cache in the global SID table Stephen Smalley
@ 2025-08-14 13:26 ` Stephen Smalley
2025-08-14 13:26 ` [PATCH v7 22/42] selinux: introduce cred_task_has_perm() Stephen Smalley
` (20 subsequent siblings)
41 siblings, 0 replies; 43+ messages in thread
From: Stephen Smalley @ 2025-08-14 13:26 UTC (permalink / raw)
To: selinux; +Cc: paul, omosnace, netdev, horms, Stephen Smalley
Update the SELinux hook functions to use the correct SELinux namespace
rather than always using the current SELinux namespace. This is
necessary for hook functions that can be called outside of process
context. In order to have a SELinux namespace available for use in all
such hook functions, this change saves a reference to the current
SELinux namespace in open file security blobs for use by send_sigiotask
and in sock security blobs for use in network input or forward hooks. It
also fixes a few remaining uses of current_selinux_state that should be
using cred_selinux_state() on an appropriate cred structure.
In order to correctly label nodes and network interfaces, the SELinux
namespace is passed from the hook functions to the sel_netnode and
sel_netif interfaces and cached along with the other information.
Similarly, where needed, the SELinux namespace is passed from the hook
functions to the selinux_netlbl and selinux_xfrm interfaces for use in
invoking various security server or AVC interfaces.
There are a few residual xfrm functions where we do not have a
SELinux namespace available currently. For now these functions
always use the init SELinux namespace.
Signed-off-by: Stephen Smalley <stephen.smalley.work@gmail.com>
---
security/selinux/hooks.c | 169 +++++++++++++++++-----------
security/selinux/include/netif.h | 4 +-
security/selinux/include/netlabel.h | 14 ++-
security/selinux/include/netnode.h | 4 +-
security/selinux/include/objsec.h | 5 +
security/selinux/include/xfrm.h | 8 +-
security/selinux/netif.c | 31 +++--
security/selinux/netlabel.c | 35 +++---
security/selinux/netnode.c | 26 +++--
security/selinux/xfrm.c | 26 +++--
10 files changed, 206 insertions(+), 116 deletions(-)
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index e8cfd18a1cb1..99a83acfa19e 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2092,14 +2092,14 @@ static int selinux_binder_transaction(const struct cred *from,
int rc;
if (mysid != fromsid) {
- rc = avc_has_perm(current_selinux_state,
+ rc = avc_has_perm(cred_selinux_state(from),
mysid, fromsid, SECCLASS_BINDER,
BINDER__IMPERSONATE, NULL);
if (rc)
return rc;
}
- return avc_has_perm(current_selinux_state, fromsid, tosid,
+ return avc_has_perm(cred_selinux_state(from), fromsid, tosid,
SECCLASS_BINDER, BINDER__CALL, NULL);
}
@@ -2127,7 +2127,7 @@ static int selinux_binder_transfer_file(const struct cred *from,
ad.u.path = file->f_path;
if (sid != fsec->sid) {
- rc = avc_has_perm(current_selinux_state,
+ rc = avc_has_perm(cred_selinux_state(to),
sid, fsec->sid,
SECCLASS_FD,
FD__USE,
@@ -2146,7 +2146,7 @@ static int selinux_binder_transfer_file(const struct cred *from,
return 0;
isec = backing_inode_security(dentry);
- return avc_has_perm(current_selinux_state,
+ return avc_has_perm(cred_selinux_state(to),
sid, isec->sid, isec->sclass, file_to_av(file),
&ad);
}
@@ -3868,10 +3868,19 @@ static int selinux_file_alloc_security(struct file *file)
fsec->sid = sid;
fsec->fown_sid = sid;
+ fsec->state = get_selinux_state(current_selinux_state);
return 0;
}
+static void selinux_file_free_security(struct file *file)
+{
+ struct file_security_struct *fsec = selinux_file(file);
+
+ put_selinux_state(fsec->state);
+ fsec->state = NULL;
+}
+
/*
* Check whether a task has the ioctl permission and cmd
* operation to an inode.
@@ -3908,7 +3917,7 @@ static int ioctl_has_perm(const struct cred *cred, struct file *file,
return 0;
isec = inode_security(inode);
- rc = avc_has_extended_perms(current_selinux_state,
+ rc = avc_has_extended_perms(cred_selinux_state(cred),
ssid, isec->sid, isec->sclass,
requested, driver, AVC_EXT_IOCTL, xperm,
&ad);
@@ -4184,7 +4193,7 @@ static int selinux_file_send_sigiotask(struct task_struct *tsk,
else
perm = signal_to_av(signum);
- return avc_has_perm(current_selinux_state,
+ return avc_has_perm(fsec->state,
fsec->fown_sid, sid,
SECCLASS_PROCESS, perm, NULL);
}
@@ -4559,9 +4568,15 @@ static int selinux_task_movememory(struct task_struct *p)
static int selinux_task_kill(struct task_struct *p, struct kernel_siginfo *info,
int sig, const struct cred *cred)
{
+ struct selinux_state *state;
u32 secid;
u32 perm;
+ if (cred)
+ state = cred_selinux_state(cred);
+ else
+ state = current_selinux_state;
+
if (!sig)
perm = PROCESS__SIGNULL; /* null signal; existence test */
else
@@ -4570,8 +4585,8 @@ static int selinux_task_kill(struct task_struct *p, struct kernel_siginfo *info,
secid = current_sid();
else
secid = cred_sid(cred);
- return avc_has_perm(current_selinux_state,
- secid, task_sid_obj(p), SECCLASS_PROCESS, perm, NULL);
+ return avc_has_perm(state, secid, task_sid_obj(p),
+ SECCLASS_PROCESS, perm, NULL);
}
static void selinux_task_to_inode(struct task_struct *p,
@@ -4797,6 +4812,7 @@ static int selinux_parse_skb(struct sk_buff *skb, struct common_audit_data *ad,
* selinux_skb_peerlbl_sid - Determine the peer label of a packet
* @skb: the packet
* @family: protocol family
+ * @state: the SELinux state
* @sid: the packet's peer label SID
*
* Description:
@@ -4808,7 +4824,8 @@ static int selinux_parse_skb(struct sk_buff *skb, struct common_audit_data *ad,
* peer labels.
*
*/
-static int selinux_skb_peerlbl_sid(struct sk_buff *skb, u16 family, u32 *sid)
+static int selinux_skb_peerlbl_sid(struct sk_buff *skb, u16 family,
+ struct selinux_state *state, u32 *sid)
{
int err;
u32 xfrm_sid;
@@ -4818,12 +4835,13 @@ static int selinux_skb_peerlbl_sid(struct sk_buff *skb, u16 family, u32 *sid)
err = selinux_xfrm_skb_sid(skb, &xfrm_sid);
if (unlikely(err))
return -EACCES;
- err = selinux_netlbl_skbuff_getsid(skb, family, &nlbl_type, &nlbl_sid);
+ err = selinux_netlbl_skbuff_getsid(skb, family, state, &nlbl_type,
+ &nlbl_sid);
if (unlikely(err))
return -EACCES;
- err = security_net_peersid_resolve(current_selinux_state, nlbl_sid,
- nlbl_type, xfrm_sid, sid);
+ err = security_net_peersid_resolve(state, nlbl_sid, nlbl_type,
+ xfrm_sid, sid);
if (unlikely(err)) {
pr_warn(
"SELinux: failure in selinux_skb_peerlbl_sid(),"
@@ -4838,6 +4856,7 @@ static int selinux_skb_peerlbl_sid(struct sk_buff *skb, u16 family, u32 *sid)
* selinux_conn_sid - Determine the child socket label for a connection
* @sk_sid: the parent socket's SID
* @skb_sid: the packet's SID
+ * @state: the SELinux state
* @conn_sid: the resulting connection SID
*
* If @skb_sid is valid then the user:role:type information from @sk_sid is
@@ -4846,13 +4865,13 @@ static int selinux_skb_peerlbl_sid(struct sk_buff *skb, u16 family, u32 *sid)
* of @sk_sid. Returns zero on success, negative values on failure.
*
*/
-static int selinux_conn_sid(u32 sk_sid, u32 skb_sid, u32 *conn_sid)
+static int selinux_conn_sid(u32 sk_sid, u32 skb_sid,
+ struct selinux_state *state, u32 *conn_sid)
{
int err = 0;
if (skb_sid != SECSID_NULL)
- err = security_sid_mls_copy(current_selinux_state, sk_sid, skb_sid,
- conn_sid);
+ err = security_sid_mls_copy(state, sk_sid, skb_sid, conn_sid);
else
*conn_sid = sk_sid;
@@ -5092,7 +5111,8 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
break;
}
- err = sel_netnode_sid(addrp, family_sa, &sid);
+ err = sel_netnode_sid(current_selinux_state, addrp, family_sa,
+ &sid);
if (err)
goto out;
@@ -5342,7 +5362,8 @@ static int selinux_socket_unix_may_send(struct socket *sock,
&ad);
}
-static int selinux_inet_sys_rcv_skb(struct net *ns, int ifindex,
+static int selinux_inet_sys_rcv_skb(struct selinux_state *state,
+ struct net *ns, int ifindex,
char *addrp, u16 family, u32 peer_sid,
struct common_audit_data *ad)
{
@@ -5350,21 +5371,19 @@ static int selinux_inet_sys_rcv_skb(struct net *ns, int ifindex,
u32 if_sid;
u32 node_sid;
- err = sel_netif_sid(ns, ifindex, &if_sid);
+ err = sel_netif_sid(state, ns, ifindex, &if_sid);
if (err)
return err;
- err = avc_has_perm(current_selinux_state,
- peer_sid, if_sid,
+ err = avc_has_perm(state, peer_sid, if_sid,
SECCLASS_NETIF, NETIF__INGRESS, ad);
if (err)
return err;
- err = sel_netnode_sid(addrp, family, &node_sid);
+ err = sel_netnode_sid(state, addrp, family, &node_sid);
if (err)
return err;
- return avc_has_perm(current_selinux_state,
- peer_sid, node_sid,
- SECCLASS_NODE, NODE__RECVFROM, ad);
+ return avc_has_perm(state, peer_sid, node_sid, SECCLASS_NODE,
+ NODE__RECVFROM, ad);
}
static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
@@ -5373,6 +5392,7 @@ static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
int err = 0;
struct sk_security_struct *sksec = selinux_sock(sk);
u32 sk_sid = sksec->sid;
+ struct selinux_state *state = sksec->state;
struct common_audit_data ad;
struct lsm_network_audit net;
char *addrp;
@@ -5383,8 +5403,7 @@ static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
return err;
if (selinux_secmark_enabled()) {
- err = avc_has_perm(current_selinux_state,
- sk_sid, skb->secmark, SECCLASS_PACKET,
+ err = avc_has_perm(state, sk_sid, skb->secmark, SECCLASS_PACKET,
PACKET__RECV, &ad);
if (err)
return err;
@@ -5393,7 +5412,7 @@ static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
err = selinux_netlbl_sock_rcv_skb(sksec, skb, family, &ad);
if (err)
return err;
- err = selinux_xfrm_sock_rcv_skb(sksec->sid, skb, &ad);
+ err = selinux_xfrm_sock_rcv_skb(sksec, skb, &ad);
return err;
}
@@ -5404,6 +5423,7 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
struct sk_security_struct *sksec = selinux_sock(sk);
u16 family = sk->sk_family;
u32 sk_sid = sksec->sid;
+ struct selinux_state *state = sksec->state;
struct common_audit_data ad;
struct lsm_network_audit net;
char *addrp;
@@ -5435,17 +5455,16 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
if (peerlbl_active) {
u32 peer_sid;
- err = selinux_skb_peerlbl_sid(skb, family, &peer_sid);
+ err = selinux_skb_peerlbl_sid(skb, family, state, &peer_sid);
if (err)
return err;
- err = selinux_inet_sys_rcv_skb(sock_net(sk), skb->skb_iif,
+ err = selinux_inet_sys_rcv_skb(state, sock_net(sk), skb->skb_iif,
addrp, family, peer_sid, &ad);
if (err) {
selinux_netlbl_err(skb, family, err, 0);
return err;
}
- err = avc_has_perm(current_selinux_state,
- sk_sid, peer_sid, SECCLASS_PEER,
+ err = avc_has_perm(state, sk_sid, peer_sid, SECCLASS_PEER,
PEER__RECV, &ad);
if (err) {
selinux_netlbl_err(skb, family, err, 0);
@@ -5454,8 +5473,7 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
}
if (secmark_active) {
- err = avc_has_perm(current_selinux_state,
- sk_sid, skb->secmark, SECCLASS_PACKET,
+ err = avc_has_perm(state, sk_sid, skb->secmark, SECCLASS_PACKET,
PACKET__RECV, &ad);
if (err)
return err;
@@ -5521,7 +5539,8 @@ static int selinux_socket_getpeersec_dgram(struct socket *sock,
isec = inode_security_novalidate(SOCK_INODE(sock));
peer_secid = isec->sid;
} else if (skb)
- selinux_skb_peerlbl_sid(skb, family, &peer_secid);
+ selinux_skb_peerlbl_sid(skb, family, current_selinux_state,
+ &peer_secid);
*secid = peer_secid;
if (peer_secid == SECSID_NULL)
@@ -5536,6 +5555,7 @@ static int selinux_sk_alloc_security(struct sock *sk, int family, gfp_t priority
sksec->peer_sid = SECINITSID_UNLABELED;
sksec->sid = SECINITSID_UNLABELED;
sksec->sclass = SECCLASS_SOCKET;
+ sksec->state = get_selinux_state(current_selinux_state);
selinux_netlbl_sk_security_reset(sksec);
return 0;
@@ -5546,6 +5566,7 @@ static void selinux_sk_free_security(struct sock *sk)
struct sk_security_struct *sksec = selinux_sock(sk);
selinux_netlbl_sk_security_free(sksec);
+ put_selinux_state(sksec->state);
}
static void selinux_sk_clone_security(const struct sock *sk, struct sock *newsk)
@@ -5556,6 +5577,10 @@ static void selinux_sk_clone_security(const struct sock *sk, struct sock *newsk)
newsksec->sid = sksec->sid;
newsksec->peer_sid = sksec->peer_sid;
newsksec->sclass = sksec->sclass;
+ if (newsksec->state != sksec->state) {
+ put_selinux_state(newsksec->state);
+ newsksec->state = get_selinux_state(sksec->state);
+ }
selinux_netlbl_sk_security_reset(newsksec);
}
@@ -5593,6 +5618,7 @@ static int selinux_sctp_process_new_assoc(struct sctp_association *asoc,
struct sock *sk = asoc->base.sk;
u16 family = sk->sk_family;
struct sk_security_struct *sksec = selinux_sock(sk);
+ struct selinux_state *state = sksec->state;
struct common_audit_data ad;
struct lsm_network_audit net;
int err;
@@ -5607,7 +5633,8 @@ static int selinux_sctp_process_new_assoc(struct sctp_association *asoc,
/* This will return peer_sid = SECSID_NULL if there are
* no peer labels, see security_net_peersid_resolve().
*/
- err = selinux_skb_peerlbl_sid(skb, family, &asoc->peer_secid);
+ err = selinux_skb_peerlbl_sid(skb, family, state,
+ &asoc->peer_secid);
if (err)
return err;
@@ -5631,8 +5658,7 @@ static int selinux_sctp_process_new_assoc(struct sctp_association *asoc,
* consistency among the peer SIDs.
*/
ad_net_init_from_sk(&ad, &net, asoc->base.sk);
- err = avc_has_perm(current_selinux_state,
- sksec->peer_sid, asoc->peer_secid,
+ err = avc_has_perm(state, sksec->peer_sid, asoc->peer_secid,
sksec->sclass, SCTP_SOCKET__ASSOCIATION,
&ad);
if (err)
@@ -5649,6 +5675,7 @@ static int selinux_sctp_assoc_request(struct sctp_association *asoc,
struct sk_buff *skb)
{
struct sk_security_struct *sksec = selinux_sock(asoc->base.sk);
+ struct selinux_state *state = sksec->state;
u32 conn_sid;
int err;
@@ -5665,7 +5692,7 @@ static int selinux_sctp_assoc_request(struct sctp_association *asoc,
* socket to be generated. selinux_sctp_sk_clone() will then
* plug this into the new socket.
*/
- err = selinux_conn_sid(sksec->sid, asoc->peer_secid, &conn_sid);
+ err = selinux_conn_sid(sksec->sid, asoc->peer_secid, state, &conn_sid);
if (err)
return err;
@@ -5792,6 +5819,10 @@ static void selinux_sctp_sk_clone(struct sctp_association *asoc, struct sock *sk
newsksec->sid = asoc->secid;
newsksec->peer_sid = asoc->peer_secid;
newsksec->sclass = sksec->sclass;
+ if (newsksec->state != sksec->state) {
+ put_selinux_state(newsksec->state);
+ newsksec->state = get_selinux_state(sksec->state);
+ }
selinux_netlbl_sctp_sk_clone(sk, newsk);
}
@@ -5802,6 +5833,10 @@ static int selinux_mptcp_add_subflow(struct sock *sk, struct sock *ssk)
ssksec->sclass = sksec->sclass;
ssksec->sid = sksec->sid;
+ if (ssksec->state != sksec->state) {
+ put_selinux_state(ssksec->state);
+ ssksec->state = get_selinux_state(sksec->state);
+ }
/* replace the existing subflow label deleting the existing one
* and re-recreating a new label using the updated context
@@ -5814,21 +5849,22 @@ static int selinux_inet_conn_request(const struct sock *sk, struct sk_buff *skb,
struct request_sock *req)
{
struct sk_security_struct *sksec = selinux_sock(sk);
+ struct selinux_state *state = sksec->state;
int err;
u16 family = req->rsk_ops->family;
u32 connsid;
u32 peersid;
- err = selinux_skb_peerlbl_sid(skb, family, &peersid);
+ err = selinux_skb_peerlbl_sid(skb, family, state, &peersid);
if (err)
return err;
- err = selinux_conn_sid(sksec->sid, peersid, &connsid);
+ err = selinux_conn_sid(sksec->sid, peersid, state, &connsid);
if (err)
return err;
req->secid = connsid;
req->peer_secid = peersid;
- return selinux_netlbl_inet_conn_request(req, family);
+ return selinux_netlbl_inet_conn_request(req, family, state);
}
static void selinux_inet_csk_clone(struct sock *newsk,
@@ -5857,7 +5893,7 @@ static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb)
if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
family = PF_INET;
- selinux_skb_peerlbl_sid(skb, family, &sksec->peer_sid);
+ selinux_skb_peerlbl_sid(skb, family, sksec->state, &sksec->peer_sid);
}
static int selinux_secmark_relabel_packet(u32 sid)
@@ -5966,6 +6002,7 @@ static unsigned int selinux_ip_forward(void *priv, struct sk_buff *skb,
u32 peer_sid;
struct common_audit_data ad;
struct lsm_network_audit net;
+ struct selinux_state *se_state = init_selinux_state;
int secmark_active, peerlbl_active;
if (!selinux_policycap_netpeer())
@@ -5977,7 +6014,7 @@ static unsigned int selinux_ip_forward(void *priv, struct sk_buff *skb,
return NF_ACCEPT;
family = state->pf;
- if (selinux_skb_peerlbl_sid(skb, family, &peer_sid) != 0)
+ if (selinux_skb_peerlbl_sid(skb, family, se_state, &peer_sid) != 0)
return NF_DROP;
ifindex = state->in->ifindex;
@@ -5988,7 +6025,7 @@ static unsigned int selinux_ip_forward(void *priv, struct sk_buff *skb,
if (peerlbl_active) {
int err;
- err = selinux_inet_sys_rcv_skb(state->net, ifindex,
+ err = selinux_inet_sys_rcv_skb(se_state, state->net, ifindex,
addrp, family, peer_sid, &ad);
if (err) {
selinux_netlbl_err(skb, family, err, 1);
@@ -5997,8 +6034,7 @@ static unsigned int selinux_ip_forward(void *priv, struct sk_buff *skb,
}
if (secmark_active)
- if (avc_has_perm(current_selinux_state,
- peer_sid, skb->secmark,
+ if (avc_has_perm(se_state, peer_sid, skb->secmark,
SECCLASS_PACKET, PACKET__FORWARD_IN, &ad))
return NF_DROP;
@@ -6007,7 +6043,8 @@ static unsigned int selinux_ip_forward(void *priv, struct sk_buff *skb,
* path because we want to make sure we apply the necessary
* labeling before IPsec is applied so we can leverage AH
* protection */
- if (selinux_netlbl_skbuff_setsid(skb, family, peer_sid) != 0)
+ if (selinux_netlbl_skbuff_setsid(skb, family, se_state, peer_sid)
+ != 0)
return NF_DROP;
return NF_ACCEPT;
@@ -6016,6 +6053,7 @@ static unsigned int selinux_ip_forward(void *priv, struct sk_buff *skb,
static unsigned int selinux_ip_output(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state)
{
+ struct selinux_state *se_state;
struct sock *sk;
u32 sid;
@@ -6047,9 +6085,12 @@ static unsigned int selinux_ip_output(void *priv, struct sk_buff *skb,
/* standard practice, label using the parent socket */
sksec = selinux_sock(sk);
sid = sksec->sid;
- } else
+ se_state = sksec->state;
+ } else {
sid = SECINITSID_KERNEL;
- if (selinux_netlbl_skbuff_setsid(skb, state->pf, sid) != 0)
+ se_state = init_selinux_state;
+ }
+ if (selinux_netlbl_skbuff_setsid(skb, state->pf, se_state, sid) != 0)
return NF_DROP;
return NF_ACCEPT;
@@ -6075,12 +6116,12 @@ static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
return NF_DROP;
if (selinux_secmark_enabled())
- if (avc_has_perm(current_selinux_state,
- sksec->sid, skb->secmark,
+ if (avc_has_perm(sksec->state, sksec->sid, skb->secmark,
SECCLASS_PACKET, PACKET__SEND, &ad))
return NF_DROP_ERR(-ECONNREFUSED);
- if (selinux_xfrm_postroute_last(sksec->sid, skb, &ad, proto))
+ if (selinux_xfrm_postroute_last(sksec->sid, skb, sksec->state, &ad,
+ proto))
return NF_DROP_ERR(-ECONNREFUSED);
return NF_ACCEPT;
@@ -6098,6 +6139,7 @@ static unsigned int selinux_ip_postroute(void *priv,
struct common_audit_data ad;
struct lsm_network_audit net;
char *addrp;
+ struct selinux_state *se_state = init_selinux_state;
int secmark_active, peerlbl_active;
/* If any sort of compatibility mode is enabled then handoff processing
@@ -6139,7 +6181,8 @@ static unsigned int selinux_ip_postroute(void *priv,
* query the packet directly to determine the security label. */
if (skb->skb_iif) {
secmark_perm = PACKET__FORWARD_OUT;
- if (selinux_skb_peerlbl_sid(skb, family, &peer_sid))
+ if (selinux_skb_peerlbl_sid(skb, family, se_state,
+ &peer_sid))
return NF_DROP;
} else {
secmark_perm = PACKET__SEND;
@@ -6159,7 +6202,8 @@ static unsigned int selinux_ip_postroute(void *priv,
struct sk_security_struct *sksec;
sksec = selinux_sock(sk);
- if (selinux_skb_peerlbl_sid(skb, family, &skb_sid))
+ se_state = sksec->state;
+ if (selinux_skb_peerlbl_sid(skb, family, se_state, &skb_sid))
return NF_DROP;
/* At this point, if the returned skb peerlbl is SECSID_NULL
* and the packet has been through at least one XFRM
@@ -6181,7 +6225,7 @@ static unsigned int selinux_ip_postroute(void *priv,
return NF_DROP_ERR(-ECONNREFUSED);
}
}
- if (selinux_conn_sid(sksec->sid, skb_sid, &peer_sid))
+ if (selinux_conn_sid(sksec->sid, skb_sid, se_state, &peer_sid))
return NF_DROP;
secmark_perm = PACKET__SEND;
} else {
@@ -6190,6 +6234,7 @@ static unsigned int selinux_ip_postroute(void *priv,
struct sk_security_struct *sksec = selinux_sock(sk);
peer_sid = sksec->sid;
secmark_perm = PACKET__SEND;
+ se_state = sksec->state;
}
ifindex = state->out->ifindex;
@@ -6198,8 +6243,7 @@ static unsigned int selinux_ip_postroute(void *priv,
return NF_DROP;
if (secmark_active)
- if (avc_has_perm(current_selinux_state,
- peer_sid, skb->secmark,
+ if (avc_has_perm(se_state, peer_sid, skb->secmark,
SECCLASS_PACKET, secmark_perm, &ad))
return NF_DROP_ERR(-ECONNREFUSED);
@@ -6207,17 +6251,15 @@ static unsigned int selinux_ip_postroute(void *priv,
u32 if_sid;
u32 node_sid;
- if (sel_netif_sid(state->net, ifindex, &if_sid))
+ if (sel_netif_sid(se_state, state->net, ifindex, &if_sid))
return NF_DROP;
- if (avc_has_perm(current_selinux_state,
- peer_sid, if_sid,
+ if (avc_has_perm(se_state, peer_sid, if_sid,
SECCLASS_NETIF, NETIF__EGRESS, &ad))
return NF_DROP_ERR(-ECONNREFUSED);
- if (sel_netnode_sid(addrp, family, &node_sid))
+ if (sel_netnode_sid(se_state, addrp, family, &node_sid))
return NF_DROP;
- if (avc_has_perm(current_selinux_state,
- peer_sid, node_sid,
+ if (avc_has_perm(se_state, peer_sid, node_sid,
SECCLASS_NODE, NODE__SENDTO, &ad))
return NF_DROP_ERR(-ECONNREFUSED);
}
@@ -7573,6 +7615,7 @@ static struct security_hook_list selinux_hooks[] __ro_after_init = {
LSM_HOOK_INIT(file_permission, selinux_file_permission),
LSM_HOOK_INIT(file_alloc_security, selinux_file_alloc_security),
+ LSM_HOOK_INIT(file_free_security, selinux_file_free_security),
LSM_HOOK_INIT(file_ioctl, selinux_file_ioctl),
LSM_HOOK_INIT(file_ioctl_compat, selinux_file_ioctl_compat),
LSM_HOOK_INIT(mmap_file, selinux_mmap_file),
diff --git a/security/selinux/include/netif.h b/security/selinux/include/netif.h
index 2838bdc170dd..32de496bb948 100644
--- a/security/selinux/include/netif.h
+++ b/security/selinux/include/netif.h
@@ -19,6 +19,8 @@
void sel_netif_flush(void);
-int sel_netif_sid(struct net *ns, int ifindex, u32 *sid);
+struct selinux_state;
+int sel_netif_sid(struct selinux_state *state, struct net *ns, int ifindex,
+ u32 *sid);
#endif /* _SELINUX_NETIF_H_ */
diff --git a/security/selinux/include/netlabel.h b/security/selinux/include/netlabel.h
index 5731c0dcd3e8..b8ee75e9d155 100644
--- a/security/selinux/include/netlabel.h
+++ b/security/selinux/include/netlabel.h
@@ -32,12 +32,15 @@ void selinux_netlbl_err(struct sk_buff *skb, u16 family, int error,
void selinux_netlbl_sk_security_free(struct sk_security_struct *sksec);
void selinux_netlbl_sk_security_reset(struct sk_security_struct *sksec);
-int selinux_netlbl_skbuff_getsid(struct sk_buff *skb, u16 family, u32 *type,
+int selinux_netlbl_skbuff_getsid(struct sk_buff *skb, u16 family,
+ struct selinux_state *state, u32 *type,
u32 *sid);
-int selinux_netlbl_skbuff_setsid(struct sk_buff *skb, u16 family, u32 sid);
+int selinux_netlbl_skbuff_setsid(struct sk_buff *skb, u16 family,
+ struct selinux_state *state, u32 sid);
int selinux_netlbl_sctp_assoc_request(struct sctp_association *asoc,
struct sk_buff *skb);
-int selinux_netlbl_inet_conn_request(struct request_sock *req, u16 family);
+int selinux_netlbl_inet_conn_request(struct request_sock *req, u16 family,
+ struct selinux_state *state);
void selinux_netlbl_inet_csk_clone(struct sock *sk, u16 family);
void selinux_netlbl_sctp_sk_clone(struct sock *sk, struct sock *newsk);
int selinux_netlbl_socket_post_create(struct sock *sk, u16 family);
@@ -75,6 +78,7 @@ selinux_netlbl_sk_security_reset(struct sk_security_struct *sksec)
}
static inline int selinux_netlbl_skbuff_getsid(struct sk_buff *skb, u16 family,
+ struct selinux_state *state,
u32 *type, u32 *sid)
{
*type = NETLBL_NLTYPE_NONE;
@@ -82,6 +86,7 @@ static inline int selinux_netlbl_skbuff_getsid(struct sk_buff *skb, u16 family,
return 0;
}
static inline int selinux_netlbl_skbuff_setsid(struct sk_buff *skb, u16 family,
+ struct selinux_state *state,
u32 sid)
{
return 0;
@@ -94,7 +99,8 @@ selinux_netlbl_sctp_assoc_request(struct sctp_association *asoc,
return 0;
}
static inline int selinux_netlbl_inet_conn_request(struct request_sock *req,
- u16 family)
+ u16 family,
+ struct selinux_state *state)
{
return 0;
}
diff --git a/security/selinux/include/netnode.h b/security/selinux/include/netnode.h
index e4dc904c3585..029b9b1110c2 100644
--- a/security/selinux/include/netnode.h
+++ b/security/selinux/include/netnode.h
@@ -21,6 +21,8 @@
void sel_netnode_flush(void);
-int sel_netnode_sid(const void *addr, u16 family, u32 *sid);
+struct selinux_state;
+int sel_netnode_sid(struct selinux_state *state, const void *addr, u16 family,
+ u32 *sid);
#endif
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h
index cfac79df617b..662329923214 100644
--- a/security/selinux/include/objsec.h
+++ b/security/selinux/include/objsec.h
@@ -28,6 +28,7 @@
#include <net/net_namespace.h>
#include "flask.h"
#include "avc.h"
+#include "security.h"
static inline bool task_avdcache_permnoaudit(struct task_security_struct *tsec)
{
@@ -57,6 +58,7 @@ struct file_security_struct {
u32 fown_sid; /* SID of file owner (for SIGIO) */
u32 isid; /* SID of inode at the time of file open */
u32 pseqno; /* Policy seqno at the time of file open */
+ struct selinux_state *state; /* SELinux state */
};
struct superblock_security_struct {
@@ -83,6 +85,7 @@ struct netif_security_struct {
const struct net *ns; /* network namespace */
int ifindex; /* device index */
u32 sid; /* SID for this interface */
+ struct selinux_state *state; /* SELinux state */
};
struct netnode_security_struct {
@@ -92,6 +95,7 @@ struct netnode_security_struct {
} addr;
u32 sid; /* SID for this node */
u16 family; /* address family */
+ struct selinux_state *state; /* SELinux state */
};
struct netport_security_struct {
@@ -118,6 +122,7 @@ struct sk_security_struct {
SCTP_ASSOC_UNSET = 0,
SCTP_ASSOC_SET,
} sctp_assoc_state;
+ struct selinux_state *state; /* SELinux state */
};
struct tun_security_struct {
diff --git a/security/selinux/include/xfrm.h b/security/selinux/include/xfrm.h
index de485556ae29..36c390475752 100644
--- a/security/selinux/include/xfrm.h
+++ b/security/selinux/include/xfrm.h
@@ -38,9 +38,11 @@ static inline int selinux_xfrm_enabled(void)
return (atomic_read(&selinux_xfrm_refcount) > 0);
}
-int selinux_xfrm_sock_rcv_skb(u32 sk_sid, struct sk_buff *skb,
+int selinux_xfrm_sock_rcv_skb(struct sk_security_struct *sksec,
+ struct sk_buff *skb,
struct common_audit_data *ad);
int selinux_xfrm_postroute_last(u32 sk_sid, struct sk_buff *skb,
+ struct selinux_state *state,
struct common_audit_data *ad, u8 proto);
int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, int ckall);
int selinux_xfrm_skb_sid(struct sk_buff *skb, u32 *sid);
@@ -60,13 +62,15 @@ static inline int selinux_xfrm_enabled(void)
return 0;
}
-static inline int selinux_xfrm_sock_rcv_skb(u32 sk_sid, struct sk_buff *skb,
+static inline int selinux_xfrm_sock_rcv_skb(struct sk_security_struct *sksec,
+ struct sk_buff *skb,
struct common_audit_data *ad)
{
return 0;
}
static inline int selinux_xfrm_postroute_last(u32 sk_sid, struct sk_buff *skb,
+ struct selinux_state *state,
struct common_audit_data *ad,
u8 proto)
{
diff --git a/security/selinux/netif.c b/security/selinux/netif.c
index 6bd8c434a37a..ddb36c7d0ba6 100644
--- a/security/selinux/netif.c
+++ b/security/selinux/netif.c
@@ -56,6 +56,7 @@ static inline u32 sel_netif_hashfn(const struct net *ns, int ifindex)
/**
* sel_netif_find - Search for an interface record
+ * @state: the SELinux state
* @ns: the network namespace
* @ifindex: the network interface
*
@@ -64,7 +65,8 @@ static inline u32 sel_netif_hashfn(const struct net *ns, int ifindex)
* If an entry can not be found in the table return NULL.
*
*/
-static inline struct sel_netif *sel_netif_find(const struct net *ns,
+static inline struct sel_netif *sel_netif_find(struct selinux_state *state,
+ const struct net *ns,
int ifindex)
{
u32 idx = sel_netif_hashfn(ns, ifindex);
@@ -72,7 +74,8 @@ static inline struct sel_netif *sel_netif_find(const struct net *ns,
list_for_each_entry_rcu(netif, &sel_netif_hash[idx], list)
if (net_eq(netif->nsec.ns, ns) &&
- netif->nsec.ifindex == ifindex)
+ netif->nsec.ifindex == ifindex &&
+ (!state || netif->nsec.state == state))
return netif;
return NULL;
@@ -113,11 +116,13 @@ static void sel_netif_destroy(struct sel_netif *netif)
{
list_del_rcu(&netif->list);
sel_netif_total--;
+ put_selinux_state(netif->nsec.state);
kfree_rcu(netif, rcu_head);
}
/**
* sel_netif_sid_slow - Lookup the SID of a network interface using the policy
+ * @state: the SELinux state
* @ns: the network namespace
* @ifindex: the network interface
* @sid: interface SID
@@ -129,7 +134,8 @@ static void sel_netif_destroy(struct sel_netif *netif)
* failure.
*
*/
-static int sel_netif_sid_slow(struct net *ns, int ifindex, u32 *sid)
+static int sel_netif_sid_slow(struct selinux_state *state, struct net *ns,
+ int ifindex, u32 *sid)
{
int ret = 0;
struct sel_netif *netif;
@@ -147,13 +153,13 @@ static int sel_netif_sid_slow(struct net *ns, int ifindex, u32 *sid)
}
spin_lock_bh(&sel_netif_lock);
- netif = sel_netif_find(ns, ifindex);
+ netif = sel_netif_find(state, ns, ifindex);
if (netif != NULL) {
*sid = netif->nsec.sid;
goto out;
}
- ret = security_netif_sid(current_selinux_state, dev->name, sid);
+ ret = security_netif_sid(state, dev->name, sid);
if (ret != 0)
goto out;
@@ -165,8 +171,11 @@ static int sel_netif_sid_slow(struct net *ns, int ifindex, u32 *sid)
new->nsec.ns = ns;
new->nsec.ifindex = ifindex;
new->nsec.sid = *sid;
- if (sel_netif_insert(new))
+ new->nsec.state = get_selinux_state(state);
+ if (sel_netif_insert(new)) {
+ put_selinux_state(state);
kfree(new);
+ }
}
out:
@@ -180,6 +189,7 @@ static int sel_netif_sid_slow(struct net *ns, int ifindex, u32 *sid)
/**
* sel_netif_sid - Lookup the SID of a network interface
+ * @state: the SELinux state
* @ns: the network namespace
* @ifindex: the network interface
* @sid: interface SID
@@ -192,12 +202,13 @@ static int sel_netif_sid_slow(struct net *ns, int ifindex, u32 *sid)
* on failure.
*
*/
-int sel_netif_sid(struct net *ns, int ifindex, u32 *sid)
+int sel_netif_sid(struct selinux_state *state, struct net *ns, int ifindex,
+ u32 *sid)
{
struct sel_netif *netif;
rcu_read_lock();
- netif = sel_netif_find(ns, ifindex);
+ netif = sel_netif_find(state, ns, ifindex);
if (likely(netif != NULL)) {
*sid = netif->nsec.sid;
rcu_read_unlock();
@@ -205,7 +216,7 @@ int sel_netif_sid(struct net *ns, int ifindex, u32 *sid)
}
rcu_read_unlock();
- return sel_netif_sid_slow(ns, ifindex, sid);
+ return sel_netif_sid_slow(state, ns, ifindex, sid);
}
/**
@@ -224,7 +235,7 @@ static void sel_netif_kill(const struct net *ns, int ifindex)
rcu_read_lock();
spin_lock_bh(&sel_netif_lock);
- netif = sel_netif_find(ns, ifindex);
+ netif = sel_netif_find(NULL, ns, ifindex);
if (netif)
sel_netif_destroy(netif);
spin_unlock_bh(&sel_netif_lock);
diff --git a/security/selinux/netlabel.c b/security/selinux/netlabel.c
index e35c224145a4..9c360f2ee7fc 100644
--- a/security/selinux/netlabel.c
+++ b/security/selinux/netlabel.c
@@ -32,6 +32,7 @@
* @skb: the packet
* @family: the packet's address family
* @secattr: the NetLabel security attributes
+ * @state: the SELinux state
* @sid: the SID
*
* Description:
@@ -43,11 +44,12 @@
static int selinux_netlbl_sidlookup_cached(struct sk_buff *skb,
u16 family,
struct netlbl_lsm_secattr *secattr,
+ struct selinux_state *state,
u32 *sid)
{
int rc;
- rc = security_netlbl_secattr_to_sid(current_selinux_state, secattr, sid);
+ rc = security_netlbl_secattr_to_sid(state, secattr, sid);
if (rc == 0 &&
(secattr->flags & NETLBL_SECATTR_CACHEABLE) &&
(secattr->flags & NETLBL_SECATTR_CACHE))
@@ -79,8 +81,7 @@ static struct netlbl_lsm_secattr *selinux_netlbl_sock_genattr(struct sock *sk)
if (secattr == NULL)
return ERR_PTR(-ENOMEM);
- rc = security_netlbl_sid_to_secattr(current_selinux_state, sksec->sid,
- secattr);
+ rc = security_netlbl_sid_to_secattr(sksec->state, sksec->sid, secattr);
if (rc != 0) {
netlbl_secattr_free(secattr);
return ERR_PTR(rc);
@@ -183,6 +184,7 @@ void selinux_netlbl_sk_security_reset(struct sk_security_struct *sksec)
* selinux_netlbl_skbuff_getsid - Get the sid of a packet using NetLabel
* @skb: the packet
* @family: protocol family
+ * @state: the SELinux state
* @type: NetLabel labeling protocol type
* @sid: the SID
*
@@ -194,6 +196,7 @@ void selinux_netlbl_sk_security_reset(struct sk_security_struct *sksec)
*/
int selinux_netlbl_skbuff_getsid(struct sk_buff *skb,
u16 family,
+ struct selinux_state *state,
u32 *type,
u32 *sid)
{
@@ -210,7 +213,7 @@ int selinux_netlbl_skbuff_getsid(struct sk_buff *skb,
rc = netlbl_skbuff_getattr(skb, family, &secattr);
if (rc == 0 && secattr.flags != NETLBL_SECATTR_NONE)
rc = selinux_netlbl_sidlookup_cached(skb, family,
- &secattr, sid);
+ &secattr, state, sid);
else
*sid = SECSID_NULL;
*type = secattr.type;
@@ -223,6 +226,7 @@ int selinux_netlbl_skbuff_getsid(struct sk_buff *skb,
* selinux_netlbl_skbuff_setsid - Set the NetLabel on a packet given a sid
* @skb: the packet
* @family: protocol family
+ * @state: the SELinux state
* @sid: the SID
*
* Description
@@ -232,6 +236,7 @@ int selinux_netlbl_skbuff_getsid(struct sk_buff *skb,
*/
int selinux_netlbl_skbuff_setsid(struct sk_buff *skb,
u16 family,
+ struct selinux_state *state,
u32 sid)
{
int rc;
@@ -252,8 +257,7 @@ int selinux_netlbl_skbuff_setsid(struct sk_buff *skb,
if (secattr == NULL) {
secattr = &secattr_storage;
netlbl_secattr_init(secattr);
- rc = security_netlbl_sid_to_secattr(current_selinux_state, sid,
- secattr);
+ rc = security_netlbl_sid_to_secattr(state, sid, secattr);
if (rc != 0)
goto skbuff_setsid_return;
}
@@ -290,8 +294,8 @@ int selinux_netlbl_sctp_assoc_request(struct sctp_association *asoc,
return 0;
netlbl_secattr_init(&secattr);
- rc = security_netlbl_sid_to_secattr(current_selinux_state,
- asoc->secid, &secattr);
+ rc = security_netlbl_sid_to_secattr(sksec->state, asoc->secid,
+ &secattr);
if (rc != 0)
goto assoc_request_return;
@@ -322,6 +326,7 @@ int selinux_netlbl_sctp_assoc_request(struct sctp_association *asoc,
* selinux_netlbl_inet_conn_request - Label an incoming stream connection
* @req: incoming connection request socket
* @family: the request socket's address family
+ * @state: the SELinux state
*
* Description:
* A new incoming connection request is represented by @req, we need to label
@@ -330,7 +335,8 @@ int selinux_netlbl_sctp_assoc_request(struct sctp_association *asoc,
* is complete. Returns zero on success, negative values on failure.
*
*/
-int selinux_netlbl_inet_conn_request(struct request_sock *req, u16 family)
+int selinux_netlbl_inet_conn_request(struct request_sock *req, u16 family,
+ struct selinux_state *state)
{
int rc;
struct netlbl_lsm_secattr secattr;
@@ -339,8 +345,7 @@ int selinux_netlbl_inet_conn_request(struct request_sock *req, u16 family)
return 0;
netlbl_secattr_init(&secattr);
- rc = security_netlbl_sid_to_secattr(current_selinux_state, req->secid,
- &secattr);
+ rc = security_netlbl_sid_to_secattr(state, req->secid, &secattr);
if (rc != 0)
goto inet_conn_request_return;
rc = netlbl_req_setattr(req, &secattr);
@@ -454,8 +459,8 @@ int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
netlbl_secattr_init(&secattr);
rc = netlbl_skbuff_getattr(skb, family, &secattr);
if (rc == 0 && secattr.flags != NETLBL_SECATTR_NONE)
- rc = selinux_netlbl_sidlookup_cached(skb, family,
- &secattr, &nlbl_sid);
+ rc = selinux_netlbl_sidlookup_cached(skb, family, &secattr,
+ sksec->state, &nlbl_sid);
else
nlbl_sid = SECINITSID_UNLABELED;
netlbl_secattr_destroy(&secattr);
@@ -473,8 +478,8 @@ int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
perm = RAWIP_SOCKET__RECVFROM;
}
- rc = avc_has_perm(current_selinux_state,
- sksec->sid, nlbl_sid, sksec->sclass, perm, ad);
+ rc = avc_has_perm(sksec->state, sksec->sid, nlbl_sid, sksec->sclass,
+ perm, ad);
if (rc == 0)
return 0;
diff --git a/security/selinux/netnode.c b/security/selinux/netnode.c
index 502aefcf2d77..dc6f09c73f9c 100644
--- a/security/selinux/netnode.c
+++ b/security/selinux/netnode.c
@@ -92,6 +92,7 @@ static unsigned int sel_netnode_hashfn_ipv6(const struct in6_addr *addr)
/**
* sel_netnode_find - Search for a node record
+ * @state: SELinux state
* @addr: IP address
* @family: address family
*
@@ -100,7 +101,8 @@ static unsigned int sel_netnode_hashfn_ipv6(const struct in6_addr *addr)
* entry can not be found in the table return NULL.
*
*/
-static struct sel_netnode *sel_netnode_find(const void *addr, u16 family)
+static struct sel_netnode *sel_netnode_find(struct selinux_state *state,
+ const void *addr, u16 family)
{
unsigned int idx;
struct sel_netnode *node;
@@ -118,7 +120,7 @@ static struct sel_netnode *sel_netnode_find(const void *addr, u16 family)
}
list_for_each_entry_rcu(node, &sel_netnode_hash[idx].list, list)
- if (node->nsec.family == family)
+ if (node->nsec.family == family && node->nsec.state == state)
switch (family) {
case PF_INET:
if (node->nsec.addr.ipv4 == *(const __be32 *)addr)
@@ -176,6 +178,7 @@ static void sel_netnode_insert(struct sel_netnode *node)
/**
* sel_netnode_sid_slow - Lookup the SID of a network address using the policy
+ * @state: the SELinux state
* @addr: the IP address
* @family: the address family
* @sid: node SID
@@ -187,14 +190,15 @@ static void sel_netnode_insert(struct sel_netnode *node)
* failure.
*
*/
-static int sel_netnode_sid_slow(const void *addr, u16 family, u32 *sid)
+static int sel_netnode_sid_slow(struct selinux_state *state, const void *addr,
+ u16 family, u32 *sid)
{
int ret;
struct sel_netnode *node;
struct sel_netnode *new;
spin_lock_bh(&sel_netnode_lock);
- node = sel_netnode_find(addr, family);
+ node = sel_netnode_find(state, addr, family);
if (node != NULL) {
*sid = node->nsec.sid;
spin_unlock_bh(&sel_netnode_lock);
@@ -207,13 +211,13 @@ static int sel_netnode_sid_slow(const void *addr, u16 family, u32 *sid)
new = kmalloc(sizeof(*new), GFP_ATOMIC);
switch (family) {
case PF_INET:
- ret = security_node_sid(current_selinux_state, PF_INET,
+ ret = security_node_sid(state, PF_INET,
addr, sizeof(struct in_addr), sid);
if (new)
new->nsec.addr.ipv4 = *(const __be32 *)addr;
break;
case PF_INET6:
- ret = security_node_sid(current_selinux_state, PF_INET6,
+ ret = security_node_sid(state, PF_INET6,
addr, sizeof(struct in6_addr), sid);
if (new)
new->nsec.addr.ipv6 = *(const struct in6_addr *)addr;
@@ -225,6 +229,7 @@ static int sel_netnode_sid_slow(const void *addr, u16 family, u32 *sid)
if (ret == 0 && new) {
new->nsec.family = family;
new->nsec.sid = *sid;
+ new->nsec.state = get_selinux_state(state);
sel_netnode_insert(new);
} else
kfree(new);
@@ -238,6 +243,7 @@ static int sel_netnode_sid_slow(const void *addr, u16 family, u32 *sid)
/**
* sel_netnode_sid - Lookup the SID of a network address
+ * @state: the SELinux state
* @addr: the IP address
* @family: the address family
* @sid: node SID
@@ -250,12 +256,13 @@ static int sel_netnode_sid_slow(const void *addr, u16 family, u32 *sid)
* on failure.
*
*/
-int sel_netnode_sid(const void *addr, u16 family, u32 *sid)
+int sel_netnode_sid(struct selinux_state *state, const void *addr, u16 family,
+ u32 *sid)
{
struct sel_netnode *node;
rcu_read_lock();
- node = sel_netnode_find(addr, family);
+ node = sel_netnode_find(state, addr, family);
if (likely(node != NULL)) {
*sid = node->nsec.sid;
rcu_read_unlock();
@@ -263,7 +270,7 @@ int sel_netnode_sid(const void *addr, u16 family, u32 *sid)
}
rcu_read_unlock();
- return sel_netnode_sid_slow(addr, family, sid);
+ return sel_netnode_sid_slow(state, addr, family, sid);
}
/**
@@ -283,6 +290,7 @@ void sel_netnode_flush(void)
list_for_each_entry_safe(node, node_tmp,
&sel_netnode_hash[idx].list, list) {
list_del_rcu(&node->list);
+ put_selinux_state(node->nsec.state);
kfree_rcu(node, rcu);
}
sel_netnode_hash[idx].size = 0;
diff --git a/security/selinux/xfrm.c b/security/selinux/xfrm.c
index 4ad8b610eb77..411e1f1ba4cd 100644
--- a/security/selinux/xfrm.c
+++ b/security/selinux/xfrm.c
@@ -149,6 +149,8 @@ static int selinux_xfrm_delete(struct xfrm_sec_ctx *ctx)
*/
int selinux_xfrm_policy_lookup(struct xfrm_sec_ctx *ctx, u32 fl_secid)
{
+ /* TODO: obtain SELinux state from related sock */
+ struct selinux_state *state = init_selinux_state;
int rc;
/* All flows should be treated as polmatch'ing an otherwise applicable
@@ -160,8 +162,7 @@ int selinux_xfrm_policy_lookup(struct xfrm_sec_ctx *ctx, u32 fl_secid)
if (!selinux_authorizable_ctx(ctx))
return -EINVAL;
- rc = avc_has_perm(current_selinux_state,
- fl_secid, ctx->ctx_sid,
+ rc = avc_has_perm(state, fl_secid, ctx->ctx_sid,
SECCLASS_ASSOCIATION, ASSOCIATION__POLMATCH, NULL);
return (rc == -EACCES ? -ESRCH : rc);
}
@@ -174,6 +175,8 @@ int selinux_xfrm_state_pol_flow_match(struct xfrm_state *x,
struct xfrm_policy *xp,
const struct flowi_common *flic)
{
+ /* TODO: obtain SELinux state from related sock */
+ struct selinux_state *state = init_selinux_state;
u32 state_sid;
u32 flic_sid;
@@ -202,9 +205,8 @@ int selinux_xfrm_state_pol_flow_match(struct xfrm_state *x,
/* We don't need a separate SA Vs. policy polmatch check since the SA
* is now of the same label as the flow and a flow Vs. policy polmatch
* check had already happened in selinux_xfrm_policy_lookup() above. */
- return (avc_has_perm(current_selinux_state, flic_sid, state_sid,
- SECCLASS_ASSOCIATION, ASSOCIATION__SENDTO,
- NULL) ? 0 : 1);
+ return (avc_has_perm(state, flic_sid, state_sid, SECCLASS_ASSOCIATION,
+ ASSOCIATION__SENDTO, NULL) ? 0 : 1);
}
static u32 selinux_xfrm_skb_sid_egress(struct sk_buff *skb)
@@ -341,6 +343,8 @@ int selinux_xfrm_state_alloc(struct xfrm_state *x,
int selinux_xfrm_state_alloc_acquire(struct xfrm_state *x,
struct xfrm_sec_ctx *polsec, u32 secid)
{
+ /* TODO: Obtain SELinux state from related sock */
+ struct selinux_state *state = init_selinux_state;
int rc;
struct xfrm_sec_ctx *ctx;
char *ctx_str = NULL;
@@ -352,8 +356,7 @@ int selinux_xfrm_state_alloc_acquire(struct xfrm_state *x,
if (secid == 0)
return -EINVAL;
- rc = security_sid_to_context(current_selinux_state, secid, &ctx_str,
- &str_len);
+ rc = security_sid_to_context(state, secid, &ctx_str, &str_len);
if (rc)
return rc;
@@ -399,10 +402,11 @@ int selinux_xfrm_state_delete(struct xfrm_state *x)
* we need to check for unlabelled access since this may not have
* gone thru the IPSec process.
*/
-int selinux_xfrm_sock_rcv_skb(u32 sk_sid, struct sk_buff *skb,
+int selinux_xfrm_sock_rcv_skb(struct sk_security_struct *sksec, struct sk_buff *skb,
struct common_audit_data *ad)
{
int i;
+ u32 sk_sid = sksec->sid;
struct sec_path *sp = skb_sec_path(skb);
u32 peer_sid = SECINITSID_UNLABELED;
@@ -421,8 +425,7 @@ int selinux_xfrm_sock_rcv_skb(u32 sk_sid, struct sk_buff *skb,
/* This check even when there's no association involved is intended,
* according to Trent Jaeger, to make sure a process can't engage in
* non-IPsec communication unless explicitly allowed by policy. */
- return avc_has_perm(current_selinux_state,
- sk_sid, peer_sid,
+ return avc_has_perm(sksec->state, sk_sid, peer_sid,
SECCLASS_ASSOCIATION, ASSOCIATION__RECVFROM, ad);
}
@@ -434,6 +437,7 @@ int selinux_xfrm_sock_rcv_skb(u32 sk_sid, struct sk_buff *skb,
* checked in the selinux_xfrm_state_pol_flow_match hook above.
*/
int selinux_xfrm_postroute_last(u32 sk_sid, struct sk_buff *skb,
+ struct selinux_state *state,
struct common_audit_data *ad, u8 proto)
{
struct dst_entry *dst;
@@ -465,6 +469,6 @@ int selinux_xfrm_postroute_last(u32 sk_sid, struct sk_buff *skb,
/* This check even when there's no association involved is intended,
* according to Trent Jaeger, to make sure a process can't engage in
* non-IPsec communication unless explicitly allowed by policy. */
- return avc_has_perm(current_selinux_state, sk_sid, SECINITSID_UNLABELED,
+ return avc_has_perm(state, sk_sid, SECINITSID_UNLABELED,
SECCLASS_ASSOCIATION, ASSOCIATION__SENDTO, ad);
}
--
2.50.1
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [PATCH v7 22/42] selinux: introduce cred_task_has_perm()
2025-08-14 13:25 [PATCH v7 00/42] SELinux namespace support Stephen Smalley
` (20 preceding siblings ...)
2025-08-14 13:26 ` [PATCH v7 21/42] selinux: update hook functions to use correct selinux namespace Stephen Smalley
@ 2025-08-14 13:26 ` Stephen Smalley
2025-08-14 13:26 ` [PATCH v7 23/42] selinux: introduce cred_has_extended_perms() Stephen Smalley
` (19 subsequent siblings)
41 siblings, 0 replies; 43+ messages in thread
From: Stephen Smalley @ 2025-08-14 13:26 UTC (permalink / raw)
To: selinux; +Cc: paul, omosnace, netdev, horms, Stephen Smalley
Introduce cred_task_has_perm() for checking permissions between a cred
and a target task against not only the current SELinux namespace but all
ancestor namespaces too.
Convert existing cred-task permission checks in the SELinux hook
functions to use cred_task_has_perm() instead of calling avc_has_perm().
Signed-off-by: Stephen Smalley <stephen.smalley.work@gmail.com>
---
security/selinux/avc.c | 44 +++++++++++++++++
security/selinux/hooks.c | 89 +++++++++++++---------------------
security/selinux/include/avc.h | 4 ++
3 files changed, 81 insertions(+), 56 deletions(-)
diff --git a/security/selinux/avc.c b/security/selinux/avc.c
index 056e597912ec..44caaead16aa 100644
--- a/security/selinux/avc.c
+++ b/security/selinux/avc.c
@@ -1246,6 +1246,50 @@ int avc_has_perm(struct selinux_state *state, u32 ssid, u32 tsid, u16 tclass,
return rc;
}
+static u32 task_sid_obj_for_state(const struct task_struct *p,
+ const struct selinux_state *state)
+{
+ const struct task_security_struct *tsec;
+ u32 sid;
+
+ rcu_read_lock();
+ tsec = selinux_cred(__task_cred(p));
+ while (tsec->state != state && tsec->parent_cred)
+ tsec = selinux_cred(tsec->parent_cred);
+ if (tsec->state == state)
+ sid = tsec->sid;
+ else
+ sid = SECINITSID_UNLABELED;
+ rcu_read_unlock();
+ return sid;
+}
+
+int cred_task_has_perm(const struct cred *cred, const struct task_struct *p,
+ u16 tclass, u32 requested,
+ struct common_audit_data *ad)
+{
+ struct task_security_struct *tsec;
+ struct selinux_state *state;
+ u32 ssid;
+ u32 tsid;
+ int rc;
+
+ do {
+ tsec = selinux_cred(cred);
+ ssid = tsec->sid;
+ state = tsec->state;
+ tsid = task_sid_obj_for_state(p, state);
+
+ rc = avc_has_perm(state, ssid, tsid, tclass, requested, ad);
+ if (rc)
+ return rc;
+
+ cred = tsec->parent_cred;
+ } while (cred);
+
+ return 0;
+}
+
u32 avc_policy_seqno(struct selinux_state *state)
{
return state->avc->avc_cache.latest_notif;
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 99a83acfa19e..d21b3d03cced 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2154,15 +2154,12 @@ static int selinux_binder_transfer_file(const struct cred *from,
static int selinux_ptrace_access_check(struct task_struct *child,
unsigned int mode)
{
- u32 sid = current_sid();
- u32 csid = task_sid_obj(child);
-
if (mode & PTRACE_MODE_READ)
- return avc_has_perm(current_selinux_state,
- sid, csid, SECCLASS_FILE, FILE__READ, NULL);
+ return cred_task_has_perm(current_cred(), child,
+ SECCLASS_FILE, FILE__READ, NULL);
- return avc_has_perm(current_selinux_state,
- sid, csid, SECCLASS_PROCESS, PROCESS__PTRACE, NULL);
+ return cred_task_has_perm(current_cred(), child, SECCLASS_PROCESS,
+ PROCESS__PTRACE, NULL);
}
static int selinux_ptrace_traceme(struct task_struct *parent)
@@ -2175,9 +2172,8 @@ static int selinux_ptrace_traceme(struct task_struct *parent)
static int selinux_capget(const struct task_struct *target, kernel_cap_t *effective,
kernel_cap_t *inheritable, kernel_cap_t *permitted)
{
- return avc_has_perm(current_selinux_state,
- current_sid(), task_sid_obj(target), SECCLASS_PROCESS,
- PROCESS__GETCAP, NULL);
+ return cred_task_has_perm(current_cred(), target, SECCLASS_PROCESS,
+ PROCESS__GETCAP, NULL);
}
static int selinux_capset(struct cred *new, const struct cred *old,
@@ -4460,23 +4456,20 @@ static int selinux_kernel_load_data(enum kernel_load_data_id id, bool contents)
static int selinux_task_setpgid(struct task_struct *p, pid_t pgid)
{
- return avc_has_perm(current_selinux_state,
- current_sid(), task_sid_obj(p), SECCLASS_PROCESS,
- PROCESS__SETPGID, NULL);
+ return cred_task_has_perm(current_cred(), p, SECCLASS_PROCESS,
+ PROCESS__SETPGID, NULL);
}
static int selinux_task_getpgid(struct task_struct *p)
{
- return avc_has_perm(current_selinux_state,
- current_sid(), task_sid_obj(p), SECCLASS_PROCESS,
- PROCESS__GETPGID, NULL);
+ return cred_task_has_perm(current_cred(), p, SECCLASS_PROCESS,
+ PROCESS__GETPGID, NULL);
}
static int selinux_task_getsid(struct task_struct *p)
{
- return avc_has_perm(current_selinux_state,
- current_sid(), task_sid_obj(p), SECCLASS_PROCESS,
- PROCESS__GETSESSION, NULL);
+ return cred_task_has_perm(current_cred(), p, SECCLASS_PROCESS,
+ PROCESS__GETSESSION, NULL);
}
static void selinux_current_getlsmprop_subj(struct lsm_prop *prop)
@@ -4492,23 +4485,20 @@ static void selinux_task_getlsmprop_obj(struct task_struct *p,
static int selinux_task_setnice(struct task_struct *p, int nice)
{
- return avc_has_perm(current_selinux_state,
- current_sid(), task_sid_obj(p), SECCLASS_PROCESS,
- PROCESS__SETSCHED, NULL);
+ return cred_task_has_perm(current_cred(), p, SECCLASS_PROCESS,
+ PROCESS__SETSCHED, NULL);
}
static int selinux_task_setioprio(struct task_struct *p, int ioprio)
{
- return avc_has_perm(current_selinux_state,
- current_sid(), task_sid_obj(p), SECCLASS_PROCESS,
- PROCESS__SETSCHED, NULL);
+ return cred_task_has_perm(current_cred(), p, SECCLASS_PROCESS,
+ PROCESS__SETSCHED, NULL);
}
static int selinux_task_getioprio(struct task_struct *p)
{
- return avc_has_perm(current_selinux_state,
- current_sid(), task_sid_obj(p), SECCLASS_PROCESS,
- PROCESS__GETSCHED, NULL);
+ return cred_task_has_perm(current_cred(), p, SECCLASS_PROCESS,
+ PROCESS__GETSCHED, NULL);
}
static int selinux_task_prlimit(const struct cred *cred, const struct cred *tcred,
@@ -4537,56 +4527,43 @@ static int selinux_task_setrlimit(struct task_struct *p, unsigned int resource,
later be used as a safe reset point for the soft limit
upon context transitions. See selinux_bprm_committing_creds. */
if (old_rlim->rlim_max != new_rlim->rlim_max)
- return avc_has_perm(current_selinux_state,
- current_sid(), task_sid_obj(p),
- SECCLASS_PROCESS, PROCESS__SETRLIMIT, NULL);
+ return cred_task_has_perm(current_cred(), p, SECCLASS_PROCESS,
+ PROCESS__SETRLIMIT, NULL);
return 0;
}
static int selinux_task_setscheduler(struct task_struct *p)
{
- return avc_has_perm(current_selinux_state,
- current_sid(), task_sid_obj(p), SECCLASS_PROCESS,
- PROCESS__SETSCHED, NULL);
+ return cred_task_has_perm(current_cred(), p, SECCLASS_PROCESS,
+ PROCESS__SETSCHED, NULL);
}
static int selinux_task_getscheduler(struct task_struct *p)
{
- return avc_has_perm(current_selinux_state,
- current_sid(), task_sid_obj(p), SECCLASS_PROCESS,
- PROCESS__GETSCHED, NULL);
+ return cred_task_has_perm(current_cred(), p, SECCLASS_PROCESS,
+ PROCESS__GETSCHED, NULL);
}
static int selinux_task_movememory(struct task_struct *p)
{
- return avc_has_perm(current_selinux_state,
- current_sid(), task_sid_obj(p), SECCLASS_PROCESS,
- PROCESS__SETSCHED, NULL);
+ return cred_task_has_perm(current_cred(), p, SECCLASS_PROCESS,
+ PROCESS__SETSCHED, NULL);
}
static int selinux_task_kill(struct task_struct *p, struct kernel_siginfo *info,
int sig, const struct cred *cred)
{
- struct selinux_state *state;
- u32 secid;
u32 perm;
- if (cred)
- state = cred_selinux_state(cred);
- else
- state = current_selinux_state;
+ if (!cred)
+ cred = current_cred();
if (!sig)
perm = PROCESS__SIGNULL; /* null signal; existence test */
else
perm = signal_to_av(sig);
- if (!cred)
- secid = current_sid();
- else
- secid = cred_sid(cred);
- return avc_has_perm(state, secid, task_sid_obj(p),
- SECCLASS_PROCESS, perm, NULL);
+ return cred_task_has_perm(cred, p, SECCLASS_PROCESS, perm, NULL);
}
static void selinux_task_to_inode(struct task_struct *p,
@@ -6730,14 +6707,14 @@ static int selinux_lsm_getattr(unsigned int attr, struct task_struct *p,
u32 len;
rcu_read_lock();
- tsec = task_security(p);
if (p != current) {
- error = avc_has_perm(current_selinux_state,
- current_sid(), tsec->sid,
- SECCLASS_PROCESS, PROCESS__GETATTR, NULL);
+ error = cred_task_has_perm(current_cred(), p,
+ SECCLASS_PROCESS,
+ PROCESS__GETATTR, NULL);
if (error)
goto err_unlock;
}
+ tsec = task_security(p);
switch (attr) {
case LSM_ATTR_CURRENT:
sid = tsec->sid;
diff --git a/security/selinux/include/avc.h b/security/selinux/include/avc.h
index f6a500e9d74d..5d79bb7c610c 100644
--- a/security/selinux/include/avc.h
+++ b/security/selinux/include/avc.h
@@ -150,6 +150,10 @@ int avc_has_extended_perms(struct selinux_state *state, u32 ssid, u32 tsid,
u16 tclass, u32 requested, u8 driver, u8 base_perm,
u8 perm, struct common_audit_data *ad);
+int cred_task_has_perm(const struct cred *cred, const struct task_struct *p,
+ u16 tclass, u32 requested,
+ struct common_audit_data *auditdata);
+
u32 avc_policy_seqno(struct selinux_state *state);
#define AVC_CALLBACK_GRANT 1
--
2.50.1
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [PATCH v7 23/42] selinux: introduce cred_has_extended_perms()
2025-08-14 13:25 [PATCH v7 00/42] SELinux namespace support Stephen Smalley
` (21 preceding siblings ...)
2025-08-14 13:26 ` [PATCH v7 22/42] selinux: introduce cred_task_has_perm() Stephen Smalley
@ 2025-08-14 13:26 ` Stephen Smalley
2025-08-14 13:26 ` [PATCH v7 24/42] selinux: introduce cred_self_has_perm() Stephen Smalley
` (18 subsequent siblings)
41 siblings, 0 replies; 43+ messages in thread
From: Stephen Smalley @ 2025-08-14 13:26 UTC (permalink / raw)
To: selinux; +Cc: paul, omosnace, netdev, horms, Stephen Smalley
Introduce cred_has_extended_perms() to check extended permissions
against the current SELinux namespace and all ancestor namespaces.
Update the caller of avc_has_extended_perms() to use this function
instead.
Signed-off-by: Stephen Smalley <stephen.smalley.work@gmail.com>
---
security/selinux/avc.c | 26 ++++++++++++++++++++++++++
security/selinux/hooks.c | 7 +++----
security/selinux/include/avc.h | 4 ++++
3 files changed, 33 insertions(+), 4 deletions(-)
diff --git a/security/selinux/avc.c b/security/selinux/avc.c
index 44caaead16aa..03760f7e7cac 100644
--- a/security/selinux/avc.c
+++ b/security/selinux/avc.c
@@ -1290,6 +1290,32 @@ int cred_task_has_perm(const struct cred *cred, const struct task_struct *p,
return 0;
}
+int cred_has_extended_perms(const struct cred *cred, u32 tsid, u16 tclass,
+ u32 requested, u8 driver, u8 base_perm, u8 xperm,
+ struct common_audit_data *ad)
+{
+ struct task_security_struct *tsec;
+ struct selinux_state *state;
+ u32 ssid;
+ int rc;
+
+ do {
+ tsec = selinux_cred(cred);
+ ssid = tsec->sid;
+ state = tsec->state;
+
+ rc = avc_has_extended_perms(state, ssid, tsid, tclass,
+ requested, driver, base_perm,
+ xperm, ad);
+ if (rc)
+ return rc;
+
+ cred = tsec->parent_cred;
+ } while (cred);
+
+ return 0;
+}
+
u32 avc_policy_seqno(struct selinux_state *state)
{
return state->avc->avc_cache.latest_notif;
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index d21b3d03cced..f22acce323b8 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -3913,10 +3913,9 @@ static int ioctl_has_perm(const struct cred *cred, struct file *file,
return 0;
isec = inode_security(inode);
- rc = avc_has_extended_perms(cred_selinux_state(cred),
- ssid, isec->sid, isec->sclass,
- requested, driver, AVC_EXT_IOCTL, xperm,
- &ad);
+ rc = cred_has_extended_perms(cred, isec->sid, isec->sclass,
+ requested, driver, AVC_EXT_IOCTL,
+ xperm, &ad);
out:
return rc;
}
diff --git a/security/selinux/include/avc.h b/security/selinux/include/avc.h
index 5d79bb7c610c..adbbecc681f2 100644
--- a/security/selinux/include/avc.h
+++ b/security/selinux/include/avc.h
@@ -154,6 +154,10 @@ int cred_task_has_perm(const struct cred *cred, const struct task_struct *p,
u16 tclass, u32 requested,
struct common_audit_data *auditdata);
+int cred_has_extended_perms(const struct cred *cred, u32 tsid, u16 tclass,
+ u32 requested, u8 driver, u8 base_perm, u8 xperm,
+ struct common_audit_data *ad);
+
u32 avc_policy_seqno(struct selinux_state *state);
#define AVC_CALLBACK_GRANT 1
--
2.50.1
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [PATCH v7 24/42] selinux: introduce cred_self_has_perm()
2025-08-14 13:25 [PATCH v7 00/42] SELinux namespace support Stephen Smalley
` (22 preceding siblings ...)
2025-08-14 13:26 ` [PATCH v7 23/42] selinux: introduce cred_has_extended_perms() Stephen Smalley
@ 2025-08-14 13:26 ` Stephen Smalley
2025-08-14 13:26 ` [PATCH v7 25/42] selinux: introduce cred_has_perm() Stephen Smalley
` (17 subsequent siblings)
41 siblings, 0 replies; 43+ messages in thread
From: Stephen Smalley @ 2025-08-14 13:26 UTC (permalink / raw)
To: selinux; +Cc: paul, omosnace, netdev, horms, Stephen Smalley
Introduce a cred_self_has_perm() function for checking permissions
between a cred and itself against the current SELinux namespace
and all ancestors. Also provide a cred_self_has_perm_noaudit() variant
for use where auditing is not desired.
Update existing permission checks in the hook functions to use this
new helper.
Signed-off-by: Stephen Smalley <stephen.smalley.work@gmail.com>
---
security/selinux/avc.c | 47 +++++++++++++++++
security/selinux/hooks.c | 92 ++++++++++++----------------------
security/selinux/include/avc.h | 6 +++
3 files changed, 86 insertions(+), 59 deletions(-)
diff --git a/security/selinux/avc.c b/security/selinux/avc.c
index 03760f7e7cac..510bbbaf4a70 100644
--- a/security/selinux/avc.c
+++ b/security/selinux/avc.c
@@ -1316,6 +1316,53 @@ int cred_has_extended_perms(const struct cred *cred, u32 tsid, u16 tclass,
return 0;
}
+int cred_self_has_perm(const struct cred *cred, u16 tclass, u32 requested,
+ struct common_audit_data *ad)
+{
+ struct task_security_struct *tsec;
+ struct selinux_state *state;
+ u32 ssid;
+ int rc;
+
+ do {
+ tsec = selinux_cred(cred);
+ ssid = tsec->sid;
+ state = tsec->state;
+ rc = avc_has_perm(state, ssid, ssid, tclass, requested, ad);
+ if (rc)
+ return rc;
+
+ cred = tsec->parent_cred;
+ } while (cred);
+
+ return 0;
+}
+
+int cred_self_has_perm_noaudit(const struct cred *cred, u16 tclass,
+ u32 requested)
+{
+ struct task_security_struct *tsec;
+ struct selinux_state *state;
+ u32 ssid;
+ struct av_decision avd;
+ int rc;
+
+ do {
+ tsec = selinux_cred(cred);
+ ssid = tsec->sid;
+ state = tsec->state;
+
+ rc = avc_has_perm_noaudit(state, ssid, ssid, tclass,
+ requested, 0, &avd);
+ if (rc)
+ return rc;
+
+ cred = tsec->parent_cred;
+ } while (cred);
+
+ return 0;
+}
+
u32 avc_policy_seqno(struct selinux_state *state)
{
return state->avc->avc_cache.latest_notif;
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index f22acce323b8..ce2bfa56be6f 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -1658,9 +1658,7 @@ static int cred_has_capability(const struct cred *cred,
int cap, unsigned int opts, bool initns)
{
struct common_audit_data ad;
- struct av_decision avd;
u16 sclass;
- u32 sid = cred_sid(cred);
u32 av = CAP_TO_MASK(cap);
int rc;
@@ -1680,14 +1678,11 @@ static int cred_has_capability(const struct cred *cred,
return -EINVAL;
}
- rc = avc_has_perm_noaudit(cred_selinux_state(cred),
- sid, sid, sclass, av, 0, &avd);
- if (!(opts & CAP_OPT_NOAUDIT)) {
- int rc2 = avc_audit(cred_selinux_state(cred),
- sid, sid, sclass, av, &avd, rc, &ad);
- if (rc2)
- return rc2;
- }
+ if (opts & CAP_OPT_NOAUDIT)
+ rc = cred_self_has_perm_noaudit(cred, sclass, av);
+ else
+ rc = cred_self_has_perm(cred, sclass, av, &ad);
+
return rc;
}
@@ -3999,7 +3994,6 @@ static int default_noexec __ro_after_init;
static int file_map_prot_check(struct file *file, unsigned long prot, int shared)
{
const struct cred *cred = current_cred();
- u32 sid = cred_sid(cred);
int rc = 0;
if (default_noexec &&
@@ -4010,9 +4004,8 @@ static int file_map_prot_check(struct file *file, unsigned long prot, int shared
* private file mapping that will also be writable.
* This has an additional check.
*/
- rc = avc_has_perm(cred_selinux_state(cred),
- sid, sid, SECCLASS_PROCESS,
- PROCESS__EXECMEM, NULL);
+ rc = cred_self_has_perm(cred, SECCLASS_PROCESS,
+ PROCESS__EXECMEM, NULL);
if (rc)
goto error;
}
@@ -4040,10 +4033,8 @@ static int selinux_mmap_addr(unsigned long addr)
int rc = 0;
if (addr < CONFIG_LSM_MMAP_MIN_ADDR) {
- u32 sid = current_sid();
- rc = avc_has_perm(current_selinux_state,
- sid, sid, SECCLASS_MEMPROTECT,
- MEMPROTECT__MMAP_ZERO, NULL);
+ rc = cred_self_has_perm(current_cred(), SECCLASS_MEMPROTECT,
+ MEMPROTECT__MMAP_ZERO, NULL);
}
return rc;
@@ -4074,7 +4065,6 @@ static int selinux_file_mprotect(struct vm_area_struct *vma,
unsigned long prot)
{
const struct cred *cred = current_cred();
- u32 sid = cred_sid(cred);
if (default_noexec &&
(prot & PROT_EXEC) && !(vma->vm_flags & VM_EXEC)) {
@@ -4090,14 +4080,12 @@ static int selinux_file_mprotect(struct vm_area_struct *vma,
*/
if (vma->vm_start >= vma->vm_mm->start_brk &&
vma->vm_end <= vma->vm_mm->brk) {
- rc = avc_has_perm(cred_selinux_state(cred), sid, sid,
- SECCLASS_PROCESS, PROCESS__EXECHEAP,
- NULL);
+ rc = cred_self_has_perm(cred, SECCLASS_PROCESS,
+ PROCESS__EXECHEAP, NULL);
} else if (!vma->vm_file && (vma_is_initial_stack(vma) ||
vma_is_stack_for_current(vma))) {
- rc = avc_has_perm(cred_selinux_state(cred), sid, sid,
- SECCLASS_PROCESS, PROCESS__EXECSTACK,
- NULL);
+ rc = cred_self_has_perm(cred, SECCLASS_PROCESS,
+ PROCESS__EXECSTACK, NULL);
} else if (vma->vm_file && vma->anon_vma) {
/*
* We are making executable a file mapping that has
@@ -4232,10 +4220,8 @@ static int selinux_file_open(struct file *file)
static int selinux_task_alloc(struct task_struct *task,
unsigned long clone_flags)
{
- u32 sid = current_sid();
-
- return avc_has_perm(current_selinux_state,
- sid, sid, SECCLASS_PROCESS, PROCESS__FORK, NULL);
+ return cred_self_has_perm(current_cred(), SECCLASS_PROCESS,
+ PROCESS__FORK, NULL);
}
/*
@@ -4357,9 +4343,8 @@ static int selinux_kernel_load_from_file(struct file *file, u32 requested)
int rc;
if (file == NULL)
- return avc_has_perm(current_selinux_state,
- sid, sid, SECCLASS_SYSTEM, requested,
- NULL);
+ return cred_self_has_perm(current_cred(), SECCLASS_SYSTEM,
+ requested, NULL);
/* finit_module */
ad.type = LSM_AUDIT_DATA_FILE;
@@ -4580,10 +4565,8 @@ static void selinux_task_to_inode(struct task_struct *p,
static int selinux_userns_create(const struct cred *cred)
{
- u32 sid = current_sid();
-
- return avc_has_perm(current_selinux_state, sid, sid, SECCLASS_USER_NAMESPACE,
- USER_NAMESPACE__CREATE, NULL);
+ return cred_self_has_perm(current_cred(), SECCLASS_USER_NAMESPACE,
+ USER_NAMESPACE__CREATE, NULL);
}
/* Returns error only if unable to parse addresses */
@@ -6767,29 +6750,24 @@ static int selinux_lsm_setattr(u64 attr, void *value, size_t size)
*/
switch (attr) {
case LSM_ATTR_EXEC:
- error = avc_has_perm(current_selinux_state,
- mysid, mysid, SECCLASS_PROCESS,
- PROCESS__SETEXEC, NULL);
+ error = cred_self_has_perm(current_cred(), SECCLASS_PROCESS,
+ PROCESS__SETEXEC, NULL);
break;
case LSM_ATTR_FSCREATE:
- error = avc_has_perm(current_selinux_state,
- mysid, mysid, SECCLASS_PROCESS,
- PROCESS__SETFSCREATE, NULL);
+ error = cred_self_has_perm(current_cred(), SECCLASS_PROCESS,
+ PROCESS__SETFSCREATE, NULL);
break;
case LSM_ATTR_KEYCREATE:
- error = avc_has_perm(current_selinux_state,
- mysid, mysid, SECCLASS_PROCESS,
- PROCESS__SETKEYCREATE, NULL);
+ error = cred_self_has_perm(current_cred(), SECCLASS_PROCESS,
+ PROCESS__SETKEYCREATE, NULL);
break;
case LSM_ATTR_SOCKCREATE:
- error = avc_has_perm(current_selinux_state,
- mysid, mysid, SECCLASS_PROCESS,
- PROCESS__SETSOCKCREATE, NULL);
+ error = cred_self_has_perm(current_cred(), SECCLASS_PROCESS,
+ PROCESS__SETSOCKCREATE, NULL);
break;
case LSM_ATTR_CURRENT:
- error = avc_has_perm(current_selinux_state,
- mysid, mysid, SECCLASS_PROCESS,
- PROCESS__SETCURRENT, NULL);
+ error = cred_self_has_perm(current_cred(), SECCLASS_PROCESS,
+ PROCESS__SETCURRENT, NULL);
break;
default:
error = -EOPNOTSUPP;
@@ -7456,10 +7434,8 @@ static int selinux_uring_override_creds(const struct cred *new)
*/
static int selinux_uring_sqpoll(void)
{
- u32 sid = current_sid();
-
- return avc_has_perm(current_selinux_state, sid, sid,
- SECCLASS_IO_URING, IO_URING__SQPOLL, NULL);
+ return cred_self_has_perm(current_cred(), SECCLASS_IO_URING,
+ IO_URING__SQPOLL, NULL);
}
/**
@@ -7491,10 +7467,8 @@ static int selinux_uring_cmd(struct io_uring_cmd *ioucmd)
*/
static int selinux_uring_allowed(void)
{
- u32 sid = current_sid();
-
- return avc_has_perm(current_selinux_state, sid, sid,
- SECCLASS_IO_URING, IO_URING__ALLOWED, NULL);
+ return cred_self_has_perm(current_cred(), SECCLASS_IO_URING,
+ IO_URING__ALLOWED, NULL);
}
#endif /* CONFIG_IO_URING */
diff --git a/security/selinux/include/avc.h b/security/selinux/include/avc.h
index adbbecc681f2..3fce5cf92b0a 100644
--- a/security/selinux/include/avc.h
+++ b/security/selinux/include/avc.h
@@ -158,6 +158,12 @@ int cred_has_extended_perms(const struct cred *cred, u32 tsid, u16 tclass,
u32 requested, u8 driver, u8 base_perm, u8 xperm,
struct common_audit_data *ad);
+int cred_self_has_perm(const struct cred *cred, u16 tclass, u32 requested,
+ struct common_audit_data *ad);
+
+int cred_self_has_perm_noaudit(const struct cred *cred, u16 tclass,
+ u32 requested);
+
u32 avc_policy_seqno(struct selinux_state *state);
#define AVC_CALLBACK_GRANT 1
--
2.50.1
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [PATCH v7 25/42] selinux: introduce cred_has_perm()
2025-08-14 13:25 [PATCH v7 00/42] SELinux namespace support Stephen Smalley
` (23 preceding siblings ...)
2025-08-14 13:26 ` [PATCH v7 24/42] selinux: introduce cred_self_has_perm() Stephen Smalley
@ 2025-08-14 13:26 ` Stephen Smalley
2025-08-14 13:26 ` [PATCH v7 26/42] selinux: introduce cred_ssid_has_perm() and cred_other_has_perm() Stephen Smalley
` (16 subsequent siblings)
41 siblings, 0 replies; 43+ messages in thread
From: Stephen Smalley @ 2025-08-14 13:26 UTC (permalink / raw)
To: selinux; +Cc: paul, omosnace, netdev, horms, Stephen Smalley
Introduce cred_has_perm() to check permissions between a cred
and a specified target SID against the current SELinux namespace
and all ancestors. Also provide a cred_has_perm_noaudit() variant
for use by checks where auditing is not desired or requires further
specialization (e.g. selinux_inode_permission).
These helpers should NOT be used when checking permissions
between two creds (or tasks) since they will not use the
target SID from the same namespace as the source cred.
They are only suitable when checking permissions to
non-cred/task objects like superblocks, inodes, etc.
Convert permission checks in the hook functions to use these
new helpers when appropriate. Also convert some further checks
to using the cred_self_has_perm() helper previously introduced.
Signed-off-by: Stephen Smalley <stephen.smalley.work@gmail.com>
---
security/selinux/avc.c | 53 +++++
security/selinux/hooks.c | 377 +++++++++++++--------------------
security/selinux/include/avc.h | 6 +
3 files changed, 208 insertions(+), 228 deletions(-)
diff --git a/security/selinux/avc.c b/security/selinux/avc.c
index 510bbbaf4a70..5a17c24a8466 100644
--- a/security/selinux/avc.c
+++ b/security/selinux/avc.c
@@ -1363,6 +1363,59 @@ int cred_self_has_perm_noaudit(const struct cred *cred, u16 tclass,
return 0;
}
+int cred_has_perm(const struct cred *cred, u32 tsid, u16 tclass,
+ u32 requested, struct common_audit_data *ad)
+{
+ struct task_security_struct *tsec;
+ struct selinux_state *state;
+ u32 ssid;
+ int rc;
+
+ do {
+ tsec = selinux_cred(cred);
+ ssid = tsec->sid;
+ state = tsec->state;
+ rc = avc_has_perm(state, ssid, tsid, tclass, requested, ad);
+ if (rc)
+ return rc;
+
+ cred = tsec->parent_cred;
+ } while (cred);
+
+ return 0;
+}
+
+int cred_has_perm_noaudit(const struct cred *cred, u32 tsid, u16 tclass,
+ u32 requested, struct av_decision *avd)
+{
+ struct task_security_struct *tsec;
+ struct selinux_state *state;
+ u32 ssid;
+ int rc;
+
+ do {
+ tsec = selinux_cred(cred);
+ ssid = tsec->sid;
+ state = tsec->state;
+
+ /*
+ * TODO Do we need to use a tmp avd for each
+ * avc_has_perm_noaudit() call and intersect/union
+ * the sets as appropriate as we go? Or can we
+ * simply use the last result since we generally
+ * only care when there is a denial?
+ */
+ rc = avc_has_perm_noaudit(state, ssid, tsid, tclass,
+ requested, 0, avd);
+ if (rc)
+ return rc;
+
+ cred = tsec->parent_cred;
+ } while (cred);
+
+ return 0;
+}
+
u32 avc_policy_seqno(struct selinux_state *state)
{
return state->avc->avc_cache.latest_notif;
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index ce2bfa56be6f..d759c48a8557 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -446,17 +446,14 @@ static int may_context_mount_sb_relabel(u32 sid,
struct superblock_security_struct *sbsec,
const struct cred *cred)
{
- const struct task_security_struct *tsec = selinux_cred(cred);
int rc;
- rc = avc_has_perm(cred_selinux_state(cred),
- tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
- FILESYSTEM__RELABELFROM, NULL);
+ rc = cred_has_perm(cred, sbsec->sid, SECCLASS_FILESYSTEM,
+ FILESYSTEM__RELABELFROM, NULL);
if (rc)
return rc;
- rc = avc_has_perm(cred_selinux_state(cred),
- tsec->sid, sid, SECCLASS_FILESYSTEM,
+ rc = cred_has_perm(cred, sid, SECCLASS_FILESYSTEM,
FILESYSTEM__RELABELTO, NULL);
return rc;
}
@@ -465,18 +462,16 @@ static int may_context_mount_inode_relabel(u32 sid,
struct superblock_security_struct *sbsec,
const struct cred *cred)
{
- const struct task_security_struct *tsec = selinux_cred(cred);
int rc;
- rc = avc_has_perm(cred_selinux_state(cred),
- tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
+
+ rc = cred_has_perm(cred, sbsec->sid, SECCLASS_FILESYSTEM,
FILESYSTEM__RELABELFROM, NULL);
if (rc)
return rc;
- rc = avc_has_perm(cred_selinux_state(cred),
- sid, sbsec->sid, SECCLASS_FILESYSTEM,
- FILESYSTEM__ASSOCIATE, NULL);
- return rc;
+ return avc_has_perm(cred_selinux_state(cred),
+ sid, sbsec->sid, SECCLASS_FILESYSTEM,
+ FILESYSTEM__ASSOCIATE, NULL);
}
static int selinux_is_genfs_special_handling(struct super_block *sb)
@@ -1695,16 +1690,13 @@ static int inode_has_perm(const struct cred *cred,
struct common_audit_data *adp)
{
struct inode_security_struct *isec;
- u32 sid;
if (unlikely(IS_PRIVATE(inode)))
return 0;
- sid = cred_sid(cred);
isec = selinux_inode(inode);
- return avc_has_perm(cred_selinux_state(cred),
- sid, isec->sid, isec->sclass, perms, adp);
+ return cred_has_perm(cred, isec->sid, isec->sclass, perms, adp);
}
/* Same as inode_has_perm, but pass explicit audit data containing
@@ -1758,7 +1750,7 @@ static inline int file_path_has_perm(const struct cred *cred,
}
#ifdef CONFIG_BPF_SYSCALL
-static int bpf_fd_pass(const struct file *file, u32 sid);
+static int bpf_fd_pass(const struct file *file, const struct cred *cred);
#endif
/* Check whether a task can use an open file descriptor to
@@ -1783,17 +1775,14 @@ static int file_has_perm(const struct cred *cred,
ad.u.file = file;
if (sid != fsec->sid) {
- rc = avc_has_perm(cred_selinux_state(cred),
- sid, fsec->sid,
- SECCLASS_FD,
- FD__USE,
- &ad);
+ rc = cred_has_perm(cred, fsec->sid, SECCLASS_FD, FD__USE,
+ &ad);
if (rc)
goto out;
}
#ifdef CONFIG_BPF_SYSCALL
- rc = bpf_fd_pass(file, cred_sid(cred));
+ rc = bpf_fd_pass(file, cred);
if (rc)
return rc;
#endif
@@ -1840,23 +1829,21 @@ static int may_create(struct inode *dir,
struct dentry *dentry,
u16 tclass)
{
- const struct task_security_struct *tsec = selinux_cred(current_cred());
+ const struct cred *cred = current_cred();
+ const struct task_security_struct *tsec = selinux_cred(cred);
struct inode_security_struct *dsec;
struct superblock_security_struct *sbsec;
- u32 sid, newsid;
+ u32 newsid;
struct common_audit_data ad;
int rc;
dsec = inode_security(dir);
sbsec = selinux_superblock(dir->i_sb);
- sid = tsec->sid;
-
ad.type = LSM_AUDIT_DATA_DENTRY;
ad.u.dentry = dentry;
- rc = avc_has_perm(current_selinux_state,
- sid, dsec->sid, SECCLASS_DIR,
+ rc = cred_has_perm(cred, dsec->sid, SECCLASS_DIR,
DIR__ADD_NAME | DIR__SEARCH,
&ad);
if (rc)
@@ -1867,8 +1854,7 @@ static int may_create(struct inode *dir,
if (rc)
return rc;
- rc = avc_has_perm(current_selinux_state,
- sid, newsid, tclass, FILE__CREATE, &ad);
+ rc = cred_has_perm(cred, newsid, tclass, FILE__CREATE, &ad);
if (rc)
return rc;
@@ -1888,9 +1874,9 @@ static int may_link(struct inode *dir,
int kind)
{
+ const struct cred *cred = current_cred();
struct inode_security_struct *dsec, *isec;
struct common_audit_data ad;
- u32 sid = current_sid();
u32 av;
int rc;
@@ -1902,8 +1888,7 @@ static int may_link(struct inode *dir,
av = DIR__SEARCH;
av |= (kind ? DIR__REMOVE_NAME : DIR__ADD_NAME);
- rc = avc_has_perm(current_selinux_state,
- sid, dsec->sid, SECCLASS_DIR, av, &ad);
+ rc = cred_has_perm(cred, dsec->sid, SECCLASS_DIR, av, &ad);
if (rc)
return rc;
@@ -1923,9 +1908,7 @@ static int may_link(struct inode *dir,
return 0;
}
- rc = avc_has_perm(current_selinux_state,
- sid, isec->sid, isec->sclass, av, &ad);
- return rc;
+ return cred_has_perm(cred, isec->sid, isec->sclass, av, &ad);
}
static inline int may_rename(struct inode *old_dir,
@@ -1933,9 +1916,9 @@ static inline int may_rename(struct inode *old_dir,
struct inode *new_dir,
struct dentry *new_dentry)
{
+ const struct cred *cred = current_cred();
struct inode_security_struct *old_dsec, *new_dsec, *old_isec, *new_isec;
struct common_audit_data ad;
- u32 sid = current_sid();
u32 av;
int old_is_dir, new_is_dir;
int rc;
@@ -1948,20 +1931,17 @@ static inline int may_rename(struct inode *old_dir,
ad.type = LSM_AUDIT_DATA_DENTRY;
ad.u.dentry = old_dentry;
- rc = avc_has_perm(current_selinux_state,
- sid, old_dsec->sid, SECCLASS_DIR,
+ rc = cred_has_perm(cred, old_dsec->sid, SECCLASS_DIR,
DIR__REMOVE_NAME | DIR__SEARCH, &ad);
if (rc)
return rc;
- rc = avc_has_perm(current_selinux_state,
- sid, old_isec->sid,
- old_isec->sclass, FILE__RENAME, &ad);
+ rc = cred_has_perm(cred, old_isec->sid, old_isec->sclass,
+ FILE__RENAME, &ad);
if (rc)
return rc;
if (old_is_dir && new_dir != old_dir) {
- rc = avc_has_perm(current_selinux_state,
- sid, old_isec->sid,
- old_isec->sclass, DIR__REPARENT, &ad);
+ rc = cred_has_perm(cred, old_isec->sid, old_isec->sclass,
+ DIR__REPARENT, &ad);
if (rc)
return rc;
}
@@ -1970,17 +1950,15 @@ static inline int may_rename(struct inode *old_dir,
av = DIR__ADD_NAME | DIR__SEARCH;
if (d_is_positive(new_dentry))
av |= DIR__REMOVE_NAME;
- rc = avc_has_perm(current_selinux_state,
- sid, new_dsec->sid, SECCLASS_DIR, av, &ad);
+ rc = cred_has_perm(cred, new_dsec->sid, SECCLASS_DIR, av, &ad);
if (rc)
return rc;
if (d_is_positive(new_dentry)) {
new_isec = backing_inode_security(new_dentry);
new_is_dir = d_is_dir(new_dentry);
- rc = avc_has_perm(current_selinux_state,
- sid, new_isec->sid,
- new_isec->sclass,
- (new_is_dir ? DIR__RMDIR : FILE__UNLINK), &ad);
+ rc = cred_has_perm(cred, new_isec->sid, new_isec->sclass,
+ (new_is_dir ? DIR__RMDIR : FILE__UNLINK),
+ &ad);
if (rc)
return rc;
}
@@ -1995,11 +1973,10 @@ static int superblock_has_perm(const struct cred *cred,
struct common_audit_data *ad)
{
struct superblock_security_struct *sbsec;
- u32 sid = cred_sid(cred);
sbsec = selinux_superblock(sb);
- return avc_has_perm(cred_selinux_state(cred),
- sid, sbsec->sid, SECCLASS_FILESYSTEM, perms, ad);
+ return cred_has_perm(cred, sbsec->sid, SECCLASS_FILESYSTEM, perms,
+ ad);
}
/* Convert a Linux mode and permission mask to an access vector. */
@@ -2122,17 +2099,14 @@ static int selinux_binder_transfer_file(const struct cred *from,
ad.u.path = file->f_path;
if (sid != fsec->sid) {
- rc = avc_has_perm(cred_selinux_state(to),
- sid, fsec->sid,
- SECCLASS_FD,
- FD__USE,
- &ad);
+ rc = cred_has_perm(to, fsec->sid, SECCLASS_FD, FD__USE,
+ &ad);
if (rc)
return rc;
}
#ifdef CONFIG_BPF_SYSCALL
- rc = bpf_fd_pass(file, sid);
+ rc = bpf_fd_pass(file, to);
if (rc)
return rc;
#endif
@@ -2141,9 +2115,8 @@ static int selinux_binder_transfer_file(const struct cred *from,
return 0;
isec = backing_inode_security(dentry);
- return avc_has_perm(cred_selinux_state(to),
- sid, isec->sid, isec->sclass, file_to_av(file),
- &ad);
+ return cred_has_perm(to, isec->sid, isec->sclass, file_to_av(file),
+ &ad);
}
static int selinux_ptrace_access_check(struct task_struct *child,
@@ -2241,25 +2214,25 @@ static int selinux_quota_on(struct dentry *dentry)
static int selinux_syslog(int type)
{
+ const struct cred *cred = current_cred();
+
switch (type) {
case SYSLOG_ACTION_READ_ALL: /* Read last kernel messages */
case SYSLOG_ACTION_SIZE_BUFFER: /* Return size of the log buffer */
- return avc_has_perm(current_selinux_state,
- current_sid(), SECINITSID_KERNEL,
- SECCLASS_SYSTEM, SYSTEM__SYSLOG_READ, NULL);
+ return cred_has_perm(cred, SECINITSID_KERNEL,
+ SECCLASS_SYSTEM,
+ SYSTEM__SYSLOG_READ, NULL);
case SYSLOG_ACTION_CONSOLE_OFF: /* Disable logging to console */
case SYSLOG_ACTION_CONSOLE_ON: /* Enable logging to console */
/* Set level of messages printed to console */
case SYSLOG_ACTION_CONSOLE_LEVEL:
- return avc_has_perm(current_selinux_state,
- current_sid(), SECINITSID_KERNEL,
- SECCLASS_SYSTEM, SYSTEM__SYSLOG_CONSOLE,
- NULL);
+ return cred_has_perm(cred, SECINITSID_KERNEL,
+ SECCLASS_SYSTEM,
+ SYSTEM__SYSLOG_CONSOLE, NULL);
}
/* All other syslog types */
- return avc_has_perm(current_selinux_state,
- current_sid(), SECINITSID_KERNEL,
- SECCLASS_SYSTEM, SYSTEM__SYSLOG_MOD, NULL);
+ return cred_has_perm(cred, SECINITSID_KERNEL, SECCLASS_SYSTEM,
+ SYSTEM__SYSLOG_MOD, NULL);
}
/*
@@ -3069,12 +3042,8 @@ static int selinux_inode_init_security_anon(struct inode *inode,
ad.type = LSM_AUDIT_DATA_ANONINODE;
ad.u.anonclass = name ? (const char *)name->name : "?";
- return avc_has_perm(current_selinux_state,
- sid,
- isec->sid,
- isec->sclass,
- FILE__CREATE,
- &ad);
+ return cred_has_perm(current_cred(), isec->sid, isec->sclass,
+ FILE__CREATE, &ad);
}
static int selinux_inode_create(struct inode *dir, struct dentry *dentry, umode_t mode)
@@ -3130,7 +3099,6 @@ static int selinux_inode_follow_link(struct dentry *dentry, struct inode *inode,
{
struct common_audit_data ad;
struct inode_security_struct *isec;
- u32 sid = current_sid();
ad.type = LSM_AUDIT_DATA_DENTRY;
ad.u.dentry = dentry;
@@ -3138,8 +3106,8 @@ static int selinux_inode_follow_link(struct dentry *dentry, struct inode *inode,
if (IS_ERR(isec))
return PTR_ERR(isec);
- return avc_has_perm(current_selinux_state,
- sid, isec->sid, isec->sclass, FILE__READ, &ad);
+ return cred_has_perm(current_cred(), isec->sid, isec->sclass,
+ FILE__READ, &ad);
}
static noinline int audit_inode_permission(struct inode *inode,
@@ -3288,9 +3256,8 @@ static int selinux_inode_permission(struct inode *inode, int requested)
struct av_decision avd;
/* Cache miss. */
- rc = avc_has_perm_noaudit(current_selinux_state, tsec->sid,
- isec->sid, isec->sclass, perms, 0,
- &avd);
+ rc = cred_has_perm_noaudit(current_cred(), isec->sid,
+ isec->sclass, perms, &avd);
audited = avc_audit_required(perms, &avd, rc,
(requested & MAY_ACCESS) ? FILE__AUDIT_ACCESS : 0,
&denied);
@@ -3381,11 +3348,12 @@ static int selinux_inode_setxattr(struct mnt_idmap *idmap,
struct dentry *dentry, const char *name,
const void *value, size_t size, int flags)
{
+ const struct cred *cred = current_cred();
struct inode *inode = d_backing_inode(dentry);
struct inode_security_struct *isec;
struct superblock_security_struct *sbsec;
struct common_audit_data ad;
- u32 newsid, sid = current_sid();
+ u32 newsid;
int rc = 0;
/* if not a selinux xattr, only check the ordinary setattr perm */
@@ -3406,9 +3374,8 @@ static int selinux_inode_setxattr(struct mnt_idmap *idmap,
ad.u.dentry = dentry;
isec = backing_inode_security(dentry);
- rc = avc_has_perm(current_selinux_state,
- sid, isec->sid, isec->sclass,
- FILE__RELABELFROM, &ad);
+ rc = cred_has_perm(cred, isec->sid, isec->sclass, FILE__RELABELFROM,
+ &ad);
if (rc)
return rc;
@@ -3447,14 +3414,13 @@ static int selinux_inode_setxattr(struct mnt_idmap *idmap,
if (rc)
return rc;
- rc = avc_has_perm(current_selinux_state,
- sid, newsid, isec->sclass,
- FILE__RELABELTO, &ad);
+ rc = cred_has_perm(cred, newsid, isec->sclass, FILE__RELABELTO,
+ &ad);
if (rc)
return rc;
rc = security_validate_transition(current_selinux_state, isec->sid, newsid,
- sid, isec->sclass);
+ current_sid(), isec->sclass);
if (rc)
return rc;
@@ -3895,11 +3861,8 @@ static int ioctl_has_perm(const struct cred *cred, struct file *file,
ad.u.op->path = file->f_path;
if (ssid != fsec->sid) {
- rc = avc_has_perm(cred_selinux_state(cred),
- ssid, fsec->sid,
- SECCLASS_FD,
- FD__USE,
- &ad);
+ rc = cred_has_perm(cred, fsec->sid, SECCLASS_FD, FD__USE,
+ &ad);
if (rc)
goto out;
}
@@ -4283,14 +4246,10 @@ static void selinux_cred_getlsmprop(const struct cred *c, struct lsm_prop *prop)
static int selinux_kernel_act_as(struct cred *new, u32 secid)
{
struct task_security_struct *tsec = selinux_cred(new);
- u32 sid = current_sid();
int ret;
- ret = avc_has_perm(tsec->state,
- sid, secid,
- SECCLASS_KERNEL_SERVICE,
- KERNEL_SERVICE__USE_AS_OVERRIDE,
- NULL);
+ ret = cred_has_perm(current_cred(), secid, SECCLASS_KERNEL_SERVICE,
+ KERNEL_SERVICE__USE_AS_OVERRIDE, NULL);
if (ret == 0) {
tsec->sid = secid;
tsec->create_sid = 0;
@@ -4308,14 +4267,12 @@ static int selinux_kernel_create_files_as(struct cred *new, struct inode *inode)
{
struct inode_security_struct *isec = inode_security(inode);
struct task_security_struct *tsec = selinux_cred(new);
- u32 sid = current_sid();
int ret;
- ret = avc_has_perm(tsec->state,
- sid, isec->sid,
- SECCLASS_KERNEL_SERVICE,
- KERNEL_SERVICE__CREATE_FILES_AS,
- NULL);
+ ret = cred_has_perm(current_cred(), isec->sid,
+ SECCLASS_KERNEL_SERVICE,
+ KERNEL_SERVICE__CREATE_FILES_AS,
+ NULL);
if (ret == 0)
tsec->create_sid = isec->sid;
@@ -4329,9 +4286,8 @@ static int selinux_kernel_module_request(char *kmod_name)
ad.type = LSM_AUDIT_DATA_KMOD;
ad.u.kmod_name = kmod_name;
- return avc_has_perm(current_selinux_state,
- current_sid(), SECINITSID_KERNEL, SECCLASS_SYSTEM,
- SYSTEM__MODULE_REQUEST, &ad);
+ return cred_has_perm(current_cred(), SECINITSID_KERNEL,
+ SECCLASS_SYSTEM, SYSTEM__MODULE_REQUEST, &ad);
}
static int selinux_kernel_load_from_file(struct file *file, u32 requested)
@@ -4339,12 +4295,13 @@ static int selinux_kernel_load_from_file(struct file *file, u32 requested)
struct common_audit_data ad;
struct inode_security_struct *isec;
struct file_security_struct *fsec;
+ const struct cred *cred = current_cred();
u32 sid = current_sid();
int rc;
if (file == NULL)
- return cred_self_has_perm(current_cred(), SECCLASS_SYSTEM,
- requested, NULL);
+ return cred_self_has_perm(cred, SECCLASS_SYSTEM, requested,
+ NULL);
/* finit_module */
ad.type = LSM_AUDIT_DATA_FILE;
@@ -4352,15 +4309,14 @@ static int selinux_kernel_load_from_file(struct file *file, u32 requested)
fsec = selinux_file(file);
if (sid != fsec->sid) {
- rc = avc_has_perm(current_selinux_state,
- sid, fsec->sid, SECCLASS_FD, FD__USE, &ad);
+ rc = cred_has_perm(cred, fsec->sid, SECCLASS_FD, FD__USE,
+ &ad);
if (rc)
return rc;
}
isec = inode_security(file_inode(file));
- return avc_has_perm(current_selinux_state,
- sid, isec->sid, SECCLASS_SYSTEM, requested, &ad);
+ return cred_has_perm(cred, isec->sid, SECCLASS_SYSTEM, requested, &ad);
}
static int selinux_kernel_read_file(struct file *file,
@@ -4885,9 +4841,8 @@ static int sock_has_perm(struct sock *sk, u32 perms)
ad_net_init_from_sk(&ad, &net, sk);
- return avc_has_perm(current_selinux_state,
- current_sid(), sksec->sid, sksec->sclass, perms,
- &ad);
+ return cred_has_perm(current_cred(), sksec->sid, sksec->sclass,
+ perms, &ad);
}
static int selinux_socket_create(int family, int type,
@@ -4906,8 +4861,8 @@ static int selinux_socket_create(int family, int type,
if (rc)
return rc;
- return avc_has_perm(current_selinux_state,
- tsec->sid, newsid, secclass, SOCKET__CREATE, NULL);
+ return cred_has_perm(current_cred(), newsid, secclass,
+ SOCKET__CREATE, NULL);
}
static int selinux_socket_post_create(struct socket *sock, int family,
@@ -5857,8 +5812,7 @@ static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb)
static int selinux_secmark_relabel_packet(u32 sid)
{
- return avc_has_perm(current_selinux_state,
- current_sid(), sid, SECCLASS_PACKET,
+ return cred_has_perm(current_cred(), sid, SECCLASS_PACKET,
PACKET__RELABELTO, NULL);
}
@@ -5888,8 +5842,6 @@ static int selinux_tun_dev_alloc_security(void *security)
static int selinux_tun_dev_create(void)
{
- u32 sid = current_sid();
-
/* we aren't taking into account the "sockcreate" SID since the socket
* that is being created here is not a socket in the traditional sense,
* instead it is a private sock, accessible only to the kernel, and
@@ -5897,18 +5849,17 @@ static int selinux_tun_dev_create(void)
* connections unlike traditional sockets - check the TUN driver to
* get a better understanding of why this socket is special */
- return avc_has_perm(current_selinux_state,
- sid, sid, SECCLASS_TUN_SOCKET, TUN_SOCKET__CREATE,
- NULL);
+ return cred_self_has_perm(current_cred(), SECCLASS_TUN_SOCKET,
+ TUN_SOCKET__CREATE, NULL);
}
static int selinux_tun_dev_attach_queue(void *security)
{
struct tun_security_struct *tunsec = selinux_tun_dev(security);
- return avc_has_perm(current_selinux_state,
- current_sid(), tunsec->sid, SECCLASS_TUN_SOCKET,
- TUN_SOCKET__ATTACH_QUEUE, NULL);
+ return cred_has_perm(current_cred(), tunsec->sid,
+ SECCLASS_TUN_SOCKET, TUN_SOCKET__ATTACH_QUEUE,
+ NULL);
}
static int selinux_tun_dev_attach(struct sock *sk, void *security)
@@ -5931,21 +5882,19 @@ static int selinux_tun_dev_attach(struct sock *sk, void *security)
static int selinux_tun_dev_open(void *security)
{
+ const struct cred *cred = current_cred();
struct tun_security_struct *tunsec = selinux_tun_dev(security);
- u32 sid = current_sid();
int err;
- err = avc_has_perm(current_selinux_state,
- sid, tunsec->sid, SECCLASS_TUN_SOCKET,
- TUN_SOCKET__RELABELFROM, NULL);
+ err = cred_has_perm(cred, tunsec->sid, SECCLASS_TUN_SOCKET,
+ TUN_SOCKET__RELABELFROM, NULL);
if (err)
return err;
- err = avc_has_perm(current_selinux_state,
- sid, sid, SECCLASS_TUN_SOCKET,
- TUN_SOCKET__RELABELTO, NULL);
+ err = cred_self_has_perm(cred, SECCLASS_TUN_SOCKET,
+ TUN_SOCKET__RELABELTO, NULL);
if (err)
return err;
- tunsec->sid = sid;
+ tunsec->sid = current_sid();
return 0;
}
@@ -6322,15 +6271,14 @@ static int ipc_has_perm(struct kern_ipc_perm *ipc_perms,
{
struct ipc_security_struct *isec;
struct common_audit_data ad;
- u32 sid = current_sid();
isec = selinux_ipc(ipc_perms);
ad.type = LSM_AUDIT_DATA_IPC;
ad.u.ipc_id = ipc_perms->key;
- return avc_has_perm(current_selinux_state,
- sid, isec->sid, isec->sclass, perms, &ad);
+ return cred_has_perm(current_cred(), isec->sid, isec->sclass, perms,
+ &ad);
}
static int selinux_msg_msg_alloc_security(struct msg_msg *msg)
@@ -6348,7 +6296,6 @@ static int selinux_msg_queue_alloc_security(struct kern_ipc_perm *msq)
{
struct ipc_security_struct *isec;
struct common_audit_data ad;
- u32 sid = current_sid();
isec = selinux_ipc(msq);
ipc_init_security(isec, SECCLASS_MSGQ);
@@ -6356,24 +6303,21 @@ static int selinux_msg_queue_alloc_security(struct kern_ipc_perm *msq)
ad.type = LSM_AUDIT_DATA_IPC;
ad.u.ipc_id = msq->key;
- return avc_has_perm(current_selinux_state,
- sid, isec->sid, SECCLASS_MSGQ,
- MSGQ__CREATE, &ad);
+ return cred_has_perm(current_cred(), isec->sid, SECCLASS_MSGQ,
+ MSGQ__CREATE, &ad);
}
static int selinux_msg_queue_associate(struct kern_ipc_perm *msq, int msqflg)
{
struct ipc_security_struct *isec;
struct common_audit_data ad;
- u32 sid = current_sid();
isec = selinux_ipc(msq);
ad.type = LSM_AUDIT_DATA_IPC;
ad.u.ipc_id = msq->key;
- return avc_has_perm(current_selinux_state,
- sid, isec->sid, SECCLASS_MSGQ,
+ return cred_has_perm(current_cred(), isec->sid, SECCLASS_MSGQ,
MSGQ__ASSOCIATE, &ad);
}
@@ -6385,8 +6329,7 @@ static int selinux_msg_queue_msgctl(struct kern_ipc_perm *msq, int cmd)
case IPC_INFO:
case MSG_INFO:
/* No specific object, just general system-wide information. */
- return avc_has_perm(current_selinux_state,
- current_sid(), SECINITSID_KERNEL,
+ return cred_has_perm(current_cred(), SECINITSID_KERNEL,
SECCLASS_SYSTEM, SYSTEM__IPC_INFO, NULL);
case IPC_STAT:
case MSG_STAT:
@@ -6408,6 +6351,7 @@ static int selinux_msg_queue_msgctl(struct kern_ipc_perm *msq, int cmd)
static int selinux_msg_queue_msgsnd(struct kern_ipc_perm *msq, struct msg_msg *msg, int msqflg)
{
+ const struct cred *cred = current_cred();
struct ipc_security_struct *isec;
struct msg_security_struct *msec;
struct common_audit_data ad;
@@ -6435,14 +6379,11 @@ static int selinux_msg_queue_msgsnd(struct kern_ipc_perm *msq, struct msg_msg *m
ad.u.ipc_id = msq->key;
/* Can this process write to the queue? */
- rc = avc_has_perm(current_selinux_state,
- sid, isec->sid, SECCLASS_MSGQ,
- MSGQ__WRITE, &ad);
+ rc = cred_has_perm(cred, isec->sid, SECCLASS_MSGQ, MSGQ__WRITE, &ad);
if (!rc)
/* Can this process send the message */
- rc = avc_has_perm(current_selinux_state,
- sid, msec->sid, SECCLASS_MSG,
- MSG__SEND, &ad);
+ rc = cred_has_perm(cred, msec->sid, SECCLASS_MSG, MSG__SEND,
+ &ad);
if (!rc)
/* Can the message be put in the queue? */
rc = avc_has_perm(current_selinux_state,
@@ -6483,7 +6424,6 @@ static int selinux_shm_alloc_security(struct kern_ipc_perm *shp)
{
struct ipc_security_struct *isec;
struct common_audit_data ad;
- u32 sid = current_sid();
isec = selinux_ipc(shp);
ipc_init_security(isec, SECCLASS_SHM);
@@ -6491,25 +6431,22 @@ static int selinux_shm_alloc_security(struct kern_ipc_perm *shp)
ad.type = LSM_AUDIT_DATA_IPC;
ad.u.ipc_id = shp->key;
- return avc_has_perm(current_selinux_state,
- sid, isec->sid, SECCLASS_SHM,
- SHM__CREATE, &ad);
+ return cred_has_perm(current_cred(), isec->sid, SECCLASS_SHM,
+ SHM__CREATE, &ad);
}
static int selinux_shm_associate(struct kern_ipc_perm *shp, int shmflg)
{
struct ipc_security_struct *isec;
struct common_audit_data ad;
- u32 sid = current_sid();
isec = selinux_ipc(shp);
ad.type = LSM_AUDIT_DATA_IPC;
ad.u.ipc_id = shp->key;
- return avc_has_perm(current_selinux_state,
- sid, isec->sid, SECCLASS_SHM,
- SHM__ASSOCIATE, &ad);
+ return cred_has_perm(current_cred(), isec->sid, SECCLASS_SHM,
+ SHM__ASSOCIATE, &ad);
}
/* Note, at this point, shp is locked down */
@@ -6521,9 +6458,9 @@ static int selinux_shm_shmctl(struct kern_ipc_perm *shp, int cmd)
case IPC_INFO:
case SHM_INFO:
/* No specific object, just general system-wide information. */
- return avc_has_perm(current_selinux_state,
- current_sid(), SECINITSID_KERNEL,
- SECCLASS_SYSTEM, SYSTEM__IPC_INFO, NULL);
+ return cred_has_perm(current_cred(), SECINITSID_KERNEL,
+ SECCLASS_SYSTEM, SYSTEM__IPC_INFO,
+ NULL);
case IPC_STAT:
case SHM_STAT:
case SHM_STAT_ANY:
@@ -6564,7 +6501,6 @@ static int selinux_sem_alloc_security(struct kern_ipc_perm *sma)
{
struct ipc_security_struct *isec;
struct common_audit_data ad;
- u32 sid = current_sid();
isec = selinux_ipc(sma);
ipc_init_security(isec, SECCLASS_SEM);
@@ -6572,25 +6508,22 @@ static int selinux_sem_alloc_security(struct kern_ipc_perm *sma)
ad.type = LSM_AUDIT_DATA_IPC;
ad.u.ipc_id = sma->key;
- return avc_has_perm(current_selinux_state,
- sid, isec->sid, SECCLASS_SEM,
- SEM__CREATE, &ad);
+ return cred_has_perm(current_cred(), isec->sid, SECCLASS_SEM,
+ SEM__CREATE, &ad);
}
static int selinux_sem_associate(struct kern_ipc_perm *sma, int semflg)
{
struct ipc_security_struct *isec;
struct common_audit_data ad;
- u32 sid = current_sid();
isec = selinux_ipc(sma);
ad.type = LSM_AUDIT_DATA_IPC;
ad.u.ipc_id = sma->key;
- return avc_has_perm(current_selinux_state,
- sid, isec->sid, SECCLASS_SEM,
- SEM__ASSOCIATE, &ad);
+ return cred_has_perm(current_cred(), isec->sid, SECCLASS_SEM,
+ SEM__ASSOCIATE, &ad);
}
/* Note, at this point, sma is locked down */
@@ -6603,9 +6536,9 @@ static int selinux_sem_semctl(struct kern_ipc_perm *sma, int cmd)
case IPC_INFO:
case SEM_INFO:
/* No specific object, just general system-wide information. */
- return avc_has_perm(current_selinux_state,
- current_sid(), SECINITSID_KERNEL,
- SECCLASS_SYSTEM, SYSTEM__IPC_INFO, NULL);
+ return cred_has_perm(current_cred(), SECINITSID_KERNEL,
+ SECCLASS_SYSTEM, SYSTEM__IPC_INFO,
+ NULL);
case GETPID:
case GETNCNT:
case GETZCNT:
@@ -6739,9 +6672,10 @@ static int selinux_lsm_getattr(unsigned int attr, struct task_struct *p,
static int selinux_lsm_setattr(u64 attr, void *value, size_t size)
{
+ const struct cred *cred = current_cred();
struct task_security_struct *tsec;
struct cred *new;
- u32 mysid = current_sid(), sid = 0, ptsid;
+ u32 sid = 0, ptsid;
int error;
char *str = value;
@@ -6750,23 +6684,23 @@ static int selinux_lsm_setattr(u64 attr, void *value, size_t size)
*/
switch (attr) {
case LSM_ATTR_EXEC:
- error = cred_self_has_perm(current_cred(), SECCLASS_PROCESS,
+ error = cred_self_has_perm(cred, SECCLASS_PROCESS,
PROCESS__SETEXEC, NULL);
break;
case LSM_ATTR_FSCREATE:
- error = cred_self_has_perm(current_cred(), SECCLASS_PROCESS,
+ error = cred_self_has_perm(cred, SECCLASS_PROCESS,
PROCESS__SETFSCREATE, NULL);
break;
case LSM_ATTR_KEYCREATE:
- error = cred_self_has_perm(current_cred(), SECCLASS_PROCESS,
+ error = cred_self_has_perm(cred, SECCLASS_PROCESS,
PROCESS__SETKEYCREATE, NULL);
break;
case LSM_ATTR_SOCKCREATE:
- error = cred_self_has_perm(current_cred(), SECCLASS_PROCESS,
+ error = cred_self_has_perm(cred, SECCLASS_PROCESS,
PROCESS__SETSOCKCREATE, NULL);
break;
case LSM_ATTR_CURRENT:
- error = cred_self_has_perm(current_cred(), SECCLASS_PROCESS,
+ error = cred_self_has_perm(cred, SECCLASS_PROCESS,
PROCESS__SETCURRENT, NULL);
break;
default:
@@ -6833,8 +6767,8 @@ static int selinux_lsm_setattr(u64 attr, void *value, size_t size)
tsec->create_sid = sid;
} else if (attr == LSM_ATTR_KEYCREATE) {
if (sid) {
- error = avc_has_perm(current_selinux_state, mysid, sid,
- SECCLASS_KEY, KEY__CREATE, NULL);
+ error = cred_has_perm(cred, sid, SECCLASS_KEY,
+ KEY__CREATE, NULL);
if (error)
goto abort_change;
}
@@ -7058,7 +6992,7 @@ static int selinux_key_permission(key_ref_t key_ref,
{
struct key *key;
struct key_security_struct *ksec;
- u32 perm, sid;
+ u32 perm;
switch (need_perm) {
case KEY_NEED_VIEW:
@@ -7090,12 +7024,10 @@ static int selinux_key_permission(key_ref_t key_ref,
}
- sid = cred_sid(cred);
key = key_ref_to_ptr(key_ref);
ksec = selinux_key(key);
- return avc_has_perm(cred_selinux_state(cred),
- sid, ksec->sid, SECCLASS_KEY, perm, NULL);
+ return cred_has_perm(cred, ksec->sid, SECCLASS_KEY, perm, NULL);
}
static int selinux_key_getsecurity(struct key *key, char **_buffer)
@@ -7117,10 +7049,9 @@ static int selinux_key_getsecurity(struct key *key, char **_buffer)
static int selinux_watch_key(struct key *key)
{
struct key_security_struct *ksec = selinux_key(key);
- u32 sid = current_sid();
- return avc_has_perm(current_selinux_state,
- sid, ksec->sid, SECCLASS_KEY, KEY__VIEW, NULL);
+ return cred_has_perm(current_cred(), ksec->sid, SECCLASS_KEY,
+ KEY__VIEW, NULL);
}
#endif
#endif
@@ -7186,19 +7117,17 @@ static int selinux_ib_alloc_security(void *ib_sec)
static int selinux_bpf(int cmd, union bpf_attr *attr,
unsigned int size, bool kernel)
{
- u32 sid = current_sid();
+ const struct cred *cred = current_cred();
int ret;
switch (cmd) {
case BPF_MAP_CREATE:
- ret = avc_has_perm(current_selinux_state,
- sid, sid, SECCLASS_BPF, BPF__MAP_CREATE,
- NULL);
+ ret = cred_self_has_perm(cred, SECCLASS_BPF, BPF__MAP_CREATE,
+ NULL);
break;
case BPF_PROG_LOAD:
- ret = avc_has_perm(current_selinux_state,
- sid, sid, SECCLASS_BPF, BPF__PROG_LOAD,
- NULL);
+ ret = cred_self_has_perm(cred, SECCLASS_BPF, BPF__PROG_LOAD,
+ NULL);
break;
default:
ret = 0;
@@ -7227,7 +7156,7 @@ static u32 bpf_map_fmode_to_av(fmode_t fmode)
* access the bpf object and that's why we have to add this additional check in
* selinux_file_receive and selinux_binder_transfer_files.
*/
-static int bpf_fd_pass(const struct file *file, u32 sid)
+static int bpf_fd_pass(const struct file *file, const struct cred *cred)
{
struct bpf_security_struct *bpfsec;
struct bpf_prog *prog;
@@ -7237,16 +7166,14 @@ static int bpf_fd_pass(const struct file *file, u32 sid)
if (file->f_op == &bpf_map_fops) {
map = file->private_data;
bpfsec = map->security;
- ret = avc_has_perm(current_selinux_state,
- sid, bpfsec->sid, SECCLASS_BPF,
+ ret = cred_has_perm(cred, bpfsec->sid, SECCLASS_BPF,
bpf_map_fmode_to_av(file->f_mode), NULL);
if (ret)
return ret;
} else if (file->f_op == &bpf_prog_fops) {
prog = file->private_data;
bpfsec = prog->aux->security;
- ret = avc_has_perm(current_selinux_state,
- sid, bpfsec->sid, SECCLASS_BPF,
+ ret = cred_has_perm(cred, bpfsec->sid, SECCLASS_BPF,
BPF__PROG_RUN, NULL);
if (ret)
return ret;
@@ -7256,23 +7183,19 @@ static int bpf_fd_pass(const struct file *file, u32 sid)
static int selinux_bpf_map(struct bpf_map *map, fmode_t fmode)
{
- u32 sid = current_sid();
struct bpf_security_struct *bpfsec;
bpfsec = map->security;
- return avc_has_perm(current_selinux_state,
- sid, bpfsec->sid, SECCLASS_BPF,
- bpf_map_fmode_to_av(fmode), NULL);
+ return cred_has_perm(current_cred(), bpfsec->sid, SECCLASS_BPF,
+ bpf_map_fmode_to_av(fmode), NULL);
}
static int selinux_bpf_prog(struct bpf_prog *prog)
{
- u32 sid = current_sid();
struct bpf_security_struct *bpfsec;
bpfsec = prog->aux->security;
- return avc_has_perm(current_selinux_state,
- sid, bpfsec->sid, SECCLASS_BPF,
+ return cred_has_perm(current_cred(), bpfsec->sid, SECCLASS_BPF,
BPF__PROG_RUN, NULL);
}
@@ -7366,7 +7289,7 @@ struct lsm_blob_sizes selinux_blob_sizes __ro_after_init = {
#ifdef CONFIG_PERF_EVENTS
static int selinux_perf_event_open(int type)
{
- u32 requested, sid = current_sid();
+ u32 requested;
if (type == PERF_SECURITY_OPEN)
requested = PERF_EVENT__OPEN;
@@ -7379,8 +7302,8 @@ static int selinux_perf_event_open(int type)
else
return -EINVAL;
- return avc_has_perm(current_selinux_state, sid, sid, SECCLASS_PERF_EVENT,
- requested, NULL);
+ return cred_self_has_perm(current_cred(), SECCLASS_PERF_EVENT,
+ requested, NULL);
}
static int selinux_perf_event_alloc(struct perf_event *event)
@@ -7396,19 +7319,17 @@ static int selinux_perf_event_alloc(struct perf_event *event)
static int selinux_perf_event_read(struct perf_event *event)
{
struct perf_event_security_struct *perfsec = event->security;
- u32 sid = current_sid();
- return avc_has_perm(current_selinux_state, sid, perfsec->sid,
- SECCLASS_PERF_EVENT, PERF_EVENT__READ, NULL);
+ return cred_has_perm(current_cred(), perfsec->sid,
+ SECCLASS_PERF_EVENT, PERF_EVENT__READ, NULL);
}
static int selinux_perf_event_write(struct perf_event *event)
{
struct perf_event_security_struct *perfsec = event->security;
- u32 sid = current_sid();
- return avc_has_perm(current_selinux_state, sid, perfsec->sid,
- SECCLASS_PERF_EVENT, PERF_EVENT__WRITE, NULL);
+ return cred_has_perm(current_cred(), perfsec->sid,
+ SECCLASS_PERF_EVENT, PERF_EVENT__WRITE, NULL);
}
#endif
@@ -7456,7 +7377,7 @@ static int selinux_uring_cmd(struct io_uring_cmd *ioucmd)
ad.type = LSM_AUDIT_DATA_FILE;
ad.u.file = file;
- return avc_has_perm(current_selinux_state, current_sid(), isec->sid,
+ return cred_has_perm(current_cred(), isec->sid,
SECCLASS_IO_URING, IO_URING__CMD, &ad);
}
diff --git a/security/selinux/include/avc.h b/security/selinux/include/avc.h
index 3fce5cf92b0a..95178feac52c 100644
--- a/security/selinux/include/avc.h
+++ b/security/selinux/include/avc.h
@@ -164,6 +164,12 @@ int cred_self_has_perm(const struct cred *cred, u16 tclass, u32 requested,
int cred_self_has_perm_noaudit(const struct cred *cred, u16 tclass,
u32 requested);
+int cred_has_perm(const struct cred *cred, u32 tsid, u16 tclass, u32 requested,
+ struct common_audit_data *ad);
+
+int cred_has_perm_noaudit(const struct cred *cred, u32 tsid, u16 tclass,
+ u32 requested, struct av_decision *avd);
+
u32 avc_policy_seqno(struct selinux_state *state);
#define AVC_CALLBACK_GRANT 1
--
2.50.1
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [PATCH v7 26/42] selinux: introduce cred_ssid_has_perm() and cred_other_has_perm()
2025-08-14 13:25 [PATCH v7 00/42] SELinux namespace support Stephen Smalley
` (24 preceding siblings ...)
2025-08-14 13:26 ` [PATCH v7 25/42] selinux: introduce cred_has_perm() Stephen Smalley
@ 2025-08-14 13:26 ` Stephen Smalley
2025-08-14 13:26 ` [PATCH v7 27/42] selinux: introduce task_obj_has_perm() Stephen Smalley
` (15 subsequent siblings)
41 siblings, 0 replies; 43+ messages in thread
From: Stephen Smalley @ 2025-08-14 13:26 UTC (permalink / raw)
To: selinux; +Cc: paul, omosnace, netdev, horms, Stephen Smalley
Introduce cred_ssid_has_perm() for checking permissions between
a fixed (source SID, target SID) pair against the current SELinux
namespace and all ancestors. This helper is appropriate for
checks between two object SIDs, but should NOT be used
when dealing with task/cred objects.
Introduce cred_other_has_perm() for checking permissions between
two creds against the current SELinux namespace and all
ancestors.
Convert permission checks of these two forms in the hook functions
to use these new namespace-aware helpers.
Signed-off-by: Stephen Smalley <stephen.smalley.work@gmail.com>
---
security/selinux/avc.c | 62 ++++++++++++++++++++++++++++++++++
security/selinux/hooks.c | 61 +++++++++++++--------------------
security/selinux/include/avc.h | 7 ++++
3 files changed, 93 insertions(+), 37 deletions(-)
diff --git a/security/selinux/avc.c b/security/selinux/avc.c
index 5a17c24a8466..f529d7f90c80 100644
--- a/security/selinux/avc.c
+++ b/security/selinux/avc.c
@@ -1416,6 +1416,68 @@ int cred_has_perm_noaudit(const struct cred *cred, u32 tsid, u16 tclass,
return 0;
}
+int cred_ssid_has_perm(const struct cred *cred, u32 ssid, u32 tsid, u16 tclass,
+ u32 requested, struct common_audit_data *ad)
+{
+ struct task_security_struct *tsec;
+ struct selinux_state *state;
+ int rc;
+
+ do {
+ tsec = selinux_cred(cred);
+ state = tsec->state;
+ rc = avc_has_perm(state, ssid, tsid, tclass, requested, ad);
+ if (rc)
+ return rc;
+
+ cred = tsec->parent_cred;
+ } while (cred);
+
+ return 0;
+}
+
+static u32 cred_sid_for_state(const struct cred *cred,
+ const struct selinux_state *state)
+{
+ const struct task_security_struct *tsec;
+ u32 sid;
+
+ tsec = selinux_cred(cred);
+ while (tsec->state != state && tsec->parent_cred)
+ tsec = selinux_cred(tsec->parent_cred);
+ if (tsec->state == state)
+ sid = tsec->sid;
+ else
+ sid = SECINITSID_UNLABELED;
+ return sid;
+}
+
+int cred_other_has_perm(const struct cred *cred, const struct cred *other,
+ u16 tclass, u32 requested,
+ struct common_audit_data *ad)
+{
+ struct task_security_struct *tsec;
+ struct selinux_state *state;
+ u32 ssid;
+ u32 tsid;
+ int rc;
+
+ do {
+ tsec = selinux_cred(cred);
+ ssid = tsec->sid;
+ state = tsec->state;
+ tsid = cred_sid_for_state(other, state);
+
+ rc = avc_has_perm(state, ssid, tsid, tclass, requested, ad);
+ if (rc)
+ return rc;
+
+ cred = tsec->parent_cred;
+ } while (cred);
+
+ return 0;
+}
+
u32 avc_policy_seqno(struct selinux_state *state)
{
return state->avc->avc_cache.latest_notif;
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index d759c48a8557..8dea622f9361 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -469,9 +469,8 @@ static int may_context_mount_inode_relabel(u32 sid,
if (rc)
return rc;
- return avc_has_perm(cred_selinux_state(cred),
- sid, sbsec->sid, SECCLASS_FILESYSTEM,
- FILESYSTEM__ASSOCIATE, NULL);
+ return cred_ssid_has_perm(cred, sid, sbsec->sid, SECCLASS_FILESYSTEM,
+ FILESYSTEM__ASSOCIATE, NULL);
}
static int selinux_is_genfs_special_handling(struct super_block *sb)
@@ -1858,10 +1857,9 @@ static int may_create(struct inode *dir,
if (rc)
return rc;
- return avc_has_perm(current_selinux_state,
- newsid, sbsec->sid,
- SECCLASS_FILESYSTEM,
- FILESYSTEM__ASSOCIATE, &ad);
+ return cred_ssid_has_perm(cred, newsid, sbsec->sid,
+ SECCLASS_FILESYSTEM, FILESYSTEM__ASSOCIATE,
+ &ad);
}
#define MAY_LINK 0
@@ -2050,9 +2048,8 @@ static inline u32 open_file_to_av(struct file *file)
static int selinux_binder_set_context_mgr(const struct cred *mgr)
{
- return avc_has_perm(current_selinux_state,
- current_sid(), cred_sid(mgr), SECCLASS_BINDER,
- BINDER__SET_CONTEXT_MGR, NULL);
+ return cred_other_has_perm(current_cred(), mgr, SECCLASS_BINDER,
+ BINDER__SET_CONTEXT_MGR, NULL);
}
static int selinux_binder_transaction(const struct cred *from,
@@ -2060,28 +2057,25 @@ static int selinux_binder_transaction(const struct cred *from,
{
u32 mysid = current_sid();
u32 fromsid = cred_sid(from);
- u32 tosid = cred_sid(to);
int rc;
if (mysid != fromsid) {
- rc = avc_has_perm(cred_selinux_state(from),
- mysid, fromsid, SECCLASS_BINDER,
- BINDER__IMPERSONATE, NULL);
+ rc = cred_other_has_perm(current_cred(), from,
+ SECCLASS_BINDER,
+ BINDER__IMPERSONATE, NULL);
if (rc)
return rc;
}
- return avc_has_perm(cred_selinux_state(from), fromsid, tosid,
- SECCLASS_BINDER, BINDER__CALL, NULL);
+ return cred_other_has_perm(from, to, SECCLASS_BINDER, BINDER__CALL,
+ NULL);
}
static int selinux_binder_transfer_binder(const struct cred *from,
const struct cred *to)
{
- return avc_has_perm(current_selinux_state,
- cred_sid(from), cred_sid(to),
- SECCLASS_BINDER, BINDER__TRANSFER,
- NULL);
+ return cred_other_has_perm(from, to, SECCLASS_BINDER,
+ BINDER__TRANSFER, NULL);
}
static int selinux_binder_transfer_file(const struct cred *from,
@@ -2149,9 +2143,8 @@ static int selinux_capset(struct cred *new, const struct cred *old,
const kernel_cap_t *inheritable,
const kernel_cap_t *permitted)
{
- return avc_has_perm(cred_selinux_state(old),
- cred_sid(old), cred_sid(new), SECCLASS_PROCESS,
- PROCESS__SETCAP, NULL);
+ return cred_other_has_perm(old, new, SECCLASS_PROCESS,
+ PROCESS__SETCAP, NULL);
}
/*
@@ -3424,12 +3417,9 @@ static int selinux_inode_setxattr(struct mnt_idmap *idmap,
if (rc)
return rc;
- return avc_has_perm(current_selinux_state,
- newsid,
- sbsec->sid,
- SECCLASS_FILESYSTEM,
- FILESYSTEM__ASSOCIATE,
- &ad);
+ return cred_ssid_has_perm(cred, newsid, sbsec->sid,
+ SECCLASS_FILESYSTEM,
+ FILESYSTEM__ASSOCIATE, &ad);
}
static int selinux_inode_set_acl(struct mnt_idmap *idmap,
@@ -4452,9 +4442,7 @@ static int selinux_task_prlimit(const struct cred *cred, const struct cred *tcre
av |= PROCESS__SETRLIMIT;
if (flags & LSM_PRLIMIT_READ)
av |= PROCESS__GETRLIMIT;
- return avc_has_perm(cred_selinux_state(cred),
- cred_sid(cred), cred_sid(tcred),
- SECCLASS_PROCESS, av, NULL);
+ return cred_other_has_perm(cred, tcred, SECCLASS_PROCESS, av, NULL);
}
static int selinux_task_setrlimit(struct task_struct *p, unsigned int resource,
@@ -6386,9 +6374,8 @@ static int selinux_msg_queue_msgsnd(struct kern_ipc_perm *msq, struct msg_msg *m
&ad);
if (!rc)
/* Can the message be put in the queue? */
- rc = avc_has_perm(current_selinux_state,
- msec->sid, isec->sid, SECCLASS_MSGQ,
- MSGQ__ENQUEUE, &ad);
+ rc = cred_ssid_has_perm(cred, msec->sid, isec->sid,
+ SECCLASS_MSGQ, MSGQ__ENQUEUE, &ad);
return rc;
}
@@ -7343,8 +7330,8 @@ static int selinux_perf_event_write(struct perf_event *event)
*/
static int selinux_uring_override_creds(const struct cred *new)
{
- return avc_has_perm(current_selinux_state, current_sid(), cred_sid(new),
- SECCLASS_IO_URING, IO_URING__OVERRIDE_CREDS, NULL);
+ return cred_other_has_perm(current_cred(), new, SECCLASS_IO_URING,
+ IO_URING__OVERRIDE_CREDS, NULL);
}
/**
diff --git a/security/selinux/include/avc.h b/security/selinux/include/avc.h
index 95178feac52c..3198ed11aa80 100644
--- a/security/selinux/include/avc.h
+++ b/security/selinux/include/avc.h
@@ -170,6 +170,13 @@ int cred_has_perm(const struct cred *cred, u32 tsid, u16 tclass, u32 requested,
int cred_has_perm_noaudit(const struct cred *cred, u32 tsid, u16 tclass,
u32 requested, struct av_decision *avd);
+int cred_ssid_has_perm(const struct cred *cred, u32 ssid, u32 tsid, u16 tclass,
+ u32 requested, struct common_audit_data *ad);
+
+int cred_other_has_perm(const struct cred *cred, const struct cred *other,
+ u16 tclass, u32 requested,
+ struct common_audit_data *ad);
+
u32 avc_policy_seqno(struct selinux_state *state);
#define AVC_CALLBACK_GRANT 1
--
2.50.1
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [PATCH v7 27/42] selinux: introduce task_obj_has_perm()
2025-08-14 13:25 [PATCH v7 00/42] SELinux namespace support Stephen Smalley
` (25 preceding siblings ...)
2025-08-14 13:26 ` [PATCH v7 26/42] selinux: introduce cred_ssid_has_perm() and cred_other_has_perm() Stephen Smalley
@ 2025-08-14 13:26 ` Stephen Smalley
2025-08-14 13:26 ` [PATCH v7 28/42] selinux: update bprm hooks for selinux namespaces Stephen Smalley
` (14 subsequent siblings)
41 siblings, 0 replies; 43+ messages in thread
From: Stephen Smalley @ 2025-08-14 13:26 UTC (permalink / raw)
To: selinux; +Cc: paul, omosnace, netdev, horms, Stephen Smalley
Introduce task_obj_has_perm() for namespace-aware permission checking
between two tasks using the objective SID for both tasks and
without assuming that either task is current.
Convert the permission checks of this form in the hook functions
to use this new helper.
Signed-off-by: Stephen Smalley <stephen.smalley.work@gmail.com>
---
security/selinux/avc.c | 57 ++++++++++++++++++++++++++++++++++
security/selinux/hooks.c | 5 ++-
security/selinux/include/avc.h | 3 ++
3 files changed, 62 insertions(+), 3 deletions(-)
diff --git a/security/selinux/avc.c b/security/selinux/avc.c
index f529d7f90c80..dcdbaa6e3d13 100644
--- a/security/selinux/avc.c
+++ b/security/selinux/avc.c
@@ -1290,6 +1290,63 @@ int cred_task_has_perm(const struct cred *cred, const struct task_struct *p,
return 0;
}
+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 NULL;
+ return tsec;
+}
+
+int task_obj_has_perm(const struct task_struct *s,
+ const struct task_struct *t,
+ u16 tclass, u32 requested,
+ struct common_audit_data *ad)
+{
+ const struct cred *cred;
+ const struct task_security_struct *tsec;
+ struct selinux_state *state;
+ u32 ssid;
+ u32 tsid;
+ int rc;
+
+ state = current_selinux_state;
+ rcu_read_lock();
+ tsec = task_security(s);
+ if (tsec)
+ ssid = tsec->sid;
+ else
+ ssid = SECINITSID_UNLABELED;
+
+ do {
+ tsid = task_sid_obj_for_state(t, state);
+
+ rc = avc_has_perm(state, ssid, tsid, tclass, requested, ad);
+ if (rc)
+ break;
+
+ if (!tsec)
+ break;
+
+ cred = tsec->parent_cred;
+ if (!cred)
+ break;
+
+ tsec = selinux_cred(cred);
+ ssid = tsec->sid;
+ state = tsec->state;
+ } while (cred);
+
+ rcu_read_unlock();
+ return rc;
+}
+
+
int cred_has_extended_perms(const struct cred *cred, u32 tsid, u16 tclass,
u32 requested, u8 driver, u8 base_perm, u8 xperm,
struct common_audit_data *ad)
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 8dea622f9361..d062ee0908a6 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2126,9 +2126,8 @@ static int selinux_ptrace_access_check(struct task_struct *child,
static int selinux_ptrace_traceme(struct task_struct *parent)
{
- return avc_has_perm(current_selinux_state,
- task_sid_obj(parent), task_sid_obj(current),
- SECCLASS_PROCESS, PROCESS__PTRACE, NULL);
+ return task_obj_has_perm(parent, current, SECCLASS_PROCESS,
+ PROCESS__PTRACE, NULL);
}
static int selinux_capget(const struct task_struct *target, kernel_cap_t *effective,
diff --git a/security/selinux/include/avc.h b/security/selinux/include/avc.h
index 3198ed11aa80..a06e89ec1bfe 100644
--- a/security/selinux/include/avc.h
+++ b/security/selinux/include/avc.h
@@ -177,6 +177,9 @@ int cred_other_has_perm(const struct cred *cred, const struct cred *other,
u16 tclass, u32 requested,
struct common_audit_data *ad);
+int task_obj_has_perm(const struct task_struct *s, const struct task_struct *t,
+ u16 tclass, u32 requested, struct common_audit_data *ad);
+
u32 avc_policy_seqno(struct selinux_state *state);
#define AVC_CALLBACK_GRANT 1
--
2.50.1
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [PATCH v7 28/42] selinux: update bprm hooks for selinux namespaces
2025-08-14 13:25 [PATCH v7 00/42] SELinux namespace support Stephen Smalley
` (26 preceding siblings ...)
2025-08-14 13:26 ` [PATCH v7 27/42] selinux: introduce task_obj_has_perm() Stephen Smalley
@ 2025-08-14 13:26 ` Stephen Smalley
2025-08-14 13:26 ` [PATCH v7 29/42] selinux: add kerneldoc to new permission checking functions Stephen Smalley
` (13 subsequent siblings)
41 siblings, 0 replies; 43+ messages in thread
From: Stephen Smalley @ 2025-08-14 13:26 UTC (permalink / raw)
To: selinux; +Cc: paul, omosnace, netdev, horms, Stephen Smalley
Update the bprm hook functions for SELinux namespaces.
Unlike most of the hook functions, this does not require
converting all of the permission checks to use the new
helpers that check permissions against the current and
all ancestor namespaces. Instead, we only need to check
the transition-related permissions against the current
namespace since only the SID in that current namespace
is changed by a transition. However, we do want to
check execute_no_trans against the ancestor namespaces
since they are not transitioning; hence, a check
is added to the end of selinux_bprm_creds_for_exec()
for that purpose. Otherwise, we just document the
fact that we are intentionally only checking against
the current SELinux namespace for the other checks.
Signed-off-by: Stephen Smalley <stephen.smalley.work@gmail.com>
---
security/selinux/hooks.c | 38 +++++++++++++++++++++++++++++++++++++-
1 file changed, 37 insertions(+), 1 deletion(-)
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index d062ee0908a6..07bf35c14ae2 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2283,6 +2283,11 @@ static int check_nnp_nosuid(const struct linux_binprm *bprm,
av |= PROCESS2__NNP_TRANSITION;
if (nosuid)
av |= PROCESS2__NOSUID_TRANSITION;
+ /*
+ * Only check against the current SELinux namespace
+ * because only the SID in the current namespace
+ * is changed by a transition.
+ */
rc = avc_has_perm(current_selinux_state,
old_tsec->sid, new_tsec->sid,
SECCLASS_PROCESS2, av, NULL);
@@ -2312,6 +2317,7 @@ static int check_nnp_nosuid(const struct linux_binprm *bprm,
static int selinux_bprm_creds_for_exec(struct linux_binprm *bprm)
{
+ const struct cred *cred = current_cred();
const struct task_security_struct *old_tsec;
struct task_security_struct *new_tsec;
struct inode_security_struct *isec;
@@ -2322,7 +2328,7 @@ static int selinux_bprm_creds_for_exec(struct linux_binprm *bprm)
/* SELinux context only depends on initial program or script and not
* the script interpreter */
- old_tsec = selinux_cred(current_cred());
+ old_tsec = selinux_cred(cred);
new_tsec = selinux_cred(bprm->cred);
isec = inode_security(inode);
@@ -2378,12 +2384,23 @@ static int selinux_bprm_creds_for_exec(struct linux_binprm *bprm)
ad.u.file = bprm->file;
if (new_tsec->sid == old_tsec->sid) {
+ /*
+ * Only check against the current SELinux namespace
+ * because only the SID in the current namespace
+ * is changed by a transition.
+ */
rc = avc_has_perm(current_selinux_state,
old_tsec->sid, isec->sid,
SECCLASS_FILE, FILE__EXECUTE_NO_TRANS, &ad);
if (rc)
return rc;
} else {
+ /*
+ * Only check against the current SELinux namespace
+ * because only the SID in the current namespace
+ * is changed by a transition.
+ */
+
/* Check permissions for the transition. */
rc = avc_has_perm(current_selinux_state,
old_tsec->sid, new_tsec->sid,
@@ -2434,6 +2451,19 @@ static int selinux_bprm_creds_for_exec(struct linux_binprm *bprm)
bprm->secureexec |= !!rc;
}
+ /*
+ * If in a non-init namespace, also check the ability of the
+ * ancestors to execute without transitioning since the SID
+ * in ancestor namespaces is NOT modified.
+ */
+ cred = old_tsec->parent_cred;
+ if (cred) {
+ rc = cred_has_perm(cred, isec->sid,
+ SECCLASS_FILE, FILE__EXECUTE_NO_TRANS, &ad);
+ if (rc)
+ return rc;
+ }
+
return 0;
}
@@ -2520,6 +2550,9 @@ static void selinux_bprm_committing_creds(const struct linux_binprm *bprm)
* higher than the default soft limit for cases where the default is
* lower than the hard limit, e.g. RLIMIT_CORE or RLIMIT_STACK.
*/
+ /* Only check against the current namespace because the SID
+ * does not change in the parent.
+ */
rc = avc_has_perm(current_selinux_state,
new_tsec->osid, new_tsec->sid, SECCLASS_PROCESS,
PROCESS__RLIMITINH, NULL);
@@ -2560,6 +2593,9 @@ static void selinux_bprm_committed_creds(const struct linux_binprm *bprm)
* This must occur _after_ the task SID has been updated so that any
* kill done after the flush will be checked against the new SID.
*/
+ /* Only check against the current namespace because the SID
+ * does not change in the parent.
+ */
rc = avc_has_perm(current_selinux_state,
osid, sid, SECCLASS_PROCESS, PROCESS__SIGINH, NULL);
if (rc) {
--
2.50.1
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [PATCH v7 29/42] selinux: add kerneldoc to new permission checking functions
2025-08-14 13:25 [PATCH v7 00/42] SELinux namespace support Stephen Smalley
` (27 preceding siblings ...)
2025-08-14 13:26 ` [PATCH v7 28/42] selinux: update bprm hooks for selinux namespaces Stephen Smalley
@ 2025-08-14 13:26 ` Stephen Smalley
2025-08-14 13:26 ` [PATCH v7 30/42] selinux: convert selinux_file_send_sigiotask() to namespace-aware helper Stephen Smalley
` (12 subsequent siblings)
41 siblings, 0 replies; 43+ messages in thread
From: Stephen Smalley @ 2025-08-14 13:26 UTC (permalink / raw)
To: selinux; +Cc: paul, omosnace, netdev, horms, Stephen Smalley
Add kerneldoc to new namespace-aware permission checking
functions.
Signed-off-by: Stephen Smalley <stephen.smalley.work@gmail.com>
---
security/selinux/avc.c | 145 ++++++++++++++++++++++++++++++++-
security/selinux/include/avc.h | 3 +-
2 files changed, 145 insertions(+), 3 deletions(-)
diff --git a/security/selinux/avc.c b/security/selinux/avc.c
index dcdbaa6e3d13..5d9b7b22770f 100644
--- a/security/selinux/avc.c
+++ b/security/selinux/avc.c
@@ -1264,6 +1264,21 @@ static u32 task_sid_obj_for_state(const struct task_struct *p,
return sid;
}
+/**
+ * cred_task_has_perm - Check and audit permissions on a (cred, task) pair
+ * @cred: subject credentials
+ * @p: target task
+ * @tclass: target security class
+ * @requested: requested permissions, interpreted based on @tclass
+ * @ad: auxiliary audit data
+ *
+ * Check permissions between a cred @cred and a task @p for @cred's namespace
+ * and all ancestors to determine whether the @requested permissions are
+ * granted.
+ * Audit the granting or denial of permissions in accordance with the policy.
+ * Return %0 if all @requested permissions are granted, -%EACCES if any
+ * permissions are denied, or another -errno upon other errors.
+ */
int cred_task_has_perm(const struct cred *cred, const struct task_struct *p,
u16 tclass, u32 requested,
struct common_audit_data *ad)
@@ -1303,6 +1318,22 @@ static const struct task_security_struct *task_security(
return tsec;
}
+/**
+ * task_obj_has_perm - Check and audit permissions on a (task, other-task) pair
+ * @s: source task
+ * @t: target task
+ * @tclass: target security class
+ * @requested: requested permissions, interpreted based on @tclass
+ * @ad: auxiliary audit data
+ *
+ * Check permissions between a task @s and a task @t for the current namespace
+ * and all ancestors to determine whether the @requested permissions are
+ * granted.
+ * Audit the granting or denial of permissions in accordance with the policy.
+ * Return %0 if all @requested permissions are granted, -%EACCES if any
+ * permissions are denied, or another -errno upon other errors.
+ * DO NOT USE when @s is current; use cred_task_has_perm() instead.
+ */
int task_obj_has_perm(const struct task_struct *s,
const struct task_struct *t,
u16 tclass, u32 requested,
@@ -1346,7 +1377,25 @@ int task_obj_has_perm(const struct task_struct *s,
return rc;
}
-
+/**
+ * cred_has_extended_perms - Check and audit extended permissions on a (cred, tsid) pair
+ * @cred: subject credentials
+ * @tsid: target security identifier
+ * @tclass: target security class
+ * @requested: requested permissions, interpreted based on @tclass
+ * @driver: driver value
+ * @base_perm: the base permission associated with the extended permission
+ * @xperm: extended permission value
+ * @ad: auxiliary audit data
+ *
+ * Check extended permissions between a cred @cred and a target
+ * security identifier @tsid for @cred's namespace and all ancestors
+ * to determine whether the @requested permissions are granted for the
+ * specified (@driver, @xperm) pair.
+ * Audit the granting or denial of permissions in accordance with the policy.
+ * Return %0 if the @requested permissions are granted, -%EACCES if any
+ * permissions are denied, or another -errno upon other errors.
+ */
int cred_has_extended_perms(const struct cred *cred, u32 tsid, u16 tclass,
u32 requested, u8 driver, u8 base_perm, u8 xperm,
struct common_audit_data *ad)
@@ -1373,6 +1422,20 @@ int cred_has_extended_perms(const struct cred *cred, u32 tsid, u16 tclass,
return 0;
}
+/**
+ * cred_self_has_perm - Check and audit permissions on a (cred, self) pair
+ * @cred: subject credentials
+ * @tclass: target security class
+ * @requested: requested permissions, interpreted based on @tclass
+ * @ad: auxiliary audit data
+ *
+ * Check permissions between a cred @cred and itself for @cred's namespace
+ * and all ancestors to determine whether the @requested permissions are
+ * granted.
+ * Audit the granting or denial of permissions in accordance with the policy.
+ * Return %0 if all @requested permissions are granted, -%EACCES if any
+ * permissions are denied, or another -errno upon other errors.
+ */
int cred_self_has_perm(const struct cred *cred, u16 tclass, u32 requested,
struct common_audit_data *ad)
{
@@ -1395,6 +1458,18 @@ int cred_self_has_perm(const struct cred *cred, u16 tclass, u32 requested,
return 0;
}
+/**
+ * cred_self_has_perm_noaudit - Check permissions on a (cred, self) pair, no audit
+ * @cred: subject credentials
+ * @tclass: target security class
+ * @requested: requested permissions, interpreted based on @tclass
+ *
+ * Check permissions between a cred @cred and itself for @cred's namespace
+ * and all ancestors to determine whether the @requested permissions are
+ * granted.
+ * Return %0 if all @requested permissions are granted, -%EACCES if any
+ * permissions are denied, or another -errno upon other errors.
+ */
int cred_self_has_perm_noaudit(const struct cred *cred, u16 tclass,
u32 requested)
{
@@ -1420,6 +1495,25 @@ int cred_self_has_perm_noaudit(const struct cred *cred, u16 tclass,
return 0;
}
+
+/**
+ * cred_has_perm - Check and audit permissions on a (cred, tsid) pair
+ * @cred: subject credentials
+ * @tsid: target security identifier
+ * @tclass: target security class
+ * @requested: requested permissions, interpreted based on @tclass
+ * @ad: auxiliary audit data
+ *
+ * Check permissions between a cred @cred and a target SID @tsid for
+ * @cred's namespace and all ancestors to determine whether the
+ * @requested permissions are granted, interpreting the permissions based
+ * on @tclass.
+ * Audit the granting or denial of permissions in accordance with the policy.
+ * Return %0 if all @requested permissions are granted, -%EACCES if any
+ * permissions are denied, or another -errno upon other errors.
+ * DO NOT USE when checking permissions between two creds (or tasks);
+ * use cred_other_has_perm() or cred_task_has_perm() instead.
+ */
int cred_has_perm(const struct cred *cred, u32 tsid, u16 tclass,
u32 requested, struct common_audit_data *ad)
{
@@ -1442,6 +1536,22 @@ int cred_has_perm(const struct cred *cred, u32 tsid, u16 tclass,
return 0;
}
+/**
+ * cred_has_perm_noaudit - Check permissions on a (cred, tsid) pair, no audit
+ * @cred: subject credentials
+ * @tsid: target security identifier
+ * @tclass: target security class
+ * @requested: requested permissions, interpreted based on @tclass
+ * @avd: access vector decisions
+ *
+ * Check permissions between a cred @cred and a target SID @tsid for
+ * @cred's namespace and all ancestors to determine whether the
+ * @requested permissions are granted.
+ * Return %0 if all @requested permissions are granted, -%EACCES if any
+ * permissions are denied, or another -errno upon other errors.
+ * DO NOT USE when checking permissions between two creds (or tasks);
+ * use cred_other_has_perm() or cred_task_has_perm() instead.
+ */
int cred_has_perm_noaudit(const struct cred *cred, u32 tsid, u16 tclass,
u32 requested, struct av_decision *avd)
{
@@ -1473,6 +1583,24 @@ int cred_has_perm_noaudit(const struct cred *cred, u32 tsid, u16 tclass,
return 0;
}
+/**
+ * cred_ssid_has_perm - Check and audit permissions on a (ssid, tsid) pair
+ * @cred: subject credentials
+ * @ssid: source security identifier
+ * @tsid: target security identifier
+ * @tclass: target security class
+ * @requested: requested permissions, interpreted based on @tclass
+ * @ad: auxiliary audit data
+ *
+ * Check permissions between a source SID @ssid and a target SID @tsid for
+ * @cred's namespace and all ancestors to determine whether the
+ * @requested permissions are granted.
+ * Audit the granting or denial of permissions in accordance with the policy.
+ * Return %0 if all @requested permissions are granted, -%EACCES if any
+ * permissions are denied, or another -errno upon other errors.
+ * DO NOT USE when checking permissions involving cred/task SIDs; this
+ * helper is only for object-to-object checks.
+ */
int cred_ssid_has_perm(const struct cred *cred, u32 ssid, u32 tsid, u16 tclass,
u32 requested, struct common_audit_data *ad)
{
@@ -1509,6 +1637,21 @@ static u32 cred_sid_for_state(const struct cred *cred,
return sid;
}
+/**
+ * cred_other_has_perm - Check and audit permissions on a (cred, other-cred) pair
+ * @cred: subject credentials
+ * @other: other credentials
+ * @tclass: target security class
+ * @requested: requested permissions, interpreted based on @tclass
+ * @ad: auxiliary audit data
+ *
+ * Check permissions between a cred @cred and a task @p for @cred's namespace
+ * and all ancestors to determine whether the @requested permissions are
+ * granted.
+ * Audit the granting or denial of permissions in accordance with the policy.
+ * Return %0 if all @requested permissions are granted, -%EACCES if any
+ * permissions are denied, or another -errno upon other errors.
+ */
int cred_other_has_perm(const struct cred *cred, const struct cred *other,
u16 tclass, u32 requested,
struct common_audit_data *ad)
diff --git a/security/selinux/include/avc.h b/security/selinux/include/avc.h
index a06e89ec1bfe..fd8c6b3a32df 100644
--- a/security/selinux/include/avc.h
+++ b/security/selinux/include/avc.h
@@ -151,8 +151,7 @@ int avc_has_extended_perms(struct selinux_state *state, u32 ssid, u32 tsid,
u8 perm, struct common_audit_data *ad);
int cred_task_has_perm(const struct cred *cred, const struct task_struct *p,
- u16 tclass, u32 requested,
- struct common_audit_data *auditdata);
+ u16 tclass, u32 requested, struct common_audit_data *ad);
int cred_has_extended_perms(const struct cred *cred, u32 tsid, u16 tclass,
u32 requested, u8 driver, u8 base_perm, u8 xperm,
--
2.50.1
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [PATCH v7 30/42] selinux: convert selinux_file_send_sigiotask() to namespace-aware helper
2025-08-14 13:25 [PATCH v7 00/42] SELinux namespace support Stephen Smalley
` (28 preceding siblings ...)
2025-08-14 13:26 ` [PATCH v7 29/42] selinux: add kerneldoc to new permission checking functions Stephen Smalley
@ 2025-08-14 13:26 ` Stephen Smalley
2025-08-14 13:26 ` [PATCH v7 31/42] selinux: rename cred_has_perm*() to cred_tsid_has_perm*() Stephen Smalley
` (11 subsequent siblings)
41 siblings, 0 replies; 43+ messages in thread
From: Stephen Smalley @ 2025-08-14 13:26 UTC (permalink / raw)
To: selinux; +Cc: paul, omosnace, netdev, horms, Stephen Smalley
Convert selinux_file_send_sigiotask() to use the cred_task_has_perm()
namespace-aware permission checking helper. This required saving the
file owner cred in the file security blob for later use in this hook
function. Since the cred already includes the cred/task security blob
which has the task SID and the SELinux state/namespace, we can drop
those separate fields from the file_security_struct at the same time.
Signed-off-by: Stephen Smalley <stephen.smalley.work@gmail.com>
---
security/selinux/hooks.c | 15 ++++++---------
security/selinux/include/objsec.h | 3 +--
2 files changed, 7 insertions(+), 11 deletions(-)
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 07bf35c14ae2..3c487b48e510 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -3849,8 +3849,7 @@ static int selinux_file_alloc_security(struct file *file)
u32 sid = current_sid();
fsec->sid = sid;
- fsec->fown_sid = sid;
- fsec->state = get_selinux_state(current_selinux_state);
+ fsec->cred = get_cred(current_cred());
return 0;
}
@@ -3859,8 +3858,7 @@ static void selinux_file_free_security(struct file *file)
{
struct file_security_struct *fsec = selinux_file(file);
- put_selinux_state(fsec->state);
- fsec->state = NULL;
+ put_cred(fsec->cred);
}
/*
@@ -4143,14 +4141,14 @@ static void selinux_file_set_fowner(struct file *file)
struct file_security_struct *fsec;
fsec = selinux_file(file);
- fsec->fown_sid = current_sid();
+ put_cred(fsec->cred);
+ fsec->cred = get_cred(current_cred());
}
static int selinux_file_send_sigiotask(struct task_struct *tsk,
struct fown_struct *fown, int signum)
{
struct file *file;
- u32 sid = task_sid_obj(tsk);
u32 perm;
struct file_security_struct *fsec;
@@ -4164,9 +4162,8 @@ static int selinux_file_send_sigiotask(struct task_struct *tsk,
else
perm = signal_to_av(signum);
- return avc_has_perm(fsec->state,
- fsec->fown_sid, sid,
- SECCLASS_PROCESS, perm, NULL);
+ return cred_task_has_perm(fsec->cred, tsk, SECCLASS_PROCESS, perm,
+ NULL);
}
static int selinux_file_receive(struct file *file)
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h
index 662329923214..9975a13700c5 100644
--- a/security/selinux/include/objsec.h
+++ b/security/selinux/include/objsec.h
@@ -55,10 +55,9 @@ struct inode_security_struct {
struct file_security_struct {
u32 sid; /* SID of open file description */
- u32 fown_sid; /* SID of file owner (for SIGIO) */
u32 isid; /* SID of inode at the time of file open */
u32 pseqno; /* Policy seqno at the time of file open */
- struct selinux_state *state; /* SELinux state */
+ const struct cred *cred; /* cred for file owner (for SIGIO) */
};
struct superblock_security_struct {
--
2.50.1
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [PATCH v7 31/42] selinux: rename cred_has_perm*() to cred_tsid_has_perm*()
2025-08-14 13:25 [PATCH v7 00/42] SELinux namespace support Stephen Smalley
` (29 preceding siblings ...)
2025-08-14 13:26 ` [PATCH v7 30/42] selinux: convert selinux_file_send_sigiotask() to namespace-aware helper Stephen Smalley
@ 2025-08-14 13:26 ` Stephen Smalley
2025-08-14 13:26 ` [PATCH v7 32/42] selinux: update cred_tsid_has_perm_noaudit() to return the combined avd Stephen Smalley
` (10 subsequent siblings)
41 siblings, 0 replies; 43+ messages in thread
From: Stephen Smalley @ 2025-08-14 13:26 UTC (permalink / raw)
To: selinux; +Cc: paul, omosnace, netdev, horms, Stephen Smalley
Rename cred_has_perm*() to cred_tsid_has_perm*() for greater
clarity and parallelism with the other helper functions.
These functions check permissions between a cred and a fixed
target SID for the current namespace and its ancestors.
Signed-off-by: Stephen Smalley <stephen.smalley.work@gmail.com>
---
security/selinux/avc.c | 12 +-
security/selinux/hooks.c | 239 +++++++++++++++++----------------
security/selinux/include/avc.h | 8 +-
3 files changed, 130 insertions(+), 129 deletions(-)
diff --git a/security/selinux/avc.c b/security/selinux/avc.c
index 5d9b7b22770f..e153f0122b4d 100644
--- a/security/selinux/avc.c
+++ b/security/selinux/avc.c
@@ -1497,7 +1497,7 @@ int cred_self_has_perm_noaudit(const struct cred *cred, u16 tclass,
/**
- * cred_has_perm - Check and audit permissions on a (cred, tsid) pair
+ * cred_tsid_has_perm - Check and audit permissions on a (cred, tsid) pair
* @cred: subject credentials
* @tsid: target security identifier
* @tclass: target security class
@@ -1514,8 +1514,8 @@ int cred_self_has_perm_noaudit(const struct cred *cred, u16 tclass,
* DO NOT USE when checking permissions between two creds (or tasks);
* use cred_other_has_perm() or cred_task_has_perm() instead.
*/
-int cred_has_perm(const struct cred *cred, u32 tsid, u16 tclass,
- u32 requested, struct common_audit_data *ad)
+int cred_tsid_has_perm(const struct cred *cred, u32 tsid, u16 tclass,
+ u32 requested, struct common_audit_data *ad)
{
struct task_security_struct *tsec;
struct selinux_state *state;
@@ -1537,7 +1537,7 @@ int cred_has_perm(const struct cred *cred, u32 tsid, u16 tclass,
}
/**
- * cred_has_perm_noaudit - Check permissions on a (cred, tsid) pair, no audit
+ * cred_tsid_has_perm_noaudit - Check permissions on a (cred, tsid) pair, no audit
* @cred: subject credentials
* @tsid: target security identifier
* @tclass: target security class
@@ -1552,8 +1552,8 @@ int cred_has_perm(const struct cred *cred, u32 tsid, u16 tclass,
* DO NOT USE when checking permissions between two creds (or tasks);
* use cred_other_has_perm() or cred_task_has_perm() instead.
*/
-int cred_has_perm_noaudit(const struct cred *cred, u32 tsid, u16 tclass,
- u32 requested, struct av_decision *avd)
+int cred_tsid_has_perm_noaudit(const struct cred *cred, u32 tsid, u16 tclass,
+ u32 requested, struct av_decision *avd)
{
struct task_security_struct *tsec;
struct selinux_state *state;
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 3c487b48e510..f229a8099167 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -448,13 +448,13 @@ static int may_context_mount_sb_relabel(u32 sid,
{
int rc;
- rc = cred_has_perm(cred, sbsec->sid, SECCLASS_FILESYSTEM,
- FILESYSTEM__RELABELFROM, NULL);
+ rc = cred_tsid_has_perm(cred, sbsec->sid, SECCLASS_FILESYSTEM,
+ FILESYSTEM__RELABELFROM, NULL);
if (rc)
return rc;
- rc = cred_has_perm(cred, sid, SECCLASS_FILESYSTEM,
- FILESYSTEM__RELABELTO, NULL);
+ rc = cred_tsid_has_perm(cred, sid, SECCLASS_FILESYSTEM,
+ FILESYSTEM__RELABELTO, NULL);
return rc;
}
@@ -464,8 +464,8 @@ static int may_context_mount_inode_relabel(u32 sid,
{
int rc;
- rc = cred_has_perm(cred, sbsec->sid, SECCLASS_FILESYSTEM,
- FILESYSTEM__RELABELFROM, NULL);
+ rc = cred_tsid_has_perm(cred, sbsec->sid, SECCLASS_FILESYSTEM,
+ FILESYSTEM__RELABELFROM, NULL);
if (rc)
return rc;
@@ -1695,7 +1695,7 @@ static int inode_has_perm(const struct cred *cred,
isec = selinux_inode(inode);
- return cred_has_perm(cred, isec->sid, isec->sclass, perms, adp);
+ return cred_tsid_has_perm(cred, isec->sid, isec->sclass, perms, adp);
}
/* Same as inode_has_perm, but pass explicit audit data containing
@@ -1774,8 +1774,8 @@ static int file_has_perm(const struct cred *cred,
ad.u.file = file;
if (sid != fsec->sid) {
- rc = cred_has_perm(cred, fsec->sid, SECCLASS_FD, FD__USE,
- &ad);
+ rc = cred_tsid_has_perm(cred, fsec->sid, SECCLASS_FD, FD__USE,
+ &ad);
if (rc)
goto out;
}
@@ -1842,9 +1842,9 @@ static int may_create(struct inode *dir,
ad.type = LSM_AUDIT_DATA_DENTRY;
ad.u.dentry = dentry;
- rc = cred_has_perm(cred, dsec->sid, SECCLASS_DIR,
- DIR__ADD_NAME | DIR__SEARCH,
- &ad);
+ rc = cred_tsid_has_perm(cred, dsec->sid, SECCLASS_DIR,
+ DIR__ADD_NAME | DIR__SEARCH,
+ &ad);
if (rc)
return rc;
@@ -1853,7 +1853,7 @@ static int may_create(struct inode *dir,
if (rc)
return rc;
- rc = cred_has_perm(cred, newsid, tclass, FILE__CREATE, &ad);
+ rc = cred_tsid_has_perm(cred, newsid, tclass, FILE__CREATE, &ad);
if (rc)
return rc;
@@ -1886,7 +1886,7 @@ static int may_link(struct inode *dir,
av = DIR__SEARCH;
av |= (kind ? DIR__REMOVE_NAME : DIR__ADD_NAME);
- rc = cred_has_perm(cred, dsec->sid, SECCLASS_DIR, av, &ad);
+ rc = cred_tsid_has_perm(cred, dsec->sid, SECCLASS_DIR, av, &ad);
if (rc)
return rc;
@@ -1906,7 +1906,7 @@ static int may_link(struct inode *dir,
return 0;
}
- return cred_has_perm(cred, isec->sid, isec->sclass, av, &ad);
+ return cred_tsid_has_perm(cred, isec->sid, isec->sclass, av, &ad);
}
static inline int may_rename(struct inode *old_dir,
@@ -1929,17 +1929,17 @@ static inline int may_rename(struct inode *old_dir,
ad.type = LSM_AUDIT_DATA_DENTRY;
ad.u.dentry = old_dentry;
- rc = cred_has_perm(cred, old_dsec->sid, SECCLASS_DIR,
- DIR__REMOVE_NAME | DIR__SEARCH, &ad);
+ rc = cred_tsid_has_perm(cred, old_dsec->sid, SECCLASS_DIR,
+ DIR__REMOVE_NAME | DIR__SEARCH, &ad);
if (rc)
return rc;
- rc = cred_has_perm(cred, old_isec->sid, old_isec->sclass,
- FILE__RENAME, &ad);
+ rc = cred_tsid_has_perm(cred, old_isec->sid, old_isec->sclass,
+ FILE__RENAME, &ad);
if (rc)
return rc;
if (old_is_dir && new_dir != old_dir) {
- rc = cred_has_perm(cred, old_isec->sid, old_isec->sclass,
- DIR__REPARENT, &ad);
+ rc = cred_tsid_has_perm(cred, old_isec->sid, old_isec->sclass,
+ DIR__REPARENT, &ad);
if (rc)
return rc;
}
@@ -1948,15 +1948,15 @@ static inline int may_rename(struct inode *old_dir,
av = DIR__ADD_NAME | DIR__SEARCH;
if (d_is_positive(new_dentry))
av |= DIR__REMOVE_NAME;
- rc = cred_has_perm(cred, new_dsec->sid, SECCLASS_DIR, av, &ad);
+ rc = cred_tsid_has_perm(cred, new_dsec->sid, SECCLASS_DIR, av, &ad);
if (rc)
return rc;
if (d_is_positive(new_dentry)) {
new_isec = backing_inode_security(new_dentry);
new_is_dir = d_is_dir(new_dentry);
- rc = cred_has_perm(cred, new_isec->sid, new_isec->sclass,
- (new_is_dir ? DIR__RMDIR : FILE__UNLINK),
- &ad);
+ rc = cred_tsid_has_perm(cred, new_isec->sid, new_isec->sclass,
+ (new_is_dir ? DIR__RMDIR : FILE__UNLINK),
+ &ad);
if (rc)
return rc;
}
@@ -1973,8 +1973,8 @@ static int superblock_has_perm(const struct cred *cred,
struct superblock_security_struct *sbsec;
sbsec = selinux_superblock(sb);
- return cred_has_perm(cred, sbsec->sid, SECCLASS_FILESYSTEM, perms,
- ad);
+ return cred_tsid_has_perm(cred, sbsec->sid, SECCLASS_FILESYSTEM, perms,
+ ad);
}
/* Convert a Linux mode and permission mask to an access vector. */
@@ -2093,8 +2093,8 @@ static int selinux_binder_transfer_file(const struct cred *from,
ad.u.path = file->f_path;
if (sid != fsec->sid) {
- rc = cred_has_perm(to, fsec->sid, SECCLASS_FD, FD__USE,
- &ad);
+ rc = cred_tsid_has_perm(to, fsec->sid, SECCLASS_FD, FD__USE,
+ &ad);
if (rc)
return rc;
}
@@ -2109,8 +2109,8 @@ static int selinux_binder_transfer_file(const struct cred *from,
return 0;
isec = backing_inode_security(dentry);
- return cred_has_perm(to, isec->sid, isec->sclass, file_to_av(file),
- &ad);
+ return cred_tsid_has_perm(to, isec->sid, isec->sclass, file_to_av(file),
+ &ad);
}
static int selinux_ptrace_access_check(struct task_struct *child,
@@ -2211,20 +2211,20 @@ static int selinux_syslog(int type)
switch (type) {
case SYSLOG_ACTION_READ_ALL: /* Read last kernel messages */
case SYSLOG_ACTION_SIZE_BUFFER: /* Return size of the log buffer */
- return cred_has_perm(cred, SECINITSID_KERNEL,
- SECCLASS_SYSTEM,
- SYSTEM__SYSLOG_READ, NULL);
+ return cred_tsid_has_perm(cred, SECINITSID_KERNEL,
+ SECCLASS_SYSTEM,
+ SYSTEM__SYSLOG_READ, NULL);
case SYSLOG_ACTION_CONSOLE_OFF: /* Disable logging to console */
case SYSLOG_ACTION_CONSOLE_ON: /* Enable logging to console */
/* Set level of messages printed to console */
case SYSLOG_ACTION_CONSOLE_LEVEL:
- return cred_has_perm(cred, SECINITSID_KERNEL,
- SECCLASS_SYSTEM,
- SYSTEM__SYSLOG_CONSOLE, NULL);
+ return cred_tsid_has_perm(cred, SECINITSID_KERNEL,
+ SECCLASS_SYSTEM,
+ SYSTEM__SYSLOG_CONSOLE, NULL);
}
/* All other syslog types */
- return cred_has_perm(cred, SECINITSID_KERNEL, SECCLASS_SYSTEM,
- SYSTEM__SYSLOG_MOD, NULL);
+ return cred_tsid_has_perm(cred, SECINITSID_KERNEL, SECCLASS_SYSTEM,
+ SYSTEM__SYSLOG_MOD, NULL);
}
/*
@@ -2458,8 +2458,8 @@ static int selinux_bprm_creds_for_exec(struct linux_binprm *bprm)
*/
cred = old_tsec->parent_cred;
if (cred) {
- rc = cred_has_perm(cred, isec->sid,
- SECCLASS_FILE, FILE__EXECUTE_NO_TRANS, &ad);
+ rc = cred_tsid_has_perm(cred, isec->sid,
+ SECCLASS_FILE, FILE__EXECUTE_NO_TRANS, &ad);
if (rc)
return rc;
}
@@ -3070,8 +3070,8 @@ static int selinux_inode_init_security_anon(struct inode *inode,
ad.type = LSM_AUDIT_DATA_ANONINODE;
ad.u.anonclass = name ? (const char *)name->name : "?";
- return cred_has_perm(current_cred(), isec->sid, isec->sclass,
- FILE__CREATE, &ad);
+ return cred_tsid_has_perm(current_cred(), isec->sid, isec->sclass,
+ FILE__CREATE, &ad);
}
static int selinux_inode_create(struct inode *dir, struct dentry *dentry, umode_t mode)
@@ -3134,8 +3134,8 @@ static int selinux_inode_follow_link(struct dentry *dentry, struct inode *inode,
if (IS_ERR(isec))
return PTR_ERR(isec);
- return cred_has_perm(current_cred(), isec->sid, isec->sclass,
- FILE__READ, &ad);
+ return cred_tsid_has_perm(current_cred(), isec->sid, isec->sclass,
+ FILE__READ, &ad);
}
static noinline int audit_inode_permission(struct inode *inode,
@@ -3284,8 +3284,8 @@ static int selinux_inode_permission(struct inode *inode, int requested)
struct av_decision avd;
/* Cache miss. */
- rc = cred_has_perm_noaudit(current_cred(), isec->sid,
- isec->sclass, perms, &avd);
+ rc = cred_tsid_has_perm_noaudit(current_cred(), isec->sid,
+ isec->sclass, perms, &avd);
audited = avc_audit_required(perms, &avd, rc,
(requested & MAY_ACCESS) ? FILE__AUDIT_ACCESS : 0,
&denied);
@@ -3402,8 +3402,8 @@ static int selinux_inode_setxattr(struct mnt_idmap *idmap,
ad.u.dentry = dentry;
isec = backing_inode_security(dentry);
- rc = cred_has_perm(cred, isec->sid, isec->sclass, FILE__RELABELFROM,
- &ad);
+ rc = cred_tsid_has_perm(cred, isec->sid, isec->sclass, FILE__RELABELFROM,
+ &ad);
if (rc)
return rc;
@@ -3442,8 +3442,8 @@ static int selinux_inode_setxattr(struct mnt_idmap *idmap,
if (rc)
return rc;
- rc = cred_has_perm(cred, newsid, isec->sclass, FILE__RELABELTO,
- &ad);
+ rc = cred_tsid_has_perm(cred, newsid, isec->sclass, FILE__RELABELTO,
+ &ad);
if (rc)
return rc;
@@ -3884,8 +3884,8 @@ static int ioctl_has_perm(const struct cred *cred, struct file *file,
ad.u.op->path = file->f_path;
if (ssid != fsec->sid) {
- rc = cred_has_perm(cred, fsec->sid, SECCLASS_FD, FD__USE,
- &ad);
+ rc = cred_tsid_has_perm(cred, fsec->sid, SECCLASS_FD, FD__USE,
+ &ad);
if (rc)
goto out;
}
@@ -4270,8 +4270,8 @@ static int selinux_kernel_act_as(struct cred *new, u32 secid)
struct task_security_struct *tsec = selinux_cred(new);
int ret;
- ret = cred_has_perm(current_cred(), secid, SECCLASS_KERNEL_SERVICE,
- KERNEL_SERVICE__USE_AS_OVERRIDE, NULL);
+ ret = cred_tsid_has_perm(current_cred(), secid, SECCLASS_KERNEL_SERVICE,
+ KERNEL_SERVICE__USE_AS_OVERRIDE, NULL);
if (ret == 0) {
tsec->sid = secid;
tsec->create_sid = 0;
@@ -4291,10 +4291,10 @@ static int selinux_kernel_create_files_as(struct cred *new, struct inode *inode)
struct task_security_struct *tsec = selinux_cred(new);
int ret;
- ret = cred_has_perm(current_cred(), isec->sid,
- SECCLASS_KERNEL_SERVICE,
- KERNEL_SERVICE__CREATE_FILES_AS,
- NULL);
+ ret = cred_tsid_has_perm(current_cred(), isec->sid,
+ SECCLASS_KERNEL_SERVICE,
+ KERNEL_SERVICE__CREATE_FILES_AS,
+ NULL);
if (ret == 0)
tsec->create_sid = isec->sid;
@@ -4308,8 +4308,8 @@ static int selinux_kernel_module_request(char *kmod_name)
ad.type = LSM_AUDIT_DATA_KMOD;
ad.u.kmod_name = kmod_name;
- return cred_has_perm(current_cred(), SECINITSID_KERNEL,
- SECCLASS_SYSTEM, SYSTEM__MODULE_REQUEST, &ad);
+ return cred_tsid_has_perm(current_cred(), SECINITSID_KERNEL,
+ SECCLASS_SYSTEM, SYSTEM__MODULE_REQUEST, &ad);
}
static int selinux_kernel_load_from_file(struct file *file, u32 requested)
@@ -4331,14 +4331,15 @@ static int selinux_kernel_load_from_file(struct file *file, u32 requested)
fsec = selinux_file(file);
if (sid != fsec->sid) {
- rc = cred_has_perm(cred, fsec->sid, SECCLASS_FD, FD__USE,
- &ad);
+ rc = cred_tsid_has_perm(cred, fsec->sid, SECCLASS_FD, FD__USE,
+ &ad);
if (rc)
return rc;
}
isec = inode_security(file_inode(file));
- return cred_has_perm(cred, isec->sid, SECCLASS_SYSTEM, requested, &ad);
+ return cred_tsid_has_perm(cred, isec->sid, SECCLASS_SYSTEM, requested,
+ &ad);
}
static int selinux_kernel_read_file(struct file *file,
@@ -4861,8 +4862,8 @@ static int sock_has_perm(struct sock *sk, u32 perms)
ad_net_init_from_sk(&ad, &net, sk);
- return cred_has_perm(current_cred(), sksec->sid, sksec->sclass,
- perms, &ad);
+ return cred_tsid_has_perm(current_cred(), sksec->sid, sksec->sclass,
+ perms, &ad);
}
static int selinux_socket_create(int family, int type,
@@ -4881,8 +4882,8 @@ static int selinux_socket_create(int family, int type,
if (rc)
return rc;
- return cred_has_perm(current_cred(), newsid, secclass,
- SOCKET__CREATE, NULL);
+ return cred_tsid_has_perm(current_cred(), newsid, secclass,
+ SOCKET__CREATE, NULL);
}
static int selinux_socket_post_create(struct socket *sock, int family,
@@ -5832,8 +5833,8 @@ static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb)
static int selinux_secmark_relabel_packet(u32 sid)
{
- return cred_has_perm(current_cred(), sid, SECCLASS_PACKET,
- PACKET__RELABELTO, NULL);
+ return cred_tsid_has_perm(current_cred(), sid, SECCLASS_PACKET,
+ PACKET__RELABELTO, NULL);
}
static void selinux_secmark_refcount_inc(void)
@@ -5877,9 +5878,9 @@ static int selinux_tun_dev_attach_queue(void *security)
{
struct tun_security_struct *tunsec = selinux_tun_dev(security);
- return cred_has_perm(current_cred(), tunsec->sid,
- SECCLASS_TUN_SOCKET, TUN_SOCKET__ATTACH_QUEUE,
- NULL);
+ return cred_tsid_has_perm(current_cred(), tunsec->sid,
+ SECCLASS_TUN_SOCKET, TUN_SOCKET__ATTACH_QUEUE,
+ NULL);
}
static int selinux_tun_dev_attach(struct sock *sk, void *security)
@@ -5906,8 +5907,8 @@ static int selinux_tun_dev_open(void *security)
struct tun_security_struct *tunsec = selinux_tun_dev(security);
int err;
- err = cred_has_perm(cred, tunsec->sid, SECCLASS_TUN_SOCKET,
- TUN_SOCKET__RELABELFROM, NULL);
+ err = cred_tsid_has_perm(cred, tunsec->sid, SECCLASS_TUN_SOCKET,
+ TUN_SOCKET__RELABELFROM, NULL);
if (err)
return err;
err = cred_self_has_perm(cred, SECCLASS_TUN_SOCKET,
@@ -6297,8 +6298,8 @@ static int ipc_has_perm(struct kern_ipc_perm *ipc_perms,
ad.type = LSM_AUDIT_DATA_IPC;
ad.u.ipc_id = ipc_perms->key;
- return cred_has_perm(current_cred(), isec->sid, isec->sclass, perms,
- &ad);
+ return cred_tsid_has_perm(current_cred(), isec->sid, isec->sclass, perms,
+ &ad);
}
static int selinux_msg_msg_alloc_security(struct msg_msg *msg)
@@ -6323,8 +6324,8 @@ static int selinux_msg_queue_alloc_security(struct kern_ipc_perm *msq)
ad.type = LSM_AUDIT_DATA_IPC;
ad.u.ipc_id = msq->key;
- return cred_has_perm(current_cred(), isec->sid, SECCLASS_MSGQ,
- MSGQ__CREATE, &ad);
+ return cred_tsid_has_perm(current_cred(), isec->sid, SECCLASS_MSGQ,
+ MSGQ__CREATE, &ad);
}
static int selinux_msg_queue_associate(struct kern_ipc_perm *msq, int msqflg)
@@ -6337,8 +6338,8 @@ static int selinux_msg_queue_associate(struct kern_ipc_perm *msq, int msqflg)
ad.type = LSM_AUDIT_DATA_IPC;
ad.u.ipc_id = msq->key;
- return cred_has_perm(current_cred(), isec->sid, SECCLASS_MSGQ,
- MSGQ__ASSOCIATE, &ad);
+ return cred_tsid_has_perm(current_cred(), isec->sid, SECCLASS_MSGQ,
+ MSGQ__ASSOCIATE, &ad);
}
static int selinux_msg_queue_msgctl(struct kern_ipc_perm *msq, int cmd)
@@ -6349,8 +6350,8 @@ static int selinux_msg_queue_msgctl(struct kern_ipc_perm *msq, int cmd)
case IPC_INFO:
case MSG_INFO:
/* No specific object, just general system-wide information. */
- return cred_has_perm(current_cred(), SECINITSID_KERNEL,
- SECCLASS_SYSTEM, SYSTEM__IPC_INFO, NULL);
+ return cred_tsid_has_perm(current_cred(), SECINITSID_KERNEL,
+ SECCLASS_SYSTEM, SYSTEM__IPC_INFO, NULL);
case IPC_STAT:
case MSG_STAT:
case MSG_STAT_ANY:
@@ -6399,11 +6400,11 @@ static int selinux_msg_queue_msgsnd(struct kern_ipc_perm *msq, struct msg_msg *m
ad.u.ipc_id = msq->key;
/* Can this process write to the queue? */
- rc = cred_has_perm(cred, isec->sid, SECCLASS_MSGQ, MSGQ__WRITE, &ad);
+ rc = cred_tsid_has_perm(cred, isec->sid, SECCLASS_MSGQ, MSGQ__WRITE, &ad);
if (!rc)
/* Can this process send the message */
- rc = cred_has_perm(cred, msec->sid, SECCLASS_MSG, MSG__SEND,
- &ad);
+ rc = cred_tsid_has_perm(cred, msec->sid, SECCLASS_MSG, MSG__SEND,
+ &ad);
if (!rc)
/* Can the message be put in the queue? */
rc = cred_ssid_has_perm(cred, msec->sid, isec->sid,
@@ -6450,8 +6451,8 @@ static int selinux_shm_alloc_security(struct kern_ipc_perm *shp)
ad.type = LSM_AUDIT_DATA_IPC;
ad.u.ipc_id = shp->key;
- return cred_has_perm(current_cred(), isec->sid, SECCLASS_SHM,
- SHM__CREATE, &ad);
+ return cred_tsid_has_perm(current_cred(), isec->sid, SECCLASS_SHM,
+ SHM__CREATE, &ad);
}
static int selinux_shm_associate(struct kern_ipc_perm *shp, int shmflg)
@@ -6464,8 +6465,8 @@ static int selinux_shm_associate(struct kern_ipc_perm *shp, int shmflg)
ad.type = LSM_AUDIT_DATA_IPC;
ad.u.ipc_id = shp->key;
- return cred_has_perm(current_cred(), isec->sid, SECCLASS_SHM,
- SHM__ASSOCIATE, &ad);
+ return cred_tsid_has_perm(current_cred(), isec->sid, SECCLASS_SHM,
+ SHM__ASSOCIATE, &ad);
}
/* Note, at this point, shp is locked down */
@@ -6477,9 +6478,9 @@ static int selinux_shm_shmctl(struct kern_ipc_perm *shp, int cmd)
case IPC_INFO:
case SHM_INFO:
/* No specific object, just general system-wide information. */
- return cred_has_perm(current_cred(), SECINITSID_KERNEL,
- SECCLASS_SYSTEM, SYSTEM__IPC_INFO,
- NULL);
+ return cred_tsid_has_perm(current_cred(), SECINITSID_KERNEL,
+ SECCLASS_SYSTEM, SYSTEM__IPC_INFO,
+ NULL);
case IPC_STAT:
case SHM_STAT:
case SHM_STAT_ANY:
@@ -6527,8 +6528,8 @@ static int selinux_sem_alloc_security(struct kern_ipc_perm *sma)
ad.type = LSM_AUDIT_DATA_IPC;
ad.u.ipc_id = sma->key;
- return cred_has_perm(current_cred(), isec->sid, SECCLASS_SEM,
- SEM__CREATE, &ad);
+ return cred_tsid_has_perm(current_cred(), isec->sid, SECCLASS_SEM,
+ SEM__CREATE, &ad);
}
static int selinux_sem_associate(struct kern_ipc_perm *sma, int semflg)
@@ -6541,8 +6542,8 @@ static int selinux_sem_associate(struct kern_ipc_perm *sma, int semflg)
ad.type = LSM_AUDIT_DATA_IPC;
ad.u.ipc_id = sma->key;
- return cred_has_perm(current_cred(), isec->sid, SECCLASS_SEM,
- SEM__ASSOCIATE, &ad);
+ return cred_tsid_has_perm(current_cred(), isec->sid, SECCLASS_SEM,
+ SEM__ASSOCIATE, &ad);
}
/* Note, at this point, sma is locked down */
@@ -6555,9 +6556,9 @@ static int selinux_sem_semctl(struct kern_ipc_perm *sma, int cmd)
case IPC_INFO:
case SEM_INFO:
/* No specific object, just general system-wide information. */
- return cred_has_perm(current_cred(), SECINITSID_KERNEL,
- SECCLASS_SYSTEM, SYSTEM__IPC_INFO,
- NULL);
+ return cred_tsid_has_perm(current_cred(), SECINITSID_KERNEL,
+ SECCLASS_SYSTEM, SYSTEM__IPC_INFO,
+ NULL);
case GETPID:
case GETNCNT:
case GETZCNT:
@@ -6786,8 +6787,8 @@ static int selinux_lsm_setattr(u64 attr, void *value, size_t size)
tsec->create_sid = sid;
} else if (attr == LSM_ATTR_KEYCREATE) {
if (sid) {
- error = cred_has_perm(cred, sid, SECCLASS_KEY,
- KEY__CREATE, NULL);
+ error = cred_tsid_has_perm(cred, sid, SECCLASS_KEY,
+ KEY__CREATE, NULL);
if (error)
goto abort_change;
}
@@ -7046,7 +7047,7 @@ static int selinux_key_permission(key_ref_t key_ref,
key = key_ref_to_ptr(key_ref);
ksec = selinux_key(key);
- return cred_has_perm(cred, ksec->sid, SECCLASS_KEY, perm, NULL);
+ return cred_tsid_has_perm(cred, ksec->sid, SECCLASS_KEY, perm, NULL);
}
static int selinux_key_getsecurity(struct key *key, char **_buffer)
@@ -7069,8 +7070,8 @@ static int selinux_watch_key(struct key *key)
{
struct key_security_struct *ksec = selinux_key(key);
- return cred_has_perm(current_cred(), ksec->sid, SECCLASS_KEY,
- KEY__VIEW, NULL);
+ return cred_tsid_has_perm(current_cred(), ksec->sid, SECCLASS_KEY,
+ KEY__VIEW, NULL);
}
#endif
#endif
@@ -7185,15 +7186,15 @@ static int bpf_fd_pass(const struct file *file, const struct cred *cred)
if (file->f_op == &bpf_map_fops) {
map = file->private_data;
bpfsec = map->security;
- ret = cred_has_perm(cred, bpfsec->sid, SECCLASS_BPF,
- bpf_map_fmode_to_av(file->f_mode), NULL);
+ ret = cred_tsid_has_perm(cred, bpfsec->sid, SECCLASS_BPF,
+ bpf_map_fmode_to_av(file->f_mode), NULL);
if (ret)
return ret;
} else if (file->f_op == &bpf_prog_fops) {
prog = file->private_data;
bpfsec = prog->aux->security;
- ret = cred_has_perm(cred, bpfsec->sid, SECCLASS_BPF,
- BPF__PROG_RUN, NULL);
+ ret = cred_tsid_has_perm(cred, bpfsec->sid, SECCLASS_BPF,
+ BPF__PROG_RUN, NULL);
if (ret)
return ret;
}
@@ -7205,8 +7206,8 @@ static int selinux_bpf_map(struct bpf_map *map, fmode_t fmode)
struct bpf_security_struct *bpfsec;
bpfsec = map->security;
- return cred_has_perm(current_cred(), bpfsec->sid, SECCLASS_BPF,
- bpf_map_fmode_to_av(fmode), NULL);
+ return cred_tsid_has_perm(current_cred(), bpfsec->sid, SECCLASS_BPF,
+ bpf_map_fmode_to_av(fmode), NULL);
}
static int selinux_bpf_prog(struct bpf_prog *prog)
@@ -7214,8 +7215,8 @@ static int selinux_bpf_prog(struct bpf_prog *prog)
struct bpf_security_struct *bpfsec;
bpfsec = prog->aux->security;
- return cred_has_perm(current_cred(), bpfsec->sid, SECCLASS_BPF,
- BPF__PROG_RUN, NULL);
+ return cred_tsid_has_perm(current_cred(), bpfsec->sid, SECCLASS_BPF,
+ BPF__PROG_RUN, NULL);
}
static int selinux_bpf_map_create(struct bpf_map *map, union bpf_attr *attr,
@@ -7339,16 +7340,16 @@ static int selinux_perf_event_read(struct perf_event *event)
{
struct perf_event_security_struct *perfsec = event->security;
- return cred_has_perm(current_cred(), perfsec->sid,
- SECCLASS_PERF_EVENT, PERF_EVENT__READ, NULL);
+ return cred_tsid_has_perm(current_cred(), perfsec->sid,
+ SECCLASS_PERF_EVENT, PERF_EVENT__READ, NULL);
}
static int selinux_perf_event_write(struct perf_event *event)
{
struct perf_event_security_struct *perfsec = event->security;
- return cred_has_perm(current_cred(), perfsec->sid,
- SECCLASS_PERF_EVENT, PERF_EVENT__WRITE, NULL);
+ return cred_tsid_has_perm(current_cred(), perfsec->sid,
+ SECCLASS_PERF_EVENT, PERF_EVENT__WRITE, NULL);
}
#endif
@@ -7396,8 +7397,8 @@ static int selinux_uring_cmd(struct io_uring_cmd *ioucmd)
ad.type = LSM_AUDIT_DATA_FILE;
ad.u.file = file;
- return cred_has_perm(current_cred(), isec->sid,
- SECCLASS_IO_URING, IO_URING__CMD, &ad);
+ return cred_tsid_has_perm(current_cred(), isec->sid,
+ SECCLASS_IO_URING, IO_URING__CMD, &ad);
}
/**
diff --git a/security/selinux/include/avc.h b/security/selinux/include/avc.h
index fd8c6b3a32df..5c6c07033711 100644
--- a/security/selinux/include/avc.h
+++ b/security/selinux/include/avc.h
@@ -163,11 +163,11 @@ int cred_self_has_perm(const struct cred *cred, u16 tclass, u32 requested,
int cred_self_has_perm_noaudit(const struct cred *cred, u16 tclass,
u32 requested);
-int cred_has_perm(const struct cred *cred, u32 tsid, u16 tclass, u32 requested,
- struct common_audit_data *ad);
+int cred_tsid_has_perm(const struct cred *cred, u32 tsid, u16 tclass,
+ u32 requested, struct common_audit_data *ad);
-int cred_has_perm_noaudit(const struct cred *cred, u32 tsid, u16 tclass,
- u32 requested, struct av_decision *avd);
+int cred_tsid_has_perm_noaudit(const struct cred *cred, u32 tsid, u16 tclass,
+ u32 requested, struct av_decision *avd);
int cred_ssid_has_perm(const struct cred *cred, u32 ssid, u32 tsid, u16 tclass,
u32 requested, struct common_audit_data *ad);
--
2.50.1
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [PATCH v7 32/42] selinux: update cred_tsid_has_perm_noaudit() to return the combined avd
2025-08-14 13:25 [PATCH v7 00/42] SELinux namespace support Stephen Smalley
` (30 preceding siblings ...)
2025-08-14 13:26 ` [PATCH v7 31/42] selinux: rename cred_has_perm*() to cred_tsid_has_perm*() Stephen Smalley
@ 2025-08-14 13:26 ` Stephen Smalley
2025-08-14 13:26 ` [PATCH v7 33/42] selinux: convert additional checks to cred_ssid_has_perm() Stephen Smalley
` (9 subsequent siblings)
41 siblings, 0 replies; 43+ messages in thread
From: Stephen Smalley @ 2025-08-14 13:26 UTC (permalink / raw)
To: selinux; +Cc: paul, omosnace, netdev, horms, Stephen Smalley
cred_tsid_has_perm_noaudit() currently just returns the last computed
av_decision (avd) structure, which in the case of multiple SELinux
namespaces will only contain the decisions from the init SELinux
namespace. Generally this has no effect since a permission denial
by any namespace will cause an immediate error return with -EACCES,
but in the case where permission is allowed and the caller caches
the avd itself for later reuse, it could lead to the caller
incorrectly only using the cached decisions from the init namespace.
Change cred_tsid_has_perm_noaudit() to combine the results from any
avc_has_perm_noaudit() calls to produce the final avd that is returned
to the caller to avoid this problem. The combining logic varies
for different fields of the avd, e.g. intersection for allowed
and flags (per-domain permissive), union for auditallow and auditdeny,
and the seqno is always set from the current namespace only.
Signed-off-by: Stephen Smalley <stephen.smalley.work@gmail.com>
---
security/selinux/avc.c | 30 ++++++++++++++++++++----------
1 file changed, 20 insertions(+), 10 deletions(-)
diff --git a/security/selinux/avc.c b/security/selinux/avc.c
index e153f0122b4d..01405d1fb546 100644
--- a/security/selinux/avc.c
+++ b/security/selinux/avc.c
@@ -1557,28 +1557,38 @@ int cred_tsid_has_perm_noaudit(const struct cred *cred, u32 tsid, u16 tclass,
{
struct task_security_struct *tsec;
struct selinux_state *state;
+ struct av_decision tmp_avd;
u32 ssid;
int rc;
- do {
+ tsec = selinux_cred(cred);
+ ssid = tsec->sid;
+ state = tsec->state;
+
+ rc = avc_has_perm_noaudit(state, ssid, tsid, tclass,
+ requested, 0, avd);
+ if (rc)
+ return rc;
+
+ cred = tsec->parent_cred;
+ while (cred) {
tsec = selinux_cred(cred);
ssid = tsec->sid;
state = tsec->state;
- /*
- * TODO Do we need to use a tmp avd for each
- * avc_has_perm_noaudit() call and intersect/union
- * the sets as appropriate as we go? Or can we
- * simply use the last result since we generally
- * only care when there is a denial?
- */
rc = avc_has_perm_noaudit(state, ssid, tsid, tclass,
- requested, 0, avd);
+ requested, 0, &tmp_avd);
+
+ avd->allowed &= tmp_avd.allowed;
+ avd->auditallow |= tmp_avd.auditallow;
+ avd->auditdeny |= tmp_avd.auditdeny;
+ avd->flags &= tmp_avd.flags;
+
if (rc)
return rc;
cred = tsec->parent_cred;
- } while (cred);
+ }
return 0;
}
--
2.50.1
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [PATCH v7 33/42] selinux: convert additional checks to cred_ssid_has_perm()
2025-08-14 13:25 [PATCH v7 00/42] SELinux namespace support Stephen Smalley
` (31 preceding siblings ...)
2025-08-14 13:26 ` [PATCH v7 32/42] selinux: update cred_tsid_has_perm_noaudit() to return the combined avd Stephen Smalley
@ 2025-08-14 13:26 ` Stephen Smalley
2025-08-14 13:26 ` [PATCH v7 34/42] selinux: introduce selinux_state_has_perm() Stephen Smalley
` (8 subsequent siblings)
41 siblings, 0 replies; 43+ messages in thread
From: Stephen Smalley @ 2025-08-14 13:26 UTC (permalink / raw)
To: selinux; +Cc: paul, omosnace, netdev, horms, Stephen Smalley
Convert additional permission checks in the hook functions to
use the namespace-aware cred_ssid_has_perm() helper function.
In particular, the following hook functions are updated:
selinux_socket_bind()
selinux_socket_connect_helper()
selinux_socket_unix_stream_connect()
selinux_socket_unix_may_send()
selinux_msg_queue_msgrcv()
In each of these cases, the check is between two object SIDs
and does not use the current cred SID.
selinux_msg_queue_msgrcv() may bear revisiting since the
source SID is the SID of the receiving task (not current).
An alternative would be to use the receiving task's cred
and the cred_tsid_has_perm() helper for these checks.
Signed-off-by: Stephen Smalley <stephen.smalley.work@gmail.com>
---
security/selinux/hooks.c | 44 ++++++++++++++++++++--------------------
1 file changed, 22 insertions(+), 22 deletions(-)
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index f229a8099167..71ccd86c5303 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -4938,6 +4938,7 @@ static int selinux_socket_socketpair(struct socket *socka,
static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, int addrlen)
{
+ const struct cred *cred = current_cred();
struct sock *sk = sock->sk;
struct sk_security_struct *sksec = selinux_sock(sk);
u16 family;
@@ -5019,10 +5020,10 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
snum, &sid);
if (err)
goto out;
- err = avc_has_perm(current_selinux_state,
- sksec->sid, sid,
- sksec->sclass,
- SOCKET__NAME_BIND, &ad);
+ err = cred_ssid_has_perm(cred, sksec->sid,
+ sid, sksec->sclass,
+ SOCKET__NAME_BIND,
+ &ad);
if (err)
goto out;
}
@@ -5056,9 +5057,8 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
else
ad.u.net->v6info.saddr = addr6->sin6_addr;
- err = avc_has_perm(current_selinux_state,
- sksec->sid, sid,
- sksec->sclass, node_perm, &ad);
+ err = cred_ssid_has_perm(cred, sksec->sid, sid,
+ sksec->sclass, node_perm, &ad);
if (err)
goto out;
}
@@ -5077,6 +5077,7 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
static int selinux_socket_connect_helper(struct socket *sock,
struct sockaddr *address, int addrlen)
{
+ const struct cred *cred = current_cred();
struct sock *sk = sock->sk;
struct sk_security_struct *sksec = selinux_sock(sk);
int err;
@@ -5151,8 +5152,8 @@ static int selinux_socket_connect_helper(struct socket *sock,
ad.u.net = &net;
ad.u.net->dport = htons(snum);
ad.u.net->family = address->sa_family;
- err = avc_has_perm(current_selinux_state,
- sksec->sid, sid, sksec->sclass, perm, &ad);
+ err = cred_ssid_has_perm(cred, sksec->sid, sid,
+ sksec->sclass, perm, &ad);
if (err)
return err;
}
@@ -5253,6 +5254,7 @@ static int selinux_socket_unix_stream_connect(struct sock *sock,
struct sock *other,
struct sock *newsk)
{
+ const struct cred *cred = current_cred();
struct sk_security_struct *sksec_sock = selinux_sock(sock);
struct sk_security_struct *sksec_other = selinux_sock(other);
struct sk_security_struct *sksec_new = selinux_sock(newsk);
@@ -5262,10 +5264,9 @@ static int selinux_socket_unix_stream_connect(struct sock *sock,
ad_net_init_from_sk(&ad, &net, other);
- err = avc_has_perm(current_selinux_state,
- sksec_sock->sid, sksec_other->sid,
- sksec_other->sclass,
- UNIX_STREAM_SOCKET__CONNECTTO, &ad);
+ err = cred_ssid_has_perm(cred, sksec_sock->sid, sksec_other->sid,
+ sksec_other->sclass,
+ UNIX_STREAM_SOCKET__CONNECTTO, &ad);
if (err)
return err;
@@ -5285,6 +5286,7 @@ static int selinux_socket_unix_stream_connect(struct sock *sock,
static int selinux_socket_unix_may_send(struct socket *sock,
struct socket *other)
{
+ const struct cred *cred = current_cred();
struct sk_security_struct *ssec = selinux_sock(sock->sk);
struct sk_security_struct *osec = selinux_sock(other->sk);
struct common_audit_data ad;
@@ -5292,9 +5294,8 @@ static int selinux_socket_unix_may_send(struct socket *sock,
ad_net_init_from_sk(&ad, &net, other->sk);
- return avc_has_perm(current_selinux_state,
- ssec->sid, osec->sid, osec->sclass, SOCKET__SENDTO,
- &ad);
+ return cred_ssid_has_perm(cred, ssec->sid, osec->sid, osec->sclass,
+ SOCKET__SENDTO, &ad);
}
static int selinux_inet_sys_rcv_skb(struct selinux_state *state,
@@ -6417,6 +6418,7 @@ static int selinux_msg_queue_msgrcv(struct kern_ipc_perm *msq, struct msg_msg *m
struct task_struct *target,
long type, int mode)
{
+ const struct cred *cred = current_cred();
struct ipc_security_struct *isec;
struct msg_security_struct *msec;
struct common_audit_data ad;
@@ -6429,13 +6431,11 @@ static int selinux_msg_queue_msgrcv(struct kern_ipc_perm *msq, struct msg_msg *m
ad.type = LSM_AUDIT_DATA_IPC;
ad.u.ipc_id = msq->key;
- rc = avc_has_perm(current_selinux_state,
- sid, isec->sid,
- SECCLASS_MSGQ, MSGQ__READ, &ad);
+ rc = cred_ssid_has_perm(cred, sid, isec->sid, SECCLASS_MSGQ,
+ MSGQ__READ, &ad);
if (!rc)
- rc = avc_has_perm(current_selinux_state,
- sid, msec->sid,
- SECCLASS_MSG, MSG__RECEIVE, &ad);
+ rc = cred_ssid_has_perm(cred, sid, msec->sid,
+ SECCLASS_MSG, MSG__RECEIVE, &ad);
return rc;
}
--
2.50.1
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [PATCH v7 34/42] selinux: introduce selinux_state_has_perm()
2025-08-14 13:25 [PATCH v7 00/42] SELinux namespace support Stephen Smalley
` (32 preceding siblings ...)
2025-08-14 13:26 ` [PATCH v7 33/42] selinux: convert additional checks to cred_ssid_has_perm() Stephen Smalley
@ 2025-08-14 13:26 ` Stephen Smalley
2025-08-14 13:26 ` [PATCH v7 35/42] selinux: annotate selinuxfs permission checks Stephen Smalley
` (7 subsequent siblings)
41 siblings, 0 replies; 43+ messages in thread
From: Stephen Smalley @ 2025-08-14 13:26 UTC (permalink / raw)
To: selinux; +Cc: paul, omosnace, netdev, horms, Stephen Smalley
Introduce selinux_state_has_perm() for checking permissions on a
(ssid, tsid) pair for a namespace and its ancestors when there
is no cred available, e.g. for the networking checks.
To support selinux_state_has_perm(), introduce a creator SID field
in the selinux_state structure to save the SID of the process
that created the namespace, or SECINITSID_KERNEL for the initial
namespace. This SID is used as the subject SID for checks in the
parent namespace.
Some of the checks previously converted to using cred_ssid_has_perm()
may be candidates for switching to this new helper even though a cred
was available in those hooks.
Signed-off-by: Stephen Smalley <stephen.smalley.work@gmail.com>
---
security/selinux/avc.c | 37 ++++++++++++++++
security/selinux/hooks.c | 69 ++++++++++++++++-------------
security/selinux/include/avc.h | 4 ++
security/selinux/include/security.h | 1 +
4 files changed, 80 insertions(+), 31 deletions(-)
diff --git a/security/selinux/avc.c b/security/selinux/avc.c
index 01405d1fb546..1095b7720eb8 100644
--- a/security/selinux/avc.c
+++ b/security/selinux/avc.c
@@ -1688,6 +1688,43 @@ int cred_other_has_perm(const struct cred *cred, const struct cred *other,
return 0;
}
+/**
+ * selinux_state_has_perm - Check and audit permissions on a (ssid, tsid) pair
+ * @state: SELinux state
+ * @ssid: source security identifier
+ * @tsid: target security identifier
+ * @tclass: target security class
+ * @requested: requested permissions, interpreted based on @tclass
+ * @ad: auxiliary audit data
+ *
+ * Check permissions between a source SID @ssid and a target SID @tsid for
+ * @state and all ancestors to determine whether the @requested permissions
+ * are granted, interpreting the permissions based on @tclass.
+ * For the ancestor checks, use the SID of the creator of the namespace
+ * as the source SID of the check.
+ * Audit the granting or denial of permissions in accordance with the policy.
+ * Return %0 if all @requested permissions are granted, -%EACCES if any
+ * permissions are denied, or another -errno upon other errors.
+ * DO NOT USE when a cred is available; use cred_*_has_perm() instead.
+ */
+int selinux_state_has_perm(struct selinux_state *state, u32 ssid, u32 tsid,
+ u16 tclass, u32 requested,
+ struct common_audit_data *ad)
+{
+ int rc;
+
+ do {
+ rc = avc_has_perm(state, ssid, tsid, tclass, requested, ad);
+ if (rc)
+ return rc;
+
+ ssid = state->creator_sid;
+ state = state->parent;
+ } while (state);
+
+ return 0;
+}
+
u32 avc_policy_seqno(struct selinux_state *state)
{
return state->avc->avc_cache.latest_notif;
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 71ccd86c5303..8a32f5655980 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -5310,16 +5310,16 @@ static int selinux_inet_sys_rcv_skb(struct selinux_state *state,
err = sel_netif_sid(state, ns, ifindex, &if_sid);
if (err)
return err;
- err = avc_has_perm(state, peer_sid, if_sid,
- SECCLASS_NETIF, NETIF__INGRESS, ad);
+ err = selinux_state_has_perm(state, peer_sid, if_sid,
+ SECCLASS_NETIF, NETIF__INGRESS, ad);
if (err)
return err;
err = sel_netnode_sid(state, addrp, family, &node_sid);
if (err)
return err;
- return avc_has_perm(state, peer_sid, node_sid, SECCLASS_NODE,
- NODE__RECVFROM, ad);
+ return selinux_state_has_perm(state, peer_sid, node_sid, SECCLASS_NODE,
+ NODE__RECVFROM, ad);
}
static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
@@ -5339,8 +5339,9 @@ static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
return err;
if (selinux_secmark_enabled()) {
- err = avc_has_perm(state, sk_sid, skb->secmark, SECCLASS_PACKET,
- PACKET__RECV, &ad);
+ err = selinux_state_has_perm(state, sk_sid, skb->secmark,
+ SECCLASS_PACKET, PACKET__RECV,
+ &ad);
if (err)
return err;
}
@@ -5400,8 +5401,8 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
selinux_netlbl_err(skb, family, err, 0);
return err;
}
- err = avc_has_perm(state, sk_sid, peer_sid, SECCLASS_PEER,
- PEER__RECV, &ad);
+ err = selinux_state_has_perm(state, sk_sid, peer_sid,
+ SECCLASS_PEER, PEER__RECV, &ad);
if (err) {
selinux_netlbl_err(skb, family, err, 0);
return err;
@@ -5409,8 +5410,9 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
}
if (secmark_active) {
- err = avc_has_perm(state, sk_sid, skb->secmark, SECCLASS_PACKET,
- PACKET__RECV, &ad);
+ err = selinux_state_has_perm(state, sk_sid, skb->secmark,
+ SECCLASS_PACKET, PACKET__RECV,
+ &ad);
if (err)
return err;
}
@@ -5594,9 +5596,9 @@ static int selinux_sctp_process_new_assoc(struct sctp_association *asoc,
* consistency among the peer SIDs.
*/
ad_net_init_from_sk(&ad, &net, asoc->base.sk);
- err = avc_has_perm(state, sksec->peer_sid, asoc->peer_secid,
- sksec->sclass, SCTP_SOCKET__ASSOCIATION,
- &ad);
+ err = selinux_state_has_perm(state, sksec->peer_sid,
+ asoc->peer_secid, sksec->sclass,
+ SCTP_SOCKET__ASSOCIATION, &ad);
if (err)
return err;
}
@@ -5964,8 +5966,9 @@ static unsigned int selinux_ip_forward(void *priv, struct sk_buff *skb,
}
if (secmark_active)
- if (avc_has_perm(se_state, peer_sid, skb->secmark,
- SECCLASS_PACKET, PACKET__FORWARD_IN, &ad))
+ if (selinux_state_has_perm(se_state, peer_sid, skb->secmark,
+ SECCLASS_PACKET,
+ PACKET__FORWARD_IN, &ad))
return NF_DROP;
if (netlbl_enabled())
@@ -6046,8 +6049,9 @@ static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
return NF_DROP;
if (selinux_secmark_enabled())
- if (avc_has_perm(sksec->state, sksec->sid, skb->secmark,
- SECCLASS_PACKET, PACKET__SEND, &ad))
+ if (selinux_state_has_perm(sksec->state, sksec->sid,
+ skb->secmark, SECCLASS_PACKET,
+ PACKET__SEND, &ad))
return NF_DROP_ERR(-ECONNREFUSED);
if (selinux_xfrm_postroute_last(sksec->sid, skb, sksec->state, &ad,
@@ -6173,8 +6177,8 @@ static unsigned int selinux_ip_postroute(void *priv,
return NF_DROP;
if (secmark_active)
- if (avc_has_perm(se_state, peer_sid, skb->secmark,
- SECCLASS_PACKET, secmark_perm, &ad))
+ if (selinux_state_has_perm(se_state, peer_sid, skb->secmark,
+ SECCLASS_PACKET, secmark_perm, &ad))
return NF_DROP_ERR(-ECONNREFUSED);
if (peerlbl_active) {
@@ -6183,14 +6187,14 @@ static unsigned int selinux_ip_postroute(void *priv,
if (sel_netif_sid(se_state, state->net, ifindex, &if_sid))
return NF_DROP;
- if (avc_has_perm(se_state, peer_sid, if_sid,
- SECCLASS_NETIF, NETIF__EGRESS, &ad))
+ if (selinux_state_has_perm(se_state, peer_sid, if_sid,
+ SECCLASS_NETIF, NETIF__EGRESS, &ad))
return NF_DROP_ERR(-ECONNREFUSED);
if (sel_netnode_sid(se_state, addrp, family, &node_sid))
return NF_DROP;
- if (avc_has_perm(se_state, peer_sid, node_sid,
- SECCLASS_NODE, NODE__SENDTO, &ad))
+ if (selinux_state_has_perm(se_state, peer_sid, node_sid,
+ SECCLASS_NODE, NODE__SENDTO, &ad))
return NF_DROP_ERR(-ECONNREFUSED);
}
@@ -7093,10 +7097,10 @@ static int selinux_ib_pkey_access(void *ib_sec, u64 subnet_prefix, u16 pkey_val)
ibpkey.subnet_prefix = subnet_prefix;
ibpkey.pkey = pkey_val;
ad.u.ibpkey = &ibpkey;
- return avc_has_perm(current_selinux_state,
- sec->sid, sid,
- SECCLASS_INFINIBAND_PKEY,
- INFINIBAND_PKEY__ACCESS, &ad);
+ return selinux_state_has_perm(current_selinux_state,
+ sec->sid, sid,
+ SECCLASS_INFINIBAND_PKEY,
+ INFINIBAND_PKEY__ACCESS, &ad);
}
static int selinux_ib_endport_manage_subnet(void *ib_sec, const char *dev_name,
@@ -7118,10 +7122,10 @@ static int selinux_ib_endport_manage_subnet(void *ib_sec, const char *dev_name,
ibendport.dev_name = dev_name;
ibendport.port = port_num;
ad.u.ibendport = &ibendport;
- return avc_has_perm(current_selinux_state,
- sec->sid, sid,
- SECCLASS_INFINIBAND_ENDPORT,
- INFINIBAND_ENDPORT__MANAGE_SUBNET, &ad);
+ return selinux_state_has_perm(current_selinux_state,
+ sec->sid, sid,
+ SECCLASS_INFINIBAND_ENDPORT,
+ INFINIBAND_ENDPORT__MANAGE_SUBNET, &ad);
}
static int selinux_ib_alloc_security(void *ib_sec)
@@ -7735,6 +7739,7 @@ int selinux_state_create(const struct cred *cred)
{
struct task_security_struct *tsec = selinux_cred(cred);
struct selinux_state *parent = tsec->state;
+ u32 creator_sid = tsec->sid;
struct selinux_state *newstate;
int rc;
@@ -7750,6 +7755,8 @@ int selinux_state_create(const struct cred *cred)
if (!newstate)
return -ENOMEM;
+ newstate->creator_sid = creator_sid;
+
refcount_set(&newstate->count, 1);
INIT_WORK(&newstate->work, selinux_state_free);
diff --git a/security/selinux/include/avc.h b/security/selinux/include/avc.h
index 5c6c07033711..cf437d0479f5 100644
--- a/security/selinux/include/avc.h
+++ b/security/selinux/include/avc.h
@@ -179,6 +179,10 @@ int cred_other_has_perm(const struct cred *cred, const struct cred *other,
int task_obj_has_perm(const struct task_struct *s, const struct task_struct *t,
u16 tclass, u32 requested, struct common_audit_data *ad);
+int selinux_state_has_perm(struct selinux_state *state, u32 ssid, u32 tsid,
+ u16 tclass, u32 requested,
+ struct common_audit_data *ad);
+
u32 avc_policy_seqno(struct selinux_state *state);
#define AVC_CALLBACK_GRANT 1
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
index f6b6482301fc..145ab528d71e 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -111,6 +111,7 @@ struct selinux_state {
refcount_t count;
struct work_struct work;
+ u32 creator_sid; /* SID of namespace creator */
unsigned short depth;
} __randomize_layout;
--
2.50.1
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [PATCH v7 35/42] selinux: annotate selinuxfs permission checks
2025-08-14 13:25 [PATCH v7 00/42] SELinux namespace support Stephen Smalley
` (33 preceding siblings ...)
2025-08-14 13:26 ` [PATCH v7 34/42] selinux: introduce selinux_state_has_perm() Stephen Smalley
@ 2025-08-14 13:26 ` Stephen Smalley
2025-08-14 13:26 ` [PATCH v7 36/42] selinux: annotate process transition " Stephen Smalley
` (6 subsequent siblings)
41 siblings, 0 replies; 43+ messages in thread
From: Stephen Smalley @ 2025-08-14 13:26 UTC (permalink / raw)
To: selinux; +Cc: paul, omosnace, netdev, horms, Stephen Smalley
Annotate the selinuxfs permission checks with comments
explaining why we only check permissions against the
current SELinux namespace (because these operations only
read or modify the state of the current SELinux namespace).
If we were instead to check permissions against ancestor
namespaces, we would need to be allowed by the ancestor
policies to perform the same operation in those namespaces,
which would be undesirable.
Signed-off-by: Stephen Smalley <stephen.smalley.work@gmail.com>
---
security/selinux/selinuxfs.c | 65 ++++++++++++++++++++++++++++++++++++
1 file changed, 65 insertions(+)
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index be78b71b7fcd..b1ce3a98a241 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -175,6 +175,10 @@ static ssize_t sel_write_enforce(struct file *file, const char __user *buf,
old_value = enforcing_enabled(state);
if (new_value != old_value) {
+ /*
+ * Only check against the current namespace because
+ * this operation only affects it and no others.
+ */
length = avc_has_perm(current_selinux_state,
current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__SETENFORCE,
@@ -362,6 +366,10 @@ static ssize_t sel_write_unshare(struct file *file, const char __user *buf,
if (*ppos != 0)
return -EINVAL;
+ /*
+ * Only check against the current namespace because
+ * this operation only affects it and no others.
+ */
rc = avc_has_perm(current_selinux_state, current_sid(),
SECINITSID_SECURITY, SECCLASS_SECURITY,
SECURITY__UNSHARE, NULL);
@@ -592,6 +600,10 @@ static int sel_open_policy(struct inode *inode, struct file *filp)
mutex_lock(&fsi->state->policy_mutex);
+ /*
+ * Only check against the current namespace because
+ * this operation only affects it and no others.
+ */
rc = avc_has_perm(current_selinux_state,
current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__READ_POLICY, NULL);
@@ -654,6 +666,10 @@ static ssize_t sel_read_policy(struct file *filp, char __user *buf,
struct policy_load_memory *plm = filp->private_data;
int ret;
+ /*
+ * Only check against the current namespace because
+ * this operation only affects it and no others.
+ */
ret = avc_has_perm(current_selinux_state,
current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__READ_POLICY, NULL);
@@ -811,6 +827,11 @@ static ssize_t sel_write_load(struct file *file, const char __user *buf,
return -EPERM;
mutex_lock(&fsi->state->policy_mutex);
+
+ /*
+ * Only check against the current namespace because
+ * this operation only affects it and no others.
+ */
length = avc_has_perm(current_selinux_state,
current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__LOAD_POLICY, NULL);
@@ -866,6 +887,10 @@ static ssize_t sel_write_context(struct file *file, char *buf, size_t size)
u32 sid, len;
ssize_t length;
+ /*
+ * Only check against the current namespace because
+ * this operation only affects it and no others.
+ */
length = avc_has_perm(current_selinux_state,
current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__CHECK_CONTEXT, NULL);
@@ -917,6 +942,10 @@ static ssize_t sel_write_checkreqprot(struct file *file, const char __user *buf,
if (fsi->state != current_selinux_state)
return -EPERM;
+ /*
+ * Only check against the current namespace because
+ * this operation only affects it and no others.
+ */
length = avc_has_perm(current_selinux_state,
current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__SETCHECKREQPROT,
@@ -976,6 +1005,10 @@ static ssize_t sel_write_validatetrans(struct file *file,
if (state != current_selinux_state)
return -EPERM;
+ /*
+ * Only check against the current namespace because
+ * this operation only affects it and no others.
+ */
rc = avc_has_perm(current_selinux_state,
current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__VALIDATE_TRANS, NULL);
@@ -1109,6 +1142,10 @@ static ssize_t sel_write_access(struct file *file, char *buf, size_t size)
struct av_decision avd;
ssize_t length;
+ /*
+ * Only check against the current namespace because
+ * this operation only affects it and no others.
+ */
length = avc_has_perm(current_selinux_state,
current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__COMPUTE_AV, NULL);
@@ -1163,6 +1200,10 @@ static ssize_t sel_write_create(struct file *file, char *buf, size_t size)
u32 len;
int nargs;
+ /*
+ * Only check against the current namespace because
+ * this operation only affects it and no others.
+ */
length = avc_has_perm(current_selinux_state,
current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__COMPUTE_CREATE,
@@ -1265,6 +1306,10 @@ static ssize_t sel_write_relabel(struct file *file, char *buf, size_t size)
char *newcon = NULL;
u32 len;
+ /*
+ * Only check against the current namespace because
+ * this operation only affects it and no others.
+ */
length = avc_has_perm(current_selinux_state,
current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__COMPUTE_RELABEL,
@@ -1331,6 +1376,10 @@ static ssize_t sel_write_user(struct file *file, char *buf, size_t size)
" userspace.\n", current->comm, current->pid);
ssleep(5);
+ /*
+ * Only check against the current namespace because
+ * this operation only affects it and no others.
+ */
length = avc_has_perm(current_selinux_state,
current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__COMPUTE_USER,
@@ -1396,6 +1445,10 @@ static ssize_t sel_write_member(struct file *file, char *buf, size_t size)
char *newcon = NULL;
u32 len;
+ /*
+ * Only check against the current namespace because
+ * this operation only affects it and no others.
+ */
length = avc_has_perm(current_selinux_state,
current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__COMPUTE_MEMBER,
@@ -1527,6 +1580,10 @@ static ssize_t sel_write_bool(struct file *filep, const char __user *buf,
mutex_lock(&fsi->state->policy_mutex);
+ /*
+ * Only check against the current namespace because
+ * this operation only affects it and no others.
+ */
length = avc_has_perm(current_selinux_state,
current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__SETBOOL,
@@ -1586,6 +1643,10 @@ static ssize_t sel_commit_bools_write(struct file *filep,
mutex_lock(&fsi->state->policy_mutex);
+ /*
+ * Only check against the current namespace because
+ * this operation only affects it and no others.
+ */
length = avc_has_perm(current_selinux_state,
current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__SETBOOL,
@@ -1707,6 +1768,10 @@ static ssize_t sel_write_avc_cache_threshold(struct file *file,
if (state != current_selinux_state)
return -EPERM;
+ /*
+ * Only check against the current namespace because
+ * this operation only affects it and no others.
+ */
ret = avc_has_perm(current_selinux_state,
current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__SETSECPARAM,
--
2.50.1
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [PATCH v7 36/42] selinux: annotate process transition permission checks
2025-08-14 13:25 [PATCH v7 00/42] SELinux namespace support Stephen Smalley
` (34 preceding siblings ...)
2025-08-14 13:26 ` [PATCH v7 35/42] selinux: annotate selinuxfs permission checks Stephen Smalley
@ 2025-08-14 13:26 ` Stephen Smalley
2025-08-14 13:26 ` [PATCH v7 37/42] selinux: convert xfrm and netlabel " Stephen Smalley
` (5 subsequent siblings)
41 siblings, 0 replies; 43+ messages in thread
From: Stephen Smalley @ 2025-08-14 13:26 UTC (permalink / raw)
To: selinux; +Cc: paul, omosnace, netdev, horms, Stephen Smalley
Annotate all process transition-related permission checks that are only
performed against the current SELinux namespace and not ancestors with
comments. These checks are only applied against the current namespace
because the process SID only changes in the current namespace; the SID
in ancestor namespaces remains unchanged.
Signed-off-by: Stephen Smalley <stephen.smalley.work@gmail.com>
---
security/selinux/hooks.c | 46 ++++++++++++++++++++++++++++++++++------
1 file changed, 40 insertions(+), 6 deletions(-)
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 8a32f5655980..e35b3fb16bb8 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2395,19 +2395,23 @@ static int selinux_bprm_creds_for_exec(struct linux_binprm *bprm)
if (rc)
return rc;
} else {
+ /* Check permissions for the transition. */
/*
* Only check against the current SELinux namespace
* because only the SID in the current namespace
* is changed by a transition.
*/
-
- /* Check permissions for the transition. */
rc = avc_has_perm(current_selinux_state,
old_tsec->sid, new_tsec->sid,
SECCLASS_PROCESS, PROCESS__TRANSITION, &ad);
if (rc)
return rc;
+ /*
+ * Only check against the current SELinux namespace
+ * because only the SID in the current namespace
+ * is changed by a transition.
+ */
rc = avc_has_perm(current_selinux_state,
new_tsec->sid, isec->sid,
SECCLASS_FILE, FILE__ENTRYPOINT, &ad);
@@ -2416,6 +2420,11 @@ static int selinux_bprm_creds_for_exec(struct linux_binprm *bprm)
/* Check for shared state */
if (bprm->unsafe & LSM_UNSAFE_SHARE) {
+ /*
+ * Only check against the current SELinux namespace
+ * because only the SID in the current namespace
+ * is changed by a transition.
+ */
rc = avc_has_perm(current_selinux_state,
old_tsec->sid, new_tsec->sid,
SECCLASS_PROCESS, PROCESS__SHARE,
@@ -2429,6 +2438,12 @@ static int selinux_bprm_creds_for_exec(struct linux_binprm *bprm)
if (bprm->unsafe & LSM_UNSAFE_PTRACE) {
u32 ptsid = ptrace_parent_sid();
if (ptsid != 0) {
+ /*
+ * Only check against the current SELinux
+ * namespace because only the SID in the
+ * current namespace is changed by a
+ * transition.
+ */
rc = avc_has_perm(current_selinux_state,
ptsid, new_tsec->sid,
SECCLASS_PROCESS,
@@ -2444,6 +2459,11 @@ static int selinux_bprm_creds_for_exec(struct linux_binprm *bprm)
/* Enable secure mode for SIDs transitions unless
the noatsecure permission is granted between
the two SIDs, i.e. ahp returns 0. */
+ /*
+ * Only check against the current SELinux namespace
+ * because only the SID in the current namespace
+ * is changed by a transition.
+ */
rc = avc_has_perm(current_selinux_state,
old_tsec->sid, new_tsec->sid,
SECCLASS_PROCESS, PROCESS__NOATSECURE,
@@ -2550,8 +2570,10 @@ static void selinux_bprm_committing_creds(const struct linux_binprm *bprm)
* higher than the default soft limit for cases where the default is
* lower than the hard limit, e.g. RLIMIT_CORE or RLIMIT_STACK.
*/
- /* Only check against the current namespace because the SID
- * does not change in the parent.
+ /*
+ * Only check against the current SELinux namespace
+ * because only the SID in the current namespace
+ * is changed by a transition.
*/
rc = avc_has_perm(current_selinux_state,
new_tsec->osid, new_tsec->sid, SECCLASS_PROCESS,
@@ -2593,8 +2615,10 @@ static void selinux_bprm_committed_creds(const struct linux_binprm *bprm)
* This must occur _after_ the task SID has been updated so that any
* kill done after the flush will be checked against the new SID.
*/
- /* Only check against the current namespace because the SID
- * does not change in the parent.
+ /*
+ * Only check against the current SELinux namespace
+ * because only the SID in the current namespace
+ * is changed by a transition.
*/
rc = avc_has_perm(current_selinux_state,
osid, sid, SECCLASS_PROCESS, PROCESS__SIGINH, NULL);
@@ -6812,6 +6836,11 @@ static int selinux_lsm_setattr(u64 attr, void *value, size_t size)
}
/* Check permissions for the transition. */
+ /*
+ * Only check against the current SELinux namespace
+ * because only the SID in the current namespace
+ * is changed by a transition.
+ */
error = avc_has_perm(current_selinux_state,
tsec->sid, sid, SECCLASS_PROCESS,
PROCESS__DYNTRANSITION, NULL);
@@ -6822,6 +6851,11 @@ static int selinux_lsm_setattr(u64 attr, void *value, size_t size)
Otherwise, leave SID unchanged and fail. */
ptsid = ptrace_parent_sid();
if (ptsid != 0) {
+ /*
+ * Only check against the current SELinux namespace
+ * because only the SID in the current namespace
+ * is changed by a transition.
+ */
error = avc_has_perm(current_selinux_state,
ptsid, sid, SECCLASS_PROCESS,
PROCESS__PTRACE, NULL);
--
2.50.1
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [PATCH v7 37/42] selinux: convert xfrm and netlabel permission checks
2025-08-14 13:25 [PATCH v7 00/42] SELinux namespace support Stephen Smalley
` (35 preceding siblings ...)
2025-08-14 13:26 ` [PATCH v7 36/42] selinux: annotate process transition " Stephen Smalley
@ 2025-08-14 13:26 ` Stephen Smalley
2025-08-14 13:26 ` [PATCH v7 38/42] selinux: switch selinux_lsm_setattr() checks to current namespace Stephen Smalley
` (4 subsequent siblings)
41 siblings, 0 replies; 43+ messages in thread
From: Stephen Smalley @ 2025-08-14 13:26 UTC (permalink / raw)
To: selinux; +Cc: paul, omosnace, netdev, horms, Stephen Smalley
Convert the xfrm and netlabel permission checks to use the appropriate
namespace-aware helper for each check. When in process context, use
cred_tsid_has_perm() to check permission; when not in process context,
use selinux_state_has_perm().
Signed-off-by: Stephen Smalley <stephen.smalley.work@gmail.com>
---
security/selinux/netlabel.c | 6 +++---
security/selinux/xfrm.c | 33 ++++++++++++++++++---------------
2 files changed, 21 insertions(+), 18 deletions(-)
diff --git a/security/selinux/netlabel.c b/security/selinux/netlabel.c
index 9c360f2ee7fc..06ce45f628f8 100644
--- a/security/selinux/netlabel.c
+++ b/security/selinux/netlabel.c
@@ -137,7 +137,7 @@ void selinux_netlbl_cache_invalidate(void)
* @gateway: true if host is acting as a gateway, false otherwise
*
* Description:
- * When a packet is dropped due to a call to avc_has_perm() pass the error
+ * When a packet is dropped due to a permission denial, pass the error
* code to the NetLabel subsystem so any protocol specific processing can be
* done. This is safe to call even if you are unsure if NetLabel labeling is
* present on the packet, NetLabel is smart enough to only act when it should.
@@ -478,8 +478,8 @@ int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
perm = RAWIP_SOCKET__RECVFROM;
}
- rc = avc_has_perm(sksec->state, sksec->sid, nlbl_sid, sksec->sclass,
- perm, ad);
+ rc = selinux_state_has_perm(sksec->state, sksec->sid, nlbl_sid,
+ sksec->sclass, perm, ad);
if (rc == 0)
return 0;
diff --git a/security/selinux/xfrm.c b/security/selinux/xfrm.c
index 411e1f1ba4cd..92fb31661e54 100644
--- a/security/selinux/xfrm.c
+++ b/security/selinux/xfrm.c
@@ -102,9 +102,9 @@ static int selinux_xfrm_alloc_user(struct xfrm_sec_ctx **ctxp,
if (rc)
goto err;
- rc = avc_has_perm(current_selinux_state,
- current_sid(), ctx->ctx_sid,
- SECCLASS_ASSOCIATION, ASSOCIATION__SETCONTEXT, NULL);
+ rc = cred_tsid_has_perm(current_cred(), ctx->ctx_sid,
+ SECCLASS_ASSOCIATION, ASSOCIATION__SETCONTEXT,
+ NULL);
if (rc)
goto err;
@@ -137,10 +137,9 @@ static int selinux_xfrm_delete(struct xfrm_sec_ctx *ctx)
if (!ctx)
return 0;
- return avc_has_perm(current_selinux_state,
- current_sid(), ctx->ctx_sid,
- SECCLASS_ASSOCIATION, ASSOCIATION__SETCONTEXT,
- NULL);
+ return cred_tsid_has_perm(current_cred(), ctx->ctx_sid,
+ SECCLASS_ASSOCIATION,
+ ASSOCIATION__SETCONTEXT, NULL);
}
/*
@@ -162,8 +161,9 @@ int selinux_xfrm_policy_lookup(struct xfrm_sec_ctx *ctx, u32 fl_secid)
if (!selinux_authorizable_ctx(ctx))
return -EINVAL;
- rc = avc_has_perm(state, fl_secid, ctx->ctx_sid,
- SECCLASS_ASSOCIATION, ASSOCIATION__POLMATCH, NULL);
+ rc = selinux_state_has_perm(state, fl_secid, ctx->ctx_sid,
+ SECCLASS_ASSOCIATION,
+ ASSOCIATION__POLMATCH, NULL);
return (rc == -EACCES ? -ESRCH : rc);
}
@@ -205,8 +205,9 @@ int selinux_xfrm_state_pol_flow_match(struct xfrm_state *x,
/* We don't need a separate SA Vs. policy polmatch check since the SA
* is now of the same label as the flow and a flow Vs. policy polmatch
* check had already happened in selinux_xfrm_policy_lookup() above. */
- return (avc_has_perm(state, flic_sid, state_sid, SECCLASS_ASSOCIATION,
- ASSOCIATION__SENDTO, NULL) ? 0 : 1);
+ return (selinux_state_has_perm(state, flic_sid, state_sid,
+ SECCLASS_ASSOCIATION,
+ ASSOCIATION__SENDTO, NULL) ? 0 : 1);
}
static u32 selinux_xfrm_skb_sid_egress(struct sk_buff *skb)
@@ -425,8 +426,9 @@ int selinux_xfrm_sock_rcv_skb(struct sk_security_struct *sksec, struct sk_buff *
/* This check even when there's no association involved is intended,
* according to Trent Jaeger, to make sure a process can't engage in
* non-IPsec communication unless explicitly allowed by policy. */
- return avc_has_perm(sksec->state, sk_sid, peer_sid,
- SECCLASS_ASSOCIATION, ASSOCIATION__RECVFROM, ad);
+ return selinux_state_has_perm(sksec->state, sk_sid, peer_sid,
+ SECCLASS_ASSOCIATION,
+ ASSOCIATION__RECVFROM, ad);
}
/*
@@ -469,6 +471,7 @@ int selinux_xfrm_postroute_last(u32 sk_sid, struct sk_buff *skb,
/* This check even when there's no association involved is intended,
* according to Trent Jaeger, to make sure a process can't engage in
* non-IPsec communication unless explicitly allowed by policy. */
- return avc_has_perm(state, sk_sid, SECINITSID_UNLABELED,
- SECCLASS_ASSOCIATION, ASSOCIATION__SENDTO, ad);
+ return selinux_state_has_perm(state, sk_sid, SECINITSID_UNLABELED,
+ SECCLASS_ASSOCIATION,
+ ASSOCIATION__SENDTO, ad);
}
--
2.50.1
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [PATCH v7 38/42] selinux: switch selinux_lsm_setattr() checks to current namespace
2025-08-14 13:25 [PATCH v7 00/42] SELinux namespace support Stephen Smalley
` (36 preceding siblings ...)
2025-08-14 13:26 ` [PATCH v7 37/42] selinux: convert xfrm and netlabel " Stephen Smalley
@ 2025-08-14 13:26 ` Stephen Smalley
2025-08-14 13:26 ` [PATCH v7 39/42] selinux: make open_perms namespace-aware Stephen Smalley
` (3 subsequent siblings)
41 siblings, 0 replies; 43+ messages in thread
From: Stephen Smalley @ 2025-08-14 13:26 UTC (permalink / raw)
To: selinux; +Cc: paul, omosnace, netdev, horms, Stephen Smalley
Switch the selinux_lsm_setattr() checks to only check against
the current SELinux namespace because this operation only changes
the SID in the current namespace.
Signed-off-by: Stephen Smalley <stephen.smalley.work@gmail.com>
---
security/selinux/hooks.c | 44 ++++++++++++++++++++++------------------
1 file changed, 24 insertions(+), 20 deletions(-)
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index e35b3fb16bb8..15b0dd725f76 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -6721,35 +6721,41 @@ static int selinux_lsm_getattr(unsigned int attr, struct task_struct *p,
static int selinux_lsm_setattr(u64 attr, void *value, size_t size)
{
const struct cred *cred = current_cred();
+ struct selinux_state *state = current_selinux_state;
struct task_security_struct *tsec;
struct cred *new;
- u32 sid = 0, ptsid;
+ u32 mysid = current_sid(), sid = 0, ptsid;
int error;
char *str = value;
/*
* Basic control over ability to set these attributes at all.
*/
+ /*
+ * Only check against the current SELinux namespace
+ * because only the SID in the current namespace
+ * is changed by this operation.
+ */
switch (attr) {
case LSM_ATTR_EXEC:
- error = cred_self_has_perm(cred, SECCLASS_PROCESS,
- PROCESS__SETEXEC, NULL);
+ error = avc_has_perm(state, mysid, mysid, SECCLASS_PROCESS,
+ PROCESS__SETEXEC, NULL);
break;
case LSM_ATTR_FSCREATE:
- error = cred_self_has_perm(cred, SECCLASS_PROCESS,
- PROCESS__SETFSCREATE, NULL);
+ error = avc_has_perm(state, mysid, mysid, SECCLASS_PROCESS,
+ PROCESS__SETFSCREATE, NULL);
break;
case LSM_ATTR_KEYCREATE:
- error = cred_self_has_perm(cred, SECCLASS_PROCESS,
- PROCESS__SETKEYCREATE, NULL);
+ error = avc_has_perm(state, mysid, mysid, SECCLASS_PROCESS,
+ PROCESS__SETKEYCREATE, NULL);
break;
case LSM_ATTR_SOCKCREATE:
- error = cred_self_has_perm(cred, SECCLASS_PROCESS,
- PROCESS__SETSOCKCREATE, NULL);
+ error = avc_has_perm(state, mysid, mysid, SECCLASS_PROCESS,
+ PROCESS__SETSOCKCREATE, NULL);
break;
case LSM_ATTR_CURRENT:
- error = cred_self_has_perm(cred, SECCLASS_PROCESS,
- PROCESS__SETCURRENT, NULL);
+ error = avc_has_perm(state, mysid, mysid, SECCLASS_PROCESS,
+ PROCESS__SETCURRENT, NULL);
break;
default:
error = -EOPNOTSUPP;
@@ -6764,7 +6770,7 @@ static int selinux_lsm_setattr(u64 attr, void *value, size_t size)
str[size-1] = 0;
size--;
}
- error = security_context_to_sid(current_selinux_state, value, size,
+ error = security_context_to_sid(state, value, size,
&sid, GFP_KERNEL);
if (error == -EINVAL && attr == LSM_ATTR_FSCREATE) {
if (!has_cap_mac_admin(true)) {
@@ -6790,9 +6796,8 @@ static int selinux_lsm_setattr(u64 attr, void *value, size_t size)
return error;
}
- error = security_context_to_sid_force(
- current_selinux_state,
- value, size, &sid);
+ error = security_context_to_sid_force(state, value,
+ size, &sid);
}
if (error)
return error;
@@ -6829,7 +6834,7 @@ static int selinux_lsm_setattr(u64 attr, void *value, size_t size)
goto abort_change;
if (!current_is_single_threaded()) {
- error = security_bounded_transition(current_selinux_state,
+ error = security_bounded_transition(state,
tsec->sid, sid);
if (error)
goto abort_change;
@@ -6841,8 +6846,7 @@ static int selinux_lsm_setattr(u64 attr, void *value, size_t size)
* because only the SID in the current namespace
* is changed by a transition.
*/
- error = avc_has_perm(current_selinux_state,
- tsec->sid, sid, SECCLASS_PROCESS,
+ error = avc_has_perm(state, tsec->sid, sid, SECCLASS_PROCESS,
PROCESS__DYNTRANSITION, NULL);
if (error)
goto abort_change;
@@ -6856,8 +6860,8 @@ static int selinux_lsm_setattr(u64 attr, void *value, size_t size)
* because only the SID in the current namespace
* is changed by a transition.
*/
- error = avc_has_perm(current_selinux_state,
- ptsid, sid, SECCLASS_PROCESS,
+ error = avc_has_perm(state, ptsid, sid,
+ SECCLASS_PROCESS,
PROCESS__PTRACE, NULL);
if (error)
goto abort_change;
--
2.50.1
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [PATCH v7 39/42] selinux: make open_perms namespace-aware
2025-08-14 13:25 [PATCH v7 00/42] SELinux namespace support Stephen Smalley
` (37 preceding siblings ...)
2025-08-14 13:26 ` [PATCH v7 38/42] selinux: switch selinux_lsm_setattr() checks to current namespace Stephen Smalley
@ 2025-08-14 13:26 ` Stephen Smalley
2025-08-14 13:26 ` [PATCH v7 40/42] selinux: split cred_ssid_has_perm() into two cases Stephen Smalley
` (2 subsequent siblings)
41 siblings, 0 replies; 43+ messages in thread
From: Stephen Smalley @ 2025-08-14 13:26 UTC (permalink / raw)
To: selinux; +Cc: paul, omosnace, netdev, horms, Stephen Smalley
Adjust the handling of the open_perms policy capability to
be namespace-aware. This ensures that file open permission
is checked against each namespace in accordance with the
namespace policy. Otherwise, a child SELinux namespace
could escape checking of file open permission in the
parent namespace by disabling it in its own policy.
Signed-off-by: Stephen Smalley <stephen.smalley.work@gmail.com>
---
security/selinux/hooks.c | 111 +++++++++++++++++++++-------
security/selinux/include/security.h | 5 +-
2 files changed, 85 insertions(+), 31 deletions(-)
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 15b0dd725f76..d83b764ab86b 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2028,22 +2028,6 @@ static inline u32 file_to_av(const struct file *file)
return av;
}
-/*
- * Convert a file to an access vector and include the correct
- * open permission.
- */
-static inline u32 open_file_to_av(struct file *file)
-{
- u32 av = file_to_av(file);
- struct inode *inode = file_inode(file);
-
- if (selinux_policycap_openperm() &&
- inode->i_sb->s_magic != SOCKFS_MAGIC)
- av |= FILE__OPEN;
-
- return av;
-}
-
/* Hook functions begin here. */
static int selinux_binder_set_context_mgr(const struct cred *mgr)
@@ -3332,7 +3316,13 @@ static int selinux_inode_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
const struct cred *cred = current_cred();
struct inode *inode = d_backing_inode(dentry);
unsigned int ia_valid = iattr->ia_valid;
- u32 av = FILE__WRITE;
+ struct inode_security_struct *isec;
+ struct task_security_struct *tsec;
+ struct selinux_state *state;
+ struct common_audit_data ad;
+ u32 ssid, tsid, av, requested;
+ u16 sclass;
+ int rc;
/* ATTR_FORCE is just used for ATTR_KILL_S[UG]ID. */
if (ia_valid & ATTR_FORCE) {
@@ -3346,13 +3336,41 @@ static int selinux_inode_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
ATTR_ATIME_SET | ATTR_MTIME_SET | ATTR_TIMES_SET))
return dentry_has_perm(cred, dentry, FILE__SETATTR);
- if (selinux_policycap_openperm() &&
- inode->i_sb->s_magic != SOCKFS_MAGIC &&
- (ia_valid & ATTR_SIZE) &&
- !(ia_valid & ATTR_FILE))
- av |= FILE__OPEN;
+ /*
+ * The following is an inlined version of dentry_has_perm()->
+ * inode_has_perm()->cred_tsid_has_perm() in order to specialize
+ * the requested permissions based on the open_perms policycap
+ * value in each namespace.
+ */
+ ad.type = LSM_AUDIT_DATA_DENTRY;
+ ad.u.dentry = dentry;
+ __inode_security_revalidate(inode, dentry, true);
+ if (unlikely(IS_PRIVATE(inode)))
+ return 0;
+ isec = selinux_inode(inode);
+ tsid = isec->sid;
+ sclass = isec->sclass;
+ av = FILE__WRITE;
+
+ do {
+ tsec = selinux_cred(cred);
+ ssid = tsec->sid;
+ state = tsec->state;
+ requested = av;
+
+ if (selinux_policycap_openperm(state) &&
+ inode->i_sb->s_magic != SOCKFS_MAGIC &&
+ (ia_valid & ATTR_SIZE) &&
+ !(ia_valid & ATTR_FILE))
+ requested |= FILE__OPEN;
+
+ rc = avc_has_perm(state, ssid, tsid, sclass, requested, &ad);
+ if (rc)
+ return rc;
+ cred = tsec->parent_cred;
+ } while (cred);
- return dentry_has_perm(cred, dentry, av);
+ return 0;
}
static int selinux_inode_getattr(const struct path *path)
@@ -4199,11 +4217,17 @@ static int selinux_file_receive(struct file *file)
static int selinux_file_open(struct file *file)
{
- struct file_security_struct *fsec;
- struct inode_security_struct *isec;
+ struct file_security_struct *fsec = selinux_file(file);
+ struct inode *inode = file_inode(file);
+ struct inode_security_struct *isec = inode_security(inode);
+ const struct cred *cred = file->f_cred;
+ struct task_security_struct *tsec;
+ struct selinux_state *state;
+ struct common_audit_data ad;
+ u32 ssid, tsid, av, requested;
+ u16 sclass;
+ int rc;
- fsec = selinux_file(file);
- isec = inode_security(file_inode(file));
/*
* Save inode label and policy sequence number
* at open-time so that selinux_file_permission
@@ -4221,7 +4245,38 @@ static int selinux_file_open(struct file *file)
* new inode label or new policy.
* This check is not redundant - do not remove.
*/
- return file_path_has_perm(file->f_cred, file, open_file_to_av(file));
+ /*
+ * The following is an inlined version of file_path_has_perm()->
+ * inode_has_perm()->cred_tsid_has_perm() in order to specialize
+ * the requested permissions based on the open_perms policycap
+ * value in each namespace.
+ */
+ ad.type = LSM_AUDIT_DATA_FILE;
+ ad.u.file = file;
+ cred = file->f_cred;
+ if (unlikely(IS_PRIVATE(inode)))
+ return 0;
+ tsid = isec->sid;
+ sclass = isec->sclass;
+ av = file_to_av(file);
+
+ do {
+ tsec = selinux_cred(cred);
+ ssid = tsec->sid;
+ state = tsec->state;
+ requested = av;
+
+ if (selinux_policycap_openperm(state) &&
+ inode->i_sb->s_magic != SOCKFS_MAGIC)
+ requested |= FILE__OPEN;
+
+ rc = avc_has_perm(state, ssid, tsid, sclass, requested, &ad);
+ if (rc)
+ return rc;
+ cred = tsec->parent_cred;
+ } while (cred);
+
+ return 0;
}
/* task security operations */
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
index 145ab528d71e..057f2da62d8a 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -232,10 +232,9 @@ static inline bool selinux_policycap_netpeer(void)
current_selinux_state->policycap[POLICYDB_CAP_NETPEER]);
}
-static inline bool selinux_policycap_openperm(void)
+static inline bool selinux_policycap_openperm(struct selinux_state *state)
{
- return READ_ONCE(
- current_selinux_state->policycap[POLICYDB_CAP_OPENPERM]);
+ return READ_ONCE(state->policycap[POLICYDB_CAP_OPENPERM]);
}
static inline bool selinux_policycap_extsockclass(void)
--
2.50.1
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [PATCH v7 40/42] selinux: split cred_ssid_has_perm() into two cases
2025-08-14 13:25 [PATCH v7 00/42] SELinux namespace support Stephen Smalley
` (38 preceding siblings ...)
2025-08-14 13:26 ` [PATCH v7 39/42] selinux: make open_perms namespace-aware Stephen Smalley
@ 2025-08-14 13:26 ` Stephen Smalley
2025-08-14 13:26 ` [PATCH v7 41/42] selinux: convert nlmsg_sock_has_extended_perms() to namespace-aware Stephen Smalley
2025-08-14 13:26 ` [PATCH v7 42/42] selinux: disallow writes to /sys/fs/selinux/user in non-init namespaces Stephen Smalley
41 siblings, 0 replies; 43+ messages in thread
From: Stephen Smalley @ 2025-08-14 13:26 UTC (permalink / raw)
To: selinux; +Cc: paul, omosnace, netdev, horms, Stephen Smalley
Split cred_ssid_has_perm() into two separate functions,
cred_obj_has_perm() to perform the namespace-aware checks
for inter-object checks like associate, and cred_ssid_has_perm()
to perform namespace-aware checks for socket and SysV IPC
checks where the SSID is in fact derived from the creating
task SID. Modify cred_ssid_has_perm() to only use the provided
ssid for the initial check in the current namespace, and to
instead use the task SID from the parent cred for each check
against the ancestor namespaces. This ensures that socket
and SysV IPC is correctly controlled in each namespace based
on the task's SID/context in that namespace.
We still need to determine whether peer labeling is correctly
handled across different namespaces, and if not, to adapt
appropriately.
Signed-off-by: Stephen Smalley <stephen.smalley.work@gmail.com>
---
security/selinux/avc.c | 59 ++++++++++++++++++++++++++++++++--
security/selinux/hooks.c | 16 ++++-----
security/selinux/include/avc.h | 3 ++
3 files changed, 67 insertions(+), 11 deletions(-)
diff --git a/security/selinux/avc.c b/security/selinux/avc.c
index 1095b7720eb8..fe77af02360b 100644
--- a/security/selinux/avc.c
+++ b/security/selinux/avc.c
@@ -1594,7 +1594,7 @@ int cred_tsid_has_perm_noaudit(const struct cred *cred, u32 tsid, u16 tclass,
}
/**
- * cred_ssid_has_perm - Check and audit permissions on a (ssid, tsid) pair
+ * cred_obj_has_perm - Check and audit permissions on a (ssid, tsid) pair
* @cred: subject credentials
* @ssid: source security identifier
* @tsid: target security identifier
@@ -1611,8 +1611,9 @@ int cred_tsid_has_perm_noaudit(const struct cred *cred, u32 tsid, u16 tclass,
* DO NOT USE when checking permissions involving cred/task SIDs; this
* helper is only for object-to-object checks.
*/
-int cred_ssid_has_perm(const struct cred *cred, u32 ssid, u32 tsid, u16 tclass,
- u32 requested, struct common_audit_data *ad)
+int cred_obj_has_perm(const struct cred *cred, u32 ssid, u32 tsid,
+ u16 tclass, u32 requested,
+ struct common_audit_data *ad)
{
struct task_security_struct *tsec;
struct selinux_state *state;
@@ -1631,6 +1632,58 @@ int cred_ssid_has_perm(const struct cred *cred, u32 ssid, u32 tsid, u16 tclass,
return 0;
}
+/**
+ * cred_ssid_has_perm - Check and audit permissions on a (ssid, tsid) pair
+ * @cred: subject credentials
+ * @ssid: source security identifier
+ * @tsid: target security identifier
+ * @tclass: target security class
+ * @requested: requested permissions, interpreted based on @tclass
+ * @ad: auxiliary audit data
+ *
+ * Check permissions between a source SID @ssid and a target SID @tsid for
+ * @cred's namespace and check between the parent cred's SID and %tsid
+ * for all ancestors to determine whether the @requested permissions are
+ * granted.
+ * Audit the granting or denial of permissions in accordance with the policy.
+ * Return %0 if all @requested permissions are granted, -%EACCES if any
+ * permissions are denied, or another -errno upon other errors.
+ * DO NOT USE when checking permissions involving cred/task SIDs; this
+ * helper is only for socket and IPC checks.
+ */
+int cred_ssid_has_perm(const struct cred *cred, u32 ssid, u32 tsid, u16 tclass,
+ u32 requested, struct common_audit_data *ad)
+{
+ struct task_security_struct *tsec;
+ struct selinux_state *state;
+ int rc;
+
+ /* Check using the provided ssid in the current namespace. */
+ tsec = selinux_cred(cred);
+ state = tsec->state;
+ rc = avc_has_perm(state, ssid, tsid, tclass, requested, ad);
+ if (rc)
+ return rc;
+
+ cred = tsec->parent_cred;
+ while (cred) {
+ /*
+ * In all ancestor namespaces, use the task SID from
+ * the corresponding credential as the subject SID.
+ */
+ tsec = selinux_cred(cred);
+ state = tsec->state;
+ ssid = tsec->sid;
+ rc = avc_has_perm(state, ssid, tsid, tclass, requested, ad);
+ if (rc)
+ return rc;
+
+ cred = tsec->parent_cred;
+ }
+
+ return 0;
+}
+
static u32 cred_sid_for_state(const struct cred *cred,
const struct selinux_state *state)
{
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index d83b764ab86b..b22dbb4a1a05 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -469,8 +469,8 @@ static int may_context_mount_inode_relabel(u32 sid,
if (rc)
return rc;
- return cred_ssid_has_perm(cred, sid, sbsec->sid, SECCLASS_FILESYSTEM,
- FILESYSTEM__ASSOCIATE, NULL);
+ return cred_obj_has_perm(cred, sid, sbsec->sid, SECCLASS_FILESYSTEM,
+ FILESYSTEM__ASSOCIATE, NULL);
}
static int selinux_is_genfs_special_handling(struct super_block *sb)
@@ -1857,9 +1857,9 @@ static int may_create(struct inode *dir,
if (rc)
return rc;
- return cred_ssid_has_perm(cred, newsid, sbsec->sid,
- SECCLASS_FILESYSTEM, FILESYSTEM__ASSOCIATE,
- &ad);
+ return cred_obj_has_perm(cred, newsid, sbsec->sid,
+ SECCLASS_FILESYSTEM, FILESYSTEM__ASSOCIATE,
+ &ad);
}
#define MAY_LINK 0
@@ -3494,9 +3494,9 @@ static int selinux_inode_setxattr(struct mnt_idmap *idmap,
if (rc)
return rc;
- return cred_ssid_has_perm(cred, newsid, sbsec->sid,
- SECCLASS_FILESYSTEM,
- FILESYSTEM__ASSOCIATE, &ad);
+ return cred_obj_has_perm(cred, newsid, sbsec->sid,
+ SECCLASS_FILESYSTEM,
+ FILESYSTEM__ASSOCIATE, &ad);
}
static int selinux_inode_set_acl(struct mnt_idmap *idmap,
diff --git a/security/selinux/include/avc.h b/security/selinux/include/avc.h
index cf437d0479f5..ce3df5a674f5 100644
--- a/security/selinux/include/avc.h
+++ b/security/selinux/include/avc.h
@@ -169,6 +169,9 @@ int cred_tsid_has_perm(const struct cred *cred, u32 tsid, u16 tclass,
int cred_tsid_has_perm_noaudit(const struct cred *cred, u32 tsid, u16 tclass,
u32 requested, struct av_decision *avd);
+int cred_obj_has_perm(const struct cred *cred, u32 ssid, u32 tsid, u16 tclass,
+ u32 requested, struct common_audit_data *ad);
+
int cred_ssid_has_perm(const struct cred *cred, u32 ssid, u32 tsid, u16 tclass,
u32 requested, struct common_audit_data *ad);
--
2.50.1
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [PATCH v7 41/42] selinux: convert nlmsg_sock_has_extended_perms() to namespace-aware
2025-08-14 13:25 [PATCH v7 00/42] SELinux namespace support Stephen Smalley
` (39 preceding siblings ...)
2025-08-14 13:26 ` [PATCH v7 40/42] selinux: split cred_ssid_has_perm() into two cases Stephen Smalley
@ 2025-08-14 13:26 ` Stephen Smalley
2025-08-14 13:26 ` [PATCH v7 42/42] selinux: disallow writes to /sys/fs/selinux/user in non-init namespaces Stephen Smalley
41 siblings, 0 replies; 43+ messages in thread
From: Stephen Smalley @ 2025-08-14 13:26 UTC (permalink / raw)
To: selinux; +Cc: paul, omosnace, netdev, horms, Stephen Smalley
Convert nlmsg_sock_has_extended_perms() to use the
cred_has_extended_perms() helper for namespace-aware checking.
Signed-off-by: Stephen Smalley <stephen.smalley.work@gmail.com>
---
security/selinux/hooks.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index b22dbb4a1a05..369e375bd9c6 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -6297,9 +6297,9 @@ static int nlmsg_sock_has_extended_perms(struct sock *sk, u32 perms, u16 nlmsg_t
driver = nlmsg_type >> 8;
xperm = nlmsg_type & 0xff;
- return avc_has_extended_perms(current_selinux_state, current_sid(),
- sksec->sid, sksec->sclass, perms,
- driver, AVC_EXT_NLMSG, xperm, &ad);
+ return cred_has_extended_perms(current_cred(), sksec->sid,
+ sksec->sclass, perms, driver,
+ AVC_EXT_NLMSG, xperm, &ad);
}
static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb)
--
2.50.1
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [PATCH v7 42/42] selinux: disallow writes to /sys/fs/selinux/user in non-init namespaces
2025-08-14 13:25 [PATCH v7 00/42] SELinux namespace support Stephen Smalley
` (40 preceding siblings ...)
2025-08-14 13:26 ` [PATCH v7 41/42] selinux: convert nlmsg_sock_has_extended_perms() to namespace-aware Stephen Smalley
@ 2025-08-14 13:26 ` Stephen Smalley
41 siblings, 0 replies; 43+ messages in thread
From: Stephen Smalley @ 2025-08-14 13:26 UTC (permalink / raw)
To: selinux; +Cc: paul, omosnace, netdev, horms, Stephen Smalley
Disallow writes to /sys/fs/selinux/user in non-init SELinux namespaces.
Signed-off-by: Stephen Smalley <stephen.smalley.work@gmail.com>
---
security/selinux/selinuxfs.c | 18 ++++++++++++++----
1 file changed, 14 insertions(+), 4 deletions(-)
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index b1ce3a98a241..f847767e5e15 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -1371,10 +1371,20 @@ static ssize_t sel_write_user(struct file *file, char *buf, size_t size)
int rc;
u32 i, len, nsids;
- pr_warn_ratelimited("SELinux: %s (%d) wrote to /sys/fs/selinux/user!"
- " This will not be supported in the future; please update your"
- " userspace.\n", current->comm, current->pid);
- ssleep(5);
+ if (state == init_selinux_state) {
+ pr_warn_ratelimited("SELinux: %s (%d) wrote to"
+ " /sys/fs/selinux/user! This will not be"
+ " supported in the future; please update your"
+ " userspace.\n", current->comm, current->pid);
+ ssleep(5);
+ } else {
+ pr_warn_ratelimited("SELinux: %s (%d) tried to write to"
+ " /sys/fs/selinux/user! This is not supported"
+ " in non-init SELinux namespaces; please"
+ " update your userspace.\n", current->comm,
+ current->pid);
+ return -EPERM;
+ }
/*
* Only check against the current namespace because
--
2.50.1
^ permalink raw reply related [flat|nested] 43+ messages in thread
end of thread, other threads:[~2025-08-14 13:27 UTC | newest]
Thread overview: 43+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-08-14 13:25 [PATCH v7 00/42] SELinux namespace support Stephen Smalley
2025-08-14 13:25 ` [PATCH v7 01/42] selinux: restore passing of selinux_state Stephen Smalley
2025-08-14 13:25 ` [PATCH v7 02/42] selinux: introduce current_selinux_state Stephen Smalley
2025-08-14 13:25 ` [PATCH v7 03/42] selinux: support multiple selinuxfs instances Stephen Smalley
2025-08-14 13:25 ` [PATCH v7 04/42] selinux: dynamically allocate selinux namespace Stephen Smalley
2025-08-14 13:25 ` [PATCH v7 05/42] netstate,selinux: create the selinux netlink socket per network namespace Stephen Smalley
2025-08-14 13:25 ` [PATCH v7 06/42] selinux: limit selinux netlink notifications to init namespace Stephen Smalley
2025-08-14 13:25 ` [PATCH v7 07/42] selinux: support per-task/cred selinux namespace Stephen Smalley
2025-08-14 13:25 ` [PATCH v7 08/42] selinux: introduce cred_selinux_state() and use it Stephen Smalley
2025-08-14 13:26 ` [PATCH v7 09/42] selinux: init inode from nearest initialized namespace Stephen Smalley
2025-08-14 13:26 ` [PATCH v7 10/42] selinux: add a selinuxfs interface to unshare selinux namespace Stephen Smalley
2025-08-14 13:26 ` [PATCH v7 11/42] selinux: add limits for SELinux namespaces Stephen Smalley
2025-08-14 13:26 ` [PATCH v7 12/42] selinux: exempt creation of init SELinux namespace from limits Stephen Smalley
2025-08-14 13:26 ` [PATCH v7 13/42] selinux: refactor selinux_state_create() Stephen Smalley
2025-08-14 13:26 ` [PATCH v7 14/42] selinux: allow userspace to detect non-init SELinux namespace Stephen Smalley
2025-08-14 13:26 ` [PATCH v7 15/42] selinuxfs: restrict write operations to the same selinux namespace Stephen Smalley
2025-08-14 13:26 ` [PATCH v7 16/42] selinux: introduce a global SID table Stephen Smalley
2025-08-14 13:26 ` [PATCH v7 17/42] selinux: wrap security server interfaces to use the " Stephen Smalley
2025-08-14 13:26 ` [PATCH v7 18/42] selinux: introduce a Kconfig option for SELinux namespaces Stephen Smalley
2025-08-14 13:26 ` [PATCH v7 19/42] selinux: eliminate global SID table if !CONFIG_SECURITY_SELINUX_NS Stephen Smalley
2025-08-14 13:26 ` [PATCH v7 20/42] selinux: maintain a small cache in the global SID table Stephen Smalley
2025-08-14 13:26 ` [PATCH v7 21/42] selinux: update hook functions to use correct selinux namespace Stephen Smalley
2025-08-14 13:26 ` [PATCH v7 22/42] selinux: introduce cred_task_has_perm() Stephen Smalley
2025-08-14 13:26 ` [PATCH v7 23/42] selinux: introduce cred_has_extended_perms() Stephen Smalley
2025-08-14 13:26 ` [PATCH v7 24/42] selinux: introduce cred_self_has_perm() Stephen Smalley
2025-08-14 13:26 ` [PATCH v7 25/42] selinux: introduce cred_has_perm() Stephen Smalley
2025-08-14 13:26 ` [PATCH v7 26/42] selinux: introduce cred_ssid_has_perm() and cred_other_has_perm() Stephen Smalley
2025-08-14 13:26 ` [PATCH v7 27/42] selinux: introduce task_obj_has_perm() Stephen Smalley
2025-08-14 13:26 ` [PATCH v7 28/42] selinux: update bprm hooks for selinux namespaces Stephen Smalley
2025-08-14 13:26 ` [PATCH v7 29/42] selinux: add kerneldoc to new permission checking functions Stephen Smalley
2025-08-14 13:26 ` [PATCH v7 30/42] selinux: convert selinux_file_send_sigiotask() to namespace-aware helper Stephen Smalley
2025-08-14 13:26 ` [PATCH v7 31/42] selinux: rename cred_has_perm*() to cred_tsid_has_perm*() Stephen Smalley
2025-08-14 13:26 ` [PATCH v7 32/42] selinux: update cred_tsid_has_perm_noaudit() to return the combined avd Stephen Smalley
2025-08-14 13:26 ` [PATCH v7 33/42] selinux: convert additional checks to cred_ssid_has_perm() Stephen Smalley
2025-08-14 13:26 ` [PATCH v7 34/42] selinux: introduce selinux_state_has_perm() Stephen Smalley
2025-08-14 13:26 ` [PATCH v7 35/42] selinux: annotate selinuxfs permission checks Stephen Smalley
2025-08-14 13:26 ` [PATCH v7 36/42] selinux: annotate process transition " Stephen Smalley
2025-08-14 13:26 ` [PATCH v7 37/42] selinux: convert xfrm and netlabel " Stephen Smalley
2025-08-14 13:26 ` [PATCH v7 38/42] selinux: switch selinux_lsm_setattr() checks to current namespace Stephen Smalley
2025-08-14 13:26 ` [PATCH v7 39/42] selinux: make open_perms namespace-aware Stephen Smalley
2025-08-14 13:26 ` [PATCH v7 40/42] selinux: split cred_ssid_has_perm() into two cases Stephen Smalley
2025-08-14 13:26 ` [PATCH v7 41/42] selinux: convert nlmsg_sock_has_extended_perms() to namespace-aware Stephen Smalley
2025-08-14 13:26 ` [PATCH v7 42/42] selinux: disallow writes to /sys/fs/selinux/user in non-init namespaces Stephen Smalley
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).