blob: dd8f96aeeb5eb6f9fb3847043093a79941f91682 [file] [log] [blame]
Madper Xied84e52d2014-02-25 00:23:22 +08001/*********************************************************************
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"
Xiaoguang Wang9c18ca22014-03-26 14:25:42 +080037#include "safe_macros.h"
Madper Xied84e52d2014-02-25 00:23:22 +080038
39char *TCID = "fork14";
40int 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
Xiaoguang Wang9c18ca22014-03-26 14:25:42 +080048static char **pointer_vec;
49
Madper Xied84e52d2014-02-25 00:23:22 +080050static void setup(void);
51static void cleanup(void);
52static int fork_test(void);
53
54int main(int ac, char **av)
55{
Xiaoguang Wang9c18ca22014-03-26 14:25:42 +080056 int lc, reproduced;
Cyril Hrubis0b9589f2014-05-27 17:40:33 +020057 const char *msg;
Madper Xied84e52d2014-02-25 00:23:22 +080058
59 msg = parse_opts(ac, av, NULL, NULL);
60 if (msg != NULL)
61 tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg);
62/*
63 * Tested on ppc64/x86_64/i386/s390x. And only 64bit has this issue.
64 * Since a 32bit program can't mmap so many memory.
65 */
66#if __WORDSIZE == 32
67 tst_brkm(TCONF, NULL, "This test is only for 64bit.");
68#endif
69 setup();
70 for (lc = 0; TEST_LOOPING(lc); lc++) {
71 tst_count = 0;
72
Xiaoguang Wang9c18ca22014-03-26 14:25:42 +080073 reproduced = fork_test();
74 if (reproduced == 0)
Madper Xied84e52d2014-02-25 00:23:22 +080075 tst_resm(TPASS, "fork failed as expected.");
76 }
77 cleanup();
78 tst_exit();
79}
80
81static void setup(void)
82{
83 tst_sig(FORK, DEF_HANDLER, cleanup);
84 TEST_PAUSE;
Xiaoguang Wang9c18ca22014-03-26 14:25:42 +080085
86 pointer_vec = SAFE_MALLOC(cleanup, EXTENT * sizeof(char *));
Madper Xied84e52d2014-02-25 00:23:22 +080087}
88
89static void cleanup(void)
90{
Xiaoguang Wang9c18ca22014-03-26 14:25:42 +080091 free(pointer_vec);
Madper Xied84e52d2014-02-25 00:23:22 +080092}
93
94static int fork_test(void)
95{
Xiaoguang Wang9c18ca22014-03-26 14:25:42 +080096 int i, j, prev_failed = 0, fails = 0;
97 int reproduced = 0;
98 void *addr;
Madper Xied84e52d2014-02-25 00:23:22 +080099
100 for (i = 0; i < EXTENT; i++) {
Xiaoguang Wang9c18ca22014-03-26 14:25:42 +0800101 addr = mmap(NULL, 1 * GB, PROT_READ | PROT_WRITE,
102 MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
103 if (addr == MAP_FAILED) {
104 pointer_vec[i] = NULL;
105 fails++;
106 /*
107 * EXTENT is "16*1024+10", if fails count exceeds 10,
108 * we are almost impossible to get an vm_area_struct
109 * sized 16TB
110 */
111 if (fails == 11) {
112 tst_brkm(TCONF, cleanup, "mmap() fails too many"
113 "times, so we are almost impossible to"
114 " get an vm_area_struct sized 16TB.");
115 }
116 } else {
117 pointer_vec[i] = addr;
118 }
119
120 switch (tst_fork()) {
Madper Xied84e52d2014-02-25 00:23:22 +0800121 case -1:
Xiaoguang Wang9c18ca22014-03-26 14:25:42 +0800122 prev_failed = 1;
123 break;
Madper Xied84e52d2014-02-25 00:23:22 +0800124 case 0:
125 exit(0);
126 default:
127 if (waitpid(-1, NULL, 0) == -1)
Xiaoguang Wang9c18ca22014-03-26 14:25:42 +0800128 tst_brkm(TBROK | TERRNO, cleanup, "waitpid");
Madper Xied84e52d2014-02-25 00:23:22 +0800129
Xiaoguang Wang9c18ca22014-03-26 14:25:42 +0800130 if (prev_failed > 0 && i >= LARGE) {
131 tst_resm(TFAIL, "Fork succeeds incorrectly");
132 reproduced = 1;
133 goto clear_memory_map;
Madper Xied84e52d2014-02-25 00:23:22 +0800134 }
135 }
136 }
Xiaoguang Wang9c18ca22014-03-26 14:25:42 +0800137
138clear_memory_map:
139 for (j = 0; j <= i; j++) {
140 if (pointer_vec[j])
141 SAFE_MUNMAP(cleanup, pointer_vec[j], 1 * GB);
142 }
143
144 return reproduced;
Madper Xied84e52d2014-02-25 00:23:22 +0800145}