diff options
author | 2017-08-22 09:13:36 +0000 | |
---|---|---|
committer | 2017-08-22 09:13:36 +0000 | |
commit | 0bad721a22b5b65b644fe726746ef68bc247f3bc (patch) | |
tree | 65b13693ba1979f2212fbddf01dc3692288faf15 | |
parent | Fix off by one overwrite. Covery CID 1452938. (diff) | |
download | wireguard-openbsd-0bad721a22b5b65b644fe726746ef68bc247f3bc.tar.xz wireguard-openbsd-0bad721a22b5b65b644fe726746ef68bc247f3bc.zip |
Make sogetopt(9) caller responsible for allocating an MT_SOOPTS mbuf.
Move a blocking memory allocation out of the socket lock and create
a simpler alloc/free pattern to review. Now both m_get() and m_free()
are in the same place.
Discussed with bluhm@.
Encouragements from deraadt@ and tedu@, ok kettenis@, florian@, visa@
-rw-r--r-- | sys/kern/uipc_socket.c | 21 | ||||
-rw-r--r-- | sys/kern/uipc_syscalls.c | 7 | ||||
-rw-r--r-- | sys/sys/socketvar.h | 5 |
3 files changed, 10 insertions, 23 deletions
diff --git a/sys/kern/uipc_socket.c b/sys/kern/uipc_socket.c index c499f46de04..369e32ecdc5 100644 --- a/sys/kern/uipc_socket.c +++ b/sys/kern/uipc_socket.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uipc_socket.c,v 1.201 2017/08/10 19:20:43 mpi Exp $ */ +/* $OpenBSD: uipc_socket.c,v 1.202 2017/08/22 09:13:36 mpi Exp $ */ /* $NetBSD: uipc_socket.c,v 1.21 1996/02/04 02:17:52 christos Exp $ */ /* @@ -1755,30 +1755,24 @@ bad: } int -sogetopt(struct socket *so, int level, int optname, struct mbuf **mp) +sogetopt(struct socket *so, int level, int optname, struct mbuf *m) { int error = 0; - struct mbuf *m; soassertlocked(so); if (level != SOL_SOCKET) { if (so->so_proto->pr_ctloutput) { - m = m_get(M_WAIT, MT_SOOPTS); m->m_len = 0; error = (*so->so_proto->pr_ctloutput)(PRCO_GETOPT, so, level, optname, m); - if (error) { - m_free(m); + if (error) return (error); - } - *mp = m; return (0); } else return (ENOPROTOOPT); } else { - m = m_get(M_WAIT, MT_SOOPTS); m->m_len = sizeof (int); switch (optname) { @@ -1856,13 +1850,10 @@ sogetopt(struct socket *so, int level, int optname, struct mbuf **mp) level = dom->dom_protosw->pr_protocol; error = (*so->so_proto->pr_ctloutput) (PRCO_GETOPT, so, level, optname, m); - if (error) { - (void)m_free(m); + if (error) return (error); - } break; } - (void)m_free(m); return (ENOPROTOOPT); #ifdef SOCKET_SPLICE @@ -1887,17 +1878,13 @@ sogetopt(struct socket *so, int level, int optname, struct mbuf **mp) &(unp->unp_connid), m->m_len); break; } - (void)m_free(m); return (ENOTCONN); } - (void)m_free(m); return (EOPNOTSUPP); default: - (void)m_free(m); return (ENOPROTOOPT); } - *mp = m; return (0); } } diff --git a/sys/kern/uipc_syscalls.c b/sys/kern/uipc_syscalls.c index 047f557274e..bc9b50cfac3 100644 --- a/sys/kern/uipc_syscalls.c +++ b/sys/kern/uipc_syscalls.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uipc_syscalls.c,v 1.158 2017/08/10 19:20:43 mpi Exp $ */ +/* $OpenBSD: uipc_syscalls.c,v 1.159 2017/08/22 09:13:36 mpi Exp $ */ /* $NetBSD: uipc_syscalls.c,v 1.19 1996/02/09 19:00:48 christos Exp $ */ /* @@ -1014,9 +1014,10 @@ sys_getsockopt(struct proc *p, void *v, register_t *retval) goto out; } else valsize = 0; + m = m_get(M_WAIT, MT_SOOPTS); so = fp->f_data; s = solock(so); - error = sogetopt(so, SCARG(uap, level), SCARG(uap, name), &m); + error = sogetopt(so, SCARG(uap, level), SCARG(uap, name), m); sounlock(s); if (error == 0 && SCARG(uap, val) && valsize && m != NULL) { if (valsize > m->m_len) @@ -1026,9 +1027,9 @@ sys_getsockopt(struct proc *p, void *v, register_t *retval) error = copyout(&valsize, SCARG(uap, avalsize), sizeof (valsize)); } + m_free(m); out: FRELE(fp, p); - m_free(m); return (error); } diff --git a/sys/sys/socketvar.h b/sys/sys/socketvar.h index 83efc2ecbb5..48a4f4d1a43 100644 --- a/sys/sys/socketvar.h +++ b/sys/sys/socketvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: socketvar.h,v 1.74 2017/07/12 10:56:47 mpi Exp $ */ +/* $OpenBSD: socketvar.h,v 1.75 2017/08/22 09:13:36 mpi Exp $ */ /* $NetBSD: socketvar.h,v 1.18 1996/02/09 18:25:38 christos Exp $ */ /*- @@ -312,8 +312,7 @@ int soconnect2(struct socket *so1, struct socket *so2); int socreate(int dom, struct socket **aso, int type, int proto); int sodisconnect(struct socket *so); void sofree(struct socket *so); -int sogetopt(struct socket *so, int level, int optname, - struct mbuf **mp); +int sogetopt(struct socket *so, int level, int optname, struct mbuf *m); void sohasoutofband(struct socket *so); void soisconnected(struct socket *so); void soisconnecting(struct socket *so); |