Skip to content

Commit

Permalink
ftrace: Set ops->old_hash on modifying what an ops hooks to
Browse files Browse the repository at this point in the history
The code that checks for trampolines when modifying function hooks
tests against a modified ops "old_hash". But the ops old_hash pointer
is not being updated before the changes are made, making it possible
to not find the right hash to the callback and possibly causing
ftrace to break in accounting and disable itself.

Have the ops set its old_hash before the modifying takes place.

Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
  • Loading branch information
Steven Rostedt (Red Hat) committed Oct 24, 2014
1 parent f114040 commit 8252ecf
Showing 1 changed file with 15 additions and 9 deletions.
24 changes: 15 additions & 9 deletions kernel/trace/ftrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -2293,10 +2293,13 @@ static void ftrace_run_update_code(int command)
FTRACE_WARN_ON(ret);
}

static void ftrace_run_modify_code(struct ftrace_ops *ops, int command)
static void ftrace_run_modify_code(struct ftrace_ops *ops, int command,
struct ftrace_hash *old_hash)
{
ops->flags |= FTRACE_OPS_FL_MODIFYING;
ops->old_hash.filter_hash = old_hash;
ftrace_run_update_code(command);
ops->old_hash.filter_hash = NULL;
ops->flags &= ~FTRACE_OPS_FL_MODIFYING;
}

Expand Down Expand Up @@ -3340,15 +3343,16 @@ static struct ftrace_ops trace_probe_ops __read_mostly =

static int ftrace_probe_registered;

static void __enable_ftrace_function_probe(void)
static void __enable_ftrace_function_probe(struct ftrace_hash *old_hash)
{
int ret;
int i;

if (ftrace_probe_registered) {
/* still need to update the function call sites */
if (ftrace_enabled)
ftrace_run_modify_code(&trace_probe_ops, FTRACE_UPDATE_CALLS);
ftrace_run_modify_code(&trace_probe_ops, FTRACE_UPDATE_CALLS,
old_hash);
return;
}

Expand Down Expand Up @@ -3477,13 +3481,14 @@ register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
} while_for_each_ftrace_rec();

ret = ftrace_hash_move(&trace_probe_ops, 1, orig_hash, hash);

__enable_ftrace_function_probe(old_hash);

if (!ret)
free_ftrace_hash_rcu(old_hash);
else
count = ret;

__enable_ftrace_function_probe();

out_unlock:
mutex_unlock(&ftrace_lock);
out:
Expand Down Expand Up @@ -3764,10 +3769,11 @@ ftrace_match_addr(struct ftrace_hash *hash, unsigned long ip, int remove)
return add_hash_entry(hash, ip);
}

static void ftrace_ops_update_code(struct ftrace_ops *ops)
static void ftrace_ops_update_code(struct ftrace_ops *ops,
struct ftrace_hash *old_hash)
{
if (ops->flags & FTRACE_OPS_FL_ENABLED && ftrace_enabled)
ftrace_run_modify_code(ops, FTRACE_UPDATE_CALLS);
ftrace_run_modify_code(ops, FTRACE_UPDATE_CALLS, old_hash);
}

static int
Expand Down Expand Up @@ -3813,7 +3819,7 @@ ftrace_set_hash(struct ftrace_ops *ops, unsigned char *buf, int len,
old_hash = *orig_hash;
ret = ftrace_hash_move(ops, enable, orig_hash, hash);
if (!ret) {
ftrace_ops_update_code(ops);
ftrace_ops_update_code(ops, old_hash);
free_ftrace_hash_rcu(old_hash);
}
mutex_unlock(&ftrace_lock);
Expand Down Expand Up @@ -4058,7 +4064,7 @@ int ftrace_regex_release(struct inode *inode, struct file *file)
ret = ftrace_hash_move(iter->ops, filter_hash,
orig_hash, iter->hash);
if (!ret) {
ftrace_ops_update_code(iter->ops);
ftrace_ops_update_code(iter->ops, old_hash);
free_ftrace_hash_rcu(old_hash);
}
mutex_unlock(&ftrace_lock);
Expand Down

0 comments on commit 8252ecf

Please sign in to comment.