git: 0fac350c54d0 - main - sockets: don't malloc/free sockaddr memory on getpeername/getsockname

From: Gleb Smirnoff <glebius_at_FreeBSD.org>
Date: Thu, 30 Nov 2023 16:34:48 UTC
The branch main has been updated by glebius:

URL: https://cgit.FreeBSD.org/src/commit/?id=0fac350c54d0a72f5341e15021efcde63eb58a4b

commit 0fac350c54d0a72f5341e15021efcde63eb58a4b
Author:     Gleb Smirnoff <glebius@FreeBSD.org>
AuthorDate: 2023-11-30 16:30:55 +0000
Commit:     Gleb Smirnoff <glebius@FreeBSD.org>
CommitDate: 2023-11-30 16:31:10 +0000

    sockets: don't malloc/free sockaddr memory on getpeername/getsockname
    
    Just like it was done for accept(2) in cfb1e92912b4, use same approach
    for two simplier syscalls that return socket addresses.  Although,
    these two syscalls aren't performance critical, this change generalizes
    some code between 3 syscalls trimming code size.
    
    Following example of accept(2), provide VNET-aware and INVARIANT-checking
    wrappers sopeeraddr() and sosockaddr() around protosw methods.
    
    Reviewed by:            tuexen
    Differential Revision:  https://reviews.freebsd.org/D42694
---
 sys/compat/linux/linux_socket.c                    | 45 +++++------
 sys/compat/linuxkpi/common/include/linux/net.h     | 17 +++--
 sys/dev/cxgbe/iw_cxgbe/cm.c                        | 14 +---
 sys/dev/hyperv/hvsock/hv_sock.c                    | 12 +--
 sys/dev/hyperv/hvsock/hv_sock.h                    |  4 +-
 sys/dev/wg/if_wg.c                                 | 24 +++---
 sys/kern/sys_socket.c                              | 17 ++---
 sys/kern/uipc_domain.c                             |  4 +-
 sys/kern/uipc_socket.c                             | 34 +++++++++
 sys/kern/uipc_syscalls.c                           | 86 +++++++---------------
 sys/kern/uipc_usrreq.c                             | 48 +++---------
 sys/net/if_ovpn.c                                  | 12 +--
 .../bluetooth/include/ng_btsocket_hci_raw.h        |  3 +-
 sys/netgraph/bluetooth/include/ng_btsocket_l2cap.h |  9 +--
 .../bluetooth/include/ng_btsocket_rfcomm.h         |  4 +-
 sys/netgraph/bluetooth/include/ng_btsocket_sco.h   |  4 +-
 sys/netgraph/bluetooth/socket/ng_btsocket.c        |  8 +-
 .../bluetooth/socket/ng_btsocket_hci_raw.c         | 29 +++-----
 sys/netgraph/bluetooth/socket/ng_btsocket_l2cap.c  | 75 ++++++-------------
 .../bluetooth/socket/ng_btsocket_l2cap_raw.c       | 47 ++++++------
 sys/netgraph/bluetooth/socket/ng_btsocket_rfcomm.c | 61 +++++----------
 sys/netgraph/bluetooth/socket/ng_btsocket_sco.c    | 62 +++++-----------
 sys/netgraph/ng_ksocket.c                          | 28 +++----
 sys/netgraph/ng_socket.c                           | 23 ++----
 sys/netinet/in_pcb.c                               | 49 ++++--------
 sys/netinet/in_pcb.h                               |  6 +-
 sys/netinet/sctp_os.h                              |  3 -
 sys/netinet/sctp_os_bsd.h                          |  7 --
 sys/netinet/sctp_usrreq.c                          | 40 ++++------
 sys/netinet/sctp_var.h                             |  4 +-
 sys/netinet6/in6.c                                 | 14 ----
 sys/netinet6/in6.h                                 |  1 -
 sys/netinet6/in6_pcb.c                             | 74 ++++++++-----------
 sys/netinet6/in6_pcb.h                             | 10 +--
 sys/netinet6/sctp6_usrreq.c                        | 84 +++++++--------------
 sys/netlink/netlink_domain.c                       | 27 +++----
 sys/ofed/drivers/infiniband/ulp/sdp/sdp_main.c     | 36 ++++-----
 sys/rpc/rpc_generic.c                              | 45 ++++-------
 sys/rpc/svc_dg.c                                   |  9 +--
 sys/rpc/svc_vc.c                                   | 27 ++-----
 sys/sys/protosw.h                                  |  4 +-
 sys/sys/socketvar.h                                |  2 +
 sys/sys/syscallsubr.h                              |  6 +-
 43 files changed, 420 insertions(+), 698 deletions(-)

diff --git a/sys/compat/linux/linux_socket.c b/sys/compat/linux/linux_socket.c
index 2893e93bbcd7..f474ea06440a 100644
--- a/sys/compat/linux/linux_socket.c
+++ b/sys/compat/linux/linux_socket.c
@@ -1106,48 +1106,50 @@ linux_accept4(struct thread *td, struct linux_accept4_args *args)
 int
 linux_getsockname(struct thread *td, struct linux_getsockname_args *args)
 {
-	struct sockaddr *sa;
-	int len, error;
+	struct sockaddr_storage ss = { .ss_len = sizeof(ss) };
+	socklen_t len;
+	int error;
 
 	error = copyin(PTRIN(args->namelen), &len, sizeof(len));
 	if (error != 0)
 		return (error);
 
-	error = kern_getsockname(td, args->s, &sa, &len);
+	error = kern_getsockname(td, args->s, (struct sockaddr *)&ss);
 	if (error != 0)
 		return (error);
 
-	if (len != 0)
-		error = linux_copyout_sockaddr(sa, PTRIN(args->addr), len);
-
-	free(sa, M_SONAME);
-	if (error == 0)
+	len = min(ss.ss_len, len);
+	error = linux_copyout_sockaddr((struct sockaddr *)&ss,
+	    PTRIN(args->addr), len);
+	if (error == 0) {
+		len = ss.ss_len;
 		error = copyout(&len, PTRIN(args->namelen), sizeof(len));
+	}
 	return (error);
 }
 
 int
 linux_getpeername(struct thread *td, struct linux_getpeername_args *args)
 {
-	struct sockaddr *sa;
-	int len, error;
+	struct sockaddr_storage ss = { .ss_len = sizeof(ss) };
+	socklen_t len;
+	int error;
 
 	error = copyin(PTRIN(args->namelen), &len, sizeof(len));
 	if (error != 0)
 		return (error);
-	if (len < 0)
-		return (EINVAL);
 
-	error = kern_getpeername(td, args->s, &sa, &len);
+	error = kern_getpeername(td, args->s, (struct sockaddr *)&ss);
 	if (error != 0)
 		return (error);
 
-	if (len != 0)
-		error = linux_copyout_sockaddr(sa, PTRIN(args->addr), len);
-
-	free(sa, M_SONAME);
-	if (error == 0)
+	len = min(ss.ss_len, len);
+	error = linux_copyout_sockaddr((struct sockaddr *)&ss,
+	    PTRIN(args->addr), len);
+	if (error == 0) {
+		len = ss.ss_len;
 		error = copyout(&len, PTRIN(args->namelen), sizeof(len));
+	}
 	return (error);
 }
 
@@ -1348,6 +1350,7 @@ static int
 linux_sendmsg_common(struct thread *td, l_int s, struct l_msghdr *msghdr,
     l_uint flags)
 {
+	struct sockaddr_storage ss = { .ss_len = sizeof(ss) };
 	struct cmsghdr *cmsg;
 	struct mbuf *control;
 	struct msghdr msg;
@@ -1356,7 +1359,6 @@ linux_sendmsg_common(struct thread *td, l_int s, struct l_msghdr *msghdr,
 	struct l_msghdr linux_msghdr;
 	struct iovec *iov;
 	socklen_t datalen;
-	struct sockaddr *sa;
 	struct socket *so;
 	sa_family_t sa_family;
 	struct file *fp;
@@ -1395,11 +1397,10 @@ linux_sendmsg_common(struct thread *td, l_int s, struct l_msghdr *msghdr,
 
 	control = NULL;
 
-	error = kern_getsockname(td, s, &sa, &datalen);
+	error = kern_getsockname(td, s, (struct sockaddr *)&ss);
 	if (error != 0)
 		goto bad;
-	sa_family = sa->sa_family;
-	free(sa, M_SONAME);
+	sa_family = ss.ss_family;
 
 	if (flags & LINUX_MSG_OOB) {
 		error = EOPNOTSUPP;
diff --git a/sys/compat/linuxkpi/common/include/linux/net.h b/sys/compat/linuxkpi/common/include/linux/net.h
index f750de8c5cf3..dc0b46df9c99 100644
--- a/sys/compat/linuxkpi/common/include/linux/net.h
+++ b/sys/compat/linuxkpi/common/include/linux/net.h
@@ -45,26 +45,27 @@ sock_create_kern(int family, int type, int proto, struct socket **res)
 }
 
 static inline int
-sock_getname(struct socket *so, struct sockaddr *addr, int *sockaddr_len,
+sock_getname(struct socket *so, struct sockaddr *sa, int *sockaddr_len,
     int peer)
 {
-	struct sockaddr *nam;
 	int error;
 
-	nam = NULL;
+	/*
+	 * XXXGL: we can't use sopeeraddr()/sosockaddr() here since with
+	 * INVARIANTS they would check if supplied sockaddr has enough
+	 * length.  Such notion doesn't even exist in Linux KPI.
+	 */
 	if (peer) {
 		if ((so->so_state & (SS_ISCONNECTED|SS_ISCONFIRMING)) == 0)
 			return (-ENOTCONN);
 
-		error = so->so_proto->pr_peeraddr(so, &nam);
+		error = so->so_proto->pr_peeraddr(so, sa);
 	} else
-		error = so->so_proto->pr_sockaddr(so, &nam);
+		error = so->so_proto->pr_sockaddr(so, sa);
 	if (error)
 		return (-error);
-	*addr = *nam;
-	*sockaddr_len = addr->sa_len;
+	*sockaddr_len = sa->sa_len;
 
-	free(nam, M_SONAME);
 	return (0);
 }
 
diff --git a/sys/dev/cxgbe/iw_cxgbe/cm.c b/sys/dev/cxgbe/iw_cxgbe/cm.c
index 84d6df3f2832..e0e48fdff9ba 100644
--- a/sys/dev/cxgbe/iw_cxgbe/cm.c
+++ b/sys/dev/cxgbe/iw_cxgbe/cm.c
@@ -145,30 +145,24 @@ static void process_newconn(struct c4iw_listen_ep *master_lep,
 
 #define GET_LOCAL_ADDR(pladdr, so) \
 	do { \
-		struct sockaddr_storage *__a = NULL; \
 		struct  inpcb *__inp = sotoinpcb(so); \
 		KASSERT(__inp != NULL, \
 		   ("GET_LOCAL_ADDR(%s):so:%p, inp = NULL", __func__, so)); \
 		if (__inp->inp_vflag & INP_IPV4) \
-			in_getsockaddr(so, (struct sockaddr **)&__a); \
+			in_getsockaddr(so, (struct sockaddr *)pladdr); \
 		else \
-			in6_getsockaddr(so, (struct sockaddr **)&__a); \
-		*(pladdr) = *__a; \
-		free(__a, M_SONAME); \
+			in6_getsockaddr(so, (struct sockaddr *)pladdr); \
 	} while (0)
 
 #define GET_REMOTE_ADDR(praddr, so) \
 	do { \
-		struct sockaddr_storage *__a = NULL; \
 		struct  inpcb *__inp = sotoinpcb(so); \
 		KASSERT(__inp != NULL, \
 		   ("GET_REMOTE_ADDR(%s):so:%p, inp = NULL", __func__, so)); \
 		if (__inp->inp_vflag & INP_IPV4) \
-			in_getpeeraddr(so, (struct sockaddr **)&__a); \
+			in_getpeeraddr(so, (struct sockaddr *)praddr); \
 		else \
-			in6_getpeeraddr(so, (struct sockaddr **)&__a); \
-		*(praddr) = *__a; \
-		free(__a, M_SONAME); \
+			in6_getpeeraddr(so, (struct sockaddr *)praddr); \
 	} while (0)
 
 static char *states[] = {
diff --git a/sys/dev/hyperv/hvsock/hv_sock.c b/sys/dev/hyperv/hvsock/hv_sock.c
index 655cc990876e..78ec520f1bb3 100644
--- a/sys/dev/hyperv/hvsock/hv_sock.c
+++ b/sys/dev/hyperv/hvsock/hv_sock.c
@@ -876,7 +876,7 @@ out:
 }
 
 int
-hvs_trans_peeraddr(struct socket *so, struct sockaddr **nam)
+hvs_trans_peeraddr(struct socket *so, struct sockaddr *sa)
 {
 	struct hvs_pcb *pcb = so2hvspcb(so);
 
@@ -886,13 +886,13 @@ hvs_trans_peeraddr(struct socket *so, struct sockaddr **nam)
 	if (pcb == NULL)
 		return (EINVAL);
 
-	*nam = sodupsockaddr((struct sockaddr *) &pcb->remote_addr, M_NOWAIT);
+	memcpy(sa, &pcb->remote_addr, pcb->remote_addr.sa_len);
 
-	return ((*nam == NULL)? ENOMEM : 0);
+	return (0);
 }
 
 int
-hvs_trans_sockaddr(struct socket *so, struct sockaddr **nam)
+hvs_trans_sockaddr(struct socket *so, struct sockaddr *sa)
 {
 	struct hvs_pcb *pcb = so2hvspcb(so);
 
@@ -902,9 +902,9 @@ hvs_trans_sockaddr(struct socket *so, struct sockaddr **nam)
 	if (pcb == NULL)
 		return (EINVAL);
 
-	*nam = sodupsockaddr((struct sockaddr *) &pcb->local_addr, M_NOWAIT);
+	memcpy(sa, &pcb->local_addr, pcb->local_addr.sa_len);
 
-	return ((*nam == NULL)? ENOMEM : 0);
+	return (0);
 }
 
 void
diff --git a/sys/dev/hyperv/hvsock/hv_sock.h b/sys/dev/hyperv/hvsock/hv_sock.h
index ee6416a29662..e11621d76dbc 100644
--- a/sys/dev/hyperv/hvsock/hv_sock.h
+++ b/sys/dev/hyperv/hvsock/hv_sock.h
@@ -103,8 +103,8 @@ int	hvs_trans_listen(struct socket *, int, struct thread *);
 int	hvs_trans_accept(struct socket *, struct sockaddr *);
 int	hvs_trans_connect(struct socket *,
 	    struct sockaddr *, struct thread *);
-int	hvs_trans_peeraddr(struct socket *, struct sockaddr **);
-int	hvs_trans_sockaddr(struct socket *, struct sockaddr **);
+int	hvs_trans_peeraddr(struct socket *, struct sockaddr *);
+int	hvs_trans_sockaddr(struct socket *, struct sockaddr *);
 int	hvs_trans_soreceive(struct socket *, struct sockaddr **,
 	    struct uio *, struct mbuf **, struct mbuf **, int *);
 int	hvs_trans_sosend(struct socket *, struct sockaddr *, struct uio *,
diff --git a/sys/dev/wg/if_wg.c b/sys/dev/wg/if_wg.c
index 0ea40b763416..71c80c8b5f77 100644
--- a/sys/dev/wg/if_wg.c
+++ b/sys/dev/wg/if_wg.c
@@ -806,14 +806,15 @@ wg_socket_bind(struct socket **in_so4, struct socket **in_so6, in_port_t *reques
 		if (ret4 && ret4 != EADDRNOTAVAIL)
 			return (ret4);
 		if (!ret4 && !sin.sin_port) {
-			struct sockaddr_in *bound_sin;
-			int ret = so4->so_proto->pr_sockaddr(so4,
-			    (struct sockaddr **)&bound_sin);
+			struct sockaddr_in bound_sin =
+			    { .sin_len = sizeof(bound_sin) };
+			int ret;
+
+			ret = sosockaddr(so4, (struct sockaddr *)&bound_sin);
 			if (ret)
 				return (ret);
-			port = ntohs(bound_sin->sin_port);
-			sin6.sin6_port = bound_sin->sin_port;
-			free(bound_sin, M_SONAME);
+			port = ntohs(bound_sin.sin_port);
+			sin6.sin6_port = bound_sin.sin_port;
 		}
 	}
 
@@ -822,13 +823,14 @@ wg_socket_bind(struct socket **in_so4, struct socket **in_so6, in_port_t *reques
 		if (ret6 && ret6 != EADDRNOTAVAIL)
 			return (ret6);
 		if (!ret6 && !sin6.sin6_port) {
-			struct sockaddr_in6 *bound_sin6;
-			int ret = so6->so_proto->pr_sockaddr(so6,
-			    (struct sockaddr **)&bound_sin6);
+			struct sockaddr_in6 bound_sin6 =
+			    { .sin6_len = sizeof(bound_sin6) };
+			int ret;
+
+			ret = sosockaddr(so6, (struct sockaddr *)&bound_sin6);
 			if (ret)
 				return (ret);
-			port = ntohs(bound_sin6->sin6_port);
-			free(bound_sin6, M_SONAME);
+			port = ntohs(bound_sin6.sin6_port);
 		}
 	}
 
diff --git a/sys/kern/sys_socket.c b/sys/kern/sys_socket.c
index 7169805a0d3f..314576281d6e 100644
--- a/sys/kern/sys_socket.c
+++ b/sys/kern/sys_socket.c
@@ -355,7 +355,7 @@ soo_close(struct file *fp, struct thread *td)
 static int
 soo_fill_kinfo(struct file *fp, struct kinfo_file *kif, struct filedesc *fdp)
 {
-	struct sockaddr *sa;
+	struct sockaddr_storage ss = { .ss_len = sizeof(ss) };
 	struct inpcb *inpcb;
 	struct unpcb *unpcb;
 	struct socket *so;
@@ -404,17 +404,16 @@ soo_fill_kinfo(struct file *fp, struct kinfo_file *kif, struct filedesc *fdp)
 		}
 		break;
 	}
-	error = so->so_proto->pr_sockaddr(so, &sa);
+	error = sosockaddr(so, (struct sockaddr *)&ss);
 	if (error == 0 &&
-	    sa->sa_len <= sizeof(kif->kf_un.kf_sock.kf_sa_local)) {
-		bcopy(sa, &kif->kf_un.kf_sock.kf_sa_local, sa->sa_len);
-		free(sa, M_SONAME);
+	    ss.ss_len <= sizeof(kif->kf_un.kf_sock.kf_sa_local)) {
+		bcopy(&ss, &kif->kf_un.kf_sock.kf_sa_local, ss.ss_len);
 	}
-	error = so->so_proto->pr_peeraddr(so, &sa);
+	ss.ss_len = sizeof(ss);
+	error = sopeeraddr(so, (struct sockaddr *)&ss);
 	if (error == 0 &&
-	    sa->sa_len <= sizeof(kif->kf_un.kf_sock.kf_sa_peer)) {
-		bcopy(sa, &kif->kf_un.kf_sock.kf_sa_peer, sa->sa_len);
-		free(sa, M_SONAME);
+	    ss.ss_len <= sizeof(kif->kf_un.kf_sock.kf_sa_peer)) {
+		bcopy(&ss, &kif->kf_un.kf_sock.kf_sa_peer, ss.ss_len);
 	}
 	strncpy(kif->kf_path, so->so_proto->pr_domain->dom_name,
 	    sizeof(kif->kf_path));
diff --git a/sys/kern/uipc_domain.c b/sys/kern/uipc_domain.c
index cf9b91511574..435b13842041 100644
--- a/sys/kern/uipc_domain.c
+++ b/sys/kern/uipc_domain.c
@@ -116,7 +116,7 @@ pr_listen_notsupp(struct socket *so, int backlog, struct thread *td)
 }
 
 static int
-pr_peeraddr_notsupp(struct socket *so, struct sockaddr **nam)
+pr_peeraddr_notsupp(struct socket *so, struct sockaddr *nam)
 {
 	return (EOPNOTSUPP);
 }
@@ -157,7 +157,7 @@ pr_shutdown_notsupp(struct socket *so)
 }
 
 static int
-pr_sockaddr_notsupp(struct socket *so, struct sockaddr **nam)
+pr_sockaddr_notsupp(struct socket *so, struct sockaddr *nam)
 {
 	return (EOPNOTSUPP);
 }
diff --git a/sys/kern/uipc_socket.c b/sys/kern/uipc_socket.c
index d16c0049dc43..efa349d140ff 100644
--- a/sys/kern/uipc_socket.c
+++ b/sys/kern/uipc_socket.c
@@ -1363,6 +1363,40 @@ soaccept(struct socket *so, struct sockaddr *sa)
 	return (error);
 }
 
+int
+sopeeraddr(struct socket *so, struct sockaddr *sa)
+{
+#ifdef INVARIANTS
+	u_char len = sa->sa_len;
+#endif
+	int error;
+
+	CURVNET_SET(so->so_vnet);
+	error = so->so_proto->pr_peeraddr(so, sa);
+	KASSERT(sa->sa_len <= len,
+	    ("%s: protocol %p sockaddr overflow", __func__, so->so_proto));
+	CURVNET_RESTORE();
+
+	return (error);
+}
+
+int
+sosockaddr(struct socket *so, struct sockaddr *sa)
+{
+#ifdef INVARIANTS
+	u_char len = sa->sa_len;
+#endif
+	int error;
+
+	CURVNET_SET(so->so_vnet);
+	error = so->so_proto->pr_sockaddr(so, sa);
+	KASSERT(sa->sa_len <= len,
+	    ("%s: protocol %p sockaddr overflow", __func__, so->so_proto));
+	CURVNET_RESTORE();
+
+	return (error);
+}
+
 int
 soconnect(struct socket *so, struct sockaddr *nam, struct thread *td)
 {
diff --git a/sys/kern/uipc_syscalls.c b/sys/kern/uipc_syscalls.c
index 0361144f2763..e46fdef84fc9 100644
--- a/sys/kern/uipc_syscalls.c
+++ b/sys/kern/uipc_syscalls.c
@@ -1308,7 +1308,7 @@ static int
 user_getsockname(struct thread *td, int fdes, struct sockaddr *asa,
     socklen_t *alen, bool compat)
 {
-	struct sockaddr *sa;
+	struct sockaddr_storage ss = { .ss_len = sizeof(ss) };
 	socklen_t len;
 	int error;
 
@@ -1316,30 +1316,28 @@ user_getsockname(struct thread *td, int fdes, struct sockaddr *asa,
 	if (error != 0)
 		return (error);
 
-	error = kern_getsockname(td, fdes, &sa, &len);
+	error = kern_getsockname(td, fdes, (struct sockaddr *)&ss);
 	if (error != 0)
 		return (error);
 
-	if (len != 0) {
 #ifdef COMPAT_OLDSOCK
-		if (compat && SV_PROC_FLAG(td->td_proc, SV_AOUT))
-			((struct osockaddr *)sa)->sa_family = sa->sa_family;
+	if (compat && SV_PROC_FLAG(td->td_proc, SV_AOUT))
+		((struct osockaddr *)&ss)->sa_family = ss.ss_family;
 #endif
-		error = copyout(sa, asa, len);
-	}
-	free(sa, M_SONAME);
-	if (error == 0)
+	len = min(ss.ss_len, len);
+	error = copyout(&ss, asa, len);
+	if (error == 0) {
+		len = ss.ss_len;
 		error = copyout(&len, alen, sizeof(len));
+	}
 	return (error);
 }
 
 int
-kern_getsockname(struct thread *td, int fd, struct sockaddr **sa,
-    socklen_t *alen)
+kern_getsockname(struct thread *td, int fd, struct sockaddr *sa)
 {
 	struct socket *so;
 	struct file *fp;
-	socklen_t len;
 	int error;
 
 	AUDIT_ARG_FD(fd);
@@ -1347,27 +1345,12 @@ kern_getsockname(struct thread *td, int fd, struct sockaddr **sa,
 	if (error != 0)
 		return (error);
 	so = fp->f_data;
-	*sa = NULL;
-	CURVNET_SET(so->so_vnet);
-	error = so->so_proto->pr_sockaddr(so, sa);
-	CURVNET_RESTORE();
-	if (error != 0)
-		goto bad;
-	if (*sa == NULL)
-		len = 0;
-	else
-		len = MIN(*alen, (*sa)->sa_len);
-	*alen = len;
+	error = sosockaddr(so, sa);
 #ifdef KTRACE
-	if (KTRPOINT(td, KTR_STRUCT))
-		ktrsockaddr(*sa);
+	if (error == 0 && KTRPOINT(td, KTR_STRUCT))
+		ktrsockaddr(sa);
 #endif
-bad:
 	fdrop(fp, td);
-	if (error != 0 && *sa != NULL) {
-		free(*sa, M_SONAME);
-		*sa = NULL;
-	}
 	return (error);
 }
 
@@ -1389,7 +1372,7 @@ static int
 user_getpeername(struct thread *td, int fdes, struct sockaddr *asa,
     socklen_t *alen, bool compat)
 {
-	struct sockaddr *sa;
+	struct sockaddr_storage ss = { .ss_len = sizeof(ss) };
 	socklen_t len;
 	int error;
 
@@ -1397,30 +1380,28 @@ user_getpeername(struct thread *td, int fdes, struct sockaddr *asa,
 	if (error != 0)
 		return (error);
 
-	error = kern_getpeername(td, fdes, &sa, &len);
+	error = kern_getpeername(td, fdes, (struct sockaddr *)&ss);
 	if (error != 0)
 		return (error);
 
-	if (len != 0) {
 #ifdef COMPAT_OLDSOCK
-		if (compat && SV_PROC_FLAG(td->td_proc, SV_AOUT))
-			((struct osockaddr *)sa)->sa_family = sa->sa_family;
+	if (compat && SV_PROC_FLAG(td->td_proc, SV_AOUT))
+		((struct osockaddr *)&ss)->sa_family = ss.ss_family;
 #endif
-		error = copyout(sa, asa, len);
-	}
-	free(sa, M_SONAME);
-	if (error == 0)
+	len = min(ss.ss_len, len);
+	error = copyout(&ss, asa, len);
+	if (error == 0) {
+		len = ss.ss_len;
 		error = copyout(&len, alen, sizeof(len));
+	}
 	return (error);
 }
 
 int
-kern_getpeername(struct thread *td, int fd, struct sockaddr **sa,
-    socklen_t *alen)
+kern_getpeername(struct thread *td, int fd, struct sockaddr *sa)
 {
 	struct socket *so;
 	struct file *fp;
-	socklen_t len;
 	int error;
 
 	AUDIT_ARG_FD(fd);
@@ -1432,26 +1413,11 @@ kern_getpeername(struct thread *td, int fd, struct sockaddr **sa,
 		error = ENOTCONN;
 		goto done;
 	}
-	*sa = NULL;
-	CURVNET_SET(so->so_vnet);
-	error = so->so_proto->pr_peeraddr(so, sa);
-	CURVNET_RESTORE();
-	if (error != 0)
-		goto bad;
-	if (*sa == NULL)
-		len = 0;
-	else
-		len = MIN(*alen, (*sa)->sa_len);
-	*alen = len;
+	error = sopeeraddr(so, sa);
 #ifdef KTRACE
-	if (KTRPOINT(td, KTR_STRUCT))
-		ktrsockaddr(*sa);
+	if (error == 0 && KTRPOINT(td, KTR_STRUCT))
+		ktrsockaddr(sa);
 #endif
-bad:
-	if (error != 0 && *sa != NULL) {
-		free(*sa, M_SONAME);
-		*sa = NULL;
-	}
 done:
 	fdrop(fp, td);
 	return (error);
diff --git a/sys/kern/uipc_usrreq.c b/sys/kern/uipc_usrreq.c
index 3071a5169b72..069294e1c963 100644
--- a/sys/kern/uipc_usrreq.c
+++ b/sys/kern/uipc_usrreq.c
@@ -436,33 +436,6 @@ uipc_abort(struct socket *so)
 		UNP_PCB_UNLOCK(unp);
 }
 
-static int
-uipc_accept(struct socket *so, struct sockaddr *ret)
-{
-	struct unpcb *unp, *unp2;
-	const struct sockaddr *sa;
-
-	/*
-	 * Pass back name of connected socket, if it was bound and we are
-	 * still connected (our peer may have closed already!).
-	 */
-	unp = sotounpcb(so);
-	KASSERT(unp != NULL, ("uipc_accept: unp == NULL"));
-
-	UNP_PCB_LOCK(unp);
-	unp2 = unp_pcb_lock_peer(unp);
-	if (unp2 != NULL && unp2->unp_addr != NULL)
-		sa = (struct sockaddr *)unp2->unp_addr;
-	else
-		sa = &sun_noname;
-	bcopy(sa, ret, sa->sa_len);
-	if (unp2 != NULL)
-		unp_pcb_unlock_pair(unp, unp2);
-	else
-		UNP_PCB_UNLOCK(unp);
-	return (0);
-}
-
 static int
 uipc_attach(struct socket *so, int proto, struct thread *td)
 {
@@ -874,7 +847,7 @@ uipc_listen(struct socket *so, int backlog, struct thread *td)
 }
 
 static int
-uipc_peeraddr(struct socket *so, struct sockaddr **nam)
+uipc_peeraddr(struct socket *so, struct sockaddr *ret)
 {
 	struct unpcb *unp, *unp2;
 	const struct sockaddr *sa;
@@ -882,8 +855,6 @@ uipc_peeraddr(struct socket *so, struct sockaddr **nam)
 	unp = sotounpcb(so);
 	KASSERT(unp != NULL, ("uipc_peeraddr: unp == NULL"));
 
-	*nam = malloc(sizeof(struct sockaddr_un), M_SONAME, M_WAITOK);
-
 	UNP_PCB_LOCK(unp);
 	unp2 = unp_pcb_lock_peer(unp);
 	if (unp2 != NULL) {
@@ -891,12 +862,12 @@ uipc_peeraddr(struct socket *so, struct sockaddr **nam)
 			sa = (struct sockaddr *)unp2->unp_addr;
 		else
 			sa = &sun_noname;
-		bcopy(sa, *nam, sa->sa_len);
+		bcopy(sa, ret, sa->sa_len);
 		unp_pcb_unlock_pair(unp, unp2);
 	} else {
-		sa = &sun_noname;
-		bcopy(sa, *nam, sa->sa_len);
 		UNP_PCB_UNLOCK(unp);
+		sa = &sun_noname;
+		bcopy(sa, ret, sa->sa_len);
 	}
 	return (0);
 }
@@ -1704,7 +1675,7 @@ uipc_shutdown(struct socket *so)
 }
 
 static int
-uipc_sockaddr(struct socket *so, struct sockaddr **nam)
+uipc_sockaddr(struct socket *so, struct sockaddr *ret)
 {
 	struct unpcb *unp;
 	const struct sockaddr *sa;
@@ -1712,13 +1683,12 @@ uipc_sockaddr(struct socket *so, struct sockaddr **nam)
 	unp = sotounpcb(so);
 	KASSERT(unp != NULL, ("uipc_sockaddr: unp == NULL"));
 
-	*nam = malloc(sizeof(struct sockaddr_un), M_SONAME, M_WAITOK);
 	UNP_PCB_LOCK(unp);
 	if (unp->unp_addr != NULL)
 		sa = (struct sockaddr *) unp->unp_addr;
 	else
 		sa = &sun_noname;
-	bcopy(sa, *nam, sa->sa_len);
+	bcopy(sa, ret, sa->sa_len);
 	UNP_PCB_UNLOCK(unp);
 	return (0);
 }
@@ -3322,7 +3292,7 @@ static struct protosw streamproto = {
 				    PR_CAPATTACH,
 	.pr_ctloutput =		&uipc_ctloutput,
 	.pr_abort = 		uipc_abort,
-	.pr_accept =		uipc_accept,
+	.pr_accept =		uipc_peeraddr,
 	.pr_attach =		uipc_attach,
 	.pr_bind =		uipc_bind,
 	.pr_bindat =		uipc_bindat,
@@ -3349,7 +3319,7 @@ static struct protosw dgramproto = {
 				    PR_SOCKBUF,
 	.pr_ctloutput =		&uipc_ctloutput,
 	.pr_abort = 		uipc_abort,
-	.pr_accept =		uipc_accept,
+	.pr_accept =		uipc_peeraddr,
 	.pr_attach =		uipc_attach,
 	.pr_bind =		uipc_bind,
 	.pr_bindat =		uipc_bindat,
@@ -3378,7 +3348,7 @@ static struct protosw seqpacketproto = {
 				    PR_WANTRCVD|PR_RIGHTS|PR_CAPATTACH,
 	.pr_ctloutput =		&uipc_ctloutput,
 	.pr_abort =		uipc_abort,
-	.pr_accept =		uipc_accept,
+	.pr_accept =		uipc_peeraddr,
 	.pr_attach =		uipc_attach,
 	.pr_bind =		uipc_bind,
 	.pr_bindat =		uipc_bindat,
diff --git a/sys/net/if_ovpn.c b/sys/net/if_ovpn.c
index 1b5d419fe58b..fb9596069101 100644
--- a/sys/net/if_ovpn.c
+++ b/sys/net/if_ovpn.c
@@ -508,7 +508,6 @@ ovpn_new_peer(struct ifnet *ifp, const nvlist_t *nvl)
 	struct sockaddr_storage remote;
 	struct ovpn_kpeer *peer = NULL;
 	struct file *fp = NULL;
-	struct sockaddr *name = NULL;
 	struct ovpn_softc *sc = ifp->if_softc;
 	struct thread *td = curthread;
 	struct socket *so = NULL;
@@ -574,23 +573,21 @@ ovpn_new_peer(struct ifnet *ifp, const nvlist_t *nvl)
 	callout_init_rm(&peer->ping_send, &sc->lock, CALLOUT_SHAREDLOCK);
 	callout_init_rm(&peer->ping_rcv, &sc->lock, 0);
 
-	ret = so->so_proto->pr_sockaddr(so, &name);
+	peer->local.ss_len = sizeof(peer->local);
+	ret = sosockaddr(so, (struct sockaddr *)&peer->local);
 	if (ret)
 		goto error;
 
-	if (ovpn_get_port((struct sockaddr_storage *)name) == 0) {
+	if (ovpn_get_port(&peer->local) == 0) {
 		ret = EINVAL;
 		goto error;
 	}
-	if (name->sa_family != remote.ss_family) {
+	if (peer->local.ss_family != remote.ss_family) {
 		ret = EINVAL;
 		goto error;
 	}
 
-	memcpy(&peer->local, name, name->sa_len);
 	memcpy(&peer->remote, &remote, sizeof(remote));
-	free(name, M_SONAME);
-	name = NULL;
 
 	if (peer->local.ss_family == AF_INET6 &&
 	    IN6_IS_ADDR_V4MAPPED(&TO_IN6(&peer->remote)->sin6_addr)) {
@@ -656,7 +653,6 @@ ovpn_new_peer(struct ifnet *ifp, const nvlist_t *nvl)
 error_locked:
 	OVPN_WUNLOCK(sc);
 error:
-	free(name, M_SONAME);
 	COUNTER_ARRAY_FREE(peer->counters, OVPN_PEER_COUNTER_SIZE);
 	uma_zfree_pcpu(pcpu_zone_4, peer->last_active);
 	free(peer, M_OVPN);
diff --git a/sys/netgraph/bluetooth/include/ng_btsocket_hci_raw.h b/sys/netgraph/bluetooth/include/ng_btsocket_hci_raw.h
index 05c109df1570..b55c95b29ee3 100644
--- a/sys/netgraph/bluetooth/include/ng_btsocket_hci_raw.h
+++ b/sys/netgraph/bluetooth/include/ng_btsocket_hci_raw.h
@@ -78,11 +78,10 @@ int  ng_btsocket_hci_raw_control    (struct socket *, u_long, void *,
 int  ng_btsocket_hci_raw_ctloutput  (struct socket *, struct sockopt *);
 void ng_btsocket_hci_raw_detach     (struct socket *);
 int  ng_btsocket_hci_raw_disconnect (struct socket *);
-int  ng_btsocket_hci_raw_peeraddr   (struct socket *, struct sockaddr **);
 int  ng_btsocket_hci_raw_send       (struct socket *, int, struct mbuf *,
                                      struct sockaddr *, struct mbuf *,
                                      struct thread *);
-int  ng_btsocket_hci_raw_sockaddr   (struct socket *, struct sockaddr **);
+int  ng_btsocket_hci_raw_sockaddr   (struct socket *, struct sockaddr *);
 
 #endif /* _KERNEL */
 
diff --git a/sys/netgraph/bluetooth/include/ng_btsocket_l2cap.h b/sys/netgraph/bluetooth/include/ng_btsocket_l2cap.h
index b512112f8b7d..7181e369119d 100644
--- a/sys/netgraph/bluetooth/include/ng_btsocket_l2cap.h
+++ b/sys/netgraph/bluetooth/include/ng_btsocket_l2cap.h
@@ -105,11 +105,11 @@ int  ng_btsocket_l2cap_raw_control    (struct socket *, u_long, void *,
                                        struct ifnet *, struct thread *);
 void ng_btsocket_l2cap_raw_detach     (struct socket *);
 int  ng_btsocket_l2cap_raw_disconnect (struct socket *);
-int  ng_btsocket_l2cap_raw_peeraddr   (struct socket *, struct sockaddr **);
+int  ng_btsocket_l2cap_raw_peeraddr   (struct socket *, struct sockaddr *);
 int  ng_btsocket_l2cap_raw_send       (struct socket *, int, struct mbuf *,
                                        struct sockaddr *, struct mbuf *,
                                        struct thread *);
-int  ng_btsocket_l2cap_raw_sockaddr   (struct socket *, struct sockaddr **);
+int  ng_btsocket_l2cap_raw_sockaddr   (struct socket *, struct sockaddr *);
 
 #endif /* _KERNEL */
 
@@ -191,7 +191,6 @@ typedef struct ng_btsocket_l2cap_pcb *	ng_btsocket_l2cap_pcb_p;
 
 void ng_btsocket_l2cap_abort      (struct socket *);
 void ng_btsocket_l2cap_close      (struct socket *);
-int  ng_btsocket_l2cap_accept     (struct socket *, struct sockaddr *);
 int  ng_btsocket_l2cap_attach     (struct socket *, int, struct thread *);
 int  ng_btsocket_l2cap_bind       (struct socket *, struct sockaddr *,
                                    struct thread *);
@@ -203,11 +202,11 @@ int  ng_btsocket_l2cap_ctloutput  (struct socket *, struct sockopt *);
 void ng_btsocket_l2cap_detach     (struct socket *);
 int  ng_btsocket_l2cap_disconnect (struct socket *);
 int  ng_btsocket_l2cap_listen     (struct socket *, int, struct thread *);
-int  ng_btsocket_l2cap_peeraddr   (struct socket *, struct sockaddr **);
+int  ng_btsocket_l2cap_peeraddr   (struct socket *, struct sockaddr *);
 int  ng_btsocket_l2cap_send       (struct socket *, int, struct mbuf *,
                                    struct sockaddr *, struct mbuf *,
                                    struct thread *);
-int  ng_btsocket_l2cap_sockaddr   (struct socket *, struct sockaddr **);
+int  ng_btsocket_l2cap_sockaddr   (struct socket *, struct sockaddr *);
 
 #endif /* _KERNEL */
 
diff --git a/sys/netgraph/bluetooth/include/ng_btsocket_rfcomm.h b/sys/netgraph/bluetooth/include/ng_btsocket_rfcomm.h
index d40b694ece14..a5448ed943a2 100644
--- a/sys/netgraph/bluetooth/include/ng_btsocket_rfcomm.h
+++ b/sys/netgraph/bluetooth/include/ng_btsocket_rfcomm.h
@@ -328,11 +328,11 @@ int  ng_btsocket_rfcomm_ctloutput  (struct socket *, struct sockopt *);
 void ng_btsocket_rfcomm_detach     (struct socket *);
 int  ng_btsocket_rfcomm_disconnect (struct socket *);
 int  ng_btsocket_rfcomm_listen     (struct socket *, int, struct thread *);
-int  ng_btsocket_rfcomm_peeraddr   (struct socket *, struct sockaddr **);
+int  ng_btsocket_rfcomm_peeraddr   (struct socket *, struct sockaddr *);
 int  ng_btsocket_rfcomm_send       (struct socket *, int, struct mbuf *,
                                     struct sockaddr *, struct mbuf *,
                                     struct thread *);
-int  ng_btsocket_rfcomm_sockaddr   (struct socket *, struct sockaddr **);
+int  ng_btsocket_rfcomm_sockaddr   (struct socket *, struct sockaddr *);
 
 #endif /* _KERNEL */
 
diff --git a/sys/netgraph/bluetooth/include/ng_btsocket_sco.h b/sys/netgraph/bluetooth/include/ng_btsocket_sco.h
index 282980cce881..4b131dab4223 100644
--- a/sys/netgraph/bluetooth/include/ng_btsocket_sco.h
+++ b/sys/netgraph/bluetooth/include/ng_btsocket_sco.h
@@ -118,11 +118,11 @@ int  ng_btsocket_sco_ctloutput  (struct socket *, struct sockopt *);
 void ng_btsocket_sco_detach     (struct socket *);
 int  ng_btsocket_sco_disconnect (struct socket *);
 int  ng_btsocket_sco_listen     (struct socket *, int, struct thread *);
-int  ng_btsocket_sco_peeraddr   (struct socket *, struct sockaddr **);
+int  ng_btsocket_sco_peeraddr   (struct socket *, struct sockaddr *);
 int  ng_btsocket_sco_send       (struct socket *, int, struct mbuf *,
                                    struct sockaddr *, struct mbuf *,
                                    struct thread *);
-int  ng_btsocket_sco_sockaddr   (struct socket *, struct sockaddr **);
+int  ng_btsocket_sco_sockaddr   (struct socket *, struct sockaddr *);
 
 #endif /* _KERNEL */
 
diff --git a/sys/netgraph/bluetooth/socket/ng_btsocket.c b/sys/netgraph/bluetooth/socket/ng_btsocket.c
index 03fa322e7775..a90256595911 100644
--- a/sys/netgraph/bluetooth/socket/ng_btsocket.c
+++ b/sys/netgraph/bluetooth/socket/ng_btsocket.c
@@ -79,7 +79,7 @@ static struct protosw ng_btsocket_hci_raw_protosw = {
 	.pr_control =		ng_btsocket_hci_raw_control,
 	.pr_detach =		ng_btsocket_hci_raw_detach,
 	.pr_disconnect =	ng_btsocket_hci_raw_disconnect,
-	.pr_peeraddr =		ng_btsocket_hci_raw_peeraddr,
+	.pr_peeraddr =		ng_btsocket_hci_raw_sockaddr,
 	.pr_send =		ng_btsocket_hci_raw_send,
 	.pr_sockaddr =		ng_btsocket_hci_raw_sockaddr,
 	.pr_close =		ng_btsocket_hci_raw_close,
@@ -110,7 +110,7 @@ static struct protosw ng_btsocket_l2cap_protosw = {
 	.pr_flags =		PR_ATOMIC|PR_CONNREQUIRED,
 	.pr_ctloutput =		ng_btsocket_l2cap_ctloutput,
 	.pr_abort =		ng_btsocket_l2cap_abort,
-	.pr_accept =		ng_btsocket_l2cap_accept,
+	.pr_accept =		ng_btsocket_l2cap_peeraddr,
 	.pr_attach =		ng_btsocket_l2cap_attach,
 	.pr_bind =		ng_btsocket_l2cap_bind,
 	.pr_connect =		ng_btsocket_l2cap_connect,
@@ -131,7 +131,7 @@ static struct protosw ng_btsocket_rfcomm_protosw = {
 	.pr_flags =		PR_CONNREQUIRED,
 	.pr_ctloutput =		ng_btsocket_rfcomm_ctloutput,
 	.pr_abort =		ng_btsocket_rfcomm_abort,
-	.pr_accept =		ng_btsocket_rfcomm_accept,
+	.pr_accept =		ng_btsocket_rfcomm_peeraddr,
 	.pr_attach =		ng_btsocket_rfcomm_attach,
 	.pr_bind =		ng_btsocket_rfcomm_bind,
 	.pr_connect =		ng_btsocket_rfcomm_connect,
@@ -152,7 +152,7 @@ static struct protosw ng_btsocket_sco_protosw = {
 	.pr_flags =		PR_ATOMIC|PR_CONNREQUIRED,
 	.pr_ctloutput =		ng_btsocket_sco_ctloutput,
 	.pr_abort =		ng_btsocket_sco_abort,
-	.pr_accept =		ng_btsocket_sco_accept,
+	.pr_accept =		ng_btsocket_sco_peeraddr,
 	.pr_attach =		ng_btsocket_sco_attach,
 	.pr_bind =		ng_btsocket_sco_bind,
 	.pr_connect =		ng_btsocket_sco_connect,
diff --git a/sys/netgraph/bluetooth/socket/ng_btsocket_hci_raw.c b/sys/netgraph/bluetooth/socket/ng_btsocket_hci_raw.c
index 935991696929..5d015b2eac6e 100644
--- a/sys/netgraph/bluetooth/socket/ng_btsocket_hci_raw.c
+++ b/sys/netgraph/bluetooth/socket/ng_btsocket_hci_raw.c
@@ -1556,16 +1556,6 @@ ng_btsocket_hci_raw_disconnect(struct socket *so)
 	return (0);
 } /* ng_btsocket_hci_raw_disconnect */
 
-/*
- * Get socket peer's address
- */
-
-int
-ng_btsocket_hci_raw_peeraddr(struct socket *so, struct sockaddr **nam)
-{
-	return (ng_btsocket_hci_raw_sockaddr(so, nam));
-} /* ng_btsocket_hci_raw_peeraddr */
-
 /*
  * Send data
  */
@@ -1656,25 +1646,24 @@ drop:
  */
 
 int
-ng_btsocket_hci_raw_sockaddr(struct socket *so, struct sockaddr **nam)
+ng_btsocket_hci_raw_sockaddr(struct socket *so, struct sockaddr *sa)
 {
 	ng_btsocket_hci_raw_pcb_p	pcb = so2hci_raw_pcb(so);
-	struct sockaddr_hci		sa;
+	struct sockaddr_hci *hci = (struct sockaddr_hci *)sa;
 
 	if (pcb == NULL)
 		return (EINVAL);
 	if (ng_btsocket_hci_raw_node == NULL)
 		return (EINVAL);
 
-	bzero(&sa, sizeof(sa));
-	sa.hci_len = sizeof(sa);
-	sa.hci_family = AF_BLUETOOTH;
+	*hci = (struct sockaddr_hci ){
+		.hci_len = sizeof(struct sockaddr_hci),
+		.hci_family = AF_BLUETOOTH,
+	};
 
 	mtx_lock(&pcb->pcb_mtx);
-	strlcpy(sa.hci_node, pcb->addr.hci_node, sizeof(sa.hci_node));
+	strlcpy(hci->hci_node, pcb->addr.hci_node, sizeof(hci->hci_node));
 	mtx_unlock(&pcb->pcb_mtx);
 
-	*nam = sodupsockaddr((struct sockaddr *) &sa, M_NOWAIT);
-
-	return ((*nam == NULL)? ENOMEM : 0);
-} /* ng_btsocket_hci_raw_sockaddr */
+	return (0);
+}
diff --git a/sys/netgraph/bluetooth/socket/ng_btsocket_l2cap.c b/sys/netgraph/bluetooth/socket/ng_btsocket_l2cap.c
index d221cc34d36a..ae5405529667 100644
--- a/sys/netgraph/bluetooth/socket/ng_btsocket_l2cap.c
+++ b/sys/netgraph/bluetooth/socket/ng_btsocket_l2cap.c
@@ -2509,68 +2509,43 @@ out:
*** 1566 LINES SKIPPED ***