bin/151664: [PATCH] sbin/route/route.c: Incorrect array bounds checking

Gleb Smirnoff glebius at FreeBSD.org
Mon Oct 25 14:20:12 UTC 2010


The following reply was made to PR bin/151664; it has been noted by GNATS.

From: Gleb Smirnoff <glebius at FreeBSD.org>
To: Alexey Illarionov <littlesavage at rambler.ru>
Cc: freebsd-gnats-submit at FreeBSD.org
Subject: Re: bin/151664: [PATCH] sbin/route/route.c: Incorrect array bounds
 checking
Date: Mon, 25 Oct 2010 18:12:06 +0400

 --G6nVm6DDWH/FONJq
 Content-Type: text/plain; charset=koi8-r
 Content-Disposition: inline
 
   Hello!
 
   Another patch, that also checks msglen even deeper down, when printing sockaddrs.
 
 -- 
 Totus tuus, Glebius.
 
 --G6nVm6DDWH/FONJq
 Content-Type: text/x-diff; charset=koi8-r
 Content-Disposition: attachment; filename="route.c.diff"
 
 Index: route.c
 ===================================================================
 --- route.c	(revision 213832)
 +++ route.c	(working copy)
 @@ -115,11 +115,11 @@
  static void	monitor(void);
  static const char	*netname(struct sockaddr *);
  static void	newroute(int, char **);
 -static void	pmsg_addrs(char *, int);
 -static void	pmsg_common(struct rt_msghdr *);
 +static void	pmsg_addrs(char *, int, size_t);
 +static void	pmsg_common(struct rt_msghdr *, size_t);
  static int	prefixlen(const char *);
  static void	print_getmsg(struct rt_msghdr *, int);
 -static void	print_rtmsg(struct rt_msghdr *, int);
 +static void	print_rtmsg(struct rt_msghdr *, size_t);
  static const char	*routename(struct sockaddr *);
  static int	rtmsg(int, int);
  static void	set_metric(char *, int);
 @@ -1306,7 +1306,7 @@
  	"RTM_NEWMADDR: new multicast group membership on iface",
  	"RTM_DELMADDR: multicast group membership removed from iface",
  	"RTM_IFANNOUNCE: interface arrival/departure",
 -	0,
 +	"RTM_IEEE80211: IEEE 802.11 wireless event",
  };
  
  char metricnames[] =
 @@ -1325,7 +1325,7 @@
  "\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR\010BRD";
  
  static void
 -print_rtmsg(struct rt_msghdr *rtm, int msglen __unused)
 +print_rtmsg(struct rt_msghdr *rtm, size_t msglen)
  {
  	struct if_msghdr *ifm;
  	struct ifa_msghdr *ifam;
 @@ -1342,13 +1342,22 @@
  		    rtm->rtm_version);
  		return;
  	}
 -	if (msgtypes[rtm->rtm_type] != NULL)
 +	if (rtm->rtm_type < sizeof(msgtypes)/sizeof(msgtypes[0]))
  		(void)printf("%s: ", msgtypes[rtm->rtm_type]);
  	else
  		(void)printf("#%d: ", rtm->rtm_type);
  	(void)printf("len %d, ", rtm->rtm_msglen);
 +
 +#define	REQUIRE(x)	do {		\
 +	if (msglen < sizeof(x))		\
 +		goto badlen;		\
 +	else				\
 +		msglen -= sizeof(x);	\
 +	} while (0)
 +
  	switch (rtm->rtm_type) {
  	case RTM_IFINFO:
 +		REQUIRE(struct if_msghdr);
  		ifm = (struct if_msghdr *)rtm;
  		(void) printf("if# %d, ", ifm->ifm_index);
  		switch (ifm->ifm_data.ifi_link_state) {
 @@ -1364,23 +1373,26 @@
  		}
  		(void) printf("link: %s, flags:", state);
  		bprintf(stdout, ifm->ifm_flags, ifnetflags);
 -		pmsg_addrs((char *)(ifm + 1), ifm->ifm_addrs);
 +		pmsg_addrs((char *)(ifm + 1), ifm->ifm_addrs, msglen);
  		break;
  	case RTM_NEWADDR:
  	case RTM_DELADDR:
 +		REQUIRE(struct ifa_msghdr);
  		ifam = (struct ifa_msghdr *)rtm;
  		(void) printf("metric %d, flags:", ifam->ifam_metric);
  		bprintf(stdout, ifam->ifam_flags, routeflags);
 -		pmsg_addrs((char *)(ifam + 1), ifam->ifam_addrs);
 +		pmsg_addrs((char *)(ifam + 1), ifam->ifam_addrs, msglen);
  		break;
  #ifdef RTM_NEWMADDR
  	case RTM_NEWMADDR:
  	case RTM_DELMADDR:
 +		REQUIRE(struct ifma_msghdr);
  		ifmam = (struct ifma_msghdr *)rtm;
 -		pmsg_addrs((char *)(ifmam + 1), ifmam->ifmam_addrs);
 +		pmsg_addrs((char *)(ifmam + 1), ifmam->ifmam_addrs, msglen);
  		break;
  #endif
  	case RTM_IFANNOUNCE:
 +		REQUIRE(struct if_announcemsghdr);
  		ifan = (struct if_announcemsghdr *)rtm;
  		(void) printf("if# %d, what: ", ifan->ifan_index);
  		switch (ifan->ifan_what) {
 @@ -1401,8 +1413,13 @@
  		(void) printf("pid: %ld, seq %d, errno %d, flags:",
  			(long)rtm->rtm_pid, rtm->rtm_seq, rtm->rtm_errno);
  		bprintf(stdout, rtm->rtm_flags, routeflags);
 -		pmsg_common(rtm);
 +		pmsg_common(rtm, msglen);
  	}
 +
 +	return;
 +
 +badlen:
 +	(void)printf("bad message length %u\n", msglen);
  }
  
  static void
 @@ -1490,7 +1507,7 @@
  #undef msec
  #define	RTA_IGN	(RTA_DST|RTA_GATEWAY|RTA_NETMASK|RTA_IFP|RTA_IFA|RTA_BRD)
  	if (verbose)
 -		pmsg_common(rtm);
 +		pmsg_common(rtm, msglen);
  	else if (rtm->rtm_addrs &~ RTA_IGN) {
  		(void) printf("sockaddrs: ");
  		bprintf(stdout, rtm->rtm_addrs, addrnames);
 @@ -1500,17 +1517,21 @@
  }
  
  static void
 -pmsg_common(struct rt_msghdr *rtm)
 +pmsg_common(struct rt_msghdr *rtm, size_t msglen)
  {
  	(void) printf("\nlocks: ");
  	bprintf(stdout, rtm->rtm_rmx.rmx_locks, metricnames);
  	(void) printf(" inits: ");
  	bprintf(stdout, rtm->rtm_inits, metricnames);
 -	pmsg_addrs(((char *)(rtm + 1)), rtm->rtm_addrs);
 +	if (msglen > sizeof(struct rt_msghdr))
 +		pmsg_addrs(((char *)(rtm + 1)), rtm->rtm_addrs,
 +		    msglen - sizeof(struct rt_msghdr));
 +	else
 +		(void) fflush(stdout);
  }
  
  static void
 -pmsg_addrs(char *cp, int addrs)
 +pmsg_addrs(char *cp, int addrs, size_t len)
  {
  	struct sockaddr *sa;
  	int i;
 @@ -1524,8 +1545,17 @@
  	(void) putchar('\n');
  	for (i = 1; i != 0; i <<= 1)
  		if (i & addrs) {
 +			if (len < sizeof(struct sockaddr)) {
 +				(void) printf("bad message length\n");
 +				break;
 +			}
  			sa = (struct sockaddr *)cp;
  			(void) printf(" %s", routename(sa));
 +			if (len < SA_SIZE(sa)) {
 +				(void) printf("bad message length\n");
 +				break;
 +			}
 +			len -= SA_SIZE(sa);
  			cp += SA_SIZE(sa);
  		}
  	(void) putchar('\n');
 
 --G6nVm6DDWH/FONJq--


More information about the freebsd-bugs mailing list