Mercurial > unleashed > wips
changeset 10582:cdf5d98e419e
6877954 7410C: Kernel panic occurring due to a null pointer dereference in the 'ip' module [2009Q2.5.0]
author | Anders Persson <Anders.Persson@Sun.COM> |
---|---|
date | Fri, 18 Sep 2009 12:50:18 -0700 |
parents | c2151e45dda5 |
children | 1058268e7f53 |
files | usr/src/uts/common/inet/tcp/tcp.c |
diffstat | 1 files changed, 32 insertions(+), 13 deletions(-) [+] |
line wrap: on
line diff
--- a/usr/src/uts/common/inet/tcp/tcp.c Fri Sep 18 12:43:49 2009 -0700 +++ b/usr/src/uts/common/inet/tcp/tcp.c Fri Sep 18 12:50:18 2009 -0700 @@ -7834,12 +7834,11 @@ PRESERVE(tcp->tcp_family); if (tcp->tcp_family == AF_INET6) { - tcp->tcp_ipversion = IPV6_VERSION; tcp->tcp_mss = tcps->tcps_mss_def_ipv6; } else { - tcp->tcp_ipversion = IPV4_VERSION; tcp->tcp_mss = tcps->tcps_mss_def_ipv4; } + PRESERVE(tcp->tcp_ipversion); /* Init in tcp_init_values */ tcp->tcp_bound_if = 0; tcp->tcp_ipv6_recvancillary = 0; @@ -7983,7 +7982,7 @@ tcp->tcp_loopback_peer = NULL; /* Initialize the header template */ - if (tcp->tcp_ipversion == IPV4_VERSION) { + if (tcp->tcp_family == AF_INET) { err = tcp_header_init_ipv4(tcp); } else { err = tcp_header_init_ipv6(tcp); @@ -8048,9 +8047,19 @@ connp->conn_mlp_type = mlptSingle; connp->conn_ulp_labeled = !is_system_labeled(); ASSERT(tcp->tcp_iphc_len >= TCP_MAX_COMBINED_HEADER_LENGTH); + + /* + * tcp_do_get{sock,peer}name constructs the sockaddr from the + * ip header, and decides which header to use based on ip version. + * That operation happens outside the squeue, so we hold the lock + * here to ensure that the ip version and header remain consistent. + */ + mutex_enter(&connp->conn_lock); + tcp->tcp_ipversion = IPV4_VERSION; tcp->tcp_ipha = (ipha_t *)tcp->tcp_iphc; tcp->tcp_ip6h = NULL; - tcp->tcp_ipversion = IPV4_VERSION; + mutex_exit(&connp->conn_lock); + tcp->tcp_hdr_len = sizeof (ipha_t) + sizeof (tcph_t); tcp->tcp_tcp_hdr_len = sizeof (tcph_t); tcp->tcp_ip_hdr_len = sizeof (ipha_t); @@ -8120,12 +8129,21 @@ connp->conn_ulp_labeled = !is_system_labeled(); ASSERT(tcp->tcp_iphc_len >= TCP_MAX_COMBINED_HEADER_LENGTH); - tcp->tcp_ipversion = IPV6_VERSION; tcp->tcp_hdr_len = IPV6_HDR_LEN + sizeof (tcph_t); tcp->tcp_tcp_hdr_len = sizeof (tcph_t); tcp->tcp_ip_hdr_len = IPV6_HDR_LEN; + + /* + * tcp_do_get{sock,peer}name constructs the sockaddr from the + * ip header, and decides which header to use based on ip version. + * That operation happens outside the squeue, so we hold the lock + * here to ensure that the ip version and header remain consistent. + */ + mutex_enter(&connp->conn_lock); + tcp->tcp_ipversion = IPV6_VERSION; tcp->tcp_ip6h = (ip6_t *)tcp->tcp_iphc; tcp->tcp_ipha = NULL; + mutex_exit(&connp->conn_lock); /* Initialize the header template */ @@ -17884,12 +17902,14 @@ sin6->sin6_family = AF_INET6; if (tcp->tcp_state >= TCPS_BOUND) { sin6->sin6_port = tcp->tcp_lport; + mutex_enter(&tcp->tcp_connp->conn_lock); if (tcp->tcp_ipversion == IPV4_VERSION) { IN6_IPADDR_TO_V4MAPPED(tcp->tcp_ipha->ipha_src, &sin6->sin6_addr); } else { sin6->sin6_addr = tcp->tcp_ip6h->ip6_src; } + mutex_exit(&tcp->tcp_connp->conn_lock); } *salenp = sizeof (sin6_t); break; @@ -17930,10 +17950,12 @@ sin6->sin6_family = AF_INET6; sin6->sin6_port = tcp->tcp_fport; sin6->sin6_addr = tcp->tcp_remote_v6; + mutex_enter(&tcp->tcp_connp->conn_lock); if (tcp->tcp_ipversion == IPV6_VERSION) { sin6->sin6_flowinfo = tcp->tcp_ip6h->ip6_vcf & ~IPV6_VERS_AND_FLOW_MASK; } + mutex_exit(&tcp->tcp_connp->conn_lock); *salenp = sizeof (sin6_t); break; } @@ -26090,7 +26112,7 @@ in_port_t requested_port; ipaddr_t v4addr; in6_addr_t v6addr; - uint_t origipversion; + uint_t ipversion; int error = 0; ASSERT((uintptr_t)len <= (uintptr_t)INT_MAX); @@ -26104,7 +26126,6 @@ } return (-TOUTSTATE); } - origipversion = tcp->tcp_ipversion; ASSERT(sa != NULL && len != 0); @@ -26132,7 +26153,7 @@ return (EAFNOSUPPORT); } requested_port = ntohs(sin->sin_port); - tcp->tcp_ipversion = IPV4_VERSION; + ipversion = IPV4_VERSION; v4addr = sin->sin_addr.s_addr; IN6_IPADDR_TO_V4MAPPED(v4addr, &v6addr); break; @@ -26144,7 +26165,7 @@ return (EAFNOSUPPORT); } requested_port = ntohs(sin6->sin6_port); - tcp->tcp_ipversion = IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr) ? + ipversion = IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr) ? IPV4_VERSION : IPV6_VERSION; v6addr = sin6->sin6_addr; break; @@ -26161,9 +26182,9 @@ tcp->tcp_bound_source_v6 = v6addr; /* Check for change in ipversion */ - if (origipversion != tcp->tcp_ipversion) { + if (tcp->tcp_ipversion != ipversion) { ASSERT(tcp->tcp_family == AF_INET6); - error = tcp->tcp_ipversion == IPV6_VERSION ? + error = (ipversion == IPV6_VERSION) ? tcp_header_init_ipv6(tcp) : tcp_header_init_ipv4(tcp); if (error) { return (ENOMEM); @@ -27075,14 +27096,12 @@ sin = (sin_t *)&addr; *sin = sin_null; sin->sin_family = AF_INET; - tcp->tcp_ipversion = IPV4_VERSION; } else { ASSERT(tcp->tcp_family == AF_INET6); len = sizeof (sin6_t); sin6 = (sin6_t *)&addr; *sin6 = sin6_null; sin6->sin6_family = AF_INET6; - tcp->tcp_ipversion = IPV6_VERSION; } sa = (struct sockaddr *)&addr; }