diff options
Diffstat (limited to 'arch/x86/kernel/ftrace.c')
| -rw-r--r-- | arch/x86/kernel/ftrace.c | 22 | 
1 files changed, 14 insertions, 8 deletions
diff --git a/arch/x86/kernel/ftrace.c b/arch/x86/kernel/ftrace.c index ef49517f6bb2..0caf8122d680 100644 --- a/arch/x86/kernel/ftrace.c +++ b/arch/x86/kernel/ftrace.c @@ -678,12 +678,8 @@ static inline void *alloc_tramp(unsigned long size)  {  	return module_alloc(size);  } -static inline void tramp_free(void *tramp, int size) +static inline void tramp_free(void *tramp)  { -	int npages = PAGE_ALIGN(size) >> PAGE_SHIFT; - -	set_memory_nx((unsigned long)tramp, npages); -	set_memory_rw((unsigned long)tramp, npages);  	module_memfree(tramp);  }  #else @@ -692,7 +688,7 @@ static inline void *alloc_tramp(unsigned long size)  {  	return NULL;  } -static inline void tramp_free(void *tramp, int size) { } +static inline void tramp_free(void *tramp) { }  #endif  /* Defined as markers to the end of the ftrace default trampolines */ @@ -730,6 +726,7 @@ create_trampoline(struct ftrace_ops *ops, unsigned int *tramp_size)  	unsigned long end_offset;  	unsigned long op_offset;  	unsigned long offset; +	unsigned long npages;  	unsigned long size;  	unsigned long retq;  	unsigned long *ptr; @@ -762,6 +759,7 @@ create_trampoline(struct ftrace_ops *ops, unsigned int *tramp_size)  		return 0;  	*tramp_size = size + RET_SIZE + sizeof(void *); +	npages = DIV_ROUND_UP(*tramp_size, PAGE_SIZE);  	/* Copy ftrace_caller onto the trampoline memory */  	ret = probe_kernel_read(trampoline, (void *)start_offset, size); @@ -806,9 +804,17 @@ create_trampoline(struct ftrace_ops *ops, unsigned int *tramp_size)  	/* ALLOC_TRAMP flags lets us know we created it */  	ops->flags |= FTRACE_OPS_FL_ALLOC_TRAMP; +	set_vm_flush_reset_perms(trampoline); + +	/* +	 * Module allocation needs to be completed by making the page +	 * executable. The page is still writable, which is a security hazard, +	 * but anyhow ftrace breaks W^X completely. +	 */ +	set_memory_x((unsigned long)trampoline, npages);  	return (unsigned long)trampoline;  fail: -	tramp_free(trampoline, *tramp_size); +	tramp_free(trampoline);  	return 0;  } @@ -939,7 +945,7 @@ void arch_ftrace_trampoline_free(struct ftrace_ops *ops)  	if (!ops || !(ops->flags & FTRACE_OPS_FL_ALLOC_TRAMP))  		return; -	tramp_free((void *)ops->trampoline, ops->trampoline_size); +	tramp_free((void *)ops->trampoline);  	ops->trampoline = 0;  }  | 
