From: Masami Hiramatsu (Google) <[email protected]>

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.

Fixes: 4346ba160409 ("fprobe: Rewrite fprobe on function-graph tracer")
Cc: [email protected]
Signed-off-by: Masami Hiramatsu (Google) <[email protected]>
---
 Changes in v6:
  - Newly added.
---
 kernel/trace/fprobe.c |   21 ++++++++++-----------
 1 file changed, 10 insertions(+), 11 deletions(-)

diff --git a/kernel/trace/fprobe.c b/kernel/trace/fprobe.c
index dcadf1d23b8a..fc7018b28fdd 100644
--- a/kernel/trace/fprobe.c
+++ b/kernel/trace/fprobe.c
@@ -4,6 +4,7 @@
  */
 #define pr_fmt(fmt) "fprobe: " fmt
 
+#include <linux/cleanup.h>
 #include <linux/err.h>
 #include <linux/fprobe.h>
 #include <linux/kallsyms.h>
@@ -107,7 +108,7 @@ static bool delete_fprobe_node(struct fprobe_hlist_node 
*node)
 }
 
 /* Check existence of the fprobe */
-static bool is_fprobe_still_exist(struct fprobe *fp)
+static bool fprobe_registered(struct fprobe *fp)
 {
        struct hlist_head *head;
        struct fprobe_hlist *fph;
@@ -120,7 +121,7 @@ static bool is_fprobe_still_exist(struct fprobe *fp)
        }
        return false;
 }
-NOKPROBE_SYMBOL(is_fprobe_still_exist);
+NOKPROBE_SYMBOL(fprobe_registered);
 
 static int add_fprobe_hash(struct fprobe *fp)
 {
@@ -132,9 +133,6 @@ static int add_fprobe_hash(struct fprobe *fp)
        if (WARN_ON_ONCE(!fph))
                return -EINVAL;
 
-       if (is_fprobe_still_exist(fp))
-               return -EEXIST;
-
        head = &fprobe_table[hash_ptr(fp, FPROBE_HASH_BITS)];
        hlist_add_head_rcu(&fp->hlist_array->hlist, head);
        return 0;
@@ -149,7 +147,7 @@ static int del_fprobe_hash(struct fprobe *fp)
        if (WARN_ON_ONCE(!fph))
                return -EINVAL;
 
-       if (!is_fprobe_still_exist(fp))
+       if (!fprobe_registered(fp))
                return -ENOENT;
 
        fph->fp = NULL;
@@ -482,7 +480,7 @@ static void fprobe_return(struct ftrace_graph_ret *trace,
                if (!fp)
                        break;
                curr += FPROBE_HEADER_SIZE_IN_LONG;
-               if (is_fprobe_still_exist(fp) && !fprobe_disabled(fp)) {
+               if (fprobe_registered(fp) && !fprobe_disabled(fp)) {
                        if (WARN_ON_ONCE(curr + size > size_words))
                                break;
                        fp->exit_handler(fp, trace->func, ret_ip, fregs,
@@ -841,12 +839,14 @@ int register_fprobe_ips(struct fprobe *fp, unsigned long 
*addrs, int num)
        struct fprobe_hlist *hlist_array;
        int ret, i;
 
+       guard(mutex)(&fprobe_mutex);
+       if (fprobe_registered(fp))
+               return -EEXIST;
+
        ret = fprobe_init(fp, addrs, num);
        if (ret)
                return ret;
 
-       mutex_lock(&fprobe_mutex);
-
        hlist_array = fp->hlist_array;
        if (fprobe_is_ftrace(fp))
                ret = fprobe_ftrace_add_ips(addrs, num);
@@ -866,7 +866,6 @@ int register_fprobe_ips(struct fprobe *fp, unsigned long 
*addrs, int num)
                                delete_fprobe_node(&hlist_array->array[i]);
                }
        }
-       mutex_unlock(&fprobe_mutex);
 
        if (ret)
                fprobe_fail_cleanup(fp);
@@ -928,7 +927,7 @@ int unregister_fprobe(struct fprobe *fp)
        int ret = 0, i, count;
 
        mutex_lock(&fprobe_mutex);
-       if (!fp || !is_fprobe_still_exist(fp)) {
+       if (!fp || !fprobe_registered(fp)) {
                ret = -EINVAL;
                goto out;
        }


Reply via email to