aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2014-11-04 15:54:55 -0500
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2014-11-04 15:54:55 -0500
commita5501fe4eaa4ee35f8de6efac8d1c4ad16094951 (patch)
treea6938084b9639c2aa54b3f7cc5fd0bebbbf3097d /drivers
parent0df1f2487d2f0d04703f142813d53615d62a1da4 (diff)
parenta87fa1d81a9fb5e9adca9820e16008c40ad09f33 (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.c88
-rw-r--r--drivers/of/selftest.c66
-rw-r--r--drivers/of/testcase-data/tests-phandle.dtsi2
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,
1280EXPORT_SYMBOL_GPL(of_property_read_string); 1280EXPORT_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 */
1300int 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}
1326EXPORT_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,
1363EXPORT_SYMBOL_GPL(of_property_match_string); 1317EXPORT_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 */
1377int of_property_count_strings(struct device_node *np, const char *propname) 1330int 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}
1398EXPORT_SYMBOL_GPL(of_property_count_strings); 1354EXPORT_SYMBOL_GPL(of_property_read_string_helper);
1399 1355
1400void of_print_phandle_args(const char *msg, const struct of_phandle_args *args) 1356void 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
342static void __init of_selftest_property_match_string(void) 342static 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 };