Skip site navigation (1)Skip section navigation (2)
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>