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