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

@@ -21,10 +21,11 @@
 
 /*
  * 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,10 +260,29 @@
         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,11 +1021,11 @@
                                 VN_HOLD(rvp);
                                 VN_RELE(vp);
                                 vp = rvp;
                         }
 
-                        ASSERT(SOTOV(so)->v_stream);
+                        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,17 +4986,23 @@
         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,11 +5063,11 @@
         strbuf.len = 0;
 
         sigintr(&smask, 0);
         res = 0;
         ASSERT(cr);
-        error = strioctl(SOTOV(so), TI_GETPEERNAME, (intptr_t)&strbuf,
+        error = strioctl(vn, TI_GETPEERNAME, (intptr_t)&strbuf,
             0, K_TO_K, cr, &res);
         sigunintr(&smask);
 
         mutex_enter(&so->so_lock);
         /*

@@ -5102,17 +5128,23 @@
         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,11 +5194,11 @@
         strbuf.len = 0;
 
         sigintr(&smask, 0);
         res = 0;
         ASSERT(cr);
-        error = strioctl(SOTOV(so), TI_GETMYNAME, (intptr_t)&strbuf,
+        error = strioctl(vn, TI_GETMYNAME, (intptr_t)&strbuf,
             0, K_TO_K, cr, &res);
         sigunintr(&smask);
 
         mutex_enter(&so->so_lock);
         /*

@@ -5236,17 +5268,24 @@
         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,11 +5426,11 @@
                          * the T_SVR4_OPTMGMT_REQ.
                          */
                         lvalue = so->so_sndbuf;
                         if (lvalue == 0) {
                                 mutex_exit(&so->so_lock);
-                                (void) strqget(strvp2wq(SOTOV(so))->q_next,
+                                (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,11 +5456,11 @@
                          * that the transport is actually using.
                          */
                         lvalue = so->so_rcvbuf;
                         if (lvalue == 0) {
                                 mutex_exit(&so->so_lock);
-                                (void) strqget(RD(strvp2wq(SOTOV(so))),
+                                (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,11 +5542,11 @@
         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,
+        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);