From: Arnd Bergmann <arnd@arndb.de>
To: Arjan van de Ven <arjan@infradead.org>
Cc: Heiko Carstens <heiko.carstens@de.ibm.com>,
Ingo Molnar <mingo@elte.hu>, David Miller <davem@davemloft.net>,
Andrew Morton <akpm@linux-foundation.org>,
linux-kernel@vger.kernel.org
Subject: Re: strict copy_from_user checks issues?
Date: Tue, 5 Jan 2010 16:20:38 +0100 [thread overview]
Message-ID: <201001051620.38943.arnd@arndb.de> (raw)
In-Reply-To: <20100105055224.39f9efff@infradead.org>
On Tuesday 05 January 2010, Arjan van de Ven wrote:
> On Tue, 5 Jan 2010 14:45:25 +0100
> Arnd Bergmann <arnd@arndb.de> wrote:
> >
> > I think it will get inlined on 32 bit machines or without
> > CONFIG_COMPAT, but not when CONFIG_COMPAT is enabled, because then
> > there are two call-sites.
>
> one of them is buggy it seems;
> it passes in a shorter length, but there is no code in sight that makes
> sure that the end of the structure (the difference between the shorter
> and full length one) gets initialized to, say, zeros rather than stack
> garbage. So looks like there is at least a bug there.
The old code (until 2.6.32) always copied sizeof (struct ifreq), which
I changed in order not corrupt the user space stack.
I checked that no code in the tun driver accesses the incompatible
parts of the structure, which would require conversion rather
than simply doing a short read, so it looks correct to me, or am I
missing something?
> Would be nice if the copy (+ clear) would be pulled to the two callers
> I suspect... at which point the warning will go away too as a side
> effect.
You mean like this?
It adds some complexity and about 200 bytes of object code,
I'm not sure it's worth it.
--
[UNTESTED PATCH] tun: avoid copy_from_user size warning
For 32 bit compat code, the tun driver only copies the
fields it needs using a short length, which copy_from_user
now warns about. Moving the copy operation outside of the
main ioctl function lets us avoid the warning.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
drivers/net/tun.c | 104 +++++++++++++++++++++++++++++++----------------------
1 files changed, 61 insertions(+), 43 deletions(-)
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 01e99f2..8eb9f38 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -1111,19 +1111,14 @@ static int set_offload(struct net_device *dev, unsigned long arg)
}
static long __tun_chr_ioctl(struct file *file, unsigned int cmd,
- unsigned long arg, int ifreq_len)
+ unsigned long arg, struct ifreq *ifr)
{
struct tun_file *tfile = file->private_data;
struct tun_struct *tun;
void __user* argp = (void __user*)arg;
- struct ifreq ifr;
int sndbuf;
int ret;
- if (cmd == TUNSETIFF || _IOC_TYPE(cmd) == 0x89)
- if (copy_from_user(&ifr, argp, ifreq_len))
- return -EFAULT;
-
if (cmd == TUNGETFEATURES) {
/* Currently this just means: "what IFF flags are valid?".
* This is needed because we never checked for invalid flags on
@@ -1136,34 +1131,21 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd,
rtnl_lock();
tun = __tun_get(tfile);
- if (cmd == TUNSETIFF && !tun) {
- ifr.ifr_name[IFNAMSIZ-1] = '\0';
-
- ret = tun_set_iff(tfile->net, file, &ifr);
-
- if (ret)
- goto unlock;
-
- if (copy_to_user(argp, &ifr, ifreq_len))
- ret = -EFAULT;
+ if (!tun) {
+ ret = -EBADFD;
+ if (cmd == TUNSETIFF) {
+ ifr->ifr_name[IFNAMSIZ-1] = '\0';
+ ret = tun_set_iff(tfile->net, file, ifr);
+ }
goto unlock;
}
- ret = -EBADFD;
- if (!tun)
- goto unlock;
-
DBG(KERN_INFO "%s: tun_chr_ioctl cmd %d\n", tun->dev->name, cmd);
ret = 0;
switch (cmd) {
case TUNGETIFF:
- ret = tun_get_iff(current->nsproxy->net_ns, tun, &ifr);
- if (ret)
- break;
-
- if (copy_to_user(argp, &ifr, ifreq_len))
- ret = -EFAULT;
+ ret = tun_get_iff(current->nsproxy->net_ns, tun, ifr);
break;
case TUNSETNOCSUM:
@@ -1234,18 +1216,16 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd,
case SIOCGIFHWADDR:
/* Get hw addres */
- memcpy(ifr.ifr_hwaddr.sa_data, tun->dev->dev_addr, ETH_ALEN);
- ifr.ifr_hwaddr.sa_family = tun->dev->type;
- if (copy_to_user(argp, &ifr, ifreq_len))
- ret = -EFAULT;
+ memcpy(ifr->ifr_hwaddr.sa_data, tun->dev->dev_addr, ETH_ALEN);
+ ifr->ifr_hwaddr.sa_family = tun->dev->type;
break;
case SIOCSIFHWADDR:
/* Set hw address */
DBG(KERN_DEBUG "%s: set hw address: %pM\n",
- tun->dev->name, ifr.ifr_hwaddr.sa_data);
+ tun->dev->name, ifr->ifr_hwaddr.sa_data);
- ret = dev_set_mac_address(tun->dev, &ifr.ifr_hwaddr);
+ ret = dev_set_mac_address(tun->dev, &ifr->ifr_hwaddr);
break;
case TUNGETSNDBUF:
@@ -1278,35 +1258,73 @@ unlock:
static long tun_chr_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
- return __tun_chr_ioctl(file, cmd, arg, sizeof (struct ifreq));
+ struct ifreq ifr;
+ struct ifreq __user *uifr = (void *)arg;
+ int ret;
+
+ switch (cmd) {
+ case TUNSETIFF:
+ case TUNGETIFF:
+ case SIOCGIFHWADDR:
+ case SIOCSIFHWADDR:
+ if (copy_from_user(&ifr, uifr, sizeof (ifr)))
+ return -EFAULT;
+
+ ret = __tun_chr_ioctl(file, cmd, arg, &ifr);
+ if (ret < 0)
+ return ret;
+
+ if (copy_to_user(uifr, &ifr, sizeof (ifr)))
+ return -EFAULT;
+
+ return ret;
+ }
+
+ return __tun_chr_ioctl(file, cmd, arg, NULL);
}
#ifdef CONFIG_COMPAT
static long tun_chr_compat_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
+ struct ifreq ifr;
+ struct compat_ifreq __user *uifr = compat_ptr(arg);
+ int ret;
+
switch (cmd) {
case TUNSETIFF:
case TUNGETIFF:
+ case SIOCGIFHWADDR:
+ case SIOCSIFHWADDR:
+ /*
+ * compat_ifreq is shorter than ifreq, so we must not access beyond
+ * the end of that structure. All fields that are used in this
+ * driver are compatible though, we don't need to convert the
+ * contents.
+ */
+ memset(&ifr, 0, sizeof (ifr));
+ if (copy_from_user((struct compat_ifreq *)&ifr, uifr, sizeof (*uifr)))
+ return -EFAULT;
+
+ ret = __tun_chr_ioctl(file, cmd, 0, &ifr);
+ if (ret)
+ return ret;
+
+ if (copy_to_user(uifr, (struct compat_ifreq *)&ifr, sizeof (*uifr)))
+ return -EFAULT;
+ return ret;
+ break;
+
case TUNSETTXFILTER:
case TUNGETSNDBUF:
case TUNSETSNDBUF:
- case SIOCGIFHWADDR:
- case SIOCSIFHWADDR:
arg = (unsigned long)compat_ptr(arg);
break;
default:
arg = (compat_ulong_t)arg;
break;
}
-
- /*
- * compat_ifreq is shorter than ifreq, so we must not access beyond
- * the end of that structure. All fields that are used in this
- * driver are compatible though, we don't need to convert the
- * contents.
- */
- return __tun_chr_ioctl(file, cmd, arg, sizeof(struct compat_ifreq));
+ return __tun_chr_ioctl(file, cmd, arg, NULL);
}
#endif /* CONFIG_COMPAT */
next prev parent reply other threads:[~2010-01-05 15:21 UTC|newest]
Thread overview: 26+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-01-04 15:43 strict copy_from_user checks issues? Heiko Carstens
2010-01-05 1:43 ` Arjan van de Ven
2010-01-05 7:35 ` Ingo Molnar
2010-01-05 9:48 ` Heiko Carstens
2010-01-05 12:47 ` Arnd Bergmann
2010-01-05 13:19 ` Heiko Carstens
2010-01-05 13:31 ` Arjan van de Ven
2010-01-05 15:22 ` [PATCH] sparc: copy_from_user() should not return -EFAULT Heiko Carstens
2010-01-05 17:27 ` Andi Kleen
2010-01-05 20:47 ` David Miller
2010-01-06 3:20 ` Arjan van de Ven
2010-01-05 17:55 ` Arnd Bergmann
2010-01-06 4:42 ` David Miller
2010-01-05 22:15 ` [tip:x86/urgent] x86: " tip-bot for Heiko Carstens
2010-01-05 13:34 ` strict copy_from_user checks issues? Arjan van de Ven
2010-01-05 13:36 ` Arjan van de Ven
2010-01-05 13:45 ` Arnd Bergmann
2010-01-05 13:52 ` Arjan van de Ven
2010-01-05 15:20 ` Arnd Bergmann [this message]
2010-01-05 21:44 ` H. Peter Anvin
2010-01-07 14:02 ` Arnd Bergmann
2010-01-07 23:57 ` H. Peter Anvin
2010-01-09 0:07 ` Arnd Bergmann
2010-01-09 0:10 ` H. Peter Anvin
2010-01-09 8:01 ` Arnd Bergmann
2010-01-09 20:57 ` H. Peter Anvin
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=201001051620.38943.arnd@arndb.de \
--to=arnd@arndb.de \
--cc=akpm@linux-foundation.org \
--cc=arjan@infradead.org \
--cc=davem@davemloft.net \
--cc=heiko.carstens@de.ibm.com \
--cc=linux-kernel@vger.kernel.org \
--cc=mingo@elte.hu \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox