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