Netdev List
 help / color / mirror / Atom feed
* [PATCH] pptp: reject payloads shorter than the PPP protocol field
@ 2026-08-18 16:21 Chuyf26
  2026-08-21  9:07 ` Simon Horman
  2026-08-21  9:26 ` Simon Horman
  0 siblings, 2 replies; 5+ messages in thread
From: Chuyf26 @ 2026-08-18 16:21 UTC (permalink / raw)
  To: Dmitry Kozlov; +Cc: netdev

pptp_rcv_core() dereferences the first payload bytes after pulling the
GRE header: payload[0] and payload[1] when stripping the address/control
field, and up to payload[4] when checking for an LCP echo request in
the out-of-order case. Only headersize + payload_len bytes of the skb
are pulled, so a PPTP packet with a payload_len smaller than these
accesses makes the driver read past the end of the packet data.

The path is: a GRE packet for an established PPTP channel arrives
through the IP protocol 47 handler pptp_rcv(), which validates the GRE
flags, looks the channel up by call id and source address and queues
the skb to the pppox socket, where pptp_rcv_core() runs for sockets in
PPPOX_CONNECTED state. payload_len is taken from the GRE header without
any lower bound, so an attacker who can inject packets carrying the
channel's call id and peer address can make pskb_may_pull() pull as
little as the GRE header itself; payload then points at the end of the
pulled data and the dereferences above read up to five bytes past the
packet. The sequence number is likewise attacker controlled, so both
the out-of-order LCP echo check and the in-order address/control
stripping are reachable.

The read lands inside the skb data allocation (tailroom of the same
slab object), so KASAN does not report it and the access does not
fault, but the bytes read are undefined and steer the accept/drop
decision: garbage may let a short malformed frame through to
ppp_input(), and the LCP echo check is meaningless for payloads
shorter than a PPP protocol field.

A PPTP payload is a PPP frame and therefore always carries at least
the two-byte PPP protocol field, and the LCP echo check needs five
bytes to be meaningful. Drop packets shorter than two bytes and only
perform the LCP echo check when at least five bytes are present.
Valid packets are unaffected.

Fixes: 00959ade36ac ("PPTP: PPP over IPv4 (Point-to-Point Tunneling Protocol)")
Reported-by: Abaci <abaci@linux.alibaba.com>
Assisted-by: abaci:qwen3.8-max
Signed-off-by: Chuyf26 <Chuyf26@linux.alibaba.com>
---
 drivers/net/ppp/pptp.c | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ppp/pptp.c b/drivers/net/ppp/pptp.c
index 3a10303eb756..ce1cd72baadf 100644
--- a/drivers/net/ppp/pptp.c
+++ b/drivers/net/ppp/pptp.c
@@ -317,10 +317,18 @@ static int pptp_rcv_core(struct sock *sk, struct sk_buff *skb)
 	if (!pskb_may_pull(skb, headersize + payload_len))
 		goto drop;
 
+	/* The payload is a PPP frame, so it always carries at least the
+	 * two-byte PPP protocol field. The payload bytes are dereferenced
+	 * below, reject packets too short to hold them.
+	 */
+	if (payload_len < 2)
+		goto drop;
+
 	payload = skb->data + 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) &&
+		if (payload_len >= 5 &&
+				(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;
-- 
2.43.5

^ permalink raw reply related	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2026-08-21  9:44 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-18 16:21 [PATCH] pptp: reject payloads shorter than the PPP protocol field Chuyf26
2026-08-21  9:07 ` Simon Horman
2026-08-21  9:42   ` Chuyf26
2026-08-21  9:26 ` Simon Horman
2026-08-21  9:42   ` Chuyf26

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox