Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 3 Jun 2011 01:49:05 +0000 (UTC)
From:      Hiroki Sato <hrs@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-user@freebsd.org
Subject:   svn commit: r222633 - user/hrs/ipv6/usr.sbin/rtsold
Message-ID:  <201106030149.p531n5FL042609@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: hrs
Date: Fri Jun  3 01:49:04 2011
New Revision: 222633
URL: http://svn.freebsd.org/changeset/base/222633

Log:
  - style(9) fixes.
  - Add length check for RDNSS and DNSSL option strings.
  - Add check for resolv.conf(5) restriction (maximum number of entries).
  
  Submitted by:	bz

Modified:
  user/hrs/ipv6/usr.sbin/rtsold/rtsol.c
  user/hrs/ipv6/usr.sbin/rtsold/rtsold.8
  user/hrs/ipv6/usr.sbin/rtsold/rtsold.c
  user/hrs/ipv6/usr.sbin/rtsold/rtsold.h

Modified: user/hrs/ipv6/usr.sbin/rtsold/rtsol.c
==============================================================================
--- user/hrs/ipv6/usr.sbin/rtsold/rtsol.c	Fri Jun  3 00:11:13 2011	(r222632)
+++ user/hrs/ipv6/usr.sbin/rtsold/rtsol.c	Fri Jun  3 01:49:04 2011	(r222633)
@@ -44,7 +44,9 @@
 #include <net/route.h>
 #include <net/if_dl.h>
 
+#define	__BSD_VISIBLE	1	/* IN6ADDR_LINKLOCAL_ALLROUTERS_INIT */
 #include <netinet/in.h>
+#undef 	__BSD_VISIBLE
 #include <netinet/ip6.h>
 #include <netinet6/ip6_var.h>
 #include <netinet/icmp6.h>
@@ -81,18 +83,20 @@ static const struct sockaddr_in6 sin6_al
 };
 
 static void call_script(const int, const char *const *, void *);
-static size_t dname_labeldec(char *, const char *);
+static size_t dname_labeldec(char *, size_t, const char *);
 static int safefile(const char *);
 
-#define _ARGS_OTHER	otherconf_script, ifi->ifname
-#define _ARGS_RESADD	resolvconf_script, "-a", ifi->ifname
-#define _ARGS_RESDEL	resolvconf_script, "-d", ifi->ifname
-#define CALL_SCRIPT(name, sm_head)					\
+#define	_ARGS_OTHER	otherconf_script, ifi->ifname
+#define	_ARGS_RESADD	resolvconf_script, "-a", ifi->ifname
+#define	_ARGS_RESDEL	resolvconf_script, "-d", ifi->ifname
+
+#define	CALL_SCRIPT(name, sm_head)					\
 	do {								\
 		const char *const sarg[] = { _ARGS_##name, NULL };	\
 		call_script(sizeof(sarg), sarg, sm_head);		\
-	} while(0);
-#define ELM_MALLOC(p,error_action)					\
+	} while(0)
+
+#define	ELM_MALLOC(p,error_action)					\
 	do {								\
 		p = malloc(sizeof(*p));					\
 		if (p == NULL) {					\
@@ -101,7 +105,7 @@ static int safefile(const char *);
 			error_action;					\
 		}							\
 		memset(p, 0, sizeof(*p));				\
-	} while(0);
+	} while(0)
 
 int
 sockopen(void)
@@ -228,7 +232,7 @@ void
 rtsol_input(int s)
 {
 	u_char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ];
-	int ifindex = 0, *hlimp = NULL;
+	int l, ifindex = 0, *hlimp = NULL;
 	ssize_t msglen;
 	struct in6_pktinfo *pi = NULL;
 	struct ifinfo *ifi = NULL;
@@ -364,26 +368,24 @@ rtsol_input(int s)
 		CALL_SCRIPT(OTHER, NULL);
 	}
 
-#define RA_OPT_NEXT_HDR(x)	(struct nd_opt_hdr *)((char *)x + \
-				(((struct nd_opt_hdr *)x)->nd_opt_len * 8))
-	raoptp = (char *)icp + sizeof(struct nd_router_advert);
-
 	/* Initialize ra_opt per-interface structure. */
 	gettimeofday(&now, NULL);
-	if (!TAILQ_EMPTY(&ifi->ifi_ra_opt)) {
-		struct ra_opt *rao_tmp;
-
-		rao = TAILQ_FIRST(&ifi->ifi_ra_opt);
-		while (rao != NULL) {
-			rao_tmp = TAILQ_NEXT(rao, rao_next);
+	if (!TAILQ_EMPTY(&ifi->ifi_ra_opt))
+		while ((rao = TAILQ_FIRST(&ifi->ifi_ra_opt)) != NULL) {
+			if (rao->rao_msg != NULL)
+				free(rao->rao_msg);
+			TAILQ_REMOVE(&ifi->ifi_ra_opt, rao, rao_next);
 			free(rao);
-			rao = rao_tmp;
 		}
-	} else
+	else
 		TAILQ_INIT(&ifi->ifi_ra_opt);
 
-	warnmsg(LOG_DEBUG, __func__, "Processing RA");
+#define	RA_OPT_NEXT_HDR(x)	(struct nd_opt_hdr *)((char *)x + \
+				(((struct nd_opt_hdr *)x)->nd_opt_len * 8))
+
 	/* Process RA options. */
+	warnmsg(LOG_DEBUG, __func__, "Processing RA");
+	raoptp = (char *)icp + sizeof(struct nd_router_advert);
 	while (raoptp < (char *)icp + msglen) {
 		ndo = (struct nd_opt_hdr *)raoptp;
 		warnmsg(LOG_DEBUG, __func__, "ndo = %p", raoptp);
@@ -411,21 +413,29 @@ rtsol_input(int s)
 				if (inet_ntop(AF_INET6, addr, ntopbuf,
 				    INET6_ADDRSTRLEN) == NULL) {
 					warnmsg(LOG_INFO, __func__,
-		    			"an invalid address in RDNSS option "
-					"in RA from %s was ignored.",
-					inet_ntop(AF_INET6, &from.sin6_addr,
-					ntopbuf, INET6_ADDRSTRLEN));
-
+		    			    "an invalid address in RDNSS option"
+					    " in RA from %s was ignored.",
+					    inet_ntop(AF_INET6, &from.sin6_addr,
+					    ntopbuf, INET6_ADDRSTRLEN));
+					addr++;
 					continue;
 				}
 				if (IN6_IS_ADDR_LINKLOCAL(addr))
 					/* XXX: % has to be escaped here */
-					sprintf(nsbuf, "%s%c%s",
-					    ntopbuf,
+					l = snprintf(nsbuf, sizeof(nsbuf),
+					    "%s%c%s", ntopbuf,
 					    SCOPE_DELIMITER,
 					    ifi->ifname);
 				else
-					sprintf(nsbuf, "%s", ntopbuf);
+					l = snprintf(nsbuf, sizeof(nsbuf),
+					    "%s", ntopbuf);
+				if (l < 0 || (size_t)l >= sizeof(nsbuf)) {
+					warnmsg(LOG_ERR, __func__,
+					    "address copying error in "
+					    "RDNSS option: %d.", l);
+					addr++;
+					continue;
+				}
 				warnmsg(LOG_DEBUG, __func__, "nsbuf = %s",
 				    nsbuf);
 
@@ -438,6 +448,7 @@ rtsol_input(int s)
 					    "strdup failed: %s",
 					    strerror(errno));
 					free(rao);
+					addr++;
 					continue;
 				}
 				/* Set expiration timer */
@@ -464,7 +475,8 @@ rtsol_input(int s)
 			}
 
 			p = raoptp + sizeof(*dnssl);
-			while (0 < (len = dname_labeldec(dname, p))) {
+			while (0 < (len = dname_labeldec(dname, sizeof(dname),
+			    p))) {
 				warnmsg(LOG_DEBUG, __func__, "dname = %s",
 				    dname);
 
@@ -519,13 +531,16 @@ int
 ra_opt_handler(struct ifinfo *ifi)
 {
 	struct ra_opt *rao;
-	struct script_msg *smp;
+	struct script_msg *smp1, *smp2, *smp3;
 	struct timeval now;
 	TAILQ_HEAD(, script_msg) sm_rdnss_head =
 		TAILQ_HEAD_INITIALIZER(sm_rdnss_head);
 	TAILQ_HEAD(, script_msg) sm_dnssl_head =
 		TAILQ_HEAD_INITIALIZER(sm_dnssl_head);
+	int dcount, dlen;
 
+	dcount = 0;
+	dlen = strlen(resstr_sh_prefix) + strlen(resstr_nl);
 	gettimeofday(&now, NULL);
 	TAILQ_FOREACH(rao, &ifi->ifi_ra_opt, rao_next) {
 		switch (rao->rao_type) {
@@ -536,17 +551,15 @@ ra_opt_handler(struct ifinfo *ifi)
 					(char *)rao->rao_msg);
 				break;
 			}
-			ELM_MALLOC(smp, continue);
-			smp->sm_msg = resstr_ns_prefix;
-			TAILQ_INSERT_TAIL(&sm_rdnss_head, smp, sm_next);
-
-			ELM_MALLOC(smp, continue);
-			smp->sm_msg = rao->rao_msg;
-			TAILQ_INSERT_TAIL(&sm_rdnss_head, smp, sm_next);
-
-			ELM_MALLOC(smp, continue);
-			smp->sm_msg = resstr_nl;
-			TAILQ_INSERT_TAIL(&sm_rdnss_head, smp, sm_next);
+			ELM_MALLOC(smp1, continue);
+			ELM_MALLOC(smp2, goto free1);
+			ELM_MALLOC(smp3, goto free2);
+			smp1->sm_msg = resstr_ns_prefix;
+			TAILQ_INSERT_TAIL(&sm_rdnss_head, smp1, sm_next);
+			smp2->sm_msg = rao->rao_msg;
+			TAILQ_INSERT_TAIL(&sm_rdnss_head, smp2, sm_next);
+			smp3->sm_msg = resstr_nl;
+			TAILQ_INSERT_TAIL(&sm_rdnss_head, smp3, sm_next);
 
 			break;
 		case ND_OPT_DNSSL:
@@ -556,47 +569,63 @@ ra_opt_handler(struct ifinfo *ifi)
 					(char *)rao->rao_msg);
 				break;
 			}
+			dcount++;
+			/* Check resolv.conf(5) restrictions. */
+			if (dcount > 6) {
+				warnmsg(LOG_INFO, __func__,
+				    "dnssl entry exceeding maximum count (%d>6)"
+				    ": %s", dcount, (char *)rao->rao_msg);
+				break;
+			}
+			if (256 < dlen + strlen(rao->rao_msg) +
+			    strlen(resstr_sp)) {
+				warnmsg(LOG_INFO, __func__,
+				    "dnssl entry exceeding maximum length "
+				    "(>256): %s", (char *)rao->rao_msg);
+				break;
+			}
+			ELM_MALLOC(smp1, continue);
+			ELM_MALLOC(smp2, goto free1);
 			if (TAILQ_EMPTY(&sm_dnssl_head)) {
-				ELM_MALLOC(smp, continue);
-				smp->sm_msg = resstr_sh_prefix;
-				TAILQ_INSERT_TAIL(&sm_dnssl_head, smp, sm_next);
-			}
-			ELM_MALLOC(smp, continue);
-			smp->sm_msg = rao->rao_msg;
-			TAILQ_INSERT_TAIL(&sm_dnssl_head, smp, sm_next);
-
-			ELM_MALLOC(smp, continue);
-			smp->sm_msg = resstr_sp;
-			TAILQ_INSERT_TAIL(&sm_dnssl_head, smp, sm_next);
+				ELM_MALLOC(smp3, goto free2);
+				smp3->sm_msg = resstr_sh_prefix;
+				TAILQ_INSERT_TAIL(&sm_dnssl_head, smp3,
+				    sm_next);
+			}
+			smp1->sm_msg = rao->rao_msg;
+			TAILQ_INSERT_TAIL(&sm_dnssl_head, smp1, sm_next);
+			smp2->sm_msg = resstr_sp;
+			TAILQ_INSERT_TAIL(&sm_dnssl_head, smp2, sm_next);
+			dlen += strlen(rao->rao_msg) + strlen(resstr_sp);
 			break;
 		default:
 			break;
 		}
+		continue;
+free2:
+		free(smp2);
+free1:
+		free(smp1);
 	}
 	/* Add \n for DNSSL list. */
 	if (!TAILQ_EMPTY(&sm_dnssl_head)) {
-		ELM_MALLOC(smp, goto ra_opt_handler_freeit);
-		smp->sm_msg = resstr_nl;
-		TAILQ_INSERT_TAIL(&sm_dnssl_head, smp, sm_next);
+		ELM_MALLOC(smp1, goto ra_opt_handler_freeit);
+		smp1->sm_msg = resstr_nl;
+		TAILQ_INSERT_TAIL(&sm_dnssl_head, smp1, sm_next);
 	}
 	TAILQ_CONCAT(&sm_rdnss_head, &sm_dnssl_head, sm_next);
 
-        if (!TAILQ_EMPTY(&sm_rdnss_head)) {
-                CALL_SCRIPT(RESADD, &sm_rdnss_head);
-	} else {
-                CALL_SCRIPT(RESDEL, NULL);
-	}
+	if (!TAILQ_EMPTY(&sm_rdnss_head))
+		CALL_SCRIPT(RESADD, &sm_rdnss_head);
+	else
+		CALL_SCRIPT(RESDEL, NULL);
 
 ra_opt_handler_freeit:
 	/* Clear script message queue. */
 	if (!TAILQ_EMPTY(&sm_rdnss_head)) {
-                struct script_msg *sm_tmp;
-
-		smp = TAILQ_FIRST(&sm_rdnss_head);
-		while(smp != NULL) {
-			sm_tmp = TAILQ_NEXT(smp, sm_next);
-			free(smp);
-			smp = sm_tmp;
+		while ((smp1 = TAILQ_FIRST(&sm_rdnss_head)) != NULL) {
+			TAILQ_REMOVE(&sm_rdnss_head, smp1, sm_next);
+			free(smp1);
 		}
 	}
 	return (0);
@@ -609,13 +638,13 @@ call_script(const int argc, const char *
 	int fd[2];
 	int error;
 	pid_t pid, wpid;
-	TAILQ_HEAD(, script_msg) *sm_head = NULL;
+	TAILQ_HEAD(, script_msg) *sm_head;
 
-	sm_head = head;
-	fd[0] = fd[1] = -1;
 	if ((scriptpath = argv[0]) == NULL)
 		return;
 
+	fd[0] = fd[1] = -1;
+	sm_head = head;
 	if (sm_head != NULL && !TAILQ_EMPTY(sm_head)) {
 		error = pipe(fd);
 		if (error) {
@@ -642,7 +671,7 @@ call_script(const int argc, const char *
 			TAILQ_FOREACH(smp, sm_head, sm_next) {
 				len = strlen(smp->sm_msg);
 				warnmsg(LOG_DEBUG, __func__,
-				    "write to child = %s(%d)",
+				    "write to child = %s(%zd)",
 				    smp->sm_msg, len);
 				if (write(fd[1], smp->sm_msg, len) != len) {
 					warnmsg(LOG_ERR, __func__,
@@ -660,10 +689,9 @@ call_script(const int argc, const char *
 		if (wpid < 0)
 			warnmsg(LOG_ERR, __func__,
 			    "wait: %s", strerror(errno));
-		else {
+		else
 			warnmsg(LOG_DEBUG, __func__,
 			    "script \"%s\" terminated", scriptpath);
-		}
 	} else {		/* child */
 		int nullfd;
 		char **_argv;
@@ -757,14 +785,15 @@ safefile(const char *path)
 
 /* Decode domain name label encoding in RFC 1035 Section 3.1 */
 static size_t
-dname_labeldec(char *dst, const char *src)
+dname_labeldec(char *dst, size_t dlen, const char *src)
 {
 	size_t len;
 	const char *src_origin;
 
 	src_origin = src;
+	memset(dst, '\0', dlen);
 	while (*src && (len = (uint8_t)(*src++) & 0x3f) != 0) {
-		warnmsg(LOG_DEBUG, __func__, "labellen = %d", len);
+		warnmsg(LOG_DEBUG, __func__, "labellen = %zd", len);
 		memcpy(dst, src, len);
 		src += len;
 		dst += len;
@@ -772,5 +801,12 @@ dname_labeldec(char *dst, const char *sr
 			break; 
 	}
 
+	/*
+	 * XXX validate that domain name only contains valid characters
+	 * for two reasons: 1) correctness, 2) we do not want to pass
+	 * possible malicious, unescaped characters like `` to a script
+	 * or program that could be exploited that way.
+	 */
+
 	return (src - src_origin);
 }

Modified: user/hrs/ipv6/usr.sbin/rtsold/rtsold.8
==============================================================================
--- user/hrs/ipv6/usr.sbin/rtsold/rtsold.8	Fri Jun  3 00:11:13 2011	(r222632)
+++ user/hrs/ipv6/usr.sbin/rtsold/rtsold.8	Fri Jun  3 01:49:04 2011	(r222633)
@@ -239,8 +239,10 @@ Specifies a script to run when router ad
 .Dv RDNSS Pq Recursive DNS Server
 or
 .Dv DNSSL Pq DNS Search List
-are encountered.  The information of DNS servers and DNS search domains
-will be sent to standard input of this script.  The
+are encountered.
+The information of DNS servers and DNS search domains will be sent to
+standard input of this script.
+The
 .Xr resolvconf 8
 script is used by default.
 .El

Modified: user/hrs/ipv6/usr.sbin/rtsold/rtsold.c
==============================================================================
--- user/hrs/ipv6/usr.sbin/rtsold/rtsold.c	Fri Jun  3 00:11:13 2011	(r222632)
+++ user/hrs/ipv6/usr.sbin/rtsold/rtsold.c	Fri Jun  3 01:49:04 2011	(r222633)
@@ -459,17 +459,14 @@ void
 iflist_init(void)
 {
 	struct ifinfo *ifi;
-	struct ifinfo *ifi_tmp;
 
-	ifi = TAILQ_FIRST(&ifinfo_head);
-	while (ifi != NULL) {
+	while ((ifi = TAILQ_FIRST(&ifinfo_head)) != NULL) {
+		TAILQ_REMOVE(&ifinfo_head, ifi, ifi_next);
 		if (ifi->sdl != NULL)
 			free(ifi->sdl);
 		if (ifi->rs_data != NULL)
 			free(ifi->rs_data);
-		ifi_tmp = TAILQ_NEXT(ifi, ifi_next);
 		free(ifi);
-		ifi = ifi_tmp;
 	}
 }
 
@@ -556,6 +553,7 @@ rtsol_check_timer(void)
 	static struct timeval returnval;
 	struct timeval now, rtsol_timer;
 	struct ifinfo *ifi;
+	struct ra_opt *rao;
 	int flags;
 
 	gettimeofday(&now, NULL);
@@ -571,17 +569,11 @@ rtsol_check_timer(void)
 				    ifi->state);
 
 			/* Remove all RA options. */
-			if (!TAILQ_EMPTY(&ifi->ifi_ra_opt)) {
-				struct ra_opt *rao;
-				struct ra_opt *rao_tmp;
-
-				rao = TAILQ_FIRST(&ifi->ifi_ra_opt);
-				while (rao != NULL) {
-					rao_tmp = TAILQ_NEXT(rao, rao_next);
-					free(rao_tmp->rao_msg);
-					free(rao_tmp);
-					rao = rao_tmp;
-				}
+			while ((rao = TAILQ_FIRST(&ifi->ifi_ra_opt)) != NULL) {
+				if (rao->rao_msg != NULL)
+					free(rao->rao_msg);
+				TAILQ_REMOVE(&ifi->ifi_ra_opt, rao, rao_next);
+				free(rao);
 			}
 			switch (ifi->state) {
 			case IFS_DOWN:
@@ -650,7 +642,6 @@ rtsol_check_timer(void)
 			rtsol_timer_update(ifi);
 		} else {
 			/* Expiration check for RA options. */
-			struct ra_opt *rao;
 			struct ra_opt *rao_tmp;
 			int expire = 0;
 
@@ -782,11 +773,15 @@ static void
 usage(void)
 {
 #ifndef SMALL
-	fprintf(stderr, "usage: rtsold [-adDfFm1] [-O script-name] [-P pidfile] [-R script-name] interfaces...\n");
-	fprintf(stderr, "usage: rtsold [-dDfFm1] [-O script-name] [-P pidfile] [-R script-name] -a\n");
+	fprintf(stderr, "usage: rtsold [-adDfFm1] [-O script-name] "
+	    "[-P pidfile] [-R script-name] interfaces...\n");
+	fprintf(stderr, "usage: rtsold [-dDfFm1] [-O script-name] "
+	    "[-P pidfile] [-R script-name] -a\n");
 #else
-	fprintf(stderr, "usage: rtsol [-dDF] [-O script-name] [-P pidfile] [-R script-name] interfaces...\n");
-	fprintf(stderr, "usage: rtsol [-dDF] [-O script-name] [-P pidfile] [-R script-name] -a\n");
+	fprintf(stderr, "usage: rtsol [-dDF] [-O script-name] "
+	    "[-P pidfile] [-R script-name] interfaces...\n");
+	fprintf(stderr, "usage: rtsol [-dDF] [-O script-name] "
+	    "[-P pidfile] [-R script-name] -a\n");
 #endif
 }
 

Modified: user/hrs/ipv6/usr.sbin/rtsold/rtsold.h
==============================================================================
--- user/hrs/ipv6/usr.sbin/rtsold/rtsold.h	Fri Jun  3 00:11:13 2011	(r222632)
+++ user/hrs/ipv6/usr.sbin/rtsold/rtsold.h	Fri Jun  3 01:49:04 2011	(r222633)
@@ -36,14 +36,16 @@ struct script_msg {
 
 	char *sm_msg;
 };
+
 struct ra_opt {
 	TAILQ_ENTRY(ra_opt)	rao_next;
 
-	u_int8_t       	rao_type;
+	u_int8_t	rao_type;
 	struct timeval	rao_expire;
 	size_t		rao_len;
 	void		*rao_msg;
 };
+
 struct ifinfo {
 	TAILQ_ENTRY(ifinfo)	ifi_next;	/* pointer to the next interface */
 
@@ -100,9 +102,11 @@ extern TAILQ_HEAD(ifinfo_head_t, ifinfo)
 #endif
 #endif
 
+#ifndef IN6ADDR_LINKLOCAL_ALLROUTERS_INIT
 #define IN6ADDR_LINKLOCAL_ALLROUTERS_INIT			\
 	{{{ 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	\
 	    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 }}}
+#endif
 
 /* rtsold.c */
 extern struct timeval tm_max;



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201106030149.p531n5FL042609>