Author: mmacy
Date: Sun Jul 15 00:47:06 2018
New Revision: 336301
URL: https://svnweb.freebsd.org/changeset/base/336301

Log:
  acquire inp lock around ip6_pcbopt to fix IPV6_TCLASS panic
  
  Simple fix to address panics relating to setting IPV6_TCLASS
  with setsockopt(). The premise of this change is that it is
  ok to call malloc with M_NOWAIT while holding a lock on the
  in6p.
  
  If it later turns out that it is not ok, then major surgery
  will be required, as ip6_setpktopt() will have to be fixed
  (as it also calls malloc with M_NOWAIT) which pulls in the
  ip6_pcbopts(), ip6_setpktopts(), ip6_setpktopt() call chain.
  
  Submitted by: Jason Eggnet
  Reviewed by:  rrs, transport, sbruno
  Sponsored by: Limelight Networks
  Differential Revision:        https://reviews.freebsd.org/D16201

Modified:
  head/sys/netinet6/ip6_output.c

Modified: head/sys/netinet6/ip6_output.c
==============================================================================
--- head/sys/netinet6/ip6_output.c      Sun Jul 15 00:31:17 2018        
(r336300)
+++ head/sys/netinet6/ip6_output.c      Sun Jul 15 00:47:06 2018        
(r336301)
@@ -1636,11 +1636,17 @@ do {                                                    
                \
                                                error = EINVAL;
                                                break;
                                        }
+                                       INP_WLOCK(in6p);
+                                       if (in6p->inp_flags & (INP_TIMEWAIT | 
INP_DROPPED)) {
+                                               INP_WUNLOCK(in6p);
+                                               return (ECONNRESET);
+                                       }
                                        optp = &in6p->in6p_outputopts;
                                        error = ip6_pcbopt(IPV6_HOPLIMIT,
                                            (u_char *)&optval, sizeof(optval),
                                            optp, (td != NULL) ? td->td_ucred :
                                            NULL, uproto);
+                                       INP_WUNLOCK(in6p);
                                        break;
                                }
 
@@ -1750,11 +1756,17 @@ do {                                                    
                \
                                        break;
                                {
                                        struct ip6_pktopts **optp;
+                                       INP_WLOCK(in6p);
+                                       if (in6p->inp_flags & (INP_TIMEWAIT | 
INP_DROPPED)) {
+                                               INP_WUNLOCK(in6p);
+                                               return (ECONNRESET);
+                                       }
                                        optp = &in6p->in6p_outputopts;
                                        error = ip6_pcbopt(optname,
                                            (u_char *)&optval, sizeof(optval),
                                            optp, (td != NULL) ? td->td_ucred :
                                            NULL, uproto);
+                                       INP_WUNLOCK(in6p);
                                        break;
                                }
 
@@ -1836,10 +1848,16 @@ do {                                                    
                \
                                        break;
                                optlen = sopt->sopt_valsize;
                                optbuf = optbuf_storage;
+                               INP_WLOCK(in6p);
+                               if (in6p->inp_flags & (INP_TIMEWAIT | 
INP_DROPPED)) {
+                                       INP_WUNLOCK(in6p);
+                                       return (ECONNRESET);
+                               }
                                optp = &in6p->in6p_outputopts;
                                error = ip6_pcbopt(optname, optbuf, optlen,
                                    optp, (td != NULL) ? td->td_ucred : NULL,
                                    uproto);
+                               INP_WUNLOCK(in6p);
                                break;
                        }
 #undef OPTSET
@@ -2286,7 +2304,9 @@ ip6_pcbopt(int optname, u_char *buf, int len, struct i
 
        if (*pktopt == NULL) {
                *pktopt = malloc(sizeof(struct ip6_pktopts), M_IP6OPT,
-                   M_WAITOK);
+                   M_NOWAIT);
+               if (*pktopt == NULL)
+                       return (ENOBUFS);
                ip6_initpktopts(*pktopt);
        }
        opt = *pktopt;
_______________________________________________
[email protected] mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "[email protected]"

Reply via email to