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