kprobes: Fix build errors with CONFIG_KRETPROBES=n
authorMasami Hiramatsu <mhiramat@kernel.org>
Wed, 4 May 2022 03:36:31 +0000 (12:36 +0900)
committerSteven Rostedt (Google) <rostedt@goodmis.org>
Fri, 27 May 2022 01:12:59 +0000 (21:12 -0400)
Max Filippov reported:

When building kernel with CONFIG_KRETPROBES=n kernel/kprobes.c
compilation fails with the following messages:

  kernel/kprobes.c: In function ‘recycle_rp_inst’:
  kernel/kprobes.c:1273:32: error: implicit declaration of function
                                   ‘get_kretprobe’

  kernel/kprobes.c: In function ‘kprobe_flush_task’:
  kernel/kprobes.c:1299:35: error: ‘struct task_struct’ has no member
                                   named ‘kretprobe_instances’

This came from the commit d741bf41d7c7 ("kprobes: Remove
kretprobe hash") which introduced get_kretprobe() and
kretprobe_instances member in task_struct when CONFIG_KRETPROBES=y,
but did not make recycle_rp_inst() and kprobe_flush_task()
depending on CONFIG_KRETPORBES.

Since those functions are only used for kretprobe, move those
functions into #ifdef CONFIG_KRETPROBE area.

Link: https://lkml.kernel.org/r/165163539094.74407.3838114721073251225.stgit@devnote2
Reported-by: Max Filippov <jcmvbkbc@gmail.com>
Fixes: d741bf41d7c7 ("kprobes: Remove kretprobe hash")
Cc: "Naveen N . Rao" <naveen.n.rao@linux.ibm.com>
Cc: Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
Cc: "David S . Miller" <davem@davemloft.net>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: stable@vger.kernel.org
Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
Tested-by: Max Filippov <jcmvbkbc@gmail.com>
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
include/linux/kprobes.h
kernel/kprobes.c

index 1571687..55041d2 100644 (file)
@@ -424,7 +424,7 @@ void unregister_kretprobe(struct kretprobe *rp);
 int register_kretprobes(struct kretprobe **rps, int num);
 void unregister_kretprobes(struct kretprobe **rps, int num);
 
-#ifdef CONFIG_KRETPROBE_ON_RETHOOK
+#if defined(CONFIG_KRETPROBE_ON_RETHOOK) || !defined(CONFIG_KRETPROBES)
 #define kprobe_flush_task(tk)  do {} while (0)
 #else
 void kprobe_flush_task(struct task_struct *tk);
index dbe57df..172ba75 100644 (file)
@@ -1257,79 +1257,6 @@ void kprobe_busy_end(void)
        preempt_enable();
 }
 
-#if !defined(CONFIG_KRETPROBE_ON_RETHOOK)
-static void free_rp_inst_rcu(struct rcu_head *head)
-{
-       struct kretprobe_instance *ri = container_of(head, struct kretprobe_instance, rcu);
-
-       if (refcount_dec_and_test(&ri->rph->ref))
-               kfree(ri->rph);
-       kfree(ri);
-}
-NOKPROBE_SYMBOL(free_rp_inst_rcu);
-
-static void recycle_rp_inst(struct kretprobe_instance *ri)
-{
-       struct kretprobe *rp = get_kretprobe(ri);
-
-       if (likely(rp))
-               freelist_add(&ri->freelist, &rp->freelist);
-       else
-               call_rcu(&ri->rcu, free_rp_inst_rcu);
-}
-NOKPROBE_SYMBOL(recycle_rp_inst);
-
-/*
- * This function is called from delayed_put_task_struct() when a task is
- * dead and cleaned up to recycle any kretprobe instances associated with
- * this task. These left over instances represent probed functions that
- * have been called but will never return.
- */
-void kprobe_flush_task(struct task_struct *tk)
-{
-       struct kretprobe_instance *ri;
-       struct llist_node *node;
-
-       /* Early boot, not yet initialized. */
-       if (unlikely(!kprobes_initialized))
-               return;
-
-       kprobe_busy_begin();
-
-       node = __llist_del_all(&tk->kretprobe_instances);
-       while (node) {
-               ri = container_of(node, struct kretprobe_instance, llist);
-               node = node->next;
-
-               recycle_rp_inst(ri);
-       }
-
-       kprobe_busy_end();
-}
-NOKPROBE_SYMBOL(kprobe_flush_task);
-
-static inline void free_rp_inst(struct kretprobe *rp)
-{
-       struct kretprobe_instance *ri;
-       struct freelist_node *node;
-       int count = 0;
-
-       node = rp->freelist.head;
-       while (node) {
-               ri = container_of(node, struct kretprobe_instance, freelist);
-               node = node->next;
-
-               kfree(ri);
-               count++;
-       }
-
-       if (refcount_sub_and_test(count, &rp->rph->ref)) {
-               kfree(rp->rph);
-               rp->rph = NULL;
-       }
-}
-#endif /* !CONFIG_KRETPROBE_ON_RETHOOK */
-
 /* Add the new probe to 'ap->list'. */
 static int add_new_kprobe(struct kprobe *ap, struct kprobe *p)
 {
@@ -1928,6 +1855,77 @@ static struct notifier_block kprobe_exceptions_nb = {
 #ifdef CONFIG_KRETPROBES
 
 #if !defined(CONFIG_KRETPROBE_ON_RETHOOK)
+static void free_rp_inst_rcu(struct rcu_head *head)
+{
+       struct kretprobe_instance *ri = container_of(head, struct kretprobe_instance, rcu);
+
+       if (refcount_dec_and_test(&ri->rph->ref))
+               kfree(ri->rph);
+       kfree(ri);
+}
+NOKPROBE_SYMBOL(free_rp_inst_rcu);
+
+static void recycle_rp_inst(struct kretprobe_instance *ri)
+{
+       struct kretprobe *rp = get_kretprobe(ri);
+
+       if (likely(rp))
+               freelist_add(&ri->freelist, &rp->freelist);
+       else
+               call_rcu(&ri->rcu, free_rp_inst_rcu);
+}
+NOKPROBE_SYMBOL(recycle_rp_inst);
+
+/*
+ * This function is called from delayed_put_task_struct() when a task is
+ * dead and cleaned up to recycle any kretprobe instances associated with
+ * this task. These left over instances represent probed functions that
+ * have been called but will never return.
+ */
+void kprobe_flush_task(struct task_struct *tk)
+{
+       struct kretprobe_instance *ri;
+       struct llist_node *node;
+
+       /* Early boot, not yet initialized. */
+       if (unlikely(!kprobes_initialized))
+               return;
+
+       kprobe_busy_begin();
+
+       node = __llist_del_all(&tk->kretprobe_instances);
+       while (node) {
+               ri = container_of(node, struct kretprobe_instance, llist);
+               node = node->next;
+
+               recycle_rp_inst(ri);
+       }
+
+       kprobe_busy_end();
+}
+NOKPROBE_SYMBOL(kprobe_flush_task);
+
+static inline void free_rp_inst(struct kretprobe *rp)
+{
+       struct kretprobe_instance *ri;
+       struct freelist_node *node;
+       int count = 0;
+
+       node = rp->freelist.head;
+       while (node) {
+               ri = container_of(node, struct kretprobe_instance, freelist);
+               node = node->next;
+
+               kfree(ri);
+               count++;
+       }
+
+       if (refcount_sub_and_test(count, &rp->rph->ref)) {
+               kfree(rp->rph);
+               rp->rph = NULL;
+       }
+}
+
 /* This assumes the 'tsk' is the current task or the is not running. */
 static kprobe_opcode_t *__kretprobe_find_ret_addr(struct task_struct *tsk,
                                                  struct llist_node **cur)