aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/trace
diff options
context:
space:
mode:
authorSteven Rostedt <srostedt@redhat.com>2011-01-27 23:14:25 -0500
committerSteven Rostedt <rostedt@goodmis.org>2011-02-07 20:56:19 -0500
commitec126cac23945de12eb2d103374e1f7ee97c5595 (patch)
tree7f0c322c26404512b95ff9b024fa8725e1c73807 /kernel/trace
parent55719274188f13cff9e3bd11fdd4c0e7617cd03d (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.c72
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 */
1366static 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
1361static int replace_preds(struct ftrace_event_call *call, 1423static 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;