1
1
mirror of https://github.com/systemd/systemd-stable.git synced 2024-10-28 11:55:23 +03:00

sd-device: fix crash if a device has many tags or devlinks

strjoina() is unsafe to be used in an unbounded loop as alloca() has no error
reporting. Thus devices with a large number of tags or devlinks trigger a
segfault in device_properties_prepare() due to overflowing the stack.

Rewrite the building of the "tags" and "devlinks" strings using
GREEDY_REALLOC() and strpcpy() to work with arbitrarily long strings. This also
avoids re-copying the entire string in each loop iteration.

Before this commit we always appended one final ":" to "tags". Change this to
start with an iniital ":" and for each tag append instead of prepend a ":".
This unifies what happens for the first and all subsequent tags so that we can
use a for loop.

Fixes #2954
This commit is contained in:
Martin Pitt 2016-04-04 11:09:00 +02:00
parent 77384fb0ed
commit 1d88a271a6

View File

@ -1457,15 +1457,20 @@ static int device_properties_prepare(sd_device *device) {
return r;
if (device->property_devlinks_outdated) {
char *devlinks = NULL;
_cleanup_free_ char *devlinks = NULL;
size_t devlinks_allocated = 0, devlinks_len = 0;
const char *devlink;
devlink = sd_device_get_devlink_first(device);
if (devlink)
devlinks = strdupa(devlink);
for (devlink = sd_device_get_devlink_first(device); devlink; devlink = sd_device_get_devlink_next(device)) {
char *e;
while ((devlink = sd_device_get_devlink_next(device)))
devlinks = strjoina(devlinks, " ", devlink);
if (!GREEDY_REALLOC(devlinks, devlinks_allocated, devlinks_len + strlen(devlink) + 2))
return -ENOMEM;
if (devlinks_len > 0)
stpcpy(devlinks + devlinks_len++, " ");
e = stpcpy(devlinks + devlinks_len, devlink);
devlinks_len = e - devlinks;
}
r = device_add_property_internal(device, "DEVLINKS", devlinks);
if (r < 0)
@ -1475,17 +1480,23 @@ static int device_properties_prepare(sd_device *device) {
}
if (device->property_tags_outdated) {
char *tags = NULL;
_cleanup_free_ char *tags = NULL;
size_t tags_allocated = 0, tags_len = 0;
const char *tag;
tag = sd_device_get_tag_first(device);
if (tag)
tags = strjoina(":", tag);
if (!GREEDY_REALLOC(tags, tags_allocated, 2))
return -ENOMEM;
stpcpy(tags, ":");
tags_len++;
while ((tag = sd_device_get_tag_next(device)))
tags = strjoina(tags, ":", tag);
for (tag = sd_device_get_tag_first(device); tag; tag = sd_device_get_tag_next(device)) {
char *e;
tags = strjoina(tags, ":");
if (!GREEDY_REALLOC(tags, tags_allocated, tags_len + strlen(tag) + 1))
return -ENOMEM;
e = stpcpy(stpcpy(tags + tags_len, tag), ":");
tags_len = e - tags;
}
r = device_add_property_internal(device, "TAGS", tags);
if (r < 0)