From owner-freebsd-alpha Tue Oct 2 1: 0:10 2001 Delivered-To: freebsd-alpha@freebsd.org Received: from freefall.freebsd.org (freefall.FreeBSD.org [216.136.204.21]) by hub.freebsd.org (Postfix) with ESMTP id BBB3A37B40D for ; Tue, 2 Oct 2001 01:00:00 -0700 (PDT) Received: (from gnats@localhost) by freefall.freebsd.org (8.11.4/8.11.4) id f92800F44323; Tue, 2 Oct 2001 01:00:00 -0700 (PDT) (envelope-from gnats) Received: from freefall.freebsd.org (freefall.FreeBSD.org [216.136.204.21]) by hub.freebsd.org (Postfix) with ESMTP id 2625437B408 for ; Tue, 2 Oct 2001 00:50:02 -0700 (PDT) Received: (from nobody@localhost) by freefall.freebsd.org (8.11.4/8.11.4) id f927o2g43335; Tue, 2 Oct 2001 00:50:02 -0700 (PDT) (envelope-from nobody) Message-Id: <200110020750.f927o2g43335@freefall.freebsd.org> Date: Tue, 2 Oct 2001 00:50:02 -0700 (PDT) From: Guy Harris To: freebsd-gnats-submit@freebsd.org X-Send-Pr-Version: www-1.0 Subject: alpha/30982: "ip_dooptions()" might dereference unaligned pointer Sender: owner-freebsd-alpha@FreeBSD.ORG Precedence: bulk List-ID: List-Archive: (Web Archive) List-Help: (List Instructions) List-Subscribe: List-Unsubscribe: X-Loop: FreeBSD.org >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