144 lines
3.7 KiB
C
144 lines
3.7 KiB
C
/*********************************************************************
|
|
* Copyright (C) 2014 Red Hat, Inc.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of version 2 of the GNU General Public
|
|
* License as published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it would be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
*
|
|
* Further, this software is distributed without any warranty that it
|
|
* is free of the rightful claim of any third person regarding
|
|
* infringement or the like. Any license provided herein, whether
|
|
* implied or otherwise, applies only to this software file. Patent
|
|
* licenses, if any, provided herein do not apply to combinations of
|
|
* this program with other software, or any other product whatsoever.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
* 02110-1301, USA.
|
|
*
|
|
* This test is a reporducer for this patch:
|
|
* https://lkml.org/lkml/2012/4/24/328
|
|
* Since vma length in dup_mmap is calculated and stored in a unsigned
|
|
* int, it will overflow when length of mmaped memory > 16 TB. When
|
|
* overflow occur, fork will incorrectly succeed. The patch above
|
|
* fixed it.
|
|
********************************************************************/
|
|
|
|
#include <sys/mman.h>
|
|
#include <sys/wait.h>
|
|
#include <stdio.h>
|
|
#include <unistd.h>
|
|
#include "test.h"
|
|
#include "safe_macros.h"
|
|
#include "lapi/abisize.h"
|
|
|
|
char *TCID = "fork14";
|
|
int TST_TOTAL = 1;
|
|
|
|
#define GB (1024 * 1024 * 1024L)
|
|
|
|
/* set mmap threshold to 16TB */
|
|
#define LARGE (16 * 1024)
|
|
#define EXTENT (16 * 1024 + 10)
|
|
|
|
static char **pointer_vec;
|
|
|
|
static void setup(void);
|
|
static void cleanup(void);
|
|
static int fork_test(void);
|
|
|
|
int main(int ac, char **av)
|
|
{
|
|
int lc, reproduced;
|
|
|
|
tst_parse_opts(ac, av, NULL, NULL);
|
|
/*
|
|
* Tested on ppc64/x86_64/i386/s390x. And only 64bit has this issue.
|
|
* Since a 32bit program can't mmap so many memory.
|
|
*/
|
|
#ifdef TST_ABI32
|
|
tst_brkm(TCONF, NULL, "This test is only for 64bit.");
|
|
#endif
|
|
setup();
|
|
for (lc = 0; TEST_LOOPING(lc); lc++) {
|
|
tst_count = 0;
|
|
|
|
reproduced = fork_test();
|
|
if (reproduced == 0)
|
|
tst_resm(TPASS, "fork failed as expected.");
|
|
}
|
|
cleanup();
|
|
tst_exit();
|
|
}
|
|
|
|
static void setup(void)
|
|
{
|
|
tst_sig(FORK, DEF_HANDLER, cleanup);
|
|
TEST_PAUSE;
|
|
|
|
pointer_vec = SAFE_MALLOC(cleanup, EXTENT * sizeof(char *));
|
|
}
|
|
|
|
static void cleanup(void)
|
|
{
|
|
free(pointer_vec);
|
|
}
|
|
|
|
static int fork_test(void)
|
|
{
|
|
int i, j, prev_failed = 0, fails = 0, cnt = 0;
|
|
int reproduced = 0;
|
|
void *addr;
|
|
|
|
for (i = 0; i < EXTENT; i++) {
|
|
addr = mmap(NULL, 1 * GB, PROT_READ | PROT_WRITE,
|
|
MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
|
|
if (addr == MAP_FAILED) {
|
|
pointer_vec[i] = NULL;
|
|
fails++;
|
|
/*
|
|
* EXTENT is "16*1024+10", if fails count exceeds 10,
|
|
* we are almost impossible to get an vm_area_struct
|
|
* sized 16TB
|
|
*/
|
|
if (fails == 11) {
|
|
tst_brkm(TCONF, cleanup, "mmap() fails too many"
|
|
"times, so we are almost impossible to"
|
|
" get an vm_area_struct sized 16TB.");
|
|
}
|
|
} else {
|
|
pointer_vec[i] = addr;
|
|
}
|
|
cnt++;
|
|
|
|
switch (tst_fork()) {
|
|
case -1:
|
|
prev_failed = 1;
|
|
break;
|
|
case 0:
|
|
exit(0);
|
|
default:
|
|
SAFE_WAITPID(cleanup, -1, NULL, 0);
|
|
|
|
if (prev_failed > 0 && i >= LARGE) {
|
|
tst_resm(TFAIL, "Fork succeeds incorrectly");
|
|
reproduced = 1;
|
|
goto clear_memory_map;
|
|
}
|
|
}
|
|
}
|
|
|
|
clear_memory_map:
|
|
for (j = 0; j < cnt; j++) {
|
|
if (pointer_vec[j])
|
|
SAFE_MUNMAP(cleanup, pointer_vec[j], 1 * GB);
|
|
}
|
|
|
|
return reproduced;
|
|
}
|