xref: /openbmc/linux/security/selinux/netlabel.c (revision e67b7985)
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  */
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 
49*e67b7985SStephen 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  */
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;
80*e67b7985SStephen 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  */
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  */
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  */
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  */
155dd3e7836SEric Paris void selinux_netlbl_sk_security_free(struct sk_security_struct *sksec)
1566c5b3fc0SPaul Moore {
157dd3e7836SEric Paris 	if (sksec->nlbl_secattr != NULL)
158dd3e7836SEric Paris 		netlbl_secattr_free(sksec->nlbl_secattr);
1596c5b3fc0SPaul Moore }
1606c5b3fc0SPaul Moore 
1616c5b3fc0SPaul Moore /**
1625778eabdSPaul Moore  * selinux_netlbl_sk_security_reset - Reset the NetLabel fields
163dd3e7836SEric Paris  * @sksec: the sk_security_struct
1645778eabdSPaul Moore  *
1655778eabdSPaul Moore  * Description:
1665778eabdSPaul Moore  * Called when the NetLabel state of a sk_security_struct needs to be reset.
16725985edcSLucas De Marchi  * The caller is responsible for all the NetLabel sk_security_struct locking.
1685778eabdSPaul Moore  *
1695778eabdSPaul Moore  */
170dd3e7836SEric Paris void selinux_netlbl_sk_security_reset(struct sk_security_struct *sksec)
1715778eabdSPaul Moore {
172dd3e7836SEric Paris 	sksec->nlbl_state = NLBL_UNSET;
1735778eabdSPaul Moore }
1745778eabdSPaul Moore 
1755778eabdSPaul Moore /**
1765778eabdSPaul Moore  * selinux_netlbl_skbuff_getsid - Get the sid of a packet using NetLabel
1775778eabdSPaul Moore  * @skb: the packet
17875e22910SPaul Moore  * @family: protocol family
179220deb96SPaul Moore  * @type: NetLabel labeling protocol type
1805778eabdSPaul Moore  * @sid: the SID
1815778eabdSPaul Moore  *
1825778eabdSPaul Moore  * Description:
1835778eabdSPaul Moore  * Call the NetLabel mechanism to get the security attributes of the given
1845778eabdSPaul Moore  * packet and use those attributes to determine the correct context/SID to
1855778eabdSPaul Moore  * assign to the packet.  Returns zero on success, negative values on failure.
1865778eabdSPaul Moore  *
1875778eabdSPaul Moore  */
18875e22910SPaul Moore int selinux_netlbl_skbuff_getsid(struct sk_buff *skb,
18975e22910SPaul Moore 				 u16 family,
190220deb96SPaul Moore 				 u32 *type,
19175e22910SPaul Moore 				 u32 *sid)
1925778eabdSPaul Moore {
1935778eabdSPaul Moore 	int rc;
1945778eabdSPaul Moore 	struct netlbl_lsm_secattr secattr;
1955778eabdSPaul Moore 
19623bcdc1aSPaul Moore 	if (!netlbl_enabled()) {
19723bcdc1aSPaul Moore 		*sid = SECSID_NULL;
19823bcdc1aSPaul Moore 		return 0;
19923bcdc1aSPaul Moore 	}
20023bcdc1aSPaul Moore 
2015778eabdSPaul Moore 	netlbl_secattr_init(&secattr);
20275e22910SPaul Moore 	rc = netlbl_skbuff_getattr(skb, family, &secattr);
2035dbe1eb0SPaul Moore 	if (rc == 0 && secattr.flags != NETLBL_SECATTR_NONE)
2044fee5242SHuw Davies 		rc = selinux_netlbl_sidlookup_cached(skb, family,
2054fee5242SHuw Davies 						     &secattr, sid);
2065dbe1eb0SPaul Moore 	else
2075778eabdSPaul Moore 		*sid = SECSID_NULL;
208220deb96SPaul Moore 	*type = secattr.type;
2095778eabdSPaul Moore 	netlbl_secattr_destroy(&secattr);
2105778eabdSPaul Moore 
2115778eabdSPaul Moore 	return rc;
2125778eabdSPaul Moore }
2135778eabdSPaul Moore 
2145778eabdSPaul Moore /**
215948bf85cSPaul Moore  * selinux_netlbl_skbuff_setsid - Set the NetLabel on a packet given a sid
216948bf85cSPaul Moore  * @skb: the packet
217948bf85cSPaul Moore  * @family: protocol family
218948bf85cSPaul Moore  * @sid: the SID
219948bf85cSPaul Moore  *
220948bf85cSPaul Moore  * Description
221948bf85cSPaul Moore  * Call the NetLabel mechanism to set the label of a packet using @sid.
222af901ca1SAndré Goddard Rosa  * Returns zero on success, negative values on failure.
223948bf85cSPaul Moore  *
224948bf85cSPaul Moore  */
225948bf85cSPaul Moore int selinux_netlbl_skbuff_setsid(struct sk_buff *skb,
226948bf85cSPaul Moore 				 u16 family,
227948bf85cSPaul Moore 				 u32 sid)
228948bf85cSPaul Moore {
229948bf85cSPaul Moore 	int rc;
2306c5b3fc0SPaul Moore 	struct netlbl_lsm_secattr secattr_storage;
2316c5b3fc0SPaul Moore 	struct netlbl_lsm_secattr *secattr = NULL;
232948bf85cSPaul Moore 	struct sock *sk;
233948bf85cSPaul Moore 
234948bf85cSPaul Moore 	/* if this is a locally generated packet check to see if it is already
235948bf85cSPaul Moore 	 * being labeled by it's parent socket, if it is just exit */
23654abc686SEric Dumazet 	sk = skb_to_full_sk(skb);
237948bf85cSPaul Moore 	if (sk != NULL) {
238948bf85cSPaul Moore 		struct sk_security_struct *sksec = sk->sk_security;
239d452930fSRichard Haines 
240948bf85cSPaul Moore 		if (sksec->nlbl_state != NLBL_REQSKB)
241948bf85cSPaul Moore 			return 0;
242050d032bSPaul Moore 		secattr = selinux_netlbl_sock_getattr(sk, sid);
243948bf85cSPaul Moore 	}
2446c5b3fc0SPaul Moore 	if (secattr == NULL) {
2456c5b3fc0SPaul Moore 		secattr = &secattr_storage;
2466c5b3fc0SPaul Moore 		netlbl_secattr_init(secattr);
247*e67b7985SStephen Smalley 		rc = security_netlbl_sid_to_secattr(sid, secattr);
248948bf85cSPaul Moore 		if (rc != 0)
249948bf85cSPaul Moore 			goto skbuff_setsid_return;
2506c5b3fc0SPaul Moore 	}
2516c5b3fc0SPaul Moore 
2526c5b3fc0SPaul Moore 	rc = netlbl_skbuff_setattr(skb, family, secattr);
253948bf85cSPaul Moore 
254948bf85cSPaul Moore skbuff_setsid_return:
2556c5b3fc0SPaul Moore 	if (secattr == &secattr_storage)
2566c5b3fc0SPaul Moore 		netlbl_secattr_destroy(secattr);
257948bf85cSPaul Moore 	return rc;
258948bf85cSPaul Moore }
259948bf85cSPaul Moore 
260948bf85cSPaul Moore /**
261d452930fSRichard Haines  * selinux_netlbl_sctp_assoc_request - Label an incoming sctp association.
262c081d53fSXin Long  * @asoc: incoming association.
263d452930fSRichard Haines  * @skb: the packet.
264d452930fSRichard Haines  *
265d452930fSRichard Haines  * Description:
266c081d53fSXin Long  * A new incoming connection is represented by @asoc, ......
267d452930fSRichard Haines  * Returns zero on success, negative values on failure.
268d452930fSRichard Haines  *
269d452930fSRichard Haines  */
270c081d53fSXin Long int selinux_netlbl_sctp_assoc_request(struct sctp_association *asoc,
271d452930fSRichard Haines 				     struct sk_buff *skb)
272d452930fSRichard Haines {
273d452930fSRichard Haines 	int rc;
274d452930fSRichard Haines 	struct netlbl_lsm_secattr secattr;
275c081d53fSXin Long 	struct sk_security_struct *sksec = asoc->base.sk->sk_security;
276d452930fSRichard Haines 	struct sockaddr_in addr4;
277d452930fSRichard Haines 	struct sockaddr_in6 addr6;
278d452930fSRichard Haines 
279c081d53fSXin Long 	if (asoc->base.sk->sk_family != PF_INET &&
280c081d53fSXin Long 	    asoc->base.sk->sk_family != PF_INET6)
281d452930fSRichard Haines 		return 0;
282d452930fSRichard Haines 
283d452930fSRichard Haines 	netlbl_secattr_init(&secattr);
284*e67b7985SStephen Smalley 	rc = security_netlbl_sid_to_secattr(asoc->secid, &secattr);
285d452930fSRichard Haines 	if (rc != 0)
286d452930fSRichard Haines 		goto assoc_request_return;
287d452930fSRichard Haines 
288d452930fSRichard Haines 	/* Move skb hdr address info to a struct sockaddr and then call
289d452930fSRichard Haines 	 * netlbl_conn_setattr().
290d452930fSRichard Haines 	 */
291d452930fSRichard Haines 	if (ip_hdr(skb)->version == 4) {
292d452930fSRichard Haines 		addr4.sin_family = AF_INET;
293d452930fSRichard Haines 		addr4.sin_addr.s_addr = ip_hdr(skb)->saddr;
294c081d53fSXin Long 		rc = netlbl_conn_setattr(asoc->base.sk, (void *)&addr4, &secattr);
29598bbbb76SArnd Bergmann 	} else if (IS_ENABLED(CONFIG_IPV6) && ip_hdr(skb)->version == 6) {
296d452930fSRichard Haines 		addr6.sin6_family = AF_INET6;
297d452930fSRichard Haines 		addr6.sin6_addr = ipv6_hdr(skb)->saddr;
298c081d53fSXin Long 		rc = netlbl_conn_setattr(asoc->base.sk, (void *)&addr6, &secattr);
29998bbbb76SArnd Bergmann 	} else {
30098bbbb76SArnd Bergmann 		rc = -EAFNOSUPPORT;
301d452930fSRichard Haines 	}
302d452930fSRichard Haines 
303d452930fSRichard Haines 	if (rc == 0)
304d452930fSRichard Haines 		sksec->nlbl_state = NLBL_LABELED;
305d452930fSRichard Haines 
306d452930fSRichard Haines assoc_request_return:
307d452930fSRichard Haines 	netlbl_secattr_destroy(&secattr);
308d452930fSRichard Haines 	return rc;
309d452930fSRichard Haines }
310d452930fSRichard Haines 
311d452930fSRichard Haines /**
312389fb800SPaul Moore  * selinux_netlbl_inet_conn_request - Label an incoming stream connection
313389fb800SPaul Moore  * @req: incoming connection request socket
314e9fd7292SPaul Moore  * @family: the request socket's address family
3155778eabdSPaul Moore  *
3165778eabdSPaul Moore  * Description:
317389fb800SPaul Moore  * A new incoming connection request is represented by @req, we need to label
318389fb800SPaul Moore  * the new request_sock here and the stack will ensure the on-the-wire label
319389fb800SPaul Moore  * will get preserved when a full sock is created once the connection handshake
320389fb800SPaul Moore  * is complete.  Returns zero on success, negative values on failure.
3215778eabdSPaul Moore  *
3225778eabdSPaul Moore  */
323389fb800SPaul Moore int selinux_netlbl_inet_conn_request(struct request_sock *req, u16 family)
3245778eabdSPaul Moore {
325014ab19aSPaul Moore 	int rc;
326389fb800SPaul Moore 	struct netlbl_lsm_secattr secattr;
327389fb800SPaul Moore 
328e1adea92SHuw Davies 	if (family != PF_INET && family != PF_INET6)
329389fb800SPaul Moore 		return 0;
330389fb800SPaul Moore 
331389fb800SPaul Moore 	netlbl_secattr_init(&secattr);
332*e67b7985SStephen Smalley 	rc = security_netlbl_sid_to_secattr(req->secid, &secattr);
333389fb800SPaul Moore 	if (rc != 0)
334389fb800SPaul Moore 		goto inet_conn_request_return;
335389fb800SPaul Moore 	rc = netlbl_req_setattr(req, &secattr);
336389fb800SPaul Moore inet_conn_request_return:
337389fb800SPaul Moore 	netlbl_secattr_destroy(&secattr);
338389fb800SPaul Moore 	return rc;
339389fb800SPaul Moore }
340389fb800SPaul Moore 
341389fb800SPaul Moore /**
342389fb800SPaul Moore  * selinux_netlbl_inet_csk_clone - Initialize the newly created sock
343389fb800SPaul Moore  * @sk: the new sock
344e9fd7292SPaul Moore  * @family: the sock's address family
345389fb800SPaul Moore  *
346389fb800SPaul Moore  * Description:
347389fb800SPaul Moore  * A new connection has been established using @sk, we've already labeled the
348389fb800SPaul Moore  * socket via the request_sock struct in selinux_netlbl_inet_conn_request() but
349389fb800SPaul Moore  * we need to set the NetLabel state here since we now have a sock structure.
350389fb800SPaul Moore  *
351389fb800SPaul Moore  */
352389fb800SPaul Moore void selinux_netlbl_inet_csk_clone(struct sock *sk, u16 family)
353389fb800SPaul Moore {
354014ab19aSPaul Moore 	struct sk_security_struct *sksec = sk->sk_security;
355014ab19aSPaul Moore 
356389fb800SPaul Moore 	if (family == PF_INET)
357014ab19aSPaul Moore 		sksec->nlbl_state = NLBL_LABELED;
358389fb800SPaul Moore 	else
359014ab19aSPaul Moore 		sksec->nlbl_state = NLBL_UNSET;
3605778eabdSPaul Moore }
3615778eabdSPaul Moore 
3625778eabdSPaul Moore /**
363d452930fSRichard Haines  * selinux_netlbl_sctp_sk_clone - Copy state to the newly created sock
364d452930fSRichard Haines  * @sk: current sock
365d452930fSRichard Haines  * @newsk: the new sock
366d452930fSRichard Haines  *
367d452930fSRichard Haines  * Description:
368d452930fSRichard Haines  * Called whenever a new socket is created by accept(2) or sctp_peeloff(3).
369d452930fSRichard Haines  */
370d452930fSRichard Haines void selinux_netlbl_sctp_sk_clone(struct sock *sk, struct sock *newsk)
371d452930fSRichard Haines {
372d452930fSRichard Haines 	struct sk_security_struct *sksec = sk->sk_security;
373d452930fSRichard Haines 	struct sk_security_struct *newsksec = newsk->sk_security;
374d452930fSRichard Haines 
375d452930fSRichard Haines 	newsksec->nlbl_state = sksec->nlbl_state;
376d452930fSRichard Haines }
377d452930fSRichard Haines 
378d452930fSRichard Haines /**
3795778eabdSPaul Moore  * selinux_netlbl_socket_post_create - Label a socket using NetLabel
380e9fd7292SPaul Moore  * @sk: the sock to label
381389fb800SPaul Moore  * @family: protocol family
3825778eabdSPaul Moore  *
3835778eabdSPaul Moore  * Description:
3845778eabdSPaul Moore  * Attempt to label a socket using the NetLabel mechanism using the given
3855778eabdSPaul Moore  * SID.  Returns zero values on success, negative values on failure.
3865778eabdSPaul Moore  *
3875778eabdSPaul Moore  */
388389fb800SPaul Moore int selinux_netlbl_socket_post_create(struct sock *sk, u16 family)
3895778eabdSPaul Moore {
3905778eabdSPaul Moore 	int rc;
391389fb800SPaul Moore 	struct sk_security_struct *sksec = sk->sk_security;
392389fb800SPaul Moore 	struct netlbl_lsm_secattr *secattr;
3935778eabdSPaul Moore 
394ceba1832SHuw Davies 	if (family != PF_INET && family != PF_INET6)
3955778eabdSPaul Moore 		return 0;
396f74af6e8SPaul Moore 
397389fb800SPaul Moore 	secattr = selinux_netlbl_sock_genattr(sk);
398389fb800SPaul Moore 	if (secattr == NULL)
399389fb800SPaul Moore 		return -ENOMEM;
400389fb800SPaul Moore 	rc = netlbl_sock_setattr(sk, family, secattr);
401389fb800SPaul Moore 	switch (rc) {
402389fb800SPaul Moore 	case 0:
403389fb800SPaul Moore 		sksec->nlbl_state = NLBL_LABELED;
404389fb800SPaul Moore 		break;
405389fb800SPaul Moore 	case -EDESTADDRREQ:
406389fb800SPaul Moore 		sksec->nlbl_state = NLBL_REQSKB;
407f74af6e8SPaul Moore 		rc = 0;
408389fb800SPaul Moore 		break;
409389fb800SPaul Moore 	}
4105778eabdSPaul Moore 
4115778eabdSPaul Moore 	return rc;
4125778eabdSPaul Moore }
4135778eabdSPaul Moore 
4145778eabdSPaul Moore /**
4155778eabdSPaul Moore  * selinux_netlbl_sock_rcv_skb - Do an inbound access check using NetLabel
4165778eabdSPaul Moore  * @sksec: the sock's sk_security_struct
4175778eabdSPaul Moore  * @skb: the packet
41875e22910SPaul Moore  * @family: protocol family
4195778eabdSPaul Moore  * @ad: the audit data
4205778eabdSPaul Moore  *
4215778eabdSPaul Moore  * Description:
4225778eabdSPaul Moore  * Fetch the NetLabel security attributes from @skb and perform an access check
4235778eabdSPaul Moore  * against the receiving socket.  Returns zero on success, negative values on
4245778eabdSPaul Moore  * error.
4255778eabdSPaul Moore  *
4265778eabdSPaul Moore  */
4275778eabdSPaul Moore int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
4285778eabdSPaul Moore 				struct sk_buff *skb,
42975e22910SPaul Moore 				u16 family,
4302bf49690SThomas Liu 				struct common_audit_data *ad)
4315778eabdSPaul Moore {
4325778eabdSPaul Moore 	int rc;
433f36158c4SPaul Moore 	u32 nlbl_sid;
434f36158c4SPaul Moore 	u32 perm;
435f36158c4SPaul Moore 	struct netlbl_lsm_secattr secattr;
4365778eabdSPaul Moore 
43723bcdc1aSPaul Moore 	if (!netlbl_enabled())
43823bcdc1aSPaul Moore 		return 0;
43923bcdc1aSPaul Moore 
440f36158c4SPaul Moore 	netlbl_secattr_init(&secattr);
44175e22910SPaul Moore 	rc = netlbl_skbuff_getattr(skb, family, &secattr);
4425dbe1eb0SPaul Moore 	if (rc == 0 && secattr.flags != NETLBL_SECATTR_NONE)
4434fee5242SHuw Davies 		rc = selinux_netlbl_sidlookup_cached(skb, family,
4444fee5242SHuw Davies 						     &secattr, &nlbl_sid);
4455dbe1eb0SPaul Moore 	else
446f36158c4SPaul Moore 		nlbl_sid = SECINITSID_UNLABELED;
447f36158c4SPaul Moore 	netlbl_secattr_destroy(&secattr);
4485778eabdSPaul Moore 	if (rc != 0)
4495778eabdSPaul Moore 		return rc;
4508d9107e8SLinus Torvalds 
4515778eabdSPaul Moore 	switch (sksec->sclass) {
4525778eabdSPaul Moore 	case SECCLASS_UDP_SOCKET:
453f36158c4SPaul Moore 		perm = UDP_SOCKET__RECVFROM;
4545778eabdSPaul Moore 		break;
4555778eabdSPaul Moore 	case SECCLASS_TCP_SOCKET:
456f36158c4SPaul Moore 		perm = TCP_SOCKET__RECVFROM;
4575778eabdSPaul Moore 		break;
4585778eabdSPaul Moore 	default:
459f36158c4SPaul Moore 		perm = RAWIP_SOCKET__RECVFROM;
4605778eabdSPaul Moore 	}
4615778eabdSPaul Moore 
462*e67b7985SStephen Smalley 	rc = avc_has_perm(sksec->sid, nlbl_sid, sksec->sclass, perm, ad);
4635778eabdSPaul Moore 	if (rc == 0)
4645778eabdSPaul Moore 		return 0;
4655778eabdSPaul Moore 
466f36158c4SPaul Moore 	if (nlbl_sid != SECINITSID_UNLABELED)
467a04e71f6SHuw Davies 		netlbl_skbuff_err(skb, family, rc, 0);
4685778eabdSPaul Moore 	return rc;
4695778eabdSPaul Moore }
4705778eabdSPaul Moore 
4715778eabdSPaul Moore /**
4721f440c99SHuw Davies  * selinux_netlbl_option - Is this a NetLabel option
4731f440c99SHuw Davies  * @level: the socket level or protocol
4741f440c99SHuw Davies  * @optname: the socket option name
4751f440c99SHuw Davies  *
4761f440c99SHuw Davies  * Description:
4771f440c99SHuw Davies  * Returns true if @level and @optname refer to a NetLabel option.
4781f440c99SHuw Davies  * Helper for selinux_netlbl_socket_setsockopt().
4791f440c99SHuw Davies  */
4801f440c99SHuw Davies static inline int selinux_netlbl_option(int level, int optname)
4811f440c99SHuw Davies {
4821f440c99SHuw Davies 	return (level == IPPROTO_IP && optname == IP_OPTIONS) ||
4831f440c99SHuw Davies 		(level == IPPROTO_IPV6 && optname == IPV6_HOPOPTS);
4841f440c99SHuw Davies }
4851f440c99SHuw Davies 
4861f440c99SHuw Davies /**
4875778eabdSPaul Moore  * selinux_netlbl_socket_setsockopt - Do not allow users to remove a NetLabel
4885778eabdSPaul Moore  * @sock: the socket
4895778eabdSPaul Moore  * @level: the socket level or protocol
4905778eabdSPaul Moore  * @optname: the socket option name
4915778eabdSPaul Moore  *
4925778eabdSPaul Moore  * Description:
4935778eabdSPaul Moore  * Check the setsockopt() call and if the user is trying to replace the IP
4945778eabdSPaul Moore  * options on a socket and a NetLabel is in place for the socket deny the
4955778eabdSPaul Moore  * access; otherwise allow the access.  Returns zero when the access is
4965778eabdSPaul Moore  * allowed, -EACCES when denied, and other negative values on error.
4975778eabdSPaul Moore  *
4985778eabdSPaul Moore  */
4995778eabdSPaul Moore int selinux_netlbl_socket_setsockopt(struct socket *sock,
5005778eabdSPaul Moore 				     int level,
5015778eabdSPaul Moore 				     int optname)
5025778eabdSPaul Moore {
5035778eabdSPaul Moore 	int rc = 0;
504ba6ff9f2SPaul Moore 	struct sock *sk = sock->sk;
505ba6ff9f2SPaul Moore 	struct sk_security_struct *sksec = sk->sk_security;
5065778eabdSPaul Moore 	struct netlbl_lsm_secattr secattr;
5075778eabdSPaul Moore 
5081f440c99SHuw Davies 	if (selinux_netlbl_option(level, optname) &&
509014ab19aSPaul Moore 	    (sksec->nlbl_state == NLBL_LABELED ||
510014ab19aSPaul Moore 	     sksec->nlbl_state == NLBL_CONNLABELED)) {
5115778eabdSPaul Moore 		netlbl_secattr_init(&secattr);
512ba6ff9f2SPaul Moore 		lock_sock(sk);
513050d032bSPaul Moore 		/* call the netlabel function directly as we want to see the
514050d032bSPaul Moore 		 * on-the-wire label that is assigned via the socket's options
515050d032bSPaul Moore 		 * and not the cached netlabel/lsm attributes */
516ba6ff9f2SPaul Moore 		rc = netlbl_sock_getattr(sk, &secattr);
517ba6ff9f2SPaul Moore 		release_sock(sk);
51809c50b4aSPaul Moore 		if (rc == 0)
5195778eabdSPaul Moore 			rc = -EACCES;
52009c50b4aSPaul Moore 		else if (rc == -ENOMSG)
52109c50b4aSPaul Moore 			rc = 0;
5225778eabdSPaul Moore 		netlbl_secattr_destroy(&secattr);
5235778eabdSPaul Moore 	}
5245778eabdSPaul Moore 
5255778eabdSPaul Moore 	return rc;
5265778eabdSPaul Moore }
527014ab19aSPaul Moore 
528014ab19aSPaul Moore /**
529d452930fSRichard Haines  * selinux_netlbl_socket_connect_helper - Help label a client-side socket on
530d452930fSRichard Haines  * connect
531d452930fSRichard Haines  * @sk: the socket to label
532d452930fSRichard Haines  * @addr: the destination address
533d452930fSRichard Haines  *
534d452930fSRichard Haines  * Description:
535d452930fSRichard Haines  * Attempt to label a connected socket with NetLabel using the given address.
536d452930fSRichard Haines  * Returns zero values on success, negative values on failure.
537d452930fSRichard Haines  *
538d452930fSRichard Haines  */
539d452930fSRichard Haines static int selinux_netlbl_socket_connect_helper(struct sock *sk,
540d452930fSRichard Haines 						struct sockaddr *addr)
541d452930fSRichard Haines {
542d452930fSRichard Haines 	int rc;
543d452930fSRichard Haines 	struct sk_security_struct *sksec = sk->sk_security;
544d452930fSRichard Haines 	struct netlbl_lsm_secattr *secattr;
545d452930fSRichard Haines 
546d452930fSRichard Haines 	/* connected sockets are allowed to disconnect when the address family
547d452930fSRichard Haines 	 * is set to AF_UNSPEC, if that is what is happening we want to reset
548d452930fSRichard Haines 	 * the socket */
549d452930fSRichard Haines 	if (addr->sa_family == AF_UNSPEC) {
550d452930fSRichard Haines 		netlbl_sock_delattr(sk);
551d452930fSRichard Haines 		sksec->nlbl_state = NLBL_REQSKB;
552d452930fSRichard Haines 		rc = 0;
553d452930fSRichard Haines 		return rc;
554d452930fSRichard Haines 	}
555d452930fSRichard Haines 	secattr = selinux_netlbl_sock_genattr(sk);
556d452930fSRichard Haines 	if (secattr == NULL) {
557d452930fSRichard Haines 		rc = -ENOMEM;
558d452930fSRichard Haines 		return rc;
559d452930fSRichard Haines 	}
560d452930fSRichard Haines 	rc = netlbl_conn_setattr(sk, addr, secattr);
561d452930fSRichard Haines 	if (rc == 0)
562d452930fSRichard Haines 		sksec->nlbl_state = NLBL_CONNLABELED;
563d452930fSRichard Haines 
564d452930fSRichard Haines 	return rc;
565d452930fSRichard Haines }
566d452930fSRichard Haines 
567d452930fSRichard Haines /**
568d452930fSRichard Haines  * selinux_netlbl_socket_connect_locked - Label a client-side socket on
569d452930fSRichard Haines  * connect
570d452930fSRichard Haines  * @sk: the socket to label
571d452930fSRichard Haines  * @addr: the destination address
572d452930fSRichard Haines  *
573d452930fSRichard Haines  * Description:
574d452930fSRichard Haines  * Attempt to label a connected socket that already has the socket locked
575d452930fSRichard Haines  * with NetLabel using the given address.
576d452930fSRichard Haines  * Returns zero values on success, negative values on failure.
577d452930fSRichard Haines  *
578d452930fSRichard Haines  */
579d452930fSRichard Haines int selinux_netlbl_socket_connect_locked(struct sock *sk,
580d452930fSRichard Haines 					 struct sockaddr *addr)
581d452930fSRichard Haines {
582d452930fSRichard Haines 	struct sk_security_struct *sksec = sk->sk_security;
583d452930fSRichard Haines 
584d452930fSRichard Haines 	if (sksec->nlbl_state != NLBL_REQSKB &&
585d452930fSRichard Haines 	    sksec->nlbl_state != NLBL_CONNLABELED)
586d452930fSRichard Haines 		return 0;
587d452930fSRichard Haines 
588d452930fSRichard Haines 	return selinux_netlbl_socket_connect_helper(sk, addr);
589d452930fSRichard Haines }
590d452930fSRichard Haines 
591d452930fSRichard Haines /**
592014ab19aSPaul Moore  * selinux_netlbl_socket_connect - Label a client-side socket on connect
593014ab19aSPaul Moore  * @sk: the socket to label
594014ab19aSPaul Moore  * @addr: the destination address
595014ab19aSPaul Moore  *
596014ab19aSPaul Moore  * Description:
597014ab19aSPaul Moore  * Attempt to label a connected socket with NetLabel using the given address.
598014ab19aSPaul Moore  * Returns zero values on success, negative values on failure.
599014ab19aSPaul Moore  *
600014ab19aSPaul Moore  */
601014ab19aSPaul Moore int selinux_netlbl_socket_connect(struct sock *sk, struct sockaddr *addr)
602014ab19aSPaul Moore {
603014ab19aSPaul Moore 	int rc;
604014ab19aSPaul Moore 
60542d64e1aSPaul Moore 	lock_sock(sk);
606d452930fSRichard Haines 	rc = selinux_netlbl_socket_connect_locked(sk, addr);
60742d64e1aSPaul Moore 	release_sock(sk);
608d452930fSRichard Haines 
609014ab19aSPaul Moore 	return rc;
610014ab19aSPaul Moore }
611