1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright (c) 2014 Dmitry Monakhov. All Rights Reserved.
5 * Perform aio writes to file and toggle O_DIRECT flag concurrently
6 * this may trigger race between file->f_flags read and modification
7 * unuligned aio allow to makes race window wider.
8 * Regression test for https://lkml.org/lkml/2014/10/8/545 CVE-2014-8086
9 * Patch proposed: http://www.spinics.net/lists/linux-ext4/msg45683.html
12 #include <sys/types.h>
21 #include <sys/types.h>
25 #define LOOP_SECONDS 10
28 static int do_aio_loop(int fd, void *buf)
31 struct io_context *ctx = NULL;
33 struct iocb iocb, *iocbs[] = { &iocb };
34 struct timeval start, now, delta = { 0, 0 };
37 err = io_setup(1, &ctx);
39 fprintf(stderr, "error %s during %s\n",
40 strerror(-err), "io_setup" );
43 gettimeofday(&start, NULL);
45 io_prep_pwrite(&iocb, fd, buf, BUF_SIZE, BUF_SIZE);
46 err = io_submit(ctx, 1, iocbs);
48 fprintf(stderr, "error %s during %s\n",
54 err = io_getevents(ctx, 1, 1, &ev, NULL);
56 fprintf(stderr, "error %s during %s\n",
62 gettimeofday(&now, NULL);
63 timersub(&now, &start, &delta);
64 if (delta.tv_sec >= LOOP_SECONDS)
71 int main(int argc, char **argv)
78 printf("Usage %s fname\n", argv[0]);
81 fd = open(argv[1], O_CREAT | O_TRUNC | O_RDWR, 0600);
94 struct timeval start, now, delta = { 0, 0 };
96 gettimeofday(&start, NULL);
98 /* child: toggle O_DIRECT*/
99 flags = fcntl(fd, F_GETFL);
101 ret = fcntl(fd, F_SETFL, flags | O_DIRECT);
103 perror("fcntl O_DIRECT");
106 ret = fcntl(fd, F_SETFL, flags);
111 gettimeofday(&now, NULL);
112 timersub(&now, &start, &delta);
113 if (delta.tv_sec >= LOOP_SECONDS)
121 err = posix_memalign(&buf, BUF_SIZE, BUF_SIZE);
122 if (err || buf == NULL) {
123 fprintf(stderr, "posix_memalign failed: %s\n",
127 /* Two tasks which performs unaligned aio will be serialized
128 which maks race window wider */
133 printf("All tasks are spawned\n");
135 ret = do_aio_loop(fd, buf);
138 /* Parent wait for all others */
140 waitpid(pid1, &ret1, 0);
143 waitpid(pid2, &ret1, 0);
145 waitpid(pid1, &ret1, 0);