Commit 9e832350 authored by Stephen Hemminger's avatar Stephen Hemminger

[TUN]: Fix user buffer verification.

When Tun initialization fails it shouldn't obscure the error return,
There are several reasons it could fail, and when diagnosing user problems
the error code might provide more info.
parent ff71578a
...@@ -169,7 +169,7 @@ static unsigned int tun_chr_poll(struct file *file, poll_table * wait) ...@@ -169,7 +169,7 @@ static unsigned int tun_chr_poll(struct file *file, poll_table * wait)
return mask; return mask;
} }
/* Get packet from user space buffer(already verified) */ /* Get packet from user space buffer */
static __inline__ ssize_t tun_get_user(struct tun_struct *tun, struct iovec *iv, size_t count) static __inline__ ssize_t tun_get_user(struct tun_struct *tun, struct iovec *iv, size_t count)
{ {
struct tun_pi pi = { 0, __constant_htons(ETH_P_IP) }; struct tun_pi pi = { 0, __constant_htons(ETH_P_IP) };
...@@ -180,7 +180,8 @@ static __inline__ ssize_t tun_get_user(struct tun_struct *tun, struct iovec *iv, ...@@ -180,7 +180,8 @@ static __inline__ ssize_t tun_get_user(struct tun_struct *tun, struct iovec *iv,
if ((len -= sizeof(pi)) > len) if ((len -= sizeof(pi)) > len)
return -EINVAL; return -EINVAL;
memcpy_fromiovec((void *)&pi, iv, sizeof(pi)); if(memcpy_fromiovec((void *)&pi, iv, sizeof(pi)))
return -EFAULT;
} }
if (!(skb = alloc_skb(len + 2, GFP_KERNEL))) { if (!(skb = alloc_skb(len + 2, GFP_KERNEL))) {
...@@ -189,7 +190,8 @@ static __inline__ ssize_t tun_get_user(struct tun_struct *tun, struct iovec *iv, ...@@ -189,7 +190,8 @@ static __inline__ ssize_t tun_get_user(struct tun_struct *tun, struct iovec *iv,
} }
skb_reserve(skb, 2); skb_reserve(skb, 2);
memcpy_fromiovec(skb_put(skb, len), iv, len); if (memcpy_fromiovec(skb_put(skb, len), iv, len))
return -EFAULT;
skb->dev = tun->dev; skb->dev = tun->dev;
switch (tun->flags & TUN_TYPE_MASK) { switch (tun->flags & TUN_TYPE_MASK) {
...@@ -213,26 +215,29 @@ static __inline__ ssize_t tun_get_user(struct tun_struct *tun, struct iovec *iv, ...@@ -213,26 +215,29 @@ static __inline__ ssize_t tun_get_user(struct tun_struct *tun, struct iovec *iv,
return count; return count;
} }
static inline size_t iov_total(const struct iovec *iv, unsigned long count)
{
unsigned long i;
size_t len;
for (i = 0, len = 0; i < count; i++)
len += iv[i].iov_len;
return len;
}
/* Writev */ /* Writev */
static ssize_t tun_chr_writev(struct file * file, const struct iovec *iv, static ssize_t tun_chr_writev(struct file * file, const struct iovec *iv,
unsigned long count, loff_t *pos) unsigned long count, loff_t *pos)
{ {
struct tun_struct *tun = file->private_data; struct tun_struct *tun = file->private_data;
unsigned long i;
size_t len;
if (!tun) if (!tun)
return -EBADFD; return -EBADFD;
DBG(KERN_INFO "%s: tun_chr_write %ld\n", tun->dev->name, count); DBG(KERN_INFO "%s: tun_chr_write %ld\n", tun->dev->name, count);
for (i = 0, len = 0; i < count; i++) { return tun_get_user(tun, (struct iovec *) iv, iov_total(iv, count));
if (verify_area(VERIFY_READ, iv[i].iov_base, iv[i].iov_len))
return -EFAULT;
len += iv[i].iov_len;
}
return tun_get_user(tun, (struct iovec *) iv, len);
} }
/* Write */ /* Write */
...@@ -243,7 +248,7 @@ static ssize_t tun_chr_write(struct file * file, const char * buf, ...@@ -243,7 +248,7 @@ static ssize_t tun_chr_write(struct file * file, const char * buf,
return tun_chr_writev(file, &iv, 1, pos); return tun_chr_writev(file, &iv, 1, pos);
} }
/* Put packet to the user space buffer (already verified) */ /* Put packet to the user space buffer */
static __inline__ ssize_t tun_put_user(struct tun_struct *tun, static __inline__ ssize_t tun_put_user(struct tun_struct *tun,
struct sk_buff *skb, struct sk_buff *skb,
struct iovec *iv, int len) struct iovec *iv, int len)
...@@ -260,7 +265,8 @@ static __inline__ ssize_t tun_put_user(struct tun_struct *tun, ...@@ -260,7 +265,8 @@ static __inline__ ssize_t tun_put_user(struct tun_struct *tun,
pi.flags |= TUN_PKT_STRIP; pi.flags |= TUN_PKT_STRIP;
} }
memcpy_toiovec(iv, (void *) &pi, sizeof(pi)); if (memcpy_toiovec(iv, (void *) &pi, sizeof(pi)))
return -EFAULT;
total += sizeof(pi); total += sizeof(pi);
} }
...@@ -283,18 +289,13 @@ static ssize_t tun_chr_readv(struct file *file, const struct iovec *iv, ...@@ -283,18 +289,13 @@ static ssize_t tun_chr_readv(struct file *file, const struct iovec *iv,
DECLARE_WAITQUEUE(wait, current); DECLARE_WAITQUEUE(wait, current);
struct sk_buff *skb; struct sk_buff *skb;
ssize_t len, ret = 0; ssize_t len, ret = 0;
unsigned long i;
if (!tun) if (!tun)
return -EBADFD; return -EBADFD;
DBG(KERN_INFO "%s: tun_chr_read\n", tun->dev->name); DBG(KERN_INFO "%s: tun_chr_read\n", tun->dev->name);
for (i = 0, len = 0; i < count; i++) { len = iov_total(iv, count);
if (verify_area(VERIFY_WRITE, iv[i].iov_base, iv[i].iov_len))
return -EFAULT;
len += iv[i].iov_len;
}
if (len < 0) if (len < 0)
return -EINVAL; return -EINVAL;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment