Date: Tue, 2 Oct 2001 00:50:02 -0700 (PDT) From: Guy Harris <guy@alum.mit.edu> To: freebsd-gnats-submit@freebsd.org Subject: alpha/30982: "ip_dooptions()" might dereference unaligned pointer Message-ID: <200110020750.f927o2g43335@freefall.freebsd.org>
next in thread | raw e-mail | index | archive | help
>Number: 30982 >Category: alpha >Synopsis: "ip_dooptions()" might dereference unaligned pointer >Confidential: no >Severity: non-critical >Priority: medium >Responsible: freebsd-alpha >State: open >Quarter: >Keywords: >Date-Required: >Class: sw-bug >Submitter-Id: current-users >Arrival-Date: Tue Oct 02 01:00:00 PDT 2001 >Closed-Date: >Last-Modified: >Originator: Guy Harris >Release: >Organization: >Environment: >Description: At Network Appliance, we have a BSD-derived networking stack; one of our Alpha-based machines crashed due to an incoming IP packet that had a 15-byte Record Route option followed by a Timestamp option. The code that processes the Timestamp option casts the pointer to the beginning of the option to a pointer to a "struct ip_timestamp" and dereferences that pointer. The only fields it fetches or sets via that pointer are one-byte fields; however, at least with the version of GCC we are using at NetApp, the code the compiler generates to fetch from and store into those one-byte fields assumes that the structure is aligned on a 4-byte boundary. (We don't tell the compiler to generate code to use the BWX extensions, so it generates loads and extracts, and it generates a load rather than a "load unaligned".) This meant that the code attempted to dereference an unaligned pointer, as the 15-byte Record Route option put the next option on an odd-byte boundary. >How-To-Repeat: If the generated Alpha kernel code does an aligned load, send to an Alpha machine a packet with a Record Route option (which should contain an odd number of bytes) followed immediately (with no padding) by a Timestamp option. >Fix: Changing the code that processes time stamp options to code = cp - (u_char *)ip; if (cp[IPOPT_OLEN] < 4 || cp[IPOPT_OLEN] > 40) { code = &cp[IPOPT_OLEN] - (u_char *)ip; goto bad; } if (cp[IPOPT_OFFSET] < 5) { code = &cp[IPOPT_OFFSET] - (u_char *)ip; goto bad; } if (cp[IPOPT_OFFSET] > cp[IPOPT_OLEN] - (int)sizeof(int32_t)) { /* Increment the overflow counter. */ cp[3] += 0x10; if ((cp[3] & 0xF0) == 0) { /* The overflow counter overflowed. */ code = &cp[IPOPT_OFFSET] - (u_char *)ip; goto bad; } break; } sin = (struct in_addr *)(cp + cp[IPOPT_OFFSET] - 1); switch (cp[3] & 0x0F) { case IPOPT_TS_TSONLY: break; case IPOPT_TS_TSANDADDR: if (cp[IPOPT_OFFSET] - 1 + sizeof(n_time) + sizeof(struct in_addr) > cp[IPOPT_OLEN]) { code = &cp[IPOPT_OFFSET] - (u_char *)ip; goto bad; } ipaddr.sin_addr = dst; ia = (INA)ifaof_ifpforaddr((SA)&ipaddr, m->m_pkthdr.rcvif); if (ia == 0) continue; (void)memcpy(sin, &IA_SIN(ia)->sin_addr, sizeof(struct in_addr)); cp[IPOPT_OFFSET] += sizeof(struct in_addr); break; case IPOPT_TS_PRESPEC: if (cp[IPOPT_OFFSET] - 1 + sizeof(n_time) + sizeof(struct in_addr) > cp[IPOPT_OLEN]) { code = &cp[IPOPT_OFFSET] - (u_char *)ip; goto bad; } memcpy(&ipaddr.sin_addr, sin, sizeof(struct in_addr)); if (ifa_ifwithaddr((SA)&ipaddr) == 0) continue; cp[IPOPT_OFFSET] += sizeof(struct in_addr); break; default: code = &cp[3] - (u_char *)ip; goto bad; } ntime = iptime(); (void)memcpy((caddr_t)cp + cp[IPOPT_OFFSET] - 1, &ntime, sizeof(n_time)); cp[IPOPT_OFFSET] += sizeof(n_time); should, I think, do it. >Release-Note: >Audit-Trail: >Unformatted: To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-alpha" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200110020750.f927o2g43335>