[gupnp/gupnp-1.4] Device,Service,RootDevice: Fix use after free



commit 13965fc0dfab6420ba69c002e6a79543b9f6f1c7
Author: Jens Georg <mail jensge org>
Date:   Sun Jan 2 20:06:26 2022 +0100

    Device,Service,RootDevice: Fix use after free
    
    Devices and Services created by a RootDevice were keeping a pointer to
    their XML element, but not to the document, so it could happen that if
    the service lived longer than the RootDevice, the element pointer was
    invalid.
    
    This is already implemented like this for DeviceProxy and ServiceProxy.
    
    No idea why the description-doc property was introduced additionally
    to the "document" property on DeviceInfo.
    
    Fixes #42

 libgupnp/gupnp-device-info-private.h |  3 ++
 libgupnp/gupnp-device-info.c         | 35 +++++++++++++---------
 libgupnp/gupnp-resource-factory.c    | 48 ++++++++++++++++++++++---------
 libgupnp/gupnp-root-device.c         | 56 +++++++++++++++++++++++-------------
 4 files changed, 96 insertions(+), 46 deletions(-)
---
diff --git a/libgupnp/gupnp-device-info-private.h b/libgupnp/gupnp-device-info-private.h
index 023d12a..ebb440d 100644
--- a/libgupnp/gupnp-device-info-private.h
+++ b/libgupnp/gupnp-device-info-private.h
@@ -15,4 +15,7 @@
 G_GNUC_INTERNAL GUPnPXMLDoc *
 _gupnp_device_info_get_document (GUPnPDeviceInfo *info);
 
+G_GNUC_INTERNAL void
+_gupnp_device_info_set_document (GUPnPDeviceInfo *info, GUPnPXMLDoc *doc);
+
 #endif /* GUPNP_DEVICE_INFO_PRIVATE_H */
diff --git a/libgupnp/gupnp-device-info.c b/libgupnp/gupnp-device-info.c
index fd3d8ce..609ed4b 100644
--- a/libgupnp/gupnp-device-info.c
+++ b/libgupnp/gupnp-device-info.c
@@ -310,19 +310,18 @@ gupnp_device_info_class_init (GUPnPDeviceInfoClass *klass)
          *
          * Stability: Private
          **/
-        g_object_class_install_property
-                (object_class,
-                 PROP_DOCUMENT,
-                 g_param_spec_object ("document",
-                                      "Document",
-                                      "The XML document related to this "
-                                      "device",
-                                      GUPNP_TYPE_XML_DOC,
-                                      G_PARAM_READWRITE |
-                                      G_PARAM_CONSTRUCT_ONLY |
-                                      G_PARAM_STATIC_NAME |
-                                      G_PARAM_STATIC_NICK |
-                                      G_PARAM_STATIC_BLURB));
+        g_object_class_install_property (
+                object_class,
+                PROP_DOCUMENT,
+                g_param_spec_object ("document",
+                                     "Document",
+                                     "The XML document related to this "
+                                     "device",
+                                     GUPNP_TYPE_XML_DOC,
+                                     G_PARAM_READWRITE | G_PARAM_CONSTRUCT |
+                                             G_PARAM_STATIC_NAME |
+                                             G_PARAM_STATIC_NICK |
+                                             G_PARAM_STATIC_BLURB));
 
         /**
          * GUPnPDeviceInfo:element:
@@ -1466,3 +1465,13 @@ _gupnp_device_info_get_document (GUPnPDeviceInfo *info)
 
         return priv->doc;
 }
+
+void
+_gupnp_device_info_set_document (GUPnPDeviceInfo *info, GUPnPXMLDoc *doc)
+{
+        GUPnPDeviceInfoPrivate *priv;
+
+        priv = gupnp_device_info_get_instance_private (info);
+
+        priv->doc = g_object_ref (doc);
+}
diff --git a/libgupnp/gupnp-resource-factory.c b/libgupnp/gupnp-resource-factory.c
index 9ab34db..05b5e01 100644
--- a/libgupnp/gupnp-resource-factory.c
+++ b/libgupnp/gupnp-resource-factory.c
@@ -25,6 +25,7 @@
 #include <config.h>
 #include <string.h>
 
+#include "gupnp-device-info-private.h"
 #include "gupnp-resource-factory-private.h"
 #include "gupnp-root-device.h"
 
@@ -338,14 +339,25 @@ gupnp_resource_factory_create_device
                                                  element,
                                                  GUPNP_TYPE_DEVICE);
 
+        GUPnPXMLDoc *doc = _gupnp_device_info_get_document (
+                GUPNP_DEVICE_INFO (root_device));
         device = g_object_new (device_type,
-                               "resource-factory", factory,
-                               "context", context,
-                               "root-device", root_device,
-                               "location", location,
-                               "udn", udn,
-                               "url-base", url_base,
-                               "element", element,
+                               "resource-factory",
+                               factory,
+                               "context",
+                               context,
+                               "root-device",
+                               root_device,
+                               "location",
+                               location,
+                               "udn",
+                               udn,
+                               "url-base",
+                               url_base,
+                               "document",
+                               doc,
+                               "element",
+                               element,
                                NULL);
 
         return device;
@@ -395,13 +407,23 @@ gupnp_resource_factory_create_service
                                                   element,
                                                   GUPNP_TYPE_SERVICE);
 
+        GUPnPXMLDoc *doc = _gupnp_device_info_get_document (
+                GUPNP_DEVICE_INFO (root_device));
         service = g_object_new (service_type,
-                                "context", context,
-                                "root-device", root_device,
-                                "location", location,
-                                "udn", udn,
-                                "url-base", url_base,
-                                "element", element,
+                                "context",
+                                context,
+                                "root-device",
+                                root_device,
+                                "location",
+                                location,
+                                "udn",
+                                udn,
+                                "url-base",
+                                url_base,
+                                "document",
+                                doc,
+                                "element",
+                                element,
                                 NULL);
 
         return service;
diff --git a/libgupnp/gupnp-root-device.c b/libgupnp/gupnp-root-device.c
index 0872752..d46aa05 100644
--- a/libgupnp/gupnp-root-device.c
+++ b/libgupnp/gupnp-root-device.c
@@ -19,9 +19,10 @@
 
 #include <libgssdp/gssdp-resource-group.h>
 
-#include "gupnp-root-device.h"
 #include "gupnp-context-private.h"
+#include "gupnp-device-info-private.h"
 #include "gupnp-error.h"
+#include "gupnp-root-device.h"
 #include "http-headers.h"
 #include "xml-util.h"
 
@@ -35,8 +36,6 @@ gupnp_root_device_initable_init (GInitable     *initable,
                                  GError       **error);
 
 struct _GUPnPRootDevicePrivate {
-        GUPnPXMLDoc *description_doc;
-
         GSSDPResourceGroup *group;
 
         char  *description_path;
@@ -72,7 +71,6 @@ gupnp_root_device_finalize (GObject *object)
         device = GUPNP_ROOT_DEVICE (object);
         priv = gupnp_root_device_get_instance_private (device);
 
-        g_clear_object (&priv->description_doc);
         g_free (priv->description_path);
         g_free (priv->description_dir);
         g_free (priv->relative_location);
@@ -129,7 +127,8 @@ gupnp_root_device_set_property (GObject      *object,
 
         switch (property_id) {
         case PROP_DESCRIPTION_DOC:
-                priv->description_doc = g_value_dup_object (value);
+                _gupnp_device_info_set_document (GUPNP_DEVICE_INFO (device),
+                                                 g_value_get_object (value));
                 break;
         case PROP_DESCRIPTION_PATH:
                 priv->description_path = g_value_dup_string (value);
@@ -345,11 +344,13 @@ gupnp_root_device_initable_init (GInitable     *initable,
                                               priv->description_path,
                                               NULL);
 
+        GUPnPXMLDoc *description_doc =
+                _gupnp_device_info_get_document (GUPNP_DEVICE_INFO (device));
         /* Check whether we have a parsed description document */
-        if (priv->description_doc == NULL) {
+        if (description_doc == NULL) {
                 /* We don't, so load and parse it */
-                priv->description_doc = load_and_parse (desc_path);
-                if (priv->description_doc == NULL) {
+                description_doc = load_and_parse (desc_path);
+                if (description_doc == NULL) {
                         g_set_error_literal (error,
                                              GUPNP_XML_ERROR,
                                              GUPNP_XML_ERROR_PARSE,
@@ -357,13 +358,15 @@ gupnp_root_device_initable_init (GInitable     *initable,
 
                         goto DONE;
                 }
+        } else {
+                g_object_ref (description_doc);
         }
 
         /* Find correct element */
-        root_element = xml_util_get_element ((xmlNode *)
-                                             gupnp_xml_doc_get_doc (priv->description_doc),
-                                             "root",
-                                             NULL);
+        root_element = xml_util_get_element (
+                (xmlNode *) gupnp_xml_doc_get_doc (description_doc),
+                "root",
+                NULL);
         if (!root_element) {
                 g_set_error_literal (error,
                                      GUPNP_XML_ERROR,
@@ -420,8 +423,12 @@ gupnp_root_device_initable_init (GInitable     *initable,
 
         /* Set additional properties */
         g_object_set (G_OBJECT (device),
-                      "location", location,
-                      "url-base", url_base,
+                      "location",
+                      location,
+                      "url-base",
+                      url_base,
+                      "document",
+                      description_doc,
                       NULL);
 
         soup_uri_free (url_base);
@@ -446,6 +453,8 @@ gupnp_root_device_initable_init (GInitable     *initable,
         if (uri)
                 soup_uri_free (uri);
 
+        g_clear_object (&description_doc);
+
         g_free (desc_path);
         g_free (location);
 
@@ -470,6 +479,7 @@ gupnp_root_device_class_init (GUPnPRootDeviceClass *klass)
          * Device description document. Constructor property.
          *
          * Since: 0.14.0
+         * Deprecated: 1.14.2: Use GUPnPDeviceInfo::document instead
          **/
         g_object_class_install_property
                 (object_class,
@@ -605,12 +615,18 @@ gupnp_root_device_new_full (GUPnPContext         *context,
         return g_initable_new (GUPNP_TYPE_ROOT_DEVICE,
                                NULL,
                                error,
-                               "context", context,
-                               "resource-factory", factory,
-                               "root-device", NULL,
-                               "description-doc", description_doc,
-                               "description-path", description_path,
-                               "description-dir", description_dir,
+                               "context",
+                               context,
+                               "resource-factory",
+                               factory,
+                               "root-device",
+                               NULL,
+                               "document",
+                               description_doc,
+                               "description-path",
+                               description_path,
+                               "description-dir",
+                               description_dir,
                                NULL);
 }
 


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