Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 593eb8a2 authored by Steven Rostedt's avatar Steven Rostedt Committed by Ingo Molnar
Browse files

ftrace: return error on failed modified text.



Have the ftrace_modify_code return error values:

  -EFAULT on error of reading the address

  -EINVAL if what is read does not match what it expected

  -EPERM  if the write fails to update after a successful match.

Signed-off-by: default avatarSteven Rostedt <srostedt@redhat.com>
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
parent 34698bcb
Loading
Loading
Loading
Loading
+7 −7
Original line number Diff line number Diff line
@@ -62,7 +62,6 @@ ftrace_modify_code(unsigned long ip, unsigned char *old_code,
		   unsigned char *new_code)
{
	unsigned char replaced[MCOUNT_INSN_SIZE];
	int ret;

	/*
	 * Note: Due to modules and __init, code can
@@ -72,15 +71,16 @@ ftrace_modify_code(unsigned long ip, unsigned char *old_code,
	 * No real locking needed, this code is run through
	 * kstop_machine, or before SMP starts.
	 */
	if (__copy_from_user_inatomic(replaced, (char __user *)ip, MCOUNT_INSN_SIZE))
		return 1;
	if (__copy_from_user_inatomic(replaced, (char __user *)ip,
				      MCOUNT_INSN_SIZE))
		return -EFAULT;

	if (memcmp(replaced, old_code, MCOUNT_INSN_SIZE) != 0)
		return 2;
		return -EINVAL;

	ret = __copy_to_user_inatomic((char __user *)ip, new_code,
					MCOUNT_INSN_SIZE);
	WARN_ON_ONCE(ret);
	if (__copy_to_user_inatomic((char __user *)ip, new_code,
				    MCOUNT_INSN_SIZE))
		return -EPERM;

	sync_core();

+22 −2
Original line number Diff line number Diff line
@@ -72,13 +72,33 @@ extern unsigned char *ftrace_nop_replace(void);
extern unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr);
extern int ftrace_dyn_arch_init(void *data);
extern int ftrace_mcount_set(unsigned long *data);
extern int ftrace_modify_code(unsigned long ip, unsigned char *old_code,
			      unsigned char *new_code);
extern int ftrace_update_ftrace_func(ftrace_func_t func);
extern void ftrace_caller(void);
extern void ftrace_call(void);
extern void mcount_call(void);

/**
 * ftrace_modify_code - modify code segment
 * @ip: the address of the code segment
 * @old_code: the contents of what is expected to be there
 * @new_code: the code to patch in
 *
 * This is a very sensitive operation and great care needs
 * to be taken by the arch.  The operation should carefully
 * read the location, check to see if what is read is indeed
 * what we expect it to be, and then on success of the compare,
 * it should write to the location.
 *
 * Return must be:
 *  0 on success
 *  -EFAULT on error reading the location
 *  -EINVAL on a failed compare of the contents
 *  -EPERM  on error writing to the location
 * Any other value will be considered a failure.
 */
extern int ftrace_modify_code(unsigned long ip, unsigned char *old_code,
			      unsigned char *new_code);

extern int skip_trace(unsigned long ip);

extern void ftrace_release(void *start, unsigned long size);
+15 −6
Original line number Diff line number Diff line
@@ -596,22 +596,22 @@ ftrace_code_disable(struct dyn_ftrace *rec)
{
	unsigned long ip;
	unsigned char *nop, *call;
	int failed;
	int ret;

	ip = rec->ip;

	nop = ftrace_nop_replace();
	call = ftrace_call_replace(ip, mcount_addr);

	failed = ftrace_modify_code(ip, call, nop);
	if (failed) {
		switch (failed) {
		case 1:
	ret = ftrace_modify_code(ip, call, nop);
	if (ret) {
		switch (ret) {
		case -EFAULT:
			WARN_ON_ONCE(1);
			pr_info("ftrace faulted on modifying ");
			print_ip_sym(ip);
			break;
		case 2:
		case -EINVAL:
			WARN_ON_ONCE(1);
			pr_info("ftrace failed to modify ");
			print_ip_sym(ip);
@@ -620,6 +620,15 @@ ftrace_code_disable(struct dyn_ftrace *rec)
			print_ip_ins(" replace: ", nop);
			printk(KERN_CONT "\n");
			break;
		case -EPERM:
			WARN_ON_ONCE(1);
			pr_info("ftrace faulted on writing ");
			print_ip_sym(ip);
			break;
		default:
			WARN_ON_ONCE(1);
			pr_info("ftrace faulted on unknown error ");
			print_ip_sym(ip);
		}

		rec->flags |= FTRACE_FL_FAILED;