• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
40 char *TCID = "fork14";
41 int 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 
49 static char **pointer_vec;
50 
51 static void setup(void);
52 static void cleanup(void);
53 static int  fork_test(void);
54 
main(int ac,char ** av)55 int 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 
setup(void)79 static 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 
cleanup(void)87 static void cleanup(void)
88 {
89 	free(pointer_vec);
90 }
91 
fork_test(void)92 static int fork_test(void)
93 {
94 	int i, j, prev_failed = 0, fails = 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 
118 		switch (tst_fork()) {
119 		case -1:
120 			prev_failed = 1;
121 		break;
122 		case 0:
123 			exit(0);
124 		default:
125 			SAFE_WAITPID(cleanup, -1, NULL, 0);
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