Skip to content

Commit d9cb4dc

Browse files
Meng Xugregkh
authored andcommitted
isdn/i4l: fetch the ppp_write buffer in one shot
[ Upstream commit 02388bf87f72e1d47174cd8f81c34443920eb5a0 ] 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 <mengxu.gatech@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 1a4f1ec commit d9cb4dc

1 file changed

Lines changed: 25 additions & 12 deletions

File tree

drivers/isdn/i4l/isdn_ppp.c

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

833832
is = file->private_data;
834833

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

855-
if (lp->isdn_device < 0 || lp->isdn_channel < 0)
856857
return 0;
858+
}
857859

858860
if ((dev->drv[lp->isdn_device]->flags & DRV_FLAG_RUNNING) &&
859861
lp->dialstate == 0 &&
860862
(lp->flags & ISDN_NET_CONNECTED)) {
861863
unsigned short hl;
862864
struct sk_buff *skb;
865+
unsigned char *cpy_buf;
863866
/*
864867
* we need to reserve enough space in front of
865868
* sk_buff. old call to dev_alloc_skb only reserved
@@ -872,11 +875,21 @@ isdn_ppp_write(int min, struct file *file, const char __user *buf, int count)
872875
return count;
873876
}
874877
skb_reserve(skb, hl);
875-
if (copy_from_user(skb_put(skb, count), buf, count))
878+
cpy_buf = skb_put(skb, count);
879+
if (copy_from_user(cpy_buf, buf, count))
876880
{
877881
kfree_skb(skb);
878882
return -EFAULT;
879883
}
884+
885+
/*
886+
* Don't reset huptimer for
887+
* LCP packets. (Echo requests).
888+
*/
889+
proto = PPP_PROTOCOL(cpy_buf);
890+
if (proto != PPP_LCP)
891+
lp->huptimer = 0;
892+
880893
if (is->debug & 0x40) {
881894
printk(KERN_DEBUG "ppp xmit: len %d\n", (int) skb->len);
882895
isdn_ppp_frame_log("xmit", skb->data, skb->len, 32, is->unit, lp->ppp_slot);

0 commit comments

Comments
 (0)