Commit 8252ecf3 authored by Steven Rostedt (Red Hat)'s avatar Steven Rostedt (Red Hat) Committed by Steven Rostedt

ftrace: Set ops->old_hash on modifying what an ops hooks to

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: default avatarSteven Rostedt <rostedt@goodmis.org>
parent f114040e
...@@ -2293,10 +2293,13 @@ static void ftrace_run_update_code(int command) ...@@ -2293,10 +2293,13 @@ static void ftrace_run_update_code(int command)
FTRACE_WARN_ON(ret); 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->flags |= FTRACE_OPS_FL_MODIFYING;
ops->old_hash.filter_hash = old_hash;
ftrace_run_update_code(command); ftrace_run_update_code(command);
ops->old_hash.filter_hash = NULL;
ops->flags &= ~FTRACE_OPS_FL_MODIFYING; ops->flags &= ~FTRACE_OPS_FL_MODIFYING;
} }
...@@ -3340,7 +3343,7 @@ static struct ftrace_ops trace_probe_ops __read_mostly = ...@@ -3340,7 +3343,7 @@ static struct ftrace_ops trace_probe_ops __read_mostly =
static int ftrace_probe_registered; 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 ret;
int i; int i;
...@@ -3348,7 +3351,8 @@ static void __enable_ftrace_function_probe(void) ...@@ -3348,7 +3351,8 @@ static void __enable_ftrace_function_probe(void)
if (ftrace_probe_registered) { if (ftrace_probe_registered) {
/* still need to update the function call sites */ /* still need to update the function call sites */
if (ftrace_enabled) 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; return;
} }
...@@ -3477,13 +3481,14 @@ register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops, ...@@ -3477,13 +3481,14 @@ register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
} while_for_each_ftrace_rec(); } while_for_each_ftrace_rec();
ret = ftrace_hash_move(&trace_probe_ops, 1, orig_hash, hash); ret = ftrace_hash_move(&trace_probe_ops, 1, orig_hash, hash);
__enable_ftrace_function_probe(old_hash);
if (!ret) if (!ret)
free_ftrace_hash_rcu(old_hash); free_ftrace_hash_rcu(old_hash);
else else
count = ret; count = ret;
__enable_ftrace_function_probe();
out_unlock: out_unlock:
mutex_unlock(&ftrace_lock); mutex_unlock(&ftrace_lock);
out: out:
...@@ -3764,10 +3769,11 @@ ftrace_match_addr(struct ftrace_hash *hash, unsigned long ip, int remove) ...@@ -3764,10 +3769,11 @@ ftrace_match_addr(struct ftrace_hash *hash, unsigned long ip, int remove)
return add_hash_entry(hash, ip); 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) 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 static int
...@@ -3813,7 +3819,7 @@ ftrace_set_hash(struct ftrace_ops *ops, unsigned char *buf, int len, ...@@ -3813,7 +3819,7 @@ ftrace_set_hash(struct ftrace_ops *ops, unsigned char *buf, int len,
old_hash = *orig_hash; old_hash = *orig_hash;
ret = ftrace_hash_move(ops, enable, orig_hash, hash); ret = ftrace_hash_move(ops, enable, orig_hash, hash);
if (!ret) { if (!ret) {
ftrace_ops_update_code(ops); ftrace_ops_update_code(ops, old_hash);
free_ftrace_hash_rcu(old_hash); free_ftrace_hash_rcu(old_hash);
} }
mutex_unlock(&ftrace_lock); mutex_unlock(&ftrace_lock);
...@@ -4058,7 +4064,7 @@ int ftrace_regex_release(struct inode *inode, struct file *file) ...@@ -4058,7 +4064,7 @@ int ftrace_regex_release(struct inode *inode, struct file *file)
ret = ftrace_hash_move(iter->ops, filter_hash, ret = ftrace_hash_move(iter->ops, filter_hash,
orig_hash, iter->hash); orig_hash, iter->hash);
if (!ret) { if (!ret) {
ftrace_ops_update_code(iter->ops); ftrace_ops_update_code(iter->ops, old_hash);
free_ftrace_hash_rcu(old_hash); free_ftrace_hash_rcu(old_hash);
} }
mutex_unlock(&ftrace_lock); mutex_unlock(&ftrace_lock);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment