Index: external/bsd/libpcap/dist/bpf_filter.c =================================================================== RCS file: /cvsroot/src/external/bsd/libpcap/dist/bpf_filter.c,v retrieving revision 1.6 diff -u -p -u -r1.6 bpf_filter.c --- external/bsd/libpcap/dist/bpf_filter.c 2 Sep 2024 15:33:36 -0000 1.6 +++ external/bsd/libpcap/dist/bpf_filter.c 5 Sep 2026 21:38:56 -0000 @@ -86,18 +86,32 @@ enum { */ #if defined(SKF_AD_VLAN_TAG_PRESENT) u_int -pcapint_filter_with_aux_data(const struct bpf_insn *pc, const u_char *p, - u_int wirelen, u_int buflen, const struct pcap_bpf_aux_data *aux_data) +pcapint_filter_with_aux_data(const struct bpf_insn *pc, u_int proglen, + const u_char *p, u_int wirelen, u_int buflen, + const struct pcap_bpf_aux_data *aux_data) #else u_int -pcapint_filter_with_aux_data(const struct bpf_insn *pc, const u_char *p, - u_int wirelen, u_int buflen, const struct pcap_bpf_aux_data *aux_data _U_) +pcapint_filter_with_aux_data(const struct bpf_insn *pc, u_int proglen, + const u_char *p, u_int wirelen, u_int buflen, + const struct pcap_bpf_aux_data *aux_data _U_) #endif { register uint32_t A, X; register bpf_u_int32 k; uint32_t mem[BPF_MEMWORDS]; + /* + * If 'proglen' is not zero, it tells the number of instructions in the + * program, in which case discard the packet as soon as the program + * counter points beyond the program end (this also covers 'pclimit' + * wrapping due to an overflow). + */ + const struct bpf_insn *pclimit = pc + proglen; + + /* + * If 'pc' is NULL, the program has no instructions regardless of the + * value of 'proglen'. + */ if (pc == 0) /* * No filter means accept all. @@ -108,10 +122,12 @@ pcapint_filter_with_aux_data(const struc --pc; for (;;) { ++pc; + if (proglen && pc >= pclimit) + return 0; switch (pc->code) { default: - abort(); + return 0; case BPF_RET|BPF_K: return (u_int)pc->k; @@ -219,18 +235,26 @@ DIAG_ON_DEFAULT_ONLY_SWITCH continue; case BPF_LD|BPF_MEM: + if (pc->k >= BPF_MEMWORDS) + return 0; A = mem[pc->k]; continue; case BPF_LDX|BPF_MEM: + if (pc->k >= BPF_MEMWORDS) + return 0; X = mem[pc->k]; continue; case BPF_ST: + if (pc->k >= BPF_MEMWORDS) + return 0; mem[pc->k] = A; continue; case BPF_STX: + if (pc->k >= BPF_MEMWORDS) + return 0; mem[pc->k] = X; continue; @@ -391,16 +415,98 @@ u_int pcapint_filter(const struct bpf_insn *pc, const u_char *p, u_int wirelen, u_int buflen) { - return pcapint_filter_with_aux_data(pc, p, wirelen, buflen, NULL); + /* + * In this implementation of this function the filter program length is + * not known, so it is impossible to use the program end guard, but it + * is not necessary: this function always receives a program that has + * been validated in the course of a setfilter_op invocation. + */ + return pcapint_filter_with_aux_data(pc, 0, p, wirelen, buflen, NULL); +} + +/* + * Return true if the instruction is valid, as far as is possible to tell + * without knowing what the rest of the filter program is. + */ +static uint8_t +pcapint_valid_insn(const struct bpf_insn *insn) +{ + /* + * Require the opcode to be valid, for particular opcodes also require + * the value of k to be valid. The list of opcodes below is exactly + * the same as in bpf_filter() to make it easier to cross-reference. + */ + switch (insn->code) { + case BPF_RET|BPF_K: + case BPF_RET|BPF_A: + case BPF_LD|BPF_W|BPF_ABS: + case BPF_LD|BPF_H|BPF_ABS: + case BPF_LD|BPF_B|BPF_ABS: + case BPF_LD|BPF_W|BPF_LEN: + case BPF_LDX|BPF_W|BPF_LEN: + case BPF_LD|BPF_W|BPF_IND: + case BPF_LD|BPF_H|BPF_IND: + case BPF_LD|BPF_B|BPF_IND: + case BPF_LDX|BPF_MSH|BPF_B: + /* + * There's no maximum packet data size + * in userland. The runtime packet length + * check suffices. + */ + case BPF_LD|BPF_IMM: + case BPF_LDX|BPF_IMM: + return 1; + case BPF_LD|BPF_MEM: + case BPF_LDX|BPF_MEM: + case BPF_ST: + case BPF_STX: + // Reject a non-existent scratch memory register. + return insn->k < BPF_MEMWORDS; + case BPF_JMP|BPF_JA: + case BPF_JMP|BPF_JGT|BPF_K: + case BPF_JMP|BPF_JGE|BPF_K: + case BPF_JMP|BPF_JEQ|BPF_K: + case BPF_JMP|BPF_JSET|BPF_K: + case BPF_JMP|BPF_JGT|BPF_X: + case BPF_JMP|BPF_JGE|BPF_X: + case BPF_JMP|BPF_JEQ|BPF_X: + case BPF_JMP|BPF_JSET|BPF_X: + case BPF_ALU|BPF_ADD|BPF_X: + case BPF_ALU|BPF_SUB|BPF_X: + case BPF_ALU|BPF_MUL|BPF_X: + case BPF_ALU|BPF_DIV|BPF_X: + case BPF_ALU|BPF_MOD|BPF_X: + case BPF_ALU|BPF_AND|BPF_X: + case BPF_ALU|BPF_OR|BPF_X: + case BPF_ALU|BPF_XOR|BPF_X: + case BPF_ALU|BPF_LSH|BPF_X: + case BPF_ALU|BPF_RSH|BPF_X: + case BPF_ALU|BPF_ADD|BPF_K: + case BPF_ALU|BPF_SUB|BPF_K: + case BPF_ALU|BPF_MUL|BPF_K: + return 1; + case BPF_ALU|BPF_DIV|BPF_K: + case BPF_ALU|BPF_MOD|BPF_K: + // Reject a constant division or modulus by 0. + return insn->k != 0; + case BPF_ALU|BPF_AND|BPF_K: + case BPF_ALU|BPF_OR|BPF_K: + case BPF_ALU|BPF_XOR|BPF_K: + case BPF_ALU|BPF_LSH|BPF_K: + case BPF_ALU|BPF_RSH|BPF_K: + case BPF_ALU|BPF_NEG: + case BPF_MISC|BPF_TAX: + case BPF_MISC|BPF_TXA: + return 1; + } + // Reject an invalid opcode. + return 0; } /* * Return true if the 'fcode' is a valid filter program. * The constraints are that each jump be forward and to a valid - * code, that memory accesses are within valid ranges (to the - * extent that this can be checked statically; loads of packet - * data have to be, and are, also checked at run time), and that - * the code terminates with either an accept or reject. + * code and that the code terminates with either an accept or reject. * * The kernel needs to be able to verify an application's filter code. * Otherwise, a bogus program could easily crash the system. @@ -416,64 +522,9 @@ pcapint_validate_filter(const struct bpf for (i = 0; i < (u_int)len; ++i) { p = &f[i]; + if (! pcapint_valid_insn(p)) + return 0; switch (BPF_CLASS(p->code)) { - /* - * Check that memory operations use valid addresses. - */ - case BPF_LD: - case BPF_LDX: - switch (BPF_MODE(p->code)) { - case BPF_IMM: - break; - case BPF_ABS: - case BPF_IND: - case BPF_MSH: - /* - * There's no maximum packet data size - * in userland. The runtime packet length - * check suffices. - */ - break; - case BPF_MEM: - if (p->k >= BPF_MEMWORDS) - return 0; - break; - case BPF_LEN: - break; - default: - return 0; - } - break; - case BPF_ST: - case BPF_STX: - if (p->k >= BPF_MEMWORDS) - return 0; - break; - case BPF_ALU: - switch (BPF_OP(p->code)) { - case BPF_ADD: - case BPF_SUB: - case BPF_MUL: - case BPF_OR: - case BPF_AND: - case BPF_XOR: - case BPF_LSH: - case BPF_RSH: - case BPF_NEG: - break; - case BPF_DIV: - case BPF_MOD: - /* - * Check for constant division or modulus - * by 0. - */ - if (BPF_SRC(p->code) == BPF_K && p->k == 0) - return 0; - break; - default: - return 0; - } - break; case BPF_JMP: /* * Check that jumps are within the code block, @@ -514,16 +565,7 @@ pcapint_validate_filter(const struct bpf if (from + p->jt >= (u_int)len || from + p->jf >= (u_int)len) return 0; break; - default: - return 0; } - break; - case BPF_RET: - break; - case BPF_MISC: - break; - default: - return 0; } } return BPF_CLASS(f[len - 1].code) == BPF_RET; Index: external/bsd/libpcap/dist/pcap-int.h =================================================================== RCS file: /cvsroot/src/external/bsd/libpcap/dist/pcap-int.h,v retrieving revision 1.10 diff -u -p -u -r1.10 pcap-int.h --- external/bsd/libpcap/dist/pcap-int.h 18 Mar 2026 23:43:20 -0000 1.10 +++ external/bsd/libpcap/dist/pcap-int.h 5 Sep 2026 21:38:57 -0000 @@ -582,11 +582,12 @@ struct pcap_bpf_aux_data { #endif /* - * Filtering routine that takes the auxiliary data as an additional - * argument. + * Filtering routine that takes the program length and the auxiliary data as + * additional arguments. */ -u_int pcapint_filter_with_aux_data(const struct bpf_insn *, - const u_char *, u_int, u_int, const struct pcap_bpf_aux_data *); +u_int pcapint_filter_with_aux_data(const struct bpf_insn *, const u_int, + const u_char *, const u_int, const u_int, + const struct pcap_bpf_aux_data *); /* * Filtering routine that doesn't. Index: external/bsd/libpcap/dist/pcap-linux.c =================================================================== RCS file: /cvsroot/src/external/bsd/libpcap/dist/pcap-linux.c,v retrieving revision 1.9 diff -u -p -u -r1.9 pcap-linux.c --- external/bsd/libpcap/dist/pcap-linux.c 18 Mar 2026 23:43:20 -0000 1.9 +++ external/bsd/libpcap/dist/pcap-linux.c 5 Sep 2026 21:38:57 -0000 @@ -4283,7 +4283,12 @@ static int pcap_handle_packet_mmap( aux_data.vlan_tag_present = tp_vlan_tci_valid; aux_data.vlan_tag = tp_vlan_tci & 0x0fff; + /* + * Belt and braces: use the filter program end guard even though the + * program has been validated via pcap_setfilter_linux(). + */ if (pcapint_filter_with_aux_data(handle->fcode.bf_insns, + handle->fcode.bf_len, bp, tp_len, snaplen, Index: external/bsd/libpcap/dist/pcap-rpcap-unix.c =================================================================== RCS file: /cvsroot/src/external/bsd/libpcap/dist/pcap-rpcap-unix.c,v retrieving revision 1.4 diff -u -p -u -r1.4 pcap-rpcap-unix.c --- external/bsd/libpcap/dist/pcap-rpcap-unix.c 2 Sep 2024 15:33:37 -0000 1.4 +++ external/bsd/libpcap/dist/pcap-rpcap-unix.c 5 Sep 2026 21:38:57 -0000 @@ -527,7 +527,9 @@ rpcap_read_unix(pcap_t *handle, int max_ } if (handle->fcode.bf_insns == NULL || - bpf_filter(handle->fcode.bf_insns, pkt, pkth.len, pkth.caplen)) + bpf_nfilter(handle->fcode.bf_insns, + handle->fcode.bf_len, + pkt, pkth.len, pkth.caplen)) { // handle->md.packets_read++; callback(user, &pkth, pkt); Index: external/bsd/libpcap/dist/pcap.c =================================================================== RCS file: /cvsroot/src/external/bsd/libpcap/dist/pcap.c,v retrieving revision 1.13 diff -u -p -u -r1.13 pcap.c --- external/bsd/libpcap/dist/pcap.c 18 Mar 2026 23:43:20 -0000 1.13 +++ external/bsd/libpcap/dist/pcap.c 5 Sep 2026 21:38:57 -0000 @@ -4355,12 +4355,14 @@ int pcap_offline_filter(const struct bpf_program *fp, const struct pcap_pkthdr *h, const u_char *pkt) { - const struct bpf_insn *fcode = fp->bf_insns; - - if (fcode != NULL) - return (pcapint_filter(fcode, pkt, h->len, h->caplen)); - else + if (fp->bf_insns == NULL) return (0); + /* + * In case the filter program has not been validated, use the program + * end guard. + */ + return pcapint_filter_with_aux_data(fp->bf_insns, fp->bf_len, pkt, + h->len, h->caplen, NULL); } static int Index: external/bsd/libpcap/dist/pcap_offline_filter.3pcap =================================================================== RCS file: /cvsroot/src/external/bsd/libpcap/dist/pcap_offline_filter.3pcap,v retrieving revision 1.6 diff -u -p -u -r1.6 pcap_offline_filter.3pcap --- external/bsd/libpcap/dist/pcap_offline_filter.3pcap 2 Sep 2024 15:33:38 -0000 1.6 +++ external/bsd/libpcap/dist/pcap_offline_filter.3pcap 5 Sep 2026 21:38:57 -0000 @@ -17,7 +17,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_OFFLINE_FILTER 3PCAP "7 April 2014" +.TH PCAP_OFFLINE_FILTER 3PCAP "12 March 2026" .SH NAME pcap_offline_filter \- check whether a filter matches a packet .SH SYNOPSIS @@ -45,10 +45,36 @@ points to the structure for the packet, and .I pkt points to the data in the packet. +.PP +In the +.B \%bpf_program +structure the +.B \%bf_insns +member is either +.B NULL +(which means an empty filter program, which accepts all packets) or points to +an array of one or more +.B \%struct bpf_insn +elements. In the latter case the +.B \%bf_len +member is set either to the number of elements (this is what +.BR \%pcap_compile () +produces). +.PP +The filter program must have been compiled for a link-layer header type +that matches the packet data; also on Linux the filter must not use +BPF extensions, see +.BR \%pcap_compile () +for more information. .SH RETURN VALUE .BR pcap_offline_filter () returns the return value of the filter program. This will be zero if the packet doesn't match the filter and non-zero if the packet matches the filter. +.SH BACKWARD COMPATIBILITY +.PP +In libpcap releases before 1.10.7 this function ignored the provided +.B \%bf_len +value. .SH SEE ALSO .BR pcap (3PCAP) Index: external/bsd/libpcap/dist/testprogs/nonblocktest.c =================================================================== RCS file: /cvsroot/src/external/bsd/libpcap/dist/testprogs/nonblocktest.c,v retrieving revision 1.1.1.1 diff -u -p -u -r1.1.1.1 nonblocktest.c --- external/bsd/libpcap/dist/testprogs/nonblocktest.c 17 Aug 2023 13:11:04 -0000 1.1.1.1 +++ external/bsd/libpcap/dist/testprogs/nonblocktest.c 5 Sep 2026 21:38:57 -0000 @@ -43,7 +43,7 @@ #include static pcap_t *pd; -static char *program_name = "nonblocktest"; +static const char *program_name = "nonblocktest"; /* Forwards */ static void PCAP_NORETURN usage(void); static void PCAP_NORETURN error(const char *, ...) PCAP_PRINTFLIKE(1, 2); Index: external/bsd/libpcap/lib/pcap.expsym =================================================================== RCS file: /cvsroot/src/external/bsd/libpcap/lib/pcap.expsym,v retrieving revision 1.2 diff -u -p -u -r1.2 pcap.expsym --- external/bsd/libpcap/lib/pcap.expsym 18 Mar 2026 23:43:21 -0000 1.2 +++ external/bsd/libpcap/lib/pcap.expsym 5 Sep 2026 21:38:57 -0000 @@ -3,7 +3,9 @@ __pcap_atoin __pcap_nametodnaddr bpf_dump bpf_filter +bpf_filter_with_aux_data bpf_image +bpf_nfilter bpf_optimize bpf_set_error bpf_validate @@ -216,6 +218,7 @@ pcapint_create_interface pcapint_createsrcstr_ex pcapint_do_addexit pcapint_filter +pcapint_filter_with_aux_data pcapint_find_dev pcapint_find_or_add_dev pcapint_find_or_add_if @@ -236,6 +239,7 @@ pcapint_setnonblock_fd pcapint_sf_cleanup pcapint_strcasecmp pcapint_utf_8_mode +pcapint_valid_insn pcapint_validate_filter pcapint_vfmt_errmsg_for_errno rpcap_create Index: sys/external/bsd/ipf/netinet/fil.c =================================================================== RCS file: /cvsroot/src/sys/external/bsd/ipf/netinet/fil.c,v retrieving revision 1.39 diff -u -p -u -r1.39 fil.c --- sys/external/bsd/ipf/netinet/fil.c 24 Jul 2026 23:41:26 -0000 1.39 +++ sys/external/bsd/ipf/netinet/fil.c 5 Sep 2026 21:38:57 -0000 @@ -2453,7 +2453,9 @@ ipf_scanlist(fr_info_t *fin, u_32_t pass continue; mc = (u_char *)fin->fin_m; wlen = fin->fin_dlen + fin->fin_hlen; - if (!bpf_filter(fr->fr_data, mc, wlen, 0)) + if (!bpf_nfilter(fr->fr_data, + fr->fr_dsize / sizeof(struct bpf_insn), + mc, wlen, 0)) continue; break; } Index: sys/net/bpf.c =================================================================== RCS file: /cvsroot/src/sys/net/bpf.c,v retrieving revision 1.258 diff -u -p -u -r1.258 bpf.c --- sys/net/bpf.c 20 Oct 2024 14:03:51 -0000 1.258 +++ sys/net/bpf.c 5 Sep 2026 21:38:57 -0000 @@ -1397,8 +1397,8 @@ bpf_setf(struct bpf_d *d, struct bpf_pro } newf = kmem_alloc(sizeof(*newf), KM_SLEEP); - newf->bf_insn = fcode; - newf->bf_size = size; + newf->bf_insns = fcode; + newf->bf_len = flen; newf->bf_jitcode = jcode; if (cmd == BIOCSETF) d->bd_jitcode = jcode; /* XXX just for kvm(3) users */ @@ -1679,23 +1679,24 @@ bpf_xfilter(struct bpf_filter **filter, { struct bpf_filter *filt; uint32_t mem[BPF_MEMWORDS]; + u_int slen; + + filt = atomic_load_consume(filter); + if (filt == NULL) /* No filter means accept all. */ + return (u_int)-1; + bpf_args_t args = { .pkt = (const uint8_t *)pkt, + .proglen = filt->bf_len, .wirelen = pktlen, .buflen = buflen, .mem = mem, .arg = NULL }; - u_int slen; - - filt = atomic_load_consume(filter); - if (filt == NULL) /* No filter means accept all. */ - return (u_int)-1; - if (filt->bf_jitcode != NULL) slen = filt->bf_jitcode(NULL, &args); else - slen = bpf_filter_ext(NULL, filt->bf_insn, &args); + slen = bpf_filter_ext(NULL, filt->bf_insns, &args); return slen; } @@ -2140,8 +2141,9 @@ bpf_free_filter(struct bpf_filter *filte KASSERT(filter != NULL); - if (filter->bf_insn != NULL) - kmem_free(filter->bf_insn, filter->bf_size); + if (filter->bf_insns != NULL) + kmem_free(filter->bf_insns, + filter->bf_len * sizeof(*filter->bf_insns)); if (filter->bf_jitcode != NULL) bpf_jit_freecode(filter->bf_jitcode); kmem_free(filter, sizeof(*filter)); Index: sys/net/bpf.h =================================================================== RCS file: /cvsroot/src/sys/net/bpf.h,v retrieving revision 1.82 diff -u -p -u -r1.82 bpf.h --- sys/net/bpf.h 23 Aug 2023 13:21:17 -0000 1.82 +++ sys/net/bpf.h 5 Sep 2026 21:38:57 -0000 @@ -392,6 +392,7 @@ typedef struct bpf_ctx bpf_ctx_t; typedef struct bpf_args { const uint8_t * pkt; + size_t proglen; size_t wirelen; size_t buflen; /* @@ -597,9 +598,13 @@ void bpf_jit_freecode(bpfjit_func_t); #endif int bpf_validate(const struct bpf_insn *, int); -u_int bpf_filter(const struct bpf_insn *, const u_char *, u_int, u_int); - -u_int bpf_filter_with_aux_data(const struct bpf_insn *, const u_char *, u_int, u_int, const struct bpf_aux_data *); +uint8_t pcapint_valid_insn(const struct bpf_insn *); +u_int bpf_filter(const struct bpf_insn *, const u_char *, u_int, u_int) + __attribute__((__deprecated__("Use pbf_nfilter"))); +u_int bpf_nfilter(const struct bpf_insn *, u_int, const u_char *, u_int, + u_int); +u_int bpf_filter_with_aux_data(const struct bpf_insn *, u_int, const u_char *, + u_int, u_int, const struct bpf_aux_data *); /* * events to be tracked by bpf_register_track_event callbacks Index: sys/net/bpf_filter.c =================================================================== RCS file: /cvsroot/src/sys/net/bpf_filter.c,v retrieving revision 1.73 diff -u -p -u -r1.73 bpf_filter.c --- sys/net/bpf_filter.c 2 Sep 2024 15:34:08 -0000 1.73 +++ sys/net/bpf_filter.c 5 Sep 2026 21:38:57 -0000 @@ -185,6 +185,41 @@ m_xbyte(const struct mbuf *m, uint32_t k #include +u_int +bpf_filter(const struct bpf_insn *pc, const u_char *p, u_int wirelen, + u_int buflen) +{ + /* + * In this implementation of this function the filter program length is + * not known, so it is impossible to use the program end guard, but it + * is not necessary: this function always receives a program that has + * been validated in the course of a setfilter_op invocation. + */ + return bpf_nfilter(pc, 0, p, wirelen, buflen); +} + +/* + * Kernel BPF implementations tend to define BPF_MAXINSNS to 512 or 4096, the + * userland interpreter in libpcap is meant to support much longer filter + * programs. In the latter case it is important that BPF_MAXINSNS does not + * interfere with the safety checks in the validator and the interpreter: + * (BPF_MAXINSNS + UINT8_MAX) * sizeof(struct bpf_insn) < UINT32_MAX + * It makes the most sense to be able to interpret as many instructions as + * pcap_compile() can produce, without optimization, for a valid filter + * expression before it consumes as much memory as the current definitions of + * NCHUNKS and CHUNKSIZE() allow. For some expressions this can be almost + * 1.53 million instructions on a 64-bit machine and twice as many on a 32-bit + * machine. + */ +#ifndef _KERNEL +#ifdef BPF_MAXINSNS +#undef BPF_MAXINSNS +#endif +#define BPF_MAXINSNS 3060000U +#endif + +#define MAX_BACKWARD_JUMPS 64U + /* * Execute the filter program starting at pc on the packet p * wirelen is the length of the original packet @@ -193,12 +228,13 @@ m_xbyte(const struct mbuf *m, uint32_t k #ifdef _KERNEL u_int -bpf_filter(const struct bpf_insn *pc, const u_char *p, u_int wirelen, - u_int buflen) +bpf_nfilter(const struct bpf_insn *pc, u_int proglen, const u_char *p, + u_int wirelen, u_int buflen) { - uint32_t mem[BPF_MEMWORDS]; + uint32_t mem[BPF_MAX_MEMWORDS]; bpf_args_t args = { .pkt = p, + .proglen = proglen, .wirelen = wirelen, .buflen = buflen, .mem = mem, @@ -211,10 +247,21 @@ bpf_filter(const struct bpf_insn *pc, co u_int bpf_filter_ext(const bpf_ctx_t *bc, const struct bpf_insn *pc, bpf_args_t *args) #else + __strong_alias(pcapint_filter, bpf_filter) +__strong_alias(pcapint_filter_with_aux_data, bpf_filter_with_aux_data) + u_int -bpf_filter(const struct bpf_insn *pc, const u_char *p, u_int wirelen, - u_int buflen) +bpf_nfilter(const struct bpf_insn *pc, u_int proglen, const u_char *p, + u_int wirelen, u_int buflen) +{ + return bpf_filter_with_aux_data(pc, proglen, p, wirelen, buflen, NULL); +} + +u_int +bpf_filter_with_aux_data(const struct bpf_insn *pc, const u_int proglen, + const u_char *p, const u_int wirelen, const u_int buflen, + const struct bpf_aux_data *arg) #endif { uint32_t A, X, k; @@ -222,41 +269,75 @@ bpf_filter(const struct bpf_insn *pc, co uint32_t mem[BPF_MEMWORDS]; bpf_args_t args_store = { .pkt = p, + .proglen = proglen, .wirelen = wirelen, .buflen = buflen, .mem = mem, - .arg = NULL + .arg = __UNCONST(arg) }; bpf_args_t * const args = &args_store; + const size_t memwords = BPF_MEMWORDS; +# define CHECK_BOUNDS() if (pc->k >= memwords) return 0 #else const uint8_t * const p = args->pkt; +# define CHECK_BOUNDS() __nothing #endif + /* + * If 'proglen' is not zero, it tells the number of instructions in the + * program, in which case discard the packet as soon as the program + * counter points beyond the program end (this also covers 'pcend' + * wrapping due to an overflow). + */ + if (args->proglen < 1 || args->proglen > BPF_MAXINSNS) + return 0; + + /* + * If 'pc' is NULL, the program has no instructions regardless of the + * value of 'proglen'. + */ if (pc == 0) { /* * No filter means accept all. + * In this case the value of 'proglen' is irrelevant */ return (u_int)-1; } /* + * Require the current instruction pointer not to overflow for both the + * filter program (where the pointer will be dereferenced) and an + * immediately following margin (where it will be not). So long as the + * margin is large enough to represent the destination of any single + * conditional [forward] jump from within the filter program, a single + * guard prevents all filter program over-read attempts that result + * from the program running out of instructions before a BPF_RET or a + * conditional jump directing the interpreter beyond the program end. + * Unconditional jumps mean a larger problem space, which the BPF_JA + * case below addresses separately. + */ + const struct bpf_insn *pcend = pc + args->proglen; + if (pcend + UINT8_MAX < pc) + return 0; + + /* * Note: safe to leave memwords uninitialised, as the validation * step ensures that it will not be read, if it was not written. */ A = 0; X = 0; + const struct bpf_insn *pc0 = pc; + unsigned backward_jumps = 0; --pc; for (;;) { ++pc; + if (pc >= pcend) + return 0; switch (pc->code) { default: -#ifdef _KERNEL return 0; -#else - abort(); - /*NOTREACHED*/ -#endif + case BPF_RET|BPF_K: return (u_int)pc->k; @@ -305,6 +386,25 @@ bpf_filter(const struct bpf_insn *pc, co case BPF_LD|BPF_B|BPF_ABS: k = pc->k; +#if !defined(_KERNEL) && defined(SKF_AD_VLAN_TAG_PRESENT) + struct bpf_aux_data *aux_data = args->arg; + switch (k) { + + case SKF_AD_OFF + SKF_AD_VLAN_TAG: + if (!aux_data) + return 0; + A = aux_data->vlan_tag; + continue; + + case SKF_AD_OFF + SKF_AD_VLAN_TAG_PRESENT: + if (!aux_data) + return 0; + A = aux_data->vlan_tag_present; + continue; + default: + break; + } +#endif if (k >= args->buflen) { #ifdef _KERNEL int merr; @@ -323,11 +423,11 @@ bpf_filter(const struct bpf_insn *pc, co continue; case BPF_LD|BPF_W|BPF_LEN: - A = args->wirelen; + A = (uint32_t)args->wirelen; continue; case BPF_LDX|BPF_W|BPF_LEN: - X = args->wirelen; + X = (uint32_t)args->wirelen; continue; case BPF_LD|BPF_W|BPF_IND: @@ -417,23 +517,77 @@ bpf_filter(const struct bpf_insn *pc, co continue; case BPF_LD|BPF_MEM: + CHECK_BOUNDS(); A = args->mem[pc->k]; continue; case BPF_LDX|BPF_MEM: + CHECK_BOUNDS(); X = args->mem[pc->k]; continue; case BPF_ST: + CHECK_BOUNDS(); args->mem[pc->k] = A; continue; case BPF_STX: + CHECK_BOUNDS(); args->mem[pc->k] = X; continue; case BPF_JMP|BPF_JA: - pc += pc->k; + /* + * The pointer (pc) decrements and increments in units + * of sizeof(struct bpf_insn) == 8 bytes. The number + * of units is in the [INT32_MIN, INT32_MAX] interval, + * hence the result can point before the beginning or + * beyond the end of the filter program and can under- + * or overflow; also on 32-bit architectures it can + * under- or overflow more than once and can test + * negative for underflow, overflow and out-of-range + * conditions after under- or overflowing at least + * once. + * + * However, it has been verified above that the program + * length is sufficiently small and the pointer does + * not wrap within the bounds of the filter program, so + * there is a one-to-one correspondence between BPF + * program counter values [0, proglen) and all valid + * values of the pointer. In other words, after this + * unconditional jump the pointer arithmetic result + * will be valid iff BPF program counter value will be + * valid. For the latter problem the solution is + * almost the same as in the validator. + * + * The main difference is that here the current value + * of BPF program counter is not a 32-bit unsigned + * variable, but a ptrdiff_t expression, which is + * 64-bit signed on 64-bit architectures and 32-bit + * signed on 32-bit architectures. However, the cast + * to 32-bit unsigned is safe in both cases because: + * pc0 <= pc < pc0 + proglen, therefore: + * 0 <= pc - pc0 < proglen <= BPF_MAXINSNS < INT32_MAX + */ + if ((bpf_u_int32)(pc - pc0) + 1 + pc->k >= args->proglen) + return 0; + /* + * Terminate the program if this is a non-forward jump + * and is: + * - a guaranteed infinite loop because it jumps to + * itself (exactly the same as in the validator), or + * - a backward jump after many enough backward jumps + * already made for this packet. + */ + if ((bpf_int32)pc->k < 0 && ((bpf_int32)pc->k == -1 || + backward_jumps++ >= MAX_BACKWARD_JUMPS)) + return 0; + + /* + * XXX - we currently implement "ip6 protochain" + * with backward jumps, so sign-extend pc->k. + */ + pc += (bpf_int32)pc->k; continue; case BPF_JMP|BPF_JGT|BPF_K: @@ -525,10 +679,14 @@ bpf_filter(const struct bpf_insn *pc, co continue; case BPF_ALU|BPF_DIV|BPF_K: + if (pc->k == 0) + return 0; A /= pc->k; continue; case BPF_ALU|BPF_MOD|BPF_K: + if (pc->k == 0) + return 0; A %= pc->k; continue; @@ -588,12 +746,93 @@ bpf_filter(const struct bpf_insn *pc, co } /* + * Return true if the instruction is valid, as far as is possible to tell + * without knowing what the rest of the filter program is. + */ +uint8_t +pcapint_valid_insn(const struct bpf_insn *insn) +{ + /* + * Require the opcode to be valid, for particular opcodes also require + * the value of k to be valid. The list of opcodes below is exactly + * the same as in bpf_filter() to make it easier to cross-reference. + */ + switch (insn->code) { + case BPF_RET|BPF_K: + case BPF_RET|BPF_A: + case BPF_LD|BPF_W|BPF_ABS: + case BPF_LD|BPF_H|BPF_ABS: + case BPF_LD|BPF_B|BPF_ABS: + case BPF_LD|BPF_W|BPF_LEN: + case BPF_LDX|BPF_W|BPF_LEN: + case BPF_LD|BPF_W|BPF_IND: + case BPF_LD|BPF_H|BPF_IND: + case BPF_LD|BPF_B|BPF_IND: + case BPF_LDX|BPF_MSH|BPF_B: + case BPF_LD|BPF_IMM: + case BPF_LDX|BPF_IMM: + return 1; + case BPF_LD|BPF_MEM: + case BPF_LDX|BPF_MEM: + case BPF_ST: + case BPF_STX: +#if defined(KERNEL) || defined(_KERNEL) + // Test is done inside validate with a variable length + return 1; +#else + // Reject a non-existent scratch memory register. + return insn->k < BPF_MEMWORDS; +#endif + + case BPF_JMP|BPF_JA: + case BPF_JMP|BPF_JGT|BPF_K: + case BPF_JMP|BPF_JGE|BPF_K: + case BPF_JMP|BPF_JEQ|BPF_K: + case BPF_JMP|BPF_JSET|BPF_K: + case BPF_JMP|BPF_JGT|BPF_X: + case BPF_JMP|BPF_JGE|BPF_X: + case BPF_JMP|BPF_JEQ|BPF_X: + case BPF_JMP|BPF_JSET|BPF_X: + case BPF_ALU|BPF_ADD|BPF_X: + case BPF_ALU|BPF_SUB|BPF_X: + case BPF_ALU|BPF_MUL|BPF_X: + case BPF_ALU|BPF_DIV|BPF_X: + case BPF_ALU|BPF_MOD|BPF_X: + case BPF_ALU|BPF_AND|BPF_X: + case BPF_ALU|BPF_OR|BPF_X: + case BPF_ALU|BPF_XOR|BPF_X: + case BPF_ALU|BPF_LSH|BPF_X: + case BPF_ALU|BPF_RSH|BPF_X: + case BPF_ALU|BPF_ADD|BPF_K: + case BPF_ALU|BPF_SUB|BPF_K: + case BPF_ALU|BPF_MUL|BPF_K: + return 1; + case BPF_ALU|BPF_DIV|BPF_K: + case BPF_ALU|BPF_MOD|BPF_K: + // Reject a constant division or modulus by 0. + return insn->k != 0; + case BPF_ALU|BPF_AND|BPF_K: + case BPF_ALU|BPF_OR|BPF_K: + case BPF_ALU|BPF_XOR|BPF_K: + case BPF_ALU|BPF_LSH|BPF_K: + case BPF_ALU|BPF_RSH|BPF_K: + case BPF_ALU|BPF_NEG: + case BPF_MISC|BPF_TAX: + case BPF_MISC|BPF_TXA: +#if defined(KERNEL) || defined(_KERNEL) + case BPF_MISC|BPF_COP: + case BPF_MISC|BPF_COPX: +#endif + return 1; + } + // Reject an invalid opcode. + return 0; +} + +/* * Return true if the 'fcode' is a valid filter program. * The constraints are that each jump be forward and to a valid - * code, that memory accesses are within valid ranges (to the - * extent that this can be checked statically; loads of packet - * data have to be, and are, also checked at run time), and that - * the code terminates with either an accept or reject. + * code and that the code terminates with either an accept or reject. * * The kernel needs to be able to verify an application's filter code. * Otherwise, a bogus program could easily crash the system. @@ -621,14 +860,14 @@ bpf_validate(const struct bpf_insn *f, i bpf_memword_init_t *mem, invalid; size_t size; const size_t extwords = bc ? bc->extwords : 0; - const size_t memwords = extwords ? extwords : BPF_MEMWORDS; + const size_t memwords = extwords ? extwords : BPF_MAX_MEMWORDS; const bpf_memword_init_t preinited = extwords ? bc->preinited : 0; #else const size_t memwords = BPF_MEMWORDS; #endif len = (u_int)signed_len; - if (len < 1) + if (len < 1 || (u_int)len > BPF_MAXINSNS || f + len < f) return 0; #if defined(KERNEL) || defined(_KERNEL) if (len > BPF_MAXINSNS) @@ -651,6 +890,8 @@ bpf_validate(const struct bpf_insn *f, i invalid |= mem[i]; #endif p = &f[i]; + if (! pcapint_valid_insn(p)) + return 0; switch (BPF_CLASS(p->code)) { /* * Check that memory operations use valid addresses. @@ -722,35 +963,58 @@ bpf_validate(const struct bpf_insn *f, i case BPF_JMP: /* * Check that jumps are within the code block, - * and that unconditional branches don't go - * backwards as a result of an overflow. + * regardless of the direction. libpcap uses + * backward jumps to implement the "protochain" + * primitive. All offsets that mean a backward + * jump in libpcap (whether in-range or not) in + * kernel BPF implementations mean out-of-range + * or overflow forward jumps -- kernel + * implementations must reject that. + * * Unconditional branches have a 32-bit offset, * so they could overflow; we check to make * sure they don't. Conditional branches have * an 8-bit offset, and the from address is <= - * BPF_MAXINSNS, and we assume that BPF_MAXINSNS + * BPF_MAXINSNS, and we know that BPF_MAXINSNS * is sufficiently small that adding 255 to it * won't overflow. * * We know that len is <= BPF_MAXINSNS, and we * assume that BPF_MAXINSNS is < the maximum size * of a u_int, so that i + 1 doesn't overflow. - * - * For userland, we don't know that the from - * or len are <= BPF_MAXINSNS, but we know that - * from <= len, and, except on a 64-bit system, - * it's unlikely that len, if it truly reflects - * the size of the program we've been handed, - * will be anywhere near the maximum size of - * a u_int. We also don't check for backward - * branches, as we currently support them in - * userland for the protochain operation. */ from = i + 1; switch (BPF_OP(p->code)) { case BPF_JA: + /* + * So long as both 'from' and bpf_insn.k are + * 32-bit unsigned, this check rejects any jump + * offset that points outside of the valid BPF + * address space of the filter program no + * matter whether signed interpretation of the + * offset is positive or negative. + * + * Note that this condition is necessary, but + * not sufficient to get correct results from + * respective pointer arithmetic in the process + * address space. Other necessary conditions + * are that BPF_MAXINSNS is correctly defined + * and enforced, and that the pointer does not + * overflow. + */ if (from + p->k >= len) goto out; + /* + * The only type of infinite loop that can be + * detected in this function is a "ja L" that + * jumps to itself. For this only k == -1 + * needs to be tested because the check above + * has already rejected all other values that + * would wrap the pointer equivalently on + * 32-bit architectures. + */ + if ((bpf_int32)p->k == -1) + goto out; #if defined(KERNEL) || defined(_KERNEL) if (from + p->k < from) goto out; Index: sys/net/bpfdesc.h =================================================================== RCS file: /cvsroot/src/sys/net/bpfdesc.h,v retrieving revision 1.50 diff -u -p -u -r1.50 bpfdesc.h --- sys/net/bpfdesc.h 19 Aug 2024 07:47:16 -0000 1.50 +++ sys/net/bpfdesc.h 5 Sep 2026 21:38:57 -0000 @@ -53,8 +53,9 @@ #endif struct bpf_filter { - struct bpf_insn *bf_insn; /* filter code */ - size_t bf_size; + /* like bpf_program */ + u_int bf_len; + struct bpf_insn *bf_insns; /* filter code */ bpfjit_func_t bf_jitcode; /* compiled filter program */ }; Index: sys/net/bpfjit.c =================================================================== RCS file: /cvsroot/src/sys/net/bpfjit.c,v retrieving revision 1.49 diff -u -p -u -r1.49 bpfjit.c --- sys/net/bpfjit.c 5 Jul 2026 17:29:13 -0000 1.49 +++ sys/net/bpfjit.c 5 Sep 2026 21:38:57 -0000 @@ -1287,7 +1287,7 @@ optimize_pass1(const bpf_ctx_t *bc, cons size_t i; uint32_t jt, jf; bpfjit_abc_length_t length; - bpf_memword_init_t invalid; /* borrowed from bpf_filter() */ + bpf_memword_init_t invalid; /* borrowed from bpf_nfilter() */ bool unreachable; const size_t memwords = GET_MEMWORDS(bc); @@ -1696,7 +1696,7 @@ kx_to_reg_arg(const struct bpf_insn *pc) static bool generate_insn_code(struct sljit_compiler *compiler, bpfjit_hint_t hints, const bpf_ctx_t *bc, const struct bpf_insn *insns, - struct bpfjit_insn_data *insn_dat, size_t insn_count) + struct bpfjit_insn_data *insn_dat, size_t insn_count, bool ignore_proglen) { /* a list of jumps to out-of-bound return from a generated function */ struct sljit_jump **ret0; @@ -1707,6 +1707,7 @@ generate_insn_code(struct sljit_compiler const struct bpf_insn *pc; struct bpfjit_jump *bjump, *jtf; struct sljit_jump *to_mchain_jump; + struct sljit_jump *insn_inrange_jump; size_t i; unsigned int mode, src, op; @@ -1740,12 +1741,61 @@ generate_insn_code(struct sljit_compiler jtf[0].sjump = jtf[1].sjump = NULL; } +#if defined(KERNEL) || defined(_KERNEL) + if (!ignore_proglen) { + /* if (args->proglen > BPF_MAXINSNS) return 0; */ + jump = sljit_emit_cmp(compiler, + SLJIT_GREATER, + SLJIT_MEM1(BJ_ARGS), + offsetof(struct bpf_args, proglen), + SLJIT_IMM, BPF_MAXINSNS); + if (jump == NULL) + goto fail; + if (!append_jump(jump, &ret0, &ret0_size, &ret0_maxsize)) + goto fail; + } +#endif /* main loop */ for (i = 0; i < insn_count; i++) { if (insn_dat[i].unreachable) continue; /* + * XXX Below, we check that i < proglen for every insns[i] + * but it's expensive. Add a simple optimisation pass that + * emits one check per basic block. + */ + if (!ignore_proglen && i > 0) { + status = sljit_emit_op1(compiler, + SLJIT_MOV, /* size_t source */ + BJ_TMP1REG, 0, + SLJIT_MEM1(BJ_ARGS), + offsetof(struct bpf_args, proglen)); + if (status != SLJIT_SUCCESS) + goto fail; + /* if (i < args->proglen) no further check needed */ + insn_inrange_jump = sljit_emit_cmp(compiler, + SLJIT_LESS, + SLJIT_IMM, i, + BJ_TMP1REG, 0); + if (insn_inrange_jump == NULL) + goto fail; + /* if (args->proglen != 0) return 0; */ + jump = sljit_emit_cmp(compiler, + SLJIT_NOT_EQUAL, + BJ_TMP1REG, 0, + SLJIT_IMM, 0); + if (jump == NULL) + goto fail; + if (!append_jump(jump, &ret0, &ret0_size, &ret0_maxsize)) + goto fail; + label = sljit_emit_label(compiler); + if (label == NULL) + goto fail; + sljit_set_label(insn_inrange_jump, label); + } + + /* * Resolve jumps to the current insn. */ label = NULL; @@ -2152,6 +2202,12 @@ bpfjit_func_t bpfjit_generate_code(const bpf_ctx_t *bc, const struct bpf_insn *insns, size_t insn_count) { + bool ignore_proglen = +#ifdef BPFJIT_IGNORE_PROGLEN + true; +#else + false; +#endif void *rv; struct sljit_compiler *compiler; @@ -2256,7 +2312,7 @@ bpfjit_generate_code(const bpf_ctx_t *bc initmask &= ~preinited | BJ_INIT_ABIT | BJ_INIT_XBIT; #if defined(_KERNEL) - /* bpf_filter() checks initialization of memwords. */ + /* bpf_nfilter() checks initialization of memwords. */ BJ_ASSERT((initmask & (BJ_INIT_MBIT(memwords) - 1)) == 0); #endif for (i = 0; i < memwords; i++) { @@ -2296,7 +2352,7 @@ bpfjit_generate_code(const bpf_ctx_t *bc goto fail; if (!generate_insn_code(compiler, hints, - bc, insns, insn_dat, insn_count)) { + bc, insns, insn_dat, insn_count, ignore_proglen)) { goto fail; } Index: sys/net/if_ppp.c =================================================================== RCS file: /cvsroot/src/sys/net/if_ppp.c,v retrieving revision 1.173 diff -u -p -u -r1.173 if_ppp.c --- sys/net/if_ppp.c 5 Jul 2024 04:31:53 -0000 1.173 +++ sys/net/if_ppp.c 5 Sep 2026 21:38:57 -0000 @@ -980,7 +980,8 @@ pppoutput(struct ifnet *ifp, struct mbuf * but only if it is a data packet. */ if (sc->sc_pass_filt_out.bf_insns != 0 && - bpf_filter(sc->sc_pass_filt_out.bf_insns, + bpf_nfilter(sc->sc_pass_filt_out.bf_insns, + sc->sc_pass_filt_out.bf_len, (u_char *)m0, len, 0) == 0) { error = 0; /* drop this packet */ goto bad; @@ -990,7 +991,8 @@ pppoutput(struct ifnet *ifp, struct mbuf * Update the time we sent the most recent packet. */ if (sc->sc_active_filt_out.bf_insns == 0 || - bpf_filter(sc->sc_active_filt_out.bf_insns, + bpf_nfilter(sc->sc_active_filt_out.bf_insns, + sc->sc_active_filt_out.bf_len, (u_char *)m0, len, 0)) sc->sc_last_sent = time_second; #else @@ -1645,14 +1647,16 @@ ppp_inproc(struct ppp_softc *sc, struct * if it counts as link activity. */ if (sc->sc_pass_filt_in.bf_insns != 0 && - bpf_filter(sc->sc_pass_filt_in.bf_insns, + bpf_nfilter(sc->sc_pass_filt_in.bf_insns, + sc->sc_pass_filt_in.bf_len, (u_char *)m, ilen, 0) == 0) { /* drop this packet */ m_freem(m); return; } if (sc->sc_active_filt_in.bf_insns == 0 || - bpf_filter(sc->sc_active_filt_in.bf_insns, + bpf_nfilter(sc->sc_active_filt_in.bf_insns, + sc->sc_active_filt_in.bf_len, (u_char *)m, ilen, 0)) sc->sc_last_recv = time_second; #else Index: sys/net/if_spppsubr.c =================================================================== RCS file: /cvsroot/src/sys/net/if_spppsubr.c,v retrieving revision 1.308 diff -u -p -u -r1.308 if_spppsubr.c --- sys/net/if_spppsubr.c 28 Jul 2026 07:10:42 -0000 1.308 +++ sys/net/if_spppsubr.c 5 Sep 2026 21:38:57 -0000 @@ -908,7 +908,8 @@ sppp_output(struct ifnet *ifp, struct mb } #ifdef SPPP_FILTER if (sp->pp_dial_filt.bf_insns != NULL && - bpf_filter(sp->pp_dial_filt.bf_insns, + bpf_nfilter(sp->pp_dial_filt.bf_insns, + sp->pp_dial_filt.bf_len, (u_char *)m, m_length(m), 0) == 0) { SPPP_UNLOCK(sp); @@ -6781,7 +6782,7 @@ sppp_update_last_activity(struct sppp *s pserialize_read_exit(s); if (sb == NULL || - bpf_filter(sb->sb_insns, (u_char *)m, m_length(m), 0)) + bpf_nfilter(sb->sb_insns, sb->sb_len, (u_char *)m, m_length(m), 0)) atomic_store_relaxed(&sp->pp_last_activity, time_uptime32); if (sb != NULL) { Index: sys/net/npf/npf_bpf.c =================================================================== RCS file: /cvsroot/src/sys/net/npf/npf_bpf.c,v retrieving revision 1.14 diff -u -p -u -r1.14 npf_bpf.c --- sys/net/npf/npf_bpf.c 29 Sep 2018 14:41:36 -0000 1.14 +++ sys/net/npf/npf_bpf.c 5 Sep 2026 21:38:57 -0000 @@ -123,13 +123,15 @@ npf_bpf_prepare(npf_cache_t *npc, bpf_ar } int -npf_bpf_filter(bpf_args_t *args, const void *code, bpfjit_func_t jcode) +npf_bpf_filter(bpf_args_t *args, const void *code, size_t clen, + bpfjit_func_t jcode) { /* Execute JIT-compiled code. */ if (__predict_true(jcode)) { return jcode(npf_bpfctx, args); } + args->proglen = clen; /* Execute BPF byte-code. */ return bpf_filter_ext(npf_bpfctx, code, args); } @@ -144,6 +146,8 @@ bool npf_bpf_validate(const void *code, size_t len) { const size_t icount = len / sizeof(struct bpf_insn); + if (icount * sizeof(struct bpf_insn) != len) + return false; return bpf_validate_ext(npf_bpfctx, code, icount) != 0; } Index: sys/net/npf/npf_impl.h =================================================================== RCS file: /cvsroot/src/sys/net/npf/npf_impl.h,v retrieving revision 1.86 diff -u -p -u -r1.86 npf_impl.h --- sys/net/npf/npf_impl.h 8 Apr 2026 00:33:07 -0000 1.86 +++ sys/net/npf/npf_impl.h 5 Sep 2026 21:38:57 -0000 @@ -376,7 +376,8 @@ bool npf_return_block(npf_cache_t *, co void npf_bpf_sysinit(void); void npf_bpf_sysfini(void); void npf_bpf_prepare(npf_cache_t *, bpf_args_t *, uint32_t *); -int npf_bpf_filter(bpf_args_t *, const void *, bpfjit_func_t); +int npf_bpf_filter(bpf_args_t *, const void *, size_t, + bpfjit_func_t); void * npf_bpf_compile(void *, size_t); bool npf_bpf_validate(const void *, size_t); Index: sys/net/npf/npf_ruleset.c =================================================================== RCS file: /cvsroot/src/sys/net/npf/npf_ruleset.c,v retrieving revision 1.58 diff -u -p -u -r1.58 npf_ruleset.c --- sys/net/npf/npf_ruleset.c 1 Sep 2026 19:04:48 -0000 1.58 +++ sys/net/npf/npf_ruleset.c 5 Sep 2026 21:38:57 -0000 @@ -861,7 +861,8 @@ npf_rule_inspect(const npf_rule_t *rl, b return true; } KASSERT(rl->r_type == NPF_CODE_BPF); - return npf_bpf_filter(bc_args, rl->r_code, rl->r_jcode) != 0; + return npf_bpf_filter(bc_args, rl->r_code, + rl->r_clen / sizeof(struct bpf_insn), rl->r_jcode) != 0; } /* Index: sys/rump/librump/rumpnet/net_stub.c =================================================================== RCS file: /cvsroot/src/sys/rump/librump/rumpnet/net_stub.c,v retrieving revision 1.50 diff -u -p -u -r1.50 net_stub.c --- sys/rump/librump/rumpnet/net_stub.c 28 Jul 2026 07:10:43 -0000 1.50 +++ sys/rump/librump/rumpnet/net_stub.c 5 Sep 2026 21:38:57 -0000 @@ -115,6 +115,7 @@ __weak_alias(tbr_dequeue,rumpnet_stub); /* bpf */ __weak_alias(bpf_validate, rumpnet_stub); __weak_alias(bpf_filter, rumpnet_stub); +__weak_alias(bpf_nfilter, rumpnet_stub); struct ifnet_head ifnet_list; struct pslist_head ifnet_pslist; Index: tests/lib/libbpfjit/t_bpfjit.c =================================================================== RCS file: /cvsroot/src/tests/lib/libbpfjit/t_bpfjit.c,v retrieving revision 1.16 diff -u -p -u -r1.16 t_bpfjit.c --- tests/lib/libbpfjit/t_bpfjit.c 5 Jul 2026 17:29:13 -0000 1.16 +++ tests/lib/libbpfjit/t_bpfjit.c 5 Sep 2026 21:38:57 -0000 @@ -3105,7 +3105,7 @@ ATF_TC_BODY(libbpfjit_ld_ind_x_overflow1 ATF_REQUIRE(code != NULL); for (i = 1; i <= sizeof(pkt); i++) { - ATF_CHECK(bpf_filter(insns, pkt, i, i) == 10 * i); + ATF_CHECK(bpf_nfilter(insns, insn_count, pkt, i, i) == 10 * i); ATF_CHECK(jitcall(code, pkt, i, i) == 10 * i); } @@ -3142,7 +3142,7 @@ ATF_TC_BODY(libbpfjit_ld_ind_x_overflow2 ATF_REQUIRE(code != NULL); for (i = 1; i <= sizeof(pkt); i++) { - ATF_CHECK(bpf_filter(insns, pkt, i, i) == 10 * i); + ATF_CHECK(bpf_nfilter(insns, insn_count, pkt, i, i) == 10 * i); ATF_CHECK(jitcall(code, pkt, i, i) == 10 * i); } Index: tests/lib/libbpfjit/t_cop.c =================================================================== RCS file: /cvsroot/src/tests/lib/libbpfjit/t_cop.c,v retrieving revision 1.4 diff -u -p -u -r1.4 t_cop.c --- tests/lib/libbpfjit/t_cop.c 13 Jul 2014 21:35:33 -0000 1.4 +++ tests/lib/libbpfjit/t_cop.c 5 Sep 2026 21:38:57 -0000 @@ -144,6 +144,7 @@ ATF_TC_BODY(libbpfjit_cop_ret_A, tc) uint8_t pkt[1] = { 0 }; bpf_args_t args = { .pkt = pkt, + .proglen = 0, .buflen = sizeof(pkt), .wirelen = sizeof(pkt), }; @@ -177,6 +178,7 @@ ATF_TC_BODY(libbpfjit_cop_ret_buflen, tc uint8_t pkt[1] = { 0 }; bpf_args_t args = { .pkt = pkt, + .proglen = 0, .buflen = sizeof(pkt), .wirelen = sizeof(pkt) }; @@ -210,6 +212,7 @@ ATF_TC_BODY(libbpfjit_cop_ret_wirelen, t uint8_t pkt[1] = { 0 }; bpf_args_t args = { .pkt = pkt, + .proglen = 0, .buflen = sizeof(pkt), .wirelen = sizeof(pkt) }; @@ -243,6 +246,7 @@ ATF_TC_BODY(libbpfjit_cop_ret_nfuncs, tc uint8_t pkt[1] = { 0 }; bpf_args_t args = { .pkt = pkt, + .proglen = 0, .buflen = sizeof(pkt), .wirelen = sizeof(pkt) }; @@ -279,6 +283,7 @@ ATF_TC_BODY(libbpfjit_cop_side_effect, t uint8_t pkt[1] = { 0 }; bpf_args_t args = { .pkt = pkt, + .proglen = 0, .buflen = sizeof(pkt), .wirelen = sizeof(pkt), .mem = NULL, @@ -321,6 +326,7 @@ ATF_TC_BODY(libbpfjit_cop_copx, tc) uint8_t pkt[1] = { 2 }; bpf_args_t args = { .pkt = pkt, + .proglen = 0, .buflen = sizeof(pkt), .wirelen = sizeof(pkt), }; @@ -399,6 +405,7 @@ ATF_TC_BODY(libbpfjit_copx_ret_A, tc) uint8_t pkt[1] = { 0 }; bpf_args_t args = { .pkt = pkt, + .proglen = 0, .buflen = sizeof(pkt), .wirelen = sizeof(pkt), }; @@ -433,6 +440,7 @@ ATF_TC_BODY(libbpfjit_copx_ret_buflen, t uint8_t pkt[1] = { 0 }; bpf_args_t args = { .pkt = pkt, + .proglen = 0, .buflen = sizeof(pkt), .wirelen = sizeof(pkt) }; @@ -467,6 +475,7 @@ ATF_TC_BODY(libbpfjit_copx_ret_wirelen, uint8_t pkt[1] = { 0 }; bpf_args_t args = { .pkt = pkt, + .proglen = 0, .buflen = sizeof(pkt), .wirelen = sizeof(pkt) }; @@ -501,6 +510,7 @@ ATF_TC_BODY(libbpfjit_copx_ret_nfuncs, t uint8_t pkt[1] = { 0 }; bpf_args_t args = { .pkt = pkt, + .proglen = 0, .buflen = sizeof(pkt), .wirelen = sizeof(pkt) }; @@ -538,6 +548,7 @@ ATF_TC_BODY(libbpfjit_copx_side_effect, uint8_t pkt[1] = { 0 }; bpf_args_t args = { .pkt = pkt, + .proglen = 0, .buflen = sizeof(pkt), .wirelen = sizeof(pkt), .mem = NULL, @@ -581,6 +592,7 @@ ATF_TC_BODY(libbpfjit_copx_cop, tc) uint8_t pkt[1] = { 2 }; bpf_args_t args = { .pkt = pkt, + .proglen = 0, .buflen = sizeof(pkt), .wirelen = sizeof(pkt), }; @@ -614,6 +626,7 @@ ATF_TC_BODY(libbpfjit_copx_invalid_index uint8_t pkt[1] = { 0 }; bpf_args_t args = { .pkt = pkt, + .proglen = 0, .buflen = sizeof(pkt), .wirelen = sizeof(pkt) }; Index: tests/lib/libbpfjit/t_extmem.c =================================================================== RCS file: /cvsroot/src/tests/lib/libbpfjit/t_extmem.c,v retrieving revision 1.3 diff -u -p -u -r1.3 t_extmem.c --- tests/lib/libbpfjit/t_extmem.c 14 Jul 2014 19:11:15 -0000 1.3 +++ tests/lib/libbpfjit/t_extmem.c 5 Sep 2026 21:38:57 -0000 @@ -85,6 +85,7 @@ ATF_TC_BODY(libbpfjit_extmem_load_defaul bpf_args_t args = { .pkt = pkt, + .proglen = 0, .buflen = sizeof(pkt), .wirelen = sizeof(pkt), .mem = mem, @@ -124,6 +125,7 @@ ATF_TC_BODY(libbpfjit_extmem_load_preini bpf_args_t args = { .pkt = pkt, + .proglen = 0, .buflen = sizeof(pkt), .wirelen = sizeof(pkt), .mem = mem, @@ -188,6 +190,7 @@ ATF_TC_BODY(libbpfjit_extmem_store, tc) bpf_args_t args = { .pkt = pkt, + .proglen = 0, .buflen = sizeof(pkt), .wirelen = sizeof(pkt), .mem = mem, @@ -240,6 +243,7 @@ ATF_TC_BODY(libbpfjit_extmem_side_effect bpf_args_t args = { .pkt = pkt, + .proglen = 0, .buflen = sizeof(pkt), .wirelen = sizeof(pkt), .mem = mem, @@ -308,6 +312,7 @@ ATF_TC_BODY(libbpfjit_cop_ret_mem, tc) bpf_args_t args = { .pkt = pkt, + .proglen = 0, .buflen = sizeof(pkt), .wirelen = sizeof(pkt), .arg = arg, @@ -353,6 +358,7 @@ ATF_TC_BODY(libbpfjit_cop_ret_preinited_ bpf_args_t args = { .pkt = pkt, + .proglen = 0, .buflen = sizeof(pkt), .wirelen = sizeof(pkt), .arg = arg, @@ -399,6 +405,7 @@ ATF_TC_BODY(libbpfjit_copx_ret_mem, tc) bpf_args_t args = { .pkt = pkt, + .proglen = 0, .buflen = sizeof(pkt), .wirelen = sizeof(pkt), .arg = arg, @@ -445,6 +452,7 @@ ATF_TC_BODY(libbpfjit_copx_ret_preinited bpf_args_t args = { .pkt = pkt, + .proglen = 0, .buflen = sizeof(pkt), .wirelen = sizeof(pkt), .arg = arg, Index: tests/net/bpf/h_bpf.h =================================================================== RCS file: /cvsroot/src/tests/net/bpf/h_bpf.h,v retrieving revision 1.2 diff -u -p -u -r1.2 h_bpf.h --- tests/net/bpf/h_bpf.h 8 Jul 2014 21:44:26 -0000 1.2 +++ tests/net/bpf/h_bpf.h 5 Sep 2026 21:38:57 -0000 @@ -87,6 +87,7 @@ exec_prog(struct bpf_insn *insns, size_t unsigned int res; args.pkt = (const uint8_t *)pkt; + args.proglen = 0; args.buflen = pktsize; args.wirelen = pktsize; @@ -116,6 +117,7 @@ interp_prog_mchain2(struct bpf_insn *ins unsigned int res; args.pkt = init_mchain2(&mb1, &mb2, pkt, pktsize, split); + args.proglen = 0; args.buflen = 0; args.wirelen = pktsize; args.mem = mem; @@ -140,6 +142,7 @@ exec_prog_mchain2(struct bpf_insn *insns unsigned int res; args.pkt = init_mchain2(&mb1, &mb2, pkt, pktsize, split); + args.proglen = 0; args.buflen = 0; args.wirelen = pktsize; Index: tests/net/bpfjit/t_cop.c =================================================================== RCS file: /cvsroot/src/tests/net/bpfjit/t_cop.c,v retrieving revision 1.4 diff -u -p -u -r1.4 t_cop.c --- tests/net/bpfjit/t_cop.c 13 Jan 2017 21:30:42 -0000 1.4 +++ tests/net/bpfjit/t_cop.c 5 Sep 2026 21:38:57 -0000 @@ -156,6 +156,7 @@ ATF_TC_BODY(bpfjit_cop_ret_A, tc) uint8_t pkt[1] = { 0 }; bpf_args_t args = { .pkt = pkt, + .proglen = 0, .buflen = sizeof(pkt), .wirelen = sizeof(pkt), }; @@ -195,6 +196,7 @@ ATF_TC_BODY(bpfjit_cop_ret_buflen, tc) uint8_t pkt[1] = { 0 }; bpf_args_t args = { .pkt = pkt, + .proglen = 0, .buflen = sizeof(pkt), .wirelen = sizeof(pkt) }; @@ -234,6 +236,7 @@ ATF_TC_BODY(bpfjit_cop_ret_wirelen, tc) uint8_t pkt[1] = { 0 }; bpf_args_t args = { .pkt = pkt, + .proglen = 0, .buflen = sizeof(pkt), .wirelen = sizeof(pkt) }; @@ -273,6 +276,7 @@ ATF_TC_BODY(bpfjit_cop_ret_nfuncs, tc) uint8_t pkt[1] = { 0 }; bpf_args_t args = { .pkt = pkt, + .proglen = 0, .buflen = sizeof(pkt), .wirelen = sizeof(pkt) }; @@ -315,6 +319,7 @@ ATF_TC_BODY(bpfjit_cop_side_effect, tc) uint8_t pkt[1] = { 0 }; bpf_args_t args = { .pkt = pkt, + .proglen = 0, .buflen = sizeof(pkt), .wirelen = sizeof(pkt), .mem = NULL, @@ -363,6 +368,7 @@ ATF_TC_BODY(bpfjit_cop_copx, tc) uint8_t pkt[1] = { 2 }; bpf_args_t args = { .pkt = pkt, + .proglen = 0, .buflen = sizeof(pkt), .wirelen = sizeof(pkt), }; @@ -457,6 +463,7 @@ ATF_TC_BODY(bpfjit_copx_ret_A, tc) uint8_t pkt[1] = { 0 }; bpf_args_t args = { .pkt = pkt, + .proglen = 0, .buflen = sizeof(pkt), .wirelen = sizeof(pkt), }; @@ -497,6 +504,7 @@ ATF_TC_BODY(bpfjit_copx_ret_buflen, tc) uint8_t pkt[1] = { 0 }; bpf_args_t args = { .pkt = pkt, + .proglen = 0, .buflen = sizeof(pkt), .wirelen = sizeof(pkt) }; @@ -537,6 +545,7 @@ ATF_TC_BODY(bpfjit_copx_ret_wirelen, tc) uint8_t pkt[1] = { 0 }; bpf_args_t args = { .pkt = pkt, + .proglen = 0, .buflen = sizeof(pkt), .wirelen = sizeof(pkt) }; @@ -577,6 +586,7 @@ ATF_TC_BODY(bpfjit_copx_ret_nfuncs, tc) uint8_t pkt[1] = { 0 }; bpf_args_t args = { .pkt = pkt, + .proglen = 0, .buflen = sizeof(pkt), .wirelen = sizeof(pkt) }; @@ -620,6 +630,7 @@ ATF_TC_BODY(bpfjit_copx_side_effect, tc) uint8_t pkt[1] = { 0 }; bpf_args_t args = { .pkt = pkt, + .proglen = 0, .buflen = sizeof(pkt), .wirelen = sizeof(pkt), .mem = NULL, @@ -669,6 +680,7 @@ ATF_TC_BODY(bpfjit_copx_cop, tc) uint8_t pkt[1] = { 2 }; bpf_args_t args = { .pkt = pkt, + .proglen = 0, .buflen = sizeof(pkt), .wirelen = sizeof(pkt), }; @@ -708,6 +720,7 @@ ATF_TC_BODY(bpfjit_copx_invalid_index, t uint8_t pkt[1] = { 0 }; bpf_args_t args = { .pkt = pkt, + .proglen = 0, .buflen = sizeof(pkt), .wirelen = sizeof(pkt) }; Index: tests/net/bpfjit/t_extmem.c =================================================================== RCS file: /cvsroot/src/tests/net/bpfjit/t_extmem.c,v retrieving revision 1.2 diff -u -p -u -r1.2 t_extmem.c --- tests/net/bpfjit/t_extmem.c 13 Jan 2017 21:30:42 -0000 1.2 +++ tests/net/bpfjit/t_extmem.c 5 Sep 2026 21:38:57 -0000 @@ -93,6 +93,7 @@ ATF_TC_BODY(bpfjit_extmem_load_preinited bpf_args_t args = { .pkt = pkt, + .proglen = 0, .buflen = sizeof(pkt), .wirelen = sizeof(pkt), .mem = mem, @@ -169,6 +170,7 @@ ATF_TC_BODY(bpfjit_extmem_store, tc) bpf_args_t args = { .pkt = pkt, + .proglen = 0, .buflen = sizeof(pkt), .wirelen = sizeof(pkt), .mem = mem, @@ -227,6 +229,7 @@ ATF_TC_BODY(bpfjit_extmem_side_effect, t bpf_args_t args = { .pkt = pkt, + .proglen = 0, .buflen = sizeof(pkt), .wirelen = sizeof(pkt), .mem = mem, @@ -307,6 +310,7 @@ ATF_TC_BODY(bpfjit_cop_ret_mem, tc) bpf_args_t args = { .pkt = pkt, + .proglen = 0, .buflen = sizeof(pkt), .wirelen = sizeof(pkt), .arg = arg, @@ -358,6 +362,7 @@ ATF_TC_BODY(bpfjit_cop_ret_preinited_mem bpf_args_t args = { .pkt = pkt, + .proglen = 0, .buflen = sizeof(pkt), .wirelen = sizeof(pkt), .arg = arg, @@ -410,6 +415,7 @@ ATF_TC_BODY(bpfjit_copx_ret_mem, tc) bpf_args_t args = { .pkt = pkt, + .proglen = 0, .buflen = sizeof(pkt), .wirelen = sizeof(pkt), .arg = arg, @@ -462,6 +468,7 @@ ATF_TC_BODY(bpfjit_copx_ret_preinited_me bpf_args_t args = { .pkt = pkt, + .proglen = 0, .buflen = sizeof(pkt), .wirelen = sizeof(pkt), .arg = arg, Index: usr.sbin/npf/npftest/libnpftest/npf_bpf_test.c =================================================================== RCS file: /cvsroot/src/usr.sbin/npf/npftest/libnpftest/npf_bpf_test.c,v retrieving revision 1.12 diff -u -p -u -r1.12 npf_bpf_test.c --- usr.sbin/npf/npftest/libnpftest/npf_bpf_test.c 1 Jul 2025 20:19:30 -0000 1.12 +++ usr.sbin/npf/npftest/libnpftest/npf_bpf_test.c 5 Sep 2026 21:38:57 -0000 @@ -61,17 +61,18 @@ test_bpf_code(void *code, size_t size) #else bc_args.pkt = (const uint8_t *)m; #endif + bc_args.proglen = 0; bc_args.buflen = m_length(m); bc_args.wirelen = bc_args.buflen; bc_args.mem = memstore; bc_args.arg = npc; - ret = npf_bpf_filter(&bc_args, code, NULL); + ret = npf_bpf_filter(&bc_args, code, size, NULL); /* JIT-compiled code. */ jcode = npf_bpf_compile(code, size); if (jcode) { - jret = npf_bpf_filter(&bc_args, NULL, jcode); + jret = npf_bpf_filter(&bc_args, NULL, 0, jcode); assert(ret == jret); (void)jret; bpf_jit_freecode(jcode); } else if (lverbose) {