1/* 2 * Copyright (C) 2012 Red Hat, Inc. 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of version 2 of the GNU General Public 6 * License as published by the Free Software Foundation. 7 * 8 * This program is distributed in the hope that it would be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 * 12 * Further, this software is distributed without any warranty that it 13 * is free of the rightful claim of any third person regarding 14 * infringement or the like. Any license provided herein, whether 15 * implied or otherwise, applies only to this software file. Patent 16 * licenses, if any, provided herein do not apply to combinations of 17 * this program with other software, or any other product whatsoever. 18 * 19 * You should have received a copy of the GNU General Public License 20 * along with this program; if not, write the Free Software 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 22 * 02110-1301, USA. 23 */ 24/* 25 * This is a reproducer for CVE-2011-2496. 26 * 27 * The normal mmap paths all avoid creating a mapping where the pgoff 28 * inside the mapping could wrap around due to overflow. However, an 29 * expanding mremap() can take such a non-wrapping mapping and make it 30 * bigger and cause a wrapping condition. There is also another case 31 * where we expand mappings hiding in plain sight: the automatic stack 32 * expansion. 33 * 34 * This program tries to remap a mapping with a new size that would 35 * wrap pgoff. Notice that it only works on 32-bit arch for now. 36 */ 37 38#define _GNU_SOURCE 39#include "config.h" 40#include <sys/types.h> 41#include <sys/mman.h> 42#include <sys/stat.h> 43#include <sys/syscall.h> 44#include <errno.h> 45#include <fcntl.h> 46#include <limits.h> 47#include <stdio.h> 48#include <stdlib.h> 49#include <unistd.h> 50 51#include "test.h" 52#include "safe_macros.h" 53#include "tst_kernel.h" 54#include "lapi/abisize.h" 55 56char *TCID = "vma03"; 57int TST_TOTAL = 1; 58 59#ifdef __NR_mmap2 60#define TESTFILE "testfile" 61 62static size_t pgsz; 63static int fd; 64 65static void *mmap2(void *addr, size_t length, int prot, 66 int flags, int fd, off_t pgoffset); 67static void setup(void); 68static void cleanup(void); 69 70int main(int argc, char *argv[]) 71{ 72 int lc; 73 void *map, *remap; 74 off_t pgoff; 75 76 if (TST_ABI != 32 || tst_kernel_bits() != 32) { 77 tst_brkm(TCONF, NULL, 78 "test is designed for 32-bit system only."); 79 } 80 81 tst_parse_opts(argc, argv, NULL, NULL); 82 83 pgsz = sysconf(_SC_PAGE_SIZE); 84 setup(); 85 86 for (lc = 0; TEST_LOOPING(lc); lc++) { 87 tst_count = 0; 88 89 fd = SAFE_OPEN(NULL, TESTFILE, O_RDWR); 90 91 /* 92 * The pgoff is counted in 4K units and must be page-aligned, 93 * hence we must align it down to page_size/4096 in a case that 94 * the system has page_size > 4K. 95 */ 96 pgoff = (ULONG_MAX - 1)&(~((pgsz-1)>>12)); 97 map = mmap2(NULL, pgsz, PROT_READ | PROT_WRITE, MAP_PRIVATE, 98 fd, pgoff); 99 if (map == MAP_FAILED) 100 tst_brkm(TBROK | TERRNO, cleanup, "mmap2"); 101 102 remap = mremap(map, pgsz, 2 * pgsz, 0); 103 if (remap == MAP_FAILED) { 104 if (errno == EINVAL) 105 tst_resm(TPASS, "mremap failed as expected."); 106 else 107 tst_resm(TFAIL | TERRNO, "mremap"); 108 munmap(map, pgsz); 109 } else { 110 tst_resm(TFAIL, "mremap succeeded unexpectedly."); 111 munmap(remap, 2 * pgsz); 112 } 113 114 close(fd); 115 } 116 117 cleanup(); 118 tst_exit(); 119} 120 121static void *mmap2(void *addr, size_t length, int prot, 122 int flags, int fd, off_t pgoffset) 123{ 124 return (void *)syscall(SYS_mmap2, addr, length, prot, 125 flags, fd, pgoffset); 126} 127 128static void setup(void) 129{ 130 tst_sig(FORK, DEF_HANDLER, cleanup); 131 132 tst_tmpdir(); 133 134 fd = SAFE_CREAT(NULL, TESTFILE, 0644); 135 close(fd); 136 137 TEST_PAUSE; 138} 139 140static void cleanup(void) 141{ 142 tst_rmdir(); 143} 144#else /* __NR_mmap2 */ 145int main(int argc, char *argv[]) 146{ 147 tst_brkm(TCONF, NULL, "__NR_mmap2 is not defined on your system"); 148} 149#endif 150