// 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 #include #include #include #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, };