ovpn: fix check for skb_to_sgvec_nomark() return value
authorAntonio Quartulli <antonio@openvpn.net>
Mon, 12 May 2025 23:17:22 +0000 (01:17 +0200)
committerAntonio Quartulli <antonio@openvpn.net>
Thu, 15 May 2025 11:09:36 +0000 (13:09 +0200)
Depending on the data offset, skb_to_sgvec_nomark() may use
less scatterlist elements than what was forecasted by the
previous call to skb_cow_data().

It specifically happens when 'skbheadlen(skb) < offset', because
in this case we entirely skip the skb's head, which would have
required its own scatterlist element.

For this reason, it doesn't make sense to check that
skb_to_sgvec_nomark() returns the same value as skb_cow_data(),
but we can rather check for errors only, as it happens in
other parts of the kernel.

Signed-off-by: Antonio Quartulli <antonio@openvpn.net>
drivers/net/ovpn/crypto_aead.c

index 74ee639ac86880da9e22b88f182f5e0851cb2746..2cca759feffac9de0e4ba480c7d0a40903b12f34 100644 (file)
@@ -88,12 +88,15 @@ int ovpn_aead_encrypt(struct ovpn_peer *peer, struct ovpn_crypto_key_slot *ks,
 
        /* build scatterlist to encrypt packet payload */
        ret = skb_to_sgvec_nomark(skb, sg + 1, 0, skb->len);
-       if (unlikely(nfrags != ret))
-               return -EINVAL;
+       if (unlikely(ret < 0)) {
+               netdev_err(peer->ovpn->dev,
+                          "encrypt: cannot map skb to sg: %d\n", ret);
+               return ret;
+       }
 
        /* append auth_tag onto scatterlist */
        __skb_push(skb, tag_size);
-       sg_set_buf(sg + nfrags + 1, skb->data, tag_size);
+       sg_set_buf(sg + ret + 1, skb->data, tag_size);
 
        /* obtain packet ID, which is used both as a first
         * 4 bytes of nonce and last 4 bytes of associated data.
@@ -201,11 +204,14 @@ int ovpn_aead_decrypt(struct ovpn_peer *peer, struct ovpn_crypto_key_slot *ks,
 
        /* build scatterlist to decrypt packet payload */
        ret = skb_to_sgvec_nomark(skb, sg + 1, payload_offset, payload_len);
-       if (unlikely(nfrags != ret))
-               return -EINVAL;
+       if (unlikely(ret < 0)) {
+               netdev_err(peer->ovpn->dev,
+                          "decrypt: cannot map skb to sg: %d\n", ret);
+               return ret;
+       }
 
        /* append auth_tag onto scatterlist */
-       sg_set_buf(sg + nfrags + 1, skb->data + OVPN_AAD_SIZE, tag_size);
+       sg_set_buf(sg + ret + 1, skb->data + OVPN_AAD_SIZE, tag_size);
 
        /* iv may be required by async crypto */
        ovpn_skb_cb(skb)->iv = kmalloc(OVPN_NONCE_SIZE, GFP_ATOMIC);