1/*
2 *  Code taken from an example posted to Red Hat bugzilla #220971
3 *
4 *  Original Author: Kostantin Khorenko from OpenVZ/Virtuozzo
5 *  Munged by Jeff Moyer to incorporate it into the autotest framework.
6 *
7 *  Description: "aio_setup_ring() function initializes info->nr_pages
8 *    variable incorrectly, then this variable can be used in error path
9 *    to free the allocated resources. By this way an unprivileged user
10 *    can crash the node."
11 *
12 *  At the beginning of aio_setup_ring, info->nr_pages is initialized
13 *  to the requested number of pages.  However, it is supposed to
14 *  indicate how many pages are mapped in info->ring_pages.  Thus, if
15 *  the call to do_mmap fails:
16 *
17 *	info->mmap_base = do_mmap(NULL, 0, info->mmap_size,
18 *				  PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE,
19 *				  0);
20 *	if (IS_ERR((void *)info->mmap_base)) {
21 *		up_write(&ctx->mm->mmap_sem);
22 *		printk("mmap err: %ld\n", -info->mmap_base);
23 *		info->mmap_size = 0;
24 *		aio_free_ring(ctx);    <---------
25 *		return -EAGAIN;
26 *	}
27 *
28 *  we end up calling aio_free_ring with a bogus array and cause an oops.
29 *
30 *  This is a destructive test.
31 */
32#include <stdio.h>
33#include <unistd.h>
34#include <sys/mman.h>
35#include <errno.h>
36#include <libgen.h>
37#include <libaio.h>
38
39int main(int __attribute__((unused)) argc, char **argv)
40{
41	long res;
42	io_context_t ctx = (void*) 0;
43	void* map;
44
45	while (1) {
46		map = mmap(NULL, 100, PROT_READ, MAP_ANONYMOUS|MAP_PRIVATE,
47			   0, 0);
48		if (map == MAP_FAILED)
49			break;
50		map = mmap(NULL, 100, PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE,
51			   0, 0);
52		if (map == MAP_FAILED)
53			break;
54	}
55
56	res = io_setup(10000, &ctx);
57	if (res != -ENOMEM) {
58		printf("%s: Error: io_setup returned %ld, expected -ENOMEM\n",
59		       basename(argv[0]), res);
60		return 1;
61	} else
62		printf("%s: Success!\n", basename(argv[0]));
63	return 0;
64}
65