diff options
author | Can Erkin Acar <canacar@cvs.openbsd.org> | 2003-10-22 18:42:41 +0000 |
---|---|---|
committer | Can Erkin Acar <canacar@cvs.openbsd.org> | 2003-10-22 18:42:41 +0000 |
commit | 6693f734d4d99c32579a9cef43ff0f9a39e4dc62 (patch) | |
tree | edbf003bbcf42419432abe8645aca40cac4fcdd9 /sys/net | |
parent | 2e46b2f39d9833b32544b6e61959e55ae2d0700d (diff) |
Add locking and write filtering to bpf descriptors.
Locking prevents dangerous ioctls such as changing the
interface and sending signals to be executed by an
unprivileged process. A filter can also be applied
to packets injected through a bpf descriptor.
These features allow programs using bpf descriptors to
safely drop/seperate privileges.
ok frantzen@ henning@ mcbride@
Diffstat (limited to 'sys/net')
-rw-r--r-- | sys/net/bpf.c | 97 | ||||
-rw-r--r-- | sys/net/bpf.h | 4 | ||||
-rw-r--r-- | sys/net/bpfdesc.h | 8 |
3 files changed, 85 insertions, 24 deletions
diff --git a/sys/net/bpf.c b/sys/net/bpf.c index 425a2d41b75..3c171166439 100644 --- a/sys/net/bpf.c +++ b/sys/net/bpf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: bpf.c,v 1.39 2003/10/04 01:03:49 deraadt Exp $ */ +/* $OpenBSD: bpf.c,v 1.40 2003/10/22 18:42:40 canacar Exp $ */ /* $NetBSD: bpf.c,v 1.33 1997/02/21 23:59:35 thorpej Exp $ */ /* @@ -80,7 +80,8 @@ int bpf_allocbufs(struct bpf_d *); void bpf_freed(struct bpf_d *); void bpf_ifname(struct ifnet *, struct ifreq *); void bpf_mcopy(const void *, void *, size_t); -int bpf_movein(struct uio *, int, struct mbuf **, struct sockaddr *); +int bpf_movein(struct uio *, int, struct mbuf **, + struct sockaddr *, struct bpf_insn *); void bpf_attachd(struct bpf_d *, struct bpf_if *); void bpf_detachd(struct bpf_d *); int bpf_setif(struct bpf_d *, struct ifreq *); @@ -95,16 +96,18 @@ void filt_bpfrdetach(struct knote *); int filt_bpfread(struct knote *, long); int -bpf_movein(uio, linktype, mp, sockp) +bpf_movein(uio, linktype, mp, sockp, filter) register struct uio *uio; int linktype; register struct mbuf **mp; register struct sockaddr *sockp; + struct bpf_insn *filter; { struct mbuf *m; int error; int len; int hlen; + int slen; /* XXX u_int ? */ /* * Build a sockaddr based on the data link layer type. @@ -181,19 +184,31 @@ bpf_movein(uio, linktype, mp, sockp) } m->m_len = len; *mp = m; + + error = uiomove(mtod(m, caddr_t), len, uio); + if (error) + goto bad; + + slen = bpf_filter(filter, mtod(m, u_char *), len, len); + if (slen == 0 || slen < len) { + error = EPERM; + goto bad; + } + + if (m->m_len < hlen) { + error = EPERM; + goto bad; + } /* - * Make room for link header. + * Make room for link header, and copy it to sockaddr */ if (hlen != 0) { + bcopy(m->m_data, sockp->sa_data, hlen); m->m_len -= hlen; m->m_data += hlen; /* XXX */ - error = uiomove((caddr_t)sockp->sa_data, hlen, uio); - if (error) - goto bad; } - error = uiomove(mtod(m, caddr_t), len - hlen, uio); - if (!error) - return (0); + + return (0); bad: m_freem(m); return (error); @@ -511,7 +526,7 @@ bpfwrite(dev, uio, ioflag) return (0); error = bpf_movein(uio, (int)d->bd_bif->bif_dlt, &m, - (struct sockaddr *)&dst); + (struct sockaddr *)&dst, d->bd_wfilter); if (error) return (error); @@ -581,6 +596,29 @@ bpfioctl(dev, cmd, addr, flag, p) register struct bpf_d *d = &bpf_dtab[minor(dev)]; int s, error = 0; + if (d->bd_locked && suser(p, 0) != 0) { + /* list of allowed ioctls when locked and not root */ + switch (cmd) { + case BIOCGBLEN: + case BIOCFLUSH: + case BIOCGDLT: + case BIOCGETIF: + case BIOCGRTIMEOUT: + case BIOCGSTATS: + case BIOCVERSION: + case BIOCGRSIG: + case BIOCGHDRCMPLT: + case FIONREAD: + case BIOCLOCK: + case BIOCSRTIMEOUT: + case BIOCIMMEDIATE: + case TIOCGPGRP: + break; + default: + return (EPERM); + } + } + switch (cmd) { default: @@ -632,7 +670,14 @@ bpfioctl(dev, cmd, addr, flag, p) * Set link layer read filter. */ case BIOCSETF: - error = bpf_setf(d, (struct bpf_program *)addr); + error = bpf_setf(d, (struct bpf_program *)addr, 0); + break; + + /* + * Set link layer write filter. + */ + case BIOCSETWF: + error = bpf_setf(d, (struct bpf_program *)addr, 1); break; /* @@ -753,6 +798,9 @@ bpfioctl(dev, cmd, addr, flag, p) d->bd_hdrcmplt = *(u_int *)addr ? 1 : 0; break; + case BIOCLOCK: /* set "locked" flag (no reset) */ + d->bd_locked = 1; + break; case FIONBIO: /* Non-blocking I/O */ if (*(int *)addr) @@ -807,20 +855,24 @@ bpfioctl(dev, cmd, addr, flag, p) * free it and replace it. Returns EINVAL for bogus requests. */ int -bpf_setf(d, fp) +bpf_setf(d, fp, wf) struct bpf_d *d; struct bpf_program *fp; + int wf; { struct bpf_insn *fcode, *old; u_int flen, size; int s; - old = d->bd_filter; + old = wf ? d->bd_wfilter : d->bd_rfilter; if (fp->bf_insns == 0) { if (fp->bf_len != 0) return (EINVAL); s = splimp(); - d->bd_filter = 0; + if (wf) + d->bd_wfilter = 0; + else + d->bd_rfilter = 0; bpf_reset_d(d); splx(s); if (old != 0) @@ -836,7 +888,10 @@ bpf_setf(d, fp) if (copyin((caddr_t)fp->bf_insns, (caddr_t)fcode, size) == 0 && bpf_validate(fcode, (int)flen)) { s = splimp(); - d->bd_filter = fcode; + if (wf) + d->bd_wfilter = fcode; + else + d->bd_rfilter = fcode; bpf_reset_d(d); splx(s); if (old != 0) @@ -1050,7 +1105,7 @@ bpf_tap(arg, pkt, pktlen) bp = (struct bpf_if *)arg; for (d = bp->bif_dlist; d != 0; d = d->bd_next) { ++d->bd_rcount; - slen = bpf_filter(d->bd_filter, pkt, pktlen, pktlen); + slen = bpf_filter(d->bd_rfilter, pkt, pktlen, pktlen); if (slen != 0) bpf_catchpacket(d, pkt, pktlen, slen, bcopy); } @@ -1105,7 +1160,7 @@ bpf_mtap(arg, m) for (d = bp->bif_dlist; d != 0; d = d->bd_next) { ++d->bd_rcount; - slen = bpf_filter(d->bd_filter, (u_char *)m, pktlen, 0); + slen = bpf_filter(d->bd_rfilter, (u_char *)m, pktlen, 0); if (slen != 0) bpf_catchpacket(d, (u_char *)m, pktlen, slen, bpf_mcopy); } @@ -1242,8 +1297,10 @@ bpf_freed(d) if (d->bd_fbuf != 0) free(d->bd_fbuf, M_DEVBUF); } - if (d->bd_filter) - free((caddr_t)d->bd_filter, M_DEVBUF); + if (d->bd_rfilter) + free((caddr_t)d->bd_rfilter, M_DEVBUF); + if (d->bd_wfilter) + free((caddr_t)d->bd_wfilter, M_DEVBUF); D_MARKFREE(d); } diff --git a/sys/net/bpf.h b/sys/net/bpf.h index e1738dfb4f2..50e210ce5b6 100644 --- a/sys/net/bpf.h +++ b/sys/net/bpf.h @@ -1,4 +1,4 @@ -/* $OpenBSD: bpf.h,v 1.23 2003/08/25 08:16:41 fgsch Exp $ */ +/* $OpenBSD: bpf.h,v 1.24 2003/10/22 18:42:40 canacar Exp $ */ /* $NetBSD: bpf.h,v 1.15 1996/12/13 07:57:33 mikel Exp $ */ /* @@ -111,6 +111,8 @@ struct bpf_version { #define BIOCGRSIG _IOR('B',115, u_int) #define BIOCGHDRCMPLT _IOR('B',116, u_int) #define BIOCSHDRCMPLT _IOW('B',117, u_int) +#define BIOCLOCK _IO('B',118) +#define BIOCSETWF _IOW('B',119, struct bpf_program) struct bpf_timeval { u_int32_t tv_sec; diff --git a/sys/net/bpfdesc.h b/sys/net/bpfdesc.h index 9060bc33915..9c3eb6d3a39 100644 --- a/sys/net/bpfdesc.h +++ b/sys/net/bpfdesc.h @@ -1,4 +1,4 @@ -/* $OpenBSD: bpfdesc.h,v 1.10 2003/06/02 23:28:11 millert Exp $ */ +/* $OpenBSD: bpfdesc.h,v 1.11 2003/10/22 18:42:40 canacar Exp $ */ /* $NetBSD: bpfdesc.h,v 1.11 1995/09/27 18:30:42 thorpej Exp $ */ /* @@ -67,13 +67,15 @@ struct bpf_d { struct bpf_if * bd_bif; /* interface descriptor */ u_long bd_rtout; /* Read timeout in 'ticks' */ u_long bd_rdStart; /* when the read started */ - struct bpf_insn *bd_filter; /* filter code */ + struct bpf_insn *bd_rfilter; /* read filter code */ + struct bpf_insn *bd_wfilter; /* write filter code */ u_long bd_rcount; /* number of packets received */ u_long bd_dcount; /* number of packets dropped */ u_char bd_promisc; /* true if listening promiscuously */ u_char bd_state; /* idle, waiting, or timed out */ u_char bd_immediate; /* true to return on packet arrival */ + u_char bd_locked; /* true if descriptor is locked */ int bd_hdrcmplt; /* false to fill in src lladdr automatically */ int bd_async; /* non-zero if packet reception should generate signal */ int bd_sig; /* signal to send upon packet reception */ @@ -97,6 +99,6 @@ struct bpf_if { }; #ifdef _KERNEL -int bpf_setf(struct bpf_d *, struct bpf_program *); +int bpf_setf(struct bpf_d *, struct bpf_program *, int); #endif /* _KERNEL */ #endif /* _NET_BPFDESC_H_ */ |