summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbluhm <bluhm@openbsd.org>2019-06-13 20:52:36 +0000
committerbluhm <bluhm@openbsd.org>2019-06-13 20:52:36 +0000
commit0fe0bd9326e05a05c0f55e030d7af496a0f8fe52 (patch)
treecfd758841e7eb185acedd46a1c8de3d2b2d00b65
parentDo memory size calculations as unsigned long. Otherwise (diff)
downloadwireguard-openbsd-0fe0bd9326e05a05c0f55e030d7af496a0f8fe52.tar.xz
wireguard-openbsd-0fe0bd9326e05a05c0f55e030d7af496a0f8fe52.zip
When tcp_close() is running in parallel with fill_file(), the kernel
could crash due to missing inp_ppcb. This happend when fstat(1) was called often and TCP was aborted with reset. Protect the sysctl path with the net lock. OK mpi@
-rw-r--r--sys/kern/kern_sysctl.c19
1 files changed, 17 insertions, 2 deletions
diff --git a/sys/kern/kern_sysctl.c b/sys/kern/kern_sysctl.c
index 7096e861223..c1a82f7dcc5 100644
--- a/sys/kern/kern_sysctl.c
+++ b/sys/kern/kern_sysctl.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kern_sysctl.c,v 1.358 2019/06/01 14:11:17 mpi Exp $ */
+/* $OpenBSD: kern_sysctl.c,v 1.359 2019/06/13 20:52:36 bluhm Exp $ */
/* $NetBSD: kern_sysctl.c,v 1.17 1996/05/20 17:49:05 mrg Exp $ */
/*-
@@ -1152,8 +1152,19 @@ fill_file(struct kinfo_file *kf, struct file *fp, struct filedesc *fdp,
break;
case DTYPE_SOCKET: {
- if (so == NULL)
+ int locked = 0;
+
+ if (so == NULL) {
so = (struct socket *)fp->f_data;
+ /* if so is passed as parameter it is already locked */
+ switch (so->so_proto->pr_domain->dom_family) {
+ case AF_INET:
+ case AF_INET6:
+ NET_LOCK();
+ locked = 1;
+ break;
+ }
+ }
kf->so_type = so->so_type;
kf->so_state = so->so_state;
@@ -1178,6 +1189,7 @@ fill_file(struct kinfo_file *kf, struct file *fp, struct filedesc *fdp,
case AF_INET: {
struct inpcb *inpcb = so->so_pcb;
+ NET_ASSERT_LOCKED();
if (show_pointers)
kf->inp_ppcb = PTRTOINT64(inpcb->inp_ppcb);
kf->inp_lport = inpcb->inp_lport;
@@ -1199,6 +1211,7 @@ fill_file(struct kinfo_file *kf, struct file *fp, struct filedesc *fdp,
case AF_INET6: {
struct inpcb *inpcb = so->so_pcb;
+ NET_ASSERT_LOCKED();
if (show_pointers)
kf->inp_ppcb = PTRTOINT64(inpcb->inp_ppcb);
kf->inp_lport = inpcb->inp_lport;
@@ -1244,6 +1257,8 @@ fill_file(struct kinfo_file *kf, struct file *fp, struct filedesc *fdp,
break;
}
}
+ if (locked)
+ NET_UNLOCK();
break;
}