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

Split Close
Expand all
Collapse all
          --- old/usr/src/uts/common/fs/sockfs/socktpi.c
          +++ new/usr/src/uts/common/fs/sockfs/socktpi.c
↓ open down ↓ 15 lines elided ↑ open up ↑
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  
  22   22  /*
  23   23   * Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved.
  24   24   * Copyright 2015, Joyent, Inc.
  25   25   * Copyright 2016 Nexenta Systems, Inc.  All rights reserved.
       26 + * Copyright 2022 MNX Cloud, Inc.
  26   27   */
  27   28  
  28   29  #include <sys/types.h>
  29   30  #include <sys/t_lock.h>
  30   31  #include <sys/param.h>
  31   32  #include <sys/systm.h>
  32   33  #include <sys/buf.h>
  33   34  #include <sys/conf.h>
  34   35  #include <sys/cred.h>
  35   36  #include <sys/kmem.h>
↓ open down ↓ 218 lines elided ↑ open up ↑
 254  255          sotpi_getsockname,      /* sop_getsockname      */
 255  256          sotpi_shutdown,         /* sop_shutdown         */
 256  257          sotpi_getsockopt,       /* sop_getsockopt       */
 257  258          sotpi_setsockopt,       /* sop_setsockopt       */
 258  259          sotpi_ioctl,            /* sop_ioctl            */
 259  260          sotpi_poll,             /* sop_poll             */
 260  261          sotpi_close,            /* sop_close            */
 261  262  };
 262  263  
 263  264  /*
      265 + * Post-close reality check for NULL v_stream...
      266 + *
      267 + * Kernel callers (e.g. in procfs) may attempt socket operations, after
      268 + * holding the vnode, after it has been closed.  For TPI sockets, post-close
      269 + * operations will have a NULL v_stream (which all functions here assume
      270 + * or even ASSERT() is non-NULL).  See sotpi_close for where we wipe it out.
      271 + *
      272 + * If we are in a state where we lost a race to close(), we need to stop ASAP,
      273 + * and return the acceptable-as-an-errno EBADF.  Because cleanup may be
      274 + * required, this macro only checks the v_stream.
      275 + *
      276 + * Checking should only be relevant for in-kernel other-thread inspectors.
      277 + * Userland ones (i.e. same process that opened the socktpi socket) SHOULD be
      278 + * protected by higher-level mechanisms. The only in-kernel inspector in the
      279 + * source base is procfs, which only accesses get{sockname,peername,sockopt}().
      280 + */
      281 +#define SOTPI_VN_NOSTREAM(vn) ((vn)->v_stream == NULL)
      282 +
      283 +/*
 264  284   * Return a TPI socket vnode.
 265  285   *
 266  286   * Note that sockets assume that the driver will clone (either itself
 267  287   * or by using the clone driver) i.e. a socket() call will always
 268  288   * result in a new vnode being created.
 269  289   */
 270  290  
 271  291  /*
 272  292   * Common create code for socket and accept. If tso is set the values
 273  293   * from that node is used instead of issuing a T_INFO_REQ.
↓ open down ↓ 722 lines elided ↑ open up ↑
 996 1016                           * cross-linkage between the underlying filesystem
 997 1017                           * node and the socket node.
 998 1018                           */
 999 1019  
1000 1020                          if ((VOP_REALVP(vp, &rvp, NULL) == 0) && (vp != rvp)) {
1001 1021                                  VN_HOLD(rvp);
1002 1022                                  VN_RELE(vp);
1003 1023                                  vp = rvp;
1004 1024                          }
1005 1025  
1006      -                        ASSERT(SOTOV(so)->v_stream);
     1026 +                        ASSERT(SOTOV(so)->v_stream != NULL);
1007 1027                          mutex_enter(&vp->v_lock);
1008 1028                          vp->v_stream = SOTOV(so)->v_stream;
1009 1029                          sti->sti_ux_bound_vp = vp;
1010 1030                          mutex_exit(&vp->v_lock);
1011 1031  
1012 1032                          /*
1013 1033                           * Use the vnode pointer value as a unique address
1014 1034                           * (together with the magic number to avoid conflicts
1015 1035                           * with implicit binds) in the transport provider.
1016 1036                           */
↓ open down ↓ 3944 lines elided ↑ open up ↑
4961 4981  int
4962 4982  sotpi_getpeername(struct sonode *so, struct sockaddr *name, socklen_t *namelen,
4963 4983      boolean_t accept, struct cred *cr)
4964 4984  {
4965 4985          struct strbuf   strbuf;
4966 4986          int             error = 0, res;
4967 4987          void            *addr;
4968 4988          t_uscalar_t     addrlen;
4969 4989          k_sigset_t      smask;
4970 4990          sotpi_info_t    *sti = SOTOTPI(so);
     4991 +        vnode_t         *vn;
4971 4992  
4972 4993          dprintso(so, 1, ("sotpi_getpeername(%p) %s\n",
4973 4994              (void *)so, pr_state(so->so_state, so->so_mode)));
4974 4995  
4975 4996          ASSERT(*namelen > 0);
4976 4997          mutex_enter(&so->so_lock);
4977 4998          so_lock_single(so);     /* Set SOLOCKED */
     4999 +        vn = SOTOV(so);
     5000 +        if (SOTPI_VN_NOSTREAM(vn)) {
     5001 +                error = EBADF;
     5002 +                goto done;
     5003 +        }
4978 5004  
4979 5005          if (accept) {
4980 5006                  bcopy(sti->sti_faddr_sa, name,
4981 5007                      MIN(*namelen, sti->sti_faddr_len));
4982 5008                  *namelen = sti->sti_faddr_noxlate ? 0: sti->sti_faddr_len;
4983 5009                  goto done;
4984 5010          }
4985 5011  
4986 5012          if (!(so->so_state & SS_ISCONNECTED)) {
4987 5013                  error = ENOTCONN;
↓ open down ↓ 44 lines elided ↑ open up ↑
5032 5058           * If the ioctl fails (e.g. due to a ECONNRESET) the error is reposted
5033 5059           * back to the socket.
5034 5060           */
5035 5061          strbuf.buf = addr;
5036 5062          strbuf.maxlen = addrlen;
5037 5063          strbuf.len = 0;
5038 5064  
5039 5065          sigintr(&smask, 0);
5040 5066          res = 0;
5041 5067          ASSERT(cr);
5042      -        error = strioctl(SOTOV(so), TI_GETPEERNAME, (intptr_t)&strbuf,
     5068 +        error = strioctl(vn, TI_GETPEERNAME, (intptr_t)&strbuf,
5043 5069              0, K_TO_K, cr, &res);
5044 5070          sigunintr(&smask);
5045 5071  
5046 5072          mutex_enter(&so->so_lock);
5047 5073          /*
5048 5074           * If there is an error record the error in so_error put don't fail
5049 5075           * the getpeername. Instead fallback on the recorded
5050 5076           * sti->sti_faddr_sa.
5051 5077           */
5052 5078          if (error) {
↓ open down ↓ 44 lines elided ↑ open up ↑
5097 5123  int
5098 5124  sotpi_getsockname(struct sonode *so, struct sockaddr *name, socklen_t *namelen,
5099 5125      struct cred *cr)
5100 5126  {
5101 5127          struct strbuf   strbuf;
5102 5128          int             error = 0, res;
5103 5129          void            *addr;
5104 5130          t_uscalar_t     addrlen;
5105 5131          k_sigset_t      smask;
5106 5132          sotpi_info_t    *sti = SOTOTPI(so);
     5133 +        vnode_t         *vn;
5107 5134  
5108 5135          dprintso(so, 1, ("sotpi_getsockname(%p) %s\n",
5109 5136              (void *)so, pr_state(so->so_state, so->so_mode)));
5110 5137  
5111 5138          ASSERT(*namelen > 0);
5112 5139          mutex_enter(&so->so_lock);
5113 5140          so_lock_single(so);     /* Set SOLOCKED */
     5141 +        vn = SOTOV(so);
     5142 +        if (SOTPI_VN_NOSTREAM(vn)) {
     5143 +                error = EBADF;
     5144 +                goto done;
     5145 +        }
5114 5146  
5115 5147  #ifdef DEBUG
5116 5148  
5117 5149          dprintso(so, 1, ("sotpi_getsockname (local): %s\n",
5118 5150              pr_addr(so->so_family, sti->sti_laddr_sa,
5119 5151              (t_uscalar_t)sti->sti_laddr_len)));
5120 5152  #endif /* DEBUG */
5121 5153          if (sti->sti_laddr_valid) {
5122 5154                  bcopy(sti->sti_laddr_sa, name,
5123 5155                      MIN(*namelen, sti->sti_laddr_len));
↓ open down ↓ 33 lines elided ↑ open up ↑
5157 5189           * If the ioctl fails (e.g. due to a ECONNRESET) the error is reposted
5158 5190           * back to the socket.
5159 5191           */
5160 5192          strbuf.buf = addr;
5161 5193          strbuf.maxlen = addrlen;
5162 5194          strbuf.len = 0;
5163 5195  
5164 5196          sigintr(&smask, 0);
5165 5197          res = 0;
5166 5198          ASSERT(cr);
5167      -        error = strioctl(SOTOV(so), TI_GETMYNAME, (intptr_t)&strbuf,
     5199 +        error = strioctl(vn, TI_GETMYNAME, (intptr_t)&strbuf,
5168 5200              0, K_TO_K, cr, &res);
5169 5201          sigunintr(&smask);
5170 5202  
5171 5203          mutex_enter(&so->so_lock);
5172 5204          /*
5173 5205           * If there is an error record the error in so_error put don't fail
5174 5206           * the getsockname. Instead fallback on the recorded
5175 5207           * sti->sti_laddr_sa.
5176 5208           */
5177 5209          if (error) {
↓ open down ↓ 53 lines elided ↑ open up ↑
5231 5263          struct opthdr           *opt_res;
5232 5264          mblk_t                  *mp = NULL;
5233 5265          int                     error = 0;
5234 5266          void                    *option = NULL; /* Set if fallback value */
5235 5267          t_uscalar_t             maxlen = *optlenp;
5236 5268          t_uscalar_t             len;
5237 5269          uint32_t                value;
5238 5270          struct timeval          tmo_val; /* used for SO_RCVTIMEO, SO_SNDTIMEO */
5239 5271          struct timeval32        tmo_val32;
5240 5272          struct so_snd_bufinfo   snd_bufinfo;    /* used for zero copy */
     5273 +        vnode_t                 *vn;
5241 5274  
5242 5275          dprintso(so, 1, ("sotpi_getsockopt(%p, 0x%x, 0x%x, %p, %p) %s\n",
5243 5276              (void *)so, level, option_name, optval, (void *)optlenp,
5244 5277              pr_state(so->so_state, so->so_mode)));
5245 5278  
5246 5279          mutex_enter(&so->so_lock);
5247 5280          so_lock_single(so);     /* Set SOLOCKED */
     5281 +        vn = SOTOV(so);
     5282 +        if (SOTPI_VN_NOSTREAM(vn)) {
     5283 +                error = EBADF;
     5284 +                eprintsoline(so, error);
     5285 +                goto done2;
     5286 +        }
5248 5287  
5249 5288          /*
5250 5289           * Check for SOL_SOCKET options.
5251 5290           * Certain SOL_SOCKET options are returned directly whereas
5252 5291           * others only provide a default (fallback) value should
5253 5292           * the T_SVR4_OPTMGMT_REQ fail.
5254 5293           */
5255 5294          if (level == SOL_SOCKET) {
5256 5295                  /* Check parameters */
5257 5296                  switch (option_name) {
↓ open down ↓ 124 lines elided ↑ open up ↑
5382 5421  
5383 5422                          /*
5384 5423                           * If the option has not been set then get a default
5385 5424                           * value from the read queue. This value is
5386 5425                           * returned if the transport fails
5387 5426                           * the T_SVR4_OPTMGMT_REQ.
5388 5427                           */
5389 5428                          lvalue = so->so_sndbuf;
5390 5429                          if (lvalue == 0) {
5391 5430                                  mutex_exit(&so->so_lock);
5392      -                                (void) strqget(strvp2wq(SOTOV(so))->q_next,
     5431 +                                (void) strqget(strvp2wq(vn)->q_next,
5393 5432                                      QHIWAT, 0, &lvalue);
5394 5433                                  mutex_enter(&so->so_lock);
5395 5434                                  dprintso(so, 1,
5396 5435                                      ("got SO_SNDBUF %ld from q\n", lvalue));
5397 5436                          }
5398 5437                          value = (int)lvalue;
5399 5438                          option = &value;
5400 5439                          len = (t_uscalar_t)sizeof (so->so_sndbuf);
5401 5440                          break;
5402 5441                  }
↓ open down ↓ 9 lines elided ↑ open up ↑
5412 5451                           * XXX If SO_RCVBUF has been set and this is an
5413 5452                           * XPG 4.2 application then do not ask the transport
5414 5453                           * since the transport might adjust the value and not
5415 5454                           * return exactly what was set by the application.
5416 5455                           * For non-XPG 4.2 application we return the value
5417 5456                           * that the transport is actually using.
5418 5457                           */
5419 5458                          lvalue = so->so_rcvbuf;
5420 5459                          if (lvalue == 0) {
5421 5460                                  mutex_exit(&so->so_lock);
5422      -                                (void) strqget(RD(strvp2wq(SOTOV(so))),
     5461 +                                (void) strqget(RD(strvp2wq(vn)),
5423 5462                                      QHIWAT, 0, &lvalue);
5424 5463                                  mutex_enter(&so->so_lock);
5425 5464                                  dprintso(so, 1,
5426 5465                                      ("got SO_RCVBUF %ld from q\n", lvalue));
5427 5466                          } else if (flags & _SOGETSOCKOPT_XPG4_2) {
5428 5467                                  value = (int)lvalue;
5429 5468                                  option = &value;
5430 5469                                  goto copyout;   /* skip asking transport */
5431 5470                          }
5432 5471                          value = (int)lvalue;
↓ open down ↓ 65 lines elided ↑ open up ↑
5498 5537          optmgmt_req.OPT_length = (t_scalar_t)(sizeof (oh) + maxlen);
5499 5538          optmgmt_req.OPT_offset = (t_scalar_t)sizeof (optmgmt_req);
5500 5539  
5501 5540          oh.level = level;
5502 5541          oh.name = option_name;
5503 5542          oh.len = maxlen;
5504 5543  
5505 5544          mp = soallocproto3(&optmgmt_req, sizeof (optmgmt_req),
5506 5545              &oh, sizeof (oh), NULL, maxlen, 0, _ALLOC_SLEEP, cr);
5507 5546          /* Let option management work in the presence of data flow control */
5508      -        error = kstrputmsg(SOTOV(so), mp, NULL, 0, 0,
     5547 +        error = kstrputmsg(vn, mp, NULL, 0, 0,
5509 5548              MSG_BAND|MSG_HOLDSIG|MSG_IGNERROR|MSG_IGNFLOW, 0);
5510 5549          mp = NULL;
5511 5550          mutex_enter(&so->so_lock);
5512 5551          if (error) {
5513 5552                  eprintsoline(so, error);
5514 5553                  goto done2;
5515 5554          }
5516 5555          error = sowaitprim(so, T_SVR4_OPTMGMT_REQ, T_OPTMGMT_ACK,
5517 5556              (t_uscalar_t)(sizeof (*optmgmt_ack) + sizeof (*opt_res)), &mp, 0);
5518 5557          if (error) {
↓ open down ↓ 1434 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX