]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
net: dsa: microchip: linearize skb for tail-tagging switches
authorJakob Unterwurzacher <jakobunt@gmail.com>
Thu, 15 May 2025 07:29:19 +0000 (09:29 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 29 May 2025 09:14:02 +0000 (11:14 +0200)
commit ba54bce747fa9e07896c1abd9b48545f7b4b31d2 upstream.

The pointer arithmentic for accessing the tail tag only works
for linear skbs.

For nonlinear skbs, it reads uninitialized memory inside the
skb headroom, essentially randomizing the tag. I have observed
it gets set to 6 most of the time.

Example where ksz9477_rcv thinks that the packet from port 1 comes from port 6
(which does not exist for the ksz9896 that's in use), dropping the packet.
Debug prints added by me (not included in this patch):

[  256.645337] ksz9477_rcv:323 tag0=6
[  256.645349] skb len=47 headroom=78 headlen=0 tailroom=0
               mac=(64,14) mac_len=14 net=(78,0) trans=78
               shinfo(txflags=0 nr_frags=1 gso(size=0 type=0 segs=0))
               csum(0x0 start=0 offset=0 ip_summed=0 complete_sw=0 valid=0 level=0)
               hash(0x0 sw=0 l4=0) proto=0x00f8 pkttype=1 iif=3
               priority=0x0 mark=0x0 alloc_cpu=0 vlan_all=0x0
               encapsulation=0 inner(proto=0x0000, mac=0, net=0, trans=0)
[  256.645377] dev name=end1 feat=0x0002e10200114bb3
[  256.645386] skb headroom: 00000000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
[  256.645395] skb headroom: 00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
[  256.645403] skb headroom: 00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
[  256.645411] skb headroom: 00000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
[  256.645420] skb headroom: 00000040: ff ff ff ff ff ff 00 1c 19 f2 e2 db 08 06
[  256.645428] skb frag:     00000000: 00 01 08 00 06 04 00 01 00 1c 19 f2 e2 db 0a 02
[  256.645436] skb frag:     00000010: 00 83 00 00 00 00 00 00 0a 02 a0 2f 00 00 00 00
[  256.645444] skb frag:     00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01
[  256.645452] ksz_common_rcv:92 dsa_conduit_find_user returned NULL

Call skb_linearize before trying to access the tag.

This patch fixes ksz9477_rcv which is used by the ksz9896 I have at
hand, and also applies the same fix to ksz8795_rcv which seems to have
the same problem.

Signed-off-by: Jakob Unterwurzacher <jakob.unterwurzacher@cherry.de>
CC: stable@vger.kernel.org
Fixes: 016e43a26bab ("net: dsa: ksz: Add KSZ8795 tag code")
Fixes: 8b8010fb7876 ("dsa: add support for Microchip KSZ tail tagging")
Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
Link: https://patch.msgid.link/20250515072920.2313014-1-jakob.unterwurzacher@cherry.de
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
net/dsa/tag_ksz.c

index c33d4bf179297c4296ca0ec309e203773d93f673..0b7564b53790da29226249c7feb253465df2d2eb 100644 (file)
@@ -140,7 +140,12 @@ static struct sk_buff *ksz8795_xmit(struct sk_buff *skb, struct net_device *dev)
 
 static struct sk_buff *ksz8795_rcv(struct sk_buff *skb, struct net_device *dev)
 {
-       u8 *tag = skb_tail_pointer(skb) - KSZ_EGRESS_TAG_LEN;
+       u8 *tag;
+
+       if (skb_linearize(skb))
+               return NULL;
+
+       tag = skb_tail_pointer(skb) - KSZ_EGRESS_TAG_LEN;
 
        return ksz_common_rcv(skb, dev, tag[0] & KSZ8795_TAIL_TAG_EG_PORT_M,
                              KSZ_EGRESS_TAG_LEN);
@@ -311,10 +316,16 @@ static struct sk_buff *ksz9477_xmit(struct sk_buff *skb,
 
 static struct sk_buff *ksz9477_rcv(struct sk_buff *skb, struct net_device *dev)
 {
-       /* Tag decoding */
-       u8 *tag = skb_tail_pointer(skb) - KSZ_EGRESS_TAG_LEN;
-       unsigned int port = tag[0] & KSZ9477_TAIL_TAG_EG_PORT_M;
        unsigned int len = KSZ_EGRESS_TAG_LEN;
+       unsigned int port;
+       u8 *tag;
+
+       if (skb_linearize(skb))
+               return NULL;
+
+       /* Tag decoding */
+       tag = skb_tail_pointer(skb) - KSZ_EGRESS_TAG_LEN;
+       port = tag[0] & KSZ9477_TAIL_TAG_EG_PORT_M;
 
        /* Extra 4-bytes PTP timestamp */
        if (tag[0] & KSZ9477_PTP_TAG_INDICATION) {