xref: /linux/security/selinux/netlabel.c (revision a430d95c5efa2b545d26a094eb5f624e36732af0)
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>
202aff9d20SCasey Schaufler #include <linux/lsm_hooks.h>
215778eabdSPaul Moore #include <net/sock.h>
225778eabdSPaul Moore #include <net/netlabel.h>
23014ab19aSPaul Moore #include <net/ip.h>
24014ab19aSPaul Moore #include <net/ipv6.h>
255778eabdSPaul Moore 
265778eabdSPaul Moore #include "objsec.h"
275778eabdSPaul Moore #include "security.h"
28d4ee4231SAdrian Bunk #include "netlabel.h"
295778eabdSPaul Moore 
305778eabdSPaul Moore /**
315dbe1eb0SPaul Moore  * selinux_netlbl_sidlookup_cached - Cache a SID lookup
325dbe1eb0SPaul Moore  * @skb: the packet
33e9fd7292SPaul Moore  * @family: the packet's address family
345dbe1eb0SPaul Moore  * @secattr: the NetLabel security attributes
355dbe1eb0SPaul Moore  * @sid: the SID
365dbe1eb0SPaul Moore  *
375dbe1eb0SPaul Moore  * Description:
385dbe1eb0SPaul Moore  * Query the SELinux security server to lookup the correct SID for the given
395dbe1eb0SPaul Moore  * security attributes.  If the query is successful, cache the result to speed
405dbe1eb0SPaul Moore  * up future lookups.  Returns zero on success, negative values on failure.
415dbe1eb0SPaul Moore  *
425dbe1eb0SPaul Moore  */
selinux_netlbl_sidlookup_cached(struct sk_buff * skb,u16 family,struct netlbl_lsm_secattr * secattr,u32 * sid)435dbe1eb0SPaul Moore static int selinux_netlbl_sidlookup_cached(struct sk_buff *skb,
444fee5242SHuw Davies 					   u16 family,
455dbe1eb0SPaul Moore 					   struct netlbl_lsm_secattr *secattr,
465dbe1eb0SPaul Moore 					   u32 *sid)
475dbe1eb0SPaul Moore {
485dbe1eb0SPaul Moore 	int rc;
495dbe1eb0SPaul Moore 
50e67b7985SStephen Smalley 	rc = security_netlbl_secattr_to_sid(secattr, sid);
515dbe1eb0SPaul Moore 	if (rc == 0 &&
525dbe1eb0SPaul Moore 	    (secattr->flags & NETLBL_SECATTR_CACHEABLE) &&
535dbe1eb0SPaul Moore 	    (secattr->flags & NETLBL_SECATTR_CACHE))
544fee5242SHuw Davies 		netlbl_cache_add(skb, family, secattr);
555dbe1eb0SPaul Moore 
565dbe1eb0SPaul Moore 	return rc;
575dbe1eb0SPaul Moore }
585dbe1eb0SPaul Moore 
595dbe1eb0SPaul Moore /**
606c5b3fc0SPaul Moore  * selinux_netlbl_sock_genattr - Generate the NetLabel socket secattr
616c5b3fc0SPaul Moore  * @sk: the socket
626c5b3fc0SPaul Moore  *
636c5b3fc0SPaul Moore  * Description:
646c5b3fc0SPaul Moore  * Generate the NetLabel security attributes for a socket, making full use of
656c5b3fc0SPaul Moore  * the socket's attribute cache.  Returns a pointer to the security attributes
66fc328c86SGaosheng Cui  * on success, or an ERR_PTR on failure.
676c5b3fc0SPaul Moore  *
686c5b3fc0SPaul Moore  */
selinux_netlbl_sock_genattr(struct sock * sk)696c5b3fc0SPaul Moore static struct netlbl_lsm_secattr *selinux_netlbl_sock_genattr(struct sock *sk)
706c5b3fc0SPaul Moore {
716c5b3fc0SPaul Moore 	int rc;
722aff9d20SCasey Schaufler 	struct sk_security_struct *sksec = selinux_sock(sk);
736c5b3fc0SPaul Moore 	struct netlbl_lsm_secattr *secattr;
746c5b3fc0SPaul Moore 
756c5b3fc0SPaul Moore 	if (sksec->nlbl_secattr != NULL)
766c5b3fc0SPaul Moore 		return sksec->nlbl_secattr;
776c5b3fc0SPaul Moore 
786c5b3fc0SPaul Moore 	secattr = netlbl_secattr_alloc(GFP_ATOMIC);
796c5b3fc0SPaul Moore 	if (secattr == NULL)
80fc328c86SGaosheng Cui 		return ERR_PTR(-ENOMEM);
81fc328c86SGaosheng Cui 
82e67b7985SStephen Smalley 	rc = security_netlbl_sid_to_secattr(sksec->sid, secattr);
836c5b3fc0SPaul Moore 	if (rc != 0) {
846c5b3fc0SPaul Moore 		netlbl_secattr_free(secattr);
85fc328c86SGaosheng Cui 		return ERR_PTR(rc);
866c5b3fc0SPaul Moore 	}
876c5b3fc0SPaul Moore 	sksec->nlbl_secattr = secattr;
886c5b3fc0SPaul Moore 
896c5b3fc0SPaul Moore 	return secattr;
906c5b3fc0SPaul Moore }
916c5b3fc0SPaul Moore 
926c5b3fc0SPaul Moore /**
93050d032bSPaul Moore  * selinux_netlbl_sock_getattr - Get the cached NetLabel secattr
94050d032bSPaul Moore  * @sk: the socket
95050d032bSPaul Moore  * @sid: the SID
96050d032bSPaul Moore  *
97050d032bSPaul Moore  * Query the socket's cached secattr and if the SID matches the cached value
98050d032bSPaul Moore  * return the cache, otherwise return NULL.
99050d032bSPaul Moore  *
100050d032bSPaul Moore  */
selinux_netlbl_sock_getattr(const struct sock * sk,u32 sid)101050d032bSPaul Moore static struct netlbl_lsm_secattr *selinux_netlbl_sock_getattr(
102050d032bSPaul Moore 							const struct sock *sk,
103050d032bSPaul Moore 							u32 sid)
104050d032bSPaul Moore {
1052aff9d20SCasey Schaufler 	struct sk_security_struct *sksec = selinux_sock(sk);
106050d032bSPaul Moore 	struct netlbl_lsm_secattr *secattr = sksec->nlbl_secattr;
107050d032bSPaul Moore 
108050d032bSPaul Moore 	if (secattr == NULL)
109050d032bSPaul Moore 		return NULL;
110050d032bSPaul Moore 
111050d032bSPaul Moore 	if ((secattr->flags & NETLBL_SECATTR_SECID) &&
112050d032bSPaul Moore 	    (secattr->attr.secid == sid))
113050d032bSPaul Moore 		return secattr;
114050d032bSPaul Moore 
115050d032bSPaul Moore 	return NULL;
116050d032bSPaul Moore }
117050d032bSPaul Moore 
118050d032bSPaul Moore /**
1195778eabdSPaul Moore  * selinux_netlbl_cache_invalidate - Invalidate the NetLabel cache
1205778eabdSPaul Moore  *
1215778eabdSPaul Moore  * Description:
1225778eabdSPaul Moore  * Invalidate the NetLabel security attribute mapping cache.
1235778eabdSPaul Moore  *
1245778eabdSPaul Moore  */
selinux_netlbl_cache_invalidate(void)1255778eabdSPaul Moore void selinux_netlbl_cache_invalidate(void)
1265778eabdSPaul Moore {
1275778eabdSPaul Moore 	netlbl_cache_invalidate();
1285778eabdSPaul Moore }
1295778eabdSPaul Moore 
1305778eabdSPaul Moore /**
131dfaebe98SPaul Moore  * selinux_netlbl_err - Handle a NetLabel packet error
132dfaebe98SPaul Moore  * @skb: the packet
133e9fd7292SPaul Moore  * @family: the packet's address family
134dfaebe98SPaul Moore  * @error: the error code
135dfaebe98SPaul Moore  * @gateway: true if host is acting as a gateway, false otherwise
136dfaebe98SPaul Moore  *
137dfaebe98SPaul Moore  * Description:
138dfaebe98SPaul Moore  * When a packet is dropped due to a call to avc_has_perm() pass the error
139dfaebe98SPaul Moore  * code to the NetLabel subsystem so any protocol specific processing can be
140dfaebe98SPaul Moore  * done.  This is safe to call even if you are unsure if NetLabel labeling is
141dfaebe98SPaul Moore  * present on the packet, NetLabel is smart enough to only act when it should.
142dfaebe98SPaul Moore  *
143dfaebe98SPaul Moore  */
selinux_netlbl_err(struct sk_buff * skb,u16 family,int error,int gateway)144a04e71f6SHuw Davies void selinux_netlbl_err(struct sk_buff *skb, u16 family, int error, int gateway)
145dfaebe98SPaul Moore {
146a04e71f6SHuw Davies 	netlbl_skbuff_err(skb, family, error, gateway);
147dfaebe98SPaul Moore }
148dfaebe98SPaul Moore 
149dfaebe98SPaul Moore /**
1506c5b3fc0SPaul Moore  * selinux_netlbl_sk_security_free - Free the NetLabel fields
151dd3e7836SEric Paris  * @sksec: the sk_security_struct
1526c5b3fc0SPaul Moore  *
1536c5b3fc0SPaul Moore  * Description:
1546c5b3fc0SPaul Moore  * Free all of the memory in the NetLabel fields of a sk_security_struct.
1556c5b3fc0SPaul Moore  *
1566c5b3fc0SPaul Moore  */
selinux_netlbl_sk_security_free(struct sk_security_struct * sksec)157dd3e7836SEric Paris void selinux_netlbl_sk_security_free(struct sk_security_struct *sksec)
1586c5b3fc0SPaul Moore {
15985c3222dSPaolo Abeni 	if (!sksec->nlbl_secattr)
16085c3222dSPaolo Abeni 		return;
16185c3222dSPaolo Abeni 
162dd3e7836SEric Paris 	netlbl_secattr_free(sksec->nlbl_secattr);
16385c3222dSPaolo Abeni 	sksec->nlbl_secattr = NULL;
16485c3222dSPaolo Abeni 	sksec->nlbl_state = NLBL_UNSET;
1656c5b3fc0SPaul Moore }
1666c5b3fc0SPaul Moore 
1676c5b3fc0SPaul Moore /**
1685778eabdSPaul Moore  * selinux_netlbl_sk_security_reset - Reset the NetLabel fields
169dd3e7836SEric Paris  * @sksec: the sk_security_struct
1705778eabdSPaul Moore  *
1715778eabdSPaul Moore  * Description:
1725778eabdSPaul Moore  * Called when the NetLabel state of a sk_security_struct needs to be reset.
17325985edcSLucas De Marchi  * The caller is responsible for all the NetLabel sk_security_struct locking.
1745778eabdSPaul Moore  *
1755778eabdSPaul Moore  */
selinux_netlbl_sk_security_reset(struct sk_security_struct * sksec)176dd3e7836SEric Paris void selinux_netlbl_sk_security_reset(struct sk_security_struct *sksec)
1775778eabdSPaul Moore {
178dd3e7836SEric Paris 	sksec->nlbl_state = NLBL_UNSET;
1795778eabdSPaul Moore }
1805778eabdSPaul Moore 
1815778eabdSPaul Moore /**
1825778eabdSPaul Moore  * selinux_netlbl_skbuff_getsid - Get the sid of a packet using NetLabel
1835778eabdSPaul Moore  * @skb: the packet
18475e22910SPaul Moore  * @family: protocol family
185220deb96SPaul Moore  * @type: NetLabel labeling protocol type
1865778eabdSPaul Moore  * @sid: the SID
1875778eabdSPaul Moore  *
1885778eabdSPaul Moore  * Description:
1895778eabdSPaul Moore  * Call the NetLabel mechanism to get the security attributes of the given
1905778eabdSPaul Moore  * packet and use those attributes to determine the correct context/SID to
1915778eabdSPaul Moore  * assign to the packet.  Returns zero on success, negative values on failure.
1925778eabdSPaul Moore  *
1935778eabdSPaul Moore  */
selinux_netlbl_skbuff_getsid(struct sk_buff * skb,u16 family,u32 * type,u32 * sid)19475e22910SPaul Moore int selinux_netlbl_skbuff_getsid(struct sk_buff *skb,
19575e22910SPaul Moore 				 u16 family,
196220deb96SPaul Moore 				 u32 *type,
19775e22910SPaul Moore 				 u32 *sid)
1985778eabdSPaul Moore {
1995778eabdSPaul Moore 	int rc;
2005778eabdSPaul Moore 	struct netlbl_lsm_secattr secattr;
2015778eabdSPaul Moore 
20223bcdc1aSPaul Moore 	if (!netlbl_enabled()) {
2031df83cbfSAndrew Kanner 		*type = NETLBL_NLTYPE_NONE;
20423bcdc1aSPaul Moore 		*sid = SECSID_NULL;
20523bcdc1aSPaul Moore 		return 0;
20623bcdc1aSPaul Moore 	}
20723bcdc1aSPaul Moore 
2085778eabdSPaul Moore 	netlbl_secattr_init(&secattr);
20975e22910SPaul Moore 	rc = netlbl_skbuff_getattr(skb, family, &secattr);
2105dbe1eb0SPaul Moore 	if (rc == 0 && secattr.flags != NETLBL_SECATTR_NONE)
2114fee5242SHuw Davies 		rc = selinux_netlbl_sidlookup_cached(skb, family,
2124fee5242SHuw Davies 						     &secattr, sid);
2135dbe1eb0SPaul Moore 	else
2145778eabdSPaul Moore 		*sid = SECSID_NULL;
215220deb96SPaul Moore 	*type = secattr.type;
2165778eabdSPaul Moore 	netlbl_secattr_destroy(&secattr);
2175778eabdSPaul Moore 
2185778eabdSPaul Moore 	return rc;
2195778eabdSPaul Moore }
2205778eabdSPaul Moore 
2215778eabdSPaul Moore /**
222948bf85cSPaul Moore  * selinux_netlbl_skbuff_setsid - Set the NetLabel on a packet given a sid
223948bf85cSPaul Moore  * @skb: the packet
224948bf85cSPaul Moore  * @family: protocol family
225948bf85cSPaul Moore  * @sid: the SID
226948bf85cSPaul Moore  *
227948bf85cSPaul Moore  * Description
228948bf85cSPaul Moore  * Call the NetLabel mechanism to set the label of a packet using @sid.
229af901ca1SAndré Goddard Rosa  * Returns zero on success, negative values on failure.
230948bf85cSPaul Moore  *
231948bf85cSPaul Moore  */
selinux_netlbl_skbuff_setsid(struct sk_buff * skb,u16 family,u32 sid)232948bf85cSPaul Moore int selinux_netlbl_skbuff_setsid(struct sk_buff *skb,
233948bf85cSPaul Moore 				 u16 family,
234948bf85cSPaul Moore 				 u32 sid)
235948bf85cSPaul Moore {
236948bf85cSPaul Moore 	int rc;
2376c5b3fc0SPaul Moore 	struct netlbl_lsm_secattr secattr_storage;
2386c5b3fc0SPaul Moore 	struct netlbl_lsm_secattr *secattr = NULL;
239948bf85cSPaul Moore 	struct sock *sk;
240948bf85cSPaul Moore 
241948bf85cSPaul Moore 	/* if this is a locally generated packet check to see if it is already
242948bf85cSPaul Moore 	 * being labeled by it's parent socket, if it is just exit */
24354abc686SEric Dumazet 	sk = skb_to_full_sk(skb);
244948bf85cSPaul Moore 	if (sk != NULL) {
2452aff9d20SCasey Schaufler 		struct sk_security_struct *sksec = selinux_sock(sk);
246d452930fSRichard Haines 
247948bf85cSPaul Moore 		if (sksec->nlbl_state != NLBL_REQSKB)
248948bf85cSPaul Moore 			return 0;
249050d032bSPaul Moore 		secattr = selinux_netlbl_sock_getattr(sk, sid);
250948bf85cSPaul Moore 	}
2516c5b3fc0SPaul Moore 	if (secattr == NULL) {
2526c5b3fc0SPaul Moore 		secattr = &secattr_storage;
2536c5b3fc0SPaul Moore 		netlbl_secattr_init(secattr);
254e67b7985SStephen Smalley 		rc = security_netlbl_sid_to_secattr(sid, secattr);
255948bf85cSPaul Moore 		if (rc != 0)
256948bf85cSPaul Moore 			goto skbuff_setsid_return;
2576c5b3fc0SPaul Moore 	}
2586c5b3fc0SPaul Moore 
2596c5b3fc0SPaul Moore 	rc = netlbl_skbuff_setattr(skb, family, secattr);
260948bf85cSPaul Moore 
261948bf85cSPaul Moore skbuff_setsid_return:
2626c5b3fc0SPaul Moore 	if (secattr == &secattr_storage)
2636c5b3fc0SPaul Moore 		netlbl_secattr_destroy(secattr);
264948bf85cSPaul Moore 	return rc;
265948bf85cSPaul Moore }
266948bf85cSPaul Moore 
267948bf85cSPaul Moore /**
268d452930fSRichard Haines  * selinux_netlbl_sctp_assoc_request - Label an incoming sctp association.
269c081d53fSXin Long  * @asoc: incoming association.
270d452930fSRichard Haines  * @skb: the packet.
271d452930fSRichard Haines  *
272d452930fSRichard Haines  * Description:
273c081d53fSXin Long  * A new incoming connection is represented by @asoc, ......
274d452930fSRichard Haines  * Returns zero on success, negative values on failure.
275d452930fSRichard Haines  *
276d452930fSRichard Haines  */
selinux_netlbl_sctp_assoc_request(struct sctp_association * asoc,struct sk_buff * skb)277c081d53fSXin Long int selinux_netlbl_sctp_assoc_request(struct sctp_association *asoc,
278d452930fSRichard Haines 				     struct sk_buff *skb)
279d452930fSRichard Haines {
280d452930fSRichard Haines 	int rc;
281d452930fSRichard Haines 	struct netlbl_lsm_secattr secattr;
2822aff9d20SCasey Schaufler 	struct sk_security_struct *sksec = selinux_sock(asoc->base.sk);
283d452930fSRichard Haines 	struct sockaddr_in addr4;
284d452930fSRichard Haines 	struct sockaddr_in6 addr6;
285d452930fSRichard Haines 
286c081d53fSXin Long 	if (asoc->base.sk->sk_family != PF_INET &&
287c081d53fSXin Long 	    asoc->base.sk->sk_family != PF_INET6)
288d452930fSRichard Haines 		return 0;
289d452930fSRichard Haines 
290d452930fSRichard Haines 	netlbl_secattr_init(&secattr);
291e67b7985SStephen Smalley 	rc = security_netlbl_sid_to_secattr(asoc->secid, &secattr);
292d452930fSRichard Haines 	if (rc != 0)
293d452930fSRichard Haines 		goto assoc_request_return;
294d452930fSRichard Haines 
295d452930fSRichard Haines 	/* Move skb hdr address info to a struct sockaddr and then call
296d452930fSRichard Haines 	 * netlbl_conn_setattr().
297d452930fSRichard Haines 	 */
298d452930fSRichard Haines 	if (ip_hdr(skb)->version == 4) {
299d452930fSRichard Haines 		addr4.sin_family = AF_INET;
300d452930fSRichard Haines 		addr4.sin_addr.s_addr = ip_hdr(skb)->saddr;
301c081d53fSXin Long 		rc = netlbl_conn_setattr(asoc->base.sk, (void *)&addr4, &secattr);
30298bbbb76SArnd Bergmann 	} else if (IS_ENABLED(CONFIG_IPV6) && ip_hdr(skb)->version == 6) {
303d452930fSRichard Haines 		addr6.sin6_family = AF_INET6;
304d452930fSRichard Haines 		addr6.sin6_addr = ipv6_hdr(skb)->saddr;
305c081d53fSXin Long 		rc = netlbl_conn_setattr(asoc->base.sk, (void *)&addr6, &secattr);
30698bbbb76SArnd Bergmann 	} else {
30798bbbb76SArnd Bergmann 		rc = -EAFNOSUPPORT;
308d452930fSRichard Haines 	}
309d452930fSRichard Haines 
310d452930fSRichard Haines 	if (rc == 0)
311d452930fSRichard Haines 		sksec->nlbl_state = NLBL_LABELED;
312d452930fSRichard Haines 
313d452930fSRichard Haines assoc_request_return:
314d452930fSRichard Haines 	netlbl_secattr_destroy(&secattr);
315d452930fSRichard Haines 	return rc;
316d452930fSRichard Haines }
317d452930fSRichard Haines 
318d452930fSRichard Haines /**
319389fb800SPaul Moore  * selinux_netlbl_inet_conn_request - Label an incoming stream connection
320389fb800SPaul Moore  * @req: incoming connection request socket
321e9fd7292SPaul Moore  * @family: the request socket's address family
3225778eabdSPaul Moore  *
3235778eabdSPaul Moore  * Description:
324389fb800SPaul Moore  * A new incoming connection request is represented by @req, we need to label
325389fb800SPaul Moore  * the new request_sock here and the stack will ensure the on-the-wire label
326389fb800SPaul Moore  * will get preserved when a full sock is created once the connection handshake
327389fb800SPaul Moore  * is complete.  Returns zero on success, negative values on failure.
3285778eabdSPaul Moore  *
3295778eabdSPaul Moore  */
selinux_netlbl_inet_conn_request(struct request_sock * req,u16 family)330389fb800SPaul Moore int selinux_netlbl_inet_conn_request(struct request_sock *req, u16 family)
3315778eabdSPaul Moore {
332014ab19aSPaul Moore 	int rc;
333389fb800SPaul Moore 	struct netlbl_lsm_secattr secattr;
334389fb800SPaul Moore 
335e1adea92SHuw Davies 	if (family != PF_INET && family != PF_INET6)
336389fb800SPaul Moore 		return 0;
337389fb800SPaul Moore 
338389fb800SPaul Moore 	netlbl_secattr_init(&secattr);
339e67b7985SStephen Smalley 	rc = security_netlbl_sid_to_secattr(req->secid, &secattr);
340389fb800SPaul Moore 	if (rc != 0)
341389fb800SPaul Moore 		goto inet_conn_request_return;
342389fb800SPaul Moore 	rc = netlbl_req_setattr(req, &secattr);
343389fb800SPaul Moore inet_conn_request_return:
344389fb800SPaul Moore 	netlbl_secattr_destroy(&secattr);
345389fb800SPaul Moore 	return rc;
346389fb800SPaul Moore }
347389fb800SPaul Moore 
348389fb800SPaul Moore /**
349389fb800SPaul Moore  * selinux_netlbl_inet_csk_clone - Initialize the newly created sock
350389fb800SPaul Moore  * @sk: the new sock
351e9fd7292SPaul Moore  * @family: the sock's address family
352389fb800SPaul Moore  *
353389fb800SPaul Moore  * Description:
354389fb800SPaul Moore  * A new connection has been established using @sk, we've already labeled the
355389fb800SPaul Moore  * socket via the request_sock struct in selinux_netlbl_inet_conn_request() but
356389fb800SPaul Moore  * we need to set the NetLabel state here since we now have a sock structure.
357389fb800SPaul Moore  *
358389fb800SPaul Moore  */
selinux_netlbl_inet_csk_clone(struct sock * sk,u16 family)359389fb800SPaul Moore void selinux_netlbl_inet_csk_clone(struct sock *sk, u16 family)
360389fb800SPaul Moore {
3612aff9d20SCasey Schaufler 	struct sk_security_struct *sksec = selinux_sock(sk);
362014ab19aSPaul Moore 
363*a3422eb4SGuido Trentalancia 	if (family == PF_INET || family == PF_INET6)
364014ab19aSPaul Moore 		sksec->nlbl_state = NLBL_LABELED;
365389fb800SPaul Moore 	else
366014ab19aSPaul Moore 		sksec->nlbl_state = NLBL_UNSET;
3675778eabdSPaul Moore }
3685778eabdSPaul Moore 
3695778eabdSPaul Moore /**
370d452930fSRichard Haines  * selinux_netlbl_sctp_sk_clone - Copy state to the newly created sock
371d452930fSRichard Haines  * @sk: current sock
372d452930fSRichard Haines  * @newsk: the new sock
373d452930fSRichard Haines  *
374d452930fSRichard Haines  * Description:
375d452930fSRichard Haines  * Called whenever a new socket is created by accept(2) or sctp_peeloff(3).
376d452930fSRichard Haines  */
selinux_netlbl_sctp_sk_clone(struct sock * sk,struct sock * newsk)377d452930fSRichard Haines void selinux_netlbl_sctp_sk_clone(struct sock *sk, struct sock *newsk)
378d452930fSRichard Haines {
3792aff9d20SCasey Schaufler 	struct sk_security_struct *sksec = selinux_sock(sk);
3802aff9d20SCasey Schaufler 	struct sk_security_struct *newsksec = selinux_sock(newsk);
381d452930fSRichard Haines 
382d452930fSRichard Haines 	newsksec->nlbl_state = sksec->nlbl_state;
383d452930fSRichard Haines }
384d452930fSRichard Haines 
385d452930fSRichard Haines /**
3865778eabdSPaul Moore  * selinux_netlbl_socket_post_create - Label a socket using NetLabel
387e9fd7292SPaul Moore  * @sk: the sock to label
388389fb800SPaul Moore  * @family: protocol family
3895778eabdSPaul Moore  *
3905778eabdSPaul Moore  * Description:
3915778eabdSPaul Moore  * Attempt to label a socket using the NetLabel mechanism using the given
3925778eabdSPaul Moore  * SID.  Returns zero values on success, negative values on failure.
3935778eabdSPaul Moore  *
3945778eabdSPaul Moore  */
selinux_netlbl_socket_post_create(struct sock * sk,u16 family)395389fb800SPaul Moore int selinux_netlbl_socket_post_create(struct sock *sk, u16 family)
3965778eabdSPaul Moore {
3975778eabdSPaul Moore 	int rc;
3982aff9d20SCasey Schaufler 	struct sk_security_struct *sksec = selinux_sock(sk);
399389fb800SPaul Moore 	struct netlbl_lsm_secattr *secattr;
4005778eabdSPaul Moore 
401ceba1832SHuw Davies 	if (family != PF_INET && family != PF_INET6)
4025778eabdSPaul Moore 		return 0;
403f74af6e8SPaul Moore 
404389fb800SPaul Moore 	secattr = selinux_netlbl_sock_genattr(sk);
405fc328c86SGaosheng Cui 	if (IS_ERR(secattr))
406fc328c86SGaosheng Cui 		return PTR_ERR(secattr);
4078ec9897eSDavide Caratti 	/* On socket creation, replacement of IP options is safe even if
4088ec9897eSDavide Caratti 	 * the caller does not hold the socket lock.
4098ec9897eSDavide Caratti 	 */
4108ec9897eSDavide Caratti 	rc = netlbl_sock_setattr(sk, family, secattr, true);
411389fb800SPaul Moore 	switch (rc) {
412389fb800SPaul Moore 	case 0:
413389fb800SPaul Moore 		sksec->nlbl_state = NLBL_LABELED;
414389fb800SPaul Moore 		break;
415389fb800SPaul Moore 	case -EDESTADDRREQ:
416389fb800SPaul Moore 		sksec->nlbl_state = NLBL_REQSKB;
417f74af6e8SPaul Moore 		rc = 0;
418389fb800SPaul Moore 		break;
419389fb800SPaul Moore 	}
4205778eabdSPaul Moore 
4215778eabdSPaul Moore 	return rc;
4225778eabdSPaul Moore }
4235778eabdSPaul Moore 
4245778eabdSPaul Moore /**
4255778eabdSPaul Moore  * selinux_netlbl_sock_rcv_skb - Do an inbound access check using NetLabel
4265778eabdSPaul Moore  * @sksec: the sock's sk_security_struct
4275778eabdSPaul Moore  * @skb: the packet
42875e22910SPaul Moore  * @family: protocol family
4295778eabdSPaul Moore  * @ad: the audit data
4305778eabdSPaul Moore  *
4315778eabdSPaul Moore  * Description:
4325778eabdSPaul Moore  * Fetch the NetLabel security attributes from @skb and perform an access check
4335778eabdSPaul Moore  * against the receiving socket.  Returns zero on success, negative values on
4345778eabdSPaul Moore  * error.
4355778eabdSPaul Moore  *
4365778eabdSPaul Moore  */
selinux_netlbl_sock_rcv_skb(struct sk_security_struct * sksec,struct sk_buff * skb,u16 family,struct common_audit_data * ad)4375778eabdSPaul Moore int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
4385778eabdSPaul Moore 				struct sk_buff *skb,
43975e22910SPaul Moore 				u16 family,
4402bf49690SThomas Liu 				struct common_audit_data *ad)
4415778eabdSPaul Moore {
4425778eabdSPaul Moore 	int rc;
443f36158c4SPaul Moore 	u32 nlbl_sid;
444f36158c4SPaul Moore 	u32 perm;
445f36158c4SPaul Moore 	struct netlbl_lsm_secattr secattr;
4465778eabdSPaul Moore 
44723bcdc1aSPaul Moore 	if (!netlbl_enabled())
44823bcdc1aSPaul Moore 		return 0;
44923bcdc1aSPaul Moore 
450f36158c4SPaul Moore 	netlbl_secattr_init(&secattr);
45175e22910SPaul Moore 	rc = netlbl_skbuff_getattr(skb, family, &secattr);
4525dbe1eb0SPaul Moore 	if (rc == 0 && secattr.flags != NETLBL_SECATTR_NONE)
4534fee5242SHuw Davies 		rc = selinux_netlbl_sidlookup_cached(skb, family,
4544fee5242SHuw Davies 						     &secattr, &nlbl_sid);
4555dbe1eb0SPaul Moore 	else
456f36158c4SPaul Moore 		nlbl_sid = SECINITSID_UNLABELED;
457f36158c4SPaul Moore 	netlbl_secattr_destroy(&secattr);
4585778eabdSPaul Moore 	if (rc != 0)
4595778eabdSPaul Moore 		return rc;
4608d9107e8SLinus Torvalds 
4615778eabdSPaul Moore 	switch (sksec->sclass) {
4625778eabdSPaul Moore 	case SECCLASS_UDP_SOCKET:
463f36158c4SPaul Moore 		perm = UDP_SOCKET__RECVFROM;
4645778eabdSPaul Moore 		break;
4655778eabdSPaul Moore 	case SECCLASS_TCP_SOCKET:
466f36158c4SPaul Moore 		perm = TCP_SOCKET__RECVFROM;
4675778eabdSPaul Moore 		break;
4685778eabdSPaul Moore 	default:
469f36158c4SPaul Moore 		perm = RAWIP_SOCKET__RECVFROM;
4705778eabdSPaul Moore 	}
4715778eabdSPaul Moore 
472e67b7985SStephen Smalley 	rc = avc_has_perm(sksec->sid, nlbl_sid, sksec->sclass, perm, ad);
4735778eabdSPaul Moore 	if (rc == 0)
4745778eabdSPaul Moore 		return 0;
4755778eabdSPaul Moore 
476f36158c4SPaul Moore 	if (nlbl_sid != SECINITSID_UNLABELED)
477a04e71f6SHuw Davies 		netlbl_skbuff_err(skb, family, rc, 0);
4785778eabdSPaul Moore 	return rc;
4795778eabdSPaul Moore }
4805778eabdSPaul Moore 
4815778eabdSPaul Moore /**
4821f440c99SHuw Davies  * selinux_netlbl_option - Is this a NetLabel option
4831f440c99SHuw Davies  * @level: the socket level or protocol
4841f440c99SHuw Davies  * @optname: the socket option name
4851f440c99SHuw Davies  *
4861f440c99SHuw Davies  * Description:
4871f440c99SHuw Davies  * Returns true if @level and @optname refer to a NetLabel option.
4881f440c99SHuw Davies  * Helper for selinux_netlbl_socket_setsockopt().
4891f440c99SHuw Davies  */
selinux_netlbl_option(int level,int optname)4901f440c99SHuw Davies static inline int selinux_netlbl_option(int level, int optname)
4911f440c99SHuw Davies {
4921f440c99SHuw Davies 	return (level == IPPROTO_IP && optname == IP_OPTIONS) ||
4931f440c99SHuw Davies 		(level == IPPROTO_IPV6 && optname == IPV6_HOPOPTS);
4941f440c99SHuw Davies }
4951f440c99SHuw Davies 
4961f440c99SHuw Davies /**
4975778eabdSPaul Moore  * selinux_netlbl_socket_setsockopt - Do not allow users to remove a NetLabel
4985778eabdSPaul Moore  * @sock: the socket
4995778eabdSPaul Moore  * @level: the socket level or protocol
5005778eabdSPaul Moore  * @optname: the socket option name
5015778eabdSPaul Moore  *
5025778eabdSPaul Moore  * Description:
5035778eabdSPaul Moore  * Check the setsockopt() call and if the user is trying to replace the IP
5045778eabdSPaul Moore  * options on a socket and a NetLabel is in place for the socket deny the
5055778eabdSPaul Moore  * access; otherwise allow the access.  Returns zero when the access is
5065778eabdSPaul Moore  * allowed, -EACCES when denied, and other negative values on error.
5075778eabdSPaul Moore  *
5085778eabdSPaul Moore  */
selinux_netlbl_socket_setsockopt(struct socket * sock,int level,int optname)5095778eabdSPaul Moore int selinux_netlbl_socket_setsockopt(struct socket *sock,
5105778eabdSPaul Moore 				     int level,
5115778eabdSPaul Moore 				     int optname)
5125778eabdSPaul Moore {
5135778eabdSPaul Moore 	int rc = 0;
514ba6ff9f2SPaul Moore 	struct sock *sk = sock->sk;
5152aff9d20SCasey Schaufler 	struct sk_security_struct *sksec = selinux_sock(sk);
5165778eabdSPaul Moore 	struct netlbl_lsm_secattr secattr;
5175778eabdSPaul Moore 
5181f440c99SHuw Davies 	if (selinux_netlbl_option(level, optname) &&
519014ab19aSPaul Moore 	    (sksec->nlbl_state == NLBL_LABELED ||
520014ab19aSPaul Moore 	     sksec->nlbl_state == NLBL_CONNLABELED)) {
5215778eabdSPaul Moore 		netlbl_secattr_init(&secattr);
522ba6ff9f2SPaul Moore 		lock_sock(sk);
523050d032bSPaul Moore 		/* call the netlabel function directly as we want to see the
524050d032bSPaul Moore 		 * on-the-wire label that is assigned via the socket's options
525050d032bSPaul Moore 		 * and not the cached netlabel/lsm attributes */
526ba6ff9f2SPaul Moore 		rc = netlbl_sock_getattr(sk, &secattr);
527ba6ff9f2SPaul Moore 		release_sock(sk);
52809c50b4aSPaul Moore 		if (rc == 0)
5295778eabdSPaul Moore 			rc = -EACCES;
53009c50b4aSPaul Moore 		else if (rc == -ENOMSG)
53109c50b4aSPaul Moore 			rc = 0;
5325778eabdSPaul Moore 		netlbl_secattr_destroy(&secattr);
5335778eabdSPaul Moore 	}
5345778eabdSPaul Moore 
5355778eabdSPaul Moore 	return rc;
5365778eabdSPaul Moore }
537014ab19aSPaul Moore 
538014ab19aSPaul Moore /**
539d452930fSRichard Haines  * selinux_netlbl_socket_connect_helper - Help label a client-side socket on
540d452930fSRichard Haines  * connect
541d452930fSRichard Haines  * @sk: the socket to label
542d452930fSRichard Haines  * @addr: the destination address
543d452930fSRichard Haines  *
544d452930fSRichard Haines  * Description:
545d452930fSRichard Haines  * Attempt to label a connected socket with NetLabel using the given address.
546d452930fSRichard Haines  * Returns zero values on success, negative values on failure.
547d452930fSRichard Haines  *
548d452930fSRichard Haines  */
selinux_netlbl_socket_connect_helper(struct sock * sk,struct sockaddr * addr)549d452930fSRichard Haines static int selinux_netlbl_socket_connect_helper(struct sock *sk,
550d452930fSRichard Haines 						struct sockaddr *addr)
551d452930fSRichard Haines {
552d452930fSRichard Haines 	int rc;
5532aff9d20SCasey Schaufler 	struct sk_security_struct *sksec = selinux_sock(sk);
554d452930fSRichard Haines 	struct netlbl_lsm_secattr *secattr;
555d452930fSRichard Haines 
556d452930fSRichard Haines 	/* connected sockets are allowed to disconnect when the address family
557d452930fSRichard Haines 	 * is set to AF_UNSPEC, if that is what is happening we want to reset
558d452930fSRichard Haines 	 * the socket */
559d452930fSRichard Haines 	if (addr->sa_family == AF_UNSPEC) {
560d452930fSRichard Haines 		netlbl_sock_delattr(sk);
561d452930fSRichard Haines 		sksec->nlbl_state = NLBL_REQSKB;
562d452930fSRichard Haines 		rc = 0;
563d452930fSRichard Haines 		return rc;
564d452930fSRichard Haines 	}
565d452930fSRichard Haines 	secattr = selinux_netlbl_sock_genattr(sk);
566fc328c86SGaosheng Cui 	if (IS_ERR(secattr))
567fc328c86SGaosheng Cui 		return PTR_ERR(secattr);
568fc328c86SGaosheng Cui 
569d452930fSRichard Haines 	rc = netlbl_conn_setattr(sk, addr, secattr);
570d452930fSRichard Haines 	if (rc == 0)
571d452930fSRichard Haines 		sksec->nlbl_state = NLBL_CONNLABELED;
572d452930fSRichard Haines 
573d452930fSRichard Haines 	return rc;
574d452930fSRichard Haines }
575d452930fSRichard Haines 
576d452930fSRichard Haines /**
577d452930fSRichard Haines  * selinux_netlbl_socket_connect_locked - Label a client-side socket on
578d452930fSRichard Haines  * connect
579d452930fSRichard Haines  * @sk: the socket to label
580d452930fSRichard Haines  * @addr: the destination address
581d452930fSRichard Haines  *
582d452930fSRichard Haines  * Description:
583d452930fSRichard Haines  * Attempt to label a connected socket that already has the socket locked
584d452930fSRichard Haines  * with NetLabel using the given address.
585d452930fSRichard Haines  * Returns zero values on success, negative values on failure.
586d452930fSRichard Haines  *
587d452930fSRichard Haines  */
selinux_netlbl_socket_connect_locked(struct sock * sk,struct sockaddr * addr)588d452930fSRichard Haines int selinux_netlbl_socket_connect_locked(struct sock *sk,
589d452930fSRichard Haines 					 struct sockaddr *addr)
590d452930fSRichard Haines {
5912aff9d20SCasey Schaufler 	struct sk_security_struct *sksec = selinux_sock(sk);
592d452930fSRichard Haines 
593d452930fSRichard Haines 	if (sksec->nlbl_state != NLBL_REQSKB &&
594d452930fSRichard Haines 	    sksec->nlbl_state != NLBL_CONNLABELED)
595d452930fSRichard Haines 		return 0;
596d452930fSRichard Haines 
597d452930fSRichard Haines 	return selinux_netlbl_socket_connect_helper(sk, addr);
598d452930fSRichard Haines }
599d452930fSRichard Haines 
600d452930fSRichard Haines /**
601014ab19aSPaul Moore  * selinux_netlbl_socket_connect - Label a client-side socket on connect
602014ab19aSPaul Moore  * @sk: the socket to label
603014ab19aSPaul Moore  * @addr: the destination address
604014ab19aSPaul Moore  *
605014ab19aSPaul Moore  * Description:
606014ab19aSPaul Moore  * Attempt to label a connected socket with NetLabel using the given address.
607014ab19aSPaul Moore  * Returns zero values on success, negative values on failure.
608014ab19aSPaul Moore  *
609014ab19aSPaul Moore  */
selinux_netlbl_socket_connect(struct sock * sk,struct sockaddr * addr)610014ab19aSPaul Moore int selinux_netlbl_socket_connect(struct sock *sk, struct sockaddr *addr)
611014ab19aSPaul Moore {
612014ab19aSPaul Moore 	int rc;
613014ab19aSPaul Moore 
61442d64e1aSPaul Moore 	lock_sock(sk);
615d452930fSRichard Haines 	rc = selinux_netlbl_socket_connect_locked(sk, addr);
61642d64e1aSPaul Moore 	release_sock(sk);
617d452930fSRichard Haines 
618014ab19aSPaul Moore 	return rc;
619014ab19aSPaul Moore }
620