From nobody@FreeBSD.org  Tue Jul 29 14:09:41 2008
Return-Path: <nobody@FreeBSD.org>
Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34])
	by hub.freebsd.org (Postfix) with ESMTP id 9AD9C1065673
	for <freebsd-gnats-submit@FreeBSD.org>; Tue, 29 Jul 2008 14:09:41 +0000 (UTC)
	(envelope-from nobody@FreeBSD.org)
Received: from www.freebsd.org (www.freebsd.org [IPv6:2001:4f8:fff6::21])
	by mx1.freebsd.org (Postfix) with ESMTP id 896978FC14
	for <freebsd-gnats-submit@FreeBSD.org>; Tue, 29 Jul 2008 14:09:41 +0000 (UTC)
	(envelope-from nobody@FreeBSD.org)
Received: from www.freebsd.org (localhost [127.0.0.1])
	by www.freebsd.org (8.14.2/8.14.2) with ESMTP id m6TE9fRC091139
	for <freebsd-gnats-submit@FreeBSD.org>; Tue, 29 Jul 2008 14:09:41 GMT
	(envelope-from nobody@www.freebsd.org)
Received: (from nobody@localhost)
	by www.freebsd.org (8.14.2/8.14.1/Submit) id m6TE9f3m091138;
	Tue, 29 Jul 2008 14:09:41 GMT
	(envelope-from nobody)
Message-Id: <200807291409.m6TE9f3m091138@www.freebsd.org>
Date: Tue, 29 Jul 2008 14:09:41 GMT
From: Steve Sears <sjs@netapp.com>
To: freebsd-gnats-submit@FreeBSD.org
Subject: Network: internet control accesses beyond end of structure
X-Send-Pr-Version: www-3.1
X-GNATS-Notify:

>Number:         126075
>Category:       kern
>Synopsis:       [inet] [patch] internet control accesses beyond end of structure
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    freebsd-net
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Tue Jul 29 14:10:03 UTC 2008
>Closed-Date:    
>Last-Modified:  Fri Jan 30 23:31:57 UTC 2009
>Originator:     Steve Sears
>Release:        6.1, 7.0
>Organization:
NetApp
>Environment:
n/a
>Description:

In the kernel in sys/netinet/in.c: in_control() we have the following code, marked at the problem area:

     * If an alias address was specified, find that one instead of
     * the first one on the interface, if possible.
     */
    if (ifp) {
        dst = ((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr;
        LIST_FOREACH(iap, INADDR_HASH(dst.s_addr), ia_hash)
            if (iap->ia_ifp == ifp &&
                iap->ia_addr.sin_addr.s_addr == dst.s_addr) {
                ia = iap;
                break;
            }
        if (ia == NULL)
            TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
->              iap = ifatoia(ifa);
->              if (iap->ia_addr.sin_family == AF_INET) {
->                  ia = iap;
->                  break;
                }
            }
    }

The macro ifatoia() is a simple cast:

#define ifatoia(ifa)    ((struct in_ifaddr *)(ifa))

Now look at the structure def for in_ifaddr:

struct in_ifaddr {
        struct  ifaddr ia_ifa;          /* protocol-independent info */
#define ia_ifp          ia_ifa.ifa_ifp
#define ia_flags        ia_ifa.ifa_flags
                                        /* ia_{,sub}net{,mask} in host order */
        u_long  ia_net;                 /* network number of interface */
        u_long  ia_netmask;             /* mask of net part */
        u_long  ia_subnet;              /* subnet number, including net */
        u_long  ia_subnetmask;          /* mask of subnet part */
        struct  in_addr ia_netbroadcast; /* to recognize net broadcasts */
        LIST_ENTRY(in_ifaddr) ia_hash;  /* entry in bucket of inet addresses */
        TAILQ_ENTRY(in_ifaddr) ia_link; /* list of internet addresses */
        struct  sockaddr_in ia_addr;    /* reserve space for interface name */
        struct  sockaddr_in ia_dstaddr; /* reserve space for broadcast addr */
#define ia_broadaddr    ia_dstaddr
        struct  sockaddr_in ia_sockmask; /* reserve space for general netmask */
};

All of the internet types include an ifaddr at the beginning, but it accessing beyond this struct after a cast is not a safe operation.


>How-To-Repeat:
Use non AF_INET network interfaces.
>Fix:
The problem is that ia_addr is not part of the overloaded ifaddr structure, so this check falls off the end of the structure in all but the in_ifaddr case. The corrected code should be:

        if (ia == NULL)
            TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
+               if (ifa->ifa_addr->sa_family == AF_INET) {
+                   ia = ifatoia(ifa);
+                   break;
+               }

This prevents bogus data being returned due to a cast allowing the code to walk off the end of valid data.



>Release-Note:
>Audit-Trail:
Responsible-Changed-From-To: freebsd-bugs->freebsd-net 
Responsible-Changed-By: gavin 
Responsible-Changed-When: Tue Jul 29 20:30:36 UTC 2008 
Responsible-Changed-Why:  
Over to maintainers 

http://www.freebsd.org/cgi/query-pr.cgi?pr=126075 
>Unformatted:
