diff options
author | Steven Rostedt <srostedt@redhat.com> | 2011-01-27 23:14:25 -0500 |
---|---|---|
committer | Steven Rostedt <rostedt@goodmis.org> | 2011-02-07 20:56:19 -0500 |
commit | ec126cac23945de12eb2d103374e1f7ee97c5595 (patch) | |
tree | 7f0c322c26404512b95ff9b024fa8725e1c73807 /kernel/trace | |
parent | 55719274188f13cff9e3bd11fdd4c0e7617cd03d (diff) |
tracing/filter: Check the created pred tree
Since the filter walks a tree to determine if a match is made or not,
if the tree was incorrectly created, it could cause an infinite loop.
Add a check to walk the entire tree before assigning it as a filter
to make sure the tree is correct.
Cc: Tom Zanussi <tzanussi@gmail.com>
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Diffstat (limited to 'kernel/trace')
-rw-r--r-- | kernel/trace/trace_events_filter.c | 72 |
1 files changed, 71 insertions, 1 deletions
diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c index 0a3e0502b507..91c9cdcb040b 100644 --- a/kernel/trace/trace_events_filter.c +++ b/kernel/trace/trace_events_filter.c | |||
@@ -1358,6 +1358,68 @@ static int count_preds(struct filter_parse_state *ps) | |||
1358 | return n_preds; | 1358 | return n_preds; |
1359 | } | 1359 | } |
1360 | 1360 | ||
1361 | /* | ||
1362 | * The tree is walked at filtering of an event. If the tree is not correctly | ||
1363 | * built, it may cause an infinite loop. Check here that the tree does | ||
1364 | * indeed terminate. | ||
1365 | */ | ||
1366 | static int check_pred_tree(struct event_filter *filter, | ||
1367 | struct filter_pred *root) | ||
1368 | { | ||
1369 | struct filter_pred *preds; | ||
1370 | struct filter_pred *pred; | ||
1371 | enum move_type move = MOVE_DOWN; | ||
1372 | int count = 0; | ||
1373 | int done = 0; | ||
1374 | int max; | ||
1375 | |||
1376 | /* | ||
1377 | * The max that we can hit a node is three times. | ||
1378 | * Once going down, once coming up from left, and | ||
1379 | * once coming up from right. This is more than enough | ||
1380 | * since leafs are only hit a single time. | ||
1381 | */ | ||
1382 | max = 3 * filter->n_preds; | ||
1383 | |||
1384 | preds = filter->preds; | ||
1385 | if (!preds) | ||
1386 | return -EINVAL; | ||
1387 | pred = root; | ||
1388 | |||
1389 | do { | ||
1390 | if (WARN_ON(count++ > max)) | ||
1391 | return -EINVAL; | ||
1392 | |||
1393 | switch (move) { | ||
1394 | case MOVE_DOWN: | ||
1395 | if (pred->left != FILTER_PRED_INVALID) { | ||
1396 | pred = &preds[pred->left]; | ||
1397 | continue; | ||
1398 | } | ||
1399 | /* A leaf at the root is just a leaf in the tree */ | ||
1400 | if (pred == root) | ||
1401 | break; | ||
1402 | pred = get_pred_parent(pred, preds, | ||
1403 | pred->parent, &move); | ||
1404 | continue; | ||
1405 | case MOVE_UP_FROM_LEFT: | ||
1406 | pred = &preds[pred->right]; | ||
1407 | move = MOVE_DOWN; | ||
1408 | continue; | ||
1409 | case MOVE_UP_FROM_RIGHT: | ||
1410 | if (pred == root) | ||
1411 | break; | ||
1412 | pred = get_pred_parent(pred, preds, | ||
1413 | pred->parent, &move); | ||
1414 | continue; | ||
1415 | } | ||
1416 | done = 1; | ||
1417 | } while (!done); | ||
1418 | |||
1419 | /* We are fine. */ | ||
1420 | return 0; | ||
1421 | } | ||
1422 | |||
1361 | static int replace_preds(struct ftrace_event_call *call, | 1423 | static int replace_preds(struct ftrace_event_call *call, |
1362 | struct event_filter *filter, | 1424 | struct event_filter *filter, |
1363 | struct filter_parse_state *ps, | 1425 | struct filter_parse_state *ps, |
@@ -1366,6 +1428,7 @@ static int replace_preds(struct ftrace_event_call *call, | |||
1366 | { | 1428 | { |
1367 | char *operand1 = NULL, *operand2 = NULL; | 1429 | char *operand1 = NULL, *operand2 = NULL; |
1368 | struct filter_pred *pred; | 1430 | struct filter_pred *pred; |
1431 | struct filter_pred *root; | ||
1369 | struct postfix_elt *elt; | 1432 | struct postfix_elt *elt; |
1370 | struct pred_stack stack = { }; /* init to NULL */ | 1433 | struct pred_stack stack = { }; /* init to NULL */ |
1371 | int err; | 1434 | int err; |
@@ -1442,7 +1505,7 @@ add_pred: | |||
1442 | if (!pred) | 1505 | if (!pred) |
1443 | return -EINVAL; | 1506 | return -EINVAL; |
1444 | /* This item is where we start from in matching */ | 1507 | /* This item is where we start from in matching */ |
1445 | filter->root = pred; | 1508 | root = pred; |
1446 | /* Make sure the stack is empty */ | 1509 | /* Make sure the stack is empty */ |
1447 | pred = __pop_pred_stack(&stack); | 1510 | pred = __pop_pred_stack(&stack); |
1448 | if (WARN_ON(pred)) { | 1511 | if (WARN_ON(pred)) { |
@@ -1450,6 +1513,13 @@ add_pred: | |||
1450 | filter->root = NULL; | 1513 | filter->root = NULL; |
1451 | goto fail; | 1514 | goto fail; |
1452 | } | 1515 | } |
1516 | err = check_pred_tree(filter, root); | ||
1517 | if (err) | ||
1518 | goto fail; | ||
1519 | |||
1520 | /* We don't set root until we know it works */ | ||
1521 | barrier(); | ||
1522 | filter->root = root; | ||
1453 | } | 1523 | } |
1454 | 1524 | ||
1455 | err = 0; | 1525 | err = 0; |