summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJens Georg <mail@jensge.org>2022-01-02 20:06:26 +0100
committerJens Georg <mail@jensge.org>2022-01-02 20:50:10 +0100
commit13965fc0dfab6420ba69c002e6a79543b9f6f1c7 (patch)
tree81941dddbbe9f077c40cafd92faa317f840e2607
parent9cf06a0280dd98be4d6328132d9df085ca1ac82a (diff)
downloadgupnp-13965fc0dfab6420ba69c002e6a79543b9f6f1c7.tar.gz
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
-rw-r--r--libgupnp/gupnp-device-info-private.h3
-rw-r--r--libgupnp/gupnp-device-info.c35
-rw-r--r--libgupnp/gupnp-resource-factory.c48
-rw-r--r--libgupnp/gupnp-root-device.c56
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);
}