* [LTP] [PATCH 1/4] Prevent linker issues in lapi/io_uring.h
@ 2021-02-01 16:39 Martin Doucha
2021-02-01 16:39 ` [LTP] [PATCH 2/4] Add safe functions for io_uring to LTP library Martin Doucha
` (2 more replies)
0 siblings, 3 replies; 4+ messages in thread
From: Martin Doucha @ 2021-02-01 16:39 UTC (permalink / raw)
To: ltp
Fallback io_uring syscall wrappers were not defined as static inline. This
will lead to linker issues when safe function variants get added to LTP
library.
Also add check for <linux/io_uring.h> to configure script and #include it
in the LAPI header if it's available.
Signed-off-by: Martin Doucha <mdoucha@suse.cz>
---
configure.ac | 1 +
include/lapi/io_uring.h | 17 +++++++++++------
2 files changed, 12 insertions(+), 6 deletions(-)
diff --git a/configure.ac b/configure.ac
index 8bdb96300..9fb50c173 100644
--- a/configure.ac
+++ b/configure.ac
@@ -49,6 +49,7 @@ AC_CHECK_HEADERS_ONCE([ \
linux/if_alg.h \
linux/if_ether.h \
linux/if_packet.h \
+ linux/io_uring.h \
linux/keyctl.h \
linux/mempolicy.h \
linux/module.h \
diff --git a/include/lapi/io_uring.h b/include/lapi/io_uring.h
index 174e81e4d..9d280f155 100644
--- a/include/lapi/io_uring.h
+++ b/include/lapi/io_uring.h
@@ -18,6 +18,10 @@
#include "lapi/syscalls.h"
+#ifdef HAVE_LINUX_IO_URING_H
+#include <linux/io_uring.h>
+#endif
+
#ifndef IOSQE_FIXED_FILE
#ifndef __kernel_rwf_t
@@ -260,8 +264,8 @@ struct io_uring_probe {
#ifndef HAVE_IO_URING_REGISTER
-int io_uring_register(int fd, unsigned int opcode, void *arg,
- unsigned int nr_args)
+static inline int io_uring_register(int fd, unsigned int opcode, void *arg,
+ unsigned int nr_args)
{
return tst_syscall(__NR_io_uring_register, fd, opcode, arg, nr_args);
}
@@ -269,22 +273,23 @@ int io_uring_register(int fd, unsigned int opcode, void *arg,
#ifndef HAVE_IO_URING_SETUP
-int io_uring_setup(unsigned int entries, struct io_uring_params *p)
+static inline int io_uring_setup(unsigned int entries,
+ struct io_uring_params *p)
{
return tst_syscall(__NR_io_uring_setup, entries, p);
}
#endif /* HAVE_IO_URING_SETUP */
#ifndef HAVE_IO_URING_ENTER
-int io_uring_enter(int fd, unsigned int to_submit, unsigned int min_complete,
- unsigned int flags, sigset_t *sig)
+static inline int io_uring_enter(int fd, unsigned int to_submit,
+ unsigned int min_complete, unsigned int flags, sigset_t *sig)
{
return tst_syscall(__NR_io_uring_enter, fd, to_submit, min_complete,
flags, sig, _NSIG / 8);
}
#endif /* HAVE_IO_URING_ENTER */
-void io_uring_setup_supported_by_kernel(void)
+static inline void io_uring_setup_supported_by_kernel(void)
{
if ((tst_kvercmp(5, 1, 0)) < 0) {
TEST(syscall(__NR_io_uring_setup, NULL, 0));
--
2.30.0
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [LTP] [PATCH 2/4] Add safe functions for io_uring to LTP library
2021-02-01 16:39 [LTP] [PATCH 1/4] Prevent linker issues in lapi/io_uring.h Martin Doucha
@ 2021-02-01 16:39 ` Martin Doucha
2021-02-01 16:39 ` [LTP] [PATCH 3/4] Add CAP_SYS_CHROOT to lapi/capability.h Martin Doucha
2021-02-01 16:39 ` [LTP] [PATCH 4/4] Add test for CVE 2020-29373 Martin Doucha
2 siblings, 0 replies; 4+ messages in thread
From: Martin Doucha @ 2021-02-01 16:39 UTC (permalink / raw)
To: ltp
Signed-off-by: Martin Doucha <mdoucha@suse.cz>
---
include/tst_safe_io_uring.h | 63 +++++++++++++++++++++
lib/tst_safe_io_uring.c | 108 ++++++++++++++++++++++++++++++++++++
2 files changed, 171 insertions(+)
create mode 100644 include/tst_safe_io_uring.h
create mode 100644 lib/tst_safe_io_uring.c
diff --git a/include/tst_safe_io_uring.h b/include/tst_safe_io_uring.h
new file mode 100644
index 000000000..fa416e35c
--- /dev/null
+++ b/include/tst_safe_io_uring.h
@@ -0,0 +1,63 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (c) Linux Test Project, 2021
+ */
+
+#ifndef TST_IO_URING_H__
+#define TST_IO_URING_H__
+
+#include "config.h"
+#include "lapi/io_uring.h"
+
+struct tst_io_uring {
+ int fd;
+ void *sqr_base, *cqr_base;
+ /* buffer sizes in bytes for unmapping */
+ size_t sqr_mapsize, cqr_mapsize;
+
+ /* Number of entries in the ring buffers */
+ uint32_t sqr_size, cqr_size;
+
+ /* Submission queue pointers */
+ struct io_uring_sqe *sqr_entries;
+ const uint32_t *sqr_head, *sqr_mask, *sqr_flags, *sqr_dropped;
+ uint32_t *sqr_tail, *sqr_array;
+
+ /* Completion queue pointers */
+ const struct io_uring_cqe *cqr_entries;
+ const uint32_t *cqr_tail, *cqr_mask, *cqr_overflow;
+ uint32_t *cqr_head;
+
+};
+
+/*
+ * Call io_uring_setup() with given arguments and prepare memory mappings
+ * into the tst_io_uring structure passed in the third argument.
+ */
+#define SAFE_IO_URING_INIT(entries, params, uring) \
+ safe_io_uring_init(__FILE__, __LINE__, (entries), (params), (uring))
+int safe_io_uring_init(const char *file, const int lineno,
+ unsigned int entries, struct io_uring_params *params,
+ struct tst_io_uring *uring);
+
+/*
+ * Release io_uring mappings and close the file descriptor. uring->fd will
+ * be set to -1 after close.
+ */
+#define SAFE_IO_URING_CLOSE(uring) \
+ safe_io_uring_close(__FILE__, __LINE__, (uring))
+int safe_io_uring_close(const char *file, const int lineno,
+ struct tst_io_uring *uring);
+
+/*
+ * Call io_uring_enter() and check for errors. The "strict" argument controls
+ * pedantic check whether return value is equal to "to_submit" argument.
+ */
+#define SAFE_IO_URING_ENTER(strict, fd, to_submit, min_complete, flags, sig) \
+ safe_io_uring_enter(__FILE__, __LINE__, (strict), (fd), (to_submit), \
+ (min_complete), (flags), (sig))
+int safe_io_uring_enter(const char *file, const int lineno, int strict,
+ int fd, unsigned int to_submit, unsigned int min_complete,
+ unsigned int flags, sigset_t *sig);
+
+#endif /* TST_IO_URING_H__ */
diff --git a/lib/tst_safe_io_uring.c b/lib/tst_safe_io_uring.c
new file mode 100644
index 000000000..f300fd38c
--- /dev/null
+++ b/lib/tst_safe_io_uring.c
@@ -0,0 +1,108 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2021 SUSE LLC <mdoucha@suse.cz>
+ */
+
+#define TST_NO_DEFAULT_MAIN
+#include "tst_test.h"
+#include "tst_safe_io_uring.h"
+
+int safe_io_uring_init(const char *file, const int lineno,
+ unsigned int entries, struct io_uring_params *params,
+ struct tst_io_uring *uring)
+{
+ errno = 0;
+ uring->fd = io_uring_setup(entries, params);
+
+ if (uring->fd == -1) {
+ tst_brk_(file, lineno, TBROK | TERRNO,
+ "io_uring_setup() failed");
+ return uring->fd;
+ } else if (uring->fd < 0) {
+ tst_brk_(file, lineno, TBROK | TERRNO,
+ "io_uring_setup() returned invalid value %d",
+ uring->fd);
+ return uring->fd;
+ }
+
+ uring->sqr_size = params->sq_entries;
+ uring->cqr_size = params->cq_entries;
+ uring->sqr_mapsize = params->sq_off.array +
+ params->sq_entries * sizeof(__u32);
+ uring->cqr_mapsize = params->cq_off.cqes +
+ params->cq_entries * sizeof(struct io_uring_cqe);
+
+ uring->sqr_base = safe_mmap(file, lineno, NULL, uring->sqr_mapsize,
+ PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE, uring->fd,
+ IORING_OFF_SQ_RING);
+
+ if (uring->sqr_base == MAP_FAILED)
+ return -1;
+
+ uring->sqr_entries = safe_mmap(file, lineno, NULL,
+ params->sq_entries * sizeof(struct io_uring_sqe),
+ PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE, uring->fd,
+ IORING_OFF_SQES);
+
+ if (uring->sqr_entries == MAP_FAILED)
+ return -1;
+
+ uring->cqr_base = safe_mmap(file, lineno, NULL, uring->cqr_mapsize,
+ PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE, uring->fd,
+ IORING_OFF_CQ_RING);
+
+ if (uring->cqr_base == MAP_FAILED)
+ return -1;
+
+ uring->sqr_head = uring->sqr_base + params->sq_off.head;
+ uring->sqr_tail = uring->sqr_base + params->sq_off.tail;
+ uring->sqr_mask = uring->sqr_base + params->sq_off.ring_mask;
+ uring->sqr_flags = uring->sqr_base + params->sq_off.flags;
+ uring->sqr_dropped = uring->sqr_base + params->sq_off.dropped;
+ uring->sqr_array = uring->sqr_base + params->sq_off.array;
+
+ uring->cqr_head = uring->cqr_base + params->cq_off.head;
+ uring->cqr_tail = uring->cqr_base + params->cq_off.tail;
+ uring->cqr_mask = uring->cqr_base + params->cq_off.ring_mask;
+ uring->cqr_overflow = uring->cqr_base + params->cq_off.overflow;
+ uring->cqr_entries = uring->cqr_base + params->cq_off.cqes;
+ return uring->fd;
+}
+
+int safe_io_uring_close(const char *file, const int lineno,
+ struct tst_io_uring *uring)
+{
+ int ret;
+
+ safe_munmap(file, lineno, NULL, uring->cqr_base, uring->cqr_mapsize);
+ safe_munmap(file, lineno, NULL, uring->sqr_entries,
+ uring->sqr_size * sizeof(struct io_uring_sqe));
+ safe_munmap(file, lineno, NULL, uring->sqr_base, uring->sqr_mapsize);
+ ret = safe_close(file, lineno, NULL, uring->fd);
+ uring->fd = -1;
+ return ret;
+}
+
+int safe_io_uring_enter(const char *file, const int lineno, int strict,
+ int fd, unsigned int to_submit, unsigned int min_complete,
+ unsigned int flags, sigset_t *sig)
+{
+ int ret;
+
+ errno = 0;
+ ret = io_uring_enter(fd, to_submit, min_complete, flags, sig);
+
+ if (ret == -1) {
+ tst_brk_(file, lineno, TBROK | TERRNO,
+ "io_uring_enter() failed");
+ } else if (ret < 0) {
+ tst_brk_(file, lineno, TBROK | TERRNO,
+ "Invalid io_uring_enter() return value %d", ret);
+ } else if (strict && to_submit != (unsigned int)ret) {
+ tst_brk_(file, lineno, TBROK,
+ "io_uring_enter() submitted %d items (expected %d)",
+ ret, to_submit);
+ }
+
+ return ret;
+}
--
2.30.0
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [LTP] [PATCH 3/4] Add CAP_SYS_CHROOT to lapi/capability.h
2021-02-01 16:39 [LTP] [PATCH 1/4] Prevent linker issues in lapi/io_uring.h Martin Doucha
2021-02-01 16:39 ` [LTP] [PATCH 2/4] Add safe functions for io_uring to LTP library Martin Doucha
@ 2021-02-01 16:39 ` Martin Doucha
2021-02-01 16:39 ` [LTP] [PATCH 4/4] Add test for CVE 2020-29373 Martin Doucha
2 siblings, 0 replies; 4+ messages in thread
From: Martin Doucha @ 2021-02-01 16:39 UTC (permalink / raw)
To: ltp
Signed-off-by: Martin Doucha <mdoucha@suse.cz>
---
include/lapi/capability.h | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/include/lapi/capability.h b/include/lapi/capability.h
index fde27efd3..95cb6819b 100644
--- a/include/lapi/capability.h
+++ b/include/lapi/capability.h
@@ -24,6 +24,10 @@
# define CAP_NET_RAW 13
#endif
+#ifndef CAP_SYS_CHROOT
+# define CAP_SYS_CHROOT 18
+#endif
+
#ifndef CAP_SYS_ADMIN
# define CAP_SYS_ADMIN 21
#endif
--
2.30.0
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [LTP] [PATCH 4/4] Add test for CVE 2020-29373
2021-02-01 16:39 [LTP] [PATCH 1/4] Prevent linker issues in lapi/io_uring.h Martin Doucha
2021-02-01 16:39 ` [LTP] [PATCH 2/4] Add safe functions for io_uring to LTP library Martin Doucha
2021-02-01 16:39 ` [LTP] [PATCH 3/4] Add CAP_SYS_CHROOT to lapi/capability.h Martin Doucha
@ 2021-02-01 16:39 ` Martin Doucha
2 siblings, 0 replies; 4+ messages in thread
From: Martin Doucha @ 2021-02-01 16:39 UTC (permalink / raw)
To: ltp
Fixes #770
Signed-off-by: Martin Doucha <mdoucha@suse.cz>
---
runtest/cve | 1 +
runtest/syscalls | 1 +
.../kernel/syscalls/io_uring/io_uring02.c | 197 ++++++++++++++++++
3 files changed, 199 insertions(+)
create mode 100644 testcases/kernel/syscalls/io_uring/io_uring02.c
diff --git a/runtest/cve b/runtest/cve
index 0bb1983bc..f650854f9 100644
--- a/runtest/cve
+++ b/runtest/cve
@@ -60,3 +60,4 @@ cve-2019-8912 af_alg07
cve-2020-11494 pty04
cve-2020-14386 sendto03
cve-2020-14416 pty03
+cve-2020-29373 io_uring02
diff --git a/runtest/syscalls b/runtest/syscalls
index 11a1e83c2..dbb33a2cd 100644
--- a/runtest/syscalls
+++ b/runtest/syscalls
@@ -1712,3 +1712,4 @@ statx07 statx07
membarrier01 membarrier01
io_uring01 io_uring01
+io_uring02 io_uring02
diff --git a/testcases/kernel/syscalls/io_uring/io_uring02.c b/testcases/kernel/syscalls/io_uring/io_uring02.c
new file mode 100644
index 000000000..b045cc34e
--- /dev/null
+++ b/testcases/kernel/syscalls/io_uring/io_uring02.c
@@ -0,0 +1,197 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2021 SUSE LLC
+ * Author: Nicolai Stange <nstange@suse.de>
+ * LTP port: Martin Doucha <mdoucha@suse.cz>
+ *
+ * CVE-2020-29373
+ *
+ * Check that io_uring does not bypass chroot. Fixed in:
+ *
+ * commit ff002b30181d30cdfbca316dadd099c3ca0d739c
+ * Author: Jens Axboe <axboe@kernel.dk>
+ * Date: Fri Feb 7 16:05:21 2020 -0700
+ *
+ * io_uring: grab ->fs as part of async preparation
+ */
+
+#include <stdio.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include "tst_test.h"
+#include "tst_safe_io_uring.h"
+
+#define CHROOT_DIR "test_root"
+#define SOCK_NAME "sock"
+#define SPAM_MARK 0xfa7
+#define BEEF_MARK 0xbeef
+
+static struct sockaddr_un addr;
+static int sendsock = -1, recvsock = -1, sockpair[2] = {-1, -1};
+static struct io_uring_params params;
+static struct tst_io_uring uring = { .fd = -1 };
+static char buf[16];
+static struct iovec iov = {
+ .iov_base = buf,
+ .iov_len = sizeof(buf)
+};
+
+static struct msghdr spam_header = {
+ .msg_name = NULL,
+ .msg_namelen = 0,
+ .msg_iov = &iov,
+ .msg_iovlen = 1
+};
+
+static struct msghdr beef_header = {
+ .msg_name = &addr,
+ .msg_namelen = sizeof(addr),
+ .msg_iov = &iov,
+ .msg_iovlen = 1
+};
+
+static void setup(void)
+{
+ char *tmpdir = tst_get_tmpdir();
+ int ret;
+
+ addr.sun_family = AF_UNIX;
+ ret = snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/%s", tmpdir,
+ SOCK_NAME);
+ free(tmpdir);
+
+ if (ret >= (int)sizeof(addr.sun_path))
+ tst_brk(TBROK, "Tempdir path is too long");
+
+ io_uring_setup_supported_by_kernel();
+
+ sendsock = SAFE_SOCKET(AF_UNIX, SOCK_DGRAM, 0);
+ recvsock = SAFE_SOCKET(AF_UNIX, SOCK_DGRAM, 0);
+ SAFE_BIND(recvsock, (struct sockaddr *)&addr, sizeof(addr));
+
+ SAFE_MKDIR(CHROOT_DIR, 0755);
+ SAFE_CHROOT(CHROOT_DIR);
+}
+
+static void run(void)
+{
+ uint32_t i, count, tail;
+ int beef_found = 0;
+ struct io_uring_sqe *sqe_ptr;
+ const struct io_uring_cqe *cqe_ptr;
+
+ SAFE_SOCKETPAIR(AF_UNIX, SOCK_DGRAM, 0, sockpair);
+ SAFE_SETSOCKOPT_INT(sockpair[0], SOL_SOCKET, SO_SNDBUF,
+ 32+sizeof(buf));
+ SAFE_FCNTL(sockpair[0], F_SETFL, O_NONBLOCK);
+
+ SAFE_IO_URING_INIT(512, ¶ms, &uring);
+ sqe_ptr = uring.sqr_entries;
+
+ /* Add spam requests to force async processing of the real test */
+ for (i = 0, tail = *uring.sqr_tail; i < 255; i++, tail++, sqe_ptr++) {
+ memset(sqe_ptr, 0, sizeof(*sqe_ptr));
+ sqe_ptr->opcode = IORING_OP_SENDMSG;
+ sqe_ptr->flags = IOSQE_IO_DRAIN;
+ sqe_ptr->fd = sockpair[0];
+ sqe_ptr->addr = (__u64)&spam_header;
+ sqe_ptr->user_data = SPAM_MARK;
+ uring.sqr_array[tail & *uring.sqr_mask] = i;
+ }
+
+ /* Add the real test to queue */
+ memset(sqe_ptr, 0, sizeof(*sqe_ptr));
+ sqe_ptr->opcode = IORING_OP_SENDMSG;
+ sqe_ptr->flags = IOSQE_IO_DRAIN;
+ sqe_ptr->fd = sendsock;
+ sqe_ptr->addr = (__u64)&beef_header;
+ sqe_ptr->user_data = BEEF_MARK;
+ uring.sqr_array[tail & *uring.sqr_mask] = i;
+ count = ++i;
+ tail++;
+
+ __atomic_store(uring.sqr_tail, &tail, __ATOMIC_RELEASE);
+ SAFE_IO_URING_ENTER(1, uring.fd, count, count, IORING_ENTER_GETEVENTS,
+ NULL);
+
+ /* Check test results */
+ __atomic_load(uring.cqr_tail, &tail, __ATOMIC_ACQUIRE);
+
+ for (i = *uring.cqr_head; i != tail; i++, count--) {
+ cqe_ptr = uring.cqr_entries + (i & *uring.cqr_mask);
+ TST_ERR = -cqe_ptr->res;
+
+ if (cqe_ptr->user_data == SPAM_MARK) {
+ if (cqe_ptr->res >= 0 || cqe_ptr->res == -EAGAIN)
+ continue;
+
+ tst_res(TFAIL | TTERRNO,
+ "Spam request failed unexpectedly");
+ continue;
+ }
+
+ if (cqe_ptr->user_data != BEEF_MARK) {
+ tst_res(TFAIL, "Unexpected entry in completion queue");
+ count++;
+ continue;
+ }
+
+ beef_found = 1;
+
+ if (cqe_ptr->res >= 0) {
+ tst_res(TFAIL, "Write outside chroot succeeded.");
+ } else if (cqe_ptr->res != -ENOENT) {
+ tst_res(TFAIL | TTERRNO,
+ "Write outside chroot failed unexpectedly");
+ } else {
+ tst_res(TPASS,
+ "Write outside chroot failed as expected");
+ }
+ }
+
+ __atomic_store(uring.cqr_head, &i, __ATOMIC_RELEASE);
+
+ if (!beef_found)
+ tst_res(TFAIL, "Write outside chroot result not found");
+
+ if (count)
+ tst_res(TFAIL, "Wrong number of entries in completion queue");
+
+ /* iteration cleanup */
+ SAFE_IO_URING_CLOSE(&uring);
+ SAFE_CLOSE(sockpair[0]);
+ SAFE_CLOSE(sockpair[1]);
+}
+
+static void cleanup(void)
+{
+ if (uring.fd >= 0)
+ SAFE_IO_URING_CLOSE(&uring);
+
+ if (sockpair[0] >= 0) {
+ SAFE_CLOSE(sockpair[0]);
+ SAFE_CLOSE(sockpair[1]);
+ }
+
+ if (recvsock >= 0)
+ SAFE_CLOSE(recvsock);
+
+ if (sendsock >= 0)
+ SAFE_CLOSE(sendsock);
+}
+
+static struct tst_test test = {
+ .test_all = run,
+ .setup = setup,
+ .cleanup = cleanup,
+ .needs_tmpdir = 1,
+ .caps = (struct tst_cap []) {
+ TST_CAP(TST_CAP_REQ, CAP_SYS_CHROOT),
+ {}
+ },
+ .tags = (const struct tst_tag[]) {
+ {"linux-git", "ff002b30181d"},
+ {"CVE", "2020-29373"},
+ {}
+ }
+};
--
2.30.0
^ permalink raw reply related [flat|nested] 4+ messages in thread
end of thread, other threads:[~2021-02-01 16:39 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-02-01 16:39 [LTP] [PATCH 1/4] Prevent linker issues in lapi/io_uring.h Martin Doucha
2021-02-01 16:39 ` [LTP] [PATCH 2/4] Add safe functions for io_uring to LTP library Martin Doucha
2021-02-01 16:39 ` [LTP] [PATCH 3/4] Add CAP_SYS_CHROOT to lapi/capability.h Martin Doucha
2021-02-01 16:39 ` [LTP] [PATCH 4/4] Add test for CVE 2020-29373 Martin Doucha
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.