kern/149240: struct ifm_data.ifi_datalen set to invalid value on
32-bit access to 64-bit kernel
Stef Walter
stef at memberwebs.com
Tue Aug 3 15:10:04 UTC 2010
>Number: 149240
>Category: kern
>Synopsis: struct ifm_data.ifi_datalen set to invalid value on 32-bit access to 64-bit kernel
>Confidential: no
>Severity: non-critical
>Priority: medium
>Responsible: freebsd-bugs
>State: open
>Quarter:
>Keywords:
>Date-Required:
>Class: sw-bug
>Submitter-Id: current-users
>Arrival-Date: Tue Aug 03 15:10:03 UTC 2010
>Closed-Date:
>Last-Modified:
>Originator: Stef Walter
>Release: FreeBSD 8.1
>Organization:
>Environment:
FreeBSD a2.ams.npubs.net 8.1-RELEASE FreeBSD 8.1-RELEASE #4: Tue Aug 3 14:31:11 UTC 2010 root at a2.ams.npubs.net:/usr/obj/usr/src/sys/RACK2 amd64
>Description:
The FreeBSD 32 compatibility layer sets the struct ifm_data.ifi_datalen member to the wrong value. ifi_datalen is supposed to contain the size of the ifm_data struct. The FreeBSD 32 compatibility code sets this to the sime of the 64-bit struct ifi_data rather than the 32-bit one.
This casues 32-bit applications using the sysctl() or PF_ROUTE style interfaces to access invalid memory, produce invalid results, and in many cases crash.
>How-To-Repeat:
/* Will produce invalid interface names when run as a 32-bit program on 64-bit */
/* gcc -o test_iflist test_iflist.c */
#include <sys/types.h>
#include <sys/sysctl.h>
#include <sys/socket.h>
#include <net/if.h>
#include <net/if_dl.h>
#include <net/route.h>
#include <string.h>
int
main (void)
{
char buffer[1024 * 64];
char name[IFNAMSIZ];
char *buf, *lim, *next;
int mib[6];
size_t length;
struct if_msghdr *ifm, *nextifm;
struct ifa_msghdr *ifam;
struct sockaddr_dl *sdl;
int addrcount;
mib[0] = CTL_NET;
mib[1] = PF_ROUTE;
mib[2] = 0;
mib[3] = 0; /* address family */
mib[4] = NET_RT_IFLIST;
mib[5] = 0;
length = sizeof (buffer);
if (sysctl (mib, 6, buffer, &length, NULL, 0) < 0)
err (1, "sysctl failed");
buf = next = buffer;
lim = buf + length;
while (next < lim) {
ifm = (struct if_msghdr*)next;
if (ifm->ifm_type != RTM_IFINFO)
errx (1, "invalid ifm_type");
if (ifm->ifm_data.ifi_datalen == 0)
ifm->ifm_data.ifi_datalen = sizeof(struct if_data);
sdl = (struct sockaddr_dl *)((char *)ifm +
sizeof(struct if_msghdr) -
sizeof(struct if_data) +
ifm->ifm_data.ifi_datalen);
if (sdl->sdl_nlen >= sizeof (name))
err (1, "name too long");
strncpy (name, sdl->sdl_data, sdl->sdl_nlen);
next += ifm->ifm_msglen;
warnx ("interface %d %s", ifm->ifm_index, name);
ifam = NULL;
addrcount = 0;
while (next < lim) {
nextifm = (struct if_msghdr*)next;
if (nextifm->ifm_type != RTM_NEWADDR)
break;
if (ifam == NULL)
ifam = (struct ifa_msghdr *)nextifm;
addrcount++;
next += nextifm->ifm_msglen;
}
}
return 0;
}
>Fix:
Patch attached
Patch attached with submission follows:
--- ./sys/net/rtsock.c.orig 2010-08-03 14:19:14.000000000 +0000
+++ ./sys/net/rtsock.c 2010-08-03 14:20:54.000000000 +0000
@@ -1440,5 +1440,5 @@ copy_ifdata32(struct if_data *src, struc
CP(*src, *dst, ifi_hdrlen);
CP(*src, *dst, ifi_link_state);
- CP(*src, *dst, ifi_datalen);
+ dst->ifi_datalen = sizeof(struct if_data32);
CP(*src, *dst, ifi_mtu);
CP(*src, *dst, ifi_metric);
>Release-Note:
>Audit-Trail:
>Unformatted:
More information about the freebsd-bugs
mailing list