Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'trace-v4.12-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace

Pull ftrace fixes from Steven Rostedt:
"There's been a few memory issues found with ftrace.

One was simply a memory leak where not all was being freed that should
have been in releasing a file pointer on set_graph_function.

Then Thomas found that the ftrace trampolines were marked for
read/write as well as execute. To shrink the possible attack surface,
he added calls to set them to ro. Which also uncovered some other
issues with freeing module allocated memory that had its permissions
changed.

Kprobes had a similar issue which is fixed and a selftest was added to
trigger that issue again"

* tag 'trace-v4.12-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace:
x86/ftrace: Make sure that ftrace trampolines are not RWX
x86/mm/ftrace: Do not bug in early boot on irqs_disabled in cpu_flush_range()
selftests/ftrace: Add a testcase for many kprobe events
kprobes/x86: Fix to set RWX bits correctly before releasing trampoline
ftrace: Fix memory leak in ftrace_graph_release()

+47 -9
+14 -6
arch/x86/kernel/ftrace.c
··· 689 689 { 690 690 return module_alloc(size); 691 691 } 692 - static inline void tramp_free(void *tramp) 692 + static inline void tramp_free(void *tramp, int size) 693 693 { 694 + int npages = PAGE_ALIGN(size) >> PAGE_SHIFT; 695 + 696 + set_memory_nx((unsigned long)tramp, npages); 697 + set_memory_rw((unsigned long)tramp, npages); 694 698 module_memfree(tramp); 695 699 } 696 700 #else ··· 703 699 { 704 700 return NULL; 705 701 } 706 - static inline void tramp_free(void *tramp) { } 702 + static inline void tramp_free(void *tramp, int size) { } 707 703 #endif 708 704 709 705 /* Defined as markers to the end of the ftrace default trampolines */ ··· 775 771 /* Copy ftrace_caller onto the trampoline memory */ 776 772 ret = probe_kernel_read(trampoline, (void *)start_offset, size); 777 773 if (WARN_ON(ret < 0)) { 778 - tramp_free(trampoline); 774 + tramp_free(trampoline, *tramp_size); 779 775 return 0; 780 776 } 781 777 ··· 801 797 802 798 /* Are we pointing to the reference? */ 803 799 if (WARN_ON(memcmp(op_ptr.op, op_ref, 3) != 0)) { 804 - tramp_free(trampoline); 800 + tramp_free(trampoline, *tramp_size); 805 801 return 0; 806 802 } 807 803 ··· 843 839 unsigned long offset; 844 840 unsigned long ip; 845 841 unsigned int size; 846 - int ret; 842 + int ret, npages; 847 843 848 844 if (ops->trampoline) { 849 845 /* ··· 852 848 */ 853 849 if (!(ops->flags & FTRACE_OPS_FL_ALLOC_TRAMP)) 854 850 return; 851 + npages = PAGE_ALIGN(ops->trampoline_size) >> PAGE_SHIFT; 852 + set_memory_rw(ops->trampoline, npages); 855 853 } else { 856 854 ops->trampoline = create_trampoline(ops, &size); 857 855 if (!ops->trampoline) 858 856 return; 859 857 ops->trampoline_size = size; 858 + npages = PAGE_ALIGN(size) >> PAGE_SHIFT; 860 859 } 861 860 862 861 offset = calc_trampoline_call_offset(ops->flags & FTRACE_OPS_FL_SAVE_REGS); ··· 870 863 /* Do a safe modify in case the trampoline is executing */ 871 864 new = ftrace_call_replace(ip, (unsigned long)func); 872 865 ret = update_ftrace_func(ip, new); 866 + set_memory_ro(ops->trampoline, npages); 873 867 874 868 /* The update should never fail */ 875 869 WARN_ON(ret); ··· 947 939 if (!ops || !(ops->flags & FTRACE_OPS_FL_ALLOC_TRAMP)) 948 940 return; 949 941 950 - tramp_free((void *)ops->trampoline); 942 + tramp_free((void *)ops->trampoline, ops->trampoline_size); 951 943 ops->trampoline = 0; 952 944 } 953 945
+9
arch/x86/kernel/kprobes/core.c
··· 52 52 #include <linux/ftrace.h> 53 53 #include <linux/frame.h> 54 54 #include <linux/kasan.h> 55 + #include <linux/moduleloader.h> 55 56 56 57 #include <asm/text-patching.h> 57 58 #include <asm/cacheflush.h> ··· 416 415 } else { 417 416 p->ainsn.boostable = false; 418 417 } 418 + } 419 + 420 + /* Recover page to RW mode before releasing it */ 421 + void free_insn_page(void *page) 422 + { 423 + set_memory_nx((unsigned long)page & PAGE_MASK, 1); 424 + set_memory_rw((unsigned long)page & PAGE_MASK, 1); 425 + module_memfree(page); 419 426 } 420 427 421 428 static int arch_copy_kprobe(struct kprobe *p)
+1 -1
arch/x86/mm/pageattr.c
··· 186 186 unsigned int i, level; 187 187 unsigned long addr; 188 188 189 - BUG_ON(irqs_disabled()); 189 + BUG_ON(irqs_disabled() && !early_boot_irqs_disabled); 190 190 WARN_ON(PAGE_ALIGN(start) != start); 191 191 192 192 on_each_cpu(__cpa_flush_range, NULL, 1);
+1 -1
kernel/kprobes.c
··· 122 122 return module_alloc(PAGE_SIZE); 123 123 } 124 124 125 - static void free_insn_page(void *page) 125 + void __weak free_insn_page(void *page) 126 126 { 127 127 module_memfree(page); 128 128 }
+1 -1
kernel/trace/ftrace.c
··· 5063 5063 } 5064 5064 5065 5065 out: 5066 - kfree(fgd->new_hash); 5066 + free_ftrace_hash(fgd->new_hash); 5067 5067 kfree(fgd); 5068 5068 5069 5069 return ret;
+21
tools/testing/selftests/ftrace/test.d/kprobe/multiple_kprobes.tc
··· 1 + #!/bin/sh 2 + # description: Register/unregister many kprobe events 3 + 4 + # ftrace fentry skip size depends on the machine architecture. 5 + # Currently HAVE_KPROBES_ON_FTRACE defined on x86 and powerpc 6 + case `uname -m` in 7 + x86_64|i[3456]86) OFFS=5;; 8 + ppc*) OFFS=4;; 9 + *) OFFS=0;; 10 + esac 11 + 12 + echo "Setup up to 256 kprobes" 13 + grep t /proc/kallsyms | cut -f3 -d" " | grep -v .*\\..* | \ 14 + head -n 256 | while read i; do echo p ${i}+${OFFS} ; done > kprobe_events ||: 15 + 16 + echo 1 > events/kprobes/enable 17 + echo 0 > events/kprobes/enable 18 + echo > kprobe_events 19 + echo "Waiting for unoptimizing & freeing" 20 + sleep 5 21 + echo "Done"