xref: /freebsd/sys/netipsec/ipsec_pcb.c (revision 5ca8e32633c4ffbbcd6762e5888b6a4ba0708c6c)
1 /*-
2  * Copyright (c) 2016 Andrey V. Elsukov <ae@FreeBSD.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26 
27 #include <sys/cdefs.h>
28 #include "opt_inet.h"
29 #include "opt_inet6.h"
30 #include "opt_ipsec.h"
31 
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/kernel.h>
35 #include <sys/lock.h>
36 #include <sys/malloc.h>
37 #include <sys/mbuf.h>
38 #include <sys/priv.h>
39 #include <sys/socket.h>
40 #include <sys/sockopt.h>
41 #include <sys/syslog.h>
42 #include <sys/proc.h>
43 
44 #include <netinet/in.h>
45 #include <netinet/in_pcb.h>
46 
47 #include <netipsec/ipsec.h>
48 #include <netipsec/ipsec6.h>
49 #include <netipsec/ipsec_support.h>
50 #include <netipsec/key.h>
51 #include <netipsec/key_debug.h>
52 
53 MALLOC_DEFINE(M_IPSEC_INPCB, "inpcbpolicy", "inpcb-resident ipsec policy");
54 
55 static void
56 ipsec_setsockaddrs_inpcb(struct inpcb *inp, union sockaddr_union *src,
57     union sockaddr_union *dst, u_int dir)
58 {
59 
60 #ifdef INET6
61 	if (inp->inp_vflag & INP_IPV6) {
62 		struct sockaddr_in6 *sin6;
63 
64 		bzero(&src->sin6, sizeof(src->sin6));
65 		bzero(&dst->sin6, sizeof(dst->sin6));
66 		src->sin6.sin6_family = AF_INET6;
67 		src->sin6.sin6_len = sizeof(struct sockaddr_in6);
68 		dst->sin6.sin6_family = AF_INET6;
69 		dst->sin6.sin6_len = sizeof(struct sockaddr_in6);
70 
71 		if (dir == IPSEC_DIR_OUTBOUND)
72 			sin6 = &src->sin6;
73 		else
74 			sin6 = &dst->sin6;
75 		sin6->sin6_addr = inp->in6p_laddr;
76 		sin6->sin6_port = inp->inp_lport;
77 		if (IN6_IS_SCOPE_LINKLOCAL(&inp->in6p_laddr)) {
78 			/* XXXAE: use in6p_zoneid */
79 			sin6->sin6_addr.s6_addr16[1] = 0;
80 			sin6->sin6_scope_id = ntohs(
81 			    inp->in6p_laddr.s6_addr16[1]);
82 		}
83 
84 		if (dir == IPSEC_DIR_OUTBOUND)
85 			sin6 = &dst->sin6;
86 		else
87 			sin6 = &src->sin6;
88 		sin6->sin6_addr = inp->in6p_faddr;
89 		sin6->sin6_port = inp->inp_fport;
90 		if (IN6_IS_SCOPE_LINKLOCAL(&inp->in6p_faddr)) {
91 			/* XXXAE: use in6p_zoneid */
92 			sin6->sin6_addr.s6_addr16[1] = 0;
93 			sin6->sin6_scope_id = ntohs(
94 			    inp->in6p_faddr.s6_addr16[1]);
95 		}
96 	}
97 #endif
98 #ifdef INET
99 	if (inp->inp_vflag & INP_IPV4) {
100 		struct sockaddr_in *sin;
101 
102 		bzero(&src->sin, sizeof(src->sin));
103 		bzero(&dst->sin, sizeof(dst->sin));
104 		src->sin.sin_family = AF_INET;
105 		src->sin.sin_len = sizeof(struct sockaddr_in);
106 		dst->sin.sin_family = AF_INET;
107 		dst->sin.sin_len = sizeof(struct sockaddr_in);
108 
109 		if (dir == IPSEC_DIR_OUTBOUND)
110 			sin = &src->sin;
111 		else
112 			sin = &dst->sin;
113 		sin->sin_addr = inp->inp_laddr;
114 		sin->sin_port = inp->inp_lport;
115 
116 		if (dir == IPSEC_DIR_OUTBOUND)
117 			sin = &dst->sin;
118 		else
119 			sin = &src->sin;
120 		sin->sin_addr = inp->inp_faddr;
121 		sin->sin_port = inp->inp_fport;
122 	}
123 #endif
124 }
125 
126 void
127 ipsec_setspidx_inpcb(struct inpcb *inp, struct secpolicyindex *spidx,
128     u_int dir)
129 {
130 
131 	ipsec_setsockaddrs_inpcb(inp, &spidx->src, &spidx->dst, dir);
132 #ifdef INET6
133 	if (inp->inp_vflag & INP_IPV6) {
134 		spidx->prefs = sizeof(struct in6_addr) << 3;
135 		spidx->prefd = sizeof(struct in6_addr) << 3;
136 	}
137 #endif
138 #ifdef INET
139 	if (inp->inp_vflag & INP_IPV4) {
140 		spidx->prefs = sizeof(struct in_addr) << 3;
141 		spidx->prefd = sizeof(struct in_addr) << 3;
142 	}
143 #endif
144 	spidx->ul_proto = IPPROTO_TCP; /* XXX: currently only TCP uses this */
145 	spidx->dir = dir;
146 	KEYDBG(IPSEC_DUMP,
147 	    printf("%s: ", __func__); kdebug_secpolicyindex(spidx, NULL));
148 }
149 
150 /* Initialize PCB policy. */
151 int
152 ipsec_init_pcbpolicy(struct inpcb *inp)
153 {
154 
155 	IPSEC_ASSERT(inp != NULL, ("null inp"));
156 	IPSEC_ASSERT(inp->inp_sp == NULL, ("inp_sp already initialized"));
157 
158 	inp->inp_sp = malloc(sizeof(struct inpcbpolicy), M_IPSEC_INPCB,
159 	    M_NOWAIT | M_ZERO);
160 	if (inp->inp_sp == NULL)
161 		return (ENOBUFS);
162 	return (0);
163 }
164 
165 /* Delete PCB policy. */
166 int
167 ipsec_delete_pcbpolicy(struct inpcb *inp)
168 {
169 
170 	if (inp->inp_sp == NULL)
171 		return (0);
172 
173 	if (inp->inp_sp->sp_in != NULL)
174 		key_freesp(&inp->inp_sp->sp_in);
175 
176 	if (inp->inp_sp->sp_out != NULL)
177 		key_freesp(&inp->inp_sp->sp_out);
178 
179 	free(inp->inp_sp, M_IPSEC_INPCB);
180 	inp->inp_sp = NULL;
181 	return (0);
182 }
183 
184 /* Deep-copy a policy in PCB. */
185 static struct secpolicy *
186 ipsec_deepcopy_pcbpolicy(struct secpolicy *src)
187 {
188 	struct secpolicy *dst;
189 	int i;
190 
191 	if (src == NULL)
192 		return (NULL);
193 
194 	IPSEC_ASSERT(src->state == IPSEC_SPSTATE_PCB, ("SP isn't PCB"));
195 
196 	dst = key_newsp();
197 	if (dst == NULL)
198 		return (NULL);
199 
200 	/* spidx is not copied here */
201 	dst->policy = src->policy;
202 	dst->state = src->state;
203 	dst->priority = src->priority;
204 	/* Do not touch the refcnt field. */
205 
206 	/* Copy IPsec request chain. */
207 	for (i = 0; i < src->tcount; i++) {
208 		dst->req[i] = ipsec_newisr();
209 		if (dst->req[i] == NULL) {
210 			key_freesp(&dst);
211 			return (NULL);
212 		}
213 		bcopy(src->req[i], dst->req[i], sizeof(struct ipsecrequest));
214 		dst->tcount++;
215 	}
216 	KEYDBG(IPSEC_DUMP,
217 	    printf("%s: copied SP(%p) -> SP(%p)\n", __func__, src, dst);
218 	    kdebug_secpolicy(dst));
219 	return (dst);
220 }
221 
222 /*
223  * Copy IPsec policy from old INPCB into new.
224  * It is expected that new INPCB has not configured policies.
225  */
226 int
227 ipsec_copy_pcbpolicy(struct inpcb *old, struct inpcb *new)
228 {
229 	struct secpolicy *sp;
230 
231 	/*
232 	 * old->inp_sp can be NULL if PCB was created when an IPsec
233 	 * support was unavailable. This is not an error, we don't have
234 	 * policies in this PCB, so nothing to copy.
235 	 */
236 	if (old->inp_sp == NULL)
237 		return (0);
238 
239 	IPSEC_ASSERT(new->inp_sp != NULL, ("new inp_sp is NULL"));
240 	IPSEC_ASSERT((new->inp_sp->flags & (
241 	    INP_INBOUND_POLICY | INP_OUTBOUND_POLICY)) == 0,
242 	    ("new PCB already has configured policies"));
243 	INP_WLOCK_ASSERT(new);
244 	INP_LOCK_ASSERT(old);
245 
246 	if (old->inp_sp->flags & INP_INBOUND_POLICY) {
247 		sp = ipsec_deepcopy_pcbpolicy(old->inp_sp->sp_in);
248 		if (sp == NULL)
249 			return (ENOBUFS);
250 		ipsec_setspidx_inpcb(new, &sp->spidx, IPSEC_DIR_INBOUND);
251 		if (new->inp_sp->sp_in != NULL)
252 			key_freesp(&new->inp_sp->sp_in);
253 		new->inp_sp->sp_in = sp;
254 		new->inp_sp->flags |= INP_INBOUND_POLICY;
255 	}
256 	if (old->inp_sp->flags & INP_OUTBOUND_POLICY) {
257 		sp = ipsec_deepcopy_pcbpolicy(old->inp_sp->sp_out);
258 		if (sp == NULL)
259 			return (ENOBUFS);
260 		ipsec_setspidx_inpcb(new, &sp->spidx, IPSEC_DIR_OUTBOUND);
261 		if (new->inp_sp->sp_out != NULL)
262 			key_freesp(&new->inp_sp->sp_out);
263 		new->inp_sp->sp_out = sp;
264 		new->inp_sp->flags |= INP_OUTBOUND_POLICY;
265 	}
266 	return (0);
267 }
268 
269 static int
270 ipsec_set_pcbpolicy(struct inpcb *inp, struct ucred *cred,
271     void *request, size_t len)
272 {
273 	struct sadb_x_policy *xpl;
274 	struct secpolicy **spp, *newsp;
275 	int error, flags;
276 
277 	xpl = (struct sadb_x_policy *)request;
278 	/* Select direction. */
279 	switch (xpl->sadb_x_policy_dir) {
280 	case IPSEC_DIR_INBOUND:
281 	case IPSEC_DIR_OUTBOUND:
282 		break;
283 	default:
284 		ipseclog((LOG_ERR, "%s: invalid direction=%u\n", __func__,
285 			xpl->sadb_x_policy_dir));
286 		return (EINVAL);
287 	}
288 	/*
289 	 * Privileged sockets are allowed to set own security policy
290 	 * and configure IPsec bypass. Unprivileged sockets only can
291 	 * have ENTRUST policy.
292 	 */
293 	switch (xpl->sadb_x_policy_type) {
294 	case IPSEC_POLICY_IPSEC:
295 	case IPSEC_POLICY_BYPASS:
296 		if (cred != NULL &&
297 		    priv_check_cred(cred, PRIV_NETINET_IPSEC) != 0)
298 			return (EACCES);
299 		/* Allocate new SP entry. */
300 		newsp = key_msg2sp(xpl, len, &error);
301 		if (newsp == NULL)
302 			return (error);
303 		newsp->state = IPSEC_SPSTATE_PCB;
304 		newsp->spidx.ul_proto = IPSEC_ULPROTO_ANY;
305 #ifdef INET
306 		if (inp->inp_vflag & INP_IPV4) {
307 			newsp->spidx.src.sin.sin_family =
308 			    newsp->spidx.dst.sin.sin_family = AF_INET;
309 			newsp->spidx.src.sin.sin_len =
310 			    newsp->spidx.dst.sin.sin_len =
311 			    sizeof(struct sockaddr_in);
312 		}
313 #endif
314 #ifdef INET6
315 		if (inp->inp_vflag & INP_IPV6) {
316 			newsp->spidx.src.sin6.sin6_family =
317 			    newsp->spidx.dst.sin6.sin6_family = AF_INET6;
318 			newsp->spidx.src.sin6.sin6_len =
319 			    newsp->spidx.dst.sin6.sin6_len =
320 			    sizeof(struct sockaddr_in6);
321 		}
322 #endif
323 		break;
324 	case IPSEC_POLICY_ENTRUST:
325 		/* We just use NULL pointer for ENTRUST policy */
326 		newsp = NULL;
327 		break;
328 	default:
329 		/* Other security policy types aren't allowed for PCB */
330 		return (EINVAL);
331 	}
332 
333 	INP_WLOCK(inp);
334 	if (xpl->sadb_x_policy_dir == IPSEC_DIR_INBOUND) {
335 		spp = &inp->inp_sp->sp_in;
336 		flags = INP_INBOUND_POLICY;
337 	} else {
338 		spp = &inp->inp_sp->sp_out;
339 		flags = INP_OUTBOUND_POLICY;
340 	}
341 	/* Clear old SP and set new SP. */
342 	if (*spp != NULL)
343 		key_freesp(spp);
344 	*spp = newsp;
345 	KEYDBG(IPSEC_DUMP,
346 	    printf("%s: new SP(%p)\n", __func__, newsp));
347 	if (newsp == NULL)
348 		inp->inp_sp->flags &= ~flags;
349 	else {
350 		inp->inp_sp->flags |= flags;
351 		KEYDBG(IPSEC_DUMP, kdebug_secpolicy(newsp));
352 	}
353 	INP_WUNLOCK(inp);
354 	return (0);
355 }
356 
357 static int
358 ipsec_get_pcbpolicy(struct inpcb *inp, void *request, size_t *len)
359 {
360 	struct sadb_x_policy *xpl;
361 	struct secpolicy *sp;
362 	int error, flags;
363 
364 	xpl = (struct sadb_x_policy *)request;
365 
366 	INP_RLOCK(inp);
367 	flags = inp->inp_sp->flags;
368 	/* Select direction. */
369 	switch (xpl->sadb_x_policy_dir) {
370 	case IPSEC_DIR_INBOUND:
371 		sp = inp->inp_sp->sp_in;
372 		flags &= INP_INBOUND_POLICY;
373 		break;
374 	case IPSEC_DIR_OUTBOUND:
375 		sp = inp->inp_sp->sp_out;
376 		flags &= INP_OUTBOUND_POLICY;
377 		break;
378 	default:
379 		INP_RUNLOCK(inp);
380 		ipseclog((LOG_ERR, "%s: invalid direction=%u\n", __func__,
381 			xpl->sadb_x_policy_dir));
382 		return (EINVAL);
383 	}
384 
385 	if (flags == 0) {
386 		/* Return ENTRUST policy */
387 		INP_RUNLOCK(inp);
388 		xpl->sadb_x_policy_exttype = SADB_X_EXT_POLICY;
389 		xpl->sadb_x_policy_type = IPSEC_POLICY_ENTRUST;
390 		xpl->sadb_x_policy_id = 0;
391 		xpl->sadb_x_policy_priority = 0;
392 		xpl->sadb_x_policy_len = PFKEY_UNIT64(sizeof(*xpl));
393 		*len = sizeof(*xpl);
394 		return (0);
395 	}
396 
397 	IPSEC_ASSERT(sp != NULL,
398 	    ("sp is NULL, but flags is 0x%04x", inp->inp_sp->flags));
399 
400 	key_addref(sp);
401 	INP_RUNLOCK(inp);
402 	error = key_sp2msg(sp, request, len);
403 	key_freesp(&sp);
404 	if (error == EINVAL)
405 		return (error);
406 	/*
407 	 * We return "success", but user should check *len.
408 	 * *len will be set to size of valid data and
409 	 * sadb_x_policy_len will contain needed size.
410 	 */
411 	return (0);
412 }
413 
414 /* Handle socket option control request for PCB */
415 static int
416 ipsec_control_pcbpolicy(struct inpcb *inp, struct sockopt *sopt)
417 {
418 	void *optdata;
419 	size_t optlen;
420 	int error;
421 
422 	if (inp->inp_sp == NULL)
423 		return (ENOPROTOOPT);
424 
425 	/* Limit maximum request size to PAGE_SIZE */
426 	optlen = sopt->sopt_valsize;
427 	if (optlen < sizeof(struct sadb_x_policy) || optlen > PAGE_SIZE)
428 		return (EINVAL);
429 
430 	optdata = malloc(optlen, M_TEMP, sopt->sopt_td ? M_WAITOK: M_NOWAIT);
431 	if (optdata == NULL)
432 		return (ENOBUFS);
433 	/*
434 	 * We need a hint from the user, what policy is requested - input
435 	 * or output? User should specify it in the buffer, even for
436 	 * setsockopt().
437 	 */
438 	error = sooptcopyin(sopt, optdata, optlen, optlen);
439 	if (error == 0) {
440 		if (sopt->sopt_dir == SOPT_SET)
441 			error = ipsec_set_pcbpolicy(inp,
442 			    sopt->sopt_td ? sopt->sopt_td->td_ucred: NULL,
443 			    optdata, optlen);
444 		else {
445 			error = ipsec_get_pcbpolicy(inp, optdata, &optlen);
446 			if (error == 0)
447 				error = sooptcopyout(sopt, optdata, optlen);
448 		}
449 	}
450 	free(optdata, M_TEMP);
451 	return (error);
452 }
453 
454 #ifdef INET
455 /*
456  * IPSEC_PCBCTL() method implementation for IPv4.
457  */
458 int
459 ipsec4_pcbctl(struct inpcb *inp, struct sockopt *sopt)
460 {
461 
462 	if (sopt->sopt_name != IP_IPSEC_POLICY)
463 		return (ENOPROTOOPT);
464 	return (ipsec_control_pcbpolicy(inp, sopt));
465 }
466 #endif
467 
468 #ifdef INET6
469 /*
470  * IPSEC_PCBCTL() method implementation for IPv6.
471  */
472 int
473 ipsec6_pcbctl(struct inpcb *inp, struct sockopt *sopt)
474 {
475 
476 	if (sopt->sopt_name != IPV6_IPSEC_POLICY)
477 		return (ENOPROTOOPT);
478 	return (ipsec_control_pcbpolicy(inp, sopt));
479 }
480 #endif
481