Repository: fwupd/fwupd (C)

Issue:
USB FD leak
I started having recent problems with the USB hub in my monitor, or its cabling, which kept connecting/disconnecting.

This lead to errors from fwupd in the journal after not very long:
```
[...]
Apr 18 12:16:26 olimpic fwupd[116785]: 10:16:26.797 FuBackend            ignoring netlink message: failed to probe: failed to open /sys/devices/pci0000:00/0000:00:14.0/usb1/1-4/1-4.2/uevent: Too many open files
Apr 18 12:16:26 olimpic fwupd[116785]: 10:16:26.800 FuBackend            failed to create device: failed to probe: failed to open /sys/devices/pci0000:00/0000:00:14.0/uevent: Too many open files
Apr 18 12:16:26 olimpic fwupd[116785]: 10:16:26.803 FuBackend            failed to create device: failed to probe: failed to open /sys/devices/pci0000:00/0000:00:14.0/uevent: Too many open files
Apr 18 12:16:26 olimpic fwupd[116785]: 10:16:26.809 FuBackend            failed to create device: failed to probe: failed to open /sys/devices/pci0000:00/0000:00:14.0/uevent: Too many open files
```

`fwupd-2.0.8-1.fc42.x86_64`

Log which show the errors:
[fwupd-journalctl.txt](https://github.com/user-attachments/files/19811375/fwupd-journalctl.txt)

List of open FDs, with many duplicates:
[fwupd-fd-list.txt](https://github.com/user-attachments/files/19811374/fwupd-fd-list.txt)



Fix (patch):
diff --git a/libfwupdplugin/fu-input-stream.c b/libfwupdplugin/fu-input-stream.c
index 49d0d51f5047..ab710b30ee3a 100644
--- a/libfwupdplugin/fu-input-stream.c
+++ b/libfwupdplugin/fu-input-stream.c
@@ -777,20 +777,3 @@ fu_input_stream_find(GInputStream *stream,
 		    (guint)bufsz);
 	return FALSE;
 }
-
-/**
- * fu_input_stream_locker_unref:
- * @stream: a #GInputStream
- *
- * Closes an input stream and then unrefs it.
- *
- * Since: 2.0.7
- **/
-void
-fu_input_stream_locker_unref(FuInputStreamLocker *stream)
-{
-	g_autoptr(GError) error_local = NULL;
-	if (!g_input_stream_close(stream, NULL, &error_local))
-		g_warning("failed to close input stream: %s", error_local->message);
-	g_object_unref(stream);
-}
diff --git a/libfwupdplugin/fu-input-stream.h b/libfwupdplugin/fu-input-stream.h
index 668a5fc02ec9..7ee1f6e68566 100644
--- a/libfwupdplugin/fu-input-stream.h
+++ b/libfwupdplugin/fu-input-stream.h
@@ -106,9 +106,3 @@ fu_input_stream_find(GInputStream *stream,
 		     gsize bufsz,
 		     gsize *offset,
 		     GError **error) G_GNUC_NON_NULL(1, 2);
-
-/* useful to close file descriptors backing the input stream */
-typedef GInputStream FuInputStreamLocker;
-void
-fu_input_stream_locker_unref(FuInputStreamLocker *stream) G_GNUC_NON_NULL(1);
-G_DEFINE_AUTOPTR_CLEANUP_FUNC(FuInputStreamLocker, fu_input_stream_locker_unref);
diff --git a/libfwupdplugin/fu-usb-bos-descriptor.c b/libfwupdplugin/fu-usb-bos-descriptor.c
index c7cccfbe496e..9e5a20b7dd8c 100644
--- a/libfwupdplugin/fu-usb-bos-descriptor.c
+++ b/libfwupdplugin/fu-usb-bos-descriptor.c
@@ -102,7 +102,11 @@ fu_usb_bos_descriptor_from_json(FwupdCodec *codec, JsonNode *json_node, GError *
 
 		/* create child */
 		stream = g_memory_input_stream_new_from_data(g_steal_pointer(&buf), bufsz, g_free);
-		if (!fu_firmware_set_stream(img, stream, error))
+		if (!fu_firmware_parse_stream(img,
+					      stream,
+					      0x0,
+					      FU_FIRMWARE_PARSE_FLAG_CACHE_BLOB,
+					      error))
 			return FALSE;
 		fu_firmware_set_id(img, FU_FIRMWARE_ID_PAYLOAD);
 		if (!fu_firmware_add_image_full(FU_FIRMWARE(self), img, error))
@@ -186,7 +190,11 @@ fu_usb_bos_descriptor_parse(FuFirmware *firmware,
 			g_prefix_error(error, "failed to cut BOS descriptor: ");
 			return FALSE;
 		}
-		if (!fu_firmware_set_stream(img, img_stream, error))
+		if (!fu_firmware_parse_stream(img,
+					      img_stream,
+					      0x0,
+					      FU_FIRMWARE_PARSE_FLAG_CACHE_BLOB,
+					      error))
 			return FALSE;
 		fu_firmware_set_id(img, FU_FIRMWARE_ID_PAYLOAD);
 		if (!fu_firmware_add_image_full(FU_FIRMWARE(self), img, error))
diff --git a/libfwupdplugin/fu-usb-descriptor.c b/libfwupdplugin/fu-usb-descriptor.c
index 30b9e3d14fb8..f5325f2923e7 100644
--- a/libfwupdplugin/fu-usb-descriptor.c
+++ b/libfwupdplugin/fu-usb-descriptor.c
@@ -6,7 +6,6 @@
 
 #include "config.h"
 
-#include "fu-partial-input-stream.h"
 #include "fu-usb-descriptor.h"
 
 G_DEFINE_TYPE(FuUsbDescriptor, fu_usb_descriptor, FU_TYPE_FIRMWARE)
@@ -17,23 +16,14 @@ fu_usb_descriptor_parse(FuFirmware *firmware,
 			FuFirmwareParseFlags flags,
 			GError **error)
 {
-	FuUsbDescriptor *self = FU_USB_DESCRIPTOR(firmware);
 	g_autoptr(FuUsbBaseHdr) st = NULL;
-	g_autoptr(GInputStream) stream_partial = NULL;
 
 	/* parse */
 	st = fu_usb_base_hdr_parse_stream(stream, 0x0, error);
 	if (st == NULL)
 		return FALSE;
-	stream_partial =
-	    fu_partial_input_stream_new(stream, 0x0, fu_usb_base_hdr_get_length(st), error);
-	if (stream_partial == NULL) {
-		g_prefix_error(error, "failed to cut USB descriptor: ");
-		return FALSE;
-	}
-	if (!fu_firmware_set_stream(firmware, stream_partial, error))
-		return FALSE;
-	fu_firmware_set_idx(FU_FIRMWARE(self), fu_usb_base_hdr_get_descriptor_type(st));
+	fu_firmware_set_size(firmware, fu_usb_base_hdr_get_length(st));
+	fu_firmware_set_idx(firmware, fu_usb_base_hdr_get_descriptor_type(st));
 
 	/* success */
 	return TRUE;
diff --git a/libfwupdplugin/fu-usb-device.c b/libfwupdplugin/fu-usb-device.c
index e2d6fbf03141..b8e754e0853b 100644
--- a/libfwupdplugin/fu-usb-device.c
+++ b/libfwupdplugin/fu-usb-device.c
@@ -50,7 +50,6 @@ typedef struct {
 	gint configuration;
 	GPtrArray *device_interfaces; /* (nullable) (element-type FuUsbDeviceInterface) */
 	guint claim_retry_count;
-	GPtrArray *descriptor_streams; /* (nullable) (element-type GInputStream) */
 } FuUsbDevicePrivate;
 
 typedef struct {
@@ -272,8 +271,6 @@ fu_usb_device_finalize(GObject *object)
 		libusb_unref_device(priv->usb_device);
 	if (priv->device_interfaces != NULL)
 		g_ptr_array_unref(priv->device_interfaces);
-	if (priv->descriptor_streams != NULL)
-		g_ptr_array_unref(priv->descriptor_streams);
 	g_ptr_array_unref(priv->interfaces);
 	g_ptr_array_unref(priv->bos_descriptors);
 	g_ptr_array_unref(priv->hid_descriptors);
@@ -996,18 +993,6 @@ fu_usb_device_parse_bos_descriptor(FuUsbDevice *self, GInputStream *stream, GErr
 	return TRUE;
 }
 
-/* these are closed on FuDevice->probe_complete() */
-static void
-fu_usb_device_add_descriptor_stream(FuUsbDevice *self, GInputStream *stream)
-{
-	FuUsbDevicePrivate *priv = GET_PRIVATE(self);
-	if (priv->descriptor_streams == NULL) {
-		priv->descriptor_streams =
-		    g_ptr_array_new_with_free_func((GDestroyNotify)fu_input_stream_locker_unref);
-	}
-	g_ptr_array_add(priv->descriptor_streams, g_object_ref(stream));
-}
-
 static gboolean
 fu_usb_device_ensure_bos_descriptors(FuUsbDevice *self, GError **error)
 {
@@ -1071,7 +1056,6 @@ fu_usb_device_ensure_bos_descriptors(FuUsbDevice *self, GError **error)
 				return FALSE;
 			}
 		} else {
-			fu_usb_device_add_descriptor_stream(self, stream); /* ->probe_complete */
 			if (!fu_usb_device_parse_bos_descriptor(self, stream, error))
 				return FALSE;
 		}
@@ -1313,18 +1297,6 @@ fu_usb_device_probe(FuDevice *device, GError **error)
 	return TRUE;
 }
 
-static void
-fu_usb_device_probe_complete(FuDevice *device)
-{
-	FuUsbDevice *self = FU_USB_DEVICE(device);
-	FuUsbDevicePrivate *priv = GET_PRIVATE(self);
-
-	/* FuUdevDevice->probe_complete */
-	FU_DEVICE_CLASS(fu_usb_device_parent_class)->probe_complete(device);
-	if (priv->descriptor_streams != NULL)
-		g_ptr_array_set_size(priv->descriptor_streams, 0);
-}
-
 /**
  * fu_usb_device_get_release:
  * @self: a #FuUsbDevice
@@ -1962,8 +1934,8 @@ fu_usb_device_ensure_interfaces(FuUsbDevice *self, GError **error)
 		}
 		libusb_free_config_descriptor(config);
 	} else {
-		g_autoptr(FuInputStreamLocker) stream = NULL;
 		g_autoptr(GError) error_local = NULL;
+		g_autoptr(GInputStream) stream = NULL;
 
 		stream = fu_usb_device_load_descriptor_stream(self, "descriptors", &error_local);
 		if (stream == NULL) {
@@ -3110,7 +3082,6 @@ fu_usb_device_class_init(FuUsbDeviceClass *klass)
 	device_class->ready = fu_usb_device_ready;
 	device_class->close = fu_usb_device_close;
 	device_class->probe = fu_usb_device_probe;
-	device_class->probe_complete = fu_usb_device_probe_complete;
 	device_class->invalidate = fu_usb_device_invalidate;
 	device_class->to_string = fu_usb_device_to_string;
 	device_class->incorporate = fu_usb_device_incorporate;
diff --git a/libfwupdplugin/fu-usb-interface.c b/libfwupdplugin/fu-usb-interface.c
index 56b074d76ca6..169e4cc480cc 100644
--- a/libfwupdplugin/fu-usb-interface.c
+++ b/libfwupdplugin/fu-usb-interface.c
@@ -65,7 +65,7 @@ fu_usb_interface_parse_extra(FuUsbInterface *self, const guint8 *buf, gsize bufs
 		if (!fu_firmware_parse_bytes(FU_FIRMWARE(img),
 					     bytes,
 					     offset,
-					     FU_FIRMWARE_PARSE_FLAG_NONE,
+					     FU_FIRMWARE_PARSE_FLAG_CACHE_BLOB,
 					     error))
 			return FALSE;
 		if (!fu_firmware_add_image_full(FU_FIRMWARE(self), FU_FIRMWARE(img), error))