lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite for Android: free password hash cracker in your pocket
[<prev] [next>] [day] [month] [year] [list]
Date:	Sun, 1 Apr 2012 12:14:52 -0700
From:	Stephen Hemminger <shemminger@...tta.com>
To:	bugzilla-daemon@...zilla.kernel.org
Cc:	netdev@...r.kernel.org
Subject: Re: [Bug 43018] New: calling function of "dev_queue_xmit()" from a
 interrupt may be deadlock.

Redirecting this to netdev list. 

I don't think this bug is possible in normal flow because of the implicit
rules about network devices:

The network standard output path is never called with interrupts
disabled. It is called with soft interrupt disabled (ie when forwarding).
Where in the standard kernel code do you see a possibility of calling
dev_queue_xmit with from an interrupt?

There is one special case which is the netconsole/netpoll code which
calls the network device transmit directly (ndo_start_xmit). This code
takes special precautions to allow being called from an interrupt routine
and does not go through dev_queue_xmit().


On Sat, 31 Mar 2012 02:10:51 GMT
bugzilla-daemon@...zilla.kernel.org wrote:

> https://bugzilla.kernel.org/show_bug.cgi?id=43018
> 
>            Summary: calling function of "dev_queue_xmit()" from a
>                     interrupt may be deadlock.
>            Product: Networking
>            Version: 2.5
>     Kernel Version: 3.0.26
>           Platform: All
>         OS/Version: Linux
>               Tree: Mainline
>             Status: NEW
>           Severity: normal
>           Priority: P1
>          Component: IPV4
>         AssignedTo: shemminger@...ux-foundation.org
>         ReportedBy: qiuli.wu@...bio.com
>         Regression: No
> 
> 
> Enter this function to send packet:
> 
> static void net_tx_action(struct softirq_action *h)
> {
>     struct softnet_data *sd = &__get_cpu_var(softnet_data);
> 
>     if (sd->completion_queue) {
>         struct sk_buff *clist;
> 
>         local_irq_disable();
>         clist = sd->completion_queue;
>         sd->completion_queue = NULL;
>         local_irq_enable();
> 
>         while (clist) {
>             struct sk_buff *skb = clist;
>             clist = clist->next;
> 
>             WARN_ON(atomic_read(&skb->users));
>             trace_kfree_skb(skb, net_tx_action);
>             __kfree_skb(skb);
>         }
>     }
> 
>     if (sd->output_queue) {
>         struct Qdisc *head;
> 
>         local_irq_disable();
>         head = sd->output_queue;
>         sd->output_queue = NULL;
>         sd->output_queue_tailp = &sd->output_queue;
>         local_irq_enable();
> 
>         while (head) {
>             struct Qdisc *q = head;
>             spinlock_t *root_lock;
> 
>             head = head->next_sched;
> 
>             root_lock = qdisc_lock(q);
>             if (spin_trylock(root_lock)) {
> //##########################################################################
>                                 //here we have got lock of "root_lock",
>                                 //just this time a interrupt coming ,and 
>                                 //in this interrupt I call "dev_queue_xmit" to
>                                 //send skb and the Qdisc is same one.
> //############################################################################ 
>                 smp_mb__before_clear_bit();
>                 clear_bit(__QDISC_STATE_SCHED,
>                       &q->state);
>                 qdisc_run(q);
>                 spin_unlock(root_lock);
>             } else {
>                 if (!test_bit(__QDISC_STATE_DEACTIVATED,
>                           &q->state)) {
>                     __netif_reschedule(q);
>                 } else {
>                     smp_mb__before_clear_bit();
>                     clear_bit(__QDISC_STATE_SCHED,
>                           &q->state);
>                 }
>             }
>         }
>     }
> }
> 
> 
> //int dev_queue_xmit(struct sk_buff *skb)->__dev_xmit_skb
> 
> static inline int __dev_xmit_skb(struct sk_buff *skb, struct Qdisc *q,
>                  struct net_device *dev,
>                  struct netdev_queue *txq)
> {
>     spinlock_t *root_lock = qdisc_lock(q);
>     bool contended;
>     int rc;
> 
>     qdisc_skb_cb(skb)->pkt_len = skb->len;
>     qdisc_calculate_pkt_len(skb, q);
>     /*
>      * Heuristic to force contended enqueues to serialize on a
>      * separate lock before trying to get qdisc main lock.
>      * This permits __QDISC_STATE_RUNNING owner to get the lock more often
>      * and dequeue packets faster.
>      */
>     contended = qdisc_is_running(q);
>     if (unlikely(contended))
>         spin_lock(&q->busylock);
> //############################################################################  
>         //HERE can't get root_lock,because soft interrupt have got it and it be
>         // interrupted .deadlock happen.
> //#############################################################################
>     spin_lock(root_lock);
>     if (unlikely(test_bit(__QDISC_STATE_DEACTIVATED, &q->state))) {
>         kfree_skb(skb);
>         rc = NET_XMIT_DROP;
>     } else if ((q->flags & TCQ_F_CAN_BYPASS) && !qdisc_qlen(q) &&
>            qdisc_run_begin(q)) {
>         /*
>          * This is a work-conserving queue; there are no old skbs
>          * waiting to be sent out; and the qdisc is not running -
>          * xmit the skb directly.
>          */
>         if (!(dev->priv_flags & IFF_XMIT_DST_RELEASE))
>             skb_dst_force(skb);
> 
>         qdisc_bstats_update(q, skb);
> 
>         if (sch_direct_xmit(skb, q, dev, txq, root_lock)) {
>             if (unlikely(contended)) {
>                 spin_unlock(&q->busylock);
>                 contended = false;
>             }
>             __qdisc_run(q);
>         } else
>             qdisc_run_end(q);
> 
>         rc = NET_XMIT_SUCCESS;
>     } else {
>         skb_dst_force(skb);
>         rc = q->enqueue(skb, q) & NET_XMIT_MASK;
>         if (qdisc_run_begin(q)) {
>             if (unlikely(contended)) {
>                 spin_unlock(&q->busylock);
>                 contended = false;
>             }
>             __qdisc_run(q);
>         }
>     }
>     spin_unlock(root_lock);
>     if (unlikely(contended))
>         spin_unlock(&q->busylock);
>     return rc;
> }
> 

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ