pptp_rcv_core() looks into the PPP payload for two special cases: allowing old-sequence LCP Echo packets and stripping PPP address/control fields. Both checks read fixed PPP fields directly from skb data. Make sure the bytes being read are present in the skb and pulled into the linear area before dereferencing them. Use the available skb payload length for these local checks, matching the existing receive path which passes the remaining skb data to ppp_input() after pulling the PPTP GRE header. Signed-off-by: Zhixing Chen --- Changes in v2: - Use the available skb payload length instead of the GRE-advertised payload_len for the local PPP field reads. - Pull the required bytes into the skb linear area before dereferencing them. v1: https://lore.kernel.org/netdev/20260813082247.31499-1-running910@gmail.com/T/ --- drivers/net/ppp/pptp.c | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/drivers/net/ppp/pptp.c b/drivers/net/ppp/pptp.c index a797a0606f6b..4fb94a455c57 100644 --- a/drivers/net/ppp/pptp.c +++ b/drivers/net/ppp/pptp.c @@ -275,6 +275,7 @@ static int pptp_rcv_core(struct sock *sk, struct sk_buff *skb) struct pppox_sock *po = pppox_sk(sk); struct pptp_opt *opt = &po->proto.pptp; int headersize, payload_len, seq; + unsigned int payload_avail; __u8 *payload; struct pptp_gre_header *header; @@ -314,23 +315,34 @@ static int pptp_rcv_core(struct sock *sk, struct sk_buff *skb) if (!pskb_may_pull(skb, headersize + payload_len)) goto drop; - payload = skb->data + headersize; + payload_avail = skb->len - headersize; /* check for expected sequence number */ if (seq < opt->seq_recv + 1 || WRAPPED(opt->seq_recv, seq)) { - if ((payload[0] == PPP_ALLSTATIONS) && (payload[1] == PPP_UI) && - (PPP_PROTOCOL(payload) == PPP_LCP) && - ((payload[4] == PPP_LCP_ECHOREQ) || (payload[4] == PPP_LCP_ECHOREP))) - goto allow_packet; + if (payload_avail >= PPP_HDRLEN + 1) { + if (!pskb_may_pull(skb, headersize + PPP_HDRLEN + 1)) + goto drop; + + payload = skb->data + headersize; + if (payload[0] == PPP_ALLSTATIONS && payload[1] == PPP_UI && + PPP_PROTOCOL(payload) == PPP_LCP && + (payload[4] == PPP_LCP_ECHOREQ || payload[4] == PPP_LCP_ECHOREP)) + goto allow_packet; + } } else { opt->seq_recv = seq; allow_packet: skb_pull(skb, headersize); - if (payload[0] == PPP_ALLSTATIONS && payload[1] == PPP_UI) { - /* chop off address/control */ - if (skb->len < 3) + if (payload_avail >= 2) { + if (!pskb_may_pull(skb, 2)) goto drop; - skb_pull(skb, 2); + + if (skb->data[0] == PPP_ALLSTATIONS && skb->data[1] == PPP_UI) { + /* chop off address/control */ + if (skb->len < 3) + goto drop; + skb_pull(skb, 2); + } } skb->ip_summed = CHECKSUM_NONE; base-commit: 25c1f6111034aef7fc06cfbdcf1e4f0d6e5ee74b -- 2.34.1