1c66b4d8dSRobert Watson /*- 22087a58cSRobert Watson * Copyright (c) 1999-2002, 2009 Robert N. M. Watson 3c66b4d8dSRobert Watson * Copyright (c) 2001 Ilmar S. Habibulin 47f53207bSRobert Watson * Copyright (c) 2001-2005 Networks Associates Technology, Inc. 530d239bcSRobert Watson * Copyright (c) 2005-2006 SPARTA, Inc. 66356dba0SRobert Watson * Copyright (c) 2008 Apple Inc. 7c66b4d8dSRobert Watson * All rights reserved. 8c66b4d8dSRobert Watson * 9c66b4d8dSRobert Watson * This software was developed by Robert Watson and Ilmar Habibulin for the 10c66b4d8dSRobert Watson * TrustedBSD Project. 11c66b4d8dSRobert Watson * 127f53207bSRobert Watson * This software was developed for the FreeBSD Project in part by McAfee 137f53207bSRobert Watson * Research, the Technology Research Division of Network Associates, Inc. 147f53207bSRobert Watson * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the 157f53207bSRobert Watson * DARPA CHATS research program. 16c66b4d8dSRobert Watson * 176758f88eSRobert Watson * This software was enhanced by SPARTA ISSO under SPAWAR contract 186758f88eSRobert Watson * N66001-04-C-6019 ("SEFOS"). 196758f88eSRobert Watson * 202087a58cSRobert Watson * This software was developed at the University of Cambridge Computer 212087a58cSRobert Watson * Laboratory with support from a grant from Google, Inc. 222087a58cSRobert Watson * 23c66b4d8dSRobert Watson * Redistribution and use in source and binary forms, with or without 24c66b4d8dSRobert Watson * modification, are permitted provided that the following conditions 25c66b4d8dSRobert Watson * are met: 26c66b4d8dSRobert Watson * 1. Redistributions of source code must retain the above copyright 27c66b4d8dSRobert Watson * notice, this list of conditions and the following disclaimer. 28c66b4d8dSRobert Watson * 2. Redistributions in binary form must reproduce the above copyright 29c66b4d8dSRobert Watson * notice, this list of conditions and the following disclaimer in the 30c66b4d8dSRobert Watson * documentation and/or other materials provided with the distribution. 31c66b4d8dSRobert Watson * 32c66b4d8dSRobert Watson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 33c66b4d8dSRobert Watson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 34c66b4d8dSRobert Watson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 35c66b4d8dSRobert Watson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 36c66b4d8dSRobert Watson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 37c66b4d8dSRobert Watson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 38c66b4d8dSRobert Watson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 39c66b4d8dSRobert Watson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 40c66b4d8dSRobert Watson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 41c66b4d8dSRobert Watson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 42c66b4d8dSRobert Watson * SUCH DAMAGE. 43c66b4d8dSRobert Watson */ 44c66b4d8dSRobert Watson 45c66b4d8dSRobert Watson #include <sys/cdefs.h> 46c66b4d8dSRobert Watson __FBSDID("$FreeBSD$"); 47c66b4d8dSRobert Watson 482087a58cSRobert Watson #include "opt_kdtrace.h" 49c66b4d8dSRobert Watson #include "opt_mac.h" 50c66b4d8dSRobert Watson 51c66b4d8dSRobert Watson #include <sys/param.h> 52c66b4d8dSRobert Watson #include <sys/kernel.h> 53c66b4d8dSRobert Watson #include <sys/lock.h> 54c66b4d8dSRobert Watson #include <sys/malloc.h> 55c66b4d8dSRobert Watson #include <sys/mutex.h> 56c66b4d8dSRobert Watson #include <sys/mac.h> 57c66b4d8dSRobert Watson #include <sys/sbuf.h> 582087a58cSRobert Watson #include <sys/sdt.h> 59c66b4d8dSRobert Watson #include <sys/systm.h> 60c66b4d8dSRobert Watson #include <sys/mount.h> 61c66b4d8dSRobert Watson #include <sys/file.h> 62c66b4d8dSRobert Watson #include <sys/namei.h> 63c66b4d8dSRobert Watson #include <sys/protosw.h> 64c66b4d8dSRobert Watson #include <sys/socket.h> 65c66b4d8dSRobert Watson #include <sys/socketvar.h> 66c66b4d8dSRobert Watson #include <sys/sysctl.h> 67c66b4d8dSRobert Watson 68c66b4d8dSRobert Watson #include <net/bpfdesc.h> 69c66b4d8dSRobert Watson #include <net/if.h> 70c66b4d8dSRobert Watson #include <net/if_var.h> 71c66b4d8dSRobert Watson 72c66b4d8dSRobert Watson #include <netinet/in.h> 73c66b4d8dSRobert Watson #include <netinet/in_pcb.h> 74c66b4d8dSRobert Watson #include <netinet/ip_var.h> 75c66b4d8dSRobert Watson 76aed55708SRobert Watson #include <security/mac/mac_framework.h> 77c66b4d8dSRobert Watson #include <security/mac/mac_internal.h> 780efd6615SRobert Watson #include <security/mac/mac_policy.h> 79c66b4d8dSRobert Watson 80c66b4d8dSRobert Watson /* 81df3c68e4SRobert Watson * Currently, sockets hold two labels: the label of the socket itself, and a 82df3c68e4SRobert Watson * peer label, which may be used by policies to hold a copy of the label of 83df3c68e4SRobert Watson * any remote endpoint. 84df3c68e4SRobert Watson * 85df3c68e4SRobert Watson * Possibly, this peer label should be maintained at the protocol layer 86df3c68e4SRobert Watson * (inpcb, unpcb, etc), as this would allow protocol-aware code to maintain 87df3c68e4SRobert Watson * the label consistently. For example, it might be copied live from a 88df3c68e4SRobert Watson * remote socket for UNIX domain sockets rather than keeping a local copy on 89df3c68e4SRobert Watson * this endpoint, but be cached and updated based on packets received for 90df3c68e4SRobert Watson * TCP/IP. 91df3c68e4SRobert Watson */ 92df3c68e4SRobert Watson 93c66b4d8dSRobert Watson struct label * 94c66b4d8dSRobert Watson mac_socket_label_alloc(int flag) 95c66b4d8dSRobert Watson { 96c66b4d8dSRobert Watson struct label *label; 97c66b4d8dSRobert Watson int error; 98c66b4d8dSRobert Watson 99c66b4d8dSRobert Watson label = mac_labelzone_alloc(flag); 100c66b4d8dSRobert Watson if (label == NULL) 101c66b4d8dSRobert Watson return (NULL); 102c66b4d8dSRobert Watson 10340202729SRobert Watson if (flag & M_WAITOK) 104fa765671SRobert Watson MAC_POLICY_CHECK(socket_init_label, label, flag); 10540202729SRobert Watson else 106fa765671SRobert Watson MAC_POLICY_CHECK_NOSLEEP(socket_init_label, label, flag); 107c66b4d8dSRobert Watson if (error) { 108fa765671SRobert Watson MAC_POLICY_PERFORM_NOSLEEP(socket_destroy_label, label); 109c66b4d8dSRobert Watson mac_labelzone_free(label); 110c66b4d8dSRobert Watson return (NULL); 111c66b4d8dSRobert Watson } 112c66b4d8dSRobert Watson return (label); 113c66b4d8dSRobert Watson } 114c66b4d8dSRobert Watson 115c66b4d8dSRobert Watson static struct label * 11630d239bcSRobert Watson mac_socketpeer_label_alloc(int flag) 117c66b4d8dSRobert Watson { 118c66b4d8dSRobert Watson struct label *label; 119c66b4d8dSRobert Watson int error; 120c66b4d8dSRobert Watson 121c66b4d8dSRobert Watson label = mac_labelzone_alloc(flag); 122c66b4d8dSRobert Watson if (label == NULL) 123c66b4d8dSRobert Watson return (NULL); 124c66b4d8dSRobert Watson 12540202729SRobert Watson if (flag & M_WAITOK) 126fa765671SRobert Watson MAC_POLICY_CHECK(socketpeer_init_label, label, flag); 12740202729SRobert Watson else 128fa765671SRobert Watson MAC_POLICY_CHECK_NOSLEEP(socketpeer_init_label, label, flag); 129c66b4d8dSRobert Watson if (error) { 130fa765671SRobert Watson MAC_POLICY_PERFORM_NOSLEEP(socketpeer_destroy_label, label); 131c66b4d8dSRobert Watson mac_labelzone_free(label); 132c66b4d8dSRobert Watson return (NULL); 133c66b4d8dSRobert Watson } 134c66b4d8dSRobert Watson return (label); 135c66b4d8dSRobert Watson } 136c66b4d8dSRobert Watson 137c66b4d8dSRobert Watson int 13830d239bcSRobert Watson mac_socket_init(struct socket *so, int flag) 139c66b4d8dSRobert Watson { 140c66b4d8dSRobert Watson 1416356dba0SRobert Watson if (mac_labeled & MPC_OBJECT_SOCKET) { 142c66b4d8dSRobert Watson so->so_label = mac_socket_label_alloc(flag); 143c66b4d8dSRobert Watson if (so->so_label == NULL) 144c66b4d8dSRobert Watson return (ENOMEM); 14530d239bcSRobert Watson so->so_peerlabel = mac_socketpeer_label_alloc(flag); 146c66b4d8dSRobert Watson if (so->so_peerlabel == NULL) { 147c66b4d8dSRobert Watson mac_socket_label_free(so->so_label); 148c66b4d8dSRobert Watson so->so_label = NULL; 149c66b4d8dSRobert Watson return (ENOMEM); 150c66b4d8dSRobert Watson } 1516356dba0SRobert Watson } else { 1526356dba0SRobert Watson so->so_label = NULL; 1536356dba0SRobert Watson so->so_peerlabel = NULL; 1546356dba0SRobert Watson } 155c66b4d8dSRobert Watson return (0); 156c66b4d8dSRobert Watson } 157c66b4d8dSRobert Watson 158c66b4d8dSRobert Watson void 159c66b4d8dSRobert Watson mac_socket_label_free(struct label *label) 160c66b4d8dSRobert Watson { 161c66b4d8dSRobert Watson 162fa765671SRobert Watson MAC_POLICY_PERFORM_NOSLEEP(socket_destroy_label, label); 163c66b4d8dSRobert Watson mac_labelzone_free(label); 164c66b4d8dSRobert Watson } 165c66b4d8dSRobert Watson 166c66b4d8dSRobert Watson static void 16730d239bcSRobert Watson mac_socketpeer_label_free(struct label *label) 168c66b4d8dSRobert Watson { 169c66b4d8dSRobert Watson 170fa765671SRobert Watson MAC_POLICY_PERFORM_NOSLEEP(socketpeer_destroy_label, label); 171c66b4d8dSRobert Watson mac_labelzone_free(label); 172c66b4d8dSRobert Watson } 173c66b4d8dSRobert Watson 174c66b4d8dSRobert Watson void 17530d239bcSRobert Watson mac_socket_destroy(struct socket *so) 176c66b4d8dSRobert Watson { 177c66b4d8dSRobert Watson 1786356dba0SRobert Watson if (so->so_label != NULL) { 17926ae2b86SRobert Watson mac_socket_label_free(so->so_label); 18026ae2b86SRobert Watson so->so_label = NULL; 18130d239bcSRobert Watson mac_socketpeer_label_free(so->so_peerlabel); 18226ae2b86SRobert Watson so->so_peerlabel = NULL; 183c66b4d8dSRobert Watson } 1846356dba0SRobert Watson } 185c66b4d8dSRobert Watson 186c66b4d8dSRobert Watson void 18730d239bcSRobert Watson mac_socket_copy_label(struct label *src, struct label *dest) 188c66b4d8dSRobert Watson { 189c66b4d8dSRobert Watson 190fa765671SRobert Watson MAC_POLICY_PERFORM_NOSLEEP(socket_copy_label, src, dest); 191c66b4d8dSRobert Watson } 192c66b4d8dSRobert Watson 193c66b4d8dSRobert Watson int 19430d239bcSRobert Watson mac_socket_externalize_label(struct label *label, char *elements, 195c66b4d8dSRobert Watson char *outbuf, size_t outbuflen) 196c66b4d8dSRobert Watson { 197c66b4d8dSRobert Watson int error; 198c66b4d8dSRobert Watson 199fa765671SRobert Watson MAC_POLICY_EXTERNALIZE(socket, label, elements, outbuf, outbuflen); 200c66b4d8dSRobert Watson 201c66b4d8dSRobert Watson return (error); 202c66b4d8dSRobert Watson } 203c66b4d8dSRobert Watson 204c66b4d8dSRobert Watson static int 20530d239bcSRobert Watson mac_socketpeer_externalize_label(struct label *label, char *elements, 206c66b4d8dSRobert Watson char *outbuf, size_t outbuflen) 207c66b4d8dSRobert Watson { 208c66b4d8dSRobert Watson int error; 209c66b4d8dSRobert Watson 210fa765671SRobert Watson MAC_POLICY_EXTERNALIZE(socketpeer, label, elements, outbuf, 211fa765671SRobert Watson outbuflen); 212c66b4d8dSRobert Watson 213c66b4d8dSRobert Watson return (error); 214c66b4d8dSRobert Watson } 215c66b4d8dSRobert Watson 216c66b4d8dSRobert Watson int 21730d239bcSRobert Watson mac_socket_internalize_label(struct label *label, char *string) 218c66b4d8dSRobert Watson { 219c66b4d8dSRobert Watson int error; 220c66b4d8dSRobert Watson 221fa765671SRobert Watson MAC_POLICY_INTERNALIZE(socket, label, string); 222c66b4d8dSRobert Watson 223c66b4d8dSRobert Watson return (error); 224c66b4d8dSRobert Watson } 225c66b4d8dSRobert Watson 226c66b4d8dSRobert Watson void 22730d239bcSRobert Watson mac_socket_create(struct ucred *cred, struct socket *so) 228c66b4d8dSRobert Watson { 229c66b4d8dSRobert Watson 230fa765671SRobert Watson MAC_POLICY_PERFORM_NOSLEEP(socket_create, cred, so, so->so_label); 231c66b4d8dSRobert Watson } 232c66b4d8dSRobert Watson 233c66b4d8dSRobert Watson void 23430d239bcSRobert Watson mac_socket_newconn(struct socket *oldso, struct socket *newso) 235c66b4d8dSRobert Watson { 236c66b4d8dSRobert Watson 237f93bfb23SRobert Watson if (mac_policy_count == 0) 238f93bfb23SRobert Watson return; 23926ae2b86SRobert Watson 240f93bfb23SRobert Watson SOCK_LOCK(oldso); 241fa765671SRobert Watson MAC_POLICY_PERFORM_NOSLEEP(socket_newconn, oldso, oldso->so_label, 242fa765671SRobert Watson newso, newso->so_label); 243f93bfb23SRobert Watson SOCK_UNLOCK(oldso); 244c66b4d8dSRobert Watson } 245c66b4d8dSRobert Watson 246c66b4d8dSRobert Watson static void 24730d239bcSRobert Watson mac_socket_relabel(struct ucred *cred, struct socket *so, 248c66b4d8dSRobert Watson struct label *newlabel) 249c66b4d8dSRobert Watson { 250c66b4d8dSRobert Watson 25126ae2b86SRobert Watson SOCK_LOCK_ASSERT(so); 25226ae2b86SRobert Watson 253fa765671SRobert Watson MAC_POLICY_PERFORM_NOSLEEP(socket_relabel, cred, so, so->so_label, 25440202729SRobert Watson newlabel); 255c66b4d8dSRobert Watson } 256c66b4d8dSRobert Watson 257c66b4d8dSRobert Watson void 25830d239bcSRobert Watson mac_socketpeer_set_from_mbuf(struct mbuf *m, struct socket *so) 259c66b4d8dSRobert Watson { 260c66b4d8dSRobert Watson struct label *label; 261c66b4d8dSRobert Watson 26226ae2b86SRobert Watson label = mac_mbuf_to_label(m); 263c66b4d8dSRobert Watson 264f93bfb23SRobert Watson SOCK_LOCK(so); 265fa765671SRobert Watson MAC_POLICY_PERFORM_NOSLEEP(socketpeer_set_from_mbuf, m, label, so, 26626ae2b86SRobert Watson so->so_peerlabel); 267f93bfb23SRobert Watson SOCK_UNLOCK(so); 268c66b4d8dSRobert Watson } 269c66b4d8dSRobert Watson 270c66b4d8dSRobert Watson void 27130d239bcSRobert Watson mac_socketpeer_set_from_socket(struct socket *oldso, struct socket *newso) 272c66b4d8dSRobert Watson { 273c66b4d8dSRobert Watson 274f93bfb23SRobert Watson if (mac_policy_count == 0) 275f93bfb23SRobert Watson return; 276f93bfb23SRobert Watson 277310e7cebSRobert Watson /* 278f93bfb23SRobert Watson * XXXRW: We want to hold locks on both sockets, but can't currently 279f93bfb23SRobert Watson * due to lock order -- opt to lock the socket where we're accessing 280f93bfb23SRobert Watson * so_label as it's more likely to change. 281310e7cebSRobert Watson */ 282f93bfb23SRobert Watson SOCK_LOCK(oldso); 283fa765671SRobert Watson MAC_POLICY_PERFORM_NOSLEEP(socketpeer_set_from_socket, oldso, 28440202729SRobert Watson oldso->so_label, newso, newso->so_peerlabel); 285f93bfb23SRobert Watson SOCK_UNLOCK(oldso); 286c66b4d8dSRobert Watson } 287c66b4d8dSRobert Watson 288c66b4d8dSRobert Watson void 28930d239bcSRobert Watson mac_socket_create_mbuf(struct socket *so, struct mbuf *m) 290c66b4d8dSRobert Watson { 291c66b4d8dSRobert Watson struct label *label; 292c66b4d8dSRobert Watson 293f93bfb23SRobert Watson if (mac_policy_count == 0) 294f93bfb23SRobert Watson return; 295c66b4d8dSRobert Watson 29626ae2b86SRobert Watson label = mac_mbuf_to_label(m); 29726ae2b86SRobert Watson 298f93bfb23SRobert Watson SOCK_LOCK(so); 299fa765671SRobert Watson MAC_POLICY_PERFORM_NOSLEEP(socket_create_mbuf, so, so->so_label, m, 300fa765671SRobert Watson label); 301f93bfb23SRobert Watson SOCK_UNLOCK(so); 302c66b4d8dSRobert Watson } 303c66b4d8dSRobert Watson 3042087a58cSRobert Watson MAC_CHECK_PROBE_DEFINE2(socket_check_accept, "struct ucred *", 3052087a58cSRobert Watson "struct socket *"); 3062087a58cSRobert Watson 307c66b4d8dSRobert Watson int 30830d239bcSRobert Watson mac_socket_check_accept(struct ucred *cred, struct socket *so) 3097f53207bSRobert Watson { 3107f53207bSRobert Watson int error; 3117f53207bSRobert Watson 312f93bfb23SRobert Watson if (mac_policy_count == 0) 313f93bfb23SRobert Watson return (0); 3147f53207bSRobert Watson 315f93bfb23SRobert Watson SOCK_LOCK(so); 316fa765671SRobert Watson MAC_POLICY_CHECK_NOSLEEP(socket_check_accept, cred, so, 317fa765671SRobert Watson so->so_label); 3182087a58cSRobert Watson MAC_CHECK_PROBE2(socket_check_accept, error, cred, so); 319f93bfb23SRobert Watson SOCK_UNLOCK(so); 3207f53207bSRobert Watson 3217f53207bSRobert Watson return (error); 3227f53207bSRobert Watson } 3237f53207bSRobert Watson 3242087a58cSRobert Watson MAC_CHECK_PROBE_DEFINE3(socket_check_bind, "struct ucred *", 3252087a58cSRobert Watson "struct socket *", "struct sockaddr *"); 3262087a58cSRobert Watson 3277f53207bSRobert Watson int 328c14172e3SRobert Watson mac_socket_check_bind(struct ucred *cred, struct socket *so, 32926ae2b86SRobert Watson struct sockaddr *sa) 330c66b4d8dSRobert Watson { 331c66b4d8dSRobert Watson int error; 332c66b4d8dSRobert Watson 333f93bfb23SRobert Watson if (mac_policy_count == 0) 334f93bfb23SRobert Watson return (0); 335310e7cebSRobert Watson 336f93bfb23SRobert Watson SOCK_LOCK(so); 337fa765671SRobert Watson MAC_POLICY_CHECK_NOSLEEP(socket_check_bind, cred, so, so->so_label, 338fa765671SRobert Watson sa); 339c14172e3SRobert Watson MAC_CHECK_PROBE3(socket_check_bind, error, cred, so, sa); 340f93bfb23SRobert Watson SOCK_UNLOCK(so); 341c66b4d8dSRobert Watson 342c66b4d8dSRobert Watson return (error); 343c66b4d8dSRobert Watson } 344c66b4d8dSRobert Watson 3452087a58cSRobert Watson MAC_CHECK_PROBE_DEFINE3(socket_check_connect, "struct ucred *", 3462087a58cSRobert Watson "struct socket *", "struct sockaddr *"); 3472087a58cSRobert Watson 348c66b4d8dSRobert Watson int 34930d239bcSRobert Watson mac_socket_check_connect(struct ucred *cred, struct socket *so, 35026ae2b86SRobert Watson struct sockaddr *sa) 351c66b4d8dSRobert Watson { 352c66b4d8dSRobert Watson int error; 353c66b4d8dSRobert Watson 354f93bfb23SRobert Watson if (mac_policy_count == 0) 355f93bfb23SRobert Watson return (0); 356310e7cebSRobert Watson 357f93bfb23SRobert Watson SOCK_LOCK(so); 358fa765671SRobert Watson MAC_POLICY_CHECK_NOSLEEP(socket_check_connect, cred, so, 359fa765671SRobert Watson so->so_label, sa); 3602087a58cSRobert Watson MAC_CHECK_PROBE3(socket_check_connect, error, cred, so, sa); 361f93bfb23SRobert Watson SOCK_UNLOCK(so); 362c66b4d8dSRobert Watson 363c66b4d8dSRobert Watson return (error); 364c66b4d8dSRobert Watson } 365c66b4d8dSRobert Watson 3662087a58cSRobert Watson MAC_CHECK_PROBE_DEFINE4(socket_check_create, "struct ucred *", "int", "int", 3672087a58cSRobert Watson "int"); 3682087a58cSRobert Watson 369c66b4d8dSRobert Watson int 37030d239bcSRobert Watson mac_socket_check_create(struct ucred *cred, int domain, int type, int proto) 3716758f88eSRobert Watson { 3726758f88eSRobert Watson int error; 3736758f88eSRobert Watson 374fa765671SRobert Watson MAC_POLICY_CHECK_NOSLEEP(socket_check_create, cred, domain, type, 375fa765671SRobert Watson proto); 3762087a58cSRobert Watson MAC_CHECK_PROBE4(socket_check_create, error, cred, domain, type, 3772087a58cSRobert Watson proto); 3786758f88eSRobert Watson 3796758f88eSRobert Watson return (error); 3806758f88eSRobert Watson } 3816758f88eSRobert Watson 3822087a58cSRobert Watson MAC_CHECK_PROBE_DEFINE2(socket_check_deliver, "struct socket *", 3832087a58cSRobert Watson "struct mbuf *"); 3842087a58cSRobert Watson 3856758f88eSRobert Watson int 38630d239bcSRobert Watson mac_socket_check_deliver(struct socket *so, struct mbuf *m) 387c66b4d8dSRobert Watson { 388c66b4d8dSRobert Watson struct label *label; 389c66b4d8dSRobert Watson int error; 390c66b4d8dSRobert Watson 391f93bfb23SRobert Watson if (mac_policy_count == 0) 392f93bfb23SRobert Watson return (0); 393310e7cebSRobert Watson 39426ae2b86SRobert Watson label = mac_mbuf_to_label(m); 395c66b4d8dSRobert Watson 396f93bfb23SRobert Watson SOCK_LOCK(so); 397fa765671SRobert Watson MAC_POLICY_CHECK_NOSLEEP(socket_check_deliver, so, so->so_label, m, 398fa765671SRobert Watson label); 3992087a58cSRobert Watson MAC_CHECK_PROBE2(socket_check_deliver, error, so, m); 400f93bfb23SRobert Watson SOCK_UNLOCK(so); 401c66b4d8dSRobert Watson 402c66b4d8dSRobert Watson return (error); 403c66b4d8dSRobert Watson } 404c66b4d8dSRobert Watson 4052087a58cSRobert Watson MAC_CHECK_PROBE_DEFINE2(socket_check_listen, "struct ucred *", 4062087a58cSRobert Watson "struct socket *"); 4072087a58cSRobert Watson 408c66b4d8dSRobert Watson int 40930d239bcSRobert Watson mac_socket_check_listen(struct ucred *cred, struct socket *so) 410c66b4d8dSRobert Watson { 411c66b4d8dSRobert Watson int error; 412c66b4d8dSRobert Watson 413f93bfb23SRobert Watson if (mac_policy_count == 0) 414f93bfb23SRobert Watson return (0); 415310e7cebSRobert Watson 416f93bfb23SRobert Watson SOCK_LOCK(so); 417fa765671SRobert Watson MAC_POLICY_CHECK_NOSLEEP(socket_check_listen, cred, so, 418fa765671SRobert Watson so->so_label); 4192087a58cSRobert Watson MAC_CHECK_PROBE2(socket_check_listen, error, cred, so); 420f93bfb23SRobert Watson SOCK_UNLOCK(so); 42126ae2b86SRobert Watson 422c66b4d8dSRobert Watson return (error); 423c66b4d8dSRobert Watson } 424c66b4d8dSRobert Watson 4252087a58cSRobert Watson MAC_CHECK_PROBE_DEFINE2(socket_check_poll, "struct ucred *", 4262087a58cSRobert Watson "struct socket *"); 4272087a58cSRobert Watson 428c66b4d8dSRobert Watson int 42930d239bcSRobert Watson mac_socket_check_poll(struct ucred *cred, struct socket *so) 4307f53207bSRobert Watson { 4317f53207bSRobert Watson int error; 4327f53207bSRobert Watson 433f93bfb23SRobert Watson if (mac_policy_count == 0) 434f93bfb23SRobert Watson return (0); 4357f53207bSRobert Watson 436f93bfb23SRobert Watson SOCK_LOCK(so); 437fa765671SRobert Watson MAC_POLICY_CHECK_NOSLEEP(socket_check_poll, cred, so, so->so_label); 4382087a58cSRobert Watson MAC_CHECK_PROBE2(socket_check_poll, error, cred, so); 439f93bfb23SRobert Watson SOCK_UNLOCK(so); 44026ae2b86SRobert Watson 4417f53207bSRobert Watson return (error); 4427f53207bSRobert Watson } 4437f53207bSRobert Watson 4442087a58cSRobert Watson MAC_CHECK_PROBE_DEFINE2(socket_check_receive, "struct ucred *", 4452087a58cSRobert Watson "struct socket *"); 4462087a58cSRobert Watson 4477f53207bSRobert Watson int 44830d239bcSRobert Watson mac_socket_check_receive(struct ucred *cred, struct socket *so) 449c66b4d8dSRobert Watson { 450c66b4d8dSRobert Watson int error; 451c66b4d8dSRobert Watson 452f93bfb23SRobert Watson if (mac_policy_count == 0) 453f93bfb23SRobert Watson return (0); 454310e7cebSRobert Watson 455f93bfb23SRobert Watson SOCK_LOCK(so); 456fa765671SRobert Watson MAC_POLICY_CHECK_NOSLEEP(socket_check_receive, cred, so, 457fa765671SRobert Watson so->so_label); 4582087a58cSRobert Watson MAC_CHECK_PROBE2(socket_check_receive, error, cred, so); 459f93bfb23SRobert Watson SOCK_UNLOCK(so); 460c66b4d8dSRobert Watson 461c66b4d8dSRobert Watson return (error); 462c66b4d8dSRobert Watson } 463c66b4d8dSRobert Watson 4642087a58cSRobert Watson MAC_CHECK_PROBE_DEFINE3(socket_check_relabel, "struct ucred *", 4652087a58cSRobert Watson "struct socket *", "struct label *"); 4662087a58cSRobert Watson 467c66b4d8dSRobert Watson static int 46830d239bcSRobert Watson mac_socket_check_relabel(struct ucred *cred, struct socket *so, 469c66b4d8dSRobert Watson struct label *newlabel) 470c66b4d8dSRobert Watson { 471c66b4d8dSRobert Watson int error; 472c66b4d8dSRobert Watson 47326ae2b86SRobert Watson SOCK_LOCK_ASSERT(so); 474310e7cebSRobert Watson 475fa765671SRobert Watson MAC_POLICY_CHECK_NOSLEEP(socket_check_relabel, cred, so, 476fa765671SRobert Watson so->so_label, newlabel); 4772087a58cSRobert Watson MAC_CHECK_PROBE3(socket_check_relabel, error, cred, so, newlabel); 478c66b4d8dSRobert Watson 479c66b4d8dSRobert Watson return (error); 480c66b4d8dSRobert Watson } 481c66b4d8dSRobert Watson 4822087a58cSRobert Watson MAC_CHECK_PROBE_DEFINE2(socket_check_send, "struct ucred *", 4832087a58cSRobert Watson "struct socket *"); 4842087a58cSRobert Watson 485c66b4d8dSRobert Watson int 48630d239bcSRobert Watson mac_socket_check_send(struct ucred *cred, struct socket *so) 487c66b4d8dSRobert Watson { 488c66b4d8dSRobert Watson int error; 489c66b4d8dSRobert Watson 490f93bfb23SRobert Watson if (mac_policy_count == 0) 491f93bfb23SRobert Watson return (0); 492310e7cebSRobert Watson 493f93bfb23SRobert Watson SOCK_LOCK(so); 494fa765671SRobert Watson MAC_POLICY_CHECK_NOSLEEP(socket_check_send, cred, so, so->so_label); 4952087a58cSRobert Watson MAC_CHECK_PROBE2(socket_check_send, error, cred, so); 496f93bfb23SRobert Watson SOCK_UNLOCK(so); 497c66b4d8dSRobert Watson 498c66b4d8dSRobert Watson return (error); 499c66b4d8dSRobert Watson } 500c66b4d8dSRobert Watson 5012087a58cSRobert Watson MAC_CHECK_PROBE_DEFINE2(socket_check_stat, "struct ucred *", 5022087a58cSRobert Watson "struct socket *"); 5032087a58cSRobert Watson 504c66b4d8dSRobert Watson int 50530d239bcSRobert Watson mac_socket_check_stat(struct ucred *cred, struct socket *so) 5067f53207bSRobert Watson { 5077f53207bSRobert Watson int error; 5087f53207bSRobert Watson 509f93bfb23SRobert Watson if (mac_policy_count == 0) 510f93bfb23SRobert Watson return (0); 5117f53207bSRobert Watson 512f93bfb23SRobert Watson SOCK_LOCK(so); 513fa765671SRobert Watson MAC_POLICY_CHECK_NOSLEEP(socket_check_stat, cred, so, so->so_label); 5142087a58cSRobert Watson MAC_CHECK_PROBE2(socket_check_stat, error, cred, so); 515f93bfb23SRobert Watson SOCK_UNLOCK(so); 5167f53207bSRobert Watson 5177f53207bSRobert Watson return (error); 5187f53207bSRobert Watson } 5197f53207bSRobert Watson 5202087a58cSRobert Watson MAC_CHECK_PROBE_DEFINE2(socket_check_visible, "struct ucred *", 5212087a58cSRobert Watson "struct socket *"); 5222087a58cSRobert Watson 5237f53207bSRobert Watson int 52430d239bcSRobert Watson mac_socket_check_visible(struct ucred *cred, struct socket *so) 525c66b4d8dSRobert Watson { 526c66b4d8dSRobert Watson int error; 527c66b4d8dSRobert Watson 528f93bfb23SRobert Watson if (mac_policy_count == 0) 529f93bfb23SRobert Watson return (0); 530310e7cebSRobert Watson 531f93bfb23SRobert Watson SOCK_LOCK(so); 532fa765671SRobert Watson MAC_POLICY_CHECK_NOSLEEP(socket_check_visible, cred, so, 533fa765671SRobert Watson so->so_label); 5342087a58cSRobert Watson MAC_CHECK_PROBE2(socket_check_visible, error, cred, so); 535f93bfb23SRobert Watson SOCK_UNLOCK(so); 536c66b4d8dSRobert Watson 537c66b4d8dSRobert Watson return (error); 538c66b4d8dSRobert Watson } 539c66b4d8dSRobert Watson 540c66b4d8dSRobert Watson int 541c66b4d8dSRobert Watson mac_socket_label_set(struct ucred *cred, struct socket *so, 542c66b4d8dSRobert Watson struct label *label) 543c66b4d8dSRobert Watson { 544c66b4d8dSRobert Watson int error; 545c66b4d8dSRobert Watson 546310e7cebSRobert Watson /* 547df3c68e4SRobert Watson * We acquire the socket lock when we perform the test and set, but 548df3c68e4SRobert Watson * have to release it as the pcb code needs to acquire the pcb lock, 549df3c68e4SRobert Watson * which will precede the socket lock in the lock order. However, 550df3c68e4SRobert Watson * this is fine, as any race will simply result in the inpcb being 551df3c68e4SRobert Watson * refreshed twice, but still consistently, as the inpcb code will 552df3c68e4SRobert Watson * acquire the socket lock before refreshing, holding both locks. 553310e7cebSRobert Watson */ 554310e7cebSRobert Watson SOCK_LOCK(so); 55530d239bcSRobert Watson error = mac_socket_check_relabel(cred, so, label); 556310e7cebSRobert Watson if (error) { 557310e7cebSRobert Watson SOCK_UNLOCK(so); 558c66b4d8dSRobert Watson return (error); 559310e7cebSRobert Watson } 560c66b4d8dSRobert Watson 56130d239bcSRobert Watson mac_socket_relabel(cred, so, label); 562310e7cebSRobert Watson SOCK_UNLOCK(so); 563df3c68e4SRobert Watson 564c66b4d8dSRobert Watson /* 565c66b4d8dSRobert Watson * If the protocol has expressed interest in socket layer changes, 566df3c68e4SRobert Watson * such as if it needs to propagate changes to a cached pcb label 567df3c68e4SRobert Watson * from the socket, notify it of the label change while holding the 568df3c68e4SRobert Watson * socket lock. 569c66b4d8dSRobert Watson */ 570c66b4d8dSRobert Watson if (so->so_proto->pr_usrreqs->pru_sosetlabel != NULL) 571c66b4d8dSRobert Watson (so->so_proto->pr_usrreqs->pru_sosetlabel)(so); 572c66b4d8dSRobert Watson 573c66b4d8dSRobert Watson return (0); 574c66b4d8dSRobert Watson } 575c66b4d8dSRobert Watson 576c66b4d8dSRobert Watson int 577c66b4d8dSRobert Watson mac_setsockopt_label(struct ucred *cred, struct socket *so, struct mac *mac) 578c66b4d8dSRobert Watson { 579c66b4d8dSRobert Watson struct label *intlabel; 580c66b4d8dSRobert Watson char *buffer; 581c66b4d8dSRobert Watson int error; 582c66b4d8dSRobert Watson 5836356dba0SRobert Watson if (!(mac_labeled & MPC_OBJECT_SOCKET)) 5846356dba0SRobert Watson return (EINVAL); 5856356dba0SRobert Watson 586c66b4d8dSRobert Watson error = mac_check_structmac_consistent(mac); 587c66b4d8dSRobert Watson if (error) 588c66b4d8dSRobert Watson return (error); 589c66b4d8dSRobert Watson 590c66b4d8dSRobert Watson buffer = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK); 591c66b4d8dSRobert Watson error = copyinstr(mac->m_string, buffer, mac->m_buflen, NULL); 592c66b4d8dSRobert Watson if (error) { 593c66b4d8dSRobert Watson free(buffer, M_MACTEMP); 594c66b4d8dSRobert Watson return (error); 595c66b4d8dSRobert Watson } 596c66b4d8dSRobert Watson 597c66b4d8dSRobert Watson intlabel = mac_socket_label_alloc(M_WAITOK); 59830d239bcSRobert Watson error = mac_socket_internalize_label(intlabel, buffer); 599c66b4d8dSRobert Watson free(buffer, M_MACTEMP); 600c66b4d8dSRobert Watson if (error) 601c66b4d8dSRobert Watson goto out; 602c66b4d8dSRobert Watson 603c66b4d8dSRobert Watson error = mac_socket_label_set(cred, so, intlabel); 604c66b4d8dSRobert Watson out: 605c66b4d8dSRobert Watson mac_socket_label_free(intlabel); 606c66b4d8dSRobert Watson return (error); 607c66b4d8dSRobert Watson } 608c66b4d8dSRobert Watson 609c66b4d8dSRobert Watson int 610c66b4d8dSRobert Watson mac_getsockopt_label(struct ucred *cred, struct socket *so, struct mac *mac) 611c66b4d8dSRobert Watson { 612c66b4d8dSRobert Watson char *buffer, *elements; 613310e7cebSRobert Watson struct label *intlabel; 614c66b4d8dSRobert Watson int error; 615c66b4d8dSRobert Watson 6166356dba0SRobert Watson if (!(mac_labeled & MPC_OBJECT_SOCKET)) 6176356dba0SRobert Watson return (EINVAL); 6186356dba0SRobert Watson 619c66b4d8dSRobert Watson error = mac_check_structmac_consistent(mac); 620c66b4d8dSRobert Watson if (error) 621c66b4d8dSRobert Watson return (error); 622c66b4d8dSRobert Watson 623c66b4d8dSRobert Watson elements = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK); 624c66b4d8dSRobert Watson error = copyinstr(mac->m_string, elements, mac->m_buflen, NULL); 625c66b4d8dSRobert Watson if (error) { 626c66b4d8dSRobert Watson free(elements, M_MACTEMP); 627c66b4d8dSRobert Watson return (error); 628c66b4d8dSRobert Watson } 629c66b4d8dSRobert Watson 630c66b4d8dSRobert Watson buffer = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); 631310e7cebSRobert Watson intlabel = mac_socket_label_alloc(M_WAITOK); 632310e7cebSRobert Watson SOCK_LOCK(so); 63330d239bcSRobert Watson mac_socket_copy_label(so->so_label, intlabel); 634310e7cebSRobert Watson SOCK_UNLOCK(so); 63530d239bcSRobert Watson error = mac_socket_externalize_label(intlabel, elements, buffer, 636310e7cebSRobert Watson mac->m_buflen); 637310e7cebSRobert Watson mac_socket_label_free(intlabel); 638c66b4d8dSRobert Watson if (error == 0) 639c66b4d8dSRobert Watson error = copyout(buffer, mac->m_string, strlen(buffer)+1); 640c66b4d8dSRobert Watson 641c66b4d8dSRobert Watson free(buffer, M_MACTEMP); 642c66b4d8dSRobert Watson free(elements, M_MACTEMP); 643c66b4d8dSRobert Watson 644c66b4d8dSRobert Watson return (error); 645c66b4d8dSRobert Watson } 646c66b4d8dSRobert Watson 647c66b4d8dSRobert Watson int 648c66b4d8dSRobert Watson mac_getsockopt_peerlabel(struct ucred *cred, struct socket *so, 649c66b4d8dSRobert Watson struct mac *mac) 650c66b4d8dSRobert Watson { 651c66b4d8dSRobert Watson char *elements, *buffer; 652310e7cebSRobert Watson struct label *intlabel; 653c66b4d8dSRobert Watson int error; 654c66b4d8dSRobert Watson 6556356dba0SRobert Watson if (!(mac_labeled & MPC_OBJECT_SOCKET)) 6566356dba0SRobert Watson return (EINVAL); 6576356dba0SRobert Watson 658c66b4d8dSRobert Watson error = mac_check_structmac_consistent(mac); 659c66b4d8dSRobert Watson if (error) 660c66b4d8dSRobert Watson return (error); 661c66b4d8dSRobert Watson 662c66b4d8dSRobert Watson elements = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK); 663c66b4d8dSRobert Watson error = copyinstr(mac->m_string, elements, mac->m_buflen, NULL); 664c66b4d8dSRobert Watson if (error) { 665c66b4d8dSRobert Watson free(elements, M_MACTEMP); 666c66b4d8dSRobert Watson return (error); 667c66b4d8dSRobert Watson } 668c66b4d8dSRobert Watson 669c66b4d8dSRobert Watson buffer = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); 670310e7cebSRobert Watson intlabel = mac_socket_label_alloc(M_WAITOK); 671310e7cebSRobert Watson SOCK_LOCK(so); 67230d239bcSRobert Watson mac_socket_copy_label(so->so_peerlabel, intlabel); 673310e7cebSRobert Watson SOCK_UNLOCK(so); 67430d239bcSRobert Watson error = mac_socketpeer_externalize_label(intlabel, elements, buffer, 675310e7cebSRobert Watson mac->m_buflen); 676310e7cebSRobert Watson mac_socket_label_free(intlabel); 677c66b4d8dSRobert Watson if (error == 0) 678c66b4d8dSRobert Watson error = copyout(buffer, mac->m_string, strlen(buffer)+1); 679c66b4d8dSRobert Watson 680c66b4d8dSRobert Watson free(buffer, M_MACTEMP); 681c66b4d8dSRobert Watson free(elements, M_MACTEMP); 682c66b4d8dSRobert Watson 683c66b4d8dSRobert Watson return (error); 684c66b4d8dSRobert Watson } 685