diff options
-rw-r--r-- | test/Makefile | 6 | ||||
-rw-r--r-- | test/ring-leak.c | 108 |
2 files changed, 112 insertions, 2 deletions
diff --git a/test/Makefile b/test/Makefile index 1ec920d..db8b09a 100644 --- a/test/Makefile +++ b/test/Makefile @@ -1,10 +1,10 @@ CFLAGS ?= -g -O2 -Wall -D_GNU_SOURCE -L../src/ -all_targets += io_uring-test io_uring-cp poll poll-cancel +all_targets += io_uring-test io_uring-cp poll poll-cancel ring-leak all: $(all_targets) -test_srcs := io_uring-test.c io_uring-cp.c poll.c poll-cancel.c +test_srcs := io_uring-test.c io_uring-cp.c poll.c poll-cancel.c ring-leak.c test_objs := $(patsubst %.c,%.ol,$(test_srcs)) @@ -16,5 +16,7 @@ poll: poll.c $(CC) $(CFLAGS) -o $@ poll.c -luring poll-cancel: poll-cancel.c $(CC) $(CFLAGS) -o $@ poll-cancel.c -luring +ring-leak: ring-leak.c + $(CC) $(CFLAGS) -o $@ ring-leak.c -luring clean: rm -f $(all_targets) $(test_objs) diff --git a/test/ring-leak.c b/test/ring-leak.c new file mode 100644 index 0000000..5f12ac7 --- /dev/null +++ b/test/ring-leak.c @@ -0,0 +1,108 @@ +/* + * Based on description from Al Viro - this demonstrates a leak of the + * io_uring instance, by sending the io_uring fd over a UNIX socket. + * + * See: + * + * https://lore.kernel.org/linux-block/20190129192702.3605-1-axboe@kernel.dk/T/#m6c87fc64e4d063786af6ec6fadce3ac1e95d3184 + * + */ +#include <stdio.h> +#include <stdlib.h> +#include <stddef.h> +#include <signal.h> +#include <inttypes.h> +#include <sys/types.h> +#include <sys/syscall.h> +#include <sys/socket.h> +#include <sys/wait.h> +#include <fcntl.h> +#include <unistd.h> +#include <string.h> +#include <linux/fs.h> + +#include "../src/liburing.h" + +static int io_uring_register_files(int ring_fd, int fd1, int fd2) +{ + __s32 *fds; + + fds = calloc(2, sizeof(__s32)); + fds[0] = fd1; + fds[1] = fd2; + + return io_uring_register(ring_fd, IORING_REGISTER_FILES, fds, 2); +} + +static int get_ring_fd(void) +{ + struct io_uring_params p; + int fd; + + memset(&p, 0, sizeof(p)); + + fd = io_uring_setup(2, &p); + if (fd < 0) { + perror("io_uring_setup"); + return -1; + } + + return fd; +} + +static void send_fd(int socket, int fd) +{ + char buf[CMSG_SPACE(sizeof(fd))]; + struct cmsghdr *cmsg; + struct msghdr msg; + + memset(buf, 0, sizeof(buf)); + memset(&msg, 0, sizeof(msg)); + + msg.msg_control = buf; + msg.msg_controllen = sizeof(buf); + + cmsg = CMSG_FIRSTHDR(&msg); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + cmsg->cmsg_len = CMSG_LEN(sizeof(fd)); + + memmove(CMSG_DATA(cmsg), &fd, sizeof(fd)); + + msg.msg_controllen = CMSG_SPACE(sizeof(fd)); + + if (sendmsg(socket, &msg, 0) < 0) + perror("sendmsg"); +} + +int main(int argc, char *argv[]) +{ + int sp[2], pid, ring_fd, ret; + + if (socketpair(AF_UNIX, SOCK_DGRAM, 0, sp) != 0) { + perror("Failed to create Unix-domain socket pair\n"); + return 1; + } + + ring_fd = get_ring_fd(); + if (ring_fd < 0) + return 1; + + ret = io_uring_register_files(ring_fd, sp[0], sp[1]); + if (ret < 0) { + perror("register files"); + return 1; + } + + pid = fork(); + if (pid) { + printf("Sending fd %d\n", ring_fd); + + send_fd(sp[0], ring_fd); + } + + close(ring_fd); + close(sp[0]); + close(sp[1]); + return 0; +} |