Pull selinux updates from Paul Moore:
- Thanks to help from the MPTCP folks, it looks like we have finally
sorted out a proper solution to the MPTCP socket labeling issue, see
the new security_mptcp_add_subflow() LSM hook.
- Fix the labeled NFS handling such that a labeled NFS share mounted
prior to the initial SELinux policy load is properly labeled once a
policy is loaded; more information in the commit description.
- Two patches to security/selinux/Makefile, the first took the cleanups
in v6.4 a bit further and the second removed the grouped targets
support as that functionality doesn't appear to be properly supported
prior to make v4.3.
- Deprecate the "fs" object context type in SELinux policies. The fs
object context type was an old vestige that was introduced back in
v2.6.12-rc2 but never really used.
- A number of small changes that remove dead code, clean up some
awkward bits, and generally improve the quality of the code. See the
individual commit descriptions for more information.
* tag 'selinux-pr-
20230626' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux:
selinux: avoid bool as identifier name
selinux: fix Makefile for versions of make < v4.3
selinux: make labeled NFS work when mounted before policy load
selinux: cleanup exit_sel_fs() declaration
selinux: deprecated fs ocon
selinux: make header files self-including
selinux: keep context struct members in sync
selinux: Implement mptcp_add_subflow hook
security, lsm: Introduce security_mptcp_add_subflow()
selinux: small cleanups in selinux_audit_rule_init()
selinux: declare read-only data arrays const
selinux: retain const qualifier on string literal in avtab_hash_eval()
selinux: drop return at end of void function avc_insert()
selinux: avc: drop unused function avc_disable()
selinux: adjust typos in comments
selinux: do not leave dangling pointer behind
selinux: more Makefile tweaks
struct sock *sk, struct sock *newsk)
LSM_HOOK(int, 0, sctp_assoc_established, struct sctp_association *asoc,
struct sk_buff *skb)
+LSM_HOOK(int, 0, mptcp_add_subflow, struct sock *sk, struct sock *ssk)
#endif /* CONFIG_SECURITY_NETWORK */
#ifdef CONFIG_SECURITY_INFINIBAND
struct sock *newsk);
int security_sctp_assoc_established(struct sctp_association *asoc,
struct sk_buff *skb);
+int security_mptcp_add_subflow(struct sock *sk, struct sock *ssk);
#else /* CONFIG_SECURITY_NETWORK */
static inline int security_unix_stream_connect(struct sock *sock,
{
return 0;
}
+
+static inline int security_mptcp_add_subflow(struct sock *sk, struct sock *ssk)
+{
+ return 0;
+}
#endif /* CONFIG_SECURITY_NETWORK */
#ifdef CONFIG_SECURITY_INFINIBAND
lock_sock_nested(sf->sk, SINGLE_DEPTH_NESTING);
+ err = security_mptcp_add_subflow(sk, sf->sk);
+ if (err)
+ goto release_ssk;
+
/* the newly created socket has to be in the same cgroup as its parent */
mptcp_attach_cgroup(sk, sf->sk);
get_net_track(net, &sf->sk->ns_tracker, GFP_KERNEL);
sock_inuse_add(net, 1);
err = tcp_set_ulp(sf->sk, "mptcp");
+
+release_ssk:
release_sock(sf->sk);
if (err) {
}
EXPORT_SYMBOL(security_sctp_assoc_established);
+/**
+ * security_mptcp_add_subflow() - Inherit the LSM label from the MPTCP socket
+ * @sk: the owning MPTCP socket
+ * @ssk: the new subflow
+ *
+ * Update the labeling for the given MPTCP subflow, to match the one of the
+ * owning MPTCP socket. This hook has to be called after the socket creation and
+ * initialization via the security_socket_create() and
+ * security_socket_post_create() LSM hooks.
+ *
+ * Return: Returns 0 on success or a negative error code on failure.
+ */
+int security_mptcp_add_subflow(struct sock *sk, struct sock *ssk)
+{
+ return call_int_hook(mptcp_add_subflow, 0, sk, ssk);
+}
+
#endif /* CONFIG_SECURITY_NETWORK */
#ifdef CONFIG_SECURITY_INFINIBAND
# Makefile for building the SELinux module as part of the kernel tree.
#
+# NOTE: There are a number of improvements that can be made to this Makefile
+# once the kernel requires make v4.3 or greater; the most important feature
+# lacking in older versions of make is support for grouped targets. These
+# improvements are noted inline in the Makefile below ...
+
obj-$(CONFIG_SECURITY_SELINUX) := selinux.o
+ccflags-y := -I$(srctree)/security/selinux -I$(srctree)/security/selinux/include
+
selinux-y := avc.o hooks.o selinuxfs.o netlink.o nlmsgtab.o netif.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
selinux-$(CONFIG_SECURITY_NETWORK_XFRM) += xfrm.o
-
selinux-$(CONFIG_NETLABEL) += netlabel.o
-
selinux-$(CONFIG_SECURITY_INFINIBAND) += ibpkey.o
-
selinux-$(CONFIG_IMA) += ima.o
-ccflags-y := -I$(srctree)/security/selinux -I$(srctree)/security/selinux/include
+genhdrs := flask.h av_permissions.h
+# see the note above, replace the dependency rule with the one below:
+# $(addprefix $(obj)/,$(selinux-y)): $(addprefix $(obj)/,$(genhdrs))
$(addprefix $(obj)/,$(selinux-y)): $(obj)/flask.h
-quiet_cmd_flask = GEN $(obj)/flask.h $(obj)/av_permissions.h
- cmd_flask = $< $(obj)/flask.h $(obj)/av_permissions.h
+quiet_cmd_genhdrs = GEN $(addprefix $(obj)/,$(genhdrs))
+ cmd_genhdrs = $< $(addprefix $(obj)/,$(genhdrs))
-targets += flask.h av_permissions.h
-# once make >= 4.3 is required, we can use grouped targets in the rule below,
-# which basically involves adding both headers and a '&' before the colon, see
-# the example below:
-# $(obj)/flask.h $(obj)/av_permissions.h &: scripts/selinux/...
+# see the note above, replace the $targets and 'flask.h' rule with the lines
+# below:
+# targets += $(genhdrs)
+# $(addprefix $(obj)/,$(genhdrs)) &: scripts/selinux/...
+targets += flask.h
$(obj)/flask.h: scripts/selinux/genheaders/genheaders FORCE
- $(call if_changed,flask)
+ $(call if_changed,genhdrs)
hlist_add_head_rcu(&node->list, head);
found:
spin_unlock_irqrestore(lock, flag);
- return;
}
/**
{
return selinux_avc.avc_cache.latest_notif;
}
-
-void avc_disable(void)
-{
- /*
- * If you are looking at this because you have realized that we are
- * not destroying the avc_node_cachep it might be easy to fix, but
- * I don't know the memory barrier semantics well enough to know. It's
- * possible that some other task dereferenced security_ops when
- * it still pointed to selinux operations. If that is the case it's
- * possible that it is about to use the avc and is about to need the
- * avc_node_cachep. I know I could wrap the security.c security_ops call
- * in an rcu_lock, but seriously, it's not worth it. Instead I just flush
- * the cache and get that memory back.
- */
- if (avc_node_cachep) {
- avc_flush();
- /* kmem_cache_destroy(avc_node_cachep); */
- }
-}
};
#define A(s, has_arg) {#s, sizeof(#s) - 1, Opt_##s, has_arg}
-static struct {
+static const struct {
const char *name;
int len;
int opt;
u32 defcontext_sid = 0;
int rc = 0;
+ /*
+ * Specifying internal flags without providing a place to
+ * place the results is not allowed
+ */
+ if (kern_flags && !set_kern_flags)
+ return -EINVAL;
+
mutex_lock(&sbsec->lock);
if (!selinux_initialized()) {
/* Defer initialization until selinux_complete_init,
after the initial policy is loaded and the security
server is ready to handle calls. */
+ if (kern_flags & SECURITY_LSM_NATIVE_LABELS) {
+ sbsec->flags |= SE_SBNATIVE;
+ *set_kern_flags |= SECURITY_LSM_NATIVE_LABELS;
+ }
goto out;
}
rc = -EINVAL;
"before the security server is initialized\n");
goto out;
}
- if (kern_flags && !set_kern_flags) {
- /* Specifying internal flags without providing a place to
- * place the results is not allowed */
- rc = -EINVAL;
- goto out;
- }
/*
* Binary mount data FS will come through this function twice. Once
* sets the label used on all file below the mountpoint, and will set
* the superblock context if not already set.
*/
- if (kern_flags & SECURITY_LSM_NATIVE_LABELS && !context_sid) {
+ if (sbsec->flags & SE_SBNATIVE) {
+ /*
+ * This means we are initializing a superblock that has been
+ * mounted before the SELinux was initialized and the
+ * filesystem requested native labeling. We had already
+ * returned SECURITY_LSM_NATIVE_LABELS in *set_kern_flags
+ * in the original mount attempt, so now we just need to set
+ * the SECURITY_FS_USE_NATIVE behavior.
+ */
+ sbsec->behavior = SECURITY_FS_USE_NATIVE;
+ } else if (kern_flags & SECURITY_LSM_NATIVE_LABELS && !context_sid) {
sbsec->behavior = SECURITY_FS_USE_NATIVE;
*set_kern_flags |= SECURITY_LSM_NATIVE_LABELS;
}
int set_rootcontext = (oldsbsec->flags & ROOTCONTEXT_MNT);
/*
- * 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())
- return 0;
-
- /*
* Specifying internal flags without providing a place to
* place the results is not allowed.
*/
if (kern_flags && !set_kern_flags)
return -EINVAL;
+ mutex_lock(&newsbsec->lock);
+
+ /*
+ * 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 (kern_flags & SECURITY_LSM_NATIVE_LABELS) {
+ newsbsec->flags |= SE_SBNATIVE;
+ *set_kern_flags |= SECURITY_LSM_NATIVE_LABELS;
+ }
+ goto out;
+ }
+
/* how can we clone if the old one wasn't set up?? */
BUG_ON(!(oldsbsec->flags & SE_SBINITIALIZED));
/* if fs is reusing a sb, make sure that the contexts match */
if (newsbsec->flags & SE_SBINITIALIZED) {
+ mutex_unlock(&newsbsec->lock);
if ((kern_flags & SECURITY_LSM_NATIVE_LABELS) && !set_context)
*set_kern_flags |= SECURITY_LSM_NATIVE_LABELS;
return selinux_cmp_sb_context(oldsb, newsb);
}
- mutex_lock(&newsbsec->lock);
-
newsbsec->flags = oldsbsec->flags;
newsbsec->sid = oldsbsec->sid;
}
/*
- * NOTE: the caller is resposible for freeing the memory even if on error.
+ * NOTE: the caller is responsible for freeing the memory even if on error.
*/
static int selinux_add_opt(int token, const char *s, void **mnt_opts)
{
spin_unlock(&isec->lock);
switch (sbsec->behavior) {
+ /*
+ * In case of SECURITY_FS_USE_NATIVE we need to re-fetch the labels
+ * via xattr when called from delayed_superblock_init().
+ */
case SECURITY_FS_USE_NATIVE:
- break;
case SECURITY_FS_USE_XATTR:
if (!(inode->i_opflags & IOP_XATTR)) {
sid = sbsec->def_sid;
selinux_netlbl_sctp_sk_clone(sk, newsk);
}
+static int selinux_mptcp_add_subflow(struct sock *sk, struct sock *ssk)
+{
+ struct sk_security_struct *ssksec = ssk->sk_security;
+ struct sk_security_struct *sksec = sk->sk_security;
+
+ ssksec->sclass = sksec->sclass;
+ ssksec->sid = sksec->sid;
+
+ /* replace the existing subflow label deleting the existing one
+ * and re-recreating a new label using the updated context
+ */
+ selinux_netlbl_sk_security_free(ssksec);
+ return selinux_netlbl_socket_post_create(ssk, ssk->sk_family);
+}
+
static int selinux_inet_conn_request(const struct sock *sk, struct sk_buff *skb,
struct request_sock *req)
{
LSM_HOOK_INIT(sctp_sk_clone, selinux_sctp_sk_clone),
LSM_HOOK_INIT(sctp_bind_connect, selinux_sctp_bind_connect),
LSM_HOOK_INIT(sctp_assoc_established, selinux_sctp_assoc_established),
+ LSM_HOOK_INIT(mptcp_add_subflow, selinux_mptcp_add_subflow),
LSM_HOOK_INIT(inet_conn_request, selinux_inet_conn_request),
LSM_HOOK_INIT(inet_csk_clone, selinux_inet_csk_clone),
LSM_HOOK_INIT(inet_conn_established, selinux_inet_conn_established),
*
* Author: Lakshmi Ramasubramanian (nramas@linux.microsoft.com)
*
- * Measure critical data structures maintainted by SELinux
+ * Measure critical data structures maintained by SELinux
* using IMA subsystem.
*/
#include <linux/vmalloc.h>
* selinux_audit_rule_match - determine if a context ID matches a rule.
* @sid: the context ID to check
* @field: the field this rule refers to
- * @op: the operater the rule uses
+ * @op: the operator the rule uses
* @rule: pointer to the audit rule to check against
*
* Returns 1 if the context id matches the rule, 0 if it does not, and
unsigned int avc_get_cache_threshold(void);
void avc_set_cache_threshold(unsigned int cache_threshold);
-/* Attempt to free avc node cache */
-void avc_disable(void);
-
#ifdef CONFIG_SECURITY_SELINUX_AVC_STATS
DECLARE_PER_CPU(struct avc_cache_stats, avc_cache_stats);
#endif
#define _SELINUX_IB_PKEY_H
#include <linux/types.h>
+#include "flask.h"
#ifdef CONFIG_SECURITY_INFINIBAND
void sel_ib_pkey_flush(void);
*
* Author: Lakshmi Ramasubramanian (nramas@linux.microsoft.com)
*
- * Measure critical data structures maintainted by SELinux
+ * Measure critical data structures maintained by SELinux
* using IMA subsystem.
*/
/* SPDX-License-Identifier: GPL-2.0 */
+
+#include <linux/stddef.h>
+
static const char *const initial_sid_to_string[] = {
NULL,
"kernel",
#define SE_SBPROC 0x0200
#define SE_SBGENFS 0x0400
#define SE_SBGENFS_XATTR 0x0800
+#define SE_SBNATIVE 0x1000
#define CONTEXT_STR "context"
#define FSCONTEXT_STR "fscontext"
extern void selinux_status_update_setenforce(int enforcing);
extern void selinux_status_update_policyload(int seqno);
extern void selinux_complete_init(void);
-extern void exit_sel_fs(void);
extern struct path selinux_null;
extern void selnl_notify_setenforce(int val);
extern void selnl_notify_policyload(u32 seqno);
*/
void selinux_netlbl_sk_security_free(struct sk_security_struct *sksec)
{
- if (sksec->nlbl_secattr != NULL)
- netlbl_secattr_free(sksec->nlbl_secattr);
+ if (!sksec->nlbl_secattr)
+ return;
+
+ netlbl_secattr_free(sksec->nlbl_secattr);
+ sksec->nlbl_secattr = NULL;
+ sksec->nlbl_state = NLBL_UNSET;
}
/**
* either whitespace or multibyte characters, they shall be
* encoded based on the percentage-encoding rule.
* If not encoded, the sscanf logic picks up only left-half
- * of the supplied name; splitted by a whitespace unexpectedly.
+ * of the supplied name; split by a whitespace unexpectedly.
*/
char *r, *w;
int c1, c2;
struct super_block *sb = dir->d_sb;
struct selinux_fs_info *fsi = sb->s_fs_info;
int i;
- static struct tree_descr files[] = {
+ static const struct tree_descr files[] = {
{ "sidtab_hash_stats", &sel_sidtab_hash_stats_ops, S_IRUGO },
};
return avtab_alloc_common(new, orig->nslot);
}
-void avtab_hash_eval(struct avtab *h, char *tag)
+void avtab_hash_eval(struct avtab *h, const char *tag)
{
int i, chain_len, slots_used, max_chain_len;
unsigned long long chain2_len_sum;
int avtab_alloc_dup(struct avtab *new, const struct avtab *orig);
struct avtab_datum *avtab_search(struct avtab *h, const struct avtab_key *k);
void avtab_destroy(struct avtab *h);
-void avtab_hash_eval(struct avtab *h, char *tag);
+void avtab_hash_eval(struct avtab *h, const char *tag);
struct policydb;
int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol,
if (sp == (COND_EXPR_MAXDEPTH - 1))
return -1;
sp++;
- s[sp] = p->bool_val_to_struct[node->bool - 1]->state;
+ s[sp] = p->bool_val_to_struct[node->boolean - 1]->state;
break;
case COND_NOT:
if (sp < 0)
return 0;
}
- if (expr->bool > p->p_bools.nprim) {
+ if (expr->boolean > p->p_bools.nprim) {
pr_err("SELinux: conditional expressions uses unknown bool.\n");
return 0;
}
return rc;
expr->expr_type = le32_to_cpu(buf[0]);
- expr->bool = le32_to_cpu(buf[1]);
+ expr->boolean = le32_to_cpu(buf[1]);
if (!expr_node_isvalid(p, expr))
return -EINVAL;
for (i = 0; i < node->expr.len; i++) {
buf[0] = cpu_to_le32(node->expr.nodes[i].expr_type);
- buf[1] = cpu_to_le32(node->expr.nodes[i].bool);
+ buf[1] = cpu_to_le32(node->expr.nodes[i].boolean);
rc = put_entry(buf, sizeof(u32), 2, fp);
if (rc)
return rc;
#define COND_NEQ 7 /* bool != bool */
#define COND_LAST COND_NEQ
u32 expr_type;
- u32 bool;
+ u32 boolean;
};
struct cond_expr {
rc = mls_context_cpy(dst, src);
if (rc) {
kfree(dst->str);
+ dst->str = NULL;
+ dst->len = 0;
return rc;
}
return 0;
#include "services.h"
#ifdef DEBUG_HASHES
-static const char *symtab_name[SYM_NUM] = {
+static const char *const symtab_name[SYM_NUM] = {
"common prefixes",
"classes",
"roles",
if (rc)
goto out;
+ if (i == OCON_FS)
+ pr_warn("SELinux: void and deprecated fs ocon %s\n",
+ c->u.name);
+
rc = context_read_and_validate(&c->context[0], p, fp);
if (rc)
goto out;
/* object context array indices */
#define OCON_ISID 0 /* initial SIDs */
-#define OCON_FS 1 /* unlabeled file systems */
+#define OCON_FS 1 /* unlabeled file systems (deprecated) */
#define OCON_PORT 2 /* TCP and UDP port numbers */
#define OCON_NETIF 3 /* network interfaces */
#define OCON_NODE 4 /* nodes */
/*
* flag which drivers have permissions
- * only looking for ioctl based extended permssions
+ * only looking for ioctl based extended permissions
*/
void services_compute_xperms_drivers(
struct extended_perms *xperms,
tmprule = kzalloc(sizeof(struct selinux_audit_rule), GFP_KERNEL);
if (!tmprule)
return -ENOMEM;
-
context_init(&tmprule->au_ctxt);
rcu_read_lock();
policy = rcu_dereference(state->policy);
policydb = &policy->policydb;
-
tmprule->au_seqno = policy->latest_granting;
-
switch (field) {
case AUDIT_SUBJ_USER:
case AUDIT_OBJ_USER:
- rc = -EINVAL;
userdatum = symtab_search(&policydb->p_users, rulestr);
- if (!userdatum)
- goto out;
+ if (!userdatum) {
+ rc = -EINVAL;
+ goto err;
+ }
tmprule->au_ctxt.user = userdatum->value;
break;
case AUDIT_SUBJ_ROLE:
case AUDIT_OBJ_ROLE:
- rc = -EINVAL;
roledatum = symtab_search(&policydb->p_roles, rulestr);
- if (!roledatum)
- goto out;
+ if (!roledatum) {
+ rc = -EINVAL;
+ goto err;
+ }
tmprule->au_ctxt.role = roledatum->value;
break;
case AUDIT_SUBJ_TYPE:
case AUDIT_OBJ_TYPE:
- rc = -EINVAL;
typedatum = symtab_search(&policydb->p_types, rulestr);
- if (!typedatum)
- goto out;
+ if (!typedatum) {
+ rc = -EINVAL;
+ goto err;
+ }
tmprule->au_ctxt.type = typedatum->value;
break;
case AUDIT_SUBJ_SEN:
rc = mls_from_string(policydb, rulestr, &tmprule->au_ctxt,
GFP_ATOMIC);
if (rc)
- goto out;
+ goto err;
break;
}
- rc = 0;
-out:
rcu_read_unlock();
- if (rc) {
- selinux_audit_rule_free(tmprule);
- tmprule = NULL;
- }
-
*rule = tmprule;
+ return 0;
+err:
+ rcu_read_unlock();
+ selinux_audit_rule_free(tmprule);
+ *rule = NULL;
return rc;
}