[Lucid][CVE-2013-4588] ipvs: Add boundary check on ioctl arguments

Luis Henriques luis.henriques at canonical.com
Tue Nov 19 10:40:27 UTC 2013

From: Arjan van de Ven <arjan at linux.intel.com>


BugLink: http://bugs.launchpad.net/bugs/1252424

The ipvs code has a nifty system for doing the size of ioctl command
copies; it defines an array with values into which it indexes the cmd
to find the right length.

Unfortunately, the ipvs code forgot to check if the cmd was in the
range that the array provides, allowing for an index outside of the
array, which then gives a "garbage" result into the length, which
then gets used for copying into a stack buffer.

Fix this by adding sanity checks on these as well as the copy size.

[ horms at verge.net.au: adjusted limit to IP_VS_SO_GET_MAX ]
Signed-off-by: Arjan van de Ven <arjan at linux.intel.com>
Acked-by: Julian Anastasov <ja at ssi.bg>
Signed-off-by: Simon Horman <horms at verge.net.au>
Signed-off-by: Patrick McHardy <kaber at trash.net>
(cherry picked from commit 04bcef2a83f40c6db24222b27a52892cba39dffb)
Signed-off-by: Luis Henriques <luis.henriques at canonical.com>
 net/netfilter/ipvs/ip_vs_ctl.c | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c
index 9bcd972..88c7265 100644
--- a/net/netfilter/ipvs/ip_vs_ctl.c
+++ b/net/netfilter/ipvs/ip_vs_ctl.c
@@ -2077,6 +2077,10 @@ do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
 	if (!capable(CAP_NET_ADMIN))
 		return -EPERM;
+	if (cmd < IP_VS_BASE_CTL || cmd > IP_VS_SO_SET_MAX)
+		return -EINVAL;
+	if (len < 0 || len >  MAX_ARG_LEN)
+		return -EINVAL;
 	if (len != set_arglen[SET_CMDID(cmd)]) {
 		pr_err("set_ctl: len %u != %u\n",
 		       len, set_arglen[SET_CMDID(cmd)]);
@@ -2352,17 +2356,25 @@ do_ip_vs_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
 	unsigned char arg[128];
 	int ret = 0;
+	unsigned int copylen;
 	if (!capable(CAP_NET_ADMIN))
 		return -EPERM;
+	if (cmd < IP_VS_BASE_CTL || cmd > IP_VS_SO_GET_MAX)
+		return -EINVAL;
 	if (*len < get_arglen[GET_CMDID(cmd)]) {
 		pr_err("get_ctl: len %u < %u\n",
 		       *len, get_arglen[GET_CMDID(cmd)]);
 		return -EINVAL;
-	if (copy_from_user(arg, user, get_arglen[GET_CMDID(cmd)]) != 0)
+	copylen = get_arglen[GET_CMDID(cmd)];
+	if (copylen > 128)
+		return -EINVAL;
+	if (copy_from_user(arg, user, copylen) != 0)
 		return -EFAULT;
 	if (mutex_lock_interruptible(&__ip_vs_mutex))

More information about the kernel-team mailing list