Skip to content

Commit

Permalink
[NETFILTER]: ip6_tables: add compat support
Browse files Browse the repository at this point in the history
Signed-off-by: Patrick McHardy <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
kaber authored and davem330 committed Jan 28, 2008
1 parent d924357 commit 3bc3fe5
Show file tree
Hide file tree
Showing 3 changed files with 802 additions and 162 deletions.
35 changes: 35 additions & 0 deletions include/linux/netfilter_ipv6/ip6_tables.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
106 changes: 0 additions & 106 deletions net/compat.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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.
*/
Expand Down Expand Up @@ -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;

Expand Down
Loading

0 comments on commit 3bc3fe5

Please sign in to comment.