diff options
author | kib <kib@FreeBSD.org> | 2016-02-24 22:00:35 +0000 |
---|---|---|
committer | kib <kib@FreeBSD.org> | 2016-02-24 22:00:35 +0000 |
commit | 4c4becd77e5fd09fea589c662bc1ccdfb645886e (patch) | |
tree | df21c4220def6941814f79231543ef1c4857ae3a /sys/net | |
parent | c9f48b7d63385be81574c190e92e621b2b6570a3 (diff) | |
download | FreeBSD-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.c | 32 |
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); } |