net: prevent infinite loop caused by incorrect proto from virtio_net_hdr_set_proto
Subsystems (4)
v3 cover net: prevent infinite loop caused by incorrect proto from virtio_net_hdr_set_proto
These patches prevent an infinite loop for gso packets with a protocol from virtio net hdr that doesn't match the protocol in the packet. Note that packets coming from a device without header_ops->parse_protocol being implemented will not be caught by the check in virtio_net_hdr_to_skb, but the infinite loop will still be prevented by the check in the gso layer.
Changes from v2 to v3:
- Remove unused *eth.
- Use MPLS_HLEN to also check if the MPLS header length is a multiple of four.
Balazs Nemeth (2):
net: check if protocol extracted by virtio_net_hdr_set_proto is
correct
net: avoid infinite loop in mpls_gso_segment when mpls_hlen == 0
include/linux/virtio_net.h | 7 ++++++- net/mpls/mpls_gso.c | 3 +++ 2 files changed, 9 insertions(+), 1 deletion(-)
--
2.29.2
PATCH v3 1/2 net: check if protocol extracted by virtio_net_hdr_set_proto is correct
For gso packets, virtio_net_hdr_set_proto sets the protocol (if it isn't set) based on the type in the virtio net hdr, but the skb could contain anything since it could come from packet_snd through a raw socket. If there is a mismatch between what virtio_net_hdr_set_proto sets and the actual protocol, then the skb could be handled incorrectly later on.
An example where this poses an issue is with the subsequent call to skb_flow_dissect_flow_keys_basic which relies on skb->protocol being set correctly. A specially crafted packet could fool skb_flow_dissect_flow_keys_basic preventing EINVAL to be returned.
Avoid blindly trusting the information provided by the virtio net header by checking that the protocol in the packet actually matches the protocol set by virtio_net_hdr_set_proto. Note that since the protocol is only checked if skb->dev implements header_ops->parse_protocol, packets from devices without the implementation are not checked at this stage.
--- include/linux/virtio_net.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
include/linux/virtio_net.h +6 -1
@@ -79,8 +79,13 @@ static inline int virtio_net_hdr_to_skb(struct sk_buff *skb, if (gso_type && skb->network_header) { struct flow_keys_basic keys; - if (!skb->protocol) + if (!skb->protocol) { + __be16 protocol = dev_parse_header_protocol(skb); + virtio_net_hdr_set_proto(skb, hdr); + if (protocol && protocol != skb->protocol) + return -EINVAL; + } retry: if (!skb_flow_dissect_flow_keys_basic(NULL, skb, &keys, NULL, 0, 0, 0,
Signature · 1 line
2.29.2
Re: [PATCH net v3 1/2] net: check if protocol extracted by virtio_net_hdr_set_proto is correct
Quoted 20 lines · Balazs Nemeth
For gso packets,
virtio_net_hdr_set_protosets the protocol (if it isn't set) based on the type in the virtio net hdr, but the skb could contain anything since it could come frompacket_sndthrough a raw socket. If there is a mismatch between whatvirtio_net_hdr_set_protosets and the actual protocol, then the skb could be handled incorrectly later on.An example where this poses an issue is with the subsequent call to
skb_flow_dissect_flow_keys_basicwhich relies onskb->protocolbeing set correctly. A specially crafted packet could foolskb_flow_dissect_flow_keys_basicpreventing EINVAL to be returned.Avoid blindly trusting the information provided by the virtio net header by checking that the protocol in the packet actually matches the protocol set by
virtio_net_hdr_set_proto. Note that since the protocol is only checked ifskb->devimplementsheader_ops->parse_protocol, packets from devices without the implementation are not checked at this stage.
Quoted 2 lines
Fixes 9274124f023b ("net: stricter validation of untrusted gso packets")Signed-off-by Balazs Nemeth <[email protected]>
This still relies entirely on data from the untrusted process. But it adds the constraint that the otherwise untrusted data at least has to be consistent, closing one loophole.
As responded in v2, we may want to look at the (few) callers and make sure that they initialize skb->protocol before the call to virtio_net_hdr_to_skb where possible. That will avoid this entire branch.
_______________________________________________
Virtualization mailing list [email protected]
https://lists.linuxfoundation.org/mailman/listinfo/virtualization
PATCH v3 2/2 net: avoid infinite loop in mpls_gso_segment when mpls_hlen == 0
In reply to Balazs NemethA packet with skb_inner_network_header(skb) == skb_network_header(skb) and ETH_P_MPLS_UC will prevent mpls_gso_segment from pulling any headers from the packet. Subsequently, the call to skb_mac_gso_segment will again call mpls_gso_segment with the same packet leading to an infinite loop. In addition, ensure that the header length is a multiple of four, which should hold irrespective of the number of stacked labels.
--- net/mpls/mpls_gso.c | 3 +++ 1 file changed, 3 insertions(+)
net/mpls/mpls_gso.c +3 -0
@@ -14,6 +14,7 @@#include <linux/netdev_features.h> #include <linux/netdevice.h> #include <linux/skbuff.h> +#include <net/mpls.h> static struct sk_buff *mpls_gso_segment (struct sk_buff *skb,netdev_features_t features)
@@ -27,6 +28,8 @@ static struct sk_buff *mpls_gso_segment(struct sk_buff *skb,skb_reset_network_header (skb); mpls_hlen =skb_inner_network_header (skb) -skb_network_header (skb); +if (unlikely (!mpls_hlen || mpls_hlen %MPLS_HLEN )) + goto out;if (unlikely (!pskb_may_pull (skb, mpls_hlen))) goto out;
Signature · 1 line
2.29.2
Re: [PATCH net v3 2/2] net: avoid infinite loop in mpls_gso_segment when mpls_hlen == 0
Quoted 9 lines · Balazs Nemeth
A packet with
skb_inner_network_header(skb)==skb_network_header(skb)andETH_P_MPLS_UCwill preventmpls_gso_segmentfrom pulling any headers from the packet. Subsequently, the call toskb_mac_gso_segmentwill again callmpls_gso_segmentwith the same packet leading to an infinite loop. In addition, ensure that the header length is a multiple of four, which should hold irrespective of the number of stacked labels.Signed-off-by Balazs Nemeth <[email protected]>
The compiler will convert that modulo into a cheap & (ETH_HLEN - 1) test for this constant.
_______________________________________________
Virtualization mailing list [email protected]
https://lists.linuxfoundation.org/mailman/listinfo/virtualization
Re: [PATCH net v3 2/2] net: avoid infinite loop in mpls_gso_segment when mpls_hlen == 0
In reply to Balazs NemethQuoted 7 lines · Balazs Nemeth
A packet with
skb_inner_network_header(skb)==skb_network_header(skb)andETH_P_MPLS_UCwill preventmpls_gso_segmentfrom pulling any headers from the packet. Subsequently, the call toskb_mac_gso_segmentwill again callmpls_gso_segmentwith the same packet leading to an infinite loop. In addition, ensure that the header length is a multiple of four, which should hold irrespective of the number of stacked labels.
Quoted 5 lines
Signed-off-by Balazs Nemeth <[email protected]>--- net/mpls/mpls_gso.c | 3 +++ 1 file changed, 3 insertions(+)
_______________________________________________
Virtualization mailing list
[email protected]
https://lists.linuxfoundation.org/mailman/listinfo/virtualization
This series was applied to netdev/net.git (refs/heads/master):
Hello:
This series was applied to netdev/net.git (refs/heads/master):
Quoted 8 lines · On Tue, 9 Mar 2021 12:30:59 +0100 you wrote:
These patches prevent an infinite loop for gso packets with a protocol from virtio net hdr that doesn't match the protocol in the packet. Note that packets coming from a device without
header_ops->parse_protocolbeing implemented will not be caught by the check invirtio_net_hdr_to_skb, but the infinite loop will still be prevented by the check in the gso layer.[...]
Here is the summary with links:
- [net,v3,1/2] net: check if protocol extracted by virtio_net_hdr_set_proto is correct
https://git.kernel.org/netdev/net/c/924a9bc362a5 - [net,v3,2/2] net: avoid infinite loop in mpls_gso_segment when mpls_hlen == 0 https://git.kernel.org/netdev/net/c/d348ede32e99
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html