Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

[NETFILTER]: ip6_tables: add compat support

parent d924357c
Loading
Loading
Loading
Loading
+35 −0
Original line number Diff line number Diff line
@@ -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 */
+0 −106
Original line number Diff line number Diff line
@@ -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;

+767 −56

File changed.

Preview size limit exceeded, changes collapsed.