Skip to content

Commit 392fdb0

Browse files
herbertxdavem330
authored andcommitted
net pppoe: Check packet length on all receive paths
The length field in the PPPOE header wasn't checked completely. This patch causes all packets shorter than the declared length to be dropped. It also changes the memcpy_toiovec call to skb_copy_datagram_iovec so that paged packets (rare for PPPOE) are handled properly. Thanks to Ilja of the Netric Security Team for discovering and reporting this bug, and Chris Wright for the total_len check. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent ea23ec2 commit 392fdb0

File tree

1 file changed

+17
-14
lines changed

1 file changed

+17
-14
lines changed

drivers/net/pppoe.c

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -341,12 +341,6 @@ static int pppoe_rcv_core(struct sock *sk, struct sk_buff *skb)
341341
struct pppox_sock *relay_po;
342342

343343
if (sk->sk_state & PPPOX_BOUND) {
344-
struct pppoe_hdr *ph = pppoe_hdr(skb);
345-
int len = ntohs(ph->length);
346-
skb_pull_rcsum(skb, sizeof(struct pppoe_hdr));
347-
if (pskb_trim_rcsum(skb, len))
348-
goto abort_kfree;
349-
350344
ppp_input(&po->chan, skb);
351345
} else if (sk->sk_state & PPPOX_RELAY) {
352346
relay_po = get_item_by_addr(&po->pppoe_relay);
@@ -357,7 +351,6 @@ static int pppoe_rcv_core(struct sock *sk, struct sk_buff *skb)
357351
if ((sk_pppox(relay_po)->sk_state & PPPOX_CONNECTED) == 0)
358352
goto abort_put;
359353

360-
skb_pull(skb, sizeof(struct pppoe_hdr));
361354
if (!__pppoe_xmit(sk_pppox(relay_po), skb))
362355
goto abort_put;
363356
} else {
@@ -388,6 +381,7 @@ static int pppoe_rcv(struct sk_buff *skb,
388381
{
389382
struct pppoe_hdr *ph;
390383
struct pppox_sock *po;
384+
int len;
391385

392386
if (!(skb = skb_share_check(skb, GFP_ATOMIC)))
393387
goto out;
@@ -399,10 +393,21 @@ static int pppoe_rcv(struct sk_buff *skb,
399393
goto drop;
400394

401395
ph = pppoe_hdr(skb);
396+
len = ntohs(ph->length);
397+
398+
skb_pull_rcsum(skb, sizeof(*ph));
399+
if (skb->len < len)
400+
goto drop;
402401

403402
po = get_item(ph->sid, eth_hdr(skb)->h_source, dev->ifindex);
404-
if (po != NULL)
405-
return sk_receive_skb(sk_pppox(po), skb, 0);
403+
if (!po)
404+
goto drop;
405+
406+
if (pskb_trim_rcsum(skb, len))
407+
goto drop;
408+
409+
return sk_receive_skb(sk_pppox(po), skb, 0);
410+
406411
drop:
407412
kfree_skb(skb);
408413
out:
@@ -937,12 +942,10 @@ static int pppoe_recvmsg(struct kiocb *iocb, struct socket *sock,
937942
m->msg_namelen = 0;
938943

939944
if (skb) {
940-
struct pppoe_hdr *ph = pppoe_hdr(skb);
941-
const int len = ntohs(ph->length);
942-
943-
error = memcpy_toiovec(m->msg_iov, (unsigned char *) &ph->tag[0], len);
945+
total_len = min(total_len, skb->len);
946+
error = skb_copy_datagram_iovec(skb, 0, m->msg_iov, total_len);
944947
if (error == 0)
945-
error = len;
948+
error = total_len;
946949
}
947950

948951
kfree_skb(skb);

0 commit comments

Comments
 (0)