]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
rds: tcp: Reorder initialization sequence in rds_tcp_init to avoid races
authorSowmini Varadhan <sowmini.varadhan@oracle.com>
Fri, 16 Jun 2017 19:11:11 +0000 (12:11 -0700)
committerChuck Anderson <chuck.anderson@oracle.com>
Sun, 18 Jun 2017 19:49:36 +0000 (12:49 -0700)
Order of initialization in rds_tcp_init needs to be done so
that resources are set up and destroyed in the correct synchronization
sequence with both the data path, as well as netns create/destroy
path. Specifically,

- we must call register_pernet_subsys and get the rds_tcp_netid
  before calling register_netdevice_notifier, otherwise we risk
  the sequence
    1. register_netdevice_notifier sets up netdev notifier callback
    2. rds_tcp_dev_event -> rds_tcp_kill_sock uses netid 0, and finds
       the wrong rtn, resulting in a panic with string that is of the form:

  BUG: unable to handle kernel NULL pointer dereference at 000000000000000d
  IP: rds_tcp_kill_sock+0x3a/0x1d0 [rds_tcp]
             :

- the rds_tcp_incoming_slab kmem_cache must be initialized before the
  datapath starts up. The latter can happen any time after the
  pernet_subsys registration of rds_tcp_net_ops, whose -> init
  function sets up the listen socket. If the rds_tcp_incoming_slab has
  not been set up at that time, a panic of the form below may be
  encountered

  BUG: unable to handle kernel NULL pointer dereference at 0000000000000014
  IP: kmem_cache_alloc+0x90/0x1c0
         :
  rds_tcp_data_recv+0x1e7/0x370 [rds_tcp]
  tcp_read_sock+0x96/0x1c0
  rds_tcp_recv_path+0x65/0x80 [rds_tcp]
         :

Orabug: 26289770

(Cherry-pick of upstream 16c09b1c7657522a321b04aa7f4300865b7cb292)

Signed-off-by: Sowmini Varadhan <sowmini.varadhan@oracle.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/rds/tcp.c

index db4d5ad590d6a09f4e3a04b10d11c3be47a8c202..5a03f05ea16cbf6875c06ff1f0f86da59926649e 100644 (file)
@@ -636,32 +636,30 @@ static int rds_tcp_init(void)
                goto out;
        }
 
-       ret = register_netdevice_notifier(&rds_tcp_dev_notifier);
-       if (ret) {
-               pr_warn("could not register rds_tcp_dev_notifier\n");
-               goto out;
-       }
-
-       ret = register_pernet_subsys(&rds_tcp_net_ops);
+       ret = rds_tcp_recv_init();
        if (ret)
                goto out_slab;
 
-       ret = rds_tcp_recv_init();
+       ret = register_pernet_subsys(&rds_tcp_net_ops);
        if (ret)
+               goto out_recv;
+
+       ret = register_netdevice_notifier(&rds_tcp_dev_notifier);
+       if (ret) {
+               pr_warn("could not register rds_tcp_dev_notifier\n");
                goto out_pernet;
+       }
 
        ret = rds_trans_register(&rds_tcp_transport);
-       if (ret)
-               goto out_recv;
 
        rds_info_register_func(RDS_INFO_TCP_SOCKETS, rds_tcp_tc_info);
 
        goto out;
 
-out_recv:
-       rds_tcp_recv_exit();
 out_pernet:
        unregister_pernet_subsys(&rds_tcp_net_ops);
+out_recv:
+       rds_tcp_recv_exit();
 out_slab:
        kmem_cache_destroy(rds_tcp_conn_slab);
 out: