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