diff options
author | 2015-09-29 10:58:51 +0000 | |
---|---|---|
committer | 2015-09-29 10:58:51 +0000 | |
commit | e1e4c63e52dea85eb7ca789fba149efc570ac56e (patch) | |
tree | a06a94077d855b0087dda28314c35b48d997cb86 | |
parent | get rid of the mutex between access to the status block and myx_down (diff) | |
download | wireguard-openbsd-e1e4c63e52dea85eb7ca789fba149efc570ac56e.tar.xz wireguard-openbsd-e1e4c63e52dea85eb7ca789fba149efc570ac56e.zip |
make the bpf filters a bpf_program instead of an array of bpf_insn.
bpf_program contains a pointer to that same array, but also the
number of elements in it. this allows us to know the size when we
want to free them.
ok deraadt@
-rw-r--r-- | sys/net/bpf.c | 69 |
1 files changed, 49 insertions, 20 deletions
diff --git a/sys/net/bpf.c b/sys/net/bpf.c index f19f2fc9bf5..b9f2c817bb0 100644 --- a/sys/net/bpf.c +++ b/sys/net/bpf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: bpf.c,v 1.128 2015/09/29 10:11:40 deraadt Exp $ */ +/* $OpenBSD: bpf.c,v 1.129 2015/09/29 10:58:51 dlg Exp $ */ /* $NetBSD: bpf.c,v 1.33 1997/02/21 23:59:35 thorpej Exp $ */ /* @@ -524,6 +524,8 @@ bpfwrite(dev_t dev, struct uio *uio, int ioflag) struct bpf_d *d; struct ifnet *ifp; struct mbuf *m; + struct bpf_program *bf; + struct bpf_insn *fcode = NULL; int error, s; struct sockaddr_storage dst; @@ -540,8 +542,12 @@ bpfwrite(dev_t dev, struct uio *uio, int ioflag) return (0); KERNEL_ASSERT_LOCKED(); /* for accessing bd_wfilter */ + bf = srp_get_locked(&d->bd_wfilter); + if (bf != NULL) + fcode = bf->bf_insns; + error = bpf_movein(uio, d->bd_bif->bif_dlt, &m, - (struct sockaddr *)&dst, srp_get_locked(&d->bd_wfilter)); + (struct sockaddr *)&dst, fcode); if (error) return (error); @@ -917,6 +923,7 @@ bpfioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) int bpf_setf(struct bpf_d *d, struct bpf_program *fp, int wf) { + struct bpf_program *bf; struct srp *filter; struct bpf_insn *fcode; u_int flen, size; @@ -938,18 +945,28 @@ bpf_setf(struct bpf_d *d, struct bpf_program *fp, int wf) if (flen > BPF_MAXINSNS) return (EINVAL); - fcode = mallocarray(flen, sizeof(*fp->bf_insns), M_DEVBUF, M_WAITOK); + fcode = mallocarray(flen, sizeof(*fp->bf_insns), M_DEVBUF, + M_WAITOK | M_CANFAIL); + if (fcode == NULL) + return (ENOMEM); + size = flen * sizeof(*fp->bf_insns); - if (copyin(fp->bf_insns, fcode, size) == 0 && - bpf_validate(fcode, (int)flen)) { - srp_update_locked(&bpf_insn_gc, filter, fcode); - s = splnet(); - bpf_reset_d(d); - splx(s); - return (0); + if (copyin(fp->bf_insns, fcode, size) != 0 || + bpf_validate(fcode, (int)flen) == 0) { + free(fcode, M_DEVBUF, size); + return (EINVAL); } - free(fcode, M_DEVBUF, size); - return (EINVAL); + + bf = malloc(sizeof(*bf), M_DEVBUF, M_WAITOK); + bf->bf_len = flen; + bf->bf_insns = fcode; + + srp_update_locked(&bpf_insn_gc, filter, bf); + + s = splnet(); + bpf_reset_d(d); + splx(s); + return (0); } /* @@ -1134,10 +1151,14 @@ bpf_tap(caddr_t arg, u_char *pkt, u_int pktlen, u_int direction) if ((direction & d->bd_dirfilt) != 0) slen = 0; else { - struct bpf_insn *fcode; - fcode = srp_enter(&d->bd_rfilter); + struct bpf_program *bf; + struct bpf_insn *fcode = NULL; + + bf = srp_enter(&d->bd_rfilter); + if (bf != NULL) + fcode = bf->bf_insns; slen = bpf_filter(fcode, pkt, pktlen, 0); - srp_leave(&d->bd_rfilter, fcode); + srp_leave(&d->bd_rfilter, bf); } if (slen > 0) { @@ -1214,10 +1235,14 @@ _bpf_mtap(caddr_t arg, struct mbuf *m, u_int direction, else if (d->bd_queue && m->m_pkthdr.pf.qid != d->bd_queue) slen = 0; else { - struct bpf_insn *fcode; - fcode = srp_enter(&d->bd_rfilter); + struct bpf_program *bf; + struct bpf_insn *fcode = NULL; + + bf = srp_enter(&d->bd_rfilter); + if (bf != NULL) + fcode = bf->bf_insns; slen = bpf_filter(fcode, (u_char *)m, pktlen, 0); - srp_leave(&d->bd_rfilter, fcode); + srp_leave(&d->bd_rfilter, bf); } if (slen > 0) { @@ -1679,7 +1704,11 @@ bpf_d_unref(void *null, void *d) } void -bpf_insn_dtor(void *null, void *fcode) +bpf_insn_dtor(void *null, void *f) { - free(fcode, M_DEVBUF, 0); + struct bpf_program *bf = f; + struct bpf_insn *insns = bf->bf_insns; + + free(insns, M_DEVBUF, bf->bf_len * sizeof(*insns)); + free(bf, M_DEVBUF, sizeof(*bf)); } |