Skip to content

Commit

Permalink
Refactor fork14 using new LTP API
Browse files Browse the repository at this point in the history
Reviewed-by: Martin Doucha <mdoucha@suse.cz>
Reviewed-by: Petr Vorel <pvorel@suse.cz>
Signed-off-by: Andrea Cervesato <andrea.cervesato@suse.com>
[ pvorel: add .skip_in_32bit ]
Signed-off-by: Petr Vorel <pvorel@suse.cz>
  • Loading branch information
acerv authored and pevik committed May 16, 2024
1 parent df1efd9 commit 7288bc8
Showing 1 changed file with 96 additions and 114 deletions.
210 changes: 96 additions & 114 deletions testcases/kernel/syscalls/fork/fork14.c
Original file line number Diff line number Diff line change
@@ -1,143 +1,125 @@
/*********************************************************************
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2014 Red Hat, Inc.
* Copyright (C) 2024 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com>
*/

/*\
* [Description]
*
* 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 reproducer for kernel 3.5:
* 7edc8b0ac16c ("mm/fork: fix overflow in vma length when copying mmap on clone")
*
* 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
* 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.
********************************************************************/
* overflow occurs, fork will incorrectly succeed. The patch above fixed it.
*/

#include <sys/mman.h>
#include "tst_test.h"
#include <stdlib.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 char **memvec;

static void setup(void);
static void cleanup(void);
static int fork_test(void);

int main(int ac, char **av)
static void run(void)
{
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();
}
int i, j, ret;
pid_t pid;
void *mem;
int prev_failed = 0;
int passed = 1;
int failures = 0;

static void setup(void)
{
tst_sig(FORK, DEF_HANDLER, cleanup);
TEST_PAUSE;
memset(memvec, 0, EXTENT);

pointer_vec = SAFE_MALLOC(cleanup, EXTENT * sizeof(char *));
}
for (i = 0; i < EXTENT; i++) {
mem = mmap(NULL, 1 * TST_GB,
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS,
0, 0);

static void cleanup(void)
{
free(pointer_vec);
}
if (mem == MAP_FAILED) {
failures++;

static int fork_test(void)
{
int i, j, prev_failed = 0, fails = 0, cnt = 0;
int reproduced = 0;
void *addr;
tst_res(TINFO, "mmap() failed");

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.");
if (failures > 10) {
tst_brk(TCONF, "mmap() fails too many "
"times, so it's almost impossible to "
"get a vm_area_struct sized 16TB");
}
} else {
pointer_vec[i] = addr;

continue;
}
cnt++;

switch (tst_fork()) {
case -1:
memvec[i] = mem;

pid = fork();

if (pid == -1) {
/* keep track of the failed fork() and verify that next one
* is failing as well.
*/
prev_failed = 1;
break;
case 0:
continue;
}

if (!pid)
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;
}
ret = waitpid(pid, NULL, 0);
if (ret == -1 && errno != ECHILD)
tst_brk(TBROK | TERRNO, "waitpid() error");

if (prev_failed && i >= LARGE) {
passed = 0;
break;
}

prev_failed = 0;

tst_res(TDEBUG, "fork() passed at %d attempt", i);
}

clear_memory_map:
for (j = 0; j < cnt; j++) {
if (pointer_vec[j])
SAFE_MUNMAP(cleanup, pointer_vec[j], 1 * GB);
for (j = 0; j < i; j++) {
if (memvec[j])
SAFE_MUNMAP(memvec[j], 1 * TST_GB);
}

return reproduced;
if (passed)
tst_res(TPASS, "fork() failed as expected");
else
tst_res(TFAIL, "fork() succeeded incorrectly");
}

static void setup(void)
{
memvec = SAFE_MALLOC(EXTENT * sizeof(char *));
}

static void cleanup(void)
{
for (long i = 0; i < EXTENT; i++) {
if (memvec && memvec[i])
SAFE_MUNMAP(memvec[i], 1 * TST_GB);
}

if (memvec)
free(memvec);
}

static struct tst_test test = {
.test_all = run,
.setup = setup,
.cleanup = cleanup,
.forks_child = 1,
.skip_in_compat = 1,
.skip_in_32bit = 1,
.tags = (const struct tst_tag[]) {
{"linux-git", "7edc8b0ac16c"},
{}
}
};

0 comments on commit 7288bc8

Please sign in to comment.