1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * SELinux NetLabel Support
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * This file provides the necessary glue to tie NetLabel into the SELinux
6*4882a593Smuzhiyun * subsystem.
7*4882a593Smuzhiyun *
8*4882a593Smuzhiyun * Author: Paul Moore <paul@paul-moore.com>
9*4882a593Smuzhiyun */
10*4882a593Smuzhiyun
11*4882a593Smuzhiyun /*
12*4882a593Smuzhiyun * (c) Copyright Hewlett-Packard Development Company, L.P., 2007, 2008
13*4882a593Smuzhiyun */
14*4882a593Smuzhiyun
15*4882a593Smuzhiyun #include <linux/spinlock.h>
16*4882a593Smuzhiyun #include <linux/rcupdate.h>
17*4882a593Smuzhiyun #include <linux/gfp.h>
18*4882a593Smuzhiyun #include <linux/ip.h>
19*4882a593Smuzhiyun #include <linux/ipv6.h>
20*4882a593Smuzhiyun #include <net/sock.h>
21*4882a593Smuzhiyun #include <net/netlabel.h>
22*4882a593Smuzhiyun #include <net/ip.h>
23*4882a593Smuzhiyun #include <net/ipv6.h>
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun #include "objsec.h"
26*4882a593Smuzhiyun #include "security.h"
27*4882a593Smuzhiyun #include "netlabel.h"
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun /**
30*4882a593Smuzhiyun * selinux_netlbl_sidlookup_cached - Cache a SID lookup
31*4882a593Smuzhiyun * @skb: the packet
32*4882a593Smuzhiyun * @secattr: the NetLabel security attributes
33*4882a593Smuzhiyun * @sid: the SID
34*4882a593Smuzhiyun *
35*4882a593Smuzhiyun * Description:
36*4882a593Smuzhiyun * Query the SELinux security server to lookup the correct SID for the given
37*4882a593Smuzhiyun * security attributes. If the query is successful, cache the result to speed
38*4882a593Smuzhiyun * up future lookups. Returns zero on success, negative values on failure.
39*4882a593Smuzhiyun *
40*4882a593Smuzhiyun */
selinux_netlbl_sidlookup_cached(struct sk_buff * skb,u16 family,struct netlbl_lsm_secattr * secattr,u32 * sid)41*4882a593Smuzhiyun static int selinux_netlbl_sidlookup_cached(struct sk_buff *skb,
42*4882a593Smuzhiyun u16 family,
43*4882a593Smuzhiyun struct netlbl_lsm_secattr *secattr,
44*4882a593Smuzhiyun u32 *sid)
45*4882a593Smuzhiyun {
46*4882a593Smuzhiyun int rc;
47*4882a593Smuzhiyun
48*4882a593Smuzhiyun rc = security_netlbl_secattr_to_sid(&selinux_state, secattr, sid);
49*4882a593Smuzhiyun if (rc == 0 &&
50*4882a593Smuzhiyun (secattr->flags & NETLBL_SECATTR_CACHEABLE) &&
51*4882a593Smuzhiyun (secattr->flags & NETLBL_SECATTR_CACHE))
52*4882a593Smuzhiyun netlbl_cache_add(skb, family, secattr);
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun return rc;
55*4882a593Smuzhiyun }
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun /**
58*4882a593Smuzhiyun * selinux_netlbl_sock_genattr - Generate the NetLabel socket secattr
59*4882a593Smuzhiyun * @sk: the socket
60*4882a593Smuzhiyun *
61*4882a593Smuzhiyun * Description:
62*4882a593Smuzhiyun * Generate the NetLabel security attributes for a socket, making full use of
63*4882a593Smuzhiyun * the socket's attribute cache. Returns a pointer to the security attributes
64*4882a593Smuzhiyun * on success, NULL on failure.
65*4882a593Smuzhiyun *
66*4882a593Smuzhiyun */
selinux_netlbl_sock_genattr(struct sock * sk)67*4882a593Smuzhiyun static struct netlbl_lsm_secattr *selinux_netlbl_sock_genattr(struct sock *sk)
68*4882a593Smuzhiyun {
69*4882a593Smuzhiyun int rc;
70*4882a593Smuzhiyun struct sk_security_struct *sksec = sk->sk_security;
71*4882a593Smuzhiyun struct netlbl_lsm_secattr *secattr;
72*4882a593Smuzhiyun
73*4882a593Smuzhiyun if (sksec->nlbl_secattr != NULL)
74*4882a593Smuzhiyun return sksec->nlbl_secattr;
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun secattr = netlbl_secattr_alloc(GFP_ATOMIC);
77*4882a593Smuzhiyun if (secattr == NULL)
78*4882a593Smuzhiyun return NULL;
79*4882a593Smuzhiyun rc = security_netlbl_sid_to_secattr(&selinux_state, sksec->sid,
80*4882a593Smuzhiyun secattr);
81*4882a593Smuzhiyun if (rc != 0) {
82*4882a593Smuzhiyun netlbl_secattr_free(secattr);
83*4882a593Smuzhiyun return NULL;
84*4882a593Smuzhiyun }
85*4882a593Smuzhiyun sksec->nlbl_secattr = secattr;
86*4882a593Smuzhiyun
87*4882a593Smuzhiyun return secattr;
88*4882a593Smuzhiyun }
89*4882a593Smuzhiyun
90*4882a593Smuzhiyun /**
91*4882a593Smuzhiyun * selinux_netlbl_sock_getattr - Get the cached NetLabel secattr
92*4882a593Smuzhiyun * @sk: the socket
93*4882a593Smuzhiyun * @sid: the SID
94*4882a593Smuzhiyun *
95*4882a593Smuzhiyun * Query the socket's cached secattr and if the SID matches the cached value
96*4882a593Smuzhiyun * return the cache, otherwise return NULL.
97*4882a593Smuzhiyun *
98*4882a593Smuzhiyun */
selinux_netlbl_sock_getattr(const struct sock * sk,u32 sid)99*4882a593Smuzhiyun static struct netlbl_lsm_secattr *selinux_netlbl_sock_getattr(
100*4882a593Smuzhiyun const struct sock *sk,
101*4882a593Smuzhiyun u32 sid)
102*4882a593Smuzhiyun {
103*4882a593Smuzhiyun struct sk_security_struct *sksec = sk->sk_security;
104*4882a593Smuzhiyun struct netlbl_lsm_secattr *secattr = sksec->nlbl_secattr;
105*4882a593Smuzhiyun
106*4882a593Smuzhiyun if (secattr == NULL)
107*4882a593Smuzhiyun return NULL;
108*4882a593Smuzhiyun
109*4882a593Smuzhiyun if ((secattr->flags & NETLBL_SECATTR_SECID) &&
110*4882a593Smuzhiyun (secattr->attr.secid == sid))
111*4882a593Smuzhiyun return secattr;
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun return NULL;
114*4882a593Smuzhiyun }
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun /**
117*4882a593Smuzhiyun * selinux_netlbl_cache_invalidate - Invalidate the NetLabel cache
118*4882a593Smuzhiyun *
119*4882a593Smuzhiyun * Description:
120*4882a593Smuzhiyun * Invalidate the NetLabel security attribute mapping cache.
121*4882a593Smuzhiyun *
122*4882a593Smuzhiyun */
selinux_netlbl_cache_invalidate(void)123*4882a593Smuzhiyun void selinux_netlbl_cache_invalidate(void)
124*4882a593Smuzhiyun {
125*4882a593Smuzhiyun netlbl_cache_invalidate();
126*4882a593Smuzhiyun }
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun /**
129*4882a593Smuzhiyun * selinux_netlbl_err - Handle a NetLabel packet error
130*4882a593Smuzhiyun * @skb: the packet
131*4882a593Smuzhiyun * @error: the error code
132*4882a593Smuzhiyun * @gateway: true if host is acting as a gateway, false otherwise
133*4882a593Smuzhiyun *
134*4882a593Smuzhiyun * Description:
135*4882a593Smuzhiyun * When a packet is dropped due to a call to avc_has_perm() pass the error
136*4882a593Smuzhiyun * code to the NetLabel subsystem so any protocol specific processing can be
137*4882a593Smuzhiyun * done. This is safe to call even if you are unsure if NetLabel labeling is
138*4882a593Smuzhiyun * present on the packet, NetLabel is smart enough to only act when it should.
139*4882a593Smuzhiyun *
140*4882a593Smuzhiyun */
selinux_netlbl_err(struct sk_buff * skb,u16 family,int error,int gateway)141*4882a593Smuzhiyun void selinux_netlbl_err(struct sk_buff *skb, u16 family, int error, int gateway)
142*4882a593Smuzhiyun {
143*4882a593Smuzhiyun netlbl_skbuff_err(skb, family, error, gateway);
144*4882a593Smuzhiyun }
145*4882a593Smuzhiyun
146*4882a593Smuzhiyun /**
147*4882a593Smuzhiyun * selinux_netlbl_sk_security_free - Free the NetLabel fields
148*4882a593Smuzhiyun * @sksec: the sk_security_struct
149*4882a593Smuzhiyun *
150*4882a593Smuzhiyun * Description:
151*4882a593Smuzhiyun * Free all of the memory in the NetLabel fields of a sk_security_struct.
152*4882a593Smuzhiyun *
153*4882a593Smuzhiyun */
selinux_netlbl_sk_security_free(struct sk_security_struct * sksec)154*4882a593Smuzhiyun void selinux_netlbl_sk_security_free(struct sk_security_struct *sksec)
155*4882a593Smuzhiyun {
156*4882a593Smuzhiyun if (sksec->nlbl_secattr != NULL)
157*4882a593Smuzhiyun netlbl_secattr_free(sksec->nlbl_secattr);
158*4882a593Smuzhiyun }
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun /**
161*4882a593Smuzhiyun * selinux_netlbl_sk_security_reset - Reset the NetLabel fields
162*4882a593Smuzhiyun * @sksec: the sk_security_struct
163*4882a593Smuzhiyun * @family: the socket family
164*4882a593Smuzhiyun *
165*4882a593Smuzhiyun * Description:
166*4882a593Smuzhiyun * Called when the NetLabel state of a sk_security_struct needs to be reset.
167*4882a593Smuzhiyun * The caller is responsible for all the NetLabel sk_security_struct locking.
168*4882a593Smuzhiyun *
169*4882a593Smuzhiyun */
selinux_netlbl_sk_security_reset(struct sk_security_struct * sksec)170*4882a593Smuzhiyun void selinux_netlbl_sk_security_reset(struct sk_security_struct *sksec)
171*4882a593Smuzhiyun {
172*4882a593Smuzhiyun sksec->nlbl_state = NLBL_UNSET;
173*4882a593Smuzhiyun }
174*4882a593Smuzhiyun
175*4882a593Smuzhiyun /**
176*4882a593Smuzhiyun * selinux_netlbl_skbuff_getsid - Get the sid of a packet using NetLabel
177*4882a593Smuzhiyun * @skb: the packet
178*4882a593Smuzhiyun * @family: protocol family
179*4882a593Smuzhiyun * @type: NetLabel labeling protocol type
180*4882a593Smuzhiyun * @sid: the SID
181*4882a593Smuzhiyun *
182*4882a593Smuzhiyun * Description:
183*4882a593Smuzhiyun * Call the NetLabel mechanism to get the security attributes of the given
184*4882a593Smuzhiyun * packet and use those attributes to determine the correct context/SID to
185*4882a593Smuzhiyun * assign to the packet. Returns zero on success, negative values on failure.
186*4882a593Smuzhiyun *
187*4882a593Smuzhiyun */
selinux_netlbl_skbuff_getsid(struct sk_buff * skb,u16 family,u32 * type,u32 * sid)188*4882a593Smuzhiyun int selinux_netlbl_skbuff_getsid(struct sk_buff *skb,
189*4882a593Smuzhiyun u16 family,
190*4882a593Smuzhiyun u32 *type,
191*4882a593Smuzhiyun u32 *sid)
192*4882a593Smuzhiyun {
193*4882a593Smuzhiyun int rc;
194*4882a593Smuzhiyun struct netlbl_lsm_secattr secattr;
195*4882a593Smuzhiyun
196*4882a593Smuzhiyun if (!netlbl_enabled()) {
197*4882a593Smuzhiyun *sid = SECSID_NULL;
198*4882a593Smuzhiyun return 0;
199*4882a593Smuzhiyun }
200*4882a593Smuzhiyun
201*4882a593Smuzhiyun netlbl_secattr_init(&secattr);
202*4882a593Smuzhiyun rc = netlbl_skbuff_getattr(skb, family, &secattr);
203*4882a593Smuzhiyun if (rc == 0 && secattr.flags != NETLBL_SECATTR_NONE)
204*4882a593Smuzhiyun rc = selinux_netlbl_sidlookup_cached(skb, family,
205*4882a593Smuzhiyun &secattr, sid);
206*4882a593Smuzhiyun else
207*4882a593Smuzhiyun *sid = SECSID_NULL;
208*4882a593Smuzhiyun *type = secattr.type;
209*4882a593Smuzhiyun netlbl_secattr_destroy(&secattr);
210*4882a593Smuzhiyun
211*4882a593Smuzhiyun return rc;
212*4882a593Smuzhiyun }
213*4882a593Smuzhiyun
214*4882a593Smuzhiyun /**
215*4882a593Smuzhiyun * selinux_netlbl_skbuff_setsid - Set the NetLabel on a packet given a sid
216*4882a593Smuzhiyun * @skb: the packet
217*4882a593Smuzhiyun * @family: protocol family
218*4882a593Smuzhiyun * @sid: the SID
219*4882a593Smuzhiyun *
220*4882a593Smuzhiyun * Description
221*4882a593Smuzhiyun * Call the NetLabel mechanism to set the label of a packet using @sid.
222*4882a593Smuzhiyun * Returns zero on success, negative values on failure.
223*4882a593Smuzhiyun *
224*4882a593Smuzhiyun */
selinux_netlbl_skbuff_setsid(struct sk_buff * skb,u16 family,u32 sid)225*4882a593Smuzhiyun int selinux_netlbl_skbuff_setsid(struct sk_buff *skb,
226*4882a593Smuzhiyun u16 family,
227*4882a593Smuzhiyun u32 sid)
228*4882a593Smuzhiyun {
229*4882a593Smuzhiyun int rc;
230*4882a593Smuzhiyun struct netlbl_lsm_secattr secattr_storage;
231*4882a593Smuzhiyun struct netlbl_lsm_secattr *secattr = NULL;
232*4882a593Smuzhiyun struct sock *sk;
233*4882a593Smuzhiyun
234*4882a593Smuzhiyun /* if this is a locally generated packet check to see if it is already
235*4882a593Smuzhiyun * being labeled by it's parent socket, if it is just exit */
236*4882a593Smuzhiyun sk = skb_to_full_sk(skb);
237*4882a593Smuzhiyun if (sk != NULL) {
238*4882a593Smuzhiyun struct sk_security_struct *sksec = sk->sk_security;
239*4882a593Smuzhiyun
240*4882a593Smuzhiyun if (sksec->nlbl_state != NLBL_REQSKB)
241*4882a593Smuzhiyun return 0;
242*4882a593Smuzhiyun secattr = selinux_netlbl_sock_getattr(sk, sid);
243*4882a593Smuzhiyun }
244*4882a593Smuzhiyun if (secattr == NULL) {
245*4882a593Smuzhiyun secattr = &secattr_storage;
246*4882a593Smuzhiyun netlbl_secattr_init(secattr);
247*4882a593Smuzhiyun rc = security_netlbl_sid_to_secattr(&selinux_state, sid,
248*4882a593Smuzhiyun secattr);
249*4882a593Smuzhiyun if (rc != 0)
250*4882a593Smuzhiyun goto skbuff_setsid_return;
251*4882a593Smuzhiyun }
252*4882a593Smuzhiyun
253*4882a593Smuzhiyun rc = netlbl_skbuff_setattr(skb, family, secattr);
254*4882a593Smuzhiyun
255*4882a593Smuzhiyun skbuff_setsid_return:
256*4882a593Smuzhiyun if (secattr == &secattr_storage)
257*4882a593Smuzhiyun netlbl_secattr_destroy(secattr);
258*4882a593Smuzhiyun return rc;
259*4882a593Smuzhiyun }
260*4882a593Smuzhiyun
261*4882a593Smuzhiyun /**
262*4882a593Smuzhiyun * selinux_netlbl_sctp_assoc_request - Label an incoming sctp association.
263*4882a593Smuzhiyun * @ep: incoming association endpoint.
264*4882a593Smuzhiyun * @skb: the packet.
265*4882a593Smuzhiyun *
266*4882a593Smuzhiyun * Description:
267*4882a593Smuzhiyun * A new incoming connection is represented by @ep, ......
268*4882a593Smuzhiyun * Returns zero on success, negative values on failure.
269*4882a593Smuzhiyun *
270*4882a593Smuzhiyun */
selinux_netlbl_sctp_assoc_request(struct sctp_endpoint * ep,struct sk_buff * skb)271*4882a593Smuzhiyun int selinux_netlbl_sctp_assoc_request(struct sctp_endpoint *ep,
272*4882a593Smuzhiyun struct sk_buff *skb)
273*4882a593Smuzhiyun {
274*4882a593Smuzhiyun int rc;
275*4882a593Smuzhiyun struct netlbl_lsm_secattr secattr;
276*4882a593Smuzhiyun struct sk_security_struct *sksec = ep->base.sk->sk_security;
277*4882a593Smuzhiyun struct sockaddr_in addr4;
278*4882a593Smuzhiyun struct sockaddr_in6 addr6;
279*4882a593Smuzhiyun
280*4882a593Smuzhiyun if (ep->base.sk->sk_family != PF_INET &&
281*4882a593Smuzhiyun ep->base.sk->sk_family != PF_INET6)
282*4882a593Smuzhiyun return 0;
283*4882a593Smuzhiyun
284*4882a593Smuzhiyun netlbl_secattr_init(&secattr);
285*4882a593Smuzhiyun rc = security_netlbl_sid_to_secattr(&selinux_state,
286*4882a593Smuzhiyun ep->secid, &secattr);
287*4882a593Smuzhiyun if (rc != 0)
288*4882a593Smuzhiyun goto assoc_request_return;
289*4882a593Smuzhiyun
290*4882a593Smuzhiyun /* Move skb hdr address info to a struct sockaddr and then call
291*4882a593Smuzhiyun * netlbl_conn_setattr().
292*4882a593Smuzhiyun */
293*4882a593Smuzhiyun if (ip_hdr(skb)->version == 4) {
294*4882a593Smuzhiyun addr4.sin_family = AF_INET;
295*4882a593Smuzhiyun addr4.sin_addr.s_addr = ip_hdr(skb)->saddr;
296*4882a593Smuzhiyun rc = netlbl_conn_setattr(ep->base.sk, (void *)&addr4, &secattr);
297*4882a593Smuzhiyun } else if (IS_ENABLED(CONFIG_IPV6) && ip_hdr(skb)->version == 6) {
298*4882a593Smuzhiyun addr6.sin6_family = AF_INET6;
299*4882a593Smuzhiyun addr6.sin6_addr = ipv6_hdr(skb)->saddr;
300*4882a593Smuzhiyun rc = netlbl_conn_setattr(ep->base.sk, (void *)&addr6, &secattr);
301*4882a593Smuzhiyun } else {
302*4882a593Smuzhiyun rc = -EAFNOSUPPORT;
303*4882a593Smuzhiyun }
304*4882a593Smuzhiyun
305*4882a593Smuzhiyun if (rc == 0)
306*4882a593Smuzhiyun sksec->nlbl_state = NLBL_LABELED;
307*4882a593Smuzhiyun
308*4882a593Smuzhiyun assoc_request_return:
309*4882a593Smuzhiyun netlbl_secattr_destroy(&secattr);
310*4882a593Smuzhiyun return rc;
311*4882a593Smuzhiyun }
312*4882a593Smuzhiyun
313*4882a593Smuzhiyun /**
314*4882a593Smuzhiyun * selinux_netlbl_inet_conn_request - Label an incoming stream connection
315*4882a593Smuzhiyun * @req: incoming connection request socket
316*4882a593Smuzhiyun *
317*4882a593Smuzhiyun * Description:
318*4882a593Smuzhiyun * A new incoming connection request is represented by @req, we need to label
319*4882a593Smuzhiyun * the new request_sock here and the stack will ensure the on-the-wire label
320*4882a593Smuzhiyun * will get preserved when a full sock is created once the connection handshake
321*4882a593Smuzhiyun * is complete. Returns zero on success, negative values on failure.
322*4882a593Smuzhiyun *
323*4882a593Smuzhiyun */
selinux_netlbl_inet_conn_request(struct request_sock * req,u16 family)324*4882a593Smuzhiyun int selinux_netlbl_inet_conn_request(struct request_sock *req, u16 family)
325*4882a593Smuzhiyun {
326*4882a593Smuzhiyun int rc;
327*4882a593Smuzhiyun struct netlbl_lsm_secattr secattr;
328*4882a593Smuzhiyun
329*4882a593Smuzhiyun if (family != PF_INET && family != PF_INET6)
330*4882a593Smuzhiyun return 0;
331*4882a593Smuzhiyun
332*4882a593Smuzhiyun netlbl_secattr_init(&secattr);
333*4882a593Smuzhiyun rc = security_netlbl_sid_to_secattr(&selinux_state, req->secid,
334*4882a593Smuzhiyun &secattr);
335*4882a593Smuzhiyun if (rc != 0)
336*4882a593Smuzhiyun goto inet_conn_request_return;
337*4882a593Smuzhiyun rc = netlbl_req_setattr(req, &secattr);
338*4882a593Smuzhiyun inet_conn_request_return:
339*4882a593Smuzhiyun netlbl_secattr_destroy(&secattr);
340*4882a593Smuzhiyun return rc;
341*4882a593Smuzhiyun }
342*4882a593Smuzhiyun
343*4882a593Smuzhiyun /**
344*4882a593Smuzhiyun * selinux_netlbl_inet_csk_clone - Initialize the newly created sock
345*4882a593Smuzhiyun * @sk: the new sock
346*4882a593Smuzhiyun *
347*4882a593Smuzhiyun * Description:
348*4882a593Smuzhiyun * A new connection has been established using @sk, we've already labeled the
349*4882a593Smuzhiyun * socket via the request_sock struct in selinux_netlbl_inet_conn_request() but
350*4882a593Smuzhiyun * we need to set the NetLabel state here since we now have a sock structure.
351*4882a593Smuzhiyun *
352*4882a593Smuzhiyun */
selinux_netlbl_inet_csk_clone(struct sock * sk,u16 family)353*4882a593Smuzhiyun void selinux_netlbl_inet_csk_clone(struct sock *sk, u16 family)
354*4882a593Smuzhiyun {
355*4882a593Smuzhiyun struct sk_security_struct *sksec = sk->sk_security;
356*4882a593Smuzhiyun
357*4882a593Smuzhiyun if (family == PF_INET)
358*4882a593Smuzhiyun sksec->nlbl_state = NLBL_LABELED;
359*4882a593Smuzhiyun else
360*4882a593Smuzhiyun sksec->nlbl_state = NLBL_UNSET;
361*4882a593Smuzhiyun }
362*4882a593Smuzhiyun
363*4882a593Smuzhiyun /**
364*4882a593Smuzhiyun * selinux_netlbl_sctp_sk_clone - Copy state to the newly created sock
365*4882a593Smuzhiyun * @sk: current sock
366*4882a593Smuzhiyun * @newsk: the new sock
367*4882a593Smuzhiyun *
368*4882a593Smuzhiyun * Description:
369*4882a593Smuzhiyun * Called whenever a new socket is created by accept(2) or sctp_peeloff(3).
370*4882a593Smuzhiyun */
selinux_netlbl_sctp_sk_clone(struct sock * sk,struct sock * newsk)371*4882a593Smuzhiyun void selinux_netlbl_sctp_sk_clone(struct sock *sk, struct sock *newsk)
372*4882a593Smuzhiyun {
373*4882a593Smuzhiyun struct sk_security_struct *sksec = sk->sk_security;
374*4882a593Smuzhiyun struct sk_security_struct *newsksec = newsk->sk_security;
375*4882a593Smuzhiyun
376*4882a593Smuzhiyun newsksec->nlbl_state = sksec->nlbl_state;
377*4882a593Smuzhiyun }
378*4882a593Smuzhiyun
379*4882a593Smuzhiyun /**
380*4882a593Smuzhiyun * selinux_netlbl_socket_post_create - Label a socket using NetLabel
381*4882a593Smuzhiyun * @sock: the socket to label
382*4882a593Smuzhiyun * @family: protocol family
383*4882a593Smuzhiyun *
384*4882a593Smuzhiyun * Description:
385*4882a593Smuzhiyun * Attempt to label a socket using the NetLabel mechanism using the given
386*4882a593Smuzhiyun * SID. Returns zero values on success, negative values on failure.
387*4882a593Smuzhiyun *
388*4882a593Smuzhiyun */
selinux_netlbl_socket_post_create(struct sock * sk,u16 family)389*4882a593Smuzhiyun int selinux_netlbl_socket_post_create(struct sock *sk, u16 family)
390*4882a593Smuzhiyun {
391*4882a593Smuzhiyun int rc;
392*4882a593Smuzhiyun struct sk_security_struct *sksec = sk->sk_security;
393*4882a593Smuzhiyun struct netlbl_lsm_secattr *secattr;
394*4882a593Smuzhiyun
395*4882a593Smuzhiyun if (family != PF_INET && family != PF_INET6)
396*4882a593Smuzhiyun return 0;
397*4882a593Smuzhiyun
398*4882a593Smuzhiyun secattr = selinux_netlbl_sock_genattr(sk);
399*4882a593Smuzhiyun if (secattr == NULL)
400*4882a593Smuzhiyun return -ENOMEM;
401*4882a593Smuzhiyun rc = netlbl_sock_setattr(sk, family, secattr);
402*4882a593Smuzhiyun switch (rc) {
403*4882a593Smuzhiyun case 0:
404*4882a593Smuzhiyun sksec->nlbl_state = NLBL_LABELED;
405*4882a593Smuzhiyun break;
406*4882a593Smuzhiyun case -EDESTADDRREQ:
407*4882a593Smuzhiyun sksec->nlbl_state = NLBL_REQSKB;
408*4882a593Smuzhiyun rc = 0;
409*4882a593Smuzhiyun break;
410*4882a593Smuzhiyun }
411*4882a593Smuzhiyun
412*4882a593Smuzhiyun return rc;
413*4882a593Smuzhiyun }
414*4882a593Smuzhiyun
415*4882a593Smuzhiyun /**
416*4882a593Smuzhiyun * selinux_netlbl_sock_rcv_skb - Do an inbound access check using NetLabel
417*4882a593Smuzhiyun * @sksec: the sock's sk_security_struct
418*4882a593Smuzhiyun * @skb: the packet
419*4882a593Smuzhiyun * @family: protocol family
420*4882a593Smuzhiyun * @ad: the audit data
421*4882a593Smuzhiyun *
422*4882a593Smuzhiyun * Description:
423*4882a593Smuzhiyun * Fetch the NetLabel security attributes from @skb and perform an access check
424*4882a593Smuzhiyun * against the receiving socket. Returns zero on success, negative values on
425*4882a593Smuzhiyun * error.
426*4882a593Smuzhiyun *
427*4882a593Smuzhiyun */
selinux_netlbl_sock_rcv_skb(struct sk_security_struct * sksec,struct sk_buff * skb,u16 family,struct common_audit_data * ad)428*4882a593Smuzhiyun int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
429*4882a593Smuzhiyun struct sk_buff *skb,
430*4882a593Smuzhiyun u16 family,
431*4882a593Smuzhiyun struct common_audit_data *ad)
432*4882a593Smuzhiyun {
433*4882a593Smuzhiyun int rc;
434*4882a593Smuzhiyun u32 nlbl_sid;
435*4882a593Smuzhiyun u32 perm;
436*4882a593Smuzhiyun struct netlbl_lsm_secattr secattr;
437*4882a593Smuzhiyun
438*4882a593Smuzhiyun if (!netlbl_enabled())
439*4882a593Smuzhiyun return 0;
440*4882a593Smuzhiyun
441*4882a593Smuzhiyun netlbl_secattr_init(&secattr);
442*4882a593Smuzhiyun rc = netlbl_skbuff_getattr(skb, family, &secattr);
443*4882a593Smuzhiyun if (rc == 0 && secattr.flags != NETLBL_SECATTR_NONE)
444*4882a593Smuzhiyun rc = selinux_netlbl_sidlookup_cached(skb, family,
445*4882a593Smuzhiyun &secattr, &nlbl_sid);
446*4882a593Smuzhiyun else
447*4882a593Smuzhiyun nlbl_sid = SECINITSID_UNLABELED;
448*4882a593Smuzhiyun netlbl_secattr_destroy(&secattr);
449*4882a593Smuzhiyun if (rc != 0)
450*4882a593Smuzhiyun return rc;
451*4882a593Smuzhiyun
452*4882a593Smuzhiyun switch (sksec->sclass) {
453*4882a593Smuzhiyun case SECCLASS_UDP_SOCKET:
454*4882a593Smuzhiyun perm = UDP_SOCKET__RECVFROM;
455*4882a593Smuzhiyun break;
456*4882a593Smuzhiyun case SECCLASS_TCP_SOCKET:
457*4882a593Smuzhiyun perm = TCP_SOCKET__RECVFROM;
458*4882a593Smuzhiyun break;
459*4882a593Smuzhiyun default:
460*4882a593Smuzhiyun perm = RAWIP_SOCKET__RECVFROM;
461*4882a593Smuzhiyun }
462*4882a593Smuzhiyun
463*4882a593Smuzhiyun rc = avc_has_perm(&selinux_state,
464*4882a593Smuzhiyun sksec->sid, nlbl_sid, sksec->sclass, perm, ad);
465*4882a593Smuzhiyun if (rc == 0)
466*4882a593Smuzhiyun return 0;
467*4882a593Smuzhiyun
468*4882a593Smuzhiyun if (nlbl_sid != SECINITSID_UNLABELED)
469*4882a593Smuzhiyun netlbl_skbuff_err(skb, family, rc, 0);
470*4882a593Smuzhiyun return rc;
471*4882a593Smuzhiyun }
472*4882a593Smuzhiyun
473*4882a593Smuzhiyun /**
474*4882a593Smuzhiyun * selinux_netlbl_option - Is this a NetLabel option
475*4882a593Smuzhiyun * @level: the socket level or protocol
476*4882a593Smuzhiyun * @optname: the socket option name
477*4882a593Smuzhiyun *
478*4882a593Smuzhiyun * Description:
479*4882a593Smuzhiyun * Returns true if @level and @optname refer to a NetLabel option.
480*4882a593Smuzhiyun * Helper for selinux_netlbl_socket_setsockopt().
481*4882a593Smuzhiyun */
selinux_netlbl_option(int level,int optname)482*4882a593Smuzhiyun static inline int selinux_netlbl_option(int level, int optname)
483*4882a593Smuzhiyun {
484*4882a593Smuzhiyun return (level == IPPROTO_IP && optname == IP_OPTIONS) ||
485*4882a593Smuzhiyun (level == IPPROTO_IPV6 && optname == IPV6_HOPOPTS);
486*4882a593Smuzhiyun }
487*4882a593Smuzhiyun
488*4882a593Smuzhiyun /**
489*4882a593Smuzhiyun * selinux_netlbl_socket_setsockopt - Do not allow users to remove a NetLabel
490*4882a593Smuzhiyun * @sock: the socket
491*4882a593Smuzhiyun * @level: the socket level or protocol
492*4882a593Smuzhiyun * @optname: the socket option name
493*4882a593Smuzhiyun *
494*4882a593Smuzhiyun * Description:
495*4882a593Smuzhiyun * Check the setsockopt() call and if the user is trying to replace the IP
496*4882a593Smuzhiyun * options on a socket and a NetLabel is in place for the socket deny the
497*4882a593Smuzhiyun * access; otherwise allow the access. Returns zero when the access is
498*4882a593Smuzhiyun * allowed, -EACCES when denied, and other negative values on error.
499*4882a593Smuzhiyun *
500*4882a593Smuzhiyun */
selinux_netlbl_socket_setsockopt(struct socket * sock,int level,int optname)501*4882a593Smuzhiyun int selinux_netlbl_socket_setsockopt(struct socket *sock,
502*4882a593Smuzhiyun int level,
503*4882a593Smuzhiyun int optname)
504*4882a593Smuzhiyun {
505*4882a593Smuzhiyun int rc = 0;
506*4882a593Smuzhiyun struct sock *sk = sock->sk;
507*4882a593Smuzhiyun struct sk_security_struct *sksec = sk->sk_security;
508*4882a593Smuzhiyun struct netlbl_lsm_secattr secattr;
509*4882a593Smuzhiyun
510*4882a593Smuzhiyun if (selinux_netlbl_option(level, optname) &&
511*4882a593Smuzhiyun (sksec->nlbl_state == NLBL_LABELED ||
512*4882a593Smuzhiyun sksec->nlbl_state == NLBL_CONNLABELED)) {
513*4882a593Smuzhiyun netlbl_secattr_init(&secattr);
514*4882a593Smuzhiyun lock_sock(sk);
515*4882a593Smuzhiyun /* call the netlabel function directly as we want to see the
516*4882a593Smuzhiyun * on-the-wire label that is assigned via the socket's options
517*4882a593Smuzhiyun * and not the cached netlabel/lsm attributes */
518*4882a593Smuzhiyun rc = netlbl_sock_getattr(sk, &secattr);
519*4882a593Smuzhiyun release_sock(sk);
520*4882a593Smuzhiyun if (rc == 0)
521*4882a593Smuzhiyun rc = -EACCES;
522*4882a593Smuzhiyun else if (rc == -ENOMSG)
523*4882a593Smuzhiyun rc = 0;
524*4882a593Smuzhiyun netlbl_secattr_destroy(&secattr);
525*4882a593Smuzhiyun }
526*4882a593Smuzhiyun
527*4882a593Smuzhiyun return rc;
528*4882a593Smuzhiyun }
529*4882a593Smuzhiyun
530*4882a593Smuzhiyun /**
531*4882a593Smuzhiyun * selinux_netlbl_socket_connect_helper - Help label a client-side socket on
532*4882a593Smuzhiyun * connect
533*4882a593Smuzhiyun * @sk: the socket to label
534*4882a593Smuzhiyun * @addr: the destination address
535*4882a593Smuzhiyun *
536*4882a593Smuzhiyun * Description:
537*4882a593Smuzhiyun * Attempt to label a connected socket with NetLabel using the given address.
538*4882a593Smuzhiyun * Returns zero values on success, negative values on failure.
539*4882a593Smuzhiyun *
540*4882a593Smuzhiyun */
selinux_netlbl_socket_connect_helper(struct sock * sk,struct sockaddr * addr)541*4882a593Smuzhiyun static int selinux_netlbl_socket_connect_helper(struct sock *sk,
542*4882a593Smuzhiyun struct sockaddr *addr)
543*4882a593Smuzhiyun {
544*4882a593Smuzhiyun int rc;
545*4882a593Smuzhiyun struct sk_security_struct *sksec = sk->sk_security;
546*4882a593Smuzhiyun struct netlbl_lsm_secattr *secattr;
547*4882a593Smuzhiyun
548*4882a593Smuzhiyun /* connected sockets are allowed to disconnect when the address family
549*4882a593Smuzhiyun * is set to AF_UNSPEC, if that is what is happening we want to reset
550*4882a593Smuzhiyun * the socket */
551*4882a593Smuzhiyun if (addr->sa_family == AF_UNSPEC) {
552*4882a593Smuzhiyun netlbl_sock_delattr(sk);
553*4882a593Smuzhiyun sksec->nlbl_state = NLBL_REQSKB;
554*4882a593Smuzhiyun rc = 0;
555*4882a593Smuzhiyun return rc;
556*4882a593Smuzhiyun }
557*4882a593Smuzhiyun secattr = selinux_netlbl_sock_genattr(sk);
558*4882a593Smuzhiyun if (secattr == NULL) {
559*4882a593Smuzhiyun rc = -ENOMEM;
560*4882a593Smuzhiyun return rc;
561*4882a593Smuzhiyun }
562*4882a593Smuzhiyun rc = netlbl_conn_setattr(sk, addr, secattr);
563*4882a593Smuzhiyun if (rc == 0)
564*4882a593Smuzhiyun sksec->nlbl_state = NLBL_CONNLABELED;
565*4882a593Smuzhiyun
566*4882a593Smuzhiyun return rc;
567*4882a593Smuzhiyun }
568*4882a593Smuzhiyun
569*4882a593Smuzhiyun /**
570*4882a593Smuzhiyun * selinux_netlbl_socket_connect_locked - Label a client-side socket on
571*4882a593Smuzhiyun * connect
572*4882a593Smuzhiyun * @sk: the socket to label
573*4882a593Smuzhiyun * @addr: the destination address
574*4882a593Smuzhiyun *
575*4882a593Smuzhiyun * Description:
576*4882a593Smuzhiyun * Attempt to label a connected socket that already has the socket locked
577*4882a593Smuzhiyun * with NetLabel using the given address.
578*4882a593Smuzhiyun * Returns zero values on success, negative values on failure.
579*4882a593Smuzhiyun *
580*4882a593Smuzhiyun */
selinux_netlbl_socket_connect_locked(struct sock * sk,struct sockaddr * addr)581*4882a593Smuzhiyun int selinux_netlbl_socket_connect_locked(struct sock *sk,
582*4882a593Smuzhiyun struct sockaddr *addr)
583*4882a593Smuzhiyun {
584*4882a593Smuzhiyun struct sk_security_struct *sksec = sk->sk_security;
585*4882a593Smuzhiyun
586*4882a593Smuzhiyun if (sksec->nlbl_state != NLBL_REQSKB &&
587*4882a593Smuzhiyun sksec->nlbl_state != NLBL_CONNLABELED)
588*4882a593Smuzhiyun return 0;
589*4882a593Smuzhiyun
590*4882a593Smuzhiyun return selinux_netlbl_socket_connect_helper(sk, addr);
591*4882a593Smuzhiyun }
592*4882a593Smuzhiyun
593*4882a593Smuzhiyun /**
594*4882a593Smuzhiyun * selinux_netlbl_socket_connect - Label a client-side socket on connect
595*4882a593Smuzhiyun * @sk: the socket to label
596*4882a593Smuzhiyun * @addr: the destination address
597*4882a593Smuzhiyun *
598*4882a593Smuzhiyun * Description:
599*4882a593Smuzhiyun * Attempt to label a connected socket with NetLabel using the given address.
600*4882a593Smuzhiyun * Returns zero values on success, negative values on failure.
601*4882a593Smuzhiyun *
602*4882a593Smuzhiyun */
selinux_netlbl_socket_connect(struct sock * sk,struct sockaddr * addr)603*4882a593Smuzhiyun int selinux_netlbl_socket_connect(struct sock *sk, struct sockaddr *addr)
604*4882a593Smuzhiyun {
605*4882a593Smuzhiyun int rc;
606*4882a593Smuzhiyun
607*4882a593Smuzhiyun lock_sock(sk);
608*4882a593Smuzhiyun rc = selinux_netlbl_socket_connect_locked(sk, addr);
609*4882a593Smuzhiyun release_sock(sk);
610*4882a593Smuzhiyun
611*4882a593Smuzhiyun return rc;
612*4882a593Smuzhiyun }
613