Skip to content

Commit

Permalink
bpf/test_run: fix unkillable BPF_PROG_TEST_RUN for flow dissector
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.

This is a follow up for a recently fixed issue in bpf_test_run, see
commit df1a2cb ("bpf/test_run: fix unkillable
BPF_PROG_TEST_RUN").

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
fomichev authored and borkmann committed Feb 25, 2019
1 parent fd92d66 commit a439184
Showing 1 changed file with 20 additions and 6 deletions.
26 changes: 20 additions & 6 deletions net/bpf/test_run.c
Original file line number Diff line number Diff line change
Expand Up @@ -293,31 +293,45 @@ int bpf_prog_test_run_flow_dissector(struct bpf_prog *prog,
if (!repeat)
repeat = 1;

rcu_read_lock();
preempt_disable();
time_start = ktime_get_ns();
for (i = 0; i < repeat; i++) {
preempt_disable();
rcu_read_lock();
retval = __skb_flow_bpf_dissect(prog, skb,
&flow_keys_dissector,
&flow_keys);
rcu_read_unlock();
preempt_enable();

if (signal_pending(current)) {
preempt_enable();
rcu_read_unlock();

ret = -EINTR;
goto out;
}

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);
duration = time_spent > U32_MAX ? U32_MAX : (u32)time_spent;

ret = bpf_test_finish(kattr, uattr, &flow_keys, sizeof(flow_keys),
retval, duration);

out:
kfree_skb(skb);
kfree(sk);
return ret;
Expand Down

0 comments on commit a439184

Please sign in to comment.