• Michael Thalmeier's avatar
    NFC: pn533: Fix socket deadlock · 37f895d7
    Michael Thalmeier authored
    A deadlock can occur when the NFC raw socket is closed while
    the driver is processing a command.
    
    Following is the call graph of the affected situation:
    
    send data via raw_sock:
    -------------
    rawsock_tx_work
      sock_hold => socket refcnt++
      nfc_data_exchange => cb = rawsock_data_exchange_complete
    
        ops->im_transceive = pn533_transceive => arg->cb = db
                                   = rawsock_data_exchange_complete
    
          pn533_send_data_async => cb = pn533_data_exchange_complete
    
            __pn533_send_async => cmd->complete_cb = cb
                                  = pn533_data_exchange_complete
    
              if_ops->send_frame_async
    
    response:
    --------
    pn533_recv_response
      queue_work(priv->wq, &priv->cmd_complete_work)
    
    pn533_wq_cmd_complete
    
      pn533_send_async_complete
    
        cmd->complete_cb() = pn533_data_exchange_complete()
    
          arg->cb() = rawsock_data_exchange_complete()
    
            sock_put => socket refcnt-- => If the corresponding
                        socket gets closed in the meantime socket
                        will be destructed
    
              sk_free
    
                __sk_free
    
                  sk->sk_destruct = rawsock_destruct
    
                    nfc_deactivate_target
    
                      ops->deactivate_target = pn533_deactivate_target
    
                        pn533_send_cmd_sync
    
                          pn533_send_cmd_async
    
                            __pn533_send_async
    
                              list_add_tail(&cmd->queue,&dev->cmd_queue)
                                      => add to command list because
                                         a command is currently
                                         processed
    
                            wait_for_completion
                                       => the workqueue thread waits
                                          here because it is the one
                                          processing the commands
                                             => deadlock
    
    To fix the deadlock pn533_deactivate_target is changed to
    issue the PN533_CMD_IN_RELEASE command in async mode. This
    way nothing blocks and the release command is executed after
    the current command.
    Signed-off-by: default avatarMichael Thalmeier <michael.thalmeier@hale.at>
    Signed-off-by: default avatarSamuel Ortiz <sameo@linux.intel.com>
    37f895d7
pn533.c 76.2 KB