Commit 3bc3fe5e authored by Patrick McHardy's avatar Patrick McHardy Committed by David S. Miller

[NETFILTER]: ip6_tables: add compat support

Signed-off-by: default avatarPatrick McHardy <kaber@trash.net>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent d924357c
......@@ -326,5 +326,40 @@ extern int ip6_masked_addrcmp(const struct in6_addr *addr1,
#define IP6T_ALIGN(s) (((s) + (__alignof__(struct ip6t_entry)-1)) & ~(__alignof__(struct ip6t_entry)-1))
#ifdef CONFIG_COMPAT
#include <net/compat.h>
struct compat_ip6t_entry
{
struct ip6t_ip6 ipv6;
compat_uint_t nfcache;
u_int16_t target_offset;
u_int16_t next_offset;
compat_uint_t comefrom;
struct compat_xt_counters counters;
unsigned char elems[0];
};
static inline struct ip6t_entry_target *
compat_ip6t_get_target(struct compat_ip6t_entry *e)
{
return (void *)e + e->target_offset;
}
#define COMPAT_IP6T_ALIGN(s) COMPAT_XT_ALIGN(s)
/* fn returns 0 to continue iteration */
#define COMPAT_IP6T_MATCH_ITERATE(e, fn, args...) \
XT_MATCH_ITERATE(struct compat_ip6t_entry, e, fn, ## args)
/* fn returns 0 to continue iteration */
#define COMPAT_IP6T_ENTRY_ITERATE(entries, size, fn, args...) \
XT_ENTRY_ITERATE(struct compat_ip6t_entry, entries, size, fn, ## args)
#define COMPAT_IP6T_ENTRY_ITERATE_CONTINUE(entries, size, n, fn, args...) \
XT_ENTRY_ITERATE_CONTINUE(struct compat_ip6t_entry, entries, size, n, \
fn, ## args)
#endif /* CONFIG_COMPAT */
#endif /*__KERNEL__*/
#endif /* _IP6_TABLES_H */
......@@ -20,7 +20,6 @@
#include <linux/syscalls.h>
#include <linux/filter.h>
#include <linux/compat.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/security.h>
#include <net/scm.h>
......@@ -316,107 +315,6 @@ void scm_detach_fds_compat(struct msghdr *kmsg, struct scm_cookie *scm)
__scm_destroy(scm);
}
/*
* For now, we assume that the compatibility and native version
* of struct ipt_entry are the same - sfr. FIXME
*/
struct compat_ipt_replace {
char name[IPT_TABLE_MAXNAMELEN];
u32 valid_hooks;
u32 num_entries;
u32 size;
u32 hook_entry[NF_INET_NUMHOOKS];
u32 underflow[NF_INET_NUMHOOKS];
u32 num_counters;
compat_uptr_t counters; /* struct ipt_counters * */
struct ipt_entry entries[0];
};
static int do_netfilter_replace(int fd, int level, int optname,
char __user *optval, int optlen)
{
struct compat_ipt_replace __user *urepl;
struct ipt_replace __user *repl_nat;
char name[IPT_TABLE_MAXNAMELEN];
u32 origsize, tmp32, num_counters;
unsigned int repl_nat_size;
int ret;
int i;
compat_uptr_t ucntrs;
urepl = (struct compat_ipt_replace __user *)optval;
if (get_user(origsize, &urepl->size))
return -EFAULT;
/* Hack: Causes ipchains to give correct error msg --RR */
if (optlen != sizeof(*urepl) + origsize)
return -ENOPROTOOPT;
/* XXX Assumes that size of ipt_entry is the same both in
* native and compat environments.
*/
repl_nat_size = sizeof(*repl_nat) + origsize;
repl_nat = compat_alloc_user_space(repl_nat_size);
ret = -EFAULT;
if (put_user(origsize, &repl_nat->size))
goto out;
if (!access_ok(VERIFY_READ, urepl, optlen) ||
!access_ok(VERIFY_WRITE, repl_nat, optlen))
goto out;
if (__copy_from_user(name, urepl->name, sizeof(urepl->name)) ||
__copy_to_user(repl_nat->name, name, sizeof(repl_nat->name)))
goto out;
if (__get_user(tmp32, &urepl->valid_hooks) ||
__put_user(tmp32, &repl_nat->valid_hooks))
goto out;
if (__get_user(tmp32, &urepl->num_entries) ||
__put_user(tmp32, &repl_nat->num_entries))
goto out;
if (__get_user(num_counters, &urepl->num_counters) ||
__put_user(num_counters, &repl_nat->num_counters))
goto out;
if (__get_user(ucntrs, &urepl->counters) ||
__put_user(compat_ptr(ucntrs), &repl_nat->counters))
goto out;
if (__copy_in_user(&repl_nat->entries[0],
&urepl->entries[0],
origsize))
goto out;
for (i = 0; i < NF_INET_NUMHOOKS; i++) {
if (__get_user(tmp32, &urepl->hook_entry[i]) ||
__put_user(tmp32, &repl_nat->hook_entry[i]) ||
__get_user(tmp32, &urepl->underflow[i]) ||
__put_user(tmp32, &repl_nat->underflow[i]))
goto out;
}
/*
* Since struct ipt_counters just contains two u_int64_t members
* we can just do the access_ok check here and pass the (converted)
* pointer into the standard syscall. We hope that the pointer is
* not misaligned ...
*/
if (!access_ok(VERIFY_WRITE, compat_ptr(ucntrs),
num_counters * sizeof(struct ipt_counters)))
goto out;
ret = sys_setsockopt(fd, level, optname,
(char __user *)repl_nat, repl_nat_size);
out:
return ret;
}
/*
* A struct sock_filter is architecture independent.
*/
......@@ -485,10 +383,6 @@ asmlinkage long compat_sys_setsockopt(int fd, int level, int optname,
int err;
struct socket *sock;
if (level == SOL_IPV6 && optname == IPT_SO_SET_REPLACE)
return do_netfilter_replace(fd, level, optname,
optval, optlen);
if (optlen < 0)
return -EINVAL;
......
This diff is collapsed.
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