xref: /openbmc/linux/security/selinux/netlabel.c (revision 1df83cbf)
11ccea77eSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
25778eabdSPaul Moore /*
35778eabdSPaul Moore  * SELinux NetLabel Support
45778eabdSPaul Moore  *
55778eabdSPaul Moore  * This file provides the necessary glue to tie NetLabel into the SELinux
65778eabdSPaul Moore  * subsystem.
75778eabdSPaul Moore  *
882c21bfaSPaul Moore  * Author: Paul Moore <paul@paul-moore.com>
95778eabdSPaul Moore  */
105778eabdSPaul Moore 
115778eabdSPaul Moore /*
12948bf85cSPaul Moore  * (c) Copyright Hewlett-Packard Development Company, L.P., 2007, 2008
135778eabdSPaul Moore  */
145778eabdSPaul Moore 
155778eabdSPaul Moore #include <linux/spinlock.h>
165778eabdSPaul Moore #include <linux/rcupdate.h>
175a0e3ad6STejun Heo #include <linux/gfp.h>
18014ab19aSPaul Moore #include <linux/ip.h>
19014ab19aSPaul Moore #include <linux/ipv6.h>
205778eabdSPaul Moore #include <net/sock.h>
215778eabdSPaul Moore #include <net/netlabel.h>
22014ab19aSPaul Moore #include <net/ip.h>
23014ab19aSPaul Moore #include <net/ipv6.h>
245778eabdSPaul Moore 
255778eabdSPaul Moore #include "objsec.h"
265778eabdSPaul Moore #include "security.h"
27d4ee4231SAdrian Bunk #include "netlabel.h"
285778eabdSPaul Moore 
295778eabdSPaul Moore /**
305dbe1eb0SPaul Moore  * selinux_netlbl_sidlookup_cached - Cache a SID lookup
315dbe1eb0SPaul Moore  * @skb: the packet
32e9fd7292SPaul Moore  * @family: the packet's address family
335dbe1eb0SPaul Moore  * @secattr: the NetLabel security attributes
345dbe1eb0SPaul Moore  * @sid: the SID
355dbe1eb0SPaul Moore  *
365dbe1eb0SPaul Moore  * Description:
375dbe1eb0SPaul Moore  * Query the SELinux security server to lookup the correct SID for the given
385dbe1eb0SPaul Moore  * security attributes.  If the query is successful, cache the result to speed
395dbe1eb0SPaul Moore  * up future lookups.  Returns zero on success, negative values on failure.
405dbe1eb0SPaul Moore  *
415dbe1eb0SPaul Moore  */
selinux_netlbl_sidlookup_cached(struct sk_buff * skb,u16 family,struct netlbl_lsm_secattr * secattr,u32 * sid)425dbe1eb0SPaul Moore static int selinux_netlbl_sidlookup_cached(struct sk_buff *skb,
434fee5242SHuw Davies 					   u16 family,
445dbe1eb0SPaul Moore 					   struct netlbl_lsm_secattr *secattr,
455dbe1eb0SPaul Moore 					   u32 *sid)
465dbe1eb0SPaul Moore {
475dbe1eb0SPaul Moore 	int rc;
485dbe1eb0SPaul Moore 
49e67b7985SStephen Smalley 	rc = security_netlbl_secattr_to_sid(secattr, sid);
505dbe1eb0SPaul Moore 	if (rc == 0 &&
515dbe1eb0SPaul Moore 	    (secattr->flags & NETLBL_SECATTR_CACHEABLE) &&
525dbe1eb0SPaul Moore 	    (secattr->flags & NETLBL_SECATTR_CACHE))
534fee5242SHuw Davies 		netlbl_cache_add(skb, family, secattr);
545dbe1eb0SPaul Moore 
555dbe1eb0SPaul Moore 	return rc;
565dbe1eb0SPaul Moore }
575dbe1eb0SPaul Moore 
585dbe1eb0SPaul Moore /**
596c5b3fc0SPaul Moore  * selinux_netlbl_sock_genattr - Generate the NetLabel socket secattr
606c5b3fc0SPaul Moore  * @sk: the socket
616c5b3fc0SPaul Moore  *
626c5b3fc0SPaul Moore  * Description:
636c5b3fc0SPaul Moore  * Generate the NetLabel security attributes for a socket, making full use of
646c5b3fc0SPaul Moore  * the socket's attribute cache.  Returns a pointer to the security attributes
656c5b3fc0SPaul Moore  * on success, NULL on failure.
666c5b3fc0SPaul Moore  *
676c5b3fc0SPaul Moore  */
selinux_netlbl_sock_genattr(struct sock * sk)686c5b3fc0SPaul Moore static struct netlbl_lsm_secattr *selinux_netlbl_sock_genattr(struct sock *sk)
696c5b3fc0SPaul Moore {
706c5b3fc0SPaul Moore 	int rc;
716c5b3fc0SPaul Moore 	struct sk_security_struct *sksec = sk->sk_security;
726c5b3fc0SPaul Moore 	struct netlbl_lsm_secattr *secattr;
736c5b3fc0SPaul Moore 
746c5b3fc0SPaul Moore 	if (sksec->nlbl_secattr != NULL)
756c5b3fc0SPaul Moore 		return sksec->nlbl_secattr;
766c5b3fc0SPaul Moore 
776c5b3fc0SPaul Moore 	secattr = netlbl_secattr_alloc(GFP_ATOMIC);
786c5b3fc0SPaul Moore 	if (secattr == NULL)
796c5b3fc0SPaul Moore 		return NULL;
80e67b7985SStephen Smalley 	rc = security_netlbl_sid_to_secattr(sksec->sid, secattr);
816c5b3fc0SPaul Moore 	if (rc != 0) {
826c5b3fc0SPaul Moore 		netlbl_secattr_free(secattr);
836c5b3fc0SPaul Moore 		return NULL;
846c5b3fc0SPaul Moore 	}
856c5b3fc0SPaul Moore 	sksec->nlbl_secattr = secattr;
866c5b3fc0SPaul Moore 
876c5b3fc0SPaul Moore 	return secattr;
886c5b3fc0SPaul Moore }
896c5b3fc0SPaul Moore 
906c5b3fc0SPaul Moore /**
91050d032bSPaul Moore  * selinux_netlbl_sock_getattr - Get the cached NetLabel secattr
92050d032bSPaul Moore  * @sk: the socket
93050d032bSPaul Moore  * @sid: the SID
94050d032bSPaul Moore  *
95050d032bSPaul Moore  * Query the socket's cached secattr and if the SID matches the cached value
96050d032bSPaul Moore  * return the cache, otherwise return NULL.
97050d032bSPaul Moore  *
98050d032bSPaul Moore  */
selinux_netlbl_sock_getattr(const struct sock * sk,u32 sid)99050d032bSPaul Moore static struct netlbl_lsm_secattr *selinux_netlbl_sock_getattr(
100050d032bSPaul Moore 							const struct sock *sk,
101050d032bSPaul Moore 							u32 sid)
102050d032bSPaul Moore {
103050d032bSPaul Moore 	struct sk_security_struct *sksec = sk->sk_security;
104050d032bSPaul Moore 	struct netlbl_lsm_secattr *secattr = sksec->nlbl_secattr;
105050d032bSPaul Moore 
106050d032bSPaul Moore 	if (secattr == NULL)
107050d032bSPaul Moore 		return NULL;
108050d032bSPaul Moore 
109050d032bSPaul Moore 	if ((secattr->flags & NETLBL_SECATTR_SECID) &&
110050d032bSPaul Moore 	    (secattr->attr.secid == sid))
111050d032bSPaul Moore 		return secattr;
112050d032bSPaul Moore 
113050d032bSPaul Moore 	return NULL;
114050d032bSPaul Moore }
115050d032bSPaul Moore 
116050d032bSPaul Moore /**
1175778eabdSPaul Moore  * selinux_netlbl_cache_invalidate - Invalidate the NetLabel cache
1185778eabdSPaul Moore  *
1195778eabdSPaul Moore  * Description:
1205778eabdSPaul Moore  * Invalidate the NetLabel security attribute mapping cache.
1215778eabdSPaul Moore  *
1225778eabdSPaul Moore  */
selinux_netlbl_cache_invalidate(void)1235778eabdSPaul Moore void selinux_netlbl_cache_invalidate(void)
1245778eabdSPaul Moore {
1255778eabdSPaul Moore 	netlbl_cache_invalidate();
1265778eabdSPaul Moore }
1275778eabdSPaul Moore 
1285778eabdSPaul Moore /**
129dfaebe98SPaul Moore  * selinux_netlbl_err - Handle a NetLabel packet error
130dfaebe98SPaul Moore  * @skb: the packet
131e9fd7292SPaul Moore  * @family: the packet's address family
132dfaebe98SPaul Moore  * @error: the error code
133dfaebe98SPaul Moore  * @gateway: true if host is acting as a gateway, false otherwise
134dfaebe98SPaul Moore  *
135dfaebe98SPaul Moore  * Description:
136dfaebe98SPaul Moore  * When a packet is dropped due to a call to avc_has_perm() pass the error
137dfaebe98SPaul Moore  * code to the NetLabel subsystem so any protocol specific processing can be
138dfaebe98SPaul Moore  * done.  This is safe to call even if you are unsure if NetLabel labeling is
139dfaebe98SPaul Moore  * present on the packet, NetLabel is smart enough to only act when it should.
140dfaebe98SPaul Moore  *
141dfaebe98SPaul Moore  */
selinux_netlbl_err(struct sk_buff * skb,u16 family,int error,int gateway)142a04e71f6SHuw Davies void selinux_netlbl_err(struct sk_buff *skb, u16 family, int error, int gateway)
143dfaebe98SPaul Moore {
144a04e71f6SHuw Davies 	netlbl_skbuff_err(skb, family, error, gateway);
145dfaebe98SPaul Moore }
146dfaebe98SPaul Moore 
147dfaebe98SPaul Moore /**
1486c5b3fc0SPaul Moore  * selinux_netlbl_sk_security_free - Free the NetLabel fields
149dd3e7836SEric Paris  * @sksec: the sk_security_struct
1506c5b3fc0SPaul Moore  *
1516c5b3fc0SPaul Moore  * Description:
1526c5b3fc0SPaul Moore  * Free all of the memory in the NetLabel fields of a sk_security_struct.
1536c5b3fc0SPaul Moore  *
1546c5b3fc0SPaul Moore  */
selinux_netlbl_sk_security_free(struct sk_security_struct * sksec)155dd3e7836SEric Paris void selinux_netlbl_sk_security_free(struct sk_security_struct *sksec)
1566c5b3fc0SPaul Moore {
15785c3222dSPaolo Abeni 	if (!sksec->nlbl_secattr)
15885c3222dSPaolo Abeni 		return;
15985c3222dSPaolo Abeni 
160dd3e7836SEric Paris 	netlbl_secattr_free(sksec->nlbl_secattr);
16185c3222dSPaolo Abeni 	sksec->nlbl_secattr = NULL;
16285c3222dSPaolo Abeni 	sksec->nlbl_state = NLBL_UNSET;
1636c5b3fc0SPaul Moore }
1646c5b3fc0SPaul Moore 
1656c5b3fc0SPaul Moore /**
1665778eabdSPaul Moore  * selinux_netlbl_sk_security_reset - Reset the NetLabel fields
167dd3e7836SEric Paris  * @sksec: the sk_security_struct
1685778eabdSPaul Moore  *
1695778eabdSPaul Moore  * Description:
1705778eabdSPaul Moore  * Called when the NetLabel state of a sk_security_struct needs to be reset.
17125985edcSLucas De Marchi  * The caller is responsible for all the NetLabel sk_security_struct locking.
1725778eabdSPaul Moore  *
1735778eabdSPaul Moore  */
selinux_netlbl_sk_security_reset(struct sk_security_struct * sksec)174dd3e7836SEric Paris void selinux_netlbl_sk_security_reset(struct sk_security_struct *sksec)
1755778eabdSPaul Moore {
176dd3e7836SEric Paris 	sksec->nlbl_state = NLBL_UNSET;
1775778eabdSPaul Moore }
1785778eabdSPaul Moore 
1795778eabdSPaul Moore /**
1805778eabdSPaul Moore  * selinux_netlbl_skbuff_getsid - Get the sid of a packet using NetLabel
1815778eabdSPaul Moore  * @skb: the packet
18275e22910SPaul Moore  * @family: protocol family
183220deb96SPaul Moore  * @type: NetLabel labeling protocol type
1845778eabdSPaul Moore  * @sid: the SID
1855778eabdSPaul Moore  *
1865778eabdSPaul Moore  * Description:
1875778eabdSPaul Moore  * Call the NetLabel mechanism to get the security attributes of the given
1885778eabdSPaul Moore  * packet and use those attributes to determine the correct context/SID to
1895778eabdSPaul Moore  * assign to the packet.  Returns zero on success, negative values on failure.
1905778eabdSPaul Moore  *
1915778eabdSPaul Moore  */
selinux_netlbl_skbuff_getsid(struct sk_buff * skb,u16 family,u32 * type,u32 * sid)19275e22910SPaul Moore int selinux_netlbl_skbuff_getsid(struct sk_buff *skb,
19375e22910SPaul Moore 				 u16 family,
194220deb96SPaul Moore 				 u32 *type,
19575e22910SPaul Moore 				 u32 *sid)
1965778eabdSPaul Moore {
1975778eabdSPaul Moore 	int rc;
1985778eabdSPaul Moore 	struct netlbl_lsm_secattr secattr;
1995778eabdSPaul Moore 
20023bcdc1aSPaul Moore 	if (!netlbl_enabled()) {
201*1df83cbfSAndrew Kanner 		*type = NETLBL_NLTYPE_NONE;
20223bcdc1aSPaul Moore 		*sid = SECSID_NULL;
20323bcdc1aSPaul Moore 		return 0;
20423bcdc1aSPaul Moore 	}
20523bcdc1aSPaul Moore 
2065778eabdSPaul Moore 	netlbl_secattr_init(&secattr);
20775e22910SPaul Moore 	rc = netlbl_skbuff_getattr(skb, family, &secattr);
2085dbe1eb0SPaul Moore 	if (rc == 0 && secattr.flags != NETLBL_SECATTR_NONE)
2094fee5242SHuw Davies 		rc = selinux_netlbl_sidlookup_cached(skb, family,
2104fee5242SHuw Davies 						     &secattr, sid);
2115dbe1eb0SPaul Moore 	else
2125778eabdSPaul Moore 		*sid = SECSID_NULL;
213220deb96SPaul Moore 	*type = secattr.type;
2145778eabdSPaul Moore 	netlbl_secattr_destroy(&secattr);
2155778eabdSPaul Moore 
2165778eabdSPaul Moore 	return rc;
2175778eabdSPaul Moore }
2185778eabdSPaul Moore 
2195778eabdSPaul Moore /**
220948bf85cSPaul Moore  * selinux_netlbl_skbuff_setsid - Set the NetLabel on a packet given a sid
221948bf85cSPaul Moore  * @skb: the packet
222948bf85cSPaul Moore  * @family: protocol family
223948bf85cSPaul Moore  * @sid: the SID
224948bf85cSPaul Moore  *
225948bf85cSPaul Moore  * Description
226948bf85cSPaul Moore  * Call the NetLabel mechanism to set the label of a packet using @sid.
227af901ca1SAndré Goddard Rosa  * Returns zero on success, negative values on failure.
228948bf85cSPaul Moore  *
229948bf85cSPaul Moore  */
selinux_netlbl_skbuff_setsid(struct sk_buff * skb,u16 family,u32 sid)230948bf85cSPaul Moore int selinux_netlbl_skbuff_setsid(struct sk_buff *skb,
231948bf85cSPaul Moore 				 u16 family,
232948bf85cSPaul Moore 				 u32 sid)
233948bf85cSPaul Moore {
234948bf85cSPaul Moore 	int rc;
2356c5b3fc0SPaul Moore 	struct netlbl_lsm_secattr secattr_storage;
2366c5b3fc0SPaul Moore 	struct netlbl_lsm_secattr *secattr = NULL;
237948bf85cSPaul Moore 	struct sock *sk;
238948bf85cSPaul Moore 
239948bf85cSPaul Moore 	/* if this is a locally generated packet check to see if it is already
240948bf85cSPaul Moore 	 * being labeled by it's parent socket, if it is just exit */
24154abc686SEric Dumazet 	sk = skb_to_full_sk(skb);
242948bf85cSPaul Moore 	if (sk != NULL) {
243948bf85cSPaul Moore 		struct sk_security_struct *sksec = sk->sk_security;
244d452930fSRichard Haines 
245948bf85cSPaul Moore 		if (sksec->nlbl_state != NLBL_REQSKB)
246948bf85cSPaul Moore 			return 0;
247050d032bSPaul Moore 		secattr = selinux_netlbl_sock_getattr(sk, sid);
248948bf85cSPaul Moore 	}
2496c5b3fc0SPaul Moore 	if (secattr == NULL) {
2506c5b3fc0SPaul Moore 		secattr = &secattr_storage;
2516c5b3fc0SPaul Moore 		netlbl_secattr_init(secattr);
252e67b7985SStephen Smalley 		rc = security_netlbl_sid_to_secattr(sid, secattr);
253948bf85cSPaul Moore 		if (rc != 0)
254948bf85cSPaul Moore 			goto skbuff_setsid_return;
2556c5b3fc0SPaul Moore 	}
2566c5b3fc0SPaul Moore 
2576c5b3fc0SPaul Moore 	rc = netlbl_skbuff_setattr(skb, family, secattr);
258948bf85cSPaul Moore 
259948bf85cSPaul Moore skbuff_setsid_return:
2606c5b3fc0SPaul Moore 	if (secattr == &secattr_storage)
2616c5b3fc0SPaul Moore 		netlbl_secattr_destroy(secattr);
262948bf85cSPaul Moore 	return rc;
263948bf85cSPaul Moore }
264948bf85cSPaul Moore 
265948bf85cSPaul Moore /**
266d452930fSRichard Haines  * selinux_netlbl_sctp_assoc_request - Label an incoming sctp association.
267c081d53fSXin Long  * @asoc: incoming association.
268d452930fSRichard Haines  * @skb: the packet.
269d452930fSRichard Haines  *
270d452930fSRichard Haines  * Description:
271c081d53fSXin Long  * A new incoming connection is represented by @asoc, ......
272d452930fSRichard Haines  * Returns zero on success, negative values on failure.
273d452930fSRichard Haines  *
274d452930fSRichard Haines  */
selinux_netlbl_sctp_assoc_request(struct sctp_association * asoc,struct sk_buff * skb)275c081d53fSXin Long int selinux_netlbl_sctp_assoc_request(struct sctp_association *asoc,
276d452930fSRichard Haines 				     struct sk_buff *skb)
277d452930fSRichard Haines {
278d452930fSRichard Haines 	int rc;
279d452930fSRichard Haines 	struct netlbl_lsm_secattr secattr;
280c081d53fSXin Long 	struct sk_security_struct *sksec = asoc->base.sk->sk_security;
281d452930fSRichard Haines 	struct sockaddr_in addr4;
282d452930fSRichard Haines 	struct sockaddr_in6 addr6;
283d452930fSRichard Haines 
284c081d53fSXin Long 	if (asoc->base.sk->sk_family != PF_INET &&
285c081d53fSXin Long 	    asoc->base.sk->sk_family != PF_INET6)
286d452930fSRichard Haines 		return 0;
287d452930fSRichard Haines 
288d452930fSRichard Haines 	netlbl_secattr_init(&secattr);
289e67b7985SStephen Smalley 	rc = security_netlbl_sid_to_secattr(asoc->secid, &secattr);
290d452930fSRichard Haines 	if (rc != 0)
291d452930fSRichard Haines 		goto assoc_request_return;
292d452930fSRichard Haines 
293d452930fSRichard Haines 	/* Move skb hdr address info to a struct sockaddr and then call
294d452930fSRichard Haines 	 * netlbl_conn_setattr().
295d452930fSRichard Haines 	 */
296d452930fSRichard Haines 	if (ip_hdr(skb)->version == 4) {
297d452930fSRichard Haines 		addr4.sin_family = AF_INET;
298d452930fSRichard Haines 		addr4.sin_addr.s_addr = ip_hdr(skb)->saddr;
299c081d53fSXin Long 		rc = netlbl_conn_setattr(asoc->base.sk, (void *)&addr4, &secattr);
30098bbbb76SArnd Bergmann 	} else if (IS_ENABLED(CONFIG_IPV6) && ip_hdr(skb)->version == 6) {
301d452930fSRichard Haines 		addr6.sin6_family = AF_INET6;
302d452930fSRichard Haines 		addr6.sin6_addr = ipv6_hdr(skb)->saddr;
303c081d53fSXin Long 		rc = netlbl_conn_setattr(asoc->base.sk, (void *)&addr6, &secattr);
30498bbbb76SArnd Bergmann 	} else {
30598bbbb76SArnd Bergmann 		rc = -EAFNOSUPPORT;
306d452930fSRichard Haines 	}
307d452930fSRichard Haines 
308d452930fSRichard Haines 	if (rc == 0)
309d452930fSRichard Haines 		sksec->nlbl_state = NLBL_LABELED;
310d452930fSRichard Haines 
311d452930fSRichard Haines assoc_request_return:
312d452930fSRichard Haines 	netlbl_secattr_destroy(&secattr);
313d452930fSRichard Haines 	return rc;
314d452930fSRichard Haines }
315d452930fSRichard Haines 
316d452930fSRichard Haines /**
317389fb800SPaul Moore  * selinux_netlbl_inet_conn_request - Label an incoming stream connection
318389fb800SPaul Moore  * @req: incoming connection request socket
319e9fd7292SPaul Moore  * @family: the request socket's address family
3205778eabdSPaul Moore  *
3215778eabdSPaul Moore  * Description:
322389fb800SPaul Moore  * A new incoming connection request is represented by @req, we need to label
323389fb800SPaul Moore  * the new request_sock here and the stack will ensure the on-the-wire label
324389fb800SPaul Moore  * will get preserved when a full sock is created once the connection handshake
325389fb800SPaul Moore  * is complete.  Returns zero on success, negative values on failure.
3265778eabdSPaul Moore  *
3275778eabdSPaul Moore  */
selinux_netlbl_inet_conn_request(struct request_sock * req,u16 family)328389fb800SPaul Moore int selinux_netlbl_inet_conn_request(struct request_sock *req, u16 family)
3295778eabdSPaul Moore {
330014ab19aSPaul Moore 	int rc;
331389fb800SPaul Moore 	struct netlbl_lsm_secattr secattr;
332389fb800SPaul Moore 
333e1adea92SHuw Davies 	if (family != PF_INET && family != PF_INET6)
334389fb800SPaul Moore 		return 0;
335389fb800SPaul Moore 
336389fb800SPaul Moore 	netlbl_secattr_init(&secattr);
337e67b7985SStephen Smalley 	rc = security_netlbl_sid_to_secattr(req->secid, &secattr);
338389fb800SPaul Moore 	if (rc != 0)
339389fb800SPaul Moore 		goto inet_conn_request_return;
340389fb800SPaul Moore 	rc = netlbl_req_setattr(req, &secattr);
341389fb800SPaul Moore inet_conn_request_return:
342389fb800SPaul Moore 	netlbl_secattr_destroy(&secattr);
343389fb800SPaul Moore 	return rc;
344389fb800SPaul Moore }
345389fb800SPaul Moore 
346389fb800SPaul Moore /**
347389fb800SPaul Moore  * selinux_netlbl_inet_csk_clone - Initialize the newly created sock
348389fb800SPaul Moore  * @sk: the new sock
349e9fd7292SPaul Moore  * @family: the sock's address family
350389fb800SPaul Moore  *
351389fb800SPaul Moore  * Description:
352389fb800SPaul Moore  * A new connection has been established using @sk, we've already labeled the
353389fb800SPaul Moore  * socket via the request_sock struct in selinux_netlbl_inet_conn_request() but
354389fb800SPaul Moore  * we need to set the NetLabel state here since we now have a sock structure.
355389fb800SPaul Moore  *
356389fb800SPaul Moore  */
selinux_netlbl_inet_csk_clone(struct sock * sk,u16 family)357389fb800SPaul Moore void selinux_netlbl_inet_csk_clone(struct sock *sk, u16 family)
358389fb800SPaul Moore {
359014ab19aSPaul Moore 	struct sk_security_struct *sksec = sk->sk_security;
360014ab19aSPaul Moore 
361389fb800SPaul Moore 	if (family == PF_INET)
362014ab19aSPaul Moore 		sksec->nlbl_state = NLBL_LABELED;
363389fb800SPaul Moore 	else
364014ab19aSPaul Moore 		sksec->nlbl_state = NLBL_UNSET;
3655778eabdSPaul Moore }
3665778eabdSPaul Moore 
3675778eabdSPaul Moore /**
368d452930fSRichard Haines  * selinux_netlbl_sctp_sk_clone - Copy state to the newly created sock
369d452930fSRichard Haines  * @sk: current sock
370d452930fSRichard Haines  * @newsk: the new sock
371d452930fSRichard Haines  *
372d452930fSRichard Haines  * Description:
373d452930fSRichard Haines  * Called whenever a new socket is created by accept(2) or sctp_peeloff(3).
374d452930fSRichard Haines  */
selinux_netlbl_sctp_sk_clone(struct sock * sk,struct sock * newsk)375d452930fSRichard Haines void selinux_netlbl_sctp_sk_clone(struct sock *sk, struct sock *newsk)
376d452930fSRichard Haines {
377d452930fSRichard Haines 	struct sk_security_struct *sksec = sk->sk_security;
378d452930fSRichard Haines 	struct sk_security_struct *newsksec = newsk->sk_security;
379d452930fSRichard Haines 
380d452930fSRichard Haines 	newsksec->nlbl_state = sksec->nlbl_state;
381d452930fSRichard Haines }
382d452930fSRichard Haines 
383d452930fSRichard Haines /**
3845778eabdSPaul Moore  * selinux_netlbl_socket_post_create - Label a socket using NetLabel
385e9fd7292SPaul Moore  * @sk: the sock to label
386389fb800SPaul Moore  * @family: protocol family
3875778eabdSPaul Moore  *
3885778eabdSPaul Moore  * Description:
3895778eabdSPaul Moore  * Attempt to label a socket using the NetLabel mechanism using the given
3905778eabdSPaul Moore  * SID.  Returns zero values on success, negative values on failure.
3915778eabdSPaul Moore  *
3925778eabdSPaul Moore  */
selinux_netlbl_socket_post_create(struct sock * sk,u16 family)393389fb800SPaul Moore int selinux_netlbl_socket_post_create(struct sock *sk, u16 family)
3945778eabdSPaul Moore {
3955778eabdSPaul Moore 	int rc;
396389fb800SPaul Moore 	struct sk_security_struct *sksec = sk->sk_security;
397389fb800SPaul Moore 	struct netlbl_lsm_secattr *secattr;
3985778eabdSPaul Moore 
399ceba1832SHuw Davies 	if (family != PF_INET && family != PF_INET6)
4005778eabdSPaul Moore 		return 0;
401f74af6e8SPaul Moore 
402389fb800SPaul Moore 	secattr = selinux_netlbl_sock_genattr(sk);
403389fb800SPaul Moore 	if (secattr == NULL)
404389fb800SPaul Moore 		return -ENOMEM;
405389fb800SPaul Moore 	rc = netlbl_sock_setattr(sk, family, secattr);
406389fb800SPaul Moore 	switch (rc) {
407389fb800SPaul Moore 	case 0:
408389fb800SPaul Moore 		sksec->nlbl_state = NLBL_LABELED;
409389fb800SPaul Moore 		break;
410389fb800SPaul Moore 	case -EDESTADDRREQ:
411389fb800SPaul Moore 		sksec->nlbl_state = NLBL_REQSKB;
412f74af6e8SPaul Moore 		rc = 0;
413389fb800SPaul Moore 		break;
414389fb800SPaul Moore 	}
4155778eabdSPaul Moore 
4165778eabdSPaul Moore 	return rc;
4175778eabdSPaul Moore }
4185778eabdSPaul Moore 
4195778eabdSPaul Moore /**
4205778eabdSPaul Moore  * selinux_netlbl_sock_rcv_skb - Do an inbound access check using NetLabel
4215778eabdSPaul Moore  * @sksec: the sock's sk_security_struct
4225778eabdSPaul Moore  * @skb: the packet
42375e22910SPaul Moore  * @family: protocol family
4245778eabdSPaul Moore  * @ad: the audit data
4255778eabdSPaul Moore  *
4265778eabdSPaul Moore  * Description:
4275778eabdSPaul Moore  * Fetch the NetLabel security attributes from @skb and perform an access check
4285778eabdSPaul Moore  * against the receiving socket.  Returns zero on success, negative values on
4295778eabdSPaul Moore  * error.
4305778eabdSPaul Moore  *
4315778eabdSPaul Moore  */
selinux_netlbl_sock_rcv_skb(struct sk_security_struct * sksec,struct sk_buff * skb,u16 family,struct common_audit_data * ad)4325778eabdSPaul Moore int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
4335778eabdSPaul Moore 				struct sk_buff *skb,
43475e22910SPaul Moore 				u16 family,
4352bf49690SThomas Liu 				struct common_audit_data *ad)
4365778eabdSPaul Moore {
4375778eabdSPaul Moore 	int rc;
438f36158c4SPaul Moore 	u32 nlbl_sid;
439f36158c4SPaul Moore 	u32 perm;
440f36158c4SPaul Moore 	struct netlbl_lsm_secattr secattr;
4415778eabdSPaul Moore 
44223bcdc1aSPaul Moore 	if (!netlbl_enabled())
44323bcdc1aSPaul Moore 		return 0;
44423bcdc1aSPaul Moore 
445f36158c4SPaul Moore 	netlbl_secattr_init(&secattr);
44675e22910SPaul Moore 	rc = netlbl_skbuff_getattr(skb, family, &secattr);
4475dbe1eb0SPaul Moore 	if (rc == 0 && secattr.flags != NETLBL_SECATTR_NONE)
4484fee5242SHuw Davies 		rc = selinux_netlbl_sidlookup_cached(skb, family,
4494fee5242SHuw Davies 						     &secattr, &nlbl_sid);
4505dbe1eb0SPaul Moore 	else
451f36158c4SPaul Moore 		nlbl_sid = SECINITSID_UNLABELED;
452f36158c4SPaul Moore 	netlbl_secattr_destroy(&secattr);
4535778eabdSPaul Moore 	if (rc != 0)
4545778eabdSPaul Moore 		return rc;
4558d9107e8SLinus Torvalds 
4565778eabdSPaul Moore 	switch (sksec->sclass) {
4575778eabdSPaul Moore 	case SECCLASS_UDP_SOCKET:
458f36158c4SPaul Moore 		perm = UDP_SOCKET__RECVFROM;
4595778eabdSPaul Moore 		break;
4605778eabdSPaul Moore 	case SECCLASS_TCP_SOCKET:
461f36158c4SPaul Moore 		perm = TCP_SOCKET__RECVFROM;
4625778eabdSPaul Moore 		break;
4635778eabdSPaul Moore 	default:
464f36158c4SPaul Moore 		perm = RAWIP_SOCKET__RECVFROM;
4655778eabdSPaul Moore 	}
4665778eabdSPaul Moore 
467e67b7985SStephen Smalley 	rc = avc_has_perm(sksec->sid, nlbl_sid, sksec->sclass, perm, ad);
4685778eabdSPaul Moore 	if (rc == 0)
4695778eabdSPaul Moore 		return 0;
4705778eabdSPaul Moore 
471f36158c4SPaul Moore 	if (nlbl_sid != SECINITSID_UNLABELED)
472a04e71f6SHuw Davies 		netlbl_skbuff_err(skb, family, rc, 0);
4735778eabdSPaul Moore 	return rc;
4745778eabdSPaul Moore }
4755778eabdSPaul Moore 
4765778eabdSPaul Moore /**
4771f440c99SHuw Davies  * selinux_netlbl_option - Is this a NetLabel option
4781f440c99SHuw Davies  * @level: the socket level or protocol
4791f440c99SHuw Davies  * @optname: the socket option name
4801f440c99SHuw Davies  *
4811f440c99SHuw Davies  * Description:
4821f440c99SHuw Davies  * Returns true if @level and @optname refer to a NetLabel option.
4831f440c99SHuw Davies  * Helper for selinux_netlbl_socket_setsockopt().
4841f440c99SHuw Davies  */
selinux_netlbl_option(int level,int optname)4851f440c99SHuw Davies static inline int selinux_netlbl_option(int level, int optname)
4861f440c99SHuw Davies {
4871f440c99SHuw Davies 	return (level == IPPROTO_IP && optname == IP_OPTIONS) ||
4881f440c99SHuw Davies 		(level == IPPROTO_IPV6 && optname == IPV6_HOPOPTS);
4891f440c99SHuw Davies }
4901f440c99SHuw Davies 
4911f440c99SHuw Davies /**
4925778eabdSPaul Moore  * selinux_netlbl_socket_setsockopt - Do not allow users to remove a NetLabel
4935778eabdSPaul Moore  * @sock: the socket
4945778eabdSPaul Moore  * @level: the socket level or protocol
4955778eabdSPaul Moore  * @optname: the socket option name
4965778eabdSPaul Moore  *
4975778eabdSPaul Moore  * Description:
4985778eabdSPaul Moore  * Check the setsockopt() call and if the user is trying to replace the IP
4995778eabdSPaul Moore  * options on a socket and a NetLabel is in place for the socket deny the
5005778eabdSPaul Moore  * access; otherwise allow the access.  Returns zero when the access is
5015778eabdSPaul Moore  * allowed, -EACCES when denied, and other negative values on error.
5025778eabdSPaul Moore  *
5035778eabdSPaul Moore  */
selinux_netlbl_socket_setsockopt(struct socket * sock,int level,int optname)5045778eabdSPaul Moore int selinux_netlbl_socket_setsockopt(struct socket *sock,
5055778eabdSPaul Moore 				     int level,
5065778eabdSPaul Moore 				     int optname)
5075778eabdSPaul Moore {
5085778eabdSPaul Moore 	int rc = 0;
509ba6ff9f2SPaul Moore 	struct sock *sk = sock->sk;
510ba6ff9f2SPaul Moore 	struct sk_security_struct *sksec = sk->sk_security;
5115778eabdSPaul Moore 	struct netlbl_lsm_secattr secattr;
5125778eabdSPaul Moore 
5131f440c99SHuw Davies 	if (selinux_netlbl_option(level, optname) &&
514014ab19aSPaul Moore 	    (sksec->nlbl_state == NLBL_LABELED ||
515014ab19aSPaul Moore 	     sksec->nlbl_state == NLBL_CONNLABELED)) {
5165778eabdSPaul Moore 		netlbl_secattr_init(&secattr);
517ba6ff9f2SPaul Moore 		lock_sock(sk);
518050d032bSPaul Moore 		/* call the netlabel function directly as we want to see the
519050d032bSPaul Moore 		 * on-the-wire label that is assigned via the socket's options
520050d032bSPaul Moore 		 * and not the cached netlabel/lsm attributes */
521ba6ff9f2SPaul Moore 		rc = netlbl_sock_getattr(sk, &secattr);
522ba6ff9f2SPaul Moore 		release_sock(sk);
52309c50b4aSPaul Moore 		if (rc == 0)
5245778eabdSPaul Moore 			rc = -EACCES;
52509c50b4aSPaul Moore 		else if (rc == -ENOMSG)
52609c50b4aSPaul Moore 			rc = 0;
5275778eabdSPaul Moore 		netlbl_secattr_destroy(&secattr);
5285778eabdSPaul Moore 	}
5295778eabdSPaul Moore 
5305778eabdSPaul Moore 	return rc;
5315778eabdSPaul Moore }
532014ab19aSPaul Moore 
533014ab19aSPaul Moore /**
534d452930fSRichard Haines  * selinux_netlbl_socket_connect_helper - Help label a client-side socket on
535d452930fSRichard Haines  * connect
536d452930fSRichard Haines  * @sk: the socket to label
537d452930fSRichard Haines  * @addr: the destination address
538d452930fSRichard Haines  *
539d452930fSRichard Haines  * Description:
540d452930fSRichard Haines  * Attempt to label a connected socket with NetLabel using the given address.
541d452930fSRichard Haines  * Returns zero values on success, negative values on failure.
542d452930fSRichard Haines  *
543d452930fSRichard Haines  */
selinux_netlbl_socket_connect_helper(struct sock * sk,struct sockaddr * addr)544d452930fSRichard Haines static int selinux_netlbl_socket_connect_helper(struct sock *sk,
545d452930fSRichard Haines 						struct sockaddr *addr)
546d452930fSRichard Haines {
547d452930fSRichard Haines 	int rc;
548d452930fSRichard Haines 	struct sk_security_struct *sksec = sk->sk_security;
549d452930fSRichard Haines 	struct netlbl_lsm_secattr *secattr;
550d452930fSRichard Haines 
551d452930fSRichard Haines 	/* connected sockets are allowed to disconnect when the address family
552d452930fSRichard Haines 	 * is set to AF_UNSPEC, if that is what is happening we want to reset
553d452930fSRichard Haines 	 * the socket */
554d452930fSRichard Haines 	if (addr->sa_family == AF_UNSPEC) {
555d452930fSRichard Haines 		netlbl_sock_delattr(sk);
556d452930fSRichard Haines 		sksec->nlbl_state = NLBL_REQSKB;
557d452930fSRichard Haines 		rc = 0;
558d452930fSRichard Haines 		return rc;
559d452930fSRichard Haines 	}
560d452930fSRichard Haines 	secattr = selinux_netlbl_sock_genattr(sk);
561d452930fSRichard Haines 	if (secattr == NULL) {
562d452930fSRichard Haines 		rc = -ENOMEM;
563d452930fSRichard Haines 		return rc;
564d452930fSRichard Haines 	}
565d452930fSRichard Haines 	rc = netlbl_conn_setattr(sk, addr, secattr);
566d452930fSRichard Haines 	if (rc == 0)
567d452930fSRichard Haines 		sksec->nlbl_state = NLBL_CONNLABELED;
568d452930fSRichard Haines 
569d452930fSRichard Haines 	return rc;
570d452930fSRichard Haines }
571d452930fSRichard Haines 
572d452930fSRichard Haines /**
573d452930fSRichard Haines  * selinux_netlbl_socket_connect_locked - Label a client-side socket on
574d452930fSRichard Haines  * connect
575d452930fSRichard Haines  * @sk: the socket to label
576d452930fSRichard Haines  * @addr: the destination address
577d452930fSRichard Haines  *
578d452930fSRichard Haines  * Description:
579d452930fSRichard Haines  * Attempt to label a connected socket that already has the socket locked
580d452930fSRichard Haines  * with NetLabel using the given address.
581d452930fSRichard Haines  * Returns zero values on success, negative values on failure.
582d452930fSRichard Haines  *
583d452930fSRichard Haines  */
selinux_netlbl_socket_connect_locked(struct sock * sk,struct sockaddr * addr)584d452930fSRichard Haines int selinux_netlbl_socket_connect_locked(struct sock *sk,
585d452930fSRichard Haines 					 struct sockaddr *addr)
586d452930fSRichard Haines {
587d452930fSRichard Haines 	struct sk_security_struct *sksec = sk->sk_security;
588d452930fSRichard Haines 
589d452930fSRichard Haines 	if (sksec->nlbl_state != NLBL_REQSKB &&
590d452930fSRichard Haines 	    sksec->nlbl_state != NLBL_CONNLABELED)
591d452930fSRichard Haines 		return 0;
592d452930fSRichard Haines 
593d452930fSRichard Haines 	return selinux_netlbl_socket_connect_helper(sk, addr);
594d452930fSRichard Haines }
595d452930fSRichard Haines 
596d452930fSRichard Haines /**
597014ab19aSPaul Moore  * selinux_netlbl_socket_connect - Label a client-side socket on connect
598014ab19aSPaul Moore  * @sk: the socket to label
599014ab19aSPaul Moore  * @addr: the destination address
600014ab19aSPaul Moore  *
601014ab19aSPaul Moore  * Description:
602014ab19aSPaul Moore  * Attempt to label a connected socket with NetLabel using the given address.
603014ab19aSPaul Moore  * Returns zero values on success, negative values on failure.
604014ab19aSPaul Moore  *
605014ab19aSPaul Moore  */
selinux_netlbl_socket_connect(struct sock * sk,struct sockaddr * addr)606014ab19aSPaul Moore int selinux_netlbl_socket_connect(struct sock *sk, struct sockaddr *addr)
607014ab19aSPaul Moore {
608014ab19aSPaul Moore 	int rc;
609014ab19aSPaul Moore 
61042d64e1aSPaul Moore 	lock_sock(sk);
611d452930fSRichard Haines 	rc = selinux_netlbl_socket_connect_locked(sk, addr);
61242d64e1aSPaul Moore 	release_sock(sk);
613d452930fSRichard Haines 
614014ab19aSPaul Moore 	return rc;
615014ab19aSPaul Moore }
616