]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/netipsec/ipsec_pcb.c
bhnd(9): Fix a few mandoc related issues
[FreeBSD/FreeBSD.git] / sys / netipsec / ipsec_pcb.c
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->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. */
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                 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
271 static int
272 ipsec_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)
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
359 static int
360 ipsec_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 */
417 static int
418 ipsec_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  */
460 int
461 ipsec4_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  */
474 int
475 ipsec6_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