1 /********************************************************************* 2 * Copyright (C) 2014 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 * This test is a reporducer for this patch: 25 * https://lkml.org/lkml/2012/4/24/328 26 * Since vma length in dup_mmap is calculated and stored in a unsigned 27 * int, it will overflow when length of mmaped memory > 16 TB. When 28 * overflow occur, fork will incorrectly succeed. The patch above 29 * fixed it. 30 ********************************************************************/ 31 32 #include <sys/mman.h> 33 #include <sys/wait.h> 34 #include <stdio.h> 35 #include <unistd.h> 36 #include "test.h" 37 #include "safe_macros.h" 38 39 char *TCID = "fork14"; 40 int TST_TOTAL = 1; 41 42 #define GB (1024 * 1024 * 1024L) 43 44 /* set mmap threshold to 16TB */ 45 #define LARGE (16 * 1024) 46 #define EXTENT (16 * 1024 + 10) 47 48 static char **pointer_vec; 49 50 static void setup(void); 51 static void cleanup(void); 52 static int fork_test(void); 53 54 int main(int ac, char **av) 55 { 56 int lc, reproduced; 57 58 tst_parse_opts(ac, av, NULL, NULL); 59 /* 60 * Tested on ppc64/x86_64/i386/s390x. And only 64bit has this issue. 61 * Since a 32bit program can't mmap so many memory. 62 */ 63 #if __WORDSIZE == 32 64 tst_brkm(TCONF, NULL, "This test is only for 64bit."); 65 #endif 66 setup(); 67 for (lc = 0; TEST_LOOPING(lc); lc++) { 68 tst_count = 0; 69 70 reproduced = fork_test(); 71 if (reproduced == 0) 72 tst_resm(TPASS, "fork failed as expected."); 73 } 74 cleanup(); 75 tst_exit(); 76 } 77 78 static void setup(void) 79 { 80 tst_sig(FORK, DEF_HANDLER, cleanup); 81 TEST_PAUSE; 82 83 pointer_vec = SAFE_MALLOC(cleanup, EXTENT * sizeof(char *)); 84 } 85 86 static void cleanup(void) 87 { 88 free(pointer_vec); 89 } 90 91 static int fork_test(void) 92 { 93 int i, j, prev_failed = 0, fails = 0; 94 int reproduced = 0; 95 void *addr; 96 97 for (i = 0; i < EXTENT; i++) { 98 addr = mmap(NULL, 1 * GB, PROT_READ | PROT_WRITE, 99 MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); 100 if (addr == MAP_FAILED) { 101 pointer_vec[i] = NULL; 102 fails++; 103 /* 104 * EXTENT is "16*1024+10", if fails count exceeds 10, 105 * we are almost impossible to get an vm_area_struct 106 * sized 16TB 107 */ 108 if (fails == 11) { 109 tst_brkm(TCONF, cleanup, "mmap() fails too many" 110 "times, so we are almost impossible to" 111 " get an vm_area_struct sized 16TB."); 112 } 113 } else { 114 pointer_vec[i] = addr; 115 } 116 117 switch (tst_fork()) { 118 case -1: 119 prev_failed = 1; 120 break; 121 case 0: 122 exit(0); 123 default: 124 SAFE_WAITPID(cleanup, -1, NULL, 0); 125 126 if (prev_failed > 0 && i >= LARGE) { 127 tst_resm(TFAIL, "Fork succeeds incorrectly"); 128 reproduced = 1; 129 goto clear_memory_map; 130 } 131 } 132 } 133 134 clear_memory_map: 135 for (j = 0; j <= i; j++) { 136 if (pointer_vec[j]) 137 SAFE_MUNMAP(cleanup, pointer_vec[j], 1 * GB); 138 } 139 140 return reproduced; 141 } 142