Skip to content

Commit

Permalink
bpf/test_run: fix unkillable BPF_PROG_TEST_RUN
Browse files Browse the repository at this point in the history
Syzbot found out that running BPF_PROG_TEST_RUN with repeat=0xffffffff
makes process unkillable. The problem is that when CONFIG_PREEMPT is
enabled, we never see need_resched() return true. This is due to the
fact that preempt_enable() (which we do in bpf_test_run_one on each
iteration) now handles resched if it's needed.

Let's disable preemption for the whole run, not per test. In this case
we can properly see whether resched is needed.
Let's also properly return -EINTR to the userspace in case of a signal
interrupt.

See recent discussion:
http://lore.kernel.org/netdev/CAH3MdRWHr4N8jei8jxDppXjmw-Nw=puNDLbu1dQOFQHxfU2onA@mail.gmail.com

I'll follow up with the same fix bpf_prog_test_run_flow_dissector in
bpf-next.

Reported-by: syzbot <syzkaller@googlegroups.com>
Signed-off-by: Stanislav Fomichev <sdf@google.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
  • Loading branch information
Stanislav Fomichev authored and Daniel Borkmann committed Feb 18, 2019
1 parent 21d2cb4 commit df1a2cb
Showing 1 changed file with 24 additions and 21 deletions.
45 changes: 24 additions & 21 deletions net/bpf/test_run.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,27 +13,13 @@
#include <net/sock.h>
#include <net/tcp.h>

static __always_inline u32 bpf_test_run_one(struct bpf_prog *prog, void *ctx,
struct bpf_cgroup_storage *storage[MAX_BPF_CGROUP_STORAGE_TYPE])
{
u32 ret;

preempt_disable();
rcu_read_lock();
bpf_cgroup_storage_set(storage);
ret = BPF_PROG_RUN(prog, ctx);
rcu_read_unlock();
preempt_enable();

return ret;
}

static int bpf_test_run(struct bpf_prog *prog, void *ctx, u32 repeat, u32 *ret,
u32 *time)
static int bpf_test_run(struct bpf_prog *prog, void *ctx, u32 repeat,
u32 *retval, u32 *time)
{
struct bpf_cgroup_storage *storage[MAX_BPF_CGROUP_STORAGE_TYPE] = { 0 };
enum bpf_cgroup_storage_type stype;
u64 time_start, time_spent = 0;
int ret = 0;
u32 i;

for_each_cgroup_storage_type(stype) {
Expand All @@ -48,25 +34,42 @@ static int bpf_test_run(struct bpf_prog *prog, void *ctx, u32 repeat, u32 *ret,

if (!repeat)
repeat = 1;

rcu_read_lock();
preempt_disable();
time_start = ktime_get_ns();
for (i = 0; i < repeat; i++) {
*ret = bpf_test_run_one(prog, ctx, storage);
bpf_cgroup_storage_set(storage);
*retval = BPF_PROG_RUN(prog, ctx);

if (signal_pending(current)) {
ret = -EINTR;
break;
}

if (need_resched()) {
if (signal_pending(current))
break;
time_spent += ktime_get_ns() - time_start;
preempt_enable();
rcu_read_unlock();

cond_resched();

rcu_read_lock();
preempt_disable();
time_start = ktime_get_ns();
}
}
time_spent += ktime_get_ns() - time_start;
preempt_enable();
rcu_read_unlock();

do_div(time_spent, repeat);
*time = time_spent > U32_MAX ? U32_MAX : (u32)time_spent;

for_each_cgroup_storage_type(stype)
bpf_cgroup_storage_free(storage[stype]);

return 0;
return ret;
}

static int bpf_test_finish(const union bpf_attr *kattr,
Expand Down

0 comments on commit df1a2cb

Please sign in to comment.