167 lines
4.4 KiB
Diff
167 lines
4.4 KiB
Diff
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);
|