diff options
author | Alexander Bluhm <bluhm@cvs.openbsd.org> | 2025-01-09 16:47:25 +0000 |
---|---|---|
committer | Alexander Bluhm <bluhm@cvs.openbsd.org> | 2025-01-09 16:47:25 +0000 |
commit | 2befe21b3a9527cf7e7259e1735254d9c8fb5a7a (patch) | |
tree | 4913d4ba81da8b99b3d3f2af506e948ed00f38ac | |
parent | 48991c3b2faa43a8532047d9d365cb4216bf2c26 (diff) |
Run TCP sysctl ident and drop with shared net lock.
Convert exclusive net lock for TCPCTL_IDENT and TCPCTL_DROP to
shared net lock and push it down into tcp_ident(). Grab the socket
lock there with in_pcbsolock_ref(). Move socket release from
in_pcbsolock() to in_pcbsounlock_rele() and add _ref and _rele
suffix to the inpcb socket lock functions. They both lock and
refcount now. in_pcbsounlock_rele() ignores NULL sockets to make
the unlock path in error case simpler. Socket lock also protects
tcp_drop() and tcp_close() now, so the socket pointer from incpb
may be NULL during unlock. In tcp_ident() improve consistency check
of address family.
OK mvs@
-rw-r--r-- | sys/netinet/in_pcb.c | 14 | ||||
-rw-r--r-- | sys/netinet/in_pcb.h | 6 | ||||
-rw-r--r-- | sys/netinet/tcp_input.c | 6 | ||||
-rw-r--r-- | sys/netinet/tcp_usrreq.c | 71 |
4 files changed, 59 insertions, 38 deletions
diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c index 2894276ee6e..61525bded00 100644 --- a/sys/netinet/in_pcb.c +++ b/sys/netinet/in_pcb.c @@ -1,4 +1,4 @@ -/* $OpenBSD: in_pcb.c,v 1.309 2025/01/03 12:56:15 mvs Exp $ */ +/* $OpenBSD: in_pcb.c,v 1.310 2025/01/09 16:47:24 bluhm Exp $ */ /* $NetBSD: in_pcb.c,v 1.25 1996/02/13 23:41:53 christos Exp $ */ /* @@ -623,7 +623,7 @@ in_pcbdetach(struct inpcb *inp) } struct socket * -in_pcbsolock(struct inpcb *inp) +in_pcbsolock_ref(struct inpcb *inp) { struct socket *so; @@ -634,18 +634,18 @@ in_pcbsolock(struct inpcb *inp) mtx_leave(&inp->inp_sofree_mtx); if (so == NULL) return NULL; - rw_enter_write(&so->so_lock); - sorele(so); - return so; } void -in_pcbsounlock(struct inpcb *inp, struct socket *so) +in_pcbsounlock_rele(struct inpcb *inp, struct socket *so) { - KASSERT(inp->inp_socket == so); + if (so == NULL) + return; + KASSERT(inp->inp_socket == NULL || inp->inp_socket == so); rw_exit_write(&so->so_lock); + sorele(so); } struct inpcb * diff --git a/sys/netinet/in_pcb.h b/sys/netinet/in_pcb.h index 36011c6c4f0..56adec0c6bf 100644 --- a/sys/netinet/in_pcb.h +++ b/sys/netinet/in_pcb.h @@ -1,4 +1,4 @@ -/* $OpenBSD: in_pcb.h,v 1.163 2025/01/05 12:10:39 bluhm Exp $ */ +/* $OpenBSD: in_pcb.h,v 1.164 2025/01/09 16:47:24 bluhm Exp $ */ /* $NetBSD: in_pcb.h,v 1.14 1996/02/13 23:42:00 christos Exp $ */ /* @@ -311,8 +311,8 @@ int in_pcbaddrisavail(const struct inpcb *, struct sockaddr_in *, int, int in_pcbconnect(struct inpcb *, struct mbuf *); void in_pcbdetach(struct inpcb *); struct socket * - in_pcbsolock(struct inpcb *); -void in_pcbsounlock(struct inpcb *, struct socket *); + in_pcbsolock_ref(struct inpcb *); +void in_pcbsounlock_rele(struct inpcb *, struct socket *); struct inpcb * in_pcbref(struct inpcb *); void in_pcbunref(struct inpcb *); diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c index 0ecd7e0f990..715b5e00506 100644 --- a/sys/netinet/tcp_input.c +++ b/sys/netinet/tcp_input.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tcp_input.c,v 1.420 2025/01/05 12:18:48 bluhm Exp $ */ +/* $OpenBSD: tcp_input.c,v 1.421 2025/01/09 16:47:24 bluhm Exp $ */ /* $NetBSD: tcp_input.c,v 1.23 1996/02/13 23:43:44 christos Exp $ */ /* @@ -3410,7 +3410,7 @@ syn_cache_timer(void *arg) mtx_leave(&syn_cache_mtx); NET_LOCK_SHARED(); - so = in_pcbsolock(inp); + so = in_pcbsolock_ref(inp); if (so != NULL) { now = tcp_now(); #ifdef TCP_ECN @@ -3418,8 +3418,8 @@ syn_cache_timer(void *arg) #endif (void) syn_cache_respond(sc, NULL, now, do_ecn); tcpstat_inc(tcps_sc_retransmitted); - in_pcbsounlock(inp, so); } + in_pcbsounlock_rele(inp, so); NET_UNLOCK_SHARED(); in_pcbunref(inp); diff --git a/sys/netinet/tcp_usrreq.c b/sys/netinet/tcp_usrreq.c index 9a8a12098da..bc40c35242e 100644 --- a/sys/netinet/tcp_usrreq.c +++ b/sys/netinet/tcp_usrreq.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tcp_usrreq.c,v 1.238 2025/01/05 12:23:38 bluhm Exp $ */ +/* $OpenBSD: tcp_usrreq.c,v 1.239 2025/01/09 16:47:24 bluhm Exp $ */ /* $NetBSD: tcp_usrreq.c,v 1.20 1996/02/13 23:44:16 christos Exp $ */ /* @@ -1122,15 +1122,13 @@ tcp_ident(void *oldp, size_t *oldlenp, void *newp, size_t newlen, int dodrop) int error = 0; struct tcp_ident_mapping tir; struct inpcb *inp; - struct tcpcb *tp = NULL; + struct socket *so = NULL; struct sockaddr_in *fin, *lin; #ifdef INET6 struct sockaddr_in6 *fin6, *lin6; struct in6_addr f6, l6; #endif - NET_ASSERT_LOCKED(); - if (dodrop) { if (oldp != NULL || *oldlenp != 0) return (EINVAL); @@ -1150,25 +1148,41 @@ tcp_ident(void *oldp, size_t *oldlenp, void *newp, size_t newlen, int dodrop) if ((error = copyin(oldp, &tir, sizeof (tir))) != 0 ) return (error); } + + NET_LOCK_SHARED(); + switch (tir.faddr.ss_family) { #ifdef INET6 case AF_INET6: + if (tir.laddr.ss_family != AF_INET6) { + NET_UNLOCK_SHARED(); + return (EAFNOSUPPORT); + } fin6 = (struct sockaddr_in6 *)&tir.faddr; error = in6_embedscope(&f6, fin6, NULL, NULL); - if (error) + if (error) { + NET_UNLOCK_SHARED(); return EINVAL; /*?*/ + } lin6 = (struct sockaddr_in6 *)&tir.laddr; error = in6_embedscope(&l6, lin6, NULL, NULL); - if (error) + if (error) { + NET_UNLOCK_SHARED(); return EINVAL; /*?*/ + } break; #endif case AF_INET: + if (tir.laddr.ss_family != AF_INET) { + NET_UNLOCK_SHARED(); + return (EAFNOSUPPORT); + } fin = (struct sockaddr_in *)&tir.faddr; lin = (struct sockaddr_in *)&tir.laddr; break; default: - return (EINVAL); + NET_UNLOCK_SHARED(); + return (EAFNOSUPPORT); } switch (tir.faddr.ss_family) { @@ -1187,11 +1201,20 @@ tcp_ident(void *oldp, size_t *oldlenp, void *newp, size_t newlen, int dodrop) } if (dodrop) { - if (inp && (tp = intotcpcb(inp)) && - ((inp->inp_socket->so_options & SO_ACCEPTCONN) == 0)) + struct tcpcb *tp = NULL; + + if (inp != NULL) { + so = in_pcbsolock_ref(inp); + if (so != NULL) + tp = intotcpcb(inp); + } + if (tp != NULL && !ISSET(so->so_options, SO_ACCEPTCONN)) tp = tcp_drop(tp, ECONNABORTED); else error = ESRCH; + + in_pcbsounlock_rele(inp, so); + NET_UNLOCK_SHARED(); in_pcbunref(inp); return (error); } @@ -1212,18 +1235,23 @@ tcp_ident(void *oldp, size_t *oldlenp, void *newp, size_t newlen, int dodrop) } } - if (inp != NULL && (inp->inp_socket->so_state & SS_CONNECTOUT)) { - tir.ruid = inp->inp_socket->so_ruid; - tir.euid = inp->inp_socket->so_euid; + if (inp != NULL) + so = in_pcbsolock_ref(inp); + + if (so != NULL && ISSET(so->so_state, SS_CONNECTOUT)) { + tir.ruid = so->so_ruid; + tir.euid = so->so_euid; } else { tir.ruid = -1; tir.euid = -1; } - *oldlenp = sizeof (tir); - error = copyout((void *)&tir, oldp, sizeof (tir)); + in_pcbsounlock_rele(inp, so); + NET_UNLOCK_SHARED(); in_pcbunref(inp); - return (error); + + *oldlenp = sizeof(tir); + return copyout(&tir, oldp, sizeof(tir)); } int @@ -1428,16 +1456,10 @@ tcp_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, return (error); case TCPCTL_IDENT: - NET_LOCK(); - error = tcp_ident(oldp, oldlenp, newp, newlen, 0); - NET_UNLOCK(); - return (error); + return tcp_ident(oldp, oldlenp, newp, newlen, 0); case TCPCTL_DROP: - NET_LOCK(); - error = tcp_ident(oldp, oldlenp, newp, newlen, 1); - NET_UNLOCK(); - return (error); + return tcp_ident(oldp, oldlenp, newp, newlen, 1); case TCPCTL_REASS_LIMIT: NET_LOCK(); @@ -1506,9 +1528,8 @@ tcp_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, return (error); default: - error = sysctl_bounded_arr(tcpctl_vars, nitems(tcpctl_vars), + return sysctl_bounded_arr(tcpctl_vars, nitems(tcpctl_vars), name, namelen, oldp, oldlenp, newp, newlen); - return (error); } /* NOTREACHED */ } |