[ARM] S3C maintainer updates merge branch maintainers-updates into s3c-fixes
[linux-2.6] / security / selinux / netlabel.c
1 /*
2  * SELinux NetLabel Support
3  *
4  * This file provides the necessary glue to tie NetLabel into the SELinux
5  * subsystem.
6  *
7  * Author: Paul Moore <paul.moore@hp.com>
8  *
9  */
10
11 /*
12  * (c) Copyright Hewlett-Packard Development Company, L.P., 2007, 2008
13  *
14  * This program is free software;  you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as published by
16  * the Free Software Foundation; either version 2 of the License, or
17  * (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY;  without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
22  * the GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program;  if not, write to the Free Software
26  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27  *
28  */
29
30 #include <linux/spinlock.h>
31 #include <linux/rcupdate.h>
32 #include <linux/ip.h>
33 #include <linux/ipv6.h>
34 #include <net/sock.h>
35 #include <net/netlabel.h>
36 #include <net/ip.h>
37 #include <net/ipv6.h>
38
39 #include "objsec.h"
40 #include "security.h"
41 #include "netlabel.h"
42
43 /**
44  * selinux_netlbl_sidlookup_cached - Cache a SID lookup
45  * @skb: the packet
46  * @secattr: the NetLabel security attributes
47  * @sid: the SID
48  *
49  * Description:
50  * Query the SELinux security server to lookup the correct SID for the given
51  * security attributes.  If the query is successful, cache the result to speed
52  * up future lookups.  Returns zero on success, negative values on failure.
53  *
54  */
55 static int selinux_netlbl_sidlookup_cached(struct sk_buff *skb,
56                                            struct netlbl_lsm_secattr *secattr,
57                                            u32 *sid)
58 {
59         int rc;
60
61         rc = security_netlbl_secattr_to_sid(secattr, sid);
62         if (rc == 0 &&
63             (secattr->flags & NETLBL_SECATTR_CACHEABLE) &&
64             (secattr->flags & NETLBL_SECATTR_CACHE))
65                 netlbl_cache_add(skb, secattr);
66
67         return rc;
68 }
69
70 /**
71  * selinux_netlbl_sock_genattr - Generate the NetLabel socket secattr
72  * @sk: the socket
73  *
74  * Description:
75  * Generate the NetLabel security attributes for a socket, making full use of
76  * the socket's attribute cache.  Returns a pointer to the security attributes
77  * on success, NULL on failure.
78  *
79  */
80 static struct netlbl_lsm_secattr *selinux_netlbl_sock_genattr(struct sock *sk)
81 {
82         int rc;
83         struct sk_security_struct *sksec = sk->sk_security;
84         struct netlbl_lsm_secattr *secattr;
85
86         if (sksec->nlbl_secattr != NULL)
87                 return sksec->nlbl_secattr;
88
89         secattr = netlbl_secattr_alloc(GFP_ATOMIC);
90         if (secattr == NULL)
91                 return NULL;
92         rc = security_netlbl_sid_to_secattr(sksec->sid, secattr);
93         if (rc != 0) {
94                 netlbl_secattr_free(secattr);
95                 return NULL;
96         }
97         sksec->nlbl_secattr = secattr;
98
99         return secattr;
100 }
101
102 /**
103  * selinux_netlbl_cache_invalidate - Invalidate the NetLabel cache
104  *
105  * Description:
106  * Invalidate the NetLabel security attribute mapping cache.
107  *
108  */
109 void selinux_netlbl_cache_invalidate(void)
110 {
111         netlbl_cache_invalidate();
112 }
113
114 /**
115  * selinux_netlbl_err - Handle a NetLabel packet error
116  * @skb: the packet
117  * @error: the error code
118  * @gateway: true if host is acting as a gateway, false otherwise
119  *
120  * Description:
121  * When a packet is dropped due to a call to avc_has_perm() pass the error
122  * code to the NetLabel subsystem so any protocol specific processing can be
123  * done.  This is safe to call even if you are unsure if NetLabel labeling is
124  * present on the packet, NetLabel is smart enough to only act when it should.
125  *
126  */
127 void selinux_netlbl_err(struct sk_buff *skb, int error, int gateway)
128 {
129         netlbl_skbuff_err(skb, error, gateway);
130 }
131
132 /**
133  * selinux_netlbl_sk_security_free - Free the NetLabel fields
134  * @sssec: the sk_security_struct
135  *
136  * Description:
137  * Free all of the memory in the NetLabel fields of a sk_security_struct.
138  *
139  */
140 void selinux_netlbl_sk_security_free(struct sk_security_struct *ssec)
141 {
142         if (ssec->nlbl_secattr != NULL)
143                 netlbl_secattr_free(ssec->nlbl_secattr);
144 }
145
146 /**
147  * selinux_netlbl_sk_security_reset - Reset the NetLabel fields
148  * @ssec: the sk_security_struct
149  * @family: the socket family
150  *
151  * Description:
152  * Called when the NetLabel state of a sk_security_struct needs to be reset.
153  * The caller is responsibile for all the NetLabel sk_security_struct locking.
154  *
155  */
156 void selinux_netlbl_sk_security_reset(struct sk_security_struct *ssec)
157 {
158         ssec->nlbl_state = NLBL_UNSET;
159 }
160
161 /**
162  * selinux_netlbl_skbuff_getsid - Get the sid of a packet using NetLabel
163  * @skb: the packet
164  * @family: protocol family
165  * @type: NetLabel labeling protocol type
166  * @sid: the SID
167  *
168  * Description:
169  * Call the NetLabel mechanism to get the security attributes of the given
170  * packet and use those attributes to determine the correct context/SID to
171  * assign to the packet.  Returns zero on success, negative values on failure.
172  *
173  */
174 int selinux_netlbl_skbuff_getsid(struct sk_buff *skb,
175                                  u16 family,
176                                  u32 *type,
177                                  u32 *sid)
178 {
179         int rc;
180         struct netlbl_lsm_secattr secattr;
181
182         if (!netlbl_enabled()) {
183                 *sid = SECSID_NULL;
184                 return 0;
185         }
186
187         netlbl_secattr_init(&secattr);
188         rc = netlbl_skbuff_getattr(skb, family, &secattr);
189         if (rc == 0 && secattr.flags != NETLBL_SECATTR_NONE)
190                 rc = selinux_netlbl_sidlookup_cached(skb, &secattr, sid);
191         else
192                 *sid = SECSID_NULL;
193         *type = secattr.type;
194         netlbl_secattr_destroy(&secattr);
195
196         return rc;
197 }
198
199 /**
200  * selinux_netlbl_skbuff_setsid - Set the NetLabel on a packet given a sid
201  * @skb: the packet
202  * @family: protocol family
203  * @sid: the SID
204  *
205  * Description
206  * Call the NetLabel mechanism to set the label of a packet using @sid.
207  * Returns zero on auccess, negative values on failure.
208  *
209  */
210 int selinux_netlbl_skbuff_setsid(struct sk_buff *skb,
211                                  u16 family,
212                                  u32 sid)
213 {
214         int rc;
215         struct netlbl_lsm_secattr secattr_storage;
216         struct netlbl_lsm_secattr *secattr = NULL;
217         struct sock *sk;
218
219         /* if this is a locally generated packet check to see if it is already
220          * being labeled by it's parent socket, if it is just exit */
221         sk = skb->sk;
222         if (sk != NULL) {
223                 struct sk_security_struct *sksec = sk->sk_security;
224                 if (sksec->nlbl_state != NLBL_REQSKB)
225                         return 0;
226                 secattr = sksec->nlbl_secattr;
227         }
228         if (secattr == NULL) {
229                 secattr = &secattr_storage;
230                 netlbl_secattr_init(secattr);
231                 rc = security_netlbl_sid_to_secattr(sid, secattr);
232                 if (rc != 0)
233                         goto skbuff_setsid_return;
234         }
235
236         rc = netlbl_skbuff_setattr(skb, family, secattr);
237
238 skbuff_setsid_return:
239         if (secattr == &secattr_storage)
240                 netlbl_secattr_destroy(secattr);
241         return rc;
242 }
243
244 /**
245  * selinux_netlbl_inet_conn_request - Label an incoming stream connection
246  * @req: incoming connection request socket
247  *
248  * Description:
249  * A new incoming connection request is represented by @req, we need to label
250  * the new request_sock here and the stack will ensure the on-the-wire label
251  * will get preserved when a full sock is created once the connection handshake
252  * is complete.  Returns zero on success, negative values on failure.
253  *
254  */
255 int selinux_netlbl_inet_conn_request(struct request_sock *req, u16 family)
256 {
257         int rc;
258         struct netlbl_lsm_secattr secattr;
259
260         if (family != PF_INET)
261                 return 0;
262
263         netlbl_secattr_init(&secattr);
264         rc = security_netlbl_sid_to_secattr(req->secid, &secattr);
265         if (rc != 0)
266                 goto inet_conn_request_return;
267         rc = netlbl_req_setattr(req, &secattr);
268 inet_conn_request_return:
269         netlbl_secattr_destroy(&secattr);
270         return rc;
271 }
272
273 /**
274  * selinux_netlbl_inet_csk_clone - Initialize the newly created sock
275  * @sk: the new sock
276  *
277  * Description:
278  * A new connection has been established using @sk, we've already labeled the
279  * socket via the request_sock struct in selinux_netlbl_inet_conn_request() but
280  * we need to set the NetLabel state here since we now have a sock structure.
281  *
282  */
283 void selinux_netlbl_inet_csk_clone(struct sock *sk, u16 family)
284 {
285         struct sk_security_struct *sksec = sk->sk_security;
286
287         if (family == PF_INET)
288                 sksec->nlbl_state = NLBL_LABELED;
289         else
290                 sksec->nlbl_state = NLBL_UNSET;
291 }
292
293 /**
294  * selinux_netlbl_socket_post_create - Label a socket using NetLabel
295  * @sock: the socket to label
296  * @family: protocol family
297  *
298  * Description:
299  * Attempt to label a socket using the NetLabel mechanism using the given
300  * SID.  Returns zero values on success, negative values on failure.
301  *
302  */
303 int selinux_netlbl_socket_post_create(struct sock *sk, u16 family)
304 {
305         int rc;
306         struct sk_security_struct *sksec = sk->sk_security;
307         struct netlbl_lsm_secattr *secattr;
308
309         if (family != PF_INET)
310                 return 0;
311
312         secattr = selinux_netlbl_sock_genattr(sk);
313         if (secattr == NULL)
314                 return -ENOMEM;
315         rc = netlbl_sock_setattr(sk, family, secattr);
316         switch (rc) {
317         case 0:
318                 sksec->nlbl_state = NLBL_LABELED;
319                 break;
320         case -EDESTADDRREQ:
321                 sksec->nlbl_state = NLBL_REQSKB;
322                 rc = 0;
323                 break;
324         }
325
326         return rc;
327 }
328
329 /**
330  * selinux_netlbl_sock_rcv_skb - Do an inbound access check using NetLabel
331  * @sksec: the sock's sk_security_struct
332  * @skb: the packet
333  * @family: protocol family
334  * @ad: the audit data
335  *
336  * Description:
337  * Fetch the NetLabel security attributes from @skb and perform an access check
338  * against the receiving socket.  Returns zero on success, negative values on
339  * error.
340  *
341  */
342 int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
343                                 struct sk_buff *skb,
344                                 u16 family,
345                                 struct avc_audit_data *ad)
346 {
347         int rc;
348         u32 nlbl_sid;
349         u32 perm;
350         struct netlbl_lsm_secattr secattr;
351
352         if (!netlbl_enabled())
353                 return 0;
354
355         netlbl_secattr_init(&secattr);
356         rc = netlbl_skbuff_getattr(skb, family, &secattr);
357         if (rc == 0 && secattr.flags != NETLBL_SECATTR_NONE)
358                 rc = selinux_netlbl_sidlookup_cached(skb, &secattr, &nlbl_sid);
359         else
360                 nlbl_sid = SECINITSID_UNLABELED;
361         netlbl_secattr_destroy(&secattr);
362         if (rc != 0)
363                 return rc;
364
365         switch (sksec->sclass) {
366         case SECCLASS_UDP_SOCKET:
367                 perm = UDP_SOCKET__RECVFROM;
368                 break;
369         case SECCLASS_TCP_SOCKET:
370                 perm = TCP_SOCKET__RECVFROM;
371                 break;
372         default:
373                 perm = RAWIP_SOCKET__RECVFROM;
374         }
375
376         rc = avc_has_perm(sksec->sid, nlbl_sid, sksec->sclass, perm, ad);
377         if (rc == 0)
378                 return 0;
379
380         if (nlbl_sid != SECINITSID_UNLABELED)
381                 netlbl_skbuff_err(skb, rc, 0);
382         return rc;
383 }
384
385 /**
386  * selinux_netlbl_socket_setsockopt - Do not allow users to remove a NetLabel
387  * @sock: the socket
388  * @level: the socket level or protocol
389  * @optname: the socket option name
390  *
391  * Description:
392  * Check the setsockopt() call and if the user is trying to replace the IP
393  * options on a socket and a NetLabel is in place for the socket deny the
394  * access; otherwise allow the access.  Returns zero when the access is
395  * allowed, -EACCES when denied, and other negative values on error.
396  *
397  */
398 int selinux_netlbl_socket_setsockopt(struct socket *sock,
399                                      int level,
400                                      int optname)
401 {
402         int rc = 0;
403         struct sock *sk = sock->sk;
404         struct sk_security_struct *sksec = sk->sk_security;
405         struct netlbl_lsm_secattr secattr;
406
407         if (level == IPPROTO_IP && optname == IP_OPTIONS &&
408             (sksec->nlbl_state == NLBL_LABELED ||
409              sksec->nlbl_state == NLBL_CONNLABELED)) {
410                 netlbl_secattr_init(&secattr);
411                 lock_sock(sk);
412                 rc = netlbl_sock_getattr(sk, &secattr);
413                 release_sock(sk);
414                 if (rc == 0)
415                         rc = -EACCES;
416                 else if (rc == -ENOMSG)
417                         rc = 0;
418                 netlbl_secattr_destroy(&secattr);
419         }
420
421         return rc;
422 }
423
424 /**
425  * selinux_netlbl_socket_connect - Label a client-side socket on connect
426  * @sk: the socket to label
427  * @addr: the destination address
428  *
429  * Description:
430  * Attempt to label a connected socket with NetLabel using the given address.
431  * Returns zero values on success, negative values on failure.
432  *
433  */
434 int selinux_netlbl_socket_connect(struct sock *sk, struct sockaddr *addr)
435 {
436         int rc;
437         struct sk_security_struct *sksec = sk->sk_security;
438         struct netlbl_lsm_secattr *secattr;
439
440         if (sksec->nlbl_state != NLBL_REQSKB &&
441             sksec->nlbl_state != NLBL_CONNLABELED)
442                 return 0;
443
444         local_bh_disable();
445         bh_lock_sock_nested(sk);
446
447         /* connected sockets are allowed to disconnect when the address family
448          * is set to AF_UNSPEC, if that is what is happening we want to reset
449          * the socket */
450         if (addr->sa_family == AF_UNSPEC) {
451                 netlbl_sock_delattr(sk);
452                 sksec->nlbl_state = NLBL_REQSKB;
453                 rc = 0;
454                 goto socket_connect_return;
455         }
456         secattr = selinux_netlbl_sock_genattr(sk);
457         if (secattr == NULL) {
458                 rc = -ENOMEM;
459                 goto socket_connect_return;
460         }
461         rc = netlbl_conn_setattr(sk, addr, secattr);
462         if (rc == 0)
463                 sksec->nlbl_state = NLBL_CONNLABELED;
464
465 socket_connect_return:
466         bh_unlock_sock(sk);
467         local_bh_enable();
468         return rc;
469 }