Re: net/dccp: warning in dccp_feat_clone_sp_val/__might_sleep

From: Cong Wang
Date: Sat Oct 29 2016 - 02:12:01 EST


On Fri, Oct 28, 2016 at 5:40 PM, Andrey Konovalov <andreyknvl@xxxxxxxxxx> wrote:
> Hi,
>
> I've got the following error report while running the syzkaller fuzzer:
>
> ------------[ cut here ]------------
> WARNING: CPU: 0 PID: 4608 at kernel/sched/core.c:7724
> __might_sleep+0x14c/0x1a0 kernel/sched/core.c:7719
> do not call blocking ops when !TASK_RUNNING; state=1 set at
> [<ffffffff811f5a5c>] prepare_to_wait+0xbc/0x210
> kernel/sched/wait.c:178
> Modules linked in:
> CPU: 0 PID: 4608 Comm: syz-executor Not tainted 4.9.0-rc2+ #320
> Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Bochs 01/01/2011
> ffff88006625f7a0 ffffffff81b46914 ffff88006625f818 0000000000000000
> ffffffff84052960 0000000000000000 ffff88006625f7e8 ffffffff81111237
> ffff88006aceac00 ffffffff00001e2c ffffed000cc4beff ffffffff84052960
> Call Trace:
> [< inline >] __dump_stack lib/dump_stack.c:15
> [<ffffffff81b46914>] dump_stack+0xb3/0x10f lib/dump_stack.c:51
> [<ffffffff81111237>] __warn+0x1a7/0x1f0 kernel/panic.c:550
> [<ffffffff8111132c>] warn_slowpath_fmt+0xac/0xd0 kernel/panic.c:565
> [<ffffffff811922fc>] __might_sleep+0x14c/0x1a0 kernel/sched/core.c:7719
> [< inline >] slab_pre_alloc_hook mm/slab.h:393
> [< inline >] slab_alloc_node mm/slub.c:2634
> [< inline >] slab_alloc mm/slub.c:2716
> [<ffffffff81508da0>] __kmalloc_track_caller+0x150/0x2a0 mm/slub.c:4240
> [<ffffffff8146be14>] kmemdup+0x24/0x50 mm/util.c:113
> [<ffffffff8388b2cf>] dccp_feat_clone_sp_val.part.5+0x4f/0xe0
> net/dccp/feat.c:374
> [< inline >] dccp_feat_clone_sp_val net/dccp/feat.c:1141
> [< inline >] dccp_feat_change_recv net/dccp/feat.c:1141
> [<ffffffff8388d491>] dccp_feat_parse_options+0xaa1/0x13d0 net/dccp/feat.c:1411
> [<ffffffff83894f01>] dccp_parse_options+0x721/0x1010 net/dccp/options.c:128
> [<ffffffff83891280>] dccp_rcv_state_process+0x200/0x15b0 net/dccp/input.c:644
> [<ffffffff838b8a94>] dccp_v4_do_rcv+0xf4/0x1a0 net/dccp/ipv4.c:681
> [< inline >] sk_backlog_rcv ./include/net/sock.h:872
> [<ffffffff82b7ceb6>] __release_sock+0x126/0x3a0 net/core/sock.c:2044
> [<ffffffff82b7d189>] release_sock+0x59/0x1c0 net/core/sock.c:2502
> [< inline >] inet_wait_for_connect net/ipv4/af_inet.c:547
> [<ffffffff8316b2a2>] __inet_stream_connect+0x5d2/0xbb0 net/ipv4/af_inet.c:617
> [<ffffffff8316b8d5>] inet_stream_connect+0x55/0xa0 net/ipv4/af_inet.c:656
> [<ffffffff82b705e4>] SYSC_connect+0x244/0x2f0 net/socket.c:1533
> [<ffffffff82b72dd4>] SyS_connect+0x24/0x30 net/socket.c:1514
> [<ffffffff83fbf701>] entry_SYSCALL_64_fastpath+0x1f/0xc2
> arch/x86/entry/entry_64.S:209

Should be fixed the attached patch. I will verify it with your
reproducer tomorrow.

Thanks!
diff --git a/net/dccp/feat.c b/net/dccp/feat.c
index 1704948..c90cb35 100644
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -367,11 +367,11 @@ static inline int dccp_feat_must_be_understood(u8 feat_num)
}

/* copy constructor, fval must not already contain allocated memory */
-static int dccp_feat_clone_sp_val(dccp_feat_val *fval, u8 const *val, u8 len)
+static int dccp_feat_clone_sp_val(dccp_feat_val *fval, u8 const *val, u8 len, gfp_t flags)
{
fval->sp.len = len;
if (fval->sp.len > 0) {
- fval->sp.vec = kmemdup(val, len, gfp_any());
+ fval->sp.vec = kmemdup(val, len, flags);
if (fval->sp.vec == NULL) {
fval->sp.len = 0;
return -ENOBUFS;
@@ -404,7 +404,8 @@ static void dccp_feat_val_destructor(u8 feat_num, dccp_feat_val *val)

if (type == FEAT_SP && dccp_feat_clone_sp_val(&new->val,
original->val.sp.vec,
- original->val.sp.len)) {
+ original->val.sp.len,
+ gfp_any())) {
kfree(new);
return NULL;
}
@@ -735,7 +736,7 @@ static int __feat_register_sp(struct list_head *fn, u8 feat, u8 is_local,
if (feat == DCCPF_CCID && !ccid_support_check(sp_val, sp_len))
return -EOPNOTSUPP;

- if (dccp_feat_clone_sp_val(&fval, sp_val, sp_len))
+ if (dccp_feat_clone_sp_val(&fval, sp_val, sp_len, gfp_any()))
return -ENOMEM;

return dccp_feat_push_change(fn, feat, is_local, mandatory, &fval);
@@ -1138,7 +1139,7 @@ static u8 dccp_feat_change_recv(struct list_head *fn, u8 is_mandatory, u8 opt,
* otherwise we accept the preferred value;
* - else if we are the client, we use the first list element.
*/
- if (dccp_feat_clone_sp_val(&fval, val, 1))
+ if (dccp_feat_clone_sp_val(&fval, val, 1, GFP_ATOMIC))
return DCCP_RESET_CODE_TOO_BUSY;

if (len > 1 && server) {