diff options
| author | Steven Rostedt <srostedt@redhat.com> | 2010-09-09 10:00:28 -0400 |
|---|---|---|
| committer | Steven Rostedt <rostedt@goodmis.org> | 2010-09-14 11:42:30 -0400 |
| commit | 4aeb69672d011fac5c8df671f3ca89f7987c104e (patch) | |
| tree | d2a96af23b9d6ac742725bb17aafe3d4b377cb6a /kernel | |
| parent | 2bccfffd1538f3523847583213567e2f7ce00926 (diff) | |
tracing: Replace typecasted void pointer in set_ftrace_filter code
The set_ftrace_filter uses seq_file and reads from two lists. The
pointer returned by t_next() can either be of type struct dyn_ftrace
or struct ftrace_func_probe. If there is a bug (there was one)
the wrong pointer may be used and the reference can cause an oops.
This patch makes t_next() and friends only return the iterator structure
which now has a pointer of type struct dyn_ftrace and struct
ftrace_func_probe. The t_show() can now test if the pointer is NULL or
not and if the pointer exists, it is guaranteed to be of the correct type.
Now if there's a bug, only wrong data will be shown but not an oops.
Cc: Chris Wright <chrisw@sous-sol.org>
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/trace/ftrace.c | 67 |
1 files changed, 46 insertions, 21 deletions
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 585ea27025b1..c8db0dbb984e 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c | |||
| @@ -1368,25 +1368,29 @@ enum { | |||
| 1368 | #define FTRACE_BUFF_MAX (KSYM_SYMBOL_LEN+4) /* room for wildcards */ | 1368 | #define FTRACE_BUFF_MAX (KSYM_SYMBOL_LEN+4) /* room for wildcards */ |
| 1369 | 1369 | ||
| 1370 | struct ftrace_iterator { | 1370 | struct ftrace_iterator { |
| 1371 | loff_t func_pos; | 1371 | loff_t func_pos; |
| 1372 | struct ftrace_page *pg; | 1372 | struct ftrace_page *pg; |
| 1373 | int hidx; | 1373 | struct dyn_ftrace *func; |
| 1374 | int idx; | 1374 | struct ftrace_func_probe *probe; |
| 1375 | unsigned flags; | 1375 | struct trace_parser parser; |
| 1376 | struct trace_parser parser; | 1376 | int hidx; |
| 1377 | int idx; | ||
| 1378 | unsigned flags; | ||
| 1377 | }; | 1379 | }; |
| 1378 | 1380 | ||
| 1379 | static void * | 1381 | static void * |
| 1380 | t_hash_next(struct seq_file *m, void *v, loff_t *pos) | 1382 | t_hash_next(struct seq_file *m, loff_t *pos) |
| 1381 | { | 1383 | { |
| 1382 | struct ftrace_iterator *iter = m->private; | 1384 | struct ftrace_iterator *iter = m->private; |
| 1383 | struct hlist_node *hnd = v; | 1385 | struct hlist_node *hnd = NULL; |
| 1384 | struct hlist_head *hhd; | 1386 | struct hlist_head *hhd; |
| 1385 | 1387 | ||
| 1386 | WARN_ON(!(iter->flags & FTRACE_ITER_HASH)); | 1388 | WARN_ON(!(iter->flags & FTRACE_ITER_HASH)); |
| 1387 | 1389 | ||
| 1388 | (*pos)++; | 1390 | (*pos)++; |
| 1389 | 1391 | ||
| 1392 | if (iter->probe) | ||
| 1393 | hnd = &iter->probe->node; | ||
| 1390 | retry: | 1394 | retry: |
| 1391 | if (iter->hidx >= FTRACE_FUNC_HASHSIZE) | 1395 | if (iter->hidx >= FTRACE_FUNC_HASHSIZE) |
| 1392 | return NULL; | 1396 | return NULL; |
| @@ -1409,7 +1413,12 @@ t_hash_next(struct seq_file *m, void *v, loff_t *pos) | |||
| 1409 | } | 1413 | } |
| 1410 | } | 1414 | } |
| 1411 | 1415 | ||
| 1412 | return hnd; | 1416 | if (WARN_ON_ONCE(!hnd)) |
| 1417 | return NULL; | ||
| 1418 | |||
| 1419 | iter->probe = hlist_entry(hnd, struct ftrace_func_probe, node); | ||
| 1420 | |||
| 1421 | return iter; | ||
| 1413 | } | 1422 | } |
| 1414 | 1423 | ||
| 1415 | static void *t_hash_start(struct seq_file *m, loff_t *pos) | 1424 | static void *t_hash_start(struct seq_file *m, loff_t *pos) |
| @@ -1428,19 +1437,24 @@ static void *t_hash_start(struct seq_file *m, loff_t *pos) | |||
| 1428 | 1437 | ||
| 1429 | iter->hidx = 0; | 1438 | iter->hidx = 0; |
| 1430 | for (l = 0; l <= (*pos - iter->func_pos); ) { | 1439 | for (l = 0; l <= (*pos - iter->func_pos); ) { |
| 1431 | p = t_hash_next(m, p, &l); | 1440 | p = t_hash_next(m, &l); |
| 1432 | if (!p) | 1441 | if (!p) |
| 1433 | break; | 1442 | break; |
| 1434 | } | 1443 | } |
| 1435 | return p; | 1444 | if (!p) |
| 1445 | return NULL; | ||
| 1446 | |||
| 1447 | return iter; | ||
| 1436 | } | 1448 | } |
| 1437 | 1449 | ||
| 1438 | static int t_hash_show(struct seq_file *m, void *v) | 1450 | static int |
| 1451 | t_hash_show(struct seq_file *m, struct ftrace_iterator *iter) | ||
| 1439 | { | 1452 | { |
| 1440 | struct ftrace_func_probe *rec; | 1453 | struct ftrace_func_probe *rec; |
| 1441 | struct hlist_node *hnd = v; | ||
| 1442 | 1454 | ||
| 1443 | rec = hlist_entry(hnd, struct ftrace_func_probe, node); | 1455 | rec = iter->probe; |
| 1456 | if (WARN_ON_ONCE(!rec)) | ||
| 1457 | return -EIO; | ||
| 1444 | 1458 | ||
| 1445 | if (rec->ops->print) | 1459 | if (rec->ops->print) |
| 1446 | return rec->ops->print(m, rec->ip, rec->ops, rec->data); | 1460 | return rec->ops->print(m, rec->ip, rec->ops, rec->data); |
| @@ -1461,7 +1475,7 @@ t_next(struct seq_file *m, void *v, loff_t *pos) | |||
| 1461 | struct dyn_ftrace *rec = NULL; | 1475 | struct dyn_ftrace *rec = NULL; |
| 1462 | 1476 | ||
| 1463 | if (iter->flags & FTRACE_ITER_HASH) | 1477 | if (iter->flags & FTRACE_ITER_HASH) |
| 1464 | return t_hash_next(m, v, pos); | 1478 | return t_hash_next(m, pos); |
| 1465 | 1479 | ||
| 1466 | (*pos)++; | 1480 | (*pos)++; |
| 1467 | 1481 | ||
| @@ -1495,7 +1509,12 @@ t_next(struct seq_file *m, void *v, loff_t *pos) | |||
| 1495 | } | 1509 | } |
| 1496 | } | 1510 | } |
| 1497 | 1511 | ||
| 1498 | return rec; | 1512 | if (!rec) |
| 1513 | return NULL; | ||
| 1514 | |||
| 1515 | iter->func = rec; | ||
| 1516 | |||
| 1517 | return iter; | ||
| 1499 | } | 1518 | } |
| 1500 | 1519 | ||
| 1501 | static void *t_start(struct seq_file *m, loff_t *pos) | 1520 | static void *t_start(struct seq_file *m, loff_t *pos) |
| @@ -1530,10 +1549,14 @@ static void *t_start(struct seq_file *m, loff_t *pos) | |||
| 1530 | break; | 1549 | break; |
| 1531 | } | 1550 | } |
| 1532 | 1551 | ||
| 1533 | if (!p && iter->flags & FTRACE_ITER_FILTER) | 1552 | if (!p) { |
| 1534 | return t_hash_start(m, pos); | 1553 | if (iter->flags & FTRACE_ITER_FILTER) |
| 1554 | return t_hash_start(m, pos); | ||
| 1535 | 1555 | ||
| 1536 | return p; | 1556 | return NULL; |
| 1557 | } | ||
| 1558 | |||
| 1559 | return iter; | ||
| 1537 | } | 1560 | } |
| 1538 | 1561 | ||
| 1539 | static void t_stop(struct seq_file *m, void *p) | 1562 | static void t_stop(struct seq_file *m, void *p) |
| @@ -1544,16 +1567,18 @@ static void t_stop(struct seq_file *m, void *p) | |||
| 1544 | static int t_show(struct seq_file *m, void *v) | 1567 | static int t_show(struct seq_file *m, void *v) |
| 1545 | { | 1568 | { |
| 1546 | struct ftrace_iterator *iter = m->private; | 1569 | struct ftrace_iterator *iter = m->private; |
| 1547 | struct dyn_ftrace *rec = v; | 1570 | struct dyn_ftrace *rec; |
| 1548 | 1571 | ||
| 1549 | if (iter->flags & FTRACE_ITER_HASH) | 1572 | if (iter->flags & FTRACE_ITER_HASH) |
| 1550 | return t_hash_show(m, v); | 1573 | return t_hash_show(m, iter); |
| 1551 | 1574 | ||
| 1552 | if (iter->flags & FTRACE_ITER_PRINTALL) { | 1575 | if (iter->flags & FTRACE_ITER_PRINTALL) { |
| 1553 | seq_printf(m, "#### all functions enabled ####\n"); | 1576 | seq_printf(m, "#### all functions enabled ####\n"); |
| 1554 | return 0; | 1577 | return 0; |
| 1555 | } | 1578 | } |
| 1556 | 1579 | ||
| 1580 | rec = iter->func; | ||
| 1581 | |||
| 1557 | if (!rec) | 1582 | if (!rec) |
| 1558 | return 0; | 1583 | return 0; |
| 1559 | 1584 | ||
