Skip to content

Commit

Permalink
[NETFILTER]: Fix possible overflow in netfilters do_replace()
Browse files Browse the repository at this point in the history
netfilter's do_replace() can overflow on addition within SMP_ALIGN()
and/or on multiplication by NR_CPUS, resulting in a buffer overflow on
the copy_from_user().  In practice, the overflow on addition is
triggerable on all systems, whereas the multiplication one might require
much physical memory to be present due to the check above.  Either is
sufficient to overwrite arbitrary amounts of kernel memory.

I really hate adding the same check to all 4 versions of do_replace(),
but the code is duplicate...

Found by Solar Designer during security audit of OpenVZ.org

Signed-Off-By: Kirill Korotaev <dev@openvz.org>
Signed-Off-By: Solar Designer <solar@openwall.com>
Signed-off-by: Patrck McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Kirill Korotaev authored and David S. Miller committed Feb 5, 2006
1 parent df4e957 commit ee4bb81
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 0 deletions.
7 changes: 7 additions & 0 deletions net/bridge/netfilter/ebtables.c
Original file line number Diff line number Diff line change
Expand Up @@ -934,6 +934,13 @@ static int do_replace(void __user *user, unsigned int len)
BUGPRINT("Entries_size never zero\n");
return -EINVAL;
}
/* overflow check */
if (tmp.nentries >= ((INT_MAX - sizeof(struct ebt_table_info)) / NR_CPUS -
SMP_CACHE_BYTES) / sizeof(struct ebt_counter))
return -ENOMEM;
if (tmp.num_counters >= INT_MAX / sizeof(struct ebt_counter))
return -ENOMEM;

countersize = COUNTER_OFFSET(tmp.nentries) *
(highest_possible_processor_id()+1);
newinfo = (struct ebt_table_info *)
Expand Down
7 changes: 7 additions & 0 deletions net/ipv4/netfilter/arp_tables.c
Original file line number Diff line number Diff line change
Expand Up @@ -807,6 +807,13 @@ static int do_replace(void __user *user, unsigned int len)
if (len != sizeof(tmp) + tmp.size)
return -ENOPROTOOPT;

/* overflow check */
if (tmp.size >= (INT_MAX - sizeof(struct xt_table_info)) / NR_CPUS -
SMP_CACHE_BYTES)
return -ENOMEM;
if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
return -ENOMEM;

newinfo = xt_alloc_table_info(tmp.size);
if (!newinfo)
return -ENOMEM;
Expand Down
7 changes: 7 additions & 0 deletions net/ipv4/netfilter/ip_tables.c
Original file line number Diff line number Diff line change
Expand Up @@ -921,6 +921,13 @@ do_replace(void __user *user, unsigned int len)
if (len != sizeof(tmp) + tmp.size)
return -ENOPROTOOPT;

/* overflow check */
if (tmp.size >= (INT_MAX - sizeof(struct xt_table_info)) / NR_CPUS -
SMP_CACHE_BYTES)
return -ENOMEM;
if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
return -ENOMEM;

newinfo = xt_alloc_table_info(tmp.size);
if (!newinfo)
return -ENOMEM;
Expand Down
7 changes: 7 additions & 0 deletions net/ipv6/netfilter/ip6_tables.c
Original file line number Diff line number Diff line change
Expand Up @@ -978,6 +978,13 @@ do_replace(void __user *user, unsigned int len)
if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
return -EFAULT;

/* overflow check */
if (tmp.size >= (INT_MAX - sizeof(struct xt_table_info)) / NR_CPUS -
SMP_CACHE_BYTES)
return -ENOMEM;
if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
return -ENOMEM;

newinfo = xt_alloc_table_info(tmp.size);
if (!newinfo)
return -ENOMEM;
Expand Down

0 comments on commit ee4bb81

Please sign in to comment.