[gupnp/gupnp-1.0] service: Check subscribtion target address



commit ab07d72950cee566276fae6577c66bac40ad3656
Author: Jens Georg <mail jensge org>
Date:   Tue Jun 16 23:04:25 2020 +0200

    service: Check subscribtion target address
    
    It should not leave "our network segment". Mitigation for
    CVE-2020-12695 and required in UDA 2.0

 libgupnp/gupnp-context-private.h |  3 +++
 libgupnp/gupnp-context.c         | 26 ++++++++++++++++++++++++++
 libgupnp/gupnp-service.c         | 31 +++++++++++++++++++++++--------
 meson.build                      |  2 +-
 4 files changed, 53 insertions(+), 9 deletions(-)
---
diff --git a/libgupnp/gupnp-context-private.h b/libgupnp/gupnp-context-private.h
index c088563..801d679 100644
--- a/libgupnp/gupnp-context-private.h
+++ b/libgupnp/gupnp-context-private.h
@@ -36,6 +36,9 @@ _gupnp_context_add_server_handler_with_data (GUPnPContext *context,
                                              const char *path,
                                              AclServerHandler *data);
 
+G_GNUC_INTERNAL gboolean
+gupnp_context_ip_is_ours (GUPnPContext *context, const char *address);
+
 G_END_DECLS
 
 #endif /* __GUPNP_CONTEXT_PRIVATE_H__ */
diff --git a/libgupnp/gupnp-context.c b/libgupnp/gupnp-context.c
index bc86bc4..42c5fef 100644
--- a/libgupnp/gupnp-context.c
+++ b/libgupnp/gupnp-context.c
@@ -1558,3 +1558,29 @@ gupnp_context_remove_server_handler (GUPnPContext *context, const char *path)
 
         soup_server_remove_handler (context->priv->server, path);
 }
+
+gboolean
+gupnp_context_ip_is_ours (GUPnPContext *context, const char *address)
+{
+        // TODO: Could easily be in GSSDPClient, which does something similar
+        gboolean retval = FALSE;
+        GInetAddress *addr = NULL;
+        GInetAddressMask *mask = NULL;
+
+        addr = g_inet_address_new_from_string (address);
+
+        // Link-local addresses are reachable
+        if (g_inet_address_get_is_link_local (addr)) {
+            retval = TRUE;
+            goto out;
+        }
+
+        mask = gssdp_client_get_address_mask (GSSDP_CLIENT (context));
+        retval = g_inet_address_mask_matches (mask, addr);
+        g_object_unref (mask);
+
+out:
+        g_object_unref (addr);
+
+        return retval;
+}
diff --git a/libgupnp/gupnp-service.c b/libgupnp/gupnp-service.c
index a64b33f..3b0c4b9 100644
--- a/libgupnp/gupnp-service.c
+++ b/libgupnp/gupnp-service.c
@@ -1182,17 +1182,28 @@ send_initial_state (SubscriptionData *data)
 }
 
 static GList *
-add_subscription_callback (GList *list,
+add_subscription_callback (GUPnPContext *context,
+                           GList *list,
                            const char *callback)
 {
-    SoupURI *local_uri = NULL;
+            SoupURI *local_uri = NULL;
+            const char *host = NULL;
 
-    local_uri = soup_uri_new (callback);
-    if (local_uri != NULL) {
-        return g_list_append (list, local_uri);
-    }
+            local_uri = soup_uri_new (callback);
+            if (local_uri == NULL)
+                        return list;
 
-    return list;
+
+            host = soup_uri_get_host (local_uri);
+            // CVE-2020-12695: Ignore subscription call-backs that are not "in
+            // our network segment"
+            if (gupnp_context_ip_is_ours (context, host)) {
+                        return g_list_append (list, local_uri);
+            } else {
+                        g_warning ("%s is not in our network; ignoring", callback);
+            }
+
+            return list;
 }
 
 /* Subscription request */
@@ -1203,6 +1214,10 @@ subscribe (GUPnPService *service,
 {
         SubscriptionData *data;
         char *start, *end;
+        GUPnPContext *context;
+
+        context = gupnp_service_info_get_context
+                                            (GUPNP_SERVICE_INFO (service));
 
         data = g_slice_new0 (SubscriptionData);
 
@@ -1224,7 +1239,7 @@ subscribe (GUPnPService *service,
                         // Also one part of CVE-2020-12695 mitigation - limit URI length
                         // UPnP does not impose any restrictions here
                         if (strlen (start) <= 256) {
-                            add_subscription_callback (data->callbacks, start);
+                            add_subscription_callback (context, data->callbacks, start);
                         } else {
                             g_warning ("Subscription URI exceeds recommended length of "
                                        "256 bytes, skipping");
diff --git a/meson.build b/meson.build
index 888366f..c7f203b 100644
--- a/meson.build
+++ b/meson.build
@@ -33,7 +33,7 @@ dependencies = [
     dependency('gio-2.0', version : '>= 2.44'),
     dependency('gmodule-2.0', version : '>= 2.44'),
     dependency('gobject-2.0', version : '>= 2.44'),
-    dependency('gssdp-1.0', version : '>= 1.0'),
+    dependency('gssdp-1.0', version : '>= 1.0.4'),
     dependency('libsoup-2.4', version : '>= 2.48.0'),
     dependency('libxml-2.0'),
     guul.get_variable('guul')


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]