From 0d638a07d3a1e98a7598eb2812a6236324e4c55f Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 1 Jun 2017 15:50:55 -0500 Subject: of: Convert to using %pOF instead of full_name Now that we have a custom printf format specifier, convert users of full_name to use %pOF instead. This is preparation to remove storing of the full path string for each node. Signed-off-by: Rob Herring --- drivers/of/device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/of/device.c') diff --git a/drivers/of/device.c b/drivers/of/device.c index 28c38c756f92..f9f31d66f64d 100644 --- a/drivers/of/device.c +++ b/drivers/of/device.c @@ -294,7 +294,7 @@ void of_device_uevent(struct device *dev, struct kobj_uevent_env *env) return; add_uevent_var(env, "OF_NAME=%s", dev->of_node->name); - add_uevent_var(env, "OF_FULLNAME=%s", dev->of_node->full_name); + add_uevent_var(env, "OF_FULLNAME=%pOF", dev->of_node); if (dev->of_node->type && strcmp("", dev->of_node->type) != 0) add_uevent_var(env, "OF_TYPE=%s", dev->of_node->type); -- cgit v1.2.3 From bc575064d688c8933a6ca51429bea9bc63628d3b Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 21 Jul 2017 15:45:32 -0500 Subject: of/device: use of_property_for_each_string to parse compatible strings Instead of directly parsing the compatible property, use the of_property_for_each_string() helper to iterate over each compatible string. This reduces the LoC and makes the functions easier to understand. Signed-off-by: Rob Herring --- drivers/of/device.c | 66 +++++++++++++++++++---------------------------------- 1 file changed, 23 insertions(+), 43 deletions(-) (limited to 'drivers/of/device.c') diff --git a/drivers/of/device.c b/drivers/of/device.c index f9f31d66f64d..9d0895fb53b5 100644 --- a/drivers/of/device.c +++ b/drivers/of/device.c @@ -195,9 +195,10 @@ EXPORT_SYMBOL(of_device_get_match_data); static ssize_t of_device_get_modalias(struct device *dev, char *str, ssize_t len) { - const char *compat; - int cplen, i; - ssize_t tsize, csize, repend; + const char *compat, *start = str; + char *c; + struct property *p; + ssize_t csize; if ((!dev) || (!dev->of_node)) return -ENODEV; @@ -205,42 +206,24 @@ static ssize_t of_device_get_modalias(struct device *dev, char *str, ssize_t len /* Name & Type */ csize = snprintf(str, len, "of:N%sT%s", dev->of_node->name, dev->of_node->type); - - /* Get compatible property if any */ - compat = of_get_property(dev->of_node, "compatible", &cplen); - if (!compat) - return csize; - - /* Find true end (we tolerate multiple \0 at the end */ - for (i = (cplen - 1); i >= 0 && !compat[i]; i--) - cplen--; - if (!cplen) - return csize; - cplen++; - - /* Check space (need cplen+1 chars including final \0) */ - tsize = csize + cplen; - repend = tsize; - - if (csize >= len) /* @ the limit, all is already filled */ - return tsize; - - if (tsize >= len) { /* limit compat list */ - cplen = len - csize - 1; - repend = len; - } - - /* Copy and do char replacement */ - memcpy(&str[csize + 1], compat, cplen); - for (i = csize; i < repend; i++) { - char c = str[i]; - if (c == '\0') - str[i] = 'C'; - else if (c == ' ') - str[i] = '_'; + len -= csize; + str += csize; + + of_property_for_each_string(dev->of_node, "compatible", p, compat) { + if (strlen(compat) + 2 > len) + break; + + csize = snprintf(str, len, "C%s", compat); + for (c = str; c; ) { + c = strchr(c, ' '); + if (c) + *c++ = '_'; + } + len -= csize; + str += csize; } - return repend; + return str - start; } int of_device_request_module(struct device *dev) @@ -288,7 +271,8 @@ void of_device_uevent(struct device *dev, struct kobj_uevent_env *env) { const char *compat; struct alias_prop *app; - int seen = 0, cplen, sl; + struct property *p; + int seen = 0; if ((!dev) || (!dev->of_node)) return; @@ -301,12 +285,8 @@ void of_device_uevent(struct device *dev, struct kobj_uevent_env *env) /* Since the compatible field can contain pretty much anything * it's not really legal to split it out with commas. We split it * up using a number of environment variables instead. */ - compat = of_get_property(dev->of_node, "compatible", &cplen); - while (compat && *compat && cplen > 0) { + of_property_for_each_string(dev->of_node, "compatible", p, compat) { add_uevent_var(env, "OF_COMPATIBLE_%d=%s", seen, compat); - sl = strlen(compat) + 1; - compat += sl; - cplen -= sl; seen++; } add_uevent_var(env, "OF_COMPATIBLE_N=%d", seen); -- cgit v1.2.3 From 08ab58d9de3eb8498ae0585001d0975e46217a39 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Wed, 23 Aug 2017 18:04:04 -0700 Subject: of/device: Prevent buffer overflow in of_device_modalias() As of_device_get_modalias() returns the number of bytes that would have been written to the target string, regardless of how much did fit in the buffer, it's possible that the returned index points beyond the buffer passed to of_device_modalias() - causing memory beyond the buffer to be null terminated. Fixes: 0634c2958927 ("of: Add function for generating a DT modalias with a newline") Cc: Rob Herring Cc: stable@vger.kernel.org Signed-off-by: Bjorn Andersson Signed-off-by: Rob Herring --- drivers/of/device.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/of/device.c') diff --git a/drivers/of/device.c b/drivers/of/device.c index 9d0895fb53b5..c5c06997fdd2 100644 --- a/drivers/of/device.c +++ b/drivers/of/device.c @@ -257,6 +257,8 @@ ssize_t of_device_modalias(struct device *dev, char *str, ssize_t len) ssize_t sl = of_device_get_modalias(dev, str, len - 2); if (sl < 0) return sl; + if (sl > len - 2) + return -ENOMEM; str[sl++] = '\n'; str[sl] = 0; -- cgit v1.2.3 From 8c2a75e5687e0137ddbb35454c7a1a468079f790 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Wed, 23 Aug 2017 18:03:52 -0700 Subject: of/device: Fix of_device_get_modalias() buffer handling of_device_request_module() calls of_device_get_modalias() with "len" 0, to calculate the size of the buffer needed to store the result, but due to integer promotion the ssize_t "len" will be compared as unsigned with strlen(compat) and the loop will generally never break. This results in a call to snprintf() with a negative len, which triggers below warning, followed by a dereference of a invalid pointer: [ 3.060067] WARNING: CPU: 0 PID: 51 at lib/vsprintf.c:2122 vsnprintf+0x348/0x6d8 ... [ 3.060301] [] vsnprintf+0x348/0x6d8 [ 3.060308] [] snprintf+0x48/0x50 [ 3.060316] [] of_device_get_modalias+0x108/0x160 [ 3.060322] [] of_device_request_module+0x20/0x88 ... Further more of_device_get_modalias() is supposed to return the number of bytes needed to store the entire modalias, so the loop needs to continue accumulate the total size even though the buffer is full. Finally the function is not expected to ensure space for the NUL, nor include it in the returned size, so only 1 should be added to the length of "compat" in the loop (to account for the character 'C'). Fixes: bc575064d688 ("of/device: use of_property_for_each_string to parse compatible strings") Cc: Rob Herring Signed-off-by: Bjorn Andersson Signed-off-by: Rob Herring --- drivers/of/device.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'drivers/of/device.c') diff --git a/drivers/of/device.c b/drivers/of/device.c index c5c06997fdd2..11a17582e568 100644 --- a/drivers/of/device.c +++ b/drivers/of/device.c @@ -195,10 +195,11 @@ EXPORT_SYMBOL(of_device_get_match_data); static ssize_t of_device_get_modalias(struct device *dev, char *str, ssize_t len) { - const char *compat, *start = str; + const char *compat; char *c; struct property *p; ssize_t csize; + ssize_t tsize; if ((!dev) || (!dev->of_node)) return -ENODEV; @@ -206,12 +207,16 @@ static ssize_t of_device_get_modalias(struct device *dev, char *str, ssize_t len /* Name & Type */ csize = snprintf(str, len, "of:N%sT%s", dev->of_node->name, dev->of_node->type); + tsize = csize; len -= csize; - str += csize; + if (str) + str += csize; of_property_for_each_string(dev->of_node, "compatible", p, compat) { - if (strlen(compat) + 2 > len) - break; + csize = strlen(compat) + 1; + tsize += csize; + if (csize > len) + continue; csize = snprintf(str, len, "C%s", compat); for (c = str; c; ) { @@ -223,7 +228,7 @@ static ssize_t of_device_get_modalias(struct device *dev, char *str, ssize_t len str += csize; } - return str - start; + return tsize; } int of_device_request_module(struct device *dev) -- cgit v1.2.3 From 6d7e3bf8d12c0ae8b297de428e67301df1b95c5f Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 25 Aug 2017 18:33:13 +0300 Subject: of: Use PLATFORM_DEVID_NONE definition Use dedicated definition instead of plain -1 where it's appropriate. No functional change intended. Signed-off-by: Andy Shevchenko Signed-off-by: Rob Herring --- drivers/of/device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/of/device.c') diff --git a/drivers/of/device.c b/drivers/of/device.c index 11a17582e568..af31e6b9ac74 100644 --- a/drivers/of/device.c +++ b/drivers/of/device.c @@ -58,7 +58,7 @@ int of_device_add(struct platform_device *ofdev) /* name and id have to be set so that the platform bus doesn't get * confused on matching */ ofdev->name = dev_name(&ofdev->dev); - ofdev->id = -1; + ofdev->id = PLATFORM_DEVID_NONE; /* * If this device has not binding numa node in devicetree, that is -- cgit v1.2.3