summaryrefslogtreecommitdiffstats
path: root/sys/net
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2016-02-24 22:00:35 +0000
committerkib <kib@FreeBSD.org>2016-02-24 22:00:35 +0000
commit4c4becd77e5fd09fea589c662bc1ccdfb645886e (patch)
treedf21c4220def6941814f79231543ef1c4857ae3a /sys/net
parentc9f48b7d63385be81574c190e92e621b2b6570a3 (diff)
downloadFreeBSD-src-4c4becd77e5fd09fea589c662bc1ccdfb645886e.zip
FreeBSD-src-4c4becd77e5fd09fea589c662bc1ccdfb645886e.tar.gz
In bpf_getdltlist(), do not call copyout(9) while holding bpf lock.
Copy the data into temprorary malloced buffer and drop the lock for copyout. Reported, reviewed and tested by: cem Sponsored by: The FreeBSD Foundation MFC after: 1 week
Diffstat (limited to 'sys/net')
-rw-r--r--sys/net/bpf.c32
1 files changed, 25 insertions, 7 deletions
diff --git a/sys/net/bpf.c b/sys/net/bpf.c
index 661a1cf..54dd184 100644
--- a/sys/net/bpf.c
+++ b/sys/net/bpf.c
@@ -2681,26 +2681,44 @@ bpf_ifdetach(void *arg __unused, struct ifnet *ifp)
static int
bpf_getdltlist(struct bpf_d *d, struct bpf_dltlist *bfl)
{
- int n, error;
struct ifnet *ifp;
struct bpf_if *bp;
+ u_int *lst;
+ int error, n, n1;
BPF_LOCK_ASSERT();
ifp = d->bd_bif->bif_ifp;
+again:
+ n1 = 0;
+ LIST_FOREACH(bp, &bpf_iflist, bif_next) {
+ if (bp->bif_ifp == ifp)
+ n1++;
+ }
+ if (bfl->bfl_list == NULL) {
+ bfl->bfl_len = n1;
+ return (0);
+ }
+ if (n1 > bfl->bfl_len)
+ return (ENOMEM);
+ BPF_UNLOCK();
+ lst = malloc(n1 * sizeof(u_int), M_TEMP, M_WAITOK);
n = 0;
- error = 0;
+ BPF_LOCK();
LIST_FOREACH(bp, &bpf_iflist, bif_next) {
if (bp->bif_ifp != ifp)
continue;
- if (bfl->bfl_list != NULL) {
- if (n >= bfl->bfl_len)
- return (ENOMEM);
- error = copyout(&bp->bif_dlt,
- bfl->bfl_list + n, sizeof(u_int));
+ if (n > n1) {
+ free(lst, M_TEMP);
+ goto again;
}
+ lst[n] = bp->bif_dlt;
n++;
}
+ BPF_UNLOCK();
+ error = copyout(lst, bfl->bfl_list, sizeof(u_int) * n);
+ free(lst, M_TEMP);
+ BPF_LOCK();
bfl->bfl_len = n;
return (error);
}
OpenPOWER on IntegriCloud