1From 5b78c8f961f25f4dc22d6f2b77ddd06d712cec63 Mon Sep 17 00:00:00 2001 2From: Jouni Malinen <jouni@codeaurora.org> 3Date: Wed, 3 Jun 2020 23:17:35 +0300 4Subject: [PATCH 1/3] WPS UPnP: Do not allow event subscriptions with URLs to 5 other networks 6 7The UPnP Device Architecture 2.0 specification errata ("UDA errata 816-04-2020.docx") addresses a problem with notifications being allowed 9to go out to other domains by disallowing such cases. Do such filtering 10for the notification callback URLs to avoid undesired connections to 11external networks based on subscriptions that any device in the local 12network could request when WPS support for external registrars is 13enabled (the upnp_iface parameter in hostapd configuration). 14 15Signed-off-by: Jouni Malinen <jouni@codeaurora.org> 16--- 17 src/wps/wps_er.c | 2 +- 18 src/wps/wps_upnp.c | 38 ++++++++++++++++++++++++++++++++++++-- 19 src/wps/wps_upnp_i.h | 3 ++- 20 3 files changed, 39 insertions(+), 4 deletions(-) 21 22diff --git a/src/wps/wps_er.c b/src/wps/wps_er.c 23index 6bded14327f8..31d2e50e4cff 100644 24--- a/src/wps/wps_er.c 25+++ b/src/wps/wps_er.c 26@@ -1298,7 +1298,7 @@ wps_er_init(struct wps_context *wps, const char *ifname, const char *filter) 27 "with %s", filter); 28 } 29 if (get_netif_info(er->ifname, &er->ip_addr, &er->ip_addr_text, 30- er->mac_addr)) { 31+ NULL, er->mac_addr)) { 32 wpa_printf(MSG_INFO, "WPS UPnP: Could not get IP/MAC address " 33 "for %s. Does it have IP address?", er->ifname); 34 wps_er_deinit(er, NULL, NULL); 35diff --git a/src/wps/wps_upnp.c b/src/wps/wps_upnp.c 36index 6e10e4bc0c3f..7d4b7439940e 100644 37--- a/src/wps/wps_upnp.c 38+++ b/src/wps/wps_upnp.c 39@@ -303,6 +303,14 @@ static void subscr_addr_free_all(struct subscription *s) 40 } 41 42 43+static int local_network_addr(struct upnp_wps_device_sm *sm, 44+ struct sockaddr_in *addr) 45+{ 46+ return (addr->sin_addr.s_addr & sm->netmask.s_addr) == 47+ (sm->ip_addr & sm->netmask.s_addr); 48+} 49+ 50+ 51 /* subscr_addr_add_url -- add address(es) for one url to subscription */ 52 static void subscr_addr_add_url(struct subscription *s, const char *url, 53 size_t url_len) 54@@ -381,6 +389,7 @@ static void subscr_addr_add_url(struct subscription *s, const char *url, 55 56 for (rp = result; rp; rp = rp->ai_next) { 57 struct subscr_addr *a; 58+ struct sockaddr_in *addr = (struct sockaddr_in *) rp->ai_addr; 59 60 /* Limit no. of address to avoid denial of service attack */ 61 if (dl_list_len(&s->addr_list) >= MAX_ADDR_PER_SUBSCRIPTION) { 62@@ -389,6 +398,13 @@ static void subscr_addr_add_url(struct subscription *s, const char *url, 63 break; 64 } 65 66+ if (!local_network_addr(s->sm, addr)) { 67+ wpa_printf(MSG_INFO, 68+ "WPS UPnP: Ignore a delivery URL that points to another network %s", 69+ inet_ntoa(addr->sin_addr)); 70+ continue; 71+ } 72+ 73 a = os_zalloc(sizeof(*a) + alloc_len); 74 if (a == NULL) 75 break; 76@@ -890,11 +906,12 @@ static int eth_get(const char *device, u8 ea[ETH_ALEN]) 77 * @net_if: Selected network interface name 78 * @ip_addr: Buffer for returning IP address in network byte order 79 * @ip_addr_text: Buffer for returning a pointer to allocated IP address text 80+ * @netmask: Buffer for returning netmask or %NULL if not needed 81 * @mac: Buffer for returning MAC address 82 * Returns: 0 on success, -1 on failure 83 */ 84 int get_netif_info(const char *net_if, unsigned *ip_addr, char **ip_addr_text, 85- u8 mac[ETH_ALEN]) 86+ struct in_addr *netmask, u8 mac[ETH_ALEN]) 87 { 88 struct ifreq req; 89 int sock = -1; 90@@ -920,6 +937,19 @@ int get_netif_info(const char *net_if, unsigned *ip_addr, char **ip_addr_text, 91 in_addr.s_addr = *ip_addr; 92 os_snprintf(*ip_addr_text, 16, "%s", inet_ntoa(in_addr)); 93 94+ if (netmask) { 95+ os_memset(&req, 0, sizeof(req)); 96+ os_strlcpy(req.ifr_name, net_if, sizeof(req.ifr_name)); 97+ if (ioctl(sock, SIOCGIFNETMASK, &req) < 0) { 98+ wpa_printf(MSG_ERROR, 99+ "WPS UPnP: SIOCGIFNETMASK failed: %d (%s)", 100+ errno, strerror(errno)); 101+ goto fail; 102+ } 103+ addr = (struct sockaddr_in *) &req.ifr_netmask; 104+ netmask->s_addr = addr->sin_addr.s_addr; 105+ } 106+ 107 #ifdef __linux__ 108 os_strlcpy(req.ifr_name, net_if, sizeof(req.ifr_name)); 109 if (ioctl(sock, SIOCGIFHWADDR, &req) < 0) { 110@@ -1026,11 +1056,15 @@ static int upnp_wps_device_start(struct upnp_wps_device_sm *sm, char *net_if) 111 112 /* Determine which IP and mac address we're using */ 113 if (get_netif_info(net_if, &sm->ip_addr, &sm->ip_addr_text, 114- sm->mac_addr)) { 115+ &sm->netmask, sm->mac_addr)) { 116 wpa_printf(MSG_INFO, "WPS UPnP: Could not get IP/MAC address " 117 "for %s. Does it have IP address?", net_if); 118 goto fail; 119 } 120+ wpa_printf(MSG_DEBUG, "WPS UPnP: Local IP address %s netmask %s hwaddr " 121+ MACSTR, 122+ sm->ip_addr_text, inet_ntoa(sm->netmask), 123+ MAC2STR(sm->mac_addr)); 124 125 /* Listen for incoming TCP connections so that others 126 * can fetch our "xml files" from us. 127diff --git a/src/wps/wps_upnp_i.h b/src/wps/wps_upnp_i.h 128index e87a93232df1..6ead7b4e9a30 100644 129--- a/src/wps/wps_upnp_i.h 130+++ b/src/wps/wps_upnp_i.h 131@@ -128,6 +128,7 @@ struct upnp_wps_device_sm { 132 u8 mac_addr[ETH_ALEN]; /* mac addr of network i.f. we use */ 133 char *ip_addr_text; /* IP address of network i.f. we use */ 134 unsigned ip_addr; /* IP address of network i.f. we use (host order) */ 135+ struct in_addr netmask; 136 int multicast_sd; /* send multicast messages over this socket */ 137 int ssdp_sd; /* receive discovery UPD packets on socket */ 138 int ssdp_sd_registered; /* nonzero if we must unregister */ 139@@ -158,7 +159,7 @@ struct subscription * subscription_find(struct upnp_wps_device_sm *sm, 140 const u8 uuid[UUID_LEN]); 141 void subscr_addr_delete(struct subscr_addr *a); 142 int get_netif_info(const char *net_if, unsigned *ip_addr, char **ip_addr_text, 143- u8 mac[ETH_ALEN]); 144+ struct in_addr *netmask, u8 mac[ETH_ALEN]); 145 146 /* wps_upnp_ssdp.c */ 147 void msearchreply_state_machine_stop(struct advertisement_state_machine *a); 148-- 1492.20.1 150 151