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);