/* * Copyright (c) International Business Machines Corp., 2001 * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* * DESCRIPTION * Testcase to check the error conditions for mprotect(2) * * ALGORITHM * test1: * Invoke mprotect() with an address of 0. Check if error * is set to ENOMEM. * test2: * Invoke mprotect() with an address that is not a multiple * of PAGESIZE. EINVAL * test3: * Mmap a file with only read permission (PROT_READ). * Try to set write permission (PROT_WRITE) using mprotect(2). * Check that error is set to EACCES. * * HISTORY * 07/2001 Ported by Wayne Boyer * 03/2002 Paul Larson: case 1 should expect ENOMEM not EFAULT */ #include <fcntl.h> #include <errno.h> #include <sys/mman.h> #include <stdlib.h> #include <unistd.h> #include "test.h" #include "safe_macros.h" char *TCID = "mprotect01"; int TST_TOTAL = 3; struct test_case { void *addr; int len; int prot; int error; void (*setupfunc) (struct test_case *self); }; static void cleanup(void); static void setup(void); static void setup1(struct test_case *self); static void setup2(struct test_case *self); static void setup3(struct test_case *self); static int fd; struct test_case TC[] = { /* Check for ENOMEM passing memory that cannot be accessed. */ {NULL, 0, PROT_READ, ENOMEM, setup1}, /* * Check for EINVAL by passing a pointer which is not a * multiple of PAGESIZE. */ {NULL, 1024, PROT_READ, EINVAL, setup2}, /* * Check for EACCES by trying to mark a section of memory * which has been mmap'ed as read-only, as PROT_WRITE */ {NULL, 0, PROT_WRITE, EACCES, setup3} }; int main(int ac, char **av) { int lc; int i; tst_parse_opts(ac, av, NULL, NULL); setup(); for (lc = 0; TEST_LOOPING(lc); lc++) { tst_count = 0; for (i = 0; i < TST_TOTAL; i++) { if (TC[i].setupfunc != NULL) TC[i].setupfunc(&TC[i]); TEST(mprotect(TC[i].addr, TC[i].len, TC[i].prot)); if (TEST_RETURN != -1) { tst_resm(TFAIL, "call succeeded unexpectedly"); continue; } if (TEST_ERRNO == TC[i].error) { tst_resm(TPASS, "expected failure - " "errno = %d : %s", TEST_ERRNO, strerror(TEST_ERRNO)); } else { tst_resm(TFAIL, "unexpected error - %d : %s - " "expected %d", TEST_ERRNO, strerror(TEST_ERRNO), TC[i].error); } } } cleanup(); tst_exit(); } static void setup1(struct test_case *self) { self->len = getpagesize() + 1; } static void setup2(struct test_case *self) { self->addr = malloc(getpagesize()); if (self->addr == NULL) tst_brkm(TINFO, cleanup, "malloc failed"); /* Ensure addr2 is not page aligned */ self->addr++; } static void setup3(struct test_case *self) { fd = SAFE_OPEN(cleanup, "/etc/passwd", O_RDONLY); self->len = getpagesize(); /* * mmap the PAGESIZE bytes as read only. */ self->addr = mmap(0, self->len, PROT_READ, MAP_SHARED, fd, 0); if (self->addr == MAP_FAILED) tst_brkm(TBROK, cleanup, "mmap failed"); } static void setup(void) { tst_sig(FORK, DEF_HANDLER, cleanup); TEST_PAUSE; } static void cleanup(void) { close(fd); }