diff mbox series

[net-next] net/smc: init conn.tx_work & conn.send_lock sooner

Message ID 20180517105421.182397-1-edumazet@google.com
State Accepted, archived
Delegated to: David Miller
Headers show
Series [net-next] net/smc: init conn.tx_work & conn.send_lock sooner | expand

Commit Message

Eric Dumazet May 17, 2018, 10:54 a.m. UTC
syzkaller found that following program crashes the host :

{
  int fd = socket(AF_SMC, SOCK_STREAM, 0);
  int val = 1;

  listen(fd, 0);
  shutdown(fd, SHUT_RDWR);
  setsockopt(fd, 6, TCP_NODELAY, &val, 4);
}

Simply initialize conn.tx_work & conn.send_lock at socket creation,
rather than deeper in the stack.

ODEBUG: assert_init not available (active state 0) object type: timer_list hint:           (null)
WARNING: CPU: 1 PID: 13988 at lib/debugobjects.c:329 debug_print_object+0x16a/0x210 lib/debugobjects.c:326
Kernel panic - not syncing: panic_on_warn set ...

CPU: 1 PID: 13988 Comm: syz-executor0 Not tainted 4.17.0-rc4+ #46
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011
Call Trace:
 __dump_stack lib/dump_stack.c:77 [inline]
 dump_stack+0x1b9/0x294 lib/dump_stack.c:113
 panic+0x22f/0x4de kernel/panic.c:184
 __warn.cold.8+0x163/0x1b3 kernel/panic.c:536
 report_bug+0x252/0x2d0 lib/bug.c:186
 fixup_bug arch/x86/kernel/traps.c:178 [inline]
 do_error_trap+0x1de/0x490 arch/x86/kernel/traps.c:296
 do_invalid_op+0x1b/0x20 arch/x86/kernel/traps.c:315
 invalid_op+0x14/0x20 arch/x86/entry/entry_64.S:992
RIP: 0010:debug_print_object+0x16a/0x210 lib/debugobjects.c:326
RSP: 0018:ffff880197a37880 EFLAGS: 00010086
RAX: 0000000000000061 RBX: 0000000000000005 RCX: ffffc90001ed0000
RDX: 0000000000004aaf RSI: ffffffff8160f6f1 RDI: 0000000000000001
RBP: ffff880197a378c0 R08: ffff8801aa7a0080 R09: ffffed003b5e3eb2
R10: ffffed003b5e3eb2 R11: ffff8801daf1f597 R12: 0000000000000001
R13: ffffffff88d96980 R14: ffffffff87fa19a0 R15: ffffffff81666ec0
 debug_object_assert_init+0x309/0x500 lib/debugobjects.c:692
 debug_timer_assert_init kernel/time/timer.c:724 [inline]
 debug_assert_init kernel/time/timer.c:776 [inline]
 del_timer+0x74/0x140 kernel/time/timer.c:1198
 try_to_grab_pending+0x439/0x9a0 kernel/workqueue.c:1223
 mod_delayed_work_on+0x91/0x250 kernel/workqueue.c:1592
 mod_delayed_work include/linux/workqueue.h:541 [inline]
 smc_setsockopt+0x387/0x6d0 net/smc/af_smc.c:1367
 __sys_setsockopt+0x1bd/0x390 net/socket.c:1903
 __do_sys_setsockopt net/socket.c:1914 [inline]
 __se_sys_setsockopt net/socket.c:1911 [inline]
 __x64_sys_setsockopt+0xbe/0x150 net/socket.c:1911
 do_syscall_64+0x1b1/0x800 arch/x86/entry/common.c:287
 entry_SYSCALL_64_after_hwframe+0x49/0xbe

Fixes: 01d2f7e2cdd3 ("net/smc: sockopts TCP_NODELAY and TCP_CORK")
Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: Ursula Braun <ubraun@linux.ibm.com>
Cc: linux-s390@vger.kernel.org
Reported-by: syzbot <syzkaller@googlegroups.com>
---
 net/smc/af_smc.c | 2 ++
 net/smc/smc_tx.c | 4 +---
 net/smc/smc_tx.h | 1 +
 3 files changed, 4 insertions(+), 3 deletions(-)

Comments

Ursula Braun May 17, 2018, 12:13 p.m. UTC | #1
On 05/17/2018 12:54 PM, Eric Dumazet wrote:
> syzkaller found that following program crashes the host :
> 
> {
>   int fd = socket(AF_SMC, SOCK_STREAM, 0);
>   int val = 1;
> 
>   listen(fd, 0);
>   shutdown(fd, SHUT_RDWR);
>   setsockopt(fd, 6, TCP_NODELAY, &val, 4);
> }
> 
> Simply initialize conn.tx_work & conn.send_lock at socket creation,
> rather than deeper in the stack.
> 
> ODEBUG: assert_init not available (active state 0) object type: timer_list hint:           (null)
> WARNING: CPU: 1 PID: 13988 at lib/debugobjects.c:329 debug_print_object+0x16a/0x210 lib/debugobjects.c:326
> Kernel panic - not syncing: panic_on_warn set ...
> 
> CPU: 1 PID: 13988 Comm: syz-executor0 Not tainted 4.17.0-rc4+ #46
> Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011
> Call Trace:
>  __dump_stack lib/dump_stack.c:77 [inline]
>  dump_stack+0x1b9/0x294 lib/dump_stack.c:113
>  panic+0x22f/0x4de kernel/panic.c:184
>  __warn.cold.8+0x163/0x1b3 kernel/panic.c:536
>  report_bug+0x252/0x2d0 lib/bug.c:186
>  fixup_bug arch/x86/kernel/traps.c:178 [inline]
>  do_error_trap+0x1de/0x490 arch/x86/kernel/traps.c:296
>  do_invalid_op+0x1b/0x20 arch/x86/kernel/traps.c:315
>  invalid_op+0x14/0x20 arch/x86/entry/entry_64.S:992
> RIP: 0010:debug_print_object+0x16a/0x210 lib/debugobjects.c:326
> RSP: 0018:ffff880197a37880 EFLAGS: 00010086
> RAX: 0000000000000061 RBX: 0000000000000005 RCX: ffffc90001ed0000
> RDX: 0000000000004aaf RSI: ffffffff8160f6f1 RDI: 0000000000000001
> RBP: ffff880197a378c0 R08: ffff8801aa7a0080 R09: ffffed003b5e3eb2
> R10: ffffed003b5e3eb2 R11: ffff8801daf1f597 R12: 0000000000000001
> R13: ffffffff88d96980 R14: ffffffff87fa19a0 R15: ffffffff81666ec0
>  debug_object_assert_init+0x309/0x500 lib/debugobjects.c:692
>  debug_timer_assert_init kernel/time/timer.c:724 [inline]
>  debug_assert_init kernel/time/timer.c:776 [inline]
>  del_timer+0x74/0x140 kernel/time/timer.c:1198
>  try_to_grab_pending+0x439/0x9a0 kernel/workqueue.c:1223
>  mod_delayed_work_on+0x91/0x250 kernel/workqueue.c:1592
>  mod_delayed_work include/linux/workqueue.h:541 [inline]
>  smc_setsockopt+0x387/0x6d0 net/smc/af_smc.c:1367
>  __sys_setsockopt+0x1bd/0x390 net/socket.c:1903
>  __do_sys_setsockopt net/socket.c:1914 [inline]
>  __se_sys_setsockopt net/socket.c:1911 [inline]
>  __x64_sys_setsockopt+0xbe/0x150 net/socket.c:1911
>  do_syscall_64+0x1b1/0x800 arch/x86/entry/common.c:287
>  entry_SYSCALL_64_after_hwframe+0x49/0xbe
>

This problem should no longer show up with yesterday's net-next commit
569bc6436568 ("net/smc: no tx work trigger for fallback sockets").
 
> Fixes: 01d2f7e2cdd3 ("net/smc: sockopts TCP_NODELAY and TCP_CORK")
> Signed-off-by: Eric Dumazet <edumazet@google.com>
> Cc: Ursula Braun <ubraun@linux.ibm.com>
> Cc: linux-s390@vger.kernel.org
> Reported-by: syzbot <syzkaller@googlegroups.com>
> ---
>  net/smc/af_smc.c | 2 ++
>  net/smc/smc_tx.c | 4 +---
>  net/smc/smc_tx.h | 1 +
>  3 files changed, 4 insertions(+), 3 deletions(-)
> 
> diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c
> index d15762b057c0d8d4167feca9a4c41f0408604c37..6ad4f6c771c3fa63d3ae714dbe65879910963a21 100644
> --- a/net/smc/af_smc.c
> +++ b/net/smc/af_smc.c
> @@ -193,8 +193,10 @@ static struct sock *smc_sock_alloc(struct net *net, struct socket *sock,
>  	sk->sk_protocol = protocol;
>  	smc = smc_sk(sk);
>  	INIT_WORK(&smc->tcp_listen_work, smc_tcp_listen_work);
> +	INIT_DELAYED_WORK(&smc->conn.tx_work, smc_tx_work);
>  	INIT_LIST_HEAD(&smc->accept_q);
>  	spin_lock_init(&smc->accept_q_lock);
> +	spin_lock_init(&smc->conn.send_lock);
>  	sk->sk_prot->hash(sk);
>  	sk_refcnt_debug_inc(sk);
>  
> diff --git a/net/smc/smc_tx.c b/net/smc/smc_tx.c
> index 58dfe0bd9d6075b5d3db97c659999b364b97da73..08a7de98bb031b5d2256e3238236108749e7ae39 100644
> --- a/net/smc/smc_tx.c
> +++ b/net/smc/smc_tx.c
> @@ -450,7 +450,7 @@ int smc_tx_sndbuf_nonempty(struct smc_connection *conn)
>  /* Wakeup sndbuf consumers from process context
>   * since there is more data to transmit
>   */
> -static void smc_tx_work(struct work_struct *work)
> +void smc_tx_work(struct work_struct *work)
>  {
>  	struct smc_connection *conn = container_of(to_delayed_work(work),
>  						   struct smc_connection,
> @@ -512,6 +512,4 @@ void smc_tx_consumer_update(struct smc_connection *conn)
>  void smc_tx_init(struct smc_sock *smc)
>  {
>  	smc->sk.sk_write_space = smc_tx_write_space;
> -	INIT_DELAYED_WORK(&smc->conn.tx_work, smc_tx_work);
> -	spin_lock_init(&smc->conn.send_lock);
>  }
> diff --git a/net/smc/smc_tx.h b/net/smc/smc_tx.h
> index 78255964fa4dc1c69f96548e035e74a167999a62..8f64b12bf03c1b52c599b1239784a404efe65dae 100644
> --- a/net/smc/smc_tx.h
> +++ b/net/smc/smc_tx.h
> @@ -27,6 +27,7 @@ static inline int smc_tx_prepared_sends(struct smc_connection *conn)
>  	return smc_curs_diff(conn->sndbuf_size, &sent, &prep);
>  }
>  
> +void smc_tx_work(struct work_struct *work);
>  void smc_tx_init(struct smc_sock *smc);
>  int smc_tx_sendmsg(struct smc_sock *smc, struct msghdr *msg, size_t len);
>  int smc_tx_sndbuf_nonempty(struct smc_connection *conn);
>
Eric Dumazet May 17, 2018, 12:20 p.m. UTC | #2
On Thu, May 17, 2018 at 5:13 AM Ursula Braun <ubraun@linux.ibm.com> wrote:

> This problem should no longer show up with yesterday's net-next commit
> 569bc6436568 ("net/smc: no tx work trigger for fallback sockets").

It definitely triggers on latest net-next, which includes 569bc6436568

Thanks.
Ursula Braun May 17, 2018, 1:57 p.m. UTC | #3
On 05/17/2018 02:20 PM, Eric Dumazet wrote:
> On Thu, May 17, 2018 at 5:13 AM Ursula Braun <ubraun@linux.ibm.com> wrote:
> 
>> This problem should no longer show up with yesterday's net-next commit
>> 569bc6436568 ("net/smc: no tx work trigger for fallback sockets").
> 
> It definitely triggers on latest net-next, which includes 569bc6436568
> 
> Thanks.
> 

Sorry, my fault. 

Your proposed patch solves the problem. On the other hand the purpose of
smc_tx_init() has been to cover tx-related socket initializations needed for
connection sockets only. tx_work is something that should be scheduled only
for active connection sockets in non-fallback mode.
Thus I prefer this alternate patch to solve the problem:

---
 net/smc/af_smc.c |    8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

--- a/net/smc/af_smc.c
+++ b/net/smc/af_smc.c
@@ -1362,14 +1362,18 @@ static int smc_setsockopt(struct socket
 		}
 		break;
 	case TCP_NODELAY:
-		if (sk->sk_state != SMC_INIT && sk->sk_state != SMC_LISTEN) {
+		if (sk->sk_state != SMC_INIT &&
+		    sk->sk_state != SMC_LISTEN &&
+		    sk->sk_state != SMC_CLOSED) {
 			if (val && !smc->use_fallback)
 				mod_delayed_work(system_wq, &smc->conn.tx_work,
 						 0);
 		}
 		break;
 	case TCP_CORK:
-		if (sk->sk_state != SMC_INIT && sk->sk_state != SMC_LISTEN) {
+		if (sk->sk_state != SMC_INIT &&
+		    sk->sk_state != SMC_LISTEN &&
+		    sk->sk_state != SMC_CLOSED) {
 			if (!val && !smc->use_fallback)
 				mod_delayed_work(system_wq, &smc->conn.tx_work,
 						 0);

What do you think?
Eric Dumazet May 17, 2018, 3:28 p.m. UTC | #4
On Thu, May 17, 2018 at 6:58 AM Ursula Braun <ubraun@linux.ibm.com> wrote:



> On 05/17/2018 02:20 PM, Eric Dumazet wrote:
> > On Thu, May 17, 2018 at 5:13 AM Ursula Braun <ubraun@linux.ibm.com>
wrote:
> >
> >> This problem should no longer show up with yesterday's net-next commit
> >> 569bc6436568 ("net/smc: no tx work trigger for fallback sockets").
> >
> > It definitely triggers on latest net-next, which includes 569bc6436568
> >
> > Thanks.
> >

> Sorry, my fault.

> Your proposed patch solves the problem. On the other hand the purpose of
> smc_tx_init() has been to cover tx-related socket initializations needed
for
> connection sockets only. tx_work is something that should be scheduled
only
> for active connection sockets in non-fallback mode.
> Thus I prefer this alternate patch to solve the problem:

> ---
>   net/smc/af_smc.c |    8 ++++++--
>   1 file changed, 6 insertions(+), 2 deletions(-)

> --- a/net/smc/af_smc.c
> +++ b/net/smc/af_smc.c
> @@ -1362,14 +1362,18 @@ static int smc_setsockopt(struct socket
>                  }
>                  break;
>          case TCP_NODELAY:
> -               if (sk->sk_state != SMC_INIT && sk->sk_state !=
SMC_LISTEN) {
> +               if (sk->sk_state != SMC_INIT &&
> +                   sk->sk_state != SMC_LISTEN &&
> +                   sk->sk_state != SMC_CLOSED) {
>                          if (val && !smc->use_fallback)
>                                  mod_delayed_work(system_wq,
&smc->conn.tx_work,
>                                                   0);
>                  }
>                  break;
>          case TCP_CORK:
> -               if (sk->sk_state != SMC_INIT && sk->sk_state !=
SMC_LISTEN) {
> +               if (sk->sk_state != SMC_INIT &&
> +                   sk->sk_state != SMC_LISTEN &&
> +                   sk->sk_state != SMC_CLOSED) {
>                          if (!val && !smc->use_fallback)
>                                  mod_delayed_work(system_wq,
&smc->conn.tx_work,
>                                                   0);

> What do you think?

I think my patch is cleaner.

Deferring spinlock and workqueues setup is a recipe for disaster.
Ursula Braun May 17, 2018, 4:30 p.m. UTC | #5
On 05/17/2018 05:28 PM, Eric Dumazet wrote:
> On Thu, May 17, 2018 at 6:58 AM Ursula Braun <ubraun@linux.ibm.com> wrote:
> 
> 
> 
>> On 05/17/2018 02:20 PM, Eric Dumazet wrote:
>>> On Thu, May 17, 2018 at 5:13 AM Ursula Braun <ubraun@linux.ibm.com>
> wrote:
>>>
>>>> This problem should no longer show up with yesterday's net-next commit
>>>> 569bc6436568 ("net/smc: no tx work trigger for fallback sockets").
>>>
>>> It definitely triggers on latest net-next, which includes 569bc6436568
>>>
>>> Thanks.
>>>
> 
>> Sorry, my fault.
> 
>> Your proposed patch solves the problem. On the other hand the purpose of
>> smc_tx_init() has been to cover tx-related socket initializations needed
> for
>> connection sockets only. tx_work is something that should be scheduled
> only
>> for active connection sockets in non-fallback mode.
>> Thus I prefer this alternate patch to solve the problem:
> 
>> ---
>>   net/smc/af_smc.c |    8 ++++++--
>>   1 file changed, 6 insertions(+), 2 deletions(-)
> 
>> --- a/net/smc/af_smc.c
>> +++ b/net/smc/af_smc.c
>> @@ -1362,14 +1362,18 @@ static int smc_setsockopt(struct socket
>>                  }
>>                  break;
>>          case TCP_NODELAY:
>> -               if (sk->sk_state != SMC_INIT && sk->sk_state !=
> SMC_LISTEN) {
>> +               if (sk->sk_state != SMC_INIT &&
>> +                   sk->sk_state != SMC_LISTEN &&
>> +                   sk->sk_state != SMC_CLOSED) {
>>                          if (val && !smc->use_fallback)
>>                                  mod_delayed_work(system_wq,
> &smc->conn.tx_work,
>>                                                   0);
>>                  }
>>                  break;
>>          case TCP_CORK:
>> -               if (sk->sk_state != SMC_INIT && sk->sk_state !=
> SMC_LISTEN) {
>> +               if (sk->sk_state != SMC_INIT &&
>> +                   sk->sk_state != SMC_LISTEN &&
>> +                   sk->sk_state != SMC_CLOSED) {
>>                          if (!val && !smc->use_fallback)
>>                                  mod_delayed_work(system_wq,
> &smc->conn.tx_work,
>>                                                   0);
> 
>> What do you think?
> 
> I think my patch is cleaner.
> 
> Deferring spinlock and workqueues setup is a recipe for disaster.
> 

If your solution is preferred, I agree. In this case my today's net/smc patch
   net/smc: initialize tx_work before llc initial handshake
for the net-tree is obsolete.
David Miller May 17, 2018, 8:25 p.m. UTC | #6
From: Eric Dumazet <edumazet@google.com>
Date: Thu, 17 May 2018 03:54:21 -0700

> syzkaller found that following program crashes the host :
> 
> {
>   int fd = socket(AF_SMC, SOCK_STREAM, 0);
>   int val = 1;
> 
>   listen(fd, 0);
>   shutdown(fd, SHUT_RDWR);
>   setsockopt(fd, 6, TCP_NODELAY, &val, 4);
> }
> 
> Simply initialize conn.tx_work & conn.send_lock at socket creation,
> rather than deeper in the stack.
 ...
> Fixes: 01d2f7e2cdd3 ("net/smc: sockopts TCP_NODELAY and TCP_CORK")
> Signed-off-by: Eric Dumazet <edumazet@google.com>
> Cc: Ursula Braun <ubraun@linux.ibm.com>
> Cc: linux-s390@vger.kernel.org
> Reported-by: syzbot <syzkaller@googlegroups.com>

Applied, thanks Eric.
diff mbox series

Patch

diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c
index d15762b057c0d8d4167feca9a4c41f0408604c37..6ad4f6c771c3fa63d3ae714dbe65879910963a21 100644
--- a/net/smc/af_smc.c
+++ b/net/smc/af_smc.c
@@ -193,8 +193,10 @@  static struct sock *smc_sock_alloc(struct net *net, struct socket *sock,
 	sk->sk_protocol = protocol;
 	smc = smc_sk(sk);
 	INIT_WORK(&smc->tcp_listen_work, smc_tcp_listen_work);
+	INIT_DELAYED_WORK(&smc->conn.tx_work, smc_tx_work);
 	INIT_LIST_HEAD(&smc->accept_q);
 	spin_lock_init(&smc->accept_q_lock);
+	spin_lock_init(&smc->conn.send_lock);
 	sk->sk_prot->hash(sk);
 	sk_refcnt_debug_inc(sk);
 
diff --git a/net/smc/smc_tx.c b/net/smc/smc_tx.c
index 58dfe0bd9d6075b5d3db97c659999b364b97da73..08a7de98bb031b5d2256e3238236108749e7ae39 100644
--- a/net/smc/smc_tx.c
+++ b/net/smc/smc_tx.c
@@ -450,7 +450,7 @@  int smc_tx_sndbuf_nonempty(struct smc_connection *conn)
 /* Wakeup sndbuf consumers from process context
  * since there is more data to transmit
  */
-static void smc_tx_work(struct work_struct *work)
+void smc_tx_work(struct work_struct *work)
 {
 	struct smc_connection *conn = container_of(to_delayed_work(work),
 						   struct smc_connection,
@@ -512,6 +512,4 @@  void smc_tx_consumer_update(struct smc_connection *conn)
 void smc_tx_init(struct smc_sock *smc)
 {
 	smc->sk.sk_write_space = smc_tx_write_space;
-	INIT_DELAYED_WORK(&smc->conn.tx_work, smc_tx_work);
-	spin_lock_init(&smc->conn.send_lock);
 }
diff --git a/net/smc/smc_tx.h b/net/smc/smc_tx.h
index 78255964fa4dc1c69f96548e035e74a167999a62..8f64b12bf03c1b52c599b1239784a404efe65dae 100644
--- a/net/smc/smc_tx.h
+++ b/net/smc/smc_tx.h
@@ -27,6 +27,7 @@  static inline int smc_tx_prepared_sends(struct smc_connection *conn)
 	return smc_curs_diff(conn->sndbuf_size, &sent, &prep);
 }
 
+void smc_tx_work(struct work_struct *work);
 void smc_tx_init(struct smc_sock *smc);
 int smc_tx_sendmsg(struct smc_sock *smc, struct msghdr *msg, size_t len);
 int smc_tx_sndbuf_nonempty(struct smc_connection *conn);