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