summaryrefslogtreecommitdiff
path: root/drivers/firewire/core-card.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/firewire/core-card.c')
-rw-r--r--drivers/firewire/core-card.c28
1 files changed, 22 insertions, 6 deletions
diff --git a/drivers/firewire/core-card.c b/drivers/firewire/core-card.c
index a754c6366b97..94992791f02e 100644
--- a/drivers/firewire/core-card.c
+++ b/drivers/firewire/core-card.c
@@ -16,6 +16,7 @@
#include <linux/list.h>
#include <linux/module.h>
#include <linux/mutex.h>
+#include <linux/minmax.h>
#include <linux/spinlock.h>
#include <linux/workqueue.h>
@@ -167,15 +168,30 @@ int fw_core_add_descriptor(struct fw_descriptor *desc)
{
size_t i;
+ /* Reject empty descriptors or those exceeding max Config ROM size (256 quadlets) */
+ if (!in_range(desc->length, 1, 256))
+ return -EINVAL;
+
+ i = 0;
/*
- * Check descriptor is valid; the length of all blocks in the
- * descriptor has to add up to exactly the length of the
- * block.
+ * Validate internal block structures within the descriptor. Each sub-block
+ * encodes its length in the top 16 bits of its header quadlet.
*/
- i = 0;
- while (i < desc->length)
- i += (desc->data[i] >> 16) + 1;
+ while (i < desc->length) {
+ u16 block_len = desc->data[i] >> 16;
+
+ /*
+ * Guard against corrupted descriptors where an individual block length
+ * claims to extend past the allocated end of desc->data, avoiding
+ * out-of-bounds reads.
+ */
+ if (block_len >= desc->length - i)
+ return -EINVAL;
+
+ i += block_len + 1;
+ }
+ /* The sum of sub-block lengths must match total descriptor length */
if (i != desc->length)
return -EINVAL;