Print this page
14685 sotpi ops need to be wary of null v_stream

*** 21,30 **** --- 21,31 ---- /* * Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright 2015, Joyent, Inc. * Copyright 2016 Nexenta Systems, Inc. All rights reserved. + * Copyright 2022 MNX Cloud, Inc. */ #include <sys/types.h> #include <sys/t_lock.h> #include <sys/param.h>
*** 259,268 **** --- 260,288 ---- sotpi_poll, /* sop_poll */ sotpi_close, /* sop_close */ }; /* + * Post-close reality check for NULL v_stream... + * + * Kernel callers (e.g. in procfs) may attempt socket operations, after + * holding the vnode, after it has been closed. For TPI sockets, post-close + * operations will have a NULL v_stream (which all functions here assume + * or even ASSERT() is non-NULL). See sotpi_close for where we wipe it out. + * + * If we are in a state where we lost a race to close(), we need to stop ASAP, + * and return the acceptable-as-an-errno EBADF. Because cleanup may be + * required, this macro only checks the v_stream. + * + * Checking should only be relevant for in-kernel other-thread inspectors. + * Userland ones (i.e. same process that opened the socktpi socket) SHOULD be + * protected by higher-level mechanisms. The only in-kernel inspector in the + * source base is procfs, which only accesses get{sockname,peername,sockopt}(). + */ + #define SOTPI_VN_NOSTREAM(vn) ((vn)->v_stream == NULL) + + /* * Return a TPI socket vnode. * * Note that sockets assume that the driver will clone (either itself * or by using the clone driver) i.e. a socket() call will always * result in a new vnode being created.
*** 1001,1011 **** VN_HOLD(rvp); VN_RELE(vp); vp = rvp; } ! ASSERT(SOTOV(so)->v_stream); mutex_enter(&vp->v_lock); vp->v_stream = SOTOV(so)->v_stream; sti->sti_ux_bound_vp = vp; mutex_exit(&vp->v_lock); --- 1021,1031 ---- VN_HOLD(rvp); VN_RELE(vp); vp = rvp; } ! ASSERT(SOTOV(so)->v_stream != NULL); mutex_enter(&vp->v_lock); vp->v_stream = SOTOV(so)->v_stream; sti->sti_ux_bound_vp = vp; mutex_exit(&vp->v_lock);
*** 4966,4982 **** --- 4986,5008 ---- int error = 0, res; void *addr; t_uscalar_t addrlen; k_sigset_t smask; sotpi_info_t *sti = SOTOTPI(so); + vnode_t *vn; dprintso(so, 1, ("sotpi_getpeername(%p) %s\n", (void *)so, pr_state(so->so_state, so->so_mode))); ASSERT(*namelen > 0); mutex_enter(&so->so_lock); so_lock_single(so); /* Set SOLOCKED */ + vn = SOTOV(so); + if (SOTPI_VN_NOSTREAM(vn)) { + error = EBADF; + goto done; + } if (accept) { bcopy(sti->sti_faddr_sa, name, MIN(*namelen, sti->sti_faddr_len)); *namelen = sti->sti_faddr_noxlate ? 0: sti->sti_faddr_len;
*** 5037,5047 **** strbuf.len = 0; sigintr(&smask, 0); res = 0; ASSERT(cr); ! error = strioctl(SOTOV(so), TI_GETPEERNAME, (intptr_t)&strbuf, 0, K_TO_K, cr, &res); sigunintr(&smask); mutex_enter(&so->so_lock); /* --- 5063,5073 ---- strbuf.len = 0; sigintr(&smask, 0); res = 0; ASSERT(cr); ! error = strioctl(vn, TI_GETPEERNAME, (intptr_t)&strbuf, 0, K_TO_K, cr, &res); sigunintr(&smask); mutex_enter(&so->so_lock); /*
*** 5102,5118 **** --- 5128,5150 ---- int error = 0, res; void *addr; t_uscalar_t addrlen; k_sigset_t smask; sotpi_info_t *sti = SOTOTPI(so); + vnode_t *vn; dprintso(so, 1, ("sotpi_getsockname(%p) %s\n", (void *)so, pr_state(so->so_state, so->so_mode))); ASSERT(*namelen > 0); mutex_enter(&so->so_lock); so_lock_single(so); /* Set SOLOCKED */ + vn = SOTOV(so); + if (SOTPI_VN_NOSTREAM(vn)) { + error = EBADF; + goto done; + } #ifdef DEBUG dprintso(so, 1, ("sotpi_getsockname (local): %s\n", pr_addr(so->so_family, sti->sti_laddr_sa,
*** 5162,5172 **** strbuf.len = 0; sigintr(&smask, 0); res = 0; ASSERT(cr); ! error = strioctl(SOTOV(so), TI_GETMYNAME, (intptr_t)&strbuf, 0, K_TO_K, cr, &res); sigunintr(&smask); mutex_enter(&so->so_lock); /* --- 5194,5204 ---- strbuf.len = 0; sigintr(&smask, 0); res = 0; ASSERT(cr); ! error = strioctl(vn, TI_GETMYNAME, (intptr_t)&strbuf, 0, K_TO_K, cr, &res); sigunintr(&smask); mutex_enter(&so->so_lock); /*
*** 5236,5252 **** --- 5268,5291 ---- t_uscalar_t len; uint32_t value; struct timeval tmo_val; /* used for SO_RCVTIMEO, SO_SNDTIMEO */ struct timeval32 tmo_val32; struct so_snd_bufinfo snd_bufinfo; /* used for zero copy */ + vnode_t *vn; dprintso(so, 1, ("sotpi_getsockopt(%p, 0x%x, 0x%x, %p, %p) %s\n", (void *)so, level, option_name, optval, (void *)optlenp, pr_state(so->so_state, so->so_mode))); mutex_enter(&so->so_lock); so_lock_single(so); /* Set SOLOCKED */ + vn = SOTOV(so); + if (SOTPI_VN_NOSTREAM(vn)) { + error = EBADF; + eprintsoline(so, error); + goto done2; + } /* * Check for SOL_SOCKET options. * Certain SOL_SOCKET options are returned directly whereas * others only provide a default (fallback) value should
*** 5387,5397 **** * the T_SVR4_OPTMGMT_REQ. */ lvalue = so->so_sndbuf; if (lvalue == 0) { mutex_exit(&so->so_lock); ! (void) strqget(strvp2wq(SOTOV(so))->q_next, QHIWAT, 0, &lvalue); mutex_enter(&so->so_lock); dprintso(so, 1, ("got SO_SNDBUF %ld from q\n", lvalue)); } --- 5426,5436 ---- * the T_SVR4_OPTMGMT_REQ. */ lvalue = so->so_sndbuf; if (lvalue == 0) { mutex_exit(&so->so_lock); ! (void) strqget(strvp2wq(vn)->q_next, QHIWAT, 0, &lvalue); mutex_enter(&so->so_lock); dprintso(so, 1, ("got SO_SNDBUF %ld from q\n", lvalue)); }
*** 5417,5427 **** * that the transport is actually using. */ lvalue = so->so_rcvbuf; if (lvalue == 0) { mutex_exit(&so->so_lock); ! (void) strqget(RD(strvp2wq(SOTOV(so))), QHIWAT, 0, &lvalue); mutex_enter(&so->so_lock); dprintso(so, 1, ("got SO_RCVBUF %ld from q\n", lvalue)); } else if (flags & _SOGETSOCKOPT_XPG4_2) { --- 5456,5466 ---- * that the transport is actually using. */ lvalue = so->so_rcvbuf; if (lvalue == 0) { mutex_exit(&so->so_lock); ! (void) strqget(RD(strvp2wq(vn)), QHIWAT, 0, &lvalue); mutex_enter(&so->so_lock); dprintso(so, 1, ("got SO_RCVBUF %ld from q\n", lvalue)); } else if (flags & _SOGETSOCKOPT_XPG4_2) {
*** 5503,5513 **** oh.len = maxlen; mp = soallocproto3(&optmgmt_req, sizeof (optmgmt_req), &oh, sizeof (oh), NULL, maxlen, 0, _ALLOC_SLEEP, cr); /* Let option management work in the presence of data flow control */ ! error = kstrputmsg(SOTOV(so), mp, NULL, 0, 0, MSG_BAND|MSG_HOLDSIG|MSG_IGNERROR|MSG_IGNFLOW, 0); mp = NULL; mutex_enter(&so->so_lock); if (error) { eprintsoline(so, error); --- 5542,5552 ---- oh.len = maxlen; mp = soallocproto3(&optmgmt_req, sizeof (optmgmt_req), &oh, sizeof (oh), NULL, maxlen, 0, _ALLOC_SLEEP, cr); /* Let option management work in the presence of data flow control */ ! error = kstrputmsg(vn, mp, NULL, 0, 0, MSG_BAND|MSG_HOLDSIG|MSG_IGNERROR|MSG_IGNFLOW, 0); mp = NULL; mutex_enter(&so->so_lock); if (error) { eprintsoline(so, error);