diff options
author | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2014-11-04 15:54:55 -0500 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2014-11-04 15:54:55 -0500 |
commit | a5501fe4eaa4ee35f8de6efac8d1c4ad16094951 (patch) | |
tree | a6938084b9639c2aa54b3f7cc5fd0bebbbf3097d /drivers | |
parent | 0df1f2487d2f0d04703f142813d53615d62a1da4 (diff) | |
parent | a87fa1d81a9fb5e9adca9820e16008c40ad09f33 (diff) |
Merge branch 'devicetree/merge' of git://git.kernel.org/pub/scm/linux/kernel/git/glikely/linux
Pull Device Tree bug fix from Grant Likely.
* 'devicetree/merge' of git://git.kernel.org/pub/scm/linux/kernel/git/glikely/linux:
of: Fix overflow bug in string property parsing functions
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/of/base.c | 88 | ||||
-rw-r--r-- | drivers/of/selftest.c | 66 | ||||
-rw-r--r-- | drivers/of/testcase-data/tests-phandle.dtsi | 2 |
3 files changed, 84 insertions, 72 deletions
diff --git a/drivers/of/base.c b/drivers/of/base.c index 2305dc0382bc..3823edf2d012 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c | |||
@@ -1280,52 +1280,6 @@ int of_property_read_string(struct device_node *np, const char *propname, | |||
1280 | EXPORT_SYMBOL_GPL(of_property_read_string); | 1280 | EXPORT_SYMBOL_GPL(of_property_read_string); |
1281 | 1281 | ||
1282 | /** | 1282 | /** |
1283 | * of_property_read_string_index - Find and read a string from a multiple | ||
1284 | * strings property. | ||
1285 | * @np: device node from which the property value is to be read. | ||
1286 | * @propname: name of the property to be searched. | ||
1287 | * @index: index of the string in the list of strings | ||
1288 | * @out_string: pointer to null terminated return string, modified only if | ||
1289 | * return value is 0. | ||
1290 | * | ||
1291 | * Search for a property in a device tree node and retrieve a null | ||
1292 | * terminated string value (pointer to data, not a copy) in the list of strings | ||
1293 | * contained in that property. | ||
1294 | * Returns 0 on success, -EINVAL if the property does not exist, -ENODATA if | ||
1295 | * property does not have a value, and -EILSEQ if the string is not | ||
1296 | * null-terminated within the length of the property data. | ||
1297 | * | ||
1298 | * The out_string pointer is modified only if a valid string can be decoded. | ||
1299 | */ | ||
1300 | int of_property_read_string_index(struct device_node *np, const char *propname, | ||
1301 | int index, const char **output) | ||
1302 | { | ||
1303 | struct property *prop = of_find_property(np, propname, NULL); | ||
1304 | int i = 0; | ||
1305 | size_t l = 0, total = 0; | ||
1306 | const char *p; | ||
1307 | |||
1308 | if (!prop) | ||
1309 | return -EINVAL; | ||
1310 | if (!prop->value) | ||
1311 | return -ENODATA; | ||
1312 | if (strnlen(prop->value, prop->length) >= prop->length) | ||
1313 | return -EILSEQ; | ||
1314 | |||
1315 | p = prop->value; | ||
1316 | |||
1317 | for (i = 0; total < prop->length; total += l, p += l) { | ||
1318 | l = strlen(p) + 1; | ||
1319 | if (i++ == index) { | ||
1320 | *output = p; | ||
1321 | return 0; | ||
1322 | } | ||
1323 | } | ||
1324 | return -ENODATA; | ||
1325 | } | ||
1326 | EXPORT_SYMBOL_GPL(of_property_read_string_index); | ||
1327 | |||
1328 | /** | ||
1329 | * of_property_match_string() - Find string in a list and return index | 1283 | * of_property_match_string() - Find string in a list and return index |
1330 | * @np: pointer to node containing string list property | 1284 | * @np: pointer to node containing string list property |
1331 | * @propname: string list property name | 1285 | * @propname: string list property name |
@@ -1351,7 +1305,7 @@ int of_property_match_string(struct device_node *np, const char *propname, | |||
1351 | end = p + prop->length; | 1305 | end = p + prop->length; |
1352 | 1306 | ||
1353 | for (i = 0; p < end; i++, p += l) { | 1307 | for (i = 0; p < end; i++, p += l) { |
1354 | l = strlen(p) + 1; | 1308 | l = strnlen(p, end - p) + 1; |
1355 | if (p + l > end) | 1309 | if (p + l > end) |
1356 | return -EILSEQ; | 1310 | return -EILSEQ; |
1357 | pr_debug("comparing %s with %s\n", string, p); | 1311 | pr_debug("comparing %s with %s\n", string, p); |
@@ -1363,39 +1317,41 @@ int of_property_match_string(struct device_node *np, const char *propname, | |||
1363 | EXPORT_SYMBOL_GPL(of_property_match_string); | 1317 | EXPORT_SYMBOL_GPL(of_property_match_string); |
1364 | 1318 | ||
1365 | /** | 1319 | /** |
1366 | * of_property_count_strings - Find and return the number of strings from a | 1320 | * of_property_read_string_util() - Utility helper for parsing string properties |
1367 | * multiple strings property. | ||
1368 | * @np: device node from which the property value is to be read. | 1321 | * @np: device node from which the property value is to be read. |
1369 | * @propname: name of the property to be searched. | 1322 | * @propname: name of the property to be searched. |
1323 | * @out_strs: output array of string pointers. | ||
1324 | * @sz: number of array elements to read. | ||
1325 | * @skip: Number of strings to skip over at beginning of list. | ||
1370 | * | 1326 | * |
1371 | * Search for a property in a device tree node and retrieve the number of null | 1327 | * Don't call this function directly. It is a utility helper for the |
1372 | * terminated string contain in it. Returns the number of strings on | 1328 | * of_property_read_string*() family of functions. |
1373 | * success, -EINVAL if the property does not exist, -ENODATA if property | ||
1374 | * does not have a value, and -EILSEQ if the string is not null-terminated | ||
1375 | * within the length of the property data. | ||
1376 | */ | 1329 | */ |
1377 | int of_property_count_strings(struct device_node *np, const char *propname) | 1330 | int of_property_read_string_helper(struct device_node *np, const char *propname, |
1331 | const char **out_strs, size_t sz, int skip) | ||
1378 | { | 1332 | { |
1379 | struct property *prop = of_find_property(np, propname, NULL); | 1333 | struct property *prop = of_find_property(np, propname, NULL); |
1380 | int i = 0; | 1334 | int l = 0, i = 0; |
1381 | size_t l = 0, total = 0; | 1335 | const char *p, *end; |
1382 | const char *p; | ||
1383 | 1336 | ||
1384 | if (!prop) | 1337 | if (!prop) |
1385 | return -EINVAL; | 1338 | return -EINVAL; |
1386 | if (!prop->value) | 1339 | if (!prop->value) |
1387 | return -ENODATA; | 1340 | return -ENODATA; |
1388 | if (strnlen(prop->value, prop->length) >= prop->length) | ||
1389 | return -EILSEQ; | ||
1390 | |||
1391 | p = prop->value; | 1341 | p = prop->value; |
1342 | end = p + prop->length; | ||
1392 | 1343 | ||
1393 | for (i = 0; total < prop->length; total += l, p += l, i++) | 1344 | for (i = 0; p < end && (!out_strs || i < skip + sz); i++, p += l) { |
1394 | l = strlen(p) + 1; | 1345 | l = strnlen(p, end - p) + 1; |
1395 | 1346 | if (p + l > end) | |
1396 | return i; | 1347 | return -EILSEQ; |
1348 | if (out_strs && i >= skip) | ||
1349 | *out_strs++ = p; | ||
1350 | } | ||
1351 | i -= skip; | ||
1352 | return i <= 0 ? -ENODATA : i; | ||
1397 | } | 1353 | } |
1398 | EXPORT_SYMBOL_GPL(of_property_count_strings); | 1354 | EXPORT_SYMBOL_GPL(of_property_read_string_helper); |
1399 | 1355 | ||
1400 | void of_print_phandle_args(const char *msg, const struct of_phandle_args *args) | 1356 | void of_print_phandle_args(const char *msg, const struct of_phandle_args *args) |
1401 | { | 1357 | { |
diff --git a/drivers/of/selftest.c b/drivers/of/selftest.c index 78001270a598..11b873c54a77 100644 --- a/drivers/of/selftest.c +++ b/drivers/of/selftest.c | |||
@@ -339,8 +339,9 @@ static void __init of_selftest_parse_phandle_with_args(void) | |||
339 | selftest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc); | 339 | selftest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc); |
340 | } | 340 | } |
341 | 341 | ||
342 | static void __init of_selftest_property_match_string(void) | 342 | static void __init of_selftest_property_string(void) |
343 | { | 343 | { |
344 | const char *strings[4]; | ||
344 | struct device_node *np; | 345 | struct device_node *np; |
345 | int rc; | 346 | int rc; |
346 | 347 | ||
@@ -357,13 +358,66 @@ static void __init of_selftest_property_match_string(void) | |||
357 | rc = of_property_match_string(np, "phandle-list-names", "third"); | 358 | rc = of_property_match_string(np, "phandle-list-names", "third"); |
358 | selftest(rc == 2, "third expected:0 got:%i\n", rc); | 359 | selftest(rc == 2, "third expected:0 got:%i\n", rc); |
359 | rc = of_property_match_string(np, "phandle-list-names", "fourth"); | 360 | rc = of_property_match_string(np, "phandle-list-names", "fourth"); |
360 | selftest(rc == -ENODATA, "unmatched string; rc=%i", rc); | 361 | selftest(rc == -ENODATA, "unmatched string; rc=%i\n", rc); |
361 | rc = of_property_match_string(np, "missing-property", "blah"); | 362 | rc = of_property_match_string(np, "missing-property", "blah"); |
362 | selftest(rc == -EINVAL, "missing property; rc=%i", rc); | 363 | selftest(rc == -EINVAL, "missing property; rc=%i\n", rc); |
363 | rc = of_property_match_string(np, "empty-property", "blah"); | 364 | rc = of_property_match_string(np, "empty-property", "blah"); |
364 | selftest(rc == -ENODATA, "empty property; rc=%i", rc); | 365 | selftest(rc == -ENODATA, "empty property; rc=%i\n", rc); |
365 | rc = of_property_match_string(np, "unterminated-string", "blah"); | 366 | rc = of_property_match_string(np, "unterminated-string", "blah"); |
366 | selftest(rc == -EILSEQ, "unterminated string; rc=%i", rc); | 367 | selftest(rc == -EILSEQ, "unterminated string; rc=%i\n", rc); |
368 | |||
369 | /* of_property_count_strings() tests */ | ||
370 | rc = of_property_count_strings(np, "string-property"); | ||
371 | selftest(rc == 1, "Incorrect string count; rc=%i\n", rc); | ||
372 | rc = of_property_count_strings(np, "phandle-list-names"); | ||
373 | selftest(rc == 3, "Incorrect string count; rc=%i\n", rc); | ||
374 | rc = of_property_count_strings(np, "unterminated-string"); | ||
375 | selftest(rc == -EILSEQ, "unterminated string; rc=%i\n", rc); | ||
376 | rc = of_property_count_strings(np, "unterminated-string-list"); | ||
377 | selftest(rc == -EILSEQ, "unterminated string array; rc=%i\n", rc); | ||
378 | |||
379 | /* of_property_read_string_index() tests */ | ||
380 | rc = of_property_read_string_index(np, "string-property", 0, strings); | ||
381 | selftest(rc == 0 && !strcmp(strings[0], "foobar"), "of_property_read_string_index() failure; rc=%i\n", rc); | ||
382 | strings[0] = NULL; | ||
383 | rc = of_property_read_string_index(np, "string-property", 1, strings); | ||
384 | selftest(rc == -ENODATA && strings[0] == NULL, "of_property_read_string_index() failure; rc=%i\n", rc); | ||
385 | rc = of_property_read_string_index(np, "phandle-list-names", 0, strings); | ||
386 | selftest(rc == 0 && !strcmp(strings[0], "first"), "of_property_read_string_index() failure; rc=%i\n", rc); | ||
387 | rc = of_property_read_string_index(np, "phandle-list-names", 1, strings); | ||
388 | selftest(rc == 0 && !strcmp(strings[0], "second"), "of_property_read_string_index() failure; rc=%i\n", rc); | ||
389 | rc = of_property_read_string_index(np, "phandle-list-names", 2, strings); | ||
390 | selftest(rc == 0 && !strcmp(strings[0], "third"), "of_property_read_string_index() failure; rc=%i\n", rc); | ||
391 | strings[0] = NULL; | ||
392 | rc = of_property_read_string_index(np, "phandle-list-names", 3, strings); | ||
393 | selftest(rc == -ENODATA && strings[0] == NULL, "of_property_read_string_index() failure; rc=%i\n", rc); | ||
394 | strings[0] = NULL; | ||
395 | rc = of_property_read_string_index(np, "unterminated-string", 0, strings); | ||
396 | selftest(rc == -EILSEQ && strings[0] == NULL, "of_property_read_string_index() failure; rc=%i\n", rc); | ||
397 | rc = of_property_read_string_index(np, "unterminated-string-list", 0, strings); | ||
398 | selftest(rc == 0 && !strcmp(strings[0], "first"), "of_property_read_string_index() failure; rc=%i\n", rc); | ||
399 | strings[0] = NULL; | ||
400 | rc = of_property_read_string_index(np, "unterminated-string-list", 2, strings); /* should fail */ | ||
401 | selftest(rc == -EILSEQ && strings[0] == NULL, "of_property_read_string_index() failure; rc=%i\n", rc); | ||
402 | strings[1] = NULL; | ||
403 | |||
404 | /* of_property_read_string_array() tests */ | ||
405 | rc = of_property_read_string_array(np, "string-property", strings, 4); | ||
406 | selftest(rc == 1, "Incorrect string count; rc=%i\n", rc); | ||
407 | rc = of_property_read_string_array(np, "phandle-list-names", strings, 4); | ||
408 | selftest(rc == 3, "Incorrect string count; rc=%i\n", rc); | ||
409 | rc = of_property_read_string_array(np, "unterminated-string", strings, 4); | ||
410 | selftest(rc == -EILSEQ, "unterminated string; rc=%i\n", rc); | ||
411 | /* -- An incorrectly formed string should cause a failure */ | ||
412 | rc = of_property_read_string_array(np, "unterminated-string-list", strings, 4); | ||
413 | selftest(rc == -EILSEQ, "unterminated string array; rc=%i\n", rc); | ||
414 | /* -- parsing the correctly formed strings should still work: */ | ||
415 | strings[2] = NULL; | ||
416 | rc = of_property_read_string_array(np, "unterminated-string-list", strings, 2); | ||
417 | selftest(rc == 2 && strings[2] == NULL, "of_property_read_string_array() failure; rc=%i\n", rc); | ||
418 | strings[1] = NULL; | ||
419 | rc = of_property_read_string_array(np, "phandle-list-names", strings, 1); | ||
420 | selftest(rc == 1 && strings[1] == NULL, "Overwrote end of string array; rc=%i, str='%s'\n", rc, strings[1]); | ||
367 | } | 421 | } |
368 | 422 | ||
369 | #define propcmp(p1, p2) (((p1)->length == (p2)->length) && \ | 423 | #define propcmp(p1, p2) (((p1)->length == (p2)->length) && \ |
@@ -881,7 +935,7 @@ static int __init of_selftest(void) | |||
881 | of_selftest_find_node_by_name(); | 935 | of_selftest_find_node_by_name(); |
882 | of_selftest_dynamic(); | 936 | of_selftest_dynamic(); |
883 | of_selftest_parse_phandle_with_args(); | 937 | of_selftest_parse_phandle_with_args(); |
884 | of_selftest_property_match_string(); | 938 | of_selftest_property_string(); |
885 | of_selftest_property_copy(); | 939 | of_selftest_property_copy(); |
886 | of_selftest_changeset(); | 940 | of_selftest_changeset(); |
887 | of_selftest_parse_interrupts(); | 941 | of_selftest_parse_interrupts(); |
diff --git a/drivers/of/testcase-data/tests-phandle.dtsi b/drivers/of/testcase-data/tests-phandle.dtsi index ce0fe083d406..5b1527e8a7fb 100644 --- a/drivers/of/testcase-data/tests-phandle.dtsi +++ b/drivers/of/testcase-data/tests-phandle.dtsi | |||
@@ -39,7 +39,9 @@ | |||
39 | phandle-list-bad-args = <&provider2 1 0>, | 39 | phandle-list-bad-args = <&provider2 1 0>, |
40 | <&provider3 0>; | 40 | <&provider3 0>; |
41 | empty-property; | 41 | empty-property; |
42 | string-property = "foobar"; | ||
42 | unterminated-string = [40 41 42 43]; | 43 | unterminated-string = [40 41 42 43]; |
44 | unterminated-string-list = "first", "second", [40 41 42 43]; | ||
43 | }; | 45 | }; |
44 | }; | 46 | }; |
45 | }; | 47 | }; |