Skip to contentSkip to conversation

Test for CVE-2016-4997 on setsockopt

PATCH New Richard Palethorpe 2 participants 5 messages Mar 23, 2017 – Mar 28, 2017

lore
Share & tools
lore
#0 lore raw

PATCH 2/4 Test for CVE-2016-4997 on setsockopt

---
 testcases/cve/cve-2016-4997.c | 87 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 87 insertions(+)
 create mode 100644 testcases/cve/cve-2016-4997.c
testcases/cve/cve-2016-4997.c new file +87 -0
new file mode 100644
index 000000000..0a68ad307
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2017 Richard Palethorpe <[email protected]>
+ * Based on repro-compatReleaseEntry.c by NCC group
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*
+ * Test for CVE-2016-4997
+ *
+ * For a full explanation of how the vulnerability works see:
+ * https://github.com/nccgroup/TriforceLinuxSyscallFuzzer/tree/master/crash_reports/report_compatIpt
+ *
+ * The original vulnerability was present in the 32-bit compatibility system
+ * call, so the test should be compiled with -m32 and run on a 64-bit kernel.
+ * For simplicities sake the test requests root privliges instead of creating
+ * a user namespace.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+
+#include "tst_test.h"
+#include "tst_safe_net.h"
+
+
+#define TOO_SMALL_OFFSET 74
+#define OFFSET_OVERWRITE 0xFFFF
+#define NEXT_OFFSET (sizeof(struct ipt_entry)		\
+		     + sizeof(struct xt_entry_match)	\
+		     + sizeof(struct xt_entry_target))
+#define PADDING (OFFSET_OVERWRITE - NEXT_OFFSET)
+
+struct payload {
+	struct ipt_replace repl;
+	struct ipt_entry ent;
+	struct xt_entry_match match;
+	struct xt_entry_target targ;
+	char padding[PADDING];
+	struct xt_entry_target targ2;
+};
+
+static void run(void)
+{
+	int ret, sock_fd;
+	struct payload p = { 0 };
+
+	sock_fd = SAFE_SOCKET(AF_INET, SOCK_DGRAM, 0);
+
+	strncpy(p.match.u.user.name, "icmp", sizeof(p.match.u.user.name));
+	p.match.u.match_size = OFFSET_OVERWRITE;
+
+	p.ent.next_offset = NEXT_OFFSET;
+	p.ent.target_offset = TOO_SMALL_OFFSET;
+
+	p.repl.num_entries = 2;
+	p.repl.num_counters = 1;
+	p.repl.size = sizeof(struct payload);
+	p.repl.valid_hooks = 0;
+
+	ret = setsockopt(sock_fd, SOL_IP, IPT_SO_SET_REPLACE,
+			 &p, sizeof(struct payload));
+	tst_res(TPASS | TERRNO, "We didn't cause a crash, setsockopt returned %d", ret);
+	if (sizeof(long) > 4)
+		tst_res(TCONF,
+			"The original vulnerability was only present in 32-bit compat mode");
+}
+
+static struct tst_test test = {
+	.tid = "cve-2016-4997",
+	.min_kver = "2.6.32",
+	.test_all = run,
+	.needs_root = 1,
+};
Signature · 1 line
2.12.0
#1 lore raw

PATCH 2/4 Test for CVE-2016-4997 on setsockopt

Hi!

Quoted 14 lines
testcases/cve/cve-2016-4997.c new file +14 -0
+static void run(void)
+{
+	int ret, sock_fd;
+	struct payload p = { 0 };
+
+	sock_fd = SAFE_SOCKET(AF_INET, SOCK_DGRAM, 0);
+
+	strncpy(p.match.u.user.name, "icmp", sizeof(p.match.u.user.name));
+	p.match.u.match_size = OFFSET_OVERWRITE;
+
+	p.ent.next_offset = NEXT_OFFSET;
+	p.ent.target_offset = TOO_SMALL_OFFSET;
+
+	p.repl.num_entries = 2;

testcases/cve/cve-2016-4997.c line 79

Quoted 10 lines
testcases/cve/cve-2016-4997.c new file +10 -0
+	p.repl.num_counters = 1;
+	p.repl.size = sizeof(struct payload);
+	p.repl.valid_hooks = 0;
+
+	ret = setsockopt(sock_fd, SOL_IP, IPT_SO_SET_REPLACE,
+			 &p, sizeof(struct payload));
+	tst_res(TPASS | TERRNO, "We didn't cause a crash, setsockopt returned %d", ret);
+	if (sizeof(long) > 4)
+		tst_res(TCONF,
+			"The original vulnerability was only present in 32-bit compat mode");

Why do we issue the TCONF at the end of the test? Shouldn't this be something do in the test setup?

Also we have tst_kernel_bits() in the test library, so we can do something as:

if (tst_kernel_bits() == 32 || sizeof(long) > 4)

	tst_res(TCONF, "...");

testcases/cve/cve-2016-4997.c line 87

Quoted 8 lines
testcases/cve/cve-2016-4997.c new file +8 -0
+}
+
+static struct tst_test test = {
+	.tid = "cve-2016-4997",
+	.min_kver = "2.6.32",
+	.test_all = run,
+	.needs_root = 1,
+};

I also wonder if we should compile the test with -m32 by default, we whould have to add a configure test if compilation with -m32 works though.

Signature · 2 lines
Cyril Hrubis
[email protected]
#2 lore raw

PATCH 2/4 Test for CVE-2016-4997 on setsockopt

Hello Metan,

On Mon, 27 Mar 2017 17:34:40 +0200
"Cyril Hrubis" <[email protected]> wrote:

", ret);

Quoted 6 lines

testcases/cve/cve-2016-4997.c line 79

Quoted 3 lines
testcases/cve/cve-2016-4997.c new file +3 -0
+	if (sizeof(long) > 4)
+		tst_res(TCONF,
+			"The original vulnerability was only present in 32-bit compat mode");  

Why do we issue the TCONF at the end of the test? Shouldn't this be something do in the test setup?

Setup makes more sense.

Quoted 6 lines

Also we have tst_kernel_bits() in the test library, so we can do something as:

if (tst_kernel_bits() == 32 || sizeof(long) > 4)

	tst_res(TCONF, "...");

OK, great.

Quoted 14 lines

testcases/cve/cve-2016-4997.c line 87

Quoted 9 lines
testcases/cve/cve-2016-4997.c new file +8 -0
+}
+
+static struct tst_test test = {
+	.tid = "cve-2016-4997",
+	.min_kver = "2.6.32",
+	.test_all = run,
+	.needs_root = 1,
+};  

I also wonder if we should compile the test with -m32 by default, we whould have to add a configure test if compilation with -m32 works though.

Yes, I think that is best, but passing -m32 to the test's make target does not cause the LTP library to be compiled with -m32 so linking fails. I'm not sure how to get it to build both binaries.

Thank you,
Richard.

#3 lore raw

PATCH 2/4 Test for CVE-2016-4997 on setsockopt

Hi!

Quoted 12 lines
Quoted 11 lines

testcases/cve/cve-2016-4997.c line 87

Quoted 6 lines
testcases/cve/cve-2016-4997.c new file +6 -0
+static struct tst_test test = {
+	.tid = "cve-2016-4997",
+	.min_kver = "2.6.32",
+	.test_all = run,
+	.needs_root = 1,
+};  

I also wonder if we should compile the test with -m32 by default, we whould have to add a configure test if compilation with -m32 works though.

Quoted 3 lines

Yes, I think that is best, but passing -m32 to the test's make target does not cause the LTP library to be compiled with -m32 so linking fails. I'm not sure how to get it to build both binaries.

Hmm, right, we would have to compile the test library for 32bit as well, that may be tricky bussines. On the other hand there are at least two other testcases that does not work when compiled for 64bits which would make use of this as well.

Signature · 2 lines
Cyril Hrubis
[email protected]
#4 lore raw

PATCH 2/4 Test for CVE-2016-4997 on setsockopt

In reply to Richard Palethorpe

Hi!

Quoted 3 lines

Yes, I think that is best, but passing -m32 to the test's make target does not cause the LTP library to be compiled with -m32 so linking fails. I'm not sure how to get it to build both binaries.

I've hacked around a bit and managed to write a code that builds 32bit library if compiler supports -m32 and also switches between 64bit or 32bit library depending on CFLAGS used to build the test. I will send it as RFC to the LTP ML.

Signature · 2 lines
Cyril Hrubis
[email protected]