From owner-freebsd-net@FreeBSD.ORG Fri Apr 11 09:03:39 2008 Return-Path: Delivered-To: freebsd-net@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 126481065673 for ; Fri, 11 Apr 2008 09:03:39 +0000 (UTC) (envelope-from mjl@luckie.org.nz) Received: from mailfilter5.ihug.co.nz (mailfilter5.ihug.co.nz [203.109.136.5]) by mx1.freebsd.org (Postfix) with ESMTP id B17AA8FC0C for ; Fri, 11 Apr 2008 09:03:38 +0000 (UTC) (envelope-from mjl@luckie.org.nz) X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: AgoFAGe//kd2XAcy/2dsb2JhbACBXao/ X-IronPort-AV: E=Sophos;i="4.25,640,1199617200"; d="scan'208";a="88958481" Ironport-Content-Filter: send-to-smtp Ironport-OCF: send-to-smtp Received: from 118-92-7-50.dsl.dyn.ihug.co.nz (HELO spandex.luckie.org.nz) ([118.92.7.50]) by smtp.mailfilter5.ihug.co.nz with ESMTP/TLS/DHE-RSA-AES256-SHA; 11 Apr 2008 20:33:42 +1200 Received: from rayon.luckie.org.nz ([192.168.1.25]) by spandex.luckie.org.nz with esmtpsa (TLSv1:AES256-SHA:256) (Exim 4.69 (FreeBSD)) (envelope-from ) id 1JkEhZ-0007U7-Dp for freebsd-net@freebsd.org; Fri, 11 Apr 2008 20:33:41 +1200 Message-ID: <47FF2265.2050308@luckie.org.nz> Date: Fri, 11 Apr 2008 20:33:41 +1200 From: Matthew Luckie User-Agent: Thunderbird 2.0.0.9 (X11/20080129) MIME-Version: 1.0 To: freebsd-net@freebsd.org Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Subject: BPF JIT compiler X-BeenThere: freebsd-net@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Networking and TCP/IP with FreeBSD List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 11 Apr 2008 09:03:39 -0000 The existing intel BPF JIT compiler has one flaw. sys/net/bpf_filter.c initialises the A and X registers to zero when called. The just in time compiler does not. This means the JIT compiler will behave differently to the interpreter on any filter that does not set the A or X registers before using them. One approach is to put two additional ops in the procedure header of all compiled filters to zero these registers. This is the easiest thing to do, though it does mean a slower JIT compiler. Another approach is to reject any filter that might use A or X before setting it. This approach is really no different to having code check the filter and conditionally include zero operations if necessary. Below is a recursive function to check if A or X need to be set in the procedure header. This function would go in bpf_jitter.c and set two additional struct members in bpf_jit_filter to allow the machdep code to do the right thing. To my way of thinking, the bpf_insn_seta, bpf_insn_usea, bpf_insn_setx, bpf_insn_seta functions could perhaps be macros. Of greater concern to me is any policy that may exist on recursion in the kernel. Comments, please. jkim@ is busy with other things, so if you're interested, please speak up. static int bpf_insn_seta(const struct bpf_insn *ins) { if(BPF_CLASS(ins->code) == BPF_LD || ins->code == (BPF_MISC|BPF_TXA)) { return 1; } return 0; } static int bpf_insn_usea(const struct bpf_insn *ins) { if(BPF_CLASS(ins->code) == BPF_ALU || (BPF_CLASS(ins->code) == BPF_JMP && BPF_OP(ins->code) != BPF_JA) || ins->code == (BPF_RET|BPF_A) || ins->code == (BPF_ST) || ins->code == (BPF_MISC|BPF_TAX)) { return 1; } return 0; } static int bpf_insn_setx(const struct bpf_insn *ins) { if(BPF_CLASS(ins->code) == BPF_LDX || ins->code == (BPF_MISC|BPF_TAX)) { return 1; } return 0; } static int bpf_insn_usex(const struct bpf_insn *ins) { if((BPF_CLASS(ins->code) == BPF_ALU && BPF_SRC(ins->code) == BPF_X) || (BPF_CLASS(ins->code) == BPF_LD && BPF_MODE(ins->code) == BPF_IND) || (BPF_CLASS(ins->code) == BPF_JMP && BPF_SRC(ins->code) == BPF_X) || ins->code == (BPF_STX) || ins->code == (BPF_MISC|BPF_TXA)) { return 1; } return 0; } /* * bpf_ax * * determine if we need to initialise the accumulator and index * registers. */ static void bpf_ax(const struct bpf_insn *fp, int i, int nins, int *a, int *x) { const struct bpf_insn *ins; int a1, a2, x1, x2; while(icode) == BPF_JMP) { if(BPF_OP(ins->code) == BPF_JA) { bpf_ax(fp, i+1+ins->k, nins, a, x); } else { a1 = a2 = *a; x1 = x2 = *x; bpf_ax(fp, i+1+ins->jt, nins, &a1, &x1); bpf_ax(fp, i+1+ins->jf, nins, &a2, &x2); if(a1 == 1 || a2 == 1) *a = 1; else *a = 0; if(x1 == 1 || x2 == 1) *x = 1; else *x = 0; } break; } i++; } if(*a != 1) *a = 0; if(*x != 1) *x = 0; return; }