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.

tracing/fprobe: Reject registration of a registered fprobe before init

Reject registration of a registered fprobe which is on the fprobe
hash table before initializing fprobe.
The add_fprobe_hash() checks this re-register fprobe, but since
fprobe_init() clears hlist_array field, it is too late to check it.
It has to check the re-registration before touncing fprobe.

Link: https://lore.kernel.org/all/177669364845.132053.18375367916162315835.stgit@mhiramat.tok.corp.google.com/

Fixes: 4346ba160409 ("fprobe: Rewrite fprobe on function-graph tracer")
Cc: stable@vger.kernel.org
Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>

+10 -11
+10 -11
kernel/trace/fprobe.c
··· 4 4 */ 5 5 #define pr_fmt(fmt) "fprobe: " fmt 6 6 7 + #include <linux/cleanup.h> 7 8 #include <linux/err.h> 8 9 #include <linux/fprobe.h> 9 10 #include <linux/kallsyms.h> ··· 108 107 } 109 108 110 109 /* Check existence of the fprobe */ 111 - static bool is_fprobe_still_exist(struct fprobe *fp) 110 + static bool fprobe_registered(struct fprobe *fp) 112 111 { 113 112 struct hlist_head *head; 114 113 struct fprobe_hlist *fph; ··· 121 120 } 122 121 return false; 123 122 } 124 - NOKPROBE_SYMBOL(is_fprobe_still_exist); 123 + NOKPROBE_SYMBOL(fprobe_registered); 125 124 126 125 static int add_fprobe_hash(struct fprobe *fp) 127 126 { ··· 132 131 133 132 if (WARN_ON_ONCE(!fph)) 134 133 return -EINVAL; 135 - 136 - if (is_fprobe_still_exist(fp)) 137 - return -EEXIST; 138 134 139 135 head = &fprobe_table[hash_ptr(fp, FPROBE_HASH_BITS)]; 140 136 hlist_add_head_rcu(&fp->hlist_array->hlist, head); ··· 147 149 if (WARN_ON_ONCE(!fph)) 148 150 return -EINVAL; 149 151 150 - if (!is_fprobe_still_exist(fp)) 152 + if (!fprobe_registered(fp)) 151 153 return -ENOENT; 152 154 153 155 fph->fp = NULL; ··· 478 480 if (!fp) 479 481 break; 480 482 curr += FPROBE_HEADER_SIZE_IN_LONG; 481 - if (is_fprobe_still_exist(fp) && !fprobe_disabled(fp)) { 483 + if (fprobe_registered(fp) && !fprobe_disabled(fp)) { 482 484 if (WARN_ON_ONCE(curr + size > size_words)) 483 485 break; 484 486 fp->exit_handler(fp, trace->func, ret_ip, fregs, ··· 837 839 struct fprobe_hlist *hlist_array; 838 840 int ret, i; 839 841 842 + guard(mutex)(&fprobe_mutex); 843 + if (fprobe_registered(fp)) 844 + return -EEXIST; 845 + 840 846 ret = fprobe_init(fp, addrs, num); 841 847 if (ret) 842 848 return ret; 843 - 844 - mutex_lock(&fprobe_mutex); 845 849 846 850 hlist_array = fp->hlist_array; 847 851 if (fprobe_is_ftrace(fp)) ··· 864 864 delete_fprobe_node(&hlist_array->array[i]); 865 865 } 866 866 } 867 - mutex_unlock(&fprobe_mutex); 868 867 869 868 if (ret) 870 869 fprobe_fail_cleanup(fp); ··· 925 926 int ret = 0, i, count; 926 927 927 928 mutex_lock(&fprobe_mutex); 928 - if (!fp || !is_fprobe_still_exist(fp)) { 929 + if (!fp || !fprobe_registered(fp)) { 929 930 ret = -EINVAL; 930 931 goto out; 931 932 }