Home | History | Annotate | Download | only in fork
      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 			if (waitpid(-1, NULL, 0) == -1)
    125 				tst_brkm(TBROK | TERRNO, cleanup, "waitpid");
    126 
    127 			if (prev_failed > 0 && i >= LARGE) {
    128 				tst_resm(TFAIL, "Fork succeeds incorrectly");
    129 				reproduced = 1;
    130 				goto clear_memory_map;
    131 			}
    132 		}
    133 	}
    134 
    135 clear_memory_map:
    136 	for (j = 0; j <= i; j++) {
    137 		if (pointer_vec[j])
    138 			SAFE_MUNMAP(cleanup, pointer_vec[j], 1 * GB);
    139 	}
    140 
    141 	return reproduced;
    142 }
    143