File lspci-Fixed-buffer-overflows-in-ls-tree.c.patch of Package pciutils

From 76d47191f9274991059a41e19e1999a12c0d3416 Mon Sep 17 00:00:00 2001
From: Martin Mares <mj@ucw.cz>
Date: Wed, 22 Jan 2020 09:49:18 +0100
Subject: [PATCH] Fixed buffer overflows in ls-tree.c

As reported in GitHub issue #24, tree dumping mode can smash the stack
if the hierarchy of buses is too deep.

Increased line buffer size to 1024 and switched to use of snprintf
everywhere, so that in the worst case, the line is truncated.

As snprintf can be problematic on obscure platforms, I wrapped it
in tree_printf(), so that we can add #ifdefs should problems arise.
---
 lib/sysdep.h |  2 ++
 ls-tree.c    | 65 +++++++++++++++++++++++++++++++++++-----------------
 2 files changed, 47 insertions(+), 22 deletions(-)

diff --git a/lib/sysdep.h b/lib/sysdep.h
index e525dc4..1a5cb16 100644
--- a/lib/sysdep.h
+++ b/lib/sysdep.h
@@ -9,9 +9,11 @@
 #ifdef __GNUC__
 #define UNUSED __attribute__((unused))
 #define NONRET __attribute__((noreturn))
+#define FORMAT_CHECK(x,y,z) __attribute__((format(x,y,z)))
 #else
 #define UNUSED
 #define NONRET
+#define FORMAT_CHECK(x,y,z)
 #define inline
 #endif
 
diff --git a/ls-tree.c b/ls-tree.c
index 6995dd2..aeb4087 100644
--- a/ls-tree.c
+++ b/ls-tree.c
@@ -6,6 +6,7 @@
  *	Can be freely distributed and used under the terms of the GNU GPL.
  */
 
+#include <stdarg.h>
 #include <stdio.h>
 #include <string.h>
 
@@ -167,6 +168,31 @@
 
 static void show_tree_bridge(struct bridge *, char *, char *);
 
+#define LINE_BUF_SIZE 1024
+
+static char * FORMAT_CHECK(printf, 3, 4)
+tree_printf(char *line, char *p, char *fmt, ...)
+{
+  va_list args;
+  char *end = line + LINE_BUF_SIZE - 2;
+
+  if (p >= end)
+    return p;
+
+  va_start(args, fmt);
+  int res = vsnprintf(p, end - p, fmt, args);
+  if (res < 0)
+   {
+      /* Ancient C libraries return -1 on overflow */
+      p += strlen(p);
+    }
+  else
+    p += res;
+
+  va_end(args);
+  return p;
+}
+
 static void
 show_tree_dev(struct device *d, char *line, char *p)
 {
@@ -174,19 +200,19 @@
   struct bridge *b;
   char namebuf[256];
 
-  p += sprintf(p, "%02x.%x", q->dev, q->func);
+  p = tree_printf(line, p, "%02x.%x", q->dev, q->func);
   for (b=&host_bridge; b; b=b->chain)
     if (b->br_dev == d)
       {
 	if (b->secondary == b->subordinate)
-	  p += sprintf(p, "-[%02x]-", b->secondary);
+	  p = tree_printf(line, p, "-[%02x]-", b->secondary);
 	else
-	  p += sprintf(p, "-[%02x-%02x]-", b->secondary, b->subordinate);
+	  p = tree_printf(line, p, "-[%02x-%02x]-", b->secondary, b->subordinate);
         show_tree_bridge(b, line, p);
         return;
       }
   if (verbose)
-    p += sprintf(p, "  %s",
+    p = tree_printf(line, p, "  %s",
 		 pci_lookup_name(pacc, namebuf, sizeof(namebuf),
 				 PCI_LOOKUP_VENDOR | PCI_LOOKUP_DEVICE,
 				 q->vendor_id, q->device_id));
@@ -200,8 +226,7 @@
     print_it(line, p);
   else if (!b->first_dev->next)
     {
-      *p++ = '-';
-      *p++ = '-';
+      p = tree_printf(line, p, "--");
       show_tree_dev(b->first_dev, line, p);
     }
   else
@@ -209,25 +234,23 @@
       struct device *d = b->first_dev;
       while (d->next)
 	{
-	  p[0] = '+';
-	  p[1] = '-';
-	  show_tree_dev(d, line, p+2);
+	  char *p2 = tree_printf(line, p, "+-");
+	  show_tree_dev(d, line, p2);
 	  d = d->next;
 	}
-      p[0] = '\\';
-      p[1] = '-';
-      show_tree_dev(d, line, p+2);
+      p = tree_printf(line, p, "\\-");
+      show_tree_dev(d, line, p);
     }
 }
 
 static void
 show_tree_bridge(struct bridge *b, char *line, char *p)
 {
-  *p++ = '-';
+  p = tree_printf(line, p, "-");
   if (!b->first_bus->sibling)
     {
       if (b == &host_bridge)
-        p += sprintf(p, "[%04x:%02x]-", b->domain, b->first_bus->number);
+        p = tree_printf(line, p, "[%04x:%02x]-", b->domain, b->first_bus->number);
       show_tree_bus(b->first_bus, line, p);
     }
   else
@@ -237,11 +260,11 @@
 
       while (u->sibling)
         {
-          k = p + sprintf(p, "+-[%04x:%02x]-", u->domain, u->number);
+          k = tree_printf(line, p, "+-[%04x:%02x]-", u->domain, u->number);
           show_tree_bus(u, line, k);
           u = u->sibling;
         }
-      k = p + sprintf(p, "\\-[%04x:%02x]-", u->domain, u->number);
+      k = tree_printf(line, p, "\\-[%04x:%02x]-", u->domain, u->number);
       show_tree_bus(u, line, k);
     }
 }
@@ -249,7 +272,7 @@
 void
 show_forest(void)
 {
-  char line[256];
+  char line[LINE_BUF_SIZE];
 
   grow_tree();
   show_tree_bridge(&host_bridge, line, line);
openSUSE Build Service is sponsored by