Skip to content

Commit 669fc83

Browse files
committed
Merge tag 'probes-fixes-v6.7-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace
Pull probes fixes from Masami Hiramatsu: - objpool: Fix objpool overrun case on memory/cache access delay especially on the big.LITTLE SoC. The objpool uses a copy of object slot index internal loop, but the slot index can be changed on another processor in parallel. In that case, the difference of 'head' local copy and the 'slot->last' index will be bigger than local slot size. In that case, we need to re-read the slot::head to update it. - kretprobe: Fix to use appropriate rcu API for kretprobe holder. Since kretprobe_holder::rp is RCU managed, it should use rcu_assign_pointer() and rcu_dereference_check() correctly. Also adding __rcu tag for finding wrong usage by sparse. - rethook: Fix to use appropriate rcu API for rethook::handler. The same as kretprobe, rethook::handler is RCU managed and it should use rcu_assign_pointer() and rcu_dereference_check(). This also adds __rcu tag for finding wrong usage by sparse. * tag 'probes-fixes-v6.7-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace: rethook: Use __rcu pointer for rethook::handler kprobes: consistent rcu api usage for kretprobe holder lib: objpool: fix head overrun on RK3588 SBC
2 parents 815fb87 + a1461f1 commit 669fc83

File tree

5 files changed

+43
-21
lines changed

5 files changed

+43
-21
lines changed

include/linux/kprobes.h

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ static inline bool kprobe_ftrace(struct kprobe *p)
139139
*
140140
*/
141141
struct kretprobe_holder {
142-
struct kretprobe *rp;
142+
struct kretprobe __rcu *rp;
143143
struct objpool_head pool;
144144
};
145145

@@ -197,10 +197,8 @@ extern int arch_trampoline_kprobe(struct kprobe *p);
197197
#ifdef CONFIG_KRETPROBE_ON_RETHOOK
198198
static nokprobe_inline struct kretprobe *get_kretprobe(struct kretprobe_instance *ri)
199199
{
200-
RCU_LOCKDEP_WARN(!rcu_read_lock_any_held(),
201-
"Kretprobe is accessed from instance under preemptive context");
202-
203-
return (struct kretprobe *)READ_ONCE(ri->node.rethook->data);
200+
/* rethook::data is non-changed field, so that you can access it freely. */
201+
return (struct kretprobe *)ri->node.rethook->data;
204202
}
205203
static nokprobe_inline unsigned long get_kretprobe_retaddr(struct kretprobe_instance *ri)
206204
{
@@ -245,10 +243,7 @@ unsigned long kretprobe_trampoline_handler(struct pt_regs *regs,
245243

246244
static nokprobe_inline struct kretprobe *get_kretprobe(struct kretprobe_instance *ri)
247245
{
248-
RCU_LOCKDEP_WARN(!rcu_read_lock_any_held(),
249-
"Kretprobe is accessed from instance under preemptive context");
250-
251-
return READ_ONCE(ri->rph->rp);
246+
return rcu_dereference_check(ri->rph->rp, rcu_read_lock_any_held());
252247
}
253248

254249
static nokprobe_inline unsigned long get_kretprobe_retaddr(struct kretprobe_instance *ri)

include/linux/rethook.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,12 @@ typedef void (*rethook_handler_t) (struct rethook_node *, void *, unsigned long,
2828
*/
2929
struct rethook {
3030
void *data;
31-
rethook_handler_t handler;
31+
/*
32+
* To avoid sparse warnings, this uses a raw function pointer with
33+
* __rcu, instead of rethook_handler_t. But this must be same as
34+
* rethook_handler_t.
35+
*/
36+
void (__rcu *handler) (struct rethook_node *, void *, unsigned long, struct pt_regs *);
3237
struct objpool_head pool;
3338
struct rcu_head rcu;
3439
};

kernel/kprobes.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2252,7 +2252,7 @@ int register_kretprobe(struct kretprobe *rp)
22522252
rp->rph = NULL;
22532253
return -ENOMEM;
22542254
}
2255-
rp->rph->rp = rp;
2255+
rcu_assign_pointer(rp->rph->rp, rp);
22562256
rp->nmissed = 0;
22572257
/* Establish function entry probe point */
22582258
ret = register_kprobe(&rp->kp);
@@ -2300,7 +2300,7 @@ void unregister_kretprobes(struct kretprobe **rps, int num)
23002300
#ifdef CONFIG_KRETPROBE_ON_RETHOOK
23012301
rethook_free(rps[i]->rh);
23022302
#else
2303-
rps[i]->rph->rp = NULL;
2303+
rcu_assign_pointer(rps[i]->rph->rp, NULL);
23042304
#endif
23052305
}
23062306
mutex_unlock(&kprobe_mutex);

kernel/trace/rethook.c

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ static void rethook_free_rcu(struct rcu_head *head)
4848
*/
4949
void rethook_stop(struct rethook *rh)
5050
{
51-
WRITE_ONCE(rh->handler, NULL);
51+
rcu_assign_pointer(rh->handler, NULL);
5252
}
5353

5454
/**
@@ -63,7 +63,7 @@ void rethook_stop(struct rethook *rh)
6363
*/
6464
void rethook_free(struct rethook *rh)
6565
{
66-
WRITE_ONCE(rh->handler, NULL);
66+
rethook_stop(rh);
6767

6868
call_rcu(&rh->rcu, rethook_free_rcu);
6969
}
@@ -82,6 +82,12 @@ static int rethook_fini_pool(struct objpool_head *head, void *context)
8282
return 0;
8383
}
8484

85+
static inline rethook_handler_t rethook_get_handler(struct rethook *rh)
86+
{
87+
return (rethook_handler_t)rcu_dereference_check(rh->handler,
88+
rcu_read_lock_any_held());
89+
}
90+
8591
/**
8692
* rethook_alloc() - Allocate struct rethook.
8793
* @data: a data to pass the @handler when hooking the return.
@@ -107,7 +113,7 @@ struct rethook *rethook_alloc(void *data, rethook_handler_t handler,
107113
return ERR_PTR(-ENOMEM);
108114

109115
rh->data = data;
110-
rh->handler = handler;
116+
rcu_assign_pointer(rh->handler, handler);
111117

112118
/* initialize the objpool for rethook nodes */
113119
if (objpool_init(&rh->pool, num, size, GFP_KERNEL, rh,
@@ -135,9 +141,10 @@ static void free_rethook_node_rcu(struct rcu_head *head)
135141
*/
136142
void rethook_recycle(struct rethook_node *node)
137143
{
138-
lockdep_assert_preemption_disabled();
144+
rethook_handler_t handler;
139145

140-
if (likely(READ_ONCE(node->rethook->handler)))
146+
handler = rethook_get_handler(node->rethook);
147+
if (likely(handler))
141148
objpool_push(node, &node->rethook->pool);
142149
else
143150
call_rcu(&node->rcu, free_rethook_node_rcu);
@@ -153,9 +160,7 @@ NOKPROBE_SYMBOL(rethook_recycle);
153160
*/
154161
struct rethook_node *rethook_try_get(struct rethook *rh)
155162
{
156-
rethook_handler_t handler = READ_ONCE(rh->handler);
157-
158-
lockdep_assert_preemption_disabled();
163+
rethook_handler_t handler = rethook_get_handler(rh);
159164

160165
/* Check whether @rh is going to be freed. */
161166
if (unlikely(!handler))
@@ -300,7 +305,7 @@ unsigned long rethook_trampoline_handler(struct pt_regs *regs,
300305
rhn = container_of(first, struct rethook_node, llist);
301306
if (WARN_ON_ONCE(rhn->frame != frame))
302307
break;
303-
handler = READ_ONCE(rhn->rethook->handler);
308+
handler = rethook_get_handler(rhn->rethook);
304309
if (handler)
305310
handler(rhn, rhn->rethook->data,
306311
correct_ret_addr, regs);

lib/objpool.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,23 @@ static inline void *objpool_try_get_slot(struct objpool_head *pool, int cpu)
201201
while (head != READ_ONCE(slot->last)) {
202202
void *obj;
203203

204+
/*
205+
* data visibility of 'last' and 'head' could be out of
206+
* order since memory updating of 'last' and 'head' are
207+
* performed in push() and pop() independently
208+
*
209+
* before any retrieving attempts, pop() must guarantee
210+
* 'last' is behind 'head', that is to say, there must
211+
* be available objects in slot, which could be ensured
212+
* by condition 'last != head && last - head <= nr_objs'
213+
* that is equivalent to 'last - head - 1 < nr_objs' as
214+
* 'last' and 'head' are both unsigned int32
215+
*/
216+
if (READ_ONCE(slot->last) - head - 1 >= pool->nr_objs) {
217+
head = READ_ONCE(slot->head);
218+
continue;
219+
}
220+
204221
/* obj must be retrieved before moving forward head */
205222
obj = READ_ONCE(slot->entries[head & slot->mask]);
206223

0 commit comments

Comments
 (0)