1/*- 2 * Copyright (c) 1999-2002 Robert N. M. Watson 3 * Copyright (c) 2001 Ilmar S. Habibulin 4 * Copyright (c) 2001-2005 Networks Associates Technology, Inc. 5 * Copyright (c) 2005 SPARTA, Inc. 6 * All rights reserved. 7 * 8 * This software was developed by Robert Watson and Ilmar Habibulin for the 9 * TrustedBSD Project. 10 * 11 * This software was developed for the FreeBSD Project in part by McAfee 12 * Research, the Technology Research Division of Network Associates, Inc. 13 * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the 14 * DARPA CHATS research program. 15 * 16 * This software was enhanced by SPARTA ISSO under SPAWAR contract 17 * N66001-04-C-6019 ("SEFOS"). 18 * 19 * Redistribution and use in source and binary forms, with or without 20 * modification, are permitted provided that the following conditions 21 * are met: 22 * 1. Redistributions of source code must retain the above copyright 23 * notice, this list of conditions and the following disclaimer. 24 * 2. Redistributions in binary form must reproduce the above copyright 25 * notice, this list of conditions and the following disclaimer in the 26 * documentation and/or other materials provided with the distribution. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 31 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 38 * SUCH DAMAGE. 39 */ 40 41#include <sys/cdefs.h>
|
42__FBSDID("$FreeBSD: head/sys/security/mac/mac_socket.c 165469 2006-12-22 23:34:47Z rwatson $");
|
42__FBSDID("$FreeBSD: head/sys/security/mac/mac_socket.c 168955 2007-04-22 19:55:56Z rwatson $"); |
43 44#include "opt_mac.h" 45 46#include <sys/param.h> 47#include <sys/kernel.h> 48#include <sys/lock.h> 49#include <sys/malloc.h> 50#include <sys/mutex.h> 51#include <sys/mac.h> 52#include <sys/sbuf.h> 53#include <sys/systm.h> 54#include <sys/mount.h> 55#include <sys/file.h> 56#include <sys/namei.h> 57#include <sys/protosw.h> 58#include <sys/socket.h> 59#include <sys/socketvar.h> 60#include <sys/sysctl.h> 61 62#include <net/bpfdesc.h> 63#include <net/if.h> 64#include <net/if_var.h> 65 66#include <netinet/in.h> 67#include <netinet/in_pcb.h> 68#include <netinet/ip_var.h> 69 70#include <security/mac/mac_framework.h> 71#include <security/mac/mac_internal.h> 72#include <security/mac/mac_policy.h> 73 74/* 75 * Currently, sockets hold two labels: the label of the socket itself, and a 76 * peer label, which may be used by policies to hold a copy of the label of 77 * any remote endpoint. 78 * 79 * Possibly, this peer label should be maintained at the protocol layer 80 * (inpcb, unpcb, etc), as this would allow protocol-aware code to maintain 81 * the label consistently. For example, it might be copied live from a 82 * remote socket for UNIX domain sockets rather than keeping a local copy on 83 * this endpoint, but be cached and updated based on packets received for 84 * TCP/IP. 85 */ 86 87struct label * 88mac_socket_label_alloc(int flag) 89{ 90 struct label *label; 91 int error; 92 93 label = mac_labelzone_alloc(flag); 94 if (label == NULL) 95 return (NULL); 96 97 MAC_CHECK(init_socket_label, label, flag); 98 if (error) { 99 MAC_PERFORM(destroy_socket_label, label); 100 mac_labelzone_free(label); 101 return (NULL); 102 } 103 return (label); 104} 105 106static struct label * 107mac_socket_peer_label_alloc(int flag) 108{ 109 struct label *label; 110 int error; 111 112 label = mac_labelzone_alloc(flag); 113 if (label == NULL) 114 return (NULL); 115 116 MAC_CHECK(init_socket_peer_label, label, flag); 117 if (error) { 118 MAC_PERFORM(destroy_socket_peer_label, label); 119 mac_labelzone_free(label); 120 return (NULL); 121 } 122 return (label); 123} 124 125int 126mac_init_socket(struct socket *so, int flag) 127{ 128 129 so->so_label = mac_socket_label_alloc(flag); 130 if (so->so_label == NULL) 131 return (ENOMEM); 132 so->so_peerlabel = mac_socket_peer_label_alloc(flag); 133 if (so->so_peerlabel == NULL) { 134 mac_socket_label_free(so->so_label); 135 so->so_label = NULL; 136 return (ENOMEM); 137 } 138 return (0); 139} 140 141void 142mac_socket_label_free(struct label *label) 143{ 144 145 MAC_PERFORM(destroy_socket_label, label); 146 mac_labelzone_free(label); 147} 148 149static void 150mac_socket_peer_label_free(struct label *label) 151{ 152 153 MAC_PERFORM(destroy_socket_peer_label, label); 154 mac_labelzone_free(label); 155} 156 157void
|
158mac_destroy_socket(struct socket *socket)
|
158mac_destroy_socket(struct socket *so) |
159{ 160
|
161 mac_socket_label_free(socket->so_label);
162 socket->so_label = NULL;
163 mac_socket_peer_label_free(socket->so_peerlabel);
164 socket->so_peerlabel = NULL;
|
161 mac_socket_label_free(so->so_label); 162 so->so_label = NULL; 163 mac_socket_peer_label_free(so->so_peerlabel); 164 so->so_peerlabel = NULL; |
165} 166 167void 168mac_copy_socket_label(struct label *src, struct label *dest) 169{ 170 171 MAC_PERFORM(copy_socket_label, src, dest); 172} 173 174int 175mac_externalize_socket_label(struct label *label, char *elements, 176 char *outbuf, size_t outbuflen) 177{ 178 int error; 179 180 MAC_EXTERNALIZE(socket, label, elements, outbuf, outbuflen); 181 182 return (error); 183} 184 185static int 186mac_externalize_socket_peer_label(struct label *label, char *elements, 187 char *outbuf, size_t outbuflen) 188{ 189 int error; 190 191 MAC_EXTERNALIZE(socket_peer, label, elements, outbuf, outbuflen); 192 193 return (error); 194} 195 196int 197mac_internalize_socket_label(struct label *label, char *string) 198{ 199 int error; 200 201 MAC_INTERNALIZE(socket, label, string); 202 203 return (error); 204} 205 206void
|
207mac_create_socket(struct ucred *cred, struct socket *socket)
|
207mac_create_socket(struct ucred *cred, struct socket *so) |
208{ 209
|
210 MAC_PERFORM(create_socket, cred, socket, socket->so_label);
|
210 MAC_PERFORM(create_socket, cred, so, so->so_label); |
211} 212 213void
|
214mac_create_socket_from_socket(struct socket *oldsocket,
215 struct socket *newsocket)
|
214mac_create_socket_from_socket(struct socket *oldso, struct socket *newso) |
215{ 216
|
218 SOCK_LOCK_ASSERT(oldsocket);
219 MAC_PERFORM(create_socket_from_socket, oldsocket, oldsocket->so_label,
220 newsocket, newsocket->so_label);
|
217 SOCK_LOCK_ASSERT(oldso); 218 219 MAC_PERFORM(create_socket_from_socket, oldso, oldso->so_label, newso, 220 newso->so_label); |
221} 222 223static void
|
224mac_relabel_socket(struct ucred *cred, struct socket *socket,
|
224mac_relabel_socket(struct ucred *cred, struct socket *so, |
225 struct label *newlabel) 226{ 227
|
228 SOCK_LOCK_ASSERT(socket);
229 MAC_PERFORM(relabel_socket, cred, socket, socket->so_label, newlabel);
|
228 SOCK_LOCK_ASSERT(so); 229 230 MAC_PERFORM(relabel_socket, cred, so, so->so_label, newlabel); |
231} 232 233void
|
233mac_set_socket_peer_from_mbuf(struct mbuf *mbuf, struct socket *socket)
|
234mac_set_socket_peer_from_mbuf(struct mbuf *m, struct socket *so) |
235{ 236 struct label *label; 237
|
237 SOCK_LOCK_ASSERT(socket);
|
238 SOCK_LOCK_ASSERT(so); |
239
|
239 label = mac_mbuf_to_label(mbuf);
|
240 label = mac_mbuf_to_label(m); |
241
|
241 MAC_PERFORM(set_socket_peer_from_mbuf, mbuf, label, socket,
242 socket->so_peerlabel);
|
242 MAC_PERFORM(set_socket_peer_from_mbuf, m, label, so, 243 so->so_peerlabel); |
244} 245 246void
|
246mac_set_socket_peer_from_socket(struct socket *oldsocket,
247 struct socket *newsocket)
|
247mac_set_socket_peer_from_socket(struct socket *oldso, struct socket *newso) |
248{ 249 250 /* 251 * XXXRW: only hold the socket lock on one at a time, as one socket 252 * is the original, and one is the new. However, it's called in both 253 * directions, so we can't assert the lock here currently. 254 */
|
255 MAC_PERFORM(set_socket_peer_from_socket, oldsocket,
256 oldsocket->so_label, newsocket, newsocket->so_peerlabel);
|
255 MAC_PERFORM(set_socket_peer_from_socket, oldso, oldso->so_label, 256 newso, newso->so_peerlabel); |
257} 258 259void
|
260mac_create_mbuf_from_socket(struct socket *socket, struct mbuf *mbuf)
|
260mac_create_mbuf_from_socket(struct socket *so, struct mbuf *m) |
261{ 262 struct label *label; 263
|
264 label = mac_mbuf_to_label(mbuf);
|
264 SOCK_LOCK_ASSERT(so); |
265
|
266 SOCK_LOCK_ASSERT(socket);
267 MAC_PERFORM(create_mbuf_from_socket, socket, socket->so_label, mbuf,
268 label);
|
266 label = mac_mbuf_to_label(m); 267 268 MAC_PERFORM(create_mbuf_from_socket, so, so->so_label, m, label); |
269} 270 271int
|
272mac_check_socket_accept(struct ucred *cred, struct socket *socket)
|
272mac_check_socket_accept(struct ucred *cred, struct socket *so) |
273{ 274 int error; 275
|
276 SOCK_LOCK_ASSERT(socket);
|
276 SOCK_LOCK_ASSERT(so); |
277
|
278 MAC_CHECK(check_socket_accept, cred, socket, socket->so_label);
|
278 MAC_CHECK(check_socket_accept, cred, so, so->so_label); |
279 280 return (error); 281} 282 283int
|
284mac_check_socket_bind(struct ucred *ucred, struct socket *socket,
285 struct sockaddr *sockaddr)
|
284mac_check_socket_bind(struct ucred *ucred, struct socket *so, 285 struct sockaddr *sa) |
286{ 287 int error; 288
|
289 SOCK_LOCK_ASSERT(socket);
|
289 SOCK_LOCK_ASSERT(so); |
290
|
291 MAC_CHECK(check_socket_bind, ucred, socket, socket->so_label,
292 sockaddr);
|
291 MAC_CHECK(check_socket_bind, ucred, so, so->so_label, sa); |
292 293 return (error); 294} 295 296int
|
298mac_check_socket_connect(struct ucred *cred, struct socket *socket,
299 struct sockaddr *sockaddr)
|
297mac_check_socket_connect(struct ucred *cred, struct socket *so, 298 struct sockaddr *sa) |
299{ 300 int error; 301
|
303 SOCK_LOCK_ASSERT(socket);
|
302 SOCK_LOCK_ASSERT(so); |
303
|
305 MAC_CHECK(check_socket_connect, cred, socket, socket->so_label,
306 sockaddr);
|
304 MAC_CHECK(check_socket_connect, cred, so, so->so_label, sa); |
305 306 return (error); 307} 308 309int
|
312mac_check_socket_create(struct ucred *cred, int domain, int type,
313 int protocol)
|
310mac_check_socket_create(struct ucred *cred, int domain, int type, int proto) |
311{ 312 int error; 313
|
317 MAC_CHECK(check_socket_create, cred, domain, type, protocol);
|
314 MAC_CHECK(check_socket_create, cred, domain, type, proto); |
315 316 return (error); 317} 318 319int
|
323mac_check_socket_deliver(struct socket *socket, struct mbuf *mbuf)
|
320mac_check_socket_deliver(struct socket *so, struct mbuf *m) |
321{ 322 struct label *label; 323 int error; 324
|
328 SOCK_LOCK_ASSERT(socket);
|
325 SOCK_LOCK_ASSERT(so); |
326
|
330 label = mac_mbuf_to_label(mbuf);
|
327 label = mac_mbuf_to_label(m); |
328
|
332 MAC_CHECK(check_socket_deliver, socket, socket->so_label, mbuf,
333 label);
|
329 MAC_CHECK(check_socket_deliver, so, so->so_label, m, label); |
330 331 return (error); 332} 333 334int
|
339mac_check_socket_listen(struct ucred *cred, struct socket *socket)
|
335mac_check_socket_listen(struct ucred *cred, struct socket *so) |
336{ 337 int error; 338
|
343 SOCK_LOCK_ASSERT(socket);
|
339 SOCK_LOCK_ASSERT(so); |
340
|
345 MAC_CHECK(check_socket_listen, cred, socket, socket->so_label);
|
341 MAC_CHECK(check_socket_listen, cred, so, so->so_label); 342 |
343 return (error); 344} 345 346int 347mac_check_socket_poll(struct ucred *cred, struct socket *so) 348{ 349 int error; 350 351 SOCK_LOCK_ASSERT(so); 352 353 MAC_CHECK(check_socket_poll, cred, so, so->so_label);
|
354 |
355 return (error); 356} 357 358int 359mac_check_socket_receive(struct ucred *cred, struct socket *so) 360{ 361 int error; 362 363 SOCK_LOCK_ASSERT(so); 364 365 MAC_CHECK(check_socket_receive, cred, so, so->so_label); 366 367 return (error); 368} 369 370static int
|
373mac_check_socket_relabel(struct ucred *cred, struct socket *socket,
|
371mac_check_socket_relabel(struct ucred *cred, struct socket *so, |
372 struct label *newlabel) 373{ 374 int error; 375
|
378 SOCK_LOCK_ASSERT(socket);
|
376 SOCK_LOCK_ASSERT(so); |
377
|
380 MAC_CHECK(check_socket_relabel, cred, socket, socket->so_label,
381 newlabel);
|
378 MAC_CHECK(check_socket_relabel, cred, so, so->so_label, newlabel); |
379 380 return (error); 381} 382 383int 384mac_check_socket_send(struct ucred *cred, struct socket *so) 385{ 386 int error; 387 388 SOCK_LOCK_ASSERT(so); 389 390 MAC_CHECK(check_socket_send, cred, so, so->so_label); 391 392 return (error); 393} 394 395int 396mac_check_socket_stat(struct ucred *cred, struct socket *so) 397{ 398 int error; 399 400 SOCK_LOCK_ASSERT(so); 401 402 MAC_CHECK(check_socket_stat, cred, so, so->so_label); 403 404 return (error); 405} 406 407int
|
411mac_check_socket_visible(struct ucred *cred, struct socket *socket)
|
408mac_check_socket_visible(struct ucred *cred, struct socket *so) |
409{ 410 int error; 411
|
415 SOCK_LOCK_ASSERT(socket);
|
412 SOCK_LOCK_ASSERT(so); |
413
|
417 MAC_CHECK(check_socket_visible, cred, socket, socket->so_label);
|
414 MAC_CHECK(check_socket_visible, cred, so, so->so_label); |
415 416 return (error); 417} 418 419int 420mac_socket_label_set(struct ucred *cred, struct socket *so, 421 struct label *label) 422{ 423 int error; 424 425 /* 426 * We acquire the socket lock when we perform the test and set, but 427 * have to release it as the pcb code needs to acquire the pcb lock, 428 * which will precede the socket lock in the lock order. However, 429 * this is fine, as any race will simply result in the inpcb being 430 * refreshed twice, but still consistently, as the inpcb code will 431 * acquire the socket lock before refreshing, holding both locks. 432 */ 433 SOCK_LOCK(so); 434 error = mac_check_socket_relabel(cred, so, label); 435 if (error) { 436 SOCK_UNLOCK(so); 437 return (error); 438 } 439 440 mac_relabel_socket(cred, so, label); 441 SOCK_UNLOCK(so); 442 443 /* 444 * If the protocol has expressed interest in socket layer changes, 445 * such as if it needs to propagate changes to a cached pcb label 446 * from the socket, notify it of the label change while holding the 447 * socket lock. 448 */ 449 if (so->so_proto->pr_usrreqs->pru_sosetlabel != NULL) 450 (so->so_proto->pr_usrreqs->pru_sosetlabel)(so); 451 452 return (0); 453} 454 455int 456mac_setsockopt_label(struct ucred *cred, struct socket *so, struct mac *mac) 457{ 458 struct label *intlabel; 459 char *buffer; 460 int error; 461 462 error = mac_check_structmac_consistent(mac); 463 if (error) 464 return (error); 465 466 buffer = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK); 467 error = copyinstr(mac->m_string, buffer, mac->m_buflen, NULL); 468 if (error) { 469 free(buffer, M_MACTEMP); 470 return (error); 471 } 472 473 intlabel = mac_socket_label_alloc(M_WAITOK); 474 error = mac_internalize_socket_label(intlabel, buffer); 475 free(buffer, M_MACTEMP); 476 if (error) 477 goto out; 478 479 error = mac_socket_label_set(cred, so, intlabel); 480out: 481 mac_socket_label_free(intlabel); 482 return (error); 483} 484 485int 486mac_getsockopt_label(struct ucred *cred, struct socket *so, struct mac *mac) 487{ 488 char *buffer, *elements; 489 struct label *intlabel; 490 int error; 491 492 error = mac_check_structmac_consistent(mac); 493 if (error) 494 return (error); 495 496 elements = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK); 497 error = copyinstr(mac->m_string, elements, mac->m_buflen, NULL); 498 if (error) { 499 free(elements, M_MACTEMP); 500 return (error); 501 } 502 503 buffer = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); 504 intlabel = mac_socket_label_alloc(M_WAITOK); 505 SOCK_LOCK(so); 506 mac_copy_socket_label(so->so_label, intlabel); 507 SOCK_UNLOCK(so); 508 error = mac_externalize_socket_label(intlabel, elements, buffer, 509 mac->m_buflen); 510 mac_socket_label_free(intlabel); 511 if (error == 0) 512 error = copyout(buffer, mac->m_string, strlen(buffer)+1); 513 514 free(buffer, M_MACTEMP); 515 free(elements, M_MACTEMP); 516 517 return (error); 518} 519 520int 521mac_getsockopt_peerlabel(struct ucred *cred, struct socket *so, 522 struct mac *mac) 523{ 524 char *elements, *buffer; 525 struct label *intlabel; 526 int error; 527 528 error = mac_check_structmac_consistent(mac); 529 if (error) 530 return (error); 531 532 elements = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK); 533 error = copyinstr(mac->m_string, elements, mac->m_buflen, NULL); 534 if (error) { 535 free(elements, M_MACTEMP); 536 return (error); 537 } 538 539 buffer = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); 540 intlabel = mac_socket_label_alloc(M_WAITOK); 541 SOCK_LOCK(so); 542 mac_copy_socket_label(so->so_peerlabel, intlabel); 543 SOCK_UNLOCK(so); 544 error = mac_externalize_socket_peer_label(intlabel, elements, buffer, 545 mac->m_buflen); 546 mac_socket_label_free(intlabel); 547 if (error == 0) 548 error = copyout(buffer, mac->m_string, strlen(buffer)+1); 549 550 free(buffer, M_MACTEMP); 551 free(elements, M_MACTEMP); 552 553 return (error); 554}
|