ipsec_pcb.c revision 317733
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: stable/11/sys/netipsec/ipsec_pcb.c 317733 2017-05-03 09:25:26Z ae $");
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
55MALLOC_DEFINE(M_IPSEC_INPCB, "inpcbpolicy", "inpcb-resident ipsec policy");
56
57static void
58ipsec_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
128void
129ipsec_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. */
153int
154ipsec_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. */
168int
169ipsec_delete_pcbpolicy(struct inpcb *inp)
170{
171
172	if (inp->inp_sp == NULL)
173		return (0);
174
175	if (inp->inp_sp->sp_in != NULL)
176		key_freesp(&inp->inp_sp->sp_in);
177
178	if (inp->inp_sp->sp_out != NULL)
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. */
187static struct secpolicy *
188ipsec_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 */
228int
229ipsec_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		if (new->inp_sp->sp_in != NULL)
254			key_freesp(&new->inp_sp->sp_in);
255		new->inp_sp->sp_in = sp;
256		new->inp_sp->flags |= INP_INBOUND_POLICY;
257	}
258	if (old->inp_sp->flags & INP_OUTBOUND_POLICY) {
259		sp = ipsec_deepcopy_pcbpolicy(old->inp_sp->sp_out);
260		if (sp == NULL)
261			return (ENOBUFS);
262		ipsec_setspidx_inpcb(new, &sp->spidx, IPSEC_DIR_OUTBOUND);
263		if (new->inp_sp->sp_out != NULL)
264			key_freesp(&new->inp_sp->sp_out);
265		new->inp_sp->sp_out = sp;
266		new->inp_sp->flags |= INP_OUTBOUND_POLICY;
267	}
268	return (0);
269}
270
271static int
272ipsec_set_pcbpolicy(struct inpcb *inp, struct ucred *cred,
273    void *request, size_t len)
274{
275	struct sadb_x_policy *xpl;
276	struct secpolicy **spp, *newsp;
277	int error, flags;
278
279	xpl = (struct sadb_x_policy *)request;
280	/* Select direction. */
281	switch (xpl->sadb_x_policy_dir) {
282	case IPSEC_DIR_INBOUND:
283	case IPSEC_DIR_OUTBOUND:
284		break;
285	default:
286		ipseclog((LOG_ERR, "%s: invalid direction=%u\n", __func__,
287			xpl->sadb_x_policy_dir));
288		return (EINVAL);
289	}
290	/*
291	 * Privileged sockets are allowed to set own security policy
292	 * and configure IPsec bypass. Unprivileged sockets only can
293	 * have ENTRUST policy.
294	 */
295	switch (xpl->sadb_x_policy_type) {
296	case IPSEC_POLICY_IPSEC:
297	case IPSEC_POLICY_BYPASS:
298		if (cred != NULL &&
299		    priv_check_cred(cred, PRIV_NETINET_IPSEC, 0) != 0)
300			return (EACCES);
301		/* Allocate new SP entry. */
302		newsp = key_msg2sp(xpl, len, &error);
303		if (newsp == NULL)
304			return (error);
305		newsp->state = IPSEC_SPSTATE_PCB;
306		newsp->spidx.ul_proto = IPSEC_ULPROTO_ANY;
307#ifdef INET
308		if (inp->inp_vflag & INP_IPV4) {
309			newsp->spidx.src.sin.sin_family =
310			    newsp->spidx.dst.sin.sin_family = AF_INET;
311			newsp->spidx.src.sin.sin_len =
312			    newsp->spidx.dst.sin.sin_len =
313			    sizeof(struct sockaddr_in);
314		}
315#endif
316#ifdef INET6
317		if (inp->inp_vflag & INP_IPV6) {
318			newsp->spidx.src.sin6.sin6_family =
319			    newsp->spidx.dst.sin6.sin6_family = AF_INET6;
320			newsp->spidx.src.sin6.sin6_len =
321			    newsp->spidx.dst.sin6.sin6_len =
322			    sizeof(struct sockaddr_in6);
323		}
324#endif
325		break;
326	case IPSEC_POLICY_ENTRUST:
327		/* We just use NULL pointer for ENTRUST policy */
328		newsp = NULL;
329		break;
330	default:
331		/* Other security policy types aren't allowed for PCB */
332		return (EINVAL);
333	}
334
335	INP_WLOCK(inp);
336	if (xpl->sadb_x_policy_dir == IPSEC_DIR_INBOUND) {
337		spp = &inp->inp_sp->sp_in;
338		flags = INP_INBOUND_POLICY;
339	} else {
340		spp = &inp->inp_sp->sp_out;
341		flags = INP_OUTBOUND_POLICY;
342	}
343	/* Clear old SP and set new SP. */
344	if (*spp != NULL)
345		key_freesp(spp);
346	*spp = newsp;
347	KEYDBG(IPSEC_DUMP,
348	    printf("%s: new SP(%p)\n", __func__, newsp));
349	if (newsp == NULL)
350		inp->inp_sp->flags &= ~flags;
351	else {
352		inp->inp_sp->flags |= flags;
353		KEYDBG(IPSEC_DUMP, kdebug_secpolicy(newsp));
354	}
355	INP_WUNLOCK(inp);
356	return (0);
357}
358
359static int
360ipsec_get_pcbpolicy(struct inpcb *inp, void *request, size_t *len)
361{
362	struct sadb_x_policy *xpl;
363	struct secpolicy *sp;
364	int error, flags;
365
366	xpl = (struct sadb_x_policy *)request;
367
368	INP_RLOCK(inp);
369	flags = inp->inp_sp->flags;
370	/* Select direction. */
371	switch (xpl->sadb_x_policy_dir) {
372	case IPSEC_DIR_INBOUND:
373		sp = inp->inp_sp->sp_in;
374		flags &= INP_INBOUND_POLICY;
375		break;
376	case IPSEC_DIR_OUTBOUND:
377		sp = inp->inp_sp->sp_out;
378		flags &= INP_OUTBOUND_POLICY;
379		break;
380	default:
381		INP_RUNLOCK(inp);
382		ipseclog((LOG_ERR, "%s: invalid direction=%u\n", __func__,
383			xpl->sadb_x_policy_dir));
384		return (EINVAL);
385	}
386
387	if (flags == 0) {
388		/* Return ENTRUST policy */
389		INP_RUNLOCK(inp);
390		xpl->sadb_x_policy_exttype = SADB_X_EXT_POLICY;
391		xpl->sadb_x_policy_type = IPSEC_POLICY_ENTRUST;
392		xpl->sadb_x_policy_id = 0;
393		xpl->sadb_x_policy_priority = 0;
394		xpl->sadb_x_policy_len = PFKEY_UNIT64(sizeof(*xpl));
395		*len = sizeof(*xpl);
396		return (0);
397	}
398
399	IPSEC_ASSERT(sp != NULL,
400	    ("sp is NULL, but flags is 0x%04x", inp->inp_sp->flags));
401
402	key_addref(sp);
403	INP_RUNLOCK(inp);
404	error = key_sp2msg(sp, request, len);
405	key_freesp(&sp);
406	if (error == EINVAL)
407		return (error);
408	/*
409	 * We return "success", but user should check *len.
410	 * *len will be set to size of valid data and
411	 * sadb_x_policy_len will contain needed size.
412	 */
413	return (0);
414}
415
416/* Handle socket option control request for PCB */
417static int
418ipsec_control_pcbpolicy(struct inpcb *inp, struct sockopt *sopt)
419{
420	void *optdata;
421	size_t optlen;
422	int error;
423
424	if (inp->inp_sp == NULL)
425		return (ENOPROTOOPT);
426
427	/* Limit maximum request size to PAGE_SIZE */
428	optlen = sopt->sopt_valsize;
429	if (optlen < sizeof(struct sadb_x_policy) || optlen > PAGE_SIZE)
430		return (EINVAL);
431
432	optdata = malloc(optlen, M_TEMP, sopt->sopt_td ? M_WAITOK: M_NOWAIT);
433	if (optdata == NULL)
434		return (ENOBUFS);
435	/*
436	 * We need a hint from the user, what policy is requested - input
437	 * or output? User should specify it in the buffer, even for
438	 * setsockopt().
439	 */
440	error = sooptcopyin(sopt, optdata, optlen, optlen);
441	if (error == 0) {
442		if (sopt->sopt_dir == SOPT_SET)
443			error = ipsec_set_pcbpolicy(inp,
444			    sopt->sopt_td ? sopt->sopt_td->td_ucred: NULL,
445			    optdata, optlen);
446		else {
447			error = ipsec_get_pcbpolicy(inp, optdata, &optlen);
448			if (error == 0)
449				error = sooptcopyout(sopt, optdata, optlen);
450		}
451	}
452	free(optdata, M_TEMP);
453	return (error);
454}
455
456#ifdef INET
457/*
458 * IPSEC_PCBCTL() method implementation for IPv4.
459 */
460int
461ipsec4_pcbctl(struct inpcb *inp, struct sockopt *sopt)
462{
463
464	if (sopt->sopt_name != IP_IPSEC_POLICY)
465		return (ENOPROTOOPT);
466	return (ipsec_control_pcbpolicy(inp, sopt));
467}
468#endif
469
470#ifdef INET6
471/*
472 * IPSEC_PCBCTL() method implementation for IPv6.
473 */
474int
475ipsec6_pcbctl(struct inpcb *inp, struct sockopt *sopt)
476{
477
478	if (sopt->sopt_name != IPV6_IPSEC_POLICY)
479		return (ENOPROTOOPT);
480	return (ipsec_control_pcbpolicy(inp, sopt));
481}
482#endif
483
484