blob: 7e8189f06a4e281ef78732830fcd8c749e5f578a [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2006 Kostantin Khorenko
* Copyright (C) 2006 Jeff Moyer
*/
/*
* Test aio_setup_ring with bad nr_pages
*
* Code taken from an example posted to Red Hat bugzilla #220971
* Original Author: Kostantin Khorenko from OpenVZ/Virtuozzo
* Munged by Jeff Moyer.
*
* Description: "aio_setup_ring() function initializes info->nr_pages
* variable incorrectly, then this variable can be used in error path
* to free the allocated resources. By this way an unprivileged user
* can crash the node."
*
* At the beginning of aio_setup_ring, info->nr_pages is initialized
* to the requested number of pages. However, it is supposed to
* indicate how many pages are mapped in info->ring_pages. Thus, if
* the call to do_mmap fails:
*
* info->mmap_base = do_mmap(NULL, 0, info->mmap_size,
* PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE,
* 0);
* if (IS_ERR((void *)info->mmap_base)) {
* up_write(&ctx->mm->mmap_sem);
* printk("mmap err: %ld\n", -info->mmap_base);
* info->mmap_size = 0;
* aio_free_ring(ctx); <---------
* return -EAGAIN;
* }
*
* we end up calling aio_free_ring with a bogus array and cause an oops.
*
* This is a destructive test.
*/
#include <stdio.h>
#include <unistd.h>
#include <sys/mman.h>
#include <errno.h>
#include <libgen.h>
#include <libaio.h>
int main(int __attribute__((unused)) argc, char **argv)
{
long res;
io_context_t ctx;
void* map;
while (1) {
map = mmap(NULL, 100, PROT_READ, MAP_ANONYMOUS|MAP_PRIVATE,
0, 0);
if (map == MAP_FAILED)
break;
map = mmap(NULL, 100, PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE,
0, 0);
if (map == MAP_FAILED)
break;
}
memset(&ctx, 0, sizeof(ctx));
res = io_setup(10000, &ctx);
if (res != -ENOMEM) {
printf("%s: Error: io_setup returned %ld, expected -ENOMEM\n",
basename(argv[0]), res);
return 1;
} else
printf("%s: Success!\n", basename(argv[0]));
return 0;
}