Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 12 Jun 2020 01:03:53 +0000 (UTC)
From:      Cy Schubert <cy@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-12@freebsd.org
Subject:   svn commit: r362081 - in stable: 11/contrib/wpa/src/wps 12/contrib/wpa/src/wps
Message-ID:  <202006120103.05C13r9h015882@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: cy
Date: Fri Jun 12 01:03:51 2020
New Revision: 362081
URL: https://svnweb.freebsd.org/changeset/base/362081

Log:
  MFC r361957-r361960
  
  r361957:
  MFV r361936:
  
  Upstream commit message:
  
  [PATCH 1/3] WPS UPnP: Do not allow event subscriptions with URLs to
  other networks
  
  The UPnP Device Architecture 2.0 specification errata ("UDA errata
  16-04-2020.docx") addresses a problem with notifications being allowed
  to go out to other domains by disallowing such cases. Do such filtering
  for the notification callback URLs to avoid undesired connections to
  external networks based on subscriptions that any device in the local
  network could request when WPS support for external registrars is
  enabled (the upnp_iface parameter in hostapd configuration).
  
  Obtained from:	https://w1.fi/security/2020-1/\
  	0001-WPS-UPnP-Do-not-allow-event-subscriptions-with-URLs-.patch
  Security:	VU#339275 and CVE-2020-12695
  
  r361958:
  MFV r361937:
  
  Upstream commit message:
  
  [PATCH 2/3] WPS UPnP: Fix event message generation using a long URL path
  
  More than about 700 character URL ended up overflowing the wpabuf used
  for building the event notification and this resulted in the wpabuf
  buffer overflow checks terminating the hostapd process. Fix this by
  allocating the buffer to be large enough to contain the full URL path.
  However, since that around 700 character limit has been the practical
  limit for more than ten years, start explicitly enforcing that as the
  limit or the callback URLs since any longer ones had not worked before
  and there is no need to enable them now either.
  
  Obtained from:	https://w1.fi/security/2020-1/\
  	0002-WPS-UPnP-Fix-event-message-generation-using-a-long-U.patch
  Security:	VU#339275 and CVE-2020-12695
  
  r361959:
  MFV r361938:
  
  Upstream commit message:
  
  [PATCH 3/3] WPS UPnP: Handle HTTP initiation failures for events more
  properly
  
  While it is appropriate to try to retransmit the event to another
  callback URL on a failure to initiate the HTTP client connection, there
  is no point in trying the exact same operation multiple times in a row.
  Replve the event_retry() calls with event_addr_failure() for these cases
  to avoid busy loops trying to repeat the same failing operation.
  
  These potential busy loops would go through eloop callbacks, so the
  process is not completely stuck on handling them, but unnecessary CPU
  would be used to process the continues retries that will keep failing
  for the same reason.
  
  Obtained from:	https://w1.fi/security/2020-1/\
  	0003-WPS-UPnP-Handle-HTTP-initiation-failures-for-events-.patch
  Security:	VU#339275 and CVE-2020-12695
  
  r361960:
  Post CVE-2020-12695 cleanup patch:
  
  Resolve a Linuxism to fix the build.

Modified:
  stable/12/contrib/wpa/src/wps/wps_er.c
  stable/12/contrib/wpa/src/wps/wps_upnp.c
  stable/12/contrib/wpa/src/wps/wps_upnp_event.c
  stable/12/contrib/wpa/src/wps/wps_upnp_i.h
Directory Properties:
  stable/12/   (props changed)

Changes in other areas also in this revision:
Modified:
  stable/11/contrib/wpa/src/wps/wps_er.c
  stable/11/contrib/wpa/src/wps/wps_upnp.c
  stable/11/contrib/wpa/src/wps/wps_upnp_event.c
  stable/11/contrib/wpa/src/wps/wps_upnp_i.h
Directory Properties:
  stable/11/   (props changed)

Modified: stable/12/contrib/wpa/src/wps/wps_er.c
==============================================================================
--- stable/12/contrib/wpa/src/wps/wps_er.c	Fri Jun 12 00:42:05 2020	(r362080)
+++ stable/12/contrib/wpa/src/wps/wps_er.c	Fri Jun 12 01:03:51 2020	(r362081)
@@ -1298,7 +1298,7 @@ wps_er_init(struct wps_context *wps, const char *ifnam
 			   "with %s", filter);
 	}
 	if (get_netif_info(er->ifname, &er->ip_addr, &er->ip_addr_text,
-			   er->mac_addr)) {
+			   NULL, er->mac_addr)) {
 		wpa_printf(MSG_INFO, "WPS UPnP: Could not get IP/MAC address "
 			   "for %s. Does it have IP address?", er->ifname);
 		wps_er_deinit(er, NULL, NULL);

Modified: stable/12/contrib/wpa/src/wps/wps_upnp.c
==============================================================================
--- stable/12/contrib/wpa/src/wps/wps_upnp.c	Fri Jun 12 00:42:05 2020	(r362080)
+++ stable/12/contrib/wpa/src/wps/wps_upnp.c	Fri Jun 12 01:03:51 2020	(r362081)
@@ -303,6 +303,14 @@ static void subscr_addr_free_all(struct subscription *
 }
 
 
+static int local_network_addr(struct upnp_wps_device_sm *sm,
+			      struct sockaddr_in *addr)
+{
+	return (addr->sin_addr.s_addr & sm->netmask.s_addr) ==
+		(sm->ip_addr & sm->netmask.s_addr);
+}
+
+
 /* subscr_addr_add_url -- add address(es) for one url to subscription */
 static void subscr_addr_add_url(struct subscription *s, const char *url,
 				size_t url_len)
@@ -320,9 +328,14 @@ static void subscr_addr_add_url(struct subscription *s
 	int rerr;
 	size_t host_len, path_len;
 
-	/* url MUST begin with http: */
-	if (url_len < 7 || os_strncasecmp(url, "http://", 7))
+	/* URL MUST begin with HTTP scheme. In addition, limit the length of
+	 * the URL to 700 characters which is around the limit that was
+	 * implicitly enforced for more than 10 years due to a bug in
+	 * generating the event messages. */
+	if (url_len < 7 || os_strncasecmp(url, "http://", 7) || url_len > 700) {
+		wpa_printf(MSG_DEBUG, "WPS UPnP: Reject an unacceptable URL");
 		goto fail;
+	}
 	url += 7;
 	url_len -= 7;
 
@@ -381,6 +394,7 @@ static void subscr_addr_add_url(struct subscription *s
 
 	for (rp = result; rp; rp = rp->ai_next) {
 		struct subscr_addr *a;
+		struct sockaddr_in *addr = (struct sockaddr_in *) rp->ai_addr;
 
 		/* Limit no. of address to avoid denial of service attack */
 		if (dl_list_len(&s->addr_list) >= MAX_ADDR_PER_SUBSCRIPTION) {
@@ -389,6 +403,13 @@ static void subscr_addr_add_url(struct subscription *s
 			break;
 		}
 
+		if (!local_network_addr(s->sm, addr)) {
+			wpa_printf(MSG_INFO,
+				   "WPS UPnP: Ignore a delivery URL that points to another network %s",
+				   inet_ntoa(addr->sin_addr));
+			continue;
+		}
+
 		a = os_zalloc(sizeof(*a) + alloc_len);
 		if (a == NULL)
 			break;
@@ -889,11 +910,12 @@ static int eth_get(const char *device, u8 ea[ETH_ALEN]
  * @net_if: Selected network interface name
  * @ip_addr: Buffer for returning IP address in network byte order
  * @ip_addr_text: Buffer for returning a pointer to allocated IP address text
+ * @netmask: Buffer for returning netmask or %NULL if not needed
  * @mac: Buffer for returning MAC address
  * Returns: 0 on success, -1 on failure
  */
 int get_netif_info(const char *net_if, unsigned *ip_addr, char **ip_addr_text,
-		   u8 mac[ETH_ALEN])
+		   struct in_addr *netmask, u8 mac[ETH_ALEN])
 {
 	struct ifreq req;
 	int sock = -1;
@@ -919,6 +941,23 @@ int get_netif_info(const char *net_if, unsigned *ip_ad
 	in_addr.s_addr = *ip_addr;
 	os_snprintf(*ip_addr_text, 16, "%s", inet_ntoa(in_addr));
 
+	if (netmask) {
+		os_memset(&req, 0, sizeof(req));
+		os_strlcpy(req.ifr_name, net_if, sizeof(req.ifr_name));
+		if (ioctl(sock, SIOCGIFNETMASK, &req) < 0) {
+			wpa_printf(MSG_ERROR,
+				   "WPS UPnP: SIOCGIFNETMASK failed: %d (%s)",
+				   errno, strerror(errno));
+			goto fail;
+		}
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+		addr = (struct sockaddr_in *) &req.ifr_addr;
+#else
+		addr = (struct sockaddr_in *) &req.ifr_netmask;
+#endif
+		netmask->s_addr = addr->sin_addr.s_addr;
+	}
+
 #ifdef __linux__
 	os_strlcpy(req.ifr_name, net_if, sizeof(req.ifr_name));
 	if (ioctl(sock, SIOCGIFHWADDR, &req) < 0) {
@@ -1025,11 +1064,15 @@ static int upnp_wps_device_start(struct upnp_wps_devic
 
 	/* Determine which IP and mac address we're using */
 	if (get_netif_info(net_if, &sm->ip_addr, &sm->ip_addr_text,
-			   sm->mac_addr)) {
+			   &sm->netmask, sm->mac_addr)) {
 		wpa_printf(MSG_INFO, "WPS UPnP: Could not get IP/MAC address "
 			   "for %s. Does it have IP address?", net_if);
 		goto fail;
 	}
+	wpa_printf(MSG_DEBUG, "WPS UPnP: Local IP address %s netmask %s hwaddr "
+		   MACSTR,
+		   sm->ip_addr_text, inet_ntoa(sm->netmask),
+		   MAC2STR(sm->mac_addr));
 
 	/* Listen for incoming TCP connections so that others
 	 * can fetch our "xml files" from us.

Modified: stable/12/contrib/wpa/src/wps/wps_upnp_event.c
==============================================================================
--- stable/12/contrib/wpa/src/wps/wps_upnp_event.c	Fri Jun 12 00:42:05 2020	(r362080)
+++ stable/12/contrib/wpa/src/wps/wps_upnp_event.c	Fri Jun 12 01:03:51 2020	(r362081)
@@ -147,7 +147,8 @@ static struct wpabuf * event_build_message(struct wps_
 	struct wpabuf *buf;
 	char *b;
 
-	buf = wpabuf_alloc(1000 + wpabuf_len(e->data));
+	buf = wpabuf_alloc(1000 + os_strlen(e->addr->path) +
+			   wpabuf_len(e->data));
 	if (buf == NULL)
 		return NULL;
 	wpabuf_printf(buf, "NOTIFY %s HTTP/1.1\r\n", e->addr->path);
@@ -293,7 +294,7 @@ static int event_send_start(struct subscription *s)
 
 	buf = event_build_message(e);
 	if (buf == NULL) {
-		event_retry(e, 0);
+		event_addr_failure(e);
 		return -1;
 	}
 
@@ -301,7 +302,7 @@ static int event_send_start(struct subscription *s)
 					 event_http_cb, e);
 	if (e->http_event == NULL) {
 		wpabuf_free(buf);
-		event_retry(e, 0);
+		event_addr_failure(e);
 		return -1;
 	}
 

Modified: stable/12/contrib/wpa/src/wps/wps_upnp_i.h
==============================================================================
--- stable/12/contrib/wpa/src/wps/wps_upnp_i.h	Fri Jun 12 00:42:05 2020	(r362080)
+++ stable/12/contrib/wpa/src/wps/wps_upnp_i.h	Fri Jun 12 01:03:51 2020	(r362081)
@@ -128,6 +128,7 @@ struct upnp_wps_device_sm {
 	u8 mac_addr[ETH_ALEN]; /* mac addr of network i.f. we use */
 	char *ip_addr_text; /* IP address of network i.f. we use */
 	unsigned ip_addr; /* IP address of network i.f. we use (host order) */
+	struct in_addr netmask;
 	int multicast_sd; /* send multicast messages over this socket */
 	int ssdp_sd; /* receive discovery UPD packets on socket */
 	int ssdp_sd_registered; /* nonzero if we must unregister */
@@ -158,7 +159,7 @@ struct subscription * subscription_find(struct upnp_wp
 					const u8 uuid[UUID_LEN]);
 void subscr_addr_delete(struct subscr_addr *a);
 int get_netif_info(const char *net_if, unsigned *ip_addr, char **ip_addr_text,
-		   u8 mac[ETH_ALEN]);
+		   struct in_addr *netmask, u8 mac[ETH_ALEN]);
 
 /* wps_upnp_ssdp.c */
 void msearchreply_state_machine_stop(struct advertisement_state_machine *a);



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