kern/126075: Network: internet control accesses beyond end of
structure
Steve Sears
sjs at netapp.com
Tue Jul 29 14:10:03 UTC 2008
>Number: 126075
>Category: kern
>Synopsis: Network: internet control accesses beyond end of structure
>Confidential: no
>Severity: serious
>Priority: medium
>Responsible: freebsd-bugs
>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:
>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:
>Unformatted:
More information about the freebsd-bugs
mailing list