diff options
author | kib <kib@FreeBSD.org> | 2016-03-09 10:19:32 +0000 |
---|---|---|
committer | kib <kib@FreeBSD.org> | 2016-03-09 10:19:32 +0000 |
commit | 4513fe819a9d93b691b42ce2e1f3a769f13a4fce (patch) | |
tree | a14c4e2289a34c9865f1e962d30e8c38dced591c | |
parent | 292b9f2cb8bc8b91f645a7ee48b68936c1a60f5d (diff) | |
download | FreeBSD-src-4513fe819a9d93b691b42ce2e1f3a769f13a4fce.zip FreeBSD-src-4513fe819a9d93b691b42ce2e1f3a769f13a4fce.tar.gz |
MFC r296009:
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.
-rw-r--r-- | sys/net/bpf.c | 32 |
1 files changed, 25 insertions, 7 deletions
diff --git a/sys/net/bpf.c b/sys/net/bpf.c index 15ab5aa..c40e29f 100644 --- a/sys/net/bpf.c +++ b/sys/net/bpf.c @@ -2616,26 +2616,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); } |