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 #include "opt_mac.h" 47c66b4d8dSRobert Watson 48c66b4d8dSRobert Watson #include <sys/param.h> 49c66b4d8dSRobert Watson #include <sys/kernel.h> 50c66b4d8dSRobert Watson #include <sys/lock.h> 51c66b4d8dSRobert Watson #include <sys/malloc.h> 52c66b4d8dSRobert Watson #include <sys/mutex.h> 53c66b4d8dSRobert Watson #include <sys/mac.h> 54c66b4d8dSRobert Watson #include <sys/sbuf.h> 552087a58cSRobert Watson #include <sys/sdt.h> 56c66b4d8dSRobert Watson #include <sys/systm.h> 57c66b4d8dSRobert Watson #include <sys/mount.h> 58c66b4d8dSRobert Watson #include <sys/file.h> 59c66b4d8dSRobert Watson #include <sys/namei.h> 60c66b4d8dSRobert Watson #include <sys/protosw.h> 61c66b4d8dSRobert Watson #include <sys/socket.h> 62c66b4d8dSRobert Watson #include <sys/socketvar.h> 63c66b4d8dSRobert Watson #include <sys/sysctl.h> 64c66b4d8dSRobert Watson 65c66b4d8dSRobert Watson #include <net/bpfdesc.h> 66c66b4d8dSRobert Watson #include <net/if.h> 67c66b4d8dSRobert Watson #include <net/if_var.h> 68c66b4d8dSRobert Watson 69c66b4d8dSRobert Watson #include <netinet/in.h> 70c66b4d8dSRobert Watson #include <netinet/in_pcb.h> 71c66b4d8dSRobert Watson #include <netinet/ip_var.h> 72c66b4d8dSRobert Watson 73aed55708SRobert Watson #include <security/mac/mac_framework.h> 74c66b4d8dSRobert Watson #include <security/mac/mac_internal.h> 750efd6615SRobert Watson #include <security/mac/mac_policy.h> 76c66b4d8dSRobert Watson 77c66b4d8dSRobert Watson /* 78df3c68e4SRobert Watson * Currently, sockets hold two labels: the label of the socket itself, and a 79df3c68e4SRobert Watson * peer label, which may be used by policies to hold a copy of the label of 80df3c68e4SRobert Watson * any remote endpoint. 81df3c68e4SRobert Watson * 82df3c68e4SRobert Watson * Possibly, this peer label should be maintained at the protocol layer 83df3c68e4SRobert Watson * (inpcb, unpcb, etc), as this would allow protocol-aware code to maintain 84df3c68e4SRobert Watson * the label consistently. For example, it might be copied live from a 85df3c68e4SRobert Watson * remote socket for UNIX domain sockets rather than keeping a local copy on 86df3c68e4SRobert Watson * this endpoint, but be cached and updated based on packets received for 87df3c68e4SRobert Watson * TCP/IP. 883de40469SRobert Watson * 893de40469SRobert Watson * Unlike with many other object types, the lock protecting MAC labels on 903de40469SRobert Watson * sockets (the socket lock) is not frequently held at the points in code 913de40469SRobert Watson * where socket-related checks are called. The MAC Framework acquires the 923de40469SRobert Watson * lock over some entry points in order to enforce atomicity (such as label 933de40469SRobert Watson * copies) but in other cases the policy modules will have to acquire the 943de40469SRobert Watson * lock themselves if they use labels. This approach (a) avoids lock 953de40469SRobert Watson * acquisitions when policies don't require labels and (b) solves a number of 963de40469SRobert Watson * potential lock order issues when multiple sockets are used in the same 973de40469SRobert Watson * entry point. 98df3c68e4SRobert Watson */ 99df3c68e4SRobert Watson 100c66b4d8dSRobert Watson struct label * 101c66b4d8dSRobert Watson mac_socket_label_alloc(int flag) 102c66b4d8dSRobert Watson { 103c66b4d8dSRobert Watson struct label *label; 104c66b4d8dSRobert Watson int error; 105c66b4d8dSRobert Watson 106c66b4d8dSRobert Watson label = mac_labelzone_alloc(flag); 107c66b4d8dSRobert Watson if (label == NULL) 108c66b4d8dSRobert Watson return (NULL); 109c66b4d8dSRobert Watson 11040202729SRobert Watson if (flag & M_WAITOK) 111fa765671SRobert Watson MAC_POLICY_CHECK(socket_init_label, label, flag); 11240202729SRobert Watson else 113fa765671SRobert Watson MAC_POLICY_CHECK_NOSLEEP(socket_init_label, label, flag); 114c66b4d8dSRobert Watson if (error) { 115fa765671SRobert Watson MAC_POLICY_PERFORM_NOSLEEP(socket_destroy_label, label); 116c66b4d8dSRobert Watson mac_labelzone_free(label); 117c66b4d8dSRobert Watson return (NULL); 118c66b4d8dSRobert Watson } 119c66b4d8dSRobert Watson return (label); 120c66b4d8dSRobert Watson } 121c66b4d8dSRobert Watson 122c66b4d8dSRobert Watson static struct label * 12330d239bcSRobert Watson mac_socketpeer_label_alloc(int flag) 124c66b4d8dSRobert Watson { 125c66b4d8dSRobert Watson struct label *label; 126c66b4d8dSRobert Watson int error; 127c66b4d8dSRobert Watson 128c66b4d8dSRobert Watson label = mac_labelzone_alloc(flag); 129c66b4d8dSRobert Watson if (label == NULL) 130c66b4d8dSRobert Watson return (NULL); 131c66b4d8dSRobert Watson 13240202729SRobert Watson if (flag & M_WAITOK) 133fa765671SRobert Watson MAC_POLICY_CHECK(socketpeer_init_label, label, flag); 13440202729SRobert Watson else 135fa765671SRobert Watson MAC_POLICY_CHECK_NOSLEEP(socketpeer_init_label, label, flag); 136c66b4d8dSRobert Watson if (error) { 137fa765671SRobert Watson MAC_POLICY_PERFORM_NOSLEEP(socketpeer_destroy_label, label); 138c66b4d8dSRobert Watson mac_labelzone_free(label); 139c66b4d8dSRobert Watson return (NULL); 140c66b4d8dSRobert Watson } 141c66b4d8dSRobert Watson return (label); 142c66b4d8dSRobert Watson } 143c66b4d8dSRobert Watson 144c66b4d8dSRobert Watson int 14530d239bcSRobert Watson mac_socket_init(struct socket *so, int flag) 146c66b4d8dSRobert Watson { 147c66b4d8dSRobert Watson 1486356dba0SRobert Watson if (mac_labeled & MPC_OBJECT_SOCKET) { 149c66b4d8dSRobert Watson so->so_label = mac_socket_label_alloc(flag); 150c66b4d8dSRobert Watson if (so->so_label == NULL) 151c66b4d8dSRobert Watson return (ENOMEM); 15230d239bcSRobert Watson so->so_peerlabel = mac_socketpeer_label_alloc(flag); 153c66b4d8dSRobert Watson if (so->so_peerlabel == NULL) { 154c66b4d8dSRobert Watson mac_socket_label_free(so->so_label); 155c66b4d8dSRobert Watson so->so_label = NULL; 156c66b4d8dSRobert Watson return (ENOMEM); 157c66b4d8dSRobert Watson } 1586356dba0SRobert Watson } else { 1596356dba0SRobert Watson so->so_label = NULL; 1606356dba0SRobert Watson so->so_peerlabel = NULL; 1616356dba0SRobert Watson } 162c66b4d8dSRobert Watson return (0); 163c66b4d8dSRobert Watson } 164c66b4d8dSRobert Watson 165c66b4d8dSRobert Watson void 166c66b4d8dSRobert Watson mac_socket_label_free(struct label *label) 167c66b4d8dSRobert Watson { 168c66b4d8dSRobert Watson 169fa765671SRobert Watson MAC_POLICY_PERFORM_NOSLEEP(socket_destroy_label, label); 170c66b4d8dSRobert Watson mac_labelzone_free(label); 171c66b4d8dSRobert Watson } 172c66b4d8dSRobert Watson 173*2fb778faSMichael Tuexen void 17430d239bcSRobert Watson mac_socketpeer_label_free(struct label *label) 175c66b4d8dSRobert Watson { 176c66b4d8dSRobert Watson 177fa765671SRobert Watson MAC_POLICY_PERFORM_NOSLEEP(socketpeer_destroy_label, label); 178c66b4d8dSRobert Watson mac_labelzone_free(label); 179c66b4d8dSRobert Watson } 180c66b4d8dSRobert Watson 181c66b4d8dSRobert Watson void 18230d239bcSRobert Watson mac_socket_destroy(struct socket *so) 183c66b4d8dSRobert Watson { 184c66b4d8dSRobert Watson 1856356dba0SRobert Watson if (so->so_label != NULL) { 18626ae2b86SRobert Watson mac_socket_label_free(so->so_label); 18726ae2b86SRobert Watson so->so_label = NULL; 188*2fb778faSMichael Tuexen if (!SOLISTENING(so)) { 18930d239bcSRobert Watson mac_socketpeer_label_free(so->so_peerlabel); 19026ae2b86SRobert Watson so->so_peerlabel = NULL; 191c66b4d8dSRobert Watson } 1926356dba0SRobert Watson } 193*2fb778faSMichael Tuexen } 194c66b4d8dSRobert Watson 195c66b4d8dSRobert Watson void 19630d239bcSRobert Watson mac_socket_copy_label(struct label *src, struct label *dest) 197c66b4d8dSRobert Watson { 198c66b4d8dSRobert Watson 199fa765671SRobert Watson MAC_POLICY_PERFORM_NOSLEEP(socket_copy_label, src, dest); 200c66b4d8dSRobert Watson } 201c66b4d8dSRobert Watson 202c66b4d8dSRobert Watson int 20330d239bcSRobert Watson mac_socket_externalize_label(struct label *label, char *elements, 204c66b4d8dSRobert Watson char *outbuf, size_t outbuflen) 205c66b4d8dSRobert Watson { 206c66b4d8dSRobert Watson int error; 207c66b4d8dSRobert Watson 208fa765671SRobert Watson MAC_POLICY_EXTERNALIZE(socket, label, elements, outbuf, outbuflen); 209c66b4d8dSRobert Watson 210c66b4d8dSRobert Watson return (error); 211c66b4d8dSRobert Watson } 212c66b4d8dSRobert Watson 213c66b4d8dSRobert Watson static int 21430d239bcSRobert Watson mac_socketpeer_externalize_label(struct label *label, char *elements, 215c66b4d8dSRobert Watson char *outbuf, size_t outbuflen) 216c66b4d8dSRobert Watson { 217c66b4d8dSRobert Watson int error; 218c66b4d8dSRobert Watson 219fa765671SRobert Watson MAC_POLICY_EXTERNALIZE(socketpeer, label, elements, outbuf, 220fa765671SRobert Watson outbuflen); 221c66b4d8dSRobert Watson 222c66b4d8dSRobert Watson return (error); 223c66b4d8dSRobert Watson } 224c66b4d8dSRobert Watson 225c66b4d8dSRobert Watson int 22630d239bcSRobert Watson mac_socket_internalize_label(struct label *label, char *string) 227c66b4d8dSRobert Watson { 228c66b4d8dSRobert Watson int error; 229c66b4d8dSRobert Watson 230fa765671SRobert Watson MAC_POLICY_INTERNALIZE(socket, label, string); 231c66b4d8dSRobert Watson 232c66b4d8dSRobert Watson return (error); 233c66b4d8dSRobert Watson } 234c66b4d8dSRobert Watson 235c66b4d8dSRobert Watson void 23630d239bcSRobert Watson mac_socket_create(struct ucred *cred, struct socket *so) 237c66b4d8dSRobert Watson { 238c66b4d8dSRobert Watson 239fa765671SRobert Watson MAC_POLICY_PERFORM_NOSLEEP(socket_create, cred, so, so->so_label); 240c66b4d8dSRobert Watson } 241c66b4d8dSRobert Watson 242c66b4d8dSRobert Watson void 24330d239bcSRobert Watson mac_socket_newconn(struct socket *oldso, struct socket *newso) 244c66b4d8dSRobert Watson { 245c66b4d8dSRobert Watson 246fa765671SRobert Watson MAC_POLICY_PERFORM_NOSLEEP(socket_newconn, oldso, oldso->so_label, 247fa765671SRobert Watson newso, newso->so_label); 248c66b4d8dSRobert Watson } 249c66b4d8dSRobert Watson 250c66b4d8dSRobert Watson static void 25130d239bcSRobert Watson mac_socket_relabel(struct ucred *cred, struct socket *so, 252c66b4d8dSRobert Watson struct label *newlabel) 253c66b4d8dSRobert Watson { 254c66b4d8dSRobert Watson 25526ae2b86SRobert Watson SOCK_LOCK_ASSERT(so); 25626ae2b86SRobert Watson 257fa765671SRobert Watson MAC_POLICY_PERFORM_NOSLEEP(socket_relabel, cred, so, so->so_label, 25840202729SRobert Watson newlabel); 259c66b4d8dSRobert Watson } 260c66b4d8dSRobert Watson 261c66b4d8dSRobert Watson void 26230d239bcSRobert Watson mac_socketpeer_set_from_mbuf(struct mbuf *m, struct socket *so) 263c66b4d8dSRobert Watson { 264c66b4d8dSRobert Watson struct label *label; 265c66b4d8dSRobert Watson 2663de40469SRobert Watson if (mac_policy_count == 0) 2673de40469SRobert Watson return; 2683de40469SRobert Watson 26926ae2b86SRobert Watson label = mac_mbuf_to_label(m); 270c66b4d8dSRobert Watson 271fa765671SRobert Watson MAC_POLICY_PERFORM_NOSLEEP(socketpeer_set_from_mbuf, m, label, so, 27226ae2b86SRobert Watson so->so_peerlabel); 273c66b4d8dSRobert Watson } 274c66b4d8dSRobert Watson 275c66b4d8dSRobert Watson void 27630d239bcSRobert Watson mac_socketpeer_set_from_socket(struct socket *oldso, struct socket *newso) 277c66b4d8dSRobert Watson { 278c66b4d8dSRobert Watson 279f93bfb23SRobert Watson if (mac_policy_count == 0) 280f93bfb23SRobert Watson return; 281f93bfb23SRobert Watson 282fa765671SRobert Watson MAC_POLICY_PERFORM_NOSLEEP(socketpeer_set_from_socket, oldso, 28340202729SRobert Watson oldso->so_label, newso, newso->so_peerlabel); 284c66b4d8dSRobert Watson } 285c66b4d8dSRobert Watson 286c66b4d8dSRobert Watson void 28730d239bcSRobert Watson mac_socket_create_mbuf(struct socket *so, struct mbuf *m) 288c66b4d8dSRobert Watson { 289c66b4d8dSRobert Watson struct label *label; 290c66b4d8dSRobert Watson 291f93bfb23SRobert Watson if (mac_policy_count == 0) 292f93bfb23SRobert Watson return; 293c66b4d8dSRobert Watson 29426ae2b86SRobert Watson label = mac_mbuf_to_label(m); 29526ae2b86SRobert Watson 296fa765671SRobert Watson MAC_POLICY_PERFORM_NOSLEEP(socket_create_mbuf, so, so->so_label, m, 297fa765671SRobert Watson label); 298c66b4d8dSRobert Watson } 299c66b4d8dSRobert Watson 3002087a58cSRobert Watson MAC_CHECK_PROBE_DEFINE2(socket_check_accept, "struct ucred *", 3012087a58cSRobert Watson "struct socket *"); 3022087a58cSRobert Watson 303c66b4d8dSRobert Watson int 30430d239bcSRobert Watson mac_socket_check_accept(struct ucred *cred, struct socket *so) 3057f53207bSRobert Watson { 3067f53207bSRobert Watson int error; 3077f53207bSRobert Watson 308fa765671SRobert Watson MAC_POLICY_CHECK_NOSLEEP(socket_check_accept, cred, so, 309fa765671SRobert Watson so->so_label); 3102087a58cSRobert Watson MAC_CHECK_PROBE2(socket_check_accept, error, cred, so); 3117f53207bSRobert Watson 3127f53207bSRobert Watson return (error); 3137f53207bSRobert Watson } 3147f53207bSRobert Watson 3152087a58cSRobert Watson MAC_CHECK_PROBE_DEFINE3(socket_check_bind, "struct ucred *", 3162087a58cSRobert Watson "struct socket *", "struct sockaddr *"); 3172087a58cSRobert Watson 3187f53207bSRobert Watson int 319c14172e3SRobert Watson mac_socket_check_bind(struct ucred *cred, struct socket *so, 32026ae2b86SRobert Watson struct sockaddr *sa) 321c66b4d8dSRobert Watson { 322c66b4d8dSRobert Watson int error; 323c66b4d8dSRobert Watson 324fa765671SRobert Watson MAC_POLICY_CHECK_NOSLEEP(socket_check_bind, cred, so, so->so_label, 325fa765671SRobert Watson sa); 326c14172e3SRobert Watson MAC_CHECK_PROBE3(socket_check_bind, error, cred, so, sa); 327c66b4d8dSRobert Watson 328c66b4d8dSRobert Watson return (error); 329c66b4d8dSRobert Watson } 330c66b4d8dSRobert Watson 3312087a58cSRobert Watson MAC_CHECK_PROBE_DEFINE3(socket_check_connect, "struct ucred *", 3322087a58cSRobert Watson "struct socket *", "struct sockaddr *"); 3332087a58cSRobert Watson 334c66b4d8dSRobert Watson int 33530d239bcSRobert Watson mac_socket_check_connect(struct ucred *cred, struct socket *so, 33626ae2b86SRobert Watson struct sockaddr *sa) 337c66b4d8dSRobert Watson { 338c66b4d8dSRobert Watson int error; 339c66b4d8dSRobert Watson 340fa765671SRobert Watson MAC_POLICY_CHECK_NOSLEEP(socket_check_connect, cred, so, 341fa765671SRobert Watson so->so_label, sa); 3422087a58cSRobert Watson MAC_CHECK_PROBE3(socket_check_connect, error, cred, so, sa); 343c66b4d8dSRobert Watson 344c66b4d8dSRobert Watson return (error); 345c66b4d8dSRobert Watson } 346c66b4d8dSRobert Watson 3472087a58cSRobert Watson MAC_CHECK_PROBE_DEFINE4(socket_check_create, "struct ucred *", "int", "int", 3482087a58cSRobert Watson "int"); 3492087a58cSRobert Watson 350c66b4d8dSRobert Watson int 35130d239bcSRobert Watson mac_socket_check_create(struct ucred *cred, int domain, int type, int proto) 3526758f88eSRobert Watson { 3536758f88eSRobert Watson int error; 3546758f88eSRobert Watson 355fa765671SRobert Watson MAC_POLICY_CHECK_NOSLEEP(socket_check_create, cred, domain, type, 356fa765671SRobert Watson proto); 3572087a58cSRobert Watson MAC_CHECK_PROBE4(socket_check_create, error, cred, domain, type, 3582087a58cSRobert Watson proto); 3596758f88eSRobert Watson 3606758f88eSRobert Watson return (error); 3616758f88eSRobert Watson } 3626758f88eSRobert Watson 3632087a58cSRobert Watson MAC_CHECK_PROBE_DEFINE2(socket_check_deliver, "struct socket *", 3642087a58cSRobert Watson "struct mbuf *"); 3652087a58cSRobert Watson 3666758f88eSRobert Watson int 36730d239bcSRobert Watson mac_socket_check_deliver(struct socket *so, struct mbuf *m) 368c66b4d8dSRobert Watson { 369c66b4d8dSRobert Watson struct label *label; 370c66b4d8dSRobert Watson int error; 371c66b4d8dSRobert Watson 372f93bfb23SRobert Watson if (mac_policy_count == 0) 373f93bfb23SRobert Watson return (0); 374310e7cebSRobert Watson 37526ae2b86SRobert Watson label = mac_mbuf_to_label(m); 376c66b4d8dSRobert Watson 377fa765671SRobert Watson MAC_POLICY_CHECK_NOSLEEP(socket_check_deliver, so, so->so_label, m, 378fa765671SRobert Watson label); 3792087a58cSRobert Watson MAC_CHECK_PROBE2(socket_check_deliver, error, so, m); 380c66b4d8dSRobert Watson 381c66b4d8dSRobert Watson return (error); 382c66b4d8dSRobert Watson } 383c66b4d8dSRobert Watson 3842087a58cSRobert Watson MAC_CHECK_PROBE_DEFINE2(socket_check_listen, "struct ucred *", 3852087a58cSRobert Watson "struct socket *"); 3862087a58cSRobert Watson 387c66b4d8dSRobert Watson int 38830d239bcSRobert Watson mac_socket_check_listen(struct ucred *cred, struct socket *so) 389c66b4d8dSRobert Watson { 390c66b4d8dSRobert Watson int error; 391c66b4d8dSRobert Watson 392fa765671SRobert Watson MAC_POLICY_CHECK_NOSLEEP(socket_check_listen, cred, so, 393fa765671SRobert Watson so->so_label); 3942087a58cSRobert Watson MAC_CHECK_PROBE2(socket_check_listen, error, cred, so); 39526ae2b86SRobert Watson 396c66b4d8dSRobert Watson return (error); 397c66b4d8dSRobert Watson } 398c66b4d8dSRobert Watson 3992087a58cSRobert Watson MAC_CHECK_PROBE_DEFINE2(socket_check_poll, "struct ucred *", 4002087a58cSRobert Watson "struct socket *"); 4012087a58cSRobert Watson 402c66b4d8dSRobert Watson int 40330d239bcSRobert Watson mac_socket_check_poll(struct ucred *cred, struct socket *so) 4047f53207bSRobert Watson { 4057f53207bSRobert Watson int error; 4067f53207bSRobert Watson 407fa765671SRobert Watson MAC_POLICY_CHECK_NOSLEEP(socket_check_poll, cred, so, so->so_label); 4082087a58cSRobert Watson MAC_CHECK_PROBE2(socket_check_poll, error, cred, so); 40926ae2b86SRobert Watson 4107f53207bSRobert Watson return (error); 4117f53207bSRobert Watson } 4127f53207bSRobert Watson 4132087a58cSRobert Watson MAC_CHECK_PROBE_DEFINE2(socket_check_receive, "struct ucred *", 4142087a58cSRobert Watson "struct socket *"); 4152087a58cSRobert Watson 4167f53207bSRobert Watson int 41730d239bcSRobert Watson mac_socket_check_receive(struct ucred *cred, struct socket *so) 418c66b4d8dSRobert Watson { 419c66b4d8dSRobert Watson int error; 420c66b4d8dSRobert Watson 421fa765671SRobert Watson MAC_POLICY_CHECK_NOSLEEP(socket_check_receive, cred, so, 422fa765671SRobert Watson so->so_label); 4232087a58cSRobert Watson MAC_CHECK_PROBE2(socket_check_receive, error, cred, so); 424c66b4d8dSRobert Watson 425c66b4d8dSRobert Watson return (error); 426c66b4d8dSRobert Watson } 427c66b4d8dSRobert Watson 4282087a58cSRobert Watson MAC_CHECK_PROBE_DEFINE3(socket_check_relabel, "struct ucred *", 4292087a58cSRobert Watson "struct socket *", "struct label *"); 4302087a58cSRobert Watson 431c66b4d8dSRobert Watson static int 43230d239bcSRobert Watson mac_socket_check_relabel(struct ucred *cred, struct socket *so, 433c66b4d8dSRobert Watson struct label *newlabel) 434c66b4d8dSRobert Watson { 435c66b4d8dSRobert Watson int error; 436c66b4d8dSRobert Watson 43726ae2b86SRobert Watson SOCK_LOCK_ASSERT(so); 438310e7cebSRobert Watson 439fa765671SRobert Watson MAC_POLICY_CHECK_NOSLEEP(socket_check_relabel, cred, so, 440fa765671SRobert Watson so->so_label, newlabel); 4412087a58cSRobert Watson MAC_CHECK_PROBE3(socket_check_relabel, error, cred, so, newlabel); 442c66b4d8dSRobert Watson 443c66b4d8dSRobert Watson return (error); 444c66b4d8dSRobert Watson } 445c66b4d8dSRobert Watson 4462087a58cSRobert Watson MAC_CHECK_PROBE_DEFINE2(socket_check_send, "struct ucred *", 4472087a58cSRobert Watson "struct socket *"); 4482087a58cSRobert Watson 449c66b4d8dSRobert Watson int 45030d239bcSRobert Watson mac_socket_check_send(struct ucred *cred, struct socket *so) 451c66b4d8dSRobert Watson { 452c66b4d8dSRobert Watson int error; 453c66b4d8dSRobert Watson 454fa765671SRobert Watson MAC_POLICY_CHECK_NOSLEEP(socket_check_send, cred, so, so->so_label); 4552087a58cSRobert Watson MAC_CHECK_PROBE2(socket_check_send, error, cred, so); 456c66b4d8dSRobert Watson 457c66b4d8dSRobert Watson return (error); 458c66b4d8dSRobert Watson } 459c66b4d8dSRobert Watson 4602087a58cSRobert Watson MAC_CHECK_PROBE_DEFINE2(socket_check_stat, "struct ucred *", 4612087a58cSRobert Watson "struct socket *"); 4622087a58cSRobert Watson 463c66b4d8dSRobert Watson int 46430d239bcSRobert Watson mac_socket_check_stat(struct ucred *cred, struct socket *so) 4657f53207bSRobert Watson { 4667f53207bSRobert Watson int error; 4677f53207bSRobert Watson 468fa765671SRobert Watson MAC_POLICY_CHECK_NOSLEEP(socket_check_stat, cred, so, so->so_label); 4692087a58cSRobert Watson MAC_CHECK_PROBE2(socket_check_stat, error, cred, so); 4707f53207bSRobert Watson 4717f53207bSRobert Watson return (error); 4727f53207bSRobert Watson } 4737f53207bSRobert Watson 4742087a58cSRobert Watson MAC_CHECK_PROBE_DEFINE2(socket_check_visible, "struct ucred *", 4752087a58cSRobert Watson "struct socket *"); 4762087a58cSRobert Watson 4777f53207bSRobert Watson int 47830d239bcSRobert Watson mac_socket_check_visible(struct ucred *cred, struct socket *so) 479c66b4d8dSRobert Watson { 480c66b4d8dSRobert Watson int error; 481c66b4d8dSRobert Watson 482fa765671SRobert Watson MAC_POLICY_CHECK_NOSLEEP(socket_check_visible, cred, so, 483fa765671SRobert Watson so->so_label); 4842087a58cSRobert Watson MAC_CHECK_PROBE2(socket_check_visible, error, cred, so); 485c66b4d8dSRobert Watson 486c66b4d8dSRobert Watson return (error); 487c66b4d8dSRobert Watson } 488c66b4d8dSRobert Watson 489c66b4d8dSRobert Watson int 490c66b4d8dSRobert Watson mac_socket_label_set(struct ucred *cred, struct socket *so, 491c66b4d8dSRobert Watson struct label *label) 492c66b4d8dSRobert Watson { 493c66b4d8dSRobert Watson int error; 494c66b4d8dSRobert Watson 495310e7cebSRobert Watson /* 496df3c68e4SRobert Watson * We acquire the socket lock when we perform the test and set, but 497df3c68e4SRobert Watson * have to release it as the pcb code needs to acquire the pcb lock, 498df3c68e4SRobert Watson * which will precede the socket lock in the lock order. However, 499df3c68e4SRobert Watson * this is fine, as any race will simply result in the inpcb being 500df3c68e4SRobert Watson * refreshed twice, but still consistently, as the inpcb code will 501df3c68e4SRobert Watson * acquire the socket lock before refreshing, holding both locks. 502310e7cebSRobert Watson */ 503310e7cebSRobert Watson SOCK_LOCK(so); 50430d239bcSRobert Watson error = mac_socket_check_relabel(cred, so, label); 505310e7cebSRobert Watson if (error) { 506310e7cebSRobert Watson SOCK_UNLOCK(so); 507c66b4d8dSRobert Watson return (error); 508310e7cebSRobert Watson } 509c66b4d8dSRobert Watson 51030d239bcSRobert Watson mac_socket_relabel(cred, so, label); 511310e7cebSRobert Watson SOCK_UNLOCK(so); 512df3c68e4SRobert Watson 513c66b4d8dSRobert Watson /* 514c66b4d8dSRobert Watson * If the protocol has expressed interest in socket layer changes, 515df3c68e4SRobert Watson * such as if it needs to propagate changes to a cached pcb label 516df3c68e4SRobert Watson * from the socket, notify it of the label change while holding the 517df3c68e4SRobert Watson * socket lock. 518c66b4d8dSRobert Watson */ 519e7d02be1SGleb Smirnoff if (so->so_proto->pr_sosetlabel != NULL) 520e7d02be1SGleb Smirnoff so->so_proto->pr_sosetlabel(so); 521c66b4d8dSRobert Watson 522c66b4d8dSRobert Watson return (0); 523c66b4d8dSRobert Watson } 524c66b4d8dSRobert Watson 525c66b4d8dSRobert Watson int 526f64a688dSBrooks Davis mac_setsockopt_label(struct ucred *cred, struct socket *so, 527f64a688dSBrooks Davis const struct mac *mac) 528c66b4d8dSRobert Watson { 529c66b4d8dSRobert Watson struct label *intlabel; 530c66b4d8dSRobert Watson char *buffer; 531c66b4d8dSRobert Watson int error; 532c66b4d8dSRobert Watson 5336356dba0SRobert Watson if (!(mac_labeled & MPC_OBJECT_SOCKET)) 5346356dba0SRobert Watson return (EINVAL); 5356356dba0SRobert Watson 536c66b4d8dSRobert Watson error = mac_check_structmac_consistent(mac); 537c66b4d8dSRobert Watson if (error) 538c66b4d8dSRobert Watson return (error); 539c66b4d8dSRobert Watson 540c66b4d8dSRobert Watson buffer = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK); 541c66b4d8dSRobert Watson error = copyinstr(mac->m_string, buffer, mac->m_buflen, NULL); 542c66b4d8dSRobert Watson if (error) { 543c66b4d8dSRobert Watson free(buffer, M_MACTEMP); 544c66b4d8dSRobert Watson return (error); 545c66b4d8dSRobert Watson } 546c66b4d8dSRobert Watson 547c66b4d8dSRobert Watson intlabel = mac_socket_label_alloc(M_WAITOK); 54830d239bcSRobert Watson error = mac_socket_internalize_label(intlabel, buffer); 549c66b4d8dSRobert Watson free(buffer, M_MACTEMP); 550c66b4d8dSRobert Watson if (error) 551c66b4d8dSRobert Watson goto out; 552c66b4d8dSRobert Watson 553c66b4d8dSRobert Watson error = mac_socket_label_set(cred, so, intlabel); 554c66b4d8dSRobert Watson out: 555c66b4d8dSRobert Watson mac_socket_label_free(intlabel); 556c66b4d8dSRobert Watson return (error); 557c66b4d8dSRobert Watson } 558c66b4d8dSRobert Watson 559c66b4d8dSRobert Watson int 560f64a688dSBrooks Davis mac_getsockopt_label(struct ucred *cred, struct socket *so, 561f64a688dSBrooks Davis const struct mac *mac) 562c66b4d8dSRobert Watson { 563c66b4d8dSRobert Watson char *buffer, *elements; 564310e7cebSRobert Watson struct label *intlabel; 565c66b4d8dSRobert Watson int error; 566c66b4d8dSRobert Watson 5676356dba0SRobert Watson if (!(mac_labeled & MPC_OBJECT_SOCKET)) 5686356dba0SRobert Watson return (EINVAL); 5696356dba0SRobert Watson 570c66b4d8dSRobert Watson error = mac_check_structmac_consistent(mac); 571c66b4d8dSRobert Watson if (error) 572c66b4d8dSRobert Watson return (error); 573c66b4d8dSRobert Watson 574c66b4d8dSRobert Watson elements = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK); 575c66b4d8dSRobert Watson error = copyinstr(mac->m_string, elements, mac->m_buflen, NULL); 576c66b4d8dSRobert Watson if (error) { 577c66b4d8dSRobert Watson free(elements, M_MACTEMP); 578c66b4d8dSRobert Watson return (error); 579c66b4d8dSRobert Watson } 580c66b4d8dSRobert Watson 581c66b4d8dSRobert Watson buffer = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); 582310e7cebSRobert Watson intlabel = mac_socket_label_alloc(M_WAITOK); 583310e7cebSRobert Watson SOCK_LOCK(so); 58430d239bcSRobert Watson mac_socket_copy_label(so->so_label, intlabel); 585310e7cebSRobert Watson SOCK_UNLOCK(so); 58630d239bcSRobert Watson error = mac_socket_externalize_label(intlabel, elements, buffer, 587310e7cebSRobert Watson mac->m_buflen); 588310e7cebSRobert Watson mac_socket_label_free(intlabel); 589c66b4d8dSRobert Watson if (error == 0) 590c66b4d8dSRobert Watson error = copyout(buffer, mac->m_string, strlen(buffer)+1); 591c66b4d8dSRobert Watson 592c66b4d8dSRobert Watson free(buffer, M_MACTEMP); 593c66b4d8dSRobert Watson free(elements, M_MACTEMP); 594c66b4d8dSRobert Watson 595c66b4d8dSRobert Watson return (error); 596c66b4d8dSRobert Watson } 597c66b4d8dSRobert Watson 598c66b4d8dSRobert Watson int 599c66b4d8dSRobert Watson mac_getsockopt_peerlabel(struct ucred *cred, struct socket *so, 600f64a688dSBrooks Davis const struct mac *mac) 601c66b4d8dSRobert Watson { 602c66b4d8dSRobert Watson char *elements, *buffer; 603310e7cebSRobert Watson struct label *intlabel; 604c66b4d8dSRobert Watson int error; 605c66b4d8dSRobert Watson 6066356dba0SRobert Watson if (!(mac_labeled & MPC_OBJECT_SOCKET)) 6076356dba0SRobert Watson return (EINVAL); 6086356dba0SRobert Watson 609c66b4d8dSRobert Watson error = mac_check_structmac_consistent(mac); 610c66b4d8dSRobert Watson if (error) 611c66b4d8dSRobert Watson return (error); 612c66b4d8dSRobert Watson 613c66b4d8dSRobert Watson elements = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK); 614c66b4d8dSRobert Watson error = copyinstr(mac->m_string, elements, mac->m_buflen, NULL); 615c66b4d8dSRobert Watson if (error) { 616c66b4d8dSRobert Watson free(elements, M_MACTEMP); 617c66b4d8dSRobert Watson return (error); 618c66b4d8dSRobert Watson } 619c66b4d8dSRobert Watson 620c66b4d8dSRobert Watson buffer = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); 621310e7cebSRobert Watson intlabel = mac_socket_label_alloc(M_WAITOK); 622310e7cebSRobert Watson SOCK_LOCK(so); 623*2fb778faSMichael Tuexen if (SOLISTENING(so)) 624*2fb778faSMichael Tuexen error = EINVAL; 625*2fb778faSMichael Tuexen else 62630d239bcSRobert Watson mac_socket_copy_label(so->so_peerlabel, intlabel); 627310e7cebSRobert Watson SOCK_UNLOCK(so); 628*2fb778faSMichael Tuexen if (error == 0) { 62930d239bcSRobert Watson error = mac_socketpeer_externalize_label(intlabel, elements, buffer, 630310e7cebSRobert Watson mac->m_buflen); 631*2fb778faSMichael Tuexen } 632310e7cebSRobert Watson mac_socket_label_free(intlabel); 633c66b4d8dSRobert Watson if (error == 0) 634c66b4d8dSRobert Watson error = copyout(buffer, mac->m_string, strlen(buffer)+1); 635c66b4d8dSRobert Watson 636c66b4d8dSRobert Watson free(buffer, M_MACTEMP); 637c66b4d8dSRobert Watson free(elements, M_MACTEMP); 638c66b4d8dSRobert Watson 639c66b4d8dSRobert Watson return (error); 640c66b4d8dSRobert Watson } 641