Skip to content

Commit f18efe5

Browse files
devnexengregkh
authored andcommitted
psp: strip variable-length PSP header in psp_dev_rcv()
commit 30cb24f upstream. psp_dev_rcv() unconditionally removes a fixed PSP_ENCAP_HLEN, even when psph->hdrlen indicates that the PSP header carries optional fields. A frame whose PSP header advertises a non-zero VC or any extension would therefore be silently mis-decapsulated: option bytes would spill into the inner packet head and downstream parsing would fail on a corrupted skb. Compute the full PSP header length from psph->hdrlen, pull the optional bytes into the linear region, and strip the whole header when decapsulating. Optional fields (VC, ...) are still ignored, just discarded with the rest of the header instead of leaking. crypt_offset and the VIRT flag are intentionally not validated here - callers know their device's PSP implementation and can decide. Both in-tree callers gate on hardware-validated PSP, so this is a correctness fix rather than a reachable corruption path under current configurations. Fixes: 0eddb80 ("psp: provide decapsulation and receive helper for drivers") Reviewed-by: Willem de Bruijn <willemb@google.com> Reviewed-by: Daniel Zahka <daniel.zahka@gmail.com> Cc: stable@vger.kernel.org Signed-off-by: David Carlier <devnexen@gmail.com> Link: https://patch.msgid.link/20260502141945.14484-1-devnexen@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 8d44391 commit f18efe5

1 file changed

Lines changed: 31 additions & 11 deletions

File tree

net/psp/psp_main.c

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -263,15 +263,16 @@ EXPORT_SYMBOL(psp_dev_encapsulate);
263263

264264
/* Receive handler for PSP packets.
265265
*
266-
* Presently it accepts only already-authenticated packets and does not
267-
* support optional fields, such as virtualization cookies. The caller should
268-
* ensure that skb->data is pointing to the mac header, and that skb->mac_len
269-
* is set. This function does not currently adjust skb->csum (CHECKSUM_COMPLETE
270-
* is not supported).
266+
* Accepts only already-authenticated packets. The full PSP header is
267+
* stripped according to psph->hdrlen; any optional fields it advertises
268+
* (virtualization cookies, etc.) are ignored and discarded along with the
269+
* rest of the header. The caller should ensure that skb->data is pointing
270+
* to the mac header, and that skb->mac_len is set. This function does not
271+
* currently adjust skb->csum (CHECKSUM_COMPLETE is not supported).
271272
*/
272273
int psp_dev_rcv(struct sk_buff *skb, u16 dev_id, u8 generation, bool strip_icv)
273274
{
274-
int l2_hlen = 0, l3_hlen, encap;
275+
int l2_hlen = 0, l3_hlen, encap, psp_hlen;
275276
struct psp_skb_ext *pse;
276277
struct psphdr *psph;
277278
struct ethhdr *eth;
@@ -312,18 +313,36 @@ int psp_dev_rcv(struct sk_buff *skb, u16 dev_id, u8 generation, bool strip_icv)
312313
if (unlikely(uh->dest != htons(PSP_DEFAULT_UDP_PORT)))
313314
return -EINVAL;
314315

315-
pse = skb_ext_add(skb, SKB_EXT_PSP);
316-
if (!pse)
316+
psph = (struct psphdr *)(skb->data + l2_hlen + l3_hlen +
317+
sizeof(struct udphdr));
318+
319+
/* Strip the full PSP header per psph->hdrlen; VC/options are pulled
320+
* into the linear region only so they can be discarded with the
321+
* rest of the header.
322+
*/
323+
psp_hlen = (psph->hdrlen + 1) * 8;
324+
325+
if (unlikely(psp_hlen < sizeof(struct psphdr)))
326+
return -EINVAL;
327+
328+
if (psp_hlen > sizeof(struct psphdr) &&
329+
!pskb_may_pull(skb, l2_hlen + l3_hlen +
330+
sizeof(struct udphdr) + psp_hlen))
317331
return -EINVAL;
318332

319333
psph = (struct psphdr *)(skb->data + l2_hlen + l3_hlen +
320334
sizeof(struct udphdr));
335+
336+
pse = skb_ext_add(skb, SKB_EXT_PSP);
337+
if (!pse)
338+
return -EINVAL;
339+
321340
pse->spi = psph->spi;
322341
pse->dev_id = dev_id;
323342
pse->generation = generation;
324343
pse->version = FIELD_GET(PSPHDR_VERFL_VERSION, psph->verfl);
325344

326-
encap = PSP_ENCAP_HLEN;
345+
encap = sizeof(struct udphdr) + psp_hlen;
327346
encap += strip_icv ? PSP_TRL_SIZE : 0;
328347

329348
if (proto == htons(ETH_P_IP)) {
@@ -340,8 +359,9 @@ int psp_dev_rcv(struct sk_buff *skb, u16 dev_id, u8 generation, bool strip_icv)
340359
ipv6h->payload_len = htons(ntohs(ipv6h->payload_len) - encap);
341360
}
342361

343-
memmove(skb->data + PSP_ENCAP_HLEN, skb->data, l2_hlen + l3_hlen);
344-
skb_pull(skb, PSP_ENCAP_HLEN);
362+
memmove(skb->data + sizeof(struct udphdr) + psp_hlen,
363+
skb->data, l2_hlen + l3_hlen);
364+
skb_pull(skb, sizeof(struct udphdr) + psp_hlen);
345365

346366
if (strip_icv)
347367
pskb_trim(skb, skb->len - PSP_TRL_SIZE);

0 commit comments

Comments
 (0)