Linux 6.9-rc1
[linux-2.6-microblaze.git] / kernel / kprobes.c
index f214f8c..9d9095e 100644 (file)
@@ -458,7 +458,7 @@ static inline int kprobe_optready(struct kprobe *p)
 }
 
 /* Return true if the kprobe is disarmed. Note: p must be on hash list */
-static inline bool kprobe_disarmed(struct kprobe *p)
+bool kprobe_disarmed(struct kprobe *p)
 {
        struct optimized_kprobe *op;
 
@@ -555,17 +555,15 @@ static void do_unoptimize_kprobes(void)
        /* See comment in do_optimize_kprobes() */
        lockdep_assert_cpus_held();
 
-       /* Unoptimization must be done anytime */
-       if (list_empty(&unoptimizing_list))
-               return;
+       if (!list_empty(&unoptimizing_list))
+               arch_unoptimize_kprobes(&unoptimizing_list, &freeing_list);
 
-       arch_unoptimize_kprobes(&unoptimizing_list, &freeing_list);
-       /* Loop on 'freeing_list' for disarming */
+       /* Loop on 'freeing_list' for disarming and removing from kprobe hash list */
        list_for_each_entry_safe(op, tmp, &freeing_list, list) {
                /* Switching from detour code to origin */
                op->kp.flags &= ~KPROBE_FLAG_OPTIMIZED;
-               /* Disarm probes if marked disabled */
-               if (kprobe_disabled(&op->kp))
+               /* Disarm probes if marked disabled and not gone */
+               if (kprobe_disabled(&op->kp) && !kprobe_gone(&op->kp))
                        arch_disarm_kprobe(&op->kp);
                if (kprobe_unused(&op->kp)) {
                        /*
@@ -662,7 +660,7 @@ void wait_for_kprobe_optimizer(void)
        mutex_unlock(&kprobe_mutex);
 }
 
-static bool optprobe_queued_unopt(struct optimized_kprobe *op)
+bool optprobe_queued_unopt(struct optimized_kprobe *op)
 {
        struct optimized_kprobe *_op;
 
@@ -797,14 +795,13 @@ static void kill_optimized_kprobe(struct kprobe *p)
        op->kp.flags &= ~KPROBE_FLAG_OPTIMIZED;
 
        if (kprobe_unused(p)) {
-               /* Enqueue if it is unused */
-               list_add(&op->list, &freeing_list);
                /*
-                * Remove unused probes from the hash list. After waiting
-                * for synchronization, this probe is reclaimed.
-                * (reclaiming is done by do_free_cleaned_kprobes().)
+                * Unused kprobe is on unoptimizing or freeing list. We move it
+                * to freeing_list and let the kprobe_optimizer() remove it from
+                * the kprobe hash list and free it.
                 */
-               hlist_del_rcu(&op->kp.hlist);
+               if (optprobe_queued_unopt(op))
+                       list_move(&op->list, &freeing_list);
        }
 
        /* Don't touch the code, because it is already freed. */
@@ -1075,7 +1072,7 @@ static int kprobe_ftrace_enabled;
 static int __arm_kprobe_ftrace(struct kprobe *p, struct ftrace_ops *ops,
                               int *cnt)
 {
-       int ret = 0;
+       int ret;
 
        lockdep_assert_held(&kprobe_mutex);
 
@@ -1113,7 +1110,7 @@ static int arm_kprobe_ftrace(struct kprobe *p)
 static int __disarm_kprobe_ftrace(struct kprobe *p, struct ftrace_ops *ops,
                                  int *cnt)
 {
-       int ret = 0;
+       int ret;
 
        lockdep_assert_held(&kprobe_mutex);
 
@@ -1548,6 +1545,17 @@ static int check_ftrace_location(struct kprobe *p)
        return 0;
 }
 
+static bool is_cfi_preamble_symbol(unsigned long addr)
+{
+       char symbuf[KSYM_NAME_LEN];
+
+       if (lookup_symbol_name(addr, symbuf))
+               return false;
+
+       return str_has_prefix("__cfi_", symbuf) ||
+               str_has_prefix("__pfx_", symbuf);
+}
+
 static int check_kprobe_address_safe(struct kprobe *p,
                                     struct module **probed_mod)
 {
@@ -1560,11 +1568,14 @@ static int check_kprobe_address_safe(struct kprobe *p,
        preempt_disable();
 
        /* Ensure it is not in reserved area nor out of text */
-       if (!kernel_text_address((unsigned long) p->addr) ||
+       if (!(core_kernel_text((unsigned long) p->addr) ||
+           is_module_text_address((unsigned long) p->addr)) ||
+           in_gate_area_no_mm((unsigned long) p->addr) ||
            within_kprobe_blacklist((unsigned long) p->addr) ||
            jump_label_text_reserved(p->addr, p->addr) ||
            static_call_text_reserved(p->addr, p->addr) ||
-           find_bug((unsigned long)p->addr)) {
+           find_bug((unsigned long)p->addr) ||
+           is_cfi_preamble_symbol((unsigned long)p->addr)) {
                ret = -EINVAL;
                goto out;
        }
@@ -1605,9 +1616,10 @@ int register_kprobe(struct kprobe *p)
        struct kprobe *old_p;
        struct module *probed_mod;
        kprobe_opcode_t *addr;
+       bool on_func_entry;
 
        /* Adjust probe address from symbol */
-       addr = kprobe_addr(p);
+       addr = _kprobe_addr(p->addr, p->symbol_name, p->offset, &on_func_entry);
        if (IS_ERR(addr))
                return PTR_ERR(addr);
        p->addr = addr;
@@ -1627,6 +1639,9 @@ int register_kprobe(struct kprobe *p)
 
        mutex_lock(&kprobe_mutex);
 
+       if (on_func_entry)
+               p->flags |= KPROBE_FLAG_ON_FUNC_ENTRY;
+
        old_p = get_kprobe(p->addr);
        if (old_p) {
                /* Since this may unoptimize 'old_p', locking 'text_mutex'. */
@@ -1706,11 +1721,12 @@ static struct kprobe *__disable_kprobe(struct kprobe *p)
                /* Try to disarm and disable this/parent probe */
                if (p == orig_p || aggr_kprobe_disabled(orig_p)) {
                        /*
-                        * If 'kprobes_all_disarmed' is set, 'orig_p'
-                        * should have already been disarmed, so
-                        * skip unneed disarming process.
+                        * Don't be lazy here.  Even if 'kprobes_all_disarmed'
+                        * is false, 'orig_p' might not have been armed yet.
+                        * Note arm_all_kprobes() __tries__ to arm all kprobes
+                        * on the best effort basis.
                         */
-                       if (!kprobes_all_disarmed) {
+                       if (!kprobes_all_disarmed && !kprobe_disabled(orig_p)) {
                                ret = disarm_kprobe(orig_p, true);
                                if (ret) {
                                        p->flags &= ~KPROBE_FLAG_DISABLED;
@@ -1759,7 +1775,13 @@ static int __unregister_kprobe_top(struct kprobe *p)
                                if ((list_p != p) && (list_p->post_handler))
                                        goto noclean;
                        }
-                       ap->post_handler = NULL;
+                       /*
+                        * For the kprobe-on-ftrace case, we keep the
+                        * post_handler setting to identify this aggrprobe
+                        * armed with kprobe_ipmodify_ops.
+                        */
+                       if (!kprobe_ftrace(ap))
+                               ap->post_handler = NULL;
                }
 noclean:
                /*
@@ -1855,13 +1877,27 @@ static struct notifier_block kprobe_exceptions_nb = {
 #ifdef CONFIG_KRETPROBES
 
 #if !defined(CONFIG_KRETPROBE_ON_RETHOOK)
+
+/* callbacks for objpool of kretprobe instances */
+static int kretprobe_init_inst(void *nod, void *context)
+{
+       struct kretprobe_instance *ri = nod;
+
+       ri->rph = context;
+       return 0;
+}
+static int kretprobe_fini_pool(struct objpool_head *head, void *context)
+{
+       kfree(context);
+       return 0;
+}
+
 static void free_rp_inst_rcu(struct rcu_head *head)
 {
        struct kretprobe_instance *ri = container_of(head, struct kretprobe_instance, rcu);
+       struct kretprobe_holder *rph = ri->rph;
 
-       if (refcount_dec_and_test(&ri->rph->ref))
-               kfree(ri->rph);
-       kfree(ri);
+       objpool_drop(ri, &rph->pool);
 }
 NOKPROBE_SYMBOL(free_rp_inst_rcu);
 
@@ -1870,7 +1906,7 @@ static void recycle_rp_inst(struct kretprobe_instance *ri)
        struct kretprobe *rp = get_kretprobe(ri);
 
        if (likely(rp))
-               freelist_add(&ri->freelist, &rp->freelist);
+               objpool_push(ri, &rp->rph->pool);
        else
                call_rcu(&ri->rcu, free_rp_inst_rcu);
 }
@@ -1907,23 +1943,12 @@ 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;
+       struct kretprobe_holder *rph = rp->rph;
 
-       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;
-       }
+       if (!rph)
+               return;
+       rp->rph = NULL;
+       objpool_fini(&rph->pool);
 }
 
 /* This assumes the 'tsk' is the current task or the is not running. */
@@ -1968,7 +1993,7 @@ NOKPROBE_SYMBOL(__kretprobe_find_ret_addr);
 unsigned long kretprobe_find_ret_addr(struct task_struct *tsk, void *fp,
                                      struct llist_node **cur)
 {
-       struct kretprobe_instance *ri = NULL;
+       struct kretprobe_instance *ri;
        kprobe_opcode_t *ret;
 
        if (WARN_ON_ONCE(!cur))
@@ -1997,9 +2022,9 @@ void __weak arch_kretprobe_fixup_return(struct pt_regs *regs,
 unsigned long __kretprobe_trampoline_handler(struct pt_regs *regs,
                                             void *frame_pointer)
 {
-       kprobe_opcode_t *correct_ret_addr = NULL;
        struct kretprobe_instance *ri = NULL;
        struct llist_node *first, *node = NULL;
+       kprobe_opcode_t *correct_ret_addr;
        struct kretprobe *rp;
 
        /* Find correct address and all nodes for this frame. */
@@ -2065,19 +2090,17 @@ NOKPROBE_SYMBOL(__kretprobe_trampoline_handler)
 static int pre_handler_kretprobe(struct kprobe *p, struct pt_regs *regs)
 {
        struct kretprobe *rp = container_of(p, struct kretprobe, kp);
+       struct kretprobe_holder *rph = rp->rph;
        struct kretprobe_instance *ri;
-       struct freelist_node *fn;
 
-       fn = freelist_try_get(&rp->freelist);
-       if (!fn) {
+       ri = objpool_pop(&rph->pool);
+       if (!ri) {
                rp->nmissed++;
                return 0;
        }
 
-       ri = container_of(fn, struct kretprobe_instance, freelist);
-
        if (rp->entry_handler && rp->entry_handler(ri, regs)) {
-               freelist_add(&ri->freelist, &rp->freelist);
+               objpool_push(ri, &rph->pool);
                return 0;
        }
 
@@ -2117,6 +2140,7 @@ static int pre_handler_kretprobe(struct kprobe *p, struct pt_regs *regs)
 NOKPROBE_SYMBOL(pre_handler_kretprobe);
 
 static void kretprobe_rethook_handler(struct rethook_node *rh, void *data,
+                                     unsigned long ret_addr,
                                      struct pt_regs *regs)
 {
        struct kretprobe *rp = (struct kretprobe *)data;
@@ -2170,7 +2194,6 @@ int kprobe_on_func_entry(kprobe_opcode_t *addr, const char *sym, unsigned long o
 int register_kretprobe(struct kretprobe *rp)
 {
        int ret;
-       struct kretprobe_instance *inst;
        int i;
        void *addr;
 
@@ -2200,28 +2223,16 @@ int register_kretprobe(struct kretprobe *rp)
        rp->kp.post_handler = NULL;
 
        /* Pre-allocate memory for max kretprobe instances */
-       if (rp->maxactive <= 0) {
-#ifdef CONFIG_PREEMPTION
+       if (rp->maxactive <= 0)
                rp->maxactive = max_t(unsigned int, 10, 2*num_possible_cpus());
-#else
-               rp->maxactive = num_possible_cpus();
-#endif
-       }
+
 #ifdef CONFIG_KRETPROBE_ON_RETHOOK
-       rp->rh = rethook_alloc((void *)rp, kretprobe_rethook_handler);
-       if (!rp->rh)
-               return -ENOMEM;
+       rp->rh = rethook_alloc((void *)rp, kretprobe_rethook_handler,
+                               sizeof(struct kretprobe_instance) +
+                               rp->data_size, rp->maxactive);
+       if (IS_ERR(rp->rh))
+               return PTR_ERR(rp->rh);
 
-       for (i = 0; i < rp->maxactive; i++) {
-               inst = kzalloc(sizeof(struct kretprobe_instance) +
-                              rp->data_size, GFP_KERNEL);
-               if (inst == NULL) {
-                       rethook_free(rp->rh);
-                       rp->rh = NULL;
-                       return -ENOMEM;
-               }
-               rethook_add_node(rp->rh, &inst->node);
-       }
        rp->nmissed = 0;
        /* Establish function entry probe point */
        ret = register_kprobe(&rp->kp);
@@ -2230,25 +2241,18 @@ int register_kretprobe(struct kretprobe *rp)
                rp->rh = NULL;
        }
 #else  /* !CONFIG_KRETPROBE_ON_RETHOOK */
-       rp->freelist.head = NULL;
        rp->rph = kzalloc(sizeof(struct kretprobe_holder), GFP_KERNEL);
        if (!rp->rph)
                return -ENOMEM;
 
-       rp->rph->rp = rp;
-       for (i = 0; i < rp->maxactive; i++) {
-               inst = kzalloc(sizeof(struct kretprobe_instance) +
-                              rp->data_size, GFP_KERNEL);
-               if (inst == NULL) {
-                       refcount_set(&rp->rph->ref, i);
-                       free_rp_inst(rp);
-                       return -ENOMEM;
-               }
-               inst->rph = rp->rph;
-               freelist_add(&inst->freelist, &rp->freelist);
+       if (objpool_init(&rp->rph->pool, rp->maxactive, rp->data_size +
+                       sizeof(struct kretprobe_instance), GFP_KERNEL,
+                       rp->rph, kretprobe_init_inst, kretprobe_fini_pool)) {
+               kfree(rp->rph);
+               rp->rph = NULL;
+               return -ENOMEM;
        }
-       refcount_set(&rp->rph->ref, i);
-
+       rcu_assign_pointer(rp->rph->rp, rp);
        rp->nmissed = 0;
        /* Establish function entry probe point */
        ret = register_kprobe(&rp->kp);
@@ -2296,7 +2300,7 @@ void unregister_kretprobes(struct kretprobe **rps, int num)
 #ifdef CONFIG_KRETPROBE_ON_RETHOOK
                rethook_free(rps[i]->rh);
 #else
-               rps[i]->rph->rp = NULL;
+               rcu_assign_pointer(rps[i]->rph->rp, NULL);
 #endif
        }
        mutex_unlock(&kprobe_mutex);
@@ -2351,6 +2355,14 @@ static void kill_kprobe(struct kprobe *p)
 
        lockdep_assert_held(&kprobe_mutex);
 
+       /*
+        * The module is going away. We should disarm the kprobe which
+        * is using ftrace, because ftrace framework is still available at
+        * 'MODULE_STATE_GOING' notification.
+        */
+       if (kprobe_ftrace(p) && !kprobe_disabled(p) && !kprobes_all_disarmed)
+               disarm_kprobe_ftrace(p);
+
        p->flags |= KPROBE_FLAG_GONE;
        if (kprobe_aggrprobe(p)) {
                /*
@@ -2367,14 +2379,6 @@ static void kill_kprobe(struct kprobe *p)
         * the original probed function (which will be freed soon) any more.
         */
        arch_remove_kprobe(p);
-
-       /*
-        * The module is going away. We should disarm the kprobe which
-        * is using ftrace, because ftrace framework is still available at
-        * 'MODULE_STATE_GOING' notification.
-        */
-       if (kprobe_ftrace(p) && !kprobe_disabled(p) && !kprobes_all_disarmed)
-               disarm_kprobe_ftrace(p);
 }
 
 /* Disable one kprobe */
@@ -2422,8 +2426,11 @@ int enable_kprobe(struct kprobe *kp)
        if (!kprobes_all_disarmed && kprobe_disabled(p)) {
                p->flags &= ~KPROBE_FLAG_DISABLED;
                ret = arm_kprobe(p);
-               if (ret)
+               if (ret) {
                        p->flags |= KPROBE_FLAG_DISABLED;
+                       if (p != kp)
+                               kp->flags |= KPROBE_FLAG_DISABLED;
+               }
        }
 out:
        mutex_unlock(&kprobe_mutex);
@@ -2683,7 +2690,7 @@ void kprobe_free_init_mem(void)
 
 static int __init init_kprobes(void)
 {
-       int i, err = 0;
+       int i, err;
 
        /* FIXME allocate the probe table, currently defined statically */
        /* initialize all list heads */
@@ -2795,7 +2802,7 @@ static int show_kprobe_addr(struct seq_file *pi, void *v)
 {
        struct hlist_head *head;
        struct kprobe *p, *kp;
-       const char *sym = NULL;
+       const char *sym;
        unsigned int i = *(loff_t *) v;
        unsigned long offset = 0;
        char *modname, namebuf[KSYM_NAME_LEN];