1/*- 2 * Copyright (c) 1999-2002 Robert N. M. Watson 3 * Copyright (c) 2001 Ilmar S. Habibulin 4 * Copyright (c) 2001-2004 Networks Associates Technology, Inc. 5 * All rights reserved. 6 * 7 * This software was developed by Robert Watson and Ilmar Habibulin for the 8 * TrustedBSD Project. 9 * 10 * This software was developed for the FreeBSD Project in part by Network 11 * Associates Laboratories, the Security Research Division of Network 12 * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), 13 * as part of the DARPA CHATS research program. 14 * 15 * Redistribution and use in source and binary forms, with or without 16 * modification, are permitted provided that the following conditions 17 * are met: 18 * 1. Redistributions of source code must retain the above copyright 19 * notice, this list of conditions and the following disclaimer. 20 * 2. Redistributions in binary form must reproduce the above copyright 21 * notice, this list of conditions and the following disclaimer in the 22 * documentation and/or other materials provided with the distribution. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 */ 36 37#include <sys/cdefs.h>
|
38__FBSDID("$FreeBSD: head/sys/security/mac/mac_net.c 165600 2006-12-28 21:57:59Z rwatson $");
|
38__FBSDID("$FreeBSD: head/sys/security/mac/mac_net.c 168955 2007-04-22 19:55:56Z rwatson $"); |
39 40#include "opt_mac.h" 41 42#include <sys/param.h> 43#include <sys/kernel.h> 44#include <sys/lock.h> 45#include <sys/malloc.h> 46#include <sys/mutex.h> 47#include <sys/mac.h> 48#include <sys/priv.h> 49#include <sys/sbuf.h> 50#include <sys/systm.h> 51#include <sys/mount.h> 52#include <sys/file.h> 53#include <sys/namei.h> 54#include <sys/protosw.h> 55#include <sys/socket.h> 56#include <sys/socketvar.h> 57#include <sys/sysctl.h> 58 59#include <net/bpfdesc.h> 60#include <net/if.h> 61#include <net/if_var.h> 62 63#include <security/mac/mac_framework.h> 64#include <security/mac/mac_internal.h> 65#include <security/mac/mac_policy.h> 66 67/* 68 * XXXRW: struct ifnet locking is incomplete in the network code, so we use 69 * our own global mutex for struct ifnet. Non-ideal, but should help in the 70 * SMP environment. 71 */ 72static struct mtx mac_ifnet_mtx; 73MTX_SYSINIT(mac_ifnet_mtx, &mac_ifnet_mtx, "mac_ifnet", MTX_DEF); 74#define MAC_IFNET_LOCK(ifp) mtx_lock(&mac_ifnet_mtx) 75#define MAC_IFNET_UNLOCK(ifp) mtx_unlock(&mac_ifnet_mtx) 76 77/* 78 * Retrieve the label associated with an mbuf by searching for the tag. 79 * Depending on the value of mac_labelmbufs, it's possible that a label will 80 * not be present, in which case NULL is returned. Policies must handle the 81 * possibility of an mbuf not having label storage if they do not enforce 82 * early loading. 83 */ 84struct label *
|
85mac_mbuf_to_label(struct mbuf *mbuf)
|
85mac_mbuf_to_label(struct mbuf *m) |
86{ 87 struct m_tag *tag; 88 struct label *label; 89
|
90 if (mbuf == NULL)
|
90 if (m == NULL) |
91 return (NULL);
|
92 tag = m_tag_find(mbuf, PACKET_TAG_MACLABEL, NULL);
|
92 tag = m_tag_find(m, PACKET_TAG_MACLABEL, NULL); |
93 if (tag == NULL) 94 return (NULL); 95 label = (struct label *)(tag+1); 96 return (label); 97} 98 99static struct label * 100mac_bpfdesc_label_alloc(void) 101{ 102 struct label *label; 103 104 label = mac_labelzone_alloc(M_WAITOK); 105 MAC_PERFORM(init_bpfdesc_label, label); 106 return (label); 107} 108 109void
|
110mac_init_bpfdesc(struct bpf_d *bpf_d)
|
110mac_init_bpfdesc(struct bpf_d *d) |
111{ 112
|
113 bpf_d->bd_label = mac_bpfdesc_label_alloc();
|
113 d->bd_label = mac_bpfdesc_label_alloc(); |
114} 115 116static struct label * 117mac_ifnet_label_alloc(void) 118{ 119 struct label *label; 120 121 label = mac_labelzone_alloc(M_WAITOK); 122 MAC_PERFORM(init_ifnet_label, label); 123 return (label); 124} 125 126void 127mac_init_ifnet(struct ifnet *ifp) 128{ 129 130 ifp->if_label = mac_ifnet_label_alloc(); 131} 132 133int 134mac_init_mbuf_tag(struct m_tag *tag, int flag) 135{ 136 struct label *label; 137 int error; 138 139 label = (struct label *) (tag + 1); 140 mac_init_label(label); 141 142 MAC_CHECK(init_mbuf_label, label, flag); 143 if (error) { 144 MAC_PERFORM(destroy_mbuf_label, label); 145 mac_destroy_label(label); 146 } 147 return (error); 148} 149 150int 151mac_init_mbuf(struct mbuf *m, int flag) 152{ 153 struct m_tag *tag; 154 int error; 155 156 M_ASSERTPKTHDR(m); 157 158#ifndef MAC_ALWAYS_LABEL_MBUF 159 /* 160 * If conditionally allocating mbuf labels, don't allocate unless 161 * they are required. 162 */ 163 if (!mac_labelmbufs) 164 return (0); 165#endif 166 tag = m_tag_get(PACKET_TAG_MACLABEL, sizeof(struct label), 167 flag); 168 if (tag == NULL) 169 return (ENOMEM); 170 error = mac_init_mbuf_tag(tag, flag); 171 if (error) { 172 m_tag_free(tag); 173 return (error); 174 } 175 m_tag_prepend(m, tag); 176 return (0); 177} 178 179static void 180mac_bpfdesc_label_free(struct label *label) 181{ 182 183 MAC_PERFORM(destroy_bpfdesc_label, label); 184 mac_labelzone_free(label); 185} 186 187void
|
188mac_destroy_bpfdesc(struct bpf_d *bpf_d)
|
188mac_destroy_bpfdesc(struct bpf_d *d) |
189{ 190
|
191 mac_bpfdesc_label_free(bpf_d->bd_label);
192 bpf_d->bd_label = NULL;
|
191 mac_bpfdesc_label_free(d->bd_label); 192 d->bd_label = NULL; |
193} 194 195static void 196mac_ifnet_label_free(struct label *label) 197{ 198 199 MAC_PERFORM(destroy_ifnet_label, label); 200 mac_labelzone_free(label); 201} 202 203void 204mac_destroy_ifnet(struct ifnet *ifp) 205{ 206 207 mac_ifnet_label_free(ifp->if_label); 208 ifp->if_label = NULL; 209} 210 211void 212mac_destroy_mbuf_tag(struct m_tag *tag) 213{ 214 struct label *label; 215 216 label = (struct label *)(tag+1); 217 218 MAC_PERFORM(destroy_mbuf_label, label); 219 mac_destroy_label(label); 220} 221 222/* 223 * mac_copy_mbuf_tag is called when an mbuf header is duplicated, in which 224 * case the labels must also be duplicated. 225 */ 226void 227mac_copy_mbuf_tag(struct m_tag *src, struct m_tag *dest) 228{ 229 struct label *src_label, *dest_label; 230 231 src_label = (struct label *)(src+1); 232 dest_label = (struct label *)(dest+1); 233 234 /* 235 * mac_init_mbuf_tag() is called on the target tag in m_tag_copy(), 236 * so we don't need to call it here. 237 */ 238 MAC_PERFORM(copy_mbuf_label, src_label, dest_label); 239} 240 241void 242mac_copy_mbuf(struct mbuf *m_from, struct mbuf *m_to) 243{ 244 struct label *src_label, *dest_label; 245 246 src_label = mac_mbuf_to_label(m_from); 247 dest_label = mac_mbuf_to_label(m_to); 248 249 MAC_PERFORM(copy_mbuf_label, src_label, dest_label); 250} 251 252static void 253mac_copy_ifnet_label(struct label *src, struct label *dest) 254{ 255 256 MAC_PERFORM(copy_ifnet_label, src, dest); 257} 258 259static int 260mac_externalize_ifnet_label(struct label *label, char *elements, 261 char *outbuf, size_t outbuflen) 262{ 263 int error; 264 265 MAC_EXTERNALIZE(ifnet, label, elements, outbuf, outbuflen); 266 267 return (error); 268} 269 270static int 271mac_internalize_ifnet_label(struct label *label, char *string) 272{ 273 int error; 274 275 MAC_INTERNALIZE(ifnet, label, string); 276 277 return (error); 278} 279 280void
|
281mac_create_ifnet(struct ifnet *ifnet)
|
281mac_create_ifnet(struct ifnet *ifp) |
282{ 283
|
284 MAC_IFNET_LOCK(ifnet);
285 MAC_PERFORM(create_ifnet, ifnet, ifnet->if_label);
286 MAC_IFNET_UNLOCK(ifnet);
|
284 MAC_IFNET_LOCK(ifp); 285 MAC_PERFORM(create_ifnet, ifp, ifp->if_label); 286 MAC_IFNET_UNLOCK(ifp); |
287} 288 289void
|
290mac_create_bpfdesc(struct ucred *cred, struct bpf_d *bpf_d)
|
290mac_create_bpfdesc(struct ucred *cred, struct bpf_d *d) |
291{ 292
|
293 MAC_PERFORM(create_bpfdesc, cred, bpf_d, bpf_d->bd_label);
|
293 MAC_PERFORM(create_bpfdesc, cred, d, d->bd_label); |
294} 295 296void
|
297mac_create_mbuf_from_bpfdesc(struct bpf_d *bpf_d, struct mbuf *mbuf)
|
297mac_create_mbuf_from_bpfdesc(struct bpf_d *d, struct mbuf *m) |
298{ 299 struct label *label; 300
|
301 BPFD_LOCK_ASSERT(bpf_d);
|
301 BPFD_LOCK_ASSERT(d); |
302
|
303 label = mac_mbuf_to_label(mbuf);
|
303 label = mac_mbuf_to_label(m); |
304
|
305 MAC_PERFORM(create_mbuf_from_bpfdesc, bpf_d, bpf_d->bd_label, mbuf,
306 label);
|
305 MAC_PERFORM(create_mbuf_from_bpfdesc, d, d->bd_label, m, label); |
306} 307 308void
|
310mac_create_mbuf_linklayer(struct ifnet *ifnet, struct mbuf *mbuf)
|
309mac_create_mbuf_linklayer(struct ifnet *ifp, struct mbuf *m) |
310{ 311 struct label *label; 312
|
314 label = mac_mbuf_to_label(mbuf);
|
313 label = mac_mbuf_to_label(m); |
314
|
316 MAC_IFNET_LOCK(ifnet);
317 MAC_PERFORM(create_mbuf_linklayer, ifnet, ifnet->if_label, mbuf,
318 label);
319 MAC_IFNET_UNLOCK(ifnet);
|
315 MAC_IFNET_LOCK(ifp); 316 MAC_PERFORM(create_mbuf_linklayer, ifp, ifp->if_label, m, label); 317 MAC_IFNET_UNLOCK(ifp); |
318} 319 320void
|
323mac_create_mbuf_from_ifnet(struct ifnet *ifnet, struct mbuf *mbuf)
|
321mac_create_mbuf_from_ifnet(struct ifnet *ifp, struct mbuf *m) |
322{ 323 struct label *label; 324
|
327 label = mac_mbuf_to_label(mbuf);
|
325 label = mac_mbuf_to_label(m); |
326
|
329 MAC_IFNET_LOCK(ifnet);
330 MAC_PERFORM(create_mbuf_from_ifnet, ifnet, ifnet->if_label, mbuf,
331 label);
332 MAC_IFNET_UNLOCK(ifnet);
|
327 MAC_IFNET_LOCK(ifp); 328 MAC_PERFORM(create_mbuf_from_ifnet, ifp, ifp->if_label, m, label); 329 MAC_IFNET_UNLOCK(ifp); |
330} 331 332void
|
336mac_create_mbuf_multicast_encap(struct mbuf *oldmbuf, struct ifnet *ifnet,
337 struct mbuf *newmbuf)
|
333mac_create_mbuf_multicast_encap(struct mbuf *m, struct ifnet *ifp, 334 struct mbuf *mnew) |
335{
|
339 struct label *oldmbuflabel, *newmbuflabel;
|
336 struct label *mlabel, *mnewlabel; |
337
|
341 oldmbuflabel = mac_mbuf_to_label(oldmbuf);
342 newmbuflabel = mac_mbuf_to_label(newmbuf);
|
338 mlabel = mac_mbuf_to_label(m); 339 mnewlabel = mac_mbuf_to_label(mnew); |
340
|
344 MAC_IFNET_LOCK(ifnet);
345 MAC_PERFORM(create_mbuf_multicast_encap, oldmbuf, oldmbuflabel,
346 ifnet, ifnet->if_label, newmbuf, newmbuflabel);
347 MAC_IFNET_UNLOCK(ifnet);
|
341 MAC_IFNET_LOCK(ifp); 342 MAC_PERFORM(create_mbuf_multicast_encap, m, mlabel, ifp, 343 ifp->if_label, mnew, mnewlabel); 344 MAC_IFNET_UNLOCK(ifp); |
345} 346 347void
|
351mac_create_mbuf_netlayer(struct mbuf *oldmbuf, struct mbuf *newmbuf)
|
348mac_create_mbuf_netlayer(struct mbuf *m, struct mbuf *mnew) |
349{
|
353 struct label *oldmbuflabel, *newmbuflabel;
|
350 struct label *mlabel, *mnewlabel; |
351
|
355 oldmbuflabel = mac_mbuf_to_label(oldmbuf);
356 newmbuflabel = mac_mbuf_to_label(newmbuf);
|
352 mlabel = mac_mbuf_to_label(m); 353 mnewlabel = mac_mbuf_to_label(mnew); |
354
|
358 MAC_PERFORM(create_mbuf_netlayer, oldmbuf, oldmbuflabel, newmbuf,
359 newmbuflabel);
|
355 MAC_PERFORM(create_mbuf_netlayer, m, mlabel, mnew, mnewlabel); |
356} 357 358int
|
363mac_check_bpfdesc_receive(struct bpf_d *bpf_d, struct ifnet *ifnet)
|
359mac_check_bpfdesc_receive(struct bpf_d *d, struct ifnet *ifp) |
360{ 361 int error; 362
|
367 BPFD_LOCK_ASSERT(bpf_d);
|
363 BPFD_LOCK_ASSERT(d); |
364
|
369 MAC_IFNET_LOCK(ifnet);
370 MAC_CHECK(check_bpfdesc_receive, bpf_d, bpf_d->bd_label, ifnet,
371 ifnet->if_label);
372 MAC_IFNET_UNLOCK(ifnet);
|
365 MAC_IFNET_LOCK(ifp); 366 MAC_CHECK(check_bpfdesc_receive, d, d->bd_label, ifp, ifp->if_label); 367 MAC_IFNET_UNLOCK(ifp); |
368 369 return (error); 370} 371 372int
|
378mac_check_ifnet_transmit(struct ifnet *ifnet, struct mbuf *mbuf)
|
373mac_check_ifnet_transmit(struct ifnet *ifp, struct mbuf *m) |
374{ 375 struct label *label; 376 int error; 377
|
383 M_ASSERTPKTHDR(mbuf);
|
378 M_ASSERTPKTHDR(m); |
379
|
385 label = mac_mbuf_to_label(mbuf);
|
380 label = mac_mbuf_to_label(m); |
381
|
387 MAC_IFNET_LOCK(ifnet);
388 MAC_CHECK(check_ifnet_transmit, ifnet, ifnet->if_label, mbuf,
389 label);
390 MAC_IFNET_UNLOCK(ifnet);
|
382 MAC_IFNET_LOCK(ifp); 383 MAC_CHECK(check_ifnet_transmit, ifp, ifp->if_label, m, label); 384 MAC_IFNET_UNLOCK(ifp); |
385 386 return (error); 387} 388 389int 390mac_ioctl_ifnet_get(struct ucred *cred, struct ifreq *ifr,
|
397 struct ifnet *ifnet)
|
391 struct ifnet *ifp) |
392{ 393 char *elements, *buffer; 394 struct label *intlabel; 395 struct mac mac; 396 int error; 397 398 error = copyin(ifr->ifr_ifru.ifru_data, &mac, sizeof(mac)); 399 if (error) 400 return (error); 401 402 error = mac_check_structmac_consistent(&mac); 403 if (error) 404 return (error); 405 406 elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 407 error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL); 408 if (error) { 409 free(elements, M_MACTEMP); 410 return (error); 411 } 412 413 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); 414 intlabel = mac_ifnet_label_alloc();
|
421 MAC_IFNET_LOCK(ifnet);
422 mac_copy_ifnet_label(ifnet->if_label, intlabel);
423 MAC_IFNET_UNLOCK(ifnet);
|
415 MAC_IFNET_LOCK(ifp); 416 mac_copy_ifnet_label(ifp->if_label, intlabel); 417 MAC_IFNET_UNLOCK(ifp); |
418 error = mac_externalize_ifnet_label(intlabel, elements, buffer, 419 mac.m_buflen); 420 mac_ifnet_label_free(intlabel); 421 if (error == 0) 422 error = copyout(buffer, mac.m_string, strlen(buffer)+1); 423 424 free(buffer, M_MACTEMP); 425 free(elements, M_MACTEMP); 426 427 return (error); 428} 429 430int
|
437mac_ioctl_ifnet_set(struct ucred *cred, struct ifreq *ifr,
438 struct ifnet *ifnet)
|
431mac_ioctl_ifnet_set(struct ucred *cred, struct ifreq *ifr, struct ifnet *ifp) |
432{ 433 struct label *intlabel; 434 struct mac mac; 435 char *buffer; 436 int error; 437 438 error = copyin(ifr->ifr_ifru.ifru_data, &mac, sizeof(mac)); 439 if (error) 440 return (error); 441 442 error = mac_check_structmac_consistent(&mac); 443 if (error) 444 return (error); 445 446 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 447 error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL); 448 if (error) { 449 free(buffer, M_MACTEMP); 450 return (error); 451 } 452 453 intlabel = mac_ifnet_label_alloc(); 454 error = mac_internalize_ifnet_label(intlabel, buffer); 455 free(buffer, M_MACTEMP); 456 if (error) { 457 mac_ifnet_label_free(intlabel); 458 return (error); 459 } 460 461 /* 462 * XXX: Note that this is a redundant privilege check, since policies 463 * impose this check themselves if required by the policy 464 * Eventually, this should go away. 465 */ 466 error = priv_check_cred(cred, PRIV_NET_SETIFMAC, 0); 467 if (error) { 468 mac_ifnet_label_free(intlabel); 469 return (error); 470 } 471
|
479 MAC_IFNET_LOCK(ifnet);
480 MAC_CHECK(check_ifnet_relabel, cred, ifnet, ifnet->if_label,
481 intlabel);
|
472 MAC_IFNET_LOCK(ifp); 473 MAC_CHECK(check_ifnet_relabel, cred, ifp, ifp->if_label, intlabel); |
474 if (error) {
|
483 MAC_IFNET_UNLOCK(ifnet);
|
475 MAC_IFNET_UNLOCK(ifp); |
476 mac_ifnet_label_free(intlabel); 477 return (error); 478 } 479
|
488 MAC_PERFORM(relabel_ifnet, cred, ifnet, ifnet->if_label, intlabel);
489 MAC_IFNET_UNLOCK(ifnet);
|
480 MAC_PERFORM(relabel_ifnet, cred, ifp, ifp->if_label, intlabel); 481 MAC_IFNET_UNLOCK(ifp); |
482 483 mac_ifnet_label_free(intlabel); 484 return (0); 485}
|