Date: Tue, 3 Aug 2010 15:02:12 GMT From: Stef Walter <stef@memberwebs.com> To: freebsd-gnats-submit@FreeBSD.org Subject: kern/149240: struct ifm_data.ifi_datalen set to invalid value on 32-bit access to 64-bit kernel Message-ID: <201008031502.o73F2CL6016830@www.freebsd.org> Resent-Message-ID: <201008031510.o73FA3UI016294@freefall.freebsd.org>
next in thread | raw e-mail | index | archive | help
>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@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:
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201008031502.o73F2CL6016830>