Skip to content

Commit 02388bf

Browse files
Meng Xudavem330
authored andcommitted
isdn/i4l: fetch the ppp_write buffer in one shot
In isdn_ppp_write(), the header (i.e., protobuf) of the buffer is fetched twice from userspace. The first fetch is used to peek at the protocol of the message and reset the huptimer if necessary; while the second fetch copies in the whole buffer. However, given that buf resides in userspace memory, a user process can race to change its memory content across fetches. By doing so, we can either avoid resetting the huptimer for any type of packets (by first setting proto to PPP_LCP and later change to the actual type) or force resetting the huptimer for LCP packets. This patch changes this double-fetch behavior into two single fetches decided by condition (lp->isdn_device < 0 || lp->isdn_channel <0). A more detailed discussion can be found at https://marc.info/?l=linux-kernel&m=150586376926123&w=2 Signed-off-by: Meng Xu <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent e24ee27 commit 02388bf

File tree

1 file changed

+25
-12
lines changed

1 file changed

+25
-12
lines changed

drivers/isdn/i4l/isdn_ppp.c

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -825,7 +825,6 @@ isdn_ppp_write(int min, struct file *file, const char __user *buf, int count)
825825
isdn_net_local *lp;
826826
struct ippp_struct *is;
827827
int proto;
828-
unsigned char protobuf[4];
829828

830829
is = file->private_data;
831830

@@ -839,24 +838,28 @@ isdn_ppp_write(int min, struct file *file, const char __user *buf, int count)
839838
if (!lp)
840839
printk(KERN_DEBUG "isdn_ppp_write: lp == NULL\n");
841840
else {
842-
/*
843-
* Don't reset huptimer for
844-
* LCP packets. (Echo requests).
845-
*/
846-
if (copy_from_user(protobuf, buf, 4))
847-
return -EFAULT;
848-
proto = PPP_PROTOCOL(protobuf);
849-
if (proto != PPP_LCP)
850-
lp->huptimer = 0;
841+
if (lp->isdn_device < 0 || lp->isdn_channel < 0) {
842+
unsigned char protobuf[4];
843+
/*
844+
* Don't reset huptimer for
845+
* LCP packets. (Echo requests).
846+
*/
847+
if (copy_from_user(protobuf, buf, 4))
848+
return -EFAULT;
849+
850+
proto = PPP_PROTOCOL(protobuf);
851+
if (proto != PPP_LCP)
852+
lp->huptimer = 0;
851853

852-
if (lp->isdn_device < 0 || lp->isdn_channel < 0)
853854
return 0;
855+
}
854856

855857
if ((dev->drv[lp->isdn_device]->flags & DRV_FLAG_RUNNING) &&
856858
lp->dialstate == 0 &&
857859
(lp->flags & ISDN_NET_CONNECTED)) {
858860
unsigned short hl;
859861
struct sk_buff *skb;
862+
unsigned char *cpy_buf;
860863
/*
861864
* we need to reserve enough space in front of
862865
* sk_buff. old call to dev_alloc_skb only reserved
@@ -869,11 +872,21 @@ isdn_ppp_write(int min, struct file *file, const char __user *buf, int count)
869872
return count;
870873
}
871874
skb_reserve(skb, hl);
872-
if (copy_from_user(skb_put(skb, count), buf, count))
875+
cpy_buf = skb_put(skb, count);
876+
if (copy_from_user(cpy_buf, buf, count))
873877
{
874878
kfree_skb(skb);
875879
return -EFAULT;
876880
}
881+
882+
/*
883+
* Don't reset huptimer for
884+
* LCP packets. (Echo requests).
885+
*/
886+
proto = PPP_PROTOCOL(cpy_buf);
887+
if (proto != PPP_LCP)
888+
lp->huptimer = 0;
889+
877890
if (is->debug & 0x40) {
878891
printk(KERN_DEBUG "ppp xmit: len %d\n", (int) skb->len);
879892
isdn_ppp_frame_log("xmit", skb->data, skb->len, 32, is->unit, lp->ppp_slot);

0 commit comments

Comments
 (0)