Skip to content

Commit 568f196

Browse files
Peter Zijlstraborkmann
authored andcommitted
bpf: check that BPF programs run with preemption disabled
Introduce cant_sleep() macro for annotation of functions that cannot sleep. Use it in BPF_PROG_RUN to catch execution of BPF programs in preemptable context. Suggested-by: Jann Horn <jannh@google.com> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Signed-off-by: Alexei Starovoitov <ast@kernel.org> Acked-by: Song Liu <songliubraving@fb.com> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
1 parent a5d9265 commit 568f196

File tree

3 files changed

+41
-3
lines changed

3 files changed

+41
-3
lines changed

include/linux/filter.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -533,7 +533,7 @@ struct sk_filter {
533533
struct bpf_prog *prog;
534534
};
535535

536-
#define BPF_PROG_RUN(filter, ctx) (*(filter)->bpf_func)(ctx, (filter)->insnsi)
536+
#define BPF_PROG_RUN(filter, ctx) ({ cant_sleep(); (*(filter)->bpf_func)(ctx, (filter)->insnsi); })
537537

538538
#define BPF_SKB_CB_LEN QDISC_CB_PRIV_LEN
539539

include/linux/kernel.h

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -245,8 +245,10 @@ extern int _cond_resched(void);
245245
#endif
246246

247247
#ifdef CONFIG_DEBUG_ATOMIC_SLEEP
248-
void ___might_sleep(const char *file, int line, int preempt_offset);
249-
void __might_sleep(const char *file, int line, int preempt_offset);
248+
extern void ___might_sleep(const char *file, int line, int preempt_offset);
249+
extern void __might_sleep(const char *file, int line, int preempt_offset);
250+
extern void __cant_sleep(const char *file, int line, int preempt_offset);
251+
250252
/**
251253
* might_sleep - annotation for functions that can sleep
252254
*
@@ -259,13 +261,21 @@ extern int _cond_resched(void);
259261
*/
260262
# define might_sleep() \
261263
do { __might_sleep(__FILE__, __LINE__, 0); might_resched(); } while (0)
264+
/**
265+
* cant_sleep - annotation for functions that cannot sleep
266+
*
267+
* this macro will print a stack trace if it is executed with preemption enabled
268+
*/
269+
# define cant_sleep() \
270+
do { __cant_sleep(__FILE__, __LINE__, 0); } while (0)
262271
# define sched_annotate_sleep() (current->task_state_change = 0)
263272
#else
264273
static inline void ___might_sleep(const char *file, int line,
265274
int preempt_offset) { }
266275
static inline void __might_sleep(const char *file, int line,
267276
int preempt_offset) { }
268277
# define might_sleep() do { might_resched(); } while (0)
278+
# define cant_sleep() do { } while (0)
269279
# define sched_annotate_sleep() do { } while (0)
270280
#endif
271281

kernel/sched/core.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6162,6 +6162,34 @@ void ___might_sleep(const char *file, int line, int preempt_offset)
61626162
add_taint(TAINT_WARN, LOCKDEP_STILL_OK);
61636163
}
61646164
EXPORT_SYMBOL(___might_sleep);
6165+
6166+
void __cant_sleep(const char *file, int line, int preempt_offset)
6167+
{
6168+
static unsigned long prev_jiffy;
6169+
6170+
if (irqs_disabled())
6171+
return;
6172+
6173+
if (!IS_ENABLED(CONFIG_PREEMPT_COUNT))
6174+
return;
6175+
6176+
if (preempt_count() > preempt_offset)
6177+
return;
6178+
6179+
if (time_before(jiffies, prev_jiffy + HZ) && prev_jiffy)
6180+
return;
6181+
prev_jiffy = jiffies;
6182+
6183+
printk(KERN_ERR "BUG: assuming atomic context at %s:%d\n", file, line);
6184+
printk(KERN_ERR "in_atomic(): %d, irqs_disabled(): %d, pid: %d, name: %s\n",
6185+
in_atomic(), irqs_disabled(),
6186+
current->pid, current->comm);
6187+
6188+
debug_show_held_locks(current);
6189+
dump_stack();
6190+
add_taint(TAINT_WARN, LOCKDEP_STILL_OK);
6191+
}
6192+
EXPORT_SYMBOL_GPL(__cant_sleep);
61656193
#endif
61666194

61676195
#ifdef CONFIG_MAGIC_SYSRQ

0 commit comments

Comments
 (0)