1 /*-
2  * Copyright (c) 2009-2013 The NetBSD Foundation, Inc.
3  * All rights reserved.
4  *
5  * This material is based upon work partially supported by The
6  * NetBSD Foundation under a contract with Mindaugas Rasiukevicius.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
18  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
21  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 /*
31  * NPF byte-code processing.
32  */
33 
34 #ifdef _KERNEL
35 #include <sys/cdefs.h>
36 __KERNEL_RCSID(0, "$NetBSD: npf_bpf.c,v 1.14 2018/09/29 14:41:36 rmind Exp $");
37 
38 #include <sys/types.h>
39 #include <sys/param.h>
40 
41 #include <sys/bitops.h>
42 #include <sys/mbuf.h>
43 #include <net/bpf.h>
44 #endif
45 
46 #define NPF_BPFCOP
47 #include "npf_impl.h"
48 
49 #if defined(_NPF_STANDALONE)
50 #define   m_length(m)                   (nbuf)->nb_mops->getchainlen(m)
51 #endif
52 
53 /*
54  * BPF context and the coprocessor.
55  */
56 
57 static bpf_ctx_t *npf_bpfctx __read_mostly;
58 
59 static uint32_t     npf_cop_l3(const bpf_ctx_t *, bpf_args_t *, uint32_t);
60 static uint32_t     npf_cop_table(const bpf_ctx_t *, bpf_args_t *, uint32_t);
61 
62 static const bpf_copfunc_t npf_bpfcop[] = {
63           [NPF_COP_L3]        = npf_cop_l3,
64           [NPF_COP_TABLE]     = npf_cop_table,
65 };
66 
67 #define   BPF_MW_ALLMASK \
68     ((1U << BPF_MW_IPVER) | (1U << BPF_MW_L4OFF) | (1U << BPF_MW_L4PROTO))
69 
70 void
npf_bpf_sysinit(void)71 npf_bpf_sysinit(void)
72 {
73           npf_bpfctx = bpf_create();
74           bpf_set_cop(npf_bpfctx, npf_bpfcop, __arraycount(npf_bpfcop));
75           bpf_set_extmem(npf_bpfctx, NPF_BPF_NWORDS, BPF_MW_ALLMASK);
76 }
77 
78 void
npf_bpf_sysfini(void)79 npf_bpf_sysfini(void)
80 {
81           bpf_destroy(npf_bpfctx);
82 }
83 
84 void
npf_bpf_prepare(npf_cache_t * npc,bpf_args_t * args,uint32_t * M)85 npf_bpf_prepare(npf_cache_t *npc, bpf_args_t *args, uint32_t *M)
86 {
87           nbuf_t *nbuf = npc->npc_nbuf;
88           const struct mbuf *mbuf = nbuf_head_mbuf(nbuf);
89           const size_t pktlen = m_length(mbuf);
90 
91           /* Prepare the arguments for the BPF programs. */
92 #ifdef _NPF_STANDALONE
93           args->pkt = (const uint8_t *)nbuf_dataptr(nbuf);
94           args->wirelen = args->buflen = pktlen;
95 #else
96           args->pkt = (const uint8_t *)mbuf;
97           args->wirelen = pktlen;
98           args->buflen = 0;
99 #endif
100           args->mem = M;
101           args->arg = npc;
102 
103           /*
104            * Convert address length to IP version.  Just mask out
105            * number 4 or set 6 if higher bits set, such that:
106            *
107            *        0         =>        0
108            *        4         =>        4 (IPVERSION)
109            *        16        =>        6 (IPV6_VERSION >> 4)
110            */
111           const u_int alen = npc->npc_alen;
112           const uint32_t ver = (alen & 4) | ((alen >> 4) * 6);
113 
114           /*
115            * Output words in the memory store:
116            *        BPF_MW_IPVER        IP version (4 or 6).
117            *        BPF_MW_L4OFF        L4 header offset.
118            *        BPF_MW_L4PROTO      L4 protocol.
119            */
120           M[BPF_MW_IPVER] = ver;
121           M[BPF_MW_L4OFF] = npc->npc_hlen;
122           M[BPF_MW_L4PROTO] = npc->npc_proto;
123 }
124 
125 int
npf_bpf_filter(bpf_args_t * args,const void * code,bpfjit_func_t jcode)126 npf_bpf_filter(bpf_args_t *args, const void *code, bpfjit_func_t jcode)
127 {
128           /* Execute JIT-compiled code. */
129           if (__predict_true(jcode)) {
130                     return jcode(npf_bpfctx, args);
131           }
132 
133           /* Execute BPF byte-code. */
134           return bpf_filter_ext(npf_bpfctx, code, args);
135 }
136 
137 void *
npf_bpf_compile(void * code,size_t size)138 npf_bpf_compile(void *code, size_t size)
139 {
140           return bpf_jit_generate(npf_bpfctx, code, size);
141 }
142 
143 bool
npf_bpf_validate(const void * code,size_t len)144 npf_bpf_validate(const void *code, size_t len)
145 {
146           const size_t icount = len / sizeof(struct bpf_insn);
147           return bpf_validate_ext(npf_bpfctx, code, icount) != 0;
148 }
149 
150 /*
151  * NPF_COP_L3: fetches layer 3 information.
152  */
153 static uint32_t
npf_cop_l3(const bpf_ctx_t * bc,bpf_args_t * args,uint32_t A)154 npf_cop_l3(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A)
155 {
156           const npf_cache_t * const npc = (const npf_cache_t *)args->arg;
157           const uint32_t ver = (npc->npc_alen & 4) | ((npc->npc_alen >> 4) * 6);
158           uint32_t * const M = args->mem;
159 
160           M[BPF_MW_IPVER] = ver;
161           M[BPF_MW_L4OFF] = npc->npc_hlen;
162           M[BPF_MW_L4PROTO] = npc->npc_proto;
163           return ver; /* A <- IP version */
164 }
165 
166 #define   SRC_FLAG_BIT        (1U << 31)
167 
168 /*
169  * NPF_COP_TABLE: perform NPF table lookup.
170  *
171  *        A <- non-zero (true) if found and zero (false) otherwise
172  */
173 static uint32_t
npf_cop_table(const bpf_ctx_t * bc,bpf_args_t * args,uint32_t A)174 npf_cop_table(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A)
175 {
176           const npf_cache_t * const npc = (const npf_cache_t *)args->arg;
177           npf_tableset_t *tblset = npf_config_tableset(npc->npc_ctx);
178           const uint32_t tid = A & (SRC_FLAG_BIT - 1);
179           const npf_addr_t *addr;
180           npf_table_t *t;
181 
182           if (!npf_iscached(npc, NPC_IP46)) {
183                     return 0;
184           }
185           t = npf_tableset_getbyid(tblset, tid);
186           if (__predict_false(!t)) {
187                     return 0;
188           }
189           addr = npc->npc_ips[(A & SRC_FLAG_BIT) ? NPF_SRC : NPF_DST];
190           return npf_table_lookup(t, npc->npc_alen, addr) == 0;
191 }
192