1

selinux/stable-6.12 PR 20240911

-----BEGIN PGP SIGNATURE-----
 
 iQJIBAABCAAyFiEES0KozwfymdVUl37v6iDy2pc3iXMFAmbiGE0UHHBhdWxAcGF1
 bC1tb29yZS5jb20ACgkQ6iDy2pc3iXMeZA/+KwrK8bHSm+y9USrYaI4S2biiomsb
 GxNS6j0yIvg6uogWI2q8uTLXDdKMuJy88i7DHAMze+k6sSg8w6yEpFngFKeSAFpa
 7X6iF/4EU2ZjwHnKRbL5r5DDGyGeKm+GxCmjkwx/Xo+Qfk85D0mzjcXYiXkwRa2h
 DGdL34XztCfJNhJpPnnHDwh6OvVTY/c20g684D/7RMAXCkOq5r5SCfRK4SX1SpaT
 ge9DEm1Oz7cC4zY0yUMby6ibBmCsfjIIO1aIXFgf1IHjKOIuMzESIG6YwphnU2zp
 mI+7Zy6vvMd3dWDTxeMKqSsu43R3jkaclUnxyORmRD2noe7ehTvgPsQp31C9mmu1
 JF+50TjkiONGkuWoYsCdRDAZnpA1GLU5cU0Y3ENDcXazV5xt9omXIek4En2MlV/S
 DsXznvyaEJrAlZUBHZcJQwao394ZsPd+4nAelBTrbu+Ok2YD1p/GIv0va+lHIgZp
 xUsRNbOs/24bxW0k6XXgv8nFhsiBuXctB4GF1x4Dw2rvUqYtSJEK7tpq5B3yWAPs
 R57xKyELZrNTkf/2jcoCRQb9EODmhefYxYvN0fVgAKrzBbtVlOLltncKu3PYD8Vl
 yQPLKlu2NaER3ipJqMIFMi+O945YWPB47pNbKFVQJmyneGgc7++It1fVmvnFqWlt
 xP+p81tIM5E++Gw=
 =VwaX
 -----END PGP SIGNATURE-----

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

Pull selinux updates from Paul Moore:

 - Ensure that both IPv4 and IPv6 connections are properly initialized

   While we always properly initialized IPv4 connections early in their
   life, we missed the necessary IPv6 change when we were adding IPv6
   support.

 - Annotate the SELinux inode revalidation function to quiet KCSAN

   KCSAN correctly identifies a race in __inode_security_revalidate()
   when we check to see if an inode's SELinux has been properly
   initialized. While KCSAN is correct, it is an intentional choice made
   for performance reasons; if necessary, we check the state a second
   time, this time with a lock held, before initializing the inode's
   state.

 - Code cleanups, simplification, etc.

   A handful of individual patches to simplify some SELinux kernel
   logic, improve return code granularity via ERR_PTR(), follow the
   guidance on using KMEM_CACHE(), and correct some minor style
   problems.

* tag 'selinux-pr-20240911' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux:
  selinux: fix style problems in security/selinux/include/audit.h
  selinux: simplify avc_xperms_audit_required()
  selinux: mark both IPv4 and IPv6 accepted connection sockets as labeled
  selinux: replace kmem_cache_create() with KMEM_CACHE()
  selinux: annotate false positive data race to avoid KCSAN warnings
  selinux: refactor code to return ERR_PTR in selinux_netlbl_sock_genattr
  selinux: Streamline type determination in security_compute_sid
This commit is contained in:
Linus Torvalds 2024-09-16 16:55:42 +02:00
commit ad060dbbcf
8 changed files with 68 additions and 76 deletions

View File

@ -134,18 +134,10 @@ static inline u32 avc_hash(u32 ssid, u32 tsid, u16 tclass)
*/ */
void __init avc_init(void) void __init avc_init(void)
{ {
avc_node_cachep = kmem_cache_create("avc_node", sizeof(struct avc_node), avc_node_cachep = KMEM_CACHE(avc_node, SLAB_PANIC);
0, SLAB_PANIC, NULL); avc_xperms_cachep = KMEM_CACHE(avc_xperms_node, SLAB_PANIC);
avc_xperms_cachep = kmem_cache_create("avc_xperms_node", avc_xperms_decision_cachep = KMEM_CACHE(avc_xperms_decision_node, SLAB_PANIC);
sizeof(struct avc_xperms_node), avc_xperms_data_cachep = KMEM_CACHE(extended_perms_data, SLAB_PANIC);
0, SLAB_PANIC, NULL);
avc_xperms_decision_cachep = kmem_cache_create(
"avc_xperms_decision_node",
sizeof(struct avc_xperms_decision_node),
0, SLAB_PANIC, NULL);
avc_xperms_data_cachep = kmem_cache_create("avc_xperms_data",
sizeof(struct extended_perms_data),
0, SLAB_PANIC, NULL);
} }
int avc_get_hash_stats(char *page) int avc_get_hash_stats(char *page)
@ -396,7 +388,7 @@ static inline u32 avc_xperms_audit_required(u32 requested,
audited = denied & avd->auditdeny; audited = denied & avd->auditdeny;
if (audited && xpd) { if (audited && xpd) {
if (avc_xperms_has_perm(xpd, perm, XPERMS_DONTAUDIT)) if (avc_xperms_has_perm(xpd, perm, XPERMS_DONTAUDIT))
audited &= ~requested; audited = 0;
} }
} else if (result) { } else if (result) {
audited = denied = requested; audited = denied = requested;
@ -404,7 +396,7 @@ static inline u32 avc_xperms_audit_required(u32 requested,
audited = requested & avd->auditallow; audited = requested & avd->auditallow;
if (audited && xpd) { if (audited && xpd) {
if (!avc_xperms_has_perm(xpd, perm, XPERMS_AUDITALLOW)) if (!avc_xperms_has_perm(xpd, perm, XPERMS_AUDITALLOW))
audited &= ~requested; audited = 0;
} }
} }

View File

@ -282,8 +282,13 @@ static int __inode_security_revalidate(struct inode *inode,
might_sleep_if(may_sleep); might_sleep_if(may_sleep);
/*
* The check of isec->initialized below is racy but
* inode_doinit_with_dentry() will recheck with
* isec->lock held.
*/
if (selinux_initialized() && if (selinux_initialized() &&
isec->initialized != LABEL_INITIALIZED) { data_race(isec->initialized != LABEL_INITIALIZED)) {
if (!may_sleep) if (!may_sleep)
return -ECHILD; return -ECHILD;

View File

@ -16,45 +16,45 @@
#include <linux/types.h> #include <linux/types.h>
/** /**
* selinux_audit_rule_init - alloc/init an selinux audit rule structure. * selinux_audit_rule_init - alloc/init an selinux audit rule structure.
* @field: the field this rule refers to * @field: the field this rule refers to
* @op: the operator the rule uses * @op: the operator the rule uses
* @rulestr: the text "target" of the rule * @rulestr: the text "target" of the rule
* @rule: pointer to the new rule structure returned via this * @rule: pointer to the new rule structure returned via this
* @gfp: GFP flag used for kmalloc * @gfp: GFP flag used for kmalloc
* *
* Returns 0 if successful, -errno if not. On success, the rule structure * Returns 0 if successful, -errno if not. On success, the rule structure
* will be allocated internally. The caller must free this structure with * will be allocated internally. The caller must free this structure with
* selinux_audit_rule_free() after use. * selinux_audit_rule_free() after use.
*/ */
int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **rule, int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **rule,
gfp_t gfp); gfp_t gfp);
/** /**
* selinux_audit_rule_free - free an selinux audit rule structure. * selinux_audit_rule_free - free an selinux audit rule structure.
* @rule: pointer to the audit rule to be freed * @rule: pointer to the audit rule to be freed
* *
* This will free all memory associated with the given rule. * This will free all memory associated with the given rule.
* If @rule is NULL, no operation is performed. * If @rule is NULL, no operation is performed.
*/ */
void selinux_audit_rule_free(void *rule); void selinux_audit_rule_free(void *rule);
/** /**
* selinux_audit_rule_match - determine if a context ID matches a rule. * selinux_audit_rule_match - determine if a context ID matches a rule.
* @sid: the context ID to check * @sid: the context ID to check
* @field: the field this rule refers to * @field: the field this rule refers to
* @op: the operator the rule uses * @op: the operator the rule uses
* @rule: pointer to the audit rule to check against * @rule: pointer to the audit rule to check against
* *
* Returns 1 if the context id matches the rule, 0 if it does not, and * Returns 1 if the context id matches the rule, 0 if it does not, and
* -errno on failure. * -errno on failure.
*/ */
int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *rule); int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *rule);
/** /**
* selinux_audit_rule_known - check to see if rule contains selinux fields. * selinux_audit_rule_known - check to see if rule contains selinux fields.
* @rule: rule to be checked * @rule: rule to be checked
* Returns 1 if there are selinux fields specified in the rule, 0 otherwise. * Returns 1 if there are selinux fields specified in the rule, 0 otherwise.
*/ */
int selinux_audit_rule_known(struct audit_krule *rule); int selinux_audit_rule_known(struct audit_krule *rule);

View File

@ -62,7 +62,7 @@ static int selinux_netlbl_sidlookup_cached(struct sk_buff *skb,
* Description: * Description:
* Generate the NetLabel security attributes for a socket, making full use of * Generate the NetLabel security attributes for a socket, making full use of
* the socket's attribute cache. Returns a pointer to the security attributes * the socket's attribute cache. Returns a pointer to the security attributes
* on success, NULL on failure. * on success, or an ERR_PTR on failure.
* *
*/ */
static struct netlbl_lsm_secattr *selinux_netlbl_sock_genattr(struct sock *sk) static struct netlbl_lsm_secattr *selinux_netlbl_sock_genattr(struct sock *sk)
@ -76,11 +76,12 @@ static struct netlbl_lsm_secattr *selinux_netlbl_sock_genattr(struct sock *sk)
secattr = netlbl_secattr_alloc(GFP_ATOMIC); secattr = netlbl_secattr_alloc(GFP_ATOMIC);
if (secattr == NULL) if (secattr == NULL)
return NULL; return ERR_PTR(-ENOMEM);
rc = security_netlbl_sid_to_secattr(sksec->sid, secattr); rc = security_netlbl_sid_to_secattr(sksec->sid, secattr);
if (rc != 0) { if (rc != 0) {
netlbl_secattr_free(secattr); netlbl_secattr_free(secattr);
return NULL; return ERR_PTR(rc);
} }
sksec->nlbl_secattr = secattr; sksec->nlbl_secattr = secattr;
@ -358,7 +359,7 @@ void selinux_netlbl_inet_csk_clone(struct sock *sk, u16 family)
{ {
struct sk_security_struct *sksec = sk->sk_security; struct sk_security_struct *sksec = sk->sk_security;
if (family == PF_INET) if (family == PF_INET || family == PF_INET6)
sksec->nlbl_state = NLBL_LABELED; sksec->nlbl_state = NLBL_LABELED;
else else
sksec->nlbl_state = NLBL_UNSET; sksec->nlbl_state = NLBL_UNSET;
@ -400,8 +401,8 @@ int selinux_netlbl_socket_post_create(struct sock *sk, u16 family)
return 0; return 0;
secattr = selinux_netlbl_sock_genattr(sk); secattr = selinux_netlbl_sock_genattr(sk);
if (secattr == NULL) if (IS_ERR(secattr))
return -ENOMEM; return PTR_ERR(secattr);
/* On socket creation, replacement of IP options is safe even if /* On socket creation, replacement of IP options is safe even if
* the caller does not hold the socket lock. * the caller does not hold the socket lock.
*/ */
@ -561,10 +562,9 @@ static int selinux_netlbl_socket_connect_helper(struct sock *sk,
return rc; return rc;
} }
secattr = selinux_netlbl_sock_genattr(sk); secattr = selinux_netlbl_sock_genattr(sk);
if (secattr == NULL) { if (IS_ERR(secattr))
rc = -ENOMEM; return PTR_ERR(secattr);
return rc;
}
rc = netlbl_conn_setattr(sk, addr, secattr); rc = netlbl_conn_setattr(sk, addr, secattr);
if (rc == 0) if (rc == 0)
sksec->nlbl_state = NLBL_CONNLABELED; sksec->nlbl_state = NLBL_CONNLABELED;

View File

@ -604,9 +604,6 @@ int avtab_write(struct policydb *p, struct avtab *a, void *fp)
void __init avtab_cache_init(void) void __init avtab_cache_init(void)
{ {
avtab_node_cachep = kmem_cache_create( avtab_node_cachep = KMEM_CACHE(avtab_node, SLAB_PANIC);
"avtab_node", sizeof(struct avtab_node), 0, SLAB_PANIC, NULL); avtab_xperms_cachep = KMEM_CACHE(avtab_extended_perms, SLAB_PANIC);
avtab_xperms_cachep = kmem_cache_create(
"avtab_extended_perms", sizeof(struct avtab_extended_perms), 0,
SLAB_PANIC, NULL);
} }

View File

@ -572,7 +572,5 @@ u32 ebitmap_hash(const struct ebitmap *e, u32 hash)
void __init ebitmap_cache_init(void) void __init ebitmap_cache_init(void)
{ {
ebitmap_node_cachep = kmem_cache_create("ebitmap_node", ebitmap_node_cachep = KMEM_CACHE(ebitmap_node, SLAB_PANIC);
sizeof(struct ebitmap_node), 0,
SLAB_PANIC, NULL);
} }

View File

@ -194,7 +194,5 @@ error:
void __init hashtab_cache_init(void) void __init hashtab_cache_init(void)
{ {
hashtab_node_cachep = kmem_cache_create("hashtab_node", hashtab_node_cachep = KMEM_CACHE(hashtab_node, SLAB_PANIC);
sizeof(struct hashtab_node), 0,
SLAB_PANIC, NULL);
} }

View File

@ -1804,22 +1804,9 @@ retry:
newcontext.role = OBJECT_R_VAL; newcontext.role = OBJECT_R_VAL;
} }
/* Set the type to default values. */ /* Set the type.
if (cladatum && cladatum->default_type == DEFAULT_SOURCE) { * Look for a type transition/member/change rule.
newcontext.type = scontext->type; */
} else if (cladatum && cladatum->default_type == DEFAULT_TARGET) {
newcontext.type = tcontext->type;
} else {
if ((tclass == policydb->process_class) || sock) {
/* Use the type of process. */
newcontext.type = scontext->type;
} else {
/* Use the type of the related object. */
newcontext.type = tcontext->type;
}
}
/* Look for a type transition/member/change rule. */
avkey.source_type = scontext->type; avkey.source_type = scontext->type;
avkey.target_type = tcontext->type; avkey.target_type = tcontext->type;
avkey.target_class = tclass; avkey.target_class = tclass;
@ -1837,9 +1824,24 @@ retry:
} }
} }
/* If a permanent rule is found, use the type from
* the type transition/member/change rule. Otherwise,
* set the type to its default values.
*/
if (avnode) { if (avnode) {
/* Use the type from the type transition/member/change rule. */
newcontext.type = avnode->datum.u.data; newcontext.type = avnode->datum.u.data;
} else if (cladatum && cladatum->default_type == DEFAULT_SOURCE) {
newcontext.type = scontext->type;
} else if (cladatum && cladatum->default_type == DEFAULT_TARGET) {
newcontext.type = tcontext->type;
} else {
if ((tclass == policydb->process_class) || sock) {
/* Use the type of process. */
newcontext.type = scontext->type;
} else {
/* Use the type of the related object. */
newcontext.type = tcontext->type;
}
} }
/* if we have a objname this is a file trans check so check those rules */ /* if we have a objname this is a file trans check so check those rules */