REDHAT-BUG-2346272: Medium severity linux/linux-kernel vulnerability
In the Linux kernel, the following vulnerability has been resolved:
pfifotailenqueue: Drop new packet when sch->limit == 0
Expected behaviour: In case we reach scheduler's limit, pfifotailenqueue() will drop a packet in scheduler's queue and decrease scheduler's qlen by one. Then, pfifotailenqueue() enqueue new packet and increase scheduler's qlen by one. Finally, pfifotailenqueue() return NETXMITCN status code.
Weird behaviour: In case we set sch->limit == 0 and trigger pfifotailenqueue() on a scheduler that has no packet, the 'drop a packet' step will do nothing. This means the scheduler's qlen still has value equal 0. Then, we continue to enqueue new packet and increase scheduler's qlen by one. In summary, we can leverage pfifotailenqueue() to increase qlen by one and return NETXMITCN status code.
The problem is: Let's say we have two qdiscs: QdiscA and QdiscB. - QdiscA's type must have '->graft()' function to create parent/child relationship. Let's say QdiscA's type is hfsc. Enqueue packet to this qdisc will trigger hfscenqueue. - QdiscB's type is pfifoheaddrop. Enqueue packet to this qdisc will trigger pfifotailenqueue. - QdiscB is configured to have sch->limit == 0. - QdiscA is configured to route the enqueued's packet to QdiscB.
Enqueue packet through QdiscA will lead to: - hfscenqueue(QdiscA) -> pfifotailenqueue(QdiscB) - QdiscB->q.qlen += 1 - pfifotailenqueue() return NETXMITCN - hfscenqueue() check for NETXMITSUCCESS and see NETXMITCN => hfscenqueue() don't increase qlen of QdiscA.
The whole process lead to a situation where QdiscA->q.qlen == 0 and QdiscB->q.qlen == 1. Replace 'hfsc' with other type (for example: 'drr') still lead to the same problem. This violate the design where parent's qlen should equal to the sum of its childrens'qlen.
Bug impact: This issue can be used for user->kernel privilege escalation when it is reachable.
Affected Software
Event History
Frequently Asked Questions
Which traffic-control configuration is exposed to the described behavior?
The trigger requires a scheduler with sch->limit set to 0 and an enqueue attempt while its queue is empty. The described topology uses an hfsc qdisc as a parent capable of grafting a child qdisc, with a pfifo_head_drop child whose enqueue path calls pfifo_tail_enqueue().
What can be done if the fix cannot be applied immediately?
Avoid configuring the affected scheduler with a limit of 0. The described incorrect queue-length increase depends on sch->limit being 0 when pfifo_tail_enqueue() is triggered on an empty queue.
How can the problematic behavior be recognized?
On an empty scheduler with a zero limit, an enqueue can increase qlen from 0 to 1 even though the operation returns NET_XMIT_CN. This occurs because the attempted drop does nothing before the new packet is enqueued.