1*33de042dSApple OSS Distributions /* 2*33de042dSApple OSS Distributions * Copyright (c) 2013-2021 Apple Inc. All rights reserved. 3*33de042dSApple OSS Distributions * 4*33de042dSApple OSS Distributions * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5*33de042dSApple OSS Distributions * 6*33de042dSApple OSS Distributions * This file contains Original Code and/or Modifications of Original Code 7*33de042dSApple OSS Distributions * as defined in and that are subject to the Apple Public Source License 8*33de042dSApple OSS Distributions * Version 2.0 (the 'License'). You may not use this file except in 9*33de042dSApple OSS Distributions * compliance with the License. The rights granted to you under the License 10*33de042dSApple OSS Distributions * may not be used to create, or enable the creation or redistribution of, 11*33de042dSApple OSS Distributions * unlawful or unlicensed copies of an Apple operating system, or to 12*33de042dSApple OSS Distributions * circumvent, violate, or enable the circumvention or violation of, any 13*33de042dSApple OSS Distributions * terms of an Apple operating system software license agreement. 14*33de042dSApple OSS Distributions * 15*33de042dSApple OSS Distributions * Please obtain a copy of the License at 16*33de042dSApple OSS Distributions * http://www.opensource.apple.com/apsl/ and read it before using this file. 17*33de042dSApple OSS Distributions * 18*33de042dSApple OSS Distributions * The Original Code and all software distributed under the License are 19*33de042dSApple OSS Distributions * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20*33de042dSApple OSS Distributions * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21*33de042dSApple OSS Distributions * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22*33de042dSApple OSS Distributions * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23*33de042dSApple OSS Distributions * Please see the License for the specific language governing rights and 24*33de042dSApple OSS Distributions * limitations under the License. 25*33de042dSApple OSS Distributions * 26*33de042dSApple OSS Distributions * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27*33de042dSApple OSS Distributions */ 28*33de042dSApple OSS Distributions 29*33de042dSApple OSS Distributions #include <sys/types.h> 30*33de042dSApple OSS Distributions #include <sys/malloc.h> 31*33de042dSApple OSS Distributions #include <sys/proc.h> 32*33de042dSApple OSS Distributions #include <sys/sysctl.h> 33*33de042dSApple OSS Distributions #include <sys/syslog.h> 34*33de042dSApple OSS Distributions 35*33de042dSApple OSS Distributions #include <net/if.h> 36*33de042dSApple OSS Distributions 37*33de042dSApple OSS Distributions #include <netinet/in.h> 38*33de042dSApple OSS Distributions #include <netinet6/in6_var.h> 39*33de042dSApple OSS Distributions #include <netinet/ip6.h> 40*33de042dSApple OSS Distributions #include <netinet6/ip6_var.h> 41*33de042dSApple OSS Distributions #include <netinet6/nd6.h> 42*33de042dSApple OSS Distributions 43*33de042dSApple OSS Distributions #if CONFIG_MACF 44*33de042dSApple OSS Distributions #include <sys/kauth.h> 45*33de042dSApple OSS Distributions #include <security/mac_framework.h> 46*33de042dSApple OSS Distributions #endif 47*33de042dSApple OSS Distributions 48*33de042dSApple OSS Distributions SYSCTL_DECL(_net_inet6); /* Note: Not in any common header. */ 49*33de042dSApple OSS Distributions 50*33de042dSApple OSS Distributions SYSCTL_NODE(_net_inet6, OID_AUTO, send, CTLFLAG_RW | CTLFLAG_LOCKED, 0, 51*33de042dSApple OSS Distributions "IPv6 Secure Neighbor Discovery"); 52*33de042dSApple OSS Distributions 53*33de042dSApple OSS Distributions static int nd6_send_opmode = ND6_SEND_OPMODE_CGA_QUIET; 54*33de042dSApple OSS Distributions SYSCTL_INT(_net_inet6_send, OID_AUTO, opmode, CTLFLAG_RW | CTLFLAG_LOCKED, 55*33de042dSApple OSS Distributions &nd6_send_opmode, 0, "configured SEND operating mode"); 56*33de042dSApple OSS Distributions 57*33de042dSApple OSS Distributions int nd6_send_opstate = ND6_SEND_OPMODE_DISABLED; 58*33de042dSApple OSS Distributions SYSCTL_INT(_net_inet6_send, OID_AUTO, opstate, CTLFLAG_RD | CTLFLAG_LOCKED, 59*33de042dSApple OSS Distributions &nd6_send_opstate, 0, "current SEND operating state"); 60*33de042dSApple OSS Distributions 61*33de042dSApple OSS Distributions static int sysctl_cga_parameters SYSCTL_HANDLER_ARGS; 62*33de042dSApple OSS Distributions 63*33de042dSApple OSS Distributions SYSCTL_PROC(_net_inet6_send, OID_AUTO, cga_parameters, 64*33de042dSApple OSS Distributions CTLTYPE_OPAQUE | CTLFLAG_RW | CTLFLAG_LOCKED, 0, 0, 65*33de042dSApple OSS Distributions sysctl_cga_parameters, "S,nd6_send_nodecfg", ""); 66*33de042dSApple OSS Distributions 67*33de042dSApple OSS Distributions /* 68*33de042dSApple OSS Distributions * The size of the buffer is sufficient to contain a public key, its size in 69*33de042dSApple OSS Distributions * machine binary type for the kernel, and the CGA precalc for the global 70*33de042dSApple OSS Distributions * scope. This interface is not a public API, so we don't anticipate that the 71*33de042dSApple OSS Distributions * userland and the kernel will be mismatched between ILP32 and LP64. 72*33de042dSApple OSS Distributions */ 73*33de042dSApple OSS Distributions #define SYSCTL_CGA_PARAMETERS_BUFFER_SIZE \ 74*33de042dSApple OSS Distributions (2 * (sizeof (u_int16_t) + IN6_CGA_KEY_MAXSIZE) + \ 75*33de042dSApple OSS Distributions sizeof (struct in6_cga_prepare)) 76*33de042dSApple OSS Distributions 77*33de042dSApple OSS Distributions static int 78*33de042dSApple OSS Distributions sysctl_cga_parameters SYSCTL_HANDLER_ARGS 79*33de042dSApple OSS Distributions { 80*33de042dSApple OSS Distributions #pragma unused(oidp, arg1) 81*33de042dSApple OSS Distributions u_int namelen; 82*33de042dSApple OSS Distributions char *oldp, *newp; 83*33de042dSApple OSS Distributions const char *fin; 84*33de042dSApple OSS Distributions struct in6_cga_nodecfg cfg; 85*33de042dSApple OSS Distributions struct iovec *__single iov; 86*33de042dSApple OSS Distributions int error; 87*33de042dSApple OSS Distributions char *buffer; 88*33de042dSApple OSS Distributions u_int16_t u16; 89*33de042dSApple OSS Distributions 90*33de042dSApple OSS Distributions namelen = arg2; 91*33de042dSApple OSS Distributions if (namelen != 0) { 92*33de042dSApple OSS Distributions log(LOG_ERR, "%s: name length err [len=%u]\n", __func__, 93*33de042dSApple OSS Distributions namelen); 94*33de042dSApple OSS Distributions return EINVAL; 95*33de042dSApple OSS Distributions } 96*33de042dSApple OSS Distributions 97*33de042dSApple OSS Distributions if (req->newlen > SYSCTL_CGA_PARAMETERS_BUFFER_SIZE) { 98*33de042dSApple OSS Distributions log(LOG_ERR, "%s: input buffer size error [len=%zu]\n", 99*33de042dSApple OSS Distributions __func__, req->newlen); 100*33de042dSApple OSS Distributions return EINVAL; 101*33de042dSApple OSS Distributions } 102*33de042dSApple OSS Distributions 103*33de042dSApple OSS Distributions #if CONFIG_MACF 104*33de042dSApple OSS Distributions error = mac_system_check_info(current_cached_proc_cred(req->p), 105*33de042dSApple OSS Distributions "net.inet6.send.cga_parameters"); 106*33de042dSApple OSS Distributions if (error != 0) { 107*33de042dSApple OSS Distributions log(LOG_ERR, "%s: mac_system_check_info denied.\n", __func__); 108*33de042dSApple OSS Distributions return EPERM; 109*33de042dSApple OSS Distributions } 110*33de042dSApple OSS Distributions #endif 111*33de042dSApple OSS Distributions 112*33de042dSApple OSS Distributions buffer = (char *)kalloc_data(SYSCTL_CGA_PARAMETERS_BUFFER_SIZE, 113*33de042dSApple OSS Distributions Z_WAITOK | Z_ZERO); 114*33de042dSApple OSS Distributions if (buffer == NULL) { 115*33de042dSApple OSS Distributions log(LOG_ERR, "%s: could not allocate marshaling buffer.\n", 116*33de042dSApple OSS Distributions __func__); 117*33de042dSApple OSS Distributions return ENOMEM; 118*33de042dSApple OSS Distributions } 119*33de042dSApple OSS Distributions 120*33de042dSApple OSS Distributions in6_cga_node_lock(); 121*33de042dSApple OSS Distributions 122*33de042dSApple OSS Distributions if (req->oldptr != USER_ADDR_NULL && req->oldlen > 0) { 123*33de042dSApple OSS Distributions oldp = buffer; 124*33de042dSApple OSS Distributions fin = &buffer[SYSCTL_CGA_PARAMETERS_BUFFER_SIZE]; 125*33de042dSApple OSS Distributions if (req->oldlen < SYSCTL_CGA_PARAMETERS_BUFFER_SIZE) { 126*33de042dSApple OSS Distributions fin = &buffer[req->oldlen]; 127*33de042dSApple OSS Distributions } 128*33de042dSApple OSS Distributions 129*33de042dSApple OSS Distributions in6_cga_query(&cfg); 130*33de042dSApple OSS Distributions iov = &cfg.cga_pubkey; 131*33de042dSApple OSS Distributions if (iov->iov_len > 0) { 132*33de042dSApple OSS Distributions VERIFY(iov->iov_len < UINT16_MAX); 133*33de042dSApple OSS Distributions 134*33de042dSApple OSS Distributions if (&oldp[sizeof(cfg.cga_prepare)] <= fin) { 135*33de042dSApple OSS Distributions bcopy(&cfg.cga_prepare, oldp, 136*33de042dSApple OSS Distributions sizeof(cfg.cga_prepare)); 137*33de042dSApple OSS Distributions } 138*33de042dSApple OSS Distributions oldp += sizeof(cfg.cga_prepare); 139*33de042dSApple OSS Distributions 140*33de042dSApple OSS Distributions if (&oldp[sizeof(u16)] < fin) { 141*33de042dSApple OSS Distributions u16 = (u_int16_t) iov->iov_len; 142*33de042dSApple OSS Distributions bcopy(&u16, oldp, sizeof(u16)); 143*33de042dSApple OSS Distributions } 144*33de042dSApple OSS Distributions oldp += sizeof(u16); 145*33de042dSApple OSS Distributions 146*33de042dSApple OSS Distributions if (&oldp[iov->iov_len] < fin) { 147*33de042dSApple OSS Distributions bcopy(__unsafe_forge_bidi_indexable(void *, iov->iov_base, iov->iov_len), oldp, iov->iov_len); 148*33de042dSApple OSS Distributions } 149*33de042dSApple OSS Distributions oldp += iov->iov_len; 150*33de042dSApple OSS Distributions 151*33de042dSApple OSS Distributions if (oldp > fin) { 152*33de042dSApple OSS Distributions req->oldlen = oldp - buffer; 153*33de042dSApple OSS Distributions log(LOG_ERR, "%s: marshalled data too large.\n", 154*33de042dSApple OSS Distributions __func__); 155*33de042dSApple OSS Distributions error = ENOMEM; 156*33de042dSApple OSS Distributions goto done; 157*33de042dSApple OSS Distributions } 158*33de042dSApple OSS Distributions } 159*33de042dSApple OSS Distributions 160*33de042dSApple OSS Distributions error = SYSCTL_OUT(req, buffer, oldp - buffer); 161*33de042dSApple OSS Distributions if (error) { 162*33de042dSApple OSS Distributions goto done; 163*33de042dSApple OSS Distributions } 164*33de042dSApple OSS Distributions } 165*33de042dSApple OSS Distributions 166*33de042dSApple OSS Distributions if (req->newptr == USER_ADDR_NULL) { 167*33de042dSApple OSS Distributions goto done; 168*33de042dSApple OSS Distributions } 169*33de042dSApple OSS Distributions 170*33de042dSApple OSS Distributions error = proc_suser(current_proc()); 171*33de042dSApple OSS Distributions if (error) { 172*33de042dSApple OSS Distributions goto done; 173*33de042dSApple OSS Distributions } 174*33de042dSApple OSS Distributions 175*33de042dSApple OSS Distributions if (req->newlen == 0) { 176*33de042dSApple OSS Distributions in6_cga_stop(); 177*33de042dSApple OSS Distributions nd6_send_opstate = ND6_SEND_OPMODE_DISABLED; 178*33de042dSApple OSS Distributions goto done; 179*33de042dSApple OSS Distributions } 180*33de042dSApple OSS Distributions 181*33de042dSApple OSS Distributions error = SYSCTL_IN(req, buffer, req->newlen); 182*33de042dSApple OSS Distributions if (error) { 183*33de042dSApple OSS Distributions goto done; 184*33de042dSApple OSS Distributions } 185*33de042dSApple OSS Distributions 186*33de042dSApple OSS Distributions newp = buffer; 187*33de042dSApple OSS Distributions fin = &buffer[req->newlen]; 188*33de042dSApple OSS Distributions 189*33de042dSApple OSS Distributions bzero(&cfg, sizeof cfg); 190*33de042dSApple OSS Distributions 191*33de042dSApple OSS Distributions if (&newp[sizeof(cfg.cga_prepare)] <= fin) { 192*33de042dSApple OSS Distributions bcopy(newp, &cfg.cga_prepare, sizeof(cfg.cga_prepare)); 193*33de042dSApple OSS Distributions } 194*33de042dSApple OSS Distributions newp += sizeof(cfg.cga_prepare); 195*33de042dSApple OSS Distributions 196*33de042dSApple OSS Distributions iov = &cfg.cga_privkey; 197*33de042dSApple OSS Distributions if (&newp[sizeof(u16)] < fin) { 198*33de042dSApple OSS Distributions bcopy(newp, &u16, sizeof(u16)); 199*33de042dSApple OSS Distributions iov->iov_len = u16; 200*33de042dSApple OSS Distributions 201*33de042dSApple OSS Distributions if (iov->iov_len > IN6_CGA_KEY_MAXSIZE) { 202*33de042dSApple OSS Distributions error = EINVAL; 203*33de042dSApple OSS Distributions goto done; 204*33de042dSApple OSS Distributions } 205*33de042dSApple OSS Distributions } 206*33de042dSApple OSS Distributions newp += sizeof(u16); 207*33de042dSApple OSS Distributions 208*33de042dSApple OSS Distributions iov->iov_base = newp; 209*33de042dSApple OSS Distributions newp += iov->iov_len; 210*33de042dSApple OSS Distributions 211*33de042dSApple OSS Distributions iov = &cfg.cga_pubkey; 212*33de042dSApple OSS Distributions if (&newp[sizeof(u16)] < fin) { 213*33de042dSApple OSS Distributions bcopy(newp, &u16, sizeof(u16)); 214*33de042dSApple OSS Distributions iov->iov_len = u16; 215*33de042dSApple OSS Distributions 216*33de042dSApple OSS Distributions if (iov->iov_len > IN6_CGA_KEY_MAXSIZE) { 217*33de042dSApple OSS Distributions error = EINVAL; 218*33de042dSApple OSS Distributions goto done; 219*33de042dSApple OSS Distributions } 220*33de042dSApple OSS Distributions } 221*33de042dSApple OSS Distributions newp += sizeof(u16); 222*33de042dSApple OSS Distributions 223*33de042dSApple OSS Distributions iov->iov_base = newp; 224*33de042dSApple OSS Distributions newp += iov->iov_len; 225*33de042dSApple OSS Distributions 226*33de042dSApple OSS Distributions if (newp > fin) { 227*33de042dSApple OSS Distributions log(LOG_ERR, "%s: input too large [octets=%ld].\n", __func__, 228*33de042dSApple OSS Distributions newp - fin); 229*33de042dSApple OSS Distributions error = ENOMEM; 230*33de042dSApple OSS Distributions goto done; 231*33de042dSApple OSS Distributions } 232*33de042dSApple OSS Distributions 233*33de042dSApple OSS Distributions error = in6_cga_start(&cfg); 234*33de042dSApple OSS Distributions if (!error) { 235*33de042dSApple OSS Distributions nd6_send_opstate = nd6_send_opmode; 236*33de042dSApple OSS Distributions } else { 237*33de042dSApple OSS Distributions log(LOG_ERR, "%s: in6_cga_start error=%d.\n", __func__, 238*33de042dSApple OSS Distributions error); 239*33de042dSApple OSS Distributions } 240*33de042dSApple OSS Distributions 241*33de042dSApple OSS Distributions done: 242*33de042dSApple OSS Distributions in6_cga_node_unlock(); 243*33de042dSApple OSS Distributions kfree_data(buffer, SYSCTL_CGA_PARAMETERS_BUFFER_SIZE); 244*33de042dSApple OSS Distributions return error; 245*33de042dSApple OSS Distributions } 246*33de042dSApple OSS Distributions 247*33de042dSApple OSS Distributions /* End of file */ 248