blob: ca0b9f39b0d6f6ba12e1c9c6e8264424da523143 [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0 or later
/*
* Copyright (c) Zilogic Systems Pvt. Ltd., 2018
* Email : code@zilogic.com
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
* the GNU General Public License for more details.
*/
/*
* test cases for madvise(2) system call, advise value as "MADV_WIPEONFORK".
*
* DESCRIPTION
* Present the child process with zero-filled memory in this
* range after a fork(2).
* The MADV_WIPEONFORK operation can be applied only to
* private anonymous pages.
* Within the child created by fork(2), the MADV_WIPEONFORK
* setting remains in place on the specified map_address range.
* The MADV_KEEPONFORK operation undo the effect of MADV_WIPEONFORK.
*
* Test-Case 1 : madvise with "MADV_WIPEONFORK"
* flow : Map memory area as private anonymous page.
* Mark memory area as wipe-on-fork.
* On fork, child process memory should be zeroed.
*
* Test-Case 2 : madvise with "MADV_WIPEONFORK" and "ZERO" length
* flow : Map memory area as private anonymous page.
* Mark memory area as wipe-on-fork, with length zero.
* On fork, child process memory should be accessible.
*
* Test-Case 3 : "MADV_WIPEONFORK" on Grand child
* flow : Map memory area as private anonymous.
* Mark memory areas as wipe-on-fork.
* On fork, child process memory should be zeroed.
* In child, fork to create grand-child,
* memory should be zeroed.
*
* Test-Case 4 : Undo "MADV_WIPEONFORK" by "MADV_KEEPONFORK"
* flow : Map memory area as private anonymous page.
* Mark memory area as wipe-on-fork.
* Mark memory area as keep-on-fork.
* On fork, child process memory should be retained.
**/
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include "lapi/mmap.h"
#include "tst_test.h"
#include "tst_safe_macros.h"
#define MAP_SIZE (16 * 1024)
static char pattern[MAP_SIZE];
static char zero[MAP_SIZE];
static const struct test_case {
int size;
int advise1;
int advise2;
char *exp;
int grand_child;
const char *desc;
} tcases[] = {
{MAP_SIZE, MADV_NORMAL, MADV_WIPEONFORK, zero, 0,
"MADV_WIPEONFORK zeroes memory in child"},
{0, MADV_NORMAL, MADV_WIPEONFORK, pattern, 0,
"MADV_WIPEONFORK with zero length does nothing"},
{MAP_SIZE, MADV_NORMAL, MADV_WIPEONFORK, zero, 1,
"MADV_WIPEONFORK zeroes memory in grand-child"},
{MAP_SIZE, MADV_WIPEONFORK, MADV_KEEPONFORK, pattern, 0,
"MADV_KEEPONFORK will undo MADV_WIPEONFORK"},
};
static void cmp_area(char *addr, const struct test_case *tc)
{
int i;
for (i = 0; i < tc->size; i++) {
if (addr[i] != tc->exp[i]) {
tst_res(TFAIL, "In PID %d, addr[%d] = 0x%02x, "
"expected[%d] = 0x%02x", getpid(),
i, addr[i], i, tc->exp[i]);
break;
}
}
tst_res(TPASS, "In PID %d, Matched expected pattern", getpid());
}
static int set_advice(char *addr, int size, int advise)
{
TEST(madvise(addr, size, advise));
if (TST_RET == -1) {
if (TST_ERR == EINVAL) {
tst_res(TCONF, "madvise(%p, %d, 0x%x) is not supported",
addr, size, advise);
} else {
tst_res(TFAIL | TTERRNO, "madvise(%p, %d, 0x%x)",
addr, size, advise);
}
return 1;
}
tst_res(TPASS, "madvise(%p, %d, 0x%x)", addr, size, advise);
return 0;
}
static char *mem_map(void)
{
char *ptr;
ptr = SAFE_MMAP(NULL, MAP_SIZE,
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS,
-1, 0);
memcpy(ptr, pattern, MAP_SIZE);
return ptr;
}
static void test_madvise(unsigned int test_nr)
{
const struct test_case *tc = &tcases[test_nr];
char *addr;
pid_t pid;
addr = mem_map();
tst_res(TINFO, "%s", tc->desc);
if (set_advice(addr, tc->size, tc->advise1))
goto un_map;
if (!set_advice(addr, tc->size, tc->advise2)) {
pid = SAFE_FORK();
if (!pid) {
if (tc->grand_child) {
pid = SAFE_FORK();
if (!pid) {
cmp_area(addr, tc);
exit(0);
}
} else {
cmp_area(addr, tc);
exit(0);
}
}
tst_reap_children();
}
un_map:
SAFE_MUNMAP(addr, MAP_SIZE);
}
static void setup(void)
{
unsigned int i;
for (i = 0; i < MAP_SIZE; i++)
pattern[i] = i % 0x03;
}
static struct tst_test test = {
.tcnt = ARRAY_SIZE(tcases),
.forks_child = 1,
.test = test_madvise,
.setup = setup,
};