Skip to content

Commit 76d4719

Browse files
committed
Fixed buffer overflows in ls-tree.c
As reported in GitHub issue pciutils#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.
1 parent cb94f26 commit 76d4719

File tree

2 files changed

+47
-22
lines changed

2 files changed

+47
-22
lines changed

lib/sysdep.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
11
/*
22
* The PCI Library -- System-Dependent Stuff
33
*
4-
* Copyright (c) 1997--2004 Martin Mares <[email protected]>
4+
* Copyright (c) 1997--2020 Martin Mares <[email protected]>
55
*
66
* Can be freely distributed and used under the terms of the GNU GPL.
77
*/
88

99
#ifdef __GNUC__
1010
#define UNUSED __attribute__((unused))
1111
#define NONRET __attribute__((noreturn))
12+
#define FORMAT_CHECK(x,y,z) __attribute__((format(x,y,z)))
1213
#else
1314
#define UNUSED
1415
#define NONRET
16+
#define FORMAT_CHECK(x,y,z)
1517
#define inline
1618
#endif
1719

ls-tree.c

+44-21
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
/*
22
* The PCI Utilities -- Show Bus Tree
33
*
4-
* Copyright (c) 1997--2018 Martin Mares <[email protected]>
4+
* Copyright (c) 1997--2020 Martin Mares <[email protected]>
55
*
66
* Can be freely distributed and used under the terms of the GNU GPL.
77
*/
88

9+
#include <stdarg.h>
910
#include <stdio.h>
1011
#include <string.h>
1112

@@ -154,29 +155,54 @@ print_it(char *line, char *p)
154155

155156
static void show_tree_bridge(struct bridge *, char *, char *);
156157

158+
#define LINE_BUF_SIZE 1024
159+
160+
static char * FORMAT_CHECK(printf, 3, 4)
161+
tree_printf(char *line, char *p, char *fmt, ...)
162+
{
163+
va_list args;
164+
char *end = line + LINE_BUF_SIZE - 2;
165+
166+
if (p >= end)
167+
return p;
168+
169+
va_start(args, fmt);
170+
int res = vsnprintf(p, end - p, fmt, args);
171+
if (res < 0)
172+
{
173+
/* Ancient C libraries return -1 on overflow */
174+
p += strlen(p);
175+
}
176+
else
177+
p += res;
178+
179+
va_end(args);
180+
return p;
181+
}
182+
157183
static void
158184
show_tree_dev(struct device *d, char *line, char *p)
159185
{
160186
struct pci_dev *q = d->dev;
161187
struct bridge *b;
162188
char namebuf[256];
163189

164-
p += sprintf(p, "%02x.%x", q->dev, q->func);
190+
p = tree_printf(line, p, "%02x.%x", q->dev, q->func);
165191
for (b=&host_bridge; b; b=b->chain)
166192
if (b->br_dev == d)
167193
{
168194
if (b->secondary == b->subordinate)
169-
p += sprintf(p, "-[%02x]-", b->secondary);
195+
p = tree_printf(line, p, "-[%02x]-", b->secondary);
170196
else
171-
p += sprintf(p, "-[%02x-%02x]-", b->secondary, b->subordinate);
197+
p = tree_printf(line, p, "-[%02x-%02x]-", b->secondary, b->subordinate);
172198
show_tree_bridge(b, line, p);
173199
return;
174200
}
175201
if (verbose)
176-
p += sprintf(p, " %s",
177-
pci_lookup_name(pacc, namebuf, sizeof(namebuf),
178-
PCI_LOOKUP_VENDOR | PCI_LOOKUP_DEVICE,
179-
q->vendor_id, q->device_id));
202+
p = tree_printf(line, p, " %s",
203+
pci_lookup_name(pacc, namebuf, sizeof(namebuf),
204+
PCI_LOOKUP_VENDOR | PCI_LOOKUP_DEVICE,
205+
q->vendor_id, q->device_id));
180206
print_it(line, p);
181207
}
182208

@@ -187,23 +213,20 @@ show_tree_bus(struct bus *b, char *line, char *p)
187213
print_it(line, p);
188214
else if (!b->first_dev->bus_next)
189215
{
190-
*p++ = '-';
191-
*p++ = '-';
216+
p = tree_printf(line, p, "--");
192217
show_tree_dev(b->first_dev, line, p);
193218
}
194219
else
195220
{
196221
struct device *d = b->first_dev;
197222
while (d->bus_next)
198223
{
199-
p[0] = '+';
200-
p[1] = '-';
201-
show_tree_dev(d, line, p+2);
224+
char *p2 = tree_printf(line, p, "+-");
225+
show_tree_dev(d, line, p2);
202226
d = d->bus_next;
203227
}
204-
p[0] = '\\';
205-
p[1] = '-';
206-
show_tree_dev(d, line, p+2);
228+
p = tree_printf(line, p, "\\-");
229+
show_tree_dev(d, line, p);
207230
}
208231
}
209232

@@ -214,7 +237,7 @@ show_tree_bridge(struct bridge *b, char *line, char *p)
214237
if (!b->first_bus->sibling)
215238
{
216239
if (b == &host_bridge)
217-
p += sprintf(p, "[%04x:%02x]-", b->domain, b->first_bus->number);
240+
p = tree_printf(line, p, "[%04x:%02x]-", b->domain, b->first_bus->number);
218241
show_tree_bus(b->first_bus, line, p);
219242
}
220243
else
@@ -224,19 +247,19 @@ show_tree_bridge(struct bridge *b, char *line, char *p)
224247

225248
while (u->sibling)
226249
{
227-
k = p + sprintf(p, "+-[%04x:%02x]-", u->domain, u->number);
250+
k = tree_printf(line, p, "+-[%04x:%02x]-", u->domain, u->number);
228251
show_tree_bus(u, line, k);
229252
u = u->sibling;
230253
}
231-
k = p + sprintf(p, "\\-[%04x:%02x]-", u->domain, u->number);
254+
k = tree_printf(line, p, "\\-[%04x:%02x]-", u->domain, u->number);
232255
show_tree_bus(u, line, k);
233256
}
234257
}
235258

236259
void
237260
show_forest(struct pci_filter *filter)
238261
{
239-
char line[256];
262+
char line[LINE_BUF_SIZE];
240263
if (filter == NULL)
241264
show_tree_bridge(&host_bridge, line, line);
242265
else
@@ -248,7 +271,7 @@ show_forest(struct pci_filter *filter)
248271
{
249272
struct pci_dev *d = b->br_dev->dev;
250273
char *p = line;
251-
p += sprintf(line, "%04x:%02x:", d->domain_16, d->bus);
274+
p = tree_printf(line, p, "%04x:%02x:", d->domain_16, d->bus);
252275
show_tree_dev(b->br_dev, line, p);
253276
}
254277
}

0 commit comments

Comments
 (0)