mirror of
https://github.com/torvalds/linux.git
synced 2026-09-22 20:54:03 +02:00
pppoatm: ensure a writable skb header and linear data
In pppoatm_send(), LLC encapsulation checks whether there is sufficient
headroom for the 4-byte LLC header, but does not ensure that the skb header
is writable.
Normal transmit packets passing through ppp_start_xmit() have their header
unshared via skb_cow_head(). However, packets can also reach pppoatm_send()
via PPP channel bridging (PPPIOCBRIDGECHAN) without going through
ppp_start_xmit().
Use skb_cow_head() to ensure both sufficient headroom and a writable
header before pushing the LLC header.
While at it:
- Call pskb_may_pull(skb, 1) before inspecting skb->data[0] to prevent
out-of-bounds reads on zero-length or non-linear frames (e.g. from
bridging).
- Defer SC_COMP_PROT protocol compression until after pppoatm_may_send()
succeeds. This eliminates the temporary skb allocation on admission failure
and completely removes the fragile "undo" heuristic at the nospace label,
avoiding any risk of reading uninitialized headroom or performing an
unbalanced skb_push().
Fixes: 4cf476ced4 ("ppp: add PPPIOCBRIDGECHAN and PPPIOCUNBRIDGECHAN ioctls")
Signed-off-by: Eric Dumazet <edumazet@google.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Link: https://patch.msgid.link/20260912233048.3977192-1-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
562219874c
commit
ecc7253683
|
|
@ -292,10 +292,13 @@ static int pppoatm_send(struct ppp_channel *chan, struct sk_buff *skb)
|
|||
struct atm_vcc *vcc;
|
||||
int ret;
|
||||
|
||||
if (!pskb_may_pull(skb, 1)) {
|
||||
kfree_skb(skb);
|
||||
return DROP_PACKET;
|
||||
}
|
||||
|
||||
ATM_SKB(skb)->vcc = pvcc->atmvcc;
|
||||
pr_debug("(skb=0x%p, vcc=0x%p)\n", skb, pvcc->atmvcc);
|
||||
if (skb->data[0] == '\0' && (pvcc->flags & SC_COMP_PROT))
|
||||
(void) skb_pull(skb, 1);
|
||||
|
||||
vcc = ATM_SKB(skb)->vcc;
|
||||
bh_lock_sock(sk_atm(vcc));
|
||||
|
|
@ -317,23 +320,13 @@ static int pppoatm_send(struct ppp_channel *chan, struct sk_buff *skb)
|
|||
|
||||
switch (pvcc->encaps) { /* LLC encapsulation needed */
|
||||
case e_llc:
|
||||
if (skb_headroom(skb) < LLC_LEN) {
|
||||
struct sk_buff *n;
|
||||
n = skb_realloc_headroom(skb, LLC_LEN);
|
||||
if (n != NULL &&
|
||||
!pppoatm_may_send(pvcc, n->truesize)) {
|
||||
kfree_skb(n);
|
||||
goto nospace;
|
||||
}
|
||||
consume_skb(skb);
|
||||
skb = n;
|
||||
if (skb == NULL) {
|
||||
bh_unlock_sock(sk_atm(vcc));
|
||||
return DROP_PACKET;
|
||||
}
|
||||
} else if (!pppoatm_may_send(pvcc, skb->truesize))
|
||||
if (skb_cow_head(skb, LLC_LEN)) {
|
||||
bh_unlock_sock(sk_atm(vcc));
|
||||
kfree_skb(skb);
|
||||
return DROP_PACKET;
|
||||
}
|
||||
if (!pppoatm_may_send(pvcc, skb->truesize))
|
||||
goto nospace;
|
||||
memcpy(skb_push(skb, LLC_LEN), pppllc, LLC_LEN);
|
||||
break;
|
||||
case e_vc:
|
||||
if (!pppoatm_may_send(pvcc, skb->truesize))
|
||||
|
|
@ -346,6 +339,12 @@ static int pppoatm_send(struct ppp_channel *chan, struct sk_buff *skb)
|
|||
return 1;
|
||||
}
|
||||
|
||||
if (skb->data[0] == '\0' && (pvcc->flags & SC_COMP_PROT))
|
||||
skb_pull(skb, 1);
|
||||
|
||||
if (pvcc->encaps == e_llc)
|
||||
memcpy(skb_push(skb, LLC_LEN), pppllc, LLC_LEN);
|
||||
|
||||
atm_account_tx(vcc, skb);
|
||||
pr_debug("atm_skb(%p)->vcc(%p)->dev(%p)\n",
|
||||
skb, ATM_SKB(skb)->vcc, ATM_SKB(skb)->vcc->dev);
|
||||
|
|
@ -355,13 +354,6 @@ static int pppoatm_send(struct ppp_channel *chan, struct sk_buff *skb)
|
|||
return ret;
|
||||
nospace:
|
||||
bh_unlock_sock(sk_atm(vcc));
|
||||
/*
|
||||
* We don't have space to send this SKB now, but we might have
|
||||
* already applied SC_COMP_PROT compression, so may need to undo
|
||||
*/
|
||||
if ((pvcc->flags & SC_COMP_PROT) && skb_headroom(skb) > 0 &&
|
||||
skb->data[-1] == '\0')
|
||||
(void) skb_push(skb, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user