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@paul-moore.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/gfp.h> 33 #include <linux/ip.h> 34 #include <linux/ipv6.h> 35 #include <net/sock.h> 36 #include <net/netlabel.h> 37 #include <net/ip.h> 38 #include <net/ipv6.h> 39 40 #include "objsec.h" 41 #include "security.h" 42 #include "netlabel.h" 43 44 /** 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 /** 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 /** 104 * selinux_netlbl_sock_getattr - Get the cached NetLabel secattr 105 * @sk: the socket 106 * @sid: the SID 107 * 108 * Query the socket's cached secattr and if the SID matches the cached value 109 * return the cache, otherwise return NULL. 110 * 111 */ 112 static struct netlbl_lsm_secattr *selinux_netlbl_sock_getattr( 113 const struct sock *sk, 114 u32 sid) 115 { 116 struct sk_security_struct *sksec = sk->sk_security; 117 struct netlbl_lsm_secattr *secattr = sksec->nlbl_secattr; 118 119 if (secattr == NULL) 120 return NULL; 121 122 if ((secattr->flags & NETLBL_SECATTR_SECID) && 123 (secattr->attr.secid == sid)) 124 return secattr; 125 126 return NULL; 127 } 128 129 /** 130 * selinux_netlbl_cache_invalidate - Invalidate the NetLabel cache 131 * 132 * Description: 133 * Invalidate the NetLabel security attribute mapping cache. 134 * 135 */ 136 void selinux_netlbl_cache_invalidate(void) 137 { 138 netlbl_cache_invalidate(); 139 } 140 141 /** 142 * selinux_netlbl_err - Handle a NetLabel packet error 143 * @skb: the packet 144 * @error: the error code 145 * @gateway: true if host is acting as a gateway, false otherwise 146 * 147 * Description: 148 * When a packet is dropped due to a call to avc_has_perm() pass the error 149 * code to the NetLabel subsystem so any protocol specific processing can be 150 * done. This is safe to call even if you are unsure if NetLabel labeling is 151 * present on the packet, NetLabel is smart enough to only act when it should. 152 * 153 */ 154 void selinux_netlbl_err(struct sk_buff *skb, int error, int gateway) 155 { 156 netlbl_skbuff_err(skb, error, gateway); 157 } 158 159 /** 160 * selinux_netlbl_sk_security_free - Free the NetLabel fields 161 * @sksec: the sk_security_struct 162 * 163 * Description: 164 * Free all of the memory in the NetLabel fields of a sk_security_struct. 165 * 166 */ 167 void selinux_netlbl_sk_security_free(struct sk_security_struct *sksec) 168 { 169 if (sksec->nlbl_secattr != NULL) 170 netlbl_secattr_free(sksec->nlbl_secattr); 171 } 172 173 /** 174 * selinux_netlbl_sk_security_reset - Reset the NetLabel fields 175 * @sksec: the sk_security_struct 176 * @family: the socket family 177 * 178 * Description: 179 * Called when the NetLabel state of a sk_security_struct needs to be reset. 180 * The caller is responsible for all the NetLabel sk_security_struct locking. 181 * 182 */ 183 void selinux_netlbl_sk_security_reset(struct sk_security_struct *sksec) 184 { 185 sksec->nlbl_state = NLBL_UNSET; 186 } 187 188 /** 189 * selinux_netlbl_skbuff_getsid - Get the sid of a packet using NetLabel 190 * @skb: the packet 191 * @family: protocol family 192 * @type: NetLabel labeling protocol type 193 * @sid: the SID 194 * 195 * Description: 196 * Call the NetLabel mechanism to get the security attributes of the given 197 * packet and use those attributes to determine the correct context/SID to 198 * assign to the packet. Returns zero on success, negative values on failure. 199 * 200 */ 201 int selinux_netlbl_skbuff_getsid(struct sk_buff *skb, 202 u16 family, 203 u32 *type, 204 u32 *sid) 205 { 206 int rc; 207 struct netlbl_lsm_secattr secattr; 208 209 if (!netlbl_enabled()) { 210 *sid = SECSID_NULL; 211 return 0; 212 } 213 214 netlbl_secattr_init(&secattr); 215 rc = netlbl_skbuff_getattr(skb, family, &secattr); 216 if (rc == 0 && secattr.flags != NETLBL_SECATTR_NONE) 217 rc = selinux_netlbl_sidlookup_cached(skb, &secattr, sid); 218 else 219 *sid = SECSID_NULL; 220 *type = secattr.type; 221 netlbl_secattr_destroy(&secattr); 222 223 return rc; 224 } 225 226 /** 227 * selinux_netlbl_skbuff_setsid - Set the NetLabel on a packet given a sid 228 * @skb: the packet 229 * @family: protocol family 230 * @sid: the SID 231 * 232 * Description 233 * Call the NetLabel mechanism to set the label of a packet using @sid. 234 * Returns zero on success, negative values on failure. 235 * 236 */ 237 int selinux_netlbl_skbuff_setsid(struct sk_buff *skb, 238 u16 family, 239 u32 sid) 240 { 241 int rc; 242 struct netlbl_lsm_secattr secattr_storage; 243 struct netlbl_lsm_secattr *secattr = NULL; 244 struct sock *sk; 245 246 /* if this is a locally generated packet check to see if it is already 247 * being labeled by it's parent socket, if it is just exit */ 248 sk = skb_to_full_sk(skb); 249 if (sk != NULL) { 250 struct sk_security_struct *sksec = sk->sk_security; 251 if (sksec->nlbl_state != NLBL_REQSKB) 252 return 0; 253 secattr = selinux_netlbl_sock_getattr(sk, sid); 254 } 255 if (secattr == NULL) { 256 secattr = &secattr_storage; 257 netlbl_secattr_init(secattr); 258 rc = security_netlbl_sid_to_secattr(sid, secattr); 259 if (rc != 0) 260 goto skbuff_setsid_return; 261 } 262 263 rc = netlbl_skbuff_setattr(skb, family, secattr); 264 265 skbuff_setsid_return: 266 if (secattr == &secattr_storage) 267 netlbl_secattr_destroy(secattr); 268 return rc; 269 } 270 271 /** 272 * selinux_netlbl_inet_conn_request - Label an incoming stream connection 273 * @req: incoming connection request socket 274 * 275 * Description: 276 * A new incoming connection request is represented by @req, we need to label 277 * the new request_sock here and the stack will ensure the on-the-wire label 278 * will get preserved when a full sock is created once the connection handshake 279 * is complete. Returns zero on success, negative values on failure. 280 * 281 */ 282 int selinux_netlbl_inet_conn_request(struct request_sock *req, u16 family) 283 { 284 int rc; 285 struct netlbl_lsm_secattr secattr; 286 287 if (family != PF_INET) 288 return 0; 289 290 netlbl_secattr_init(&secattr); 291 rc = security_netlbl_sid_to_secattr(req->secid, &secattr); 292 if (rc != 0) 293 goto inet_conn_request_return; 294 rc = netlbl_req_setattr(req, &secattr); 295 inet_conn_request_return: 296 netlbl_secattr_destroy(&secattr); 297 return rc; 298 } 299 300 /** 301 * selinux_netlbl_inet_csk_clone - Initialize the newly created sock 302 * @sk: the new sock 303 * 304 * Description: 305 * A new connection has been established using @sk, we've already labeled the 306 * socket via the request_sock struct in selinux_netlbl_inet_conn_request() but 307 * we need to set the NetLabel state here since we now have a sock structure. 308 * 309 */ 310 void selinux_netlbl_inet_csk_clone(struct sock *sk, u16 family) 311 { 312 struct sk_security_struct *sksec = sk->sk_security; 313 314 if (family == PF_INET) 315 sksec->nlbl_state = NLBL_LABELED; 316 else 317 sksec->nlbl_state = NLBL_UNSET; 318 } 319 320 /** 321 * selinux_netlbl_socket_post_create - Label a socket using NetLabel 322 * @sock: the socket to label 323 * @family: protocol family 324 * 325 * Description: 326 * Attempt to label a socket using the NetLabel mechanism using the given 327 * SID. Returns zero values on success, negative values on failure. 328 * 329 */ 330 int selinux_netlbl_socket_post_create(struct sock *sk, u16 family) 331 { 332 int rc; 333 struct sk_security_struct *sksec = sk->sk_security; 334 struct netlbl_lsm_secattr *secattr; 335 336 if (family != PF_INET) 337 return 0; 338 339 secattr = selinux_netlbl_sock_genattr(sk); 340 if (secattr == NULL) 341 return -ENOMEM; 342 rc = netlbl_sock_setattr(sk, family, secattr); 343 switch (rc) { 344 case 0: 345 sksec->nlbl_state = NLBL_LABELED; 346 break; 347 case -EDESTADDRREQ: 348 sksec->nlbl_state = NLBL_REQSKB; 349 rc = 0; 350 break; 351 } 352 353 return rc; 354 } 355 356 /** 357 * selinux_netlbl_sock_rcv_skb - Do an inbound access check using NetLabel 358 * @sksec: the sock's sk_security_struct 359 * @skb: the packet 360 * @family: protocol family 361 * @ad: the audit data 362 * 363 * Description: 364 * Fetch the NetLabel security attributes from @skb and perform an access check 365 * against the receiving socket. Returns zero on success, negative values on 366 * error. 367 * 368 */ 369 int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec, 370 struct sk_buff *skb, 371 u16 family, 372 struct common_audit_data *ad) 373 { 374 int rc; 375 u32 nlbl_sid; 376 u32 perm; 377 struct netlbl_lsm_secattr secattr; 378 379 if (!netlbl_enabled()) 380 return 0; 381 382 netlbl_secattr_init(&secattr); 383 rc = netlbl_skbuff_getattr(skb, family, &secattr); 384 if (rc == 0 && secattr.flags != NETLBL_SECATTR_NONE) 385 rc = selinux_netlbl_sidlookup_cached(skb, &secattr, &nlbl_sid); 386 else 387 nlbl_sid = SECINITSID_UNLABELED; 388 netlbl_secattr_destroy(&secattr); 389 if (rc != 0) 390 return rc; 391 392 switch (sksec->sclass) { 393 case SECCLASS_UDP_SOCKET: 394 perm = UDP_SOCKET__RECVFROM; 395 break; 396 case SECCLASS_TCP_SOCKET: 397 perm = TCP_SOCKET__RECVFROM; 398 break; 399 default: 400 perm = RAWIP_SOCKET__RECVFROM; 401 } 402 403 rc = avc_has_perm(sksec->sid, nlbl_sid, sksec->sclass, perm, ad); 404 if (rc == 0) 405 return 0; 406 407 if (nlbl_sid != SECINITSID_UNLABELED) 408 netlbl_skbuff_err(skb, rc, 0); 409 return rc; 410 } 411 412 /** 413 * selinux_netlbl_socket_setsockopt - Do not allow users to remove a NetLabel 414 * @sock: the socket 415 * @level: the socket level or protocol 416 * @optname: the socket option name 417 * 418 * Description: 419 * Check the setsockopt() call and if the user is trying to replace the IP 420 * options on a socket and a NetLabel is in place for the socket deny the 421 * access; otherwise allow the access. Returns zero when the access is 422 * allowed, -EACCES when denied, and other negative values on error. 423 * 424 */ 425 int selinux_netlbl_socket_setsockopt(struct socket *sock, 426 int level, 427 int optname) 428 { 429 int rc = 0; 430 struct sock *sk = sock->sk; 431 struct sk_security_struct *sksec = sk->sk_security; 432 struct netlbl_lsm_secattr secattr; 433 434 if (level == IPPROTO_IP && optname == IP_OPTIONS && 435 (sksec->nlbl_state == NLBL_LABELED || 436 sksec->nlbl_state == NLBL_CONNLABELED)) { 437 netlbl_secattr_init(&secattr); 438 lock_sock(sk); 439 /* call the netlabel function directly as we want to see the 440 * on-the-wire label that is assigned via the socket's options 441 * and not the cached netlabel/lsm attributes */ 442 rc = netlbl_sock_getattr(sk, &secattr); 443 release_sock(sk); 444 if (rc == 0) 445 rc = -EACCES; 446 else if (rc == -ENOMSG) 447 rc = 0; 448 netlbl_secattr_destroy(&secattr); 449 } 450 451 return rc; 452 } 453 454 /** 455 * selinux_netlbl_socket_connect - Label a client-side socket on connect 456 * @sk: the socket to label 457 * @addr: the destination address 458 * 459 * Description: 460 * Attempt to label a connected socket with NetLabel using the given address. 461 * Returns zero values on success, negative values on failure. 462 * 463 */ 464 int selinux_netlbl_socket_connect(struct sock *sk, struct sockaddr *addr) 465 { 466 int rc; 467 struct sk_security_struct *sksec = sk->sk_security; 468 struct netlbl_lsm_secattr *secattr; 469 470 if (sksec->nlbl_state != NLBL_REQSKB && 471 sksec->nlbl_state != NLBL_CONNLABELED) 472 return 0; 473 474 lock_sock(sk); 475 476 /* connected sockets are allowed to disconnect when the address family 477 * is set to AF_UNSPEC, if that is what is happening we want to reset 478 * the socket */ 479 if (addr->sa_family == AF_UNSPEC) { 480 netlbl_sock_delattr(sk); 481 sksec->nlbl_state = NLBL_REQSKB; 482 rc = 0; 483 goto socket_connect_return; 484 } 485 secattr = selinux_netlbl_sock_genattr(sk); 486 if (secattr == NULL) { 487 rc = -ENOMEM; 488 goto socket_connect_return; 489 } 490 rc = netlbl_conn_setattr(sk, addr, secattr); 491 if (rc == 0) 492 sksec->nlbl_state = NLBL_CONNLABELED; 493 494 socket_connect_return: 495 release_sock(sk); 496 return rc; 497 } 498