mirror of
https://github.com/torvalds/linux.git
synced 2024-11-15 00:21:59 +00:00
a1aa5390cc
In of_modalias(), we can get passed the str and len parameters which would cause a kernel oops in vsnprintf() since it only allows passing a NULL ptr when the length is also 0. Also, we need to filter out the negative values of the len parameter as these will result in a really huge buffer since snprintf() takes size_t parameter while ours is ssize_t... Found by Linux Verification Center (linuxtesting.org) with the Svace static analysis tool. Signed-off-by: Sergey Shtylyov <s.shtylyov@omp.ru> Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/1d211023-3923-685b-20f0-f3f90ea56e1f@omp.ru Signed-off-by: Rob Herring <robh@kernel.org>
83 lines
1.5 KiB
C
83 lines
1.5 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Linux kernel module helpers.
|
|
*/
|
|
|
|
#include <linux/of.h>
|
|
#include <linux/module.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/string.h>
|
|
|
|
ssize_t of_modalias(const struct device_node *np, char *str, ssize_t len)
|
|
{
|
|
const char *compat;
|
|
char *c;
|
|
struct property *p;
|
|
ssize_t csize;
|
|
ssize_t tsize;
|
|
|
|
/*
|
|
* Prevent a kernel oops in vsnprintf() -- it only allows passing a
|
|
* NULL ptr when the length is also 0. Also filter out the negative
|
|
* lengths...
|
|
*/
|
|
if ((len > 0 && !str) || len < 0)
|
|
return -EINVAL;
|
|
|
|
/* Name & Type */
|
|
/* %p eats all alphanum characters, so %c must be used here */
|
|
csize = snprintf(str, len, "of:N%pOFn%c%s", np, 'T',
|
|
of_node_get_device_type(np));
|
|
tsize = csize;
|
|
len -= csize;
|
|
if (str)
|
|
str += csize;
|
|
|
|
of_property_for_each_string(np, "compatible", p, compat) {
|
|
csize = strlen(compat) + 1;
|
|
tsize += csize;
|
|
if (csize > len)
|
|
continue;
|
|
|
|
csize = snprintf(str, len, "C%s", compat);
|
|
for (c = str; c; ) {
|
|
c = strchr(c, ' ');
|
|
if (c)
|
|
*c++ = '_';
|
|
}
|
|
len -= csize;
|
|
str += csize;
|
|
}
|
|
|
|
return tsize;
|
|
}
|
|
|
|
int of_request_module(const struct device_node *np)
|
|
{
|
|
char *str;
|
|
ssize_t size;
|
|
int ret;
|
|
|
|
if (!np)
|
|
return -ENODEV;
|
|
|
|
size = of_modalias(np, NULL, 0);
|
|
if (size < 0)
|
|
return size;
|
|
|
|
/* Reserve an additional byte for the trailing '\0' */
|
|
size++;
|
|
|
|
str = kmalloc(size, GFP_KERNEL);
|
|
if (!str)
|
|
return -ENOMEM;
|
|
|
|
of_modalias(np, str, size);
|
|
str[size - 1] = '\0';
|
|
ret = request_module(str);
|
|
kfree(str);
|
|
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL_GPL(of_request_module);
|