1197543Sbz/*- 2197543Sbz * Copyright (c) 2009 Simon L. Nielsen <simon@FreeBSD.org>, 3197543Sbz * Bjoern A. Zeeb <bz@FreeBSD.org> 4197543Sbz * 5197543Sbz * Redistribution and use in source and binary forms, with or without 6197543Sbz * modification, are permitted provided that the following conditions 7197543Sbz * are met: 8197543Sbz * 1. Redistributions of source code must retain the above copyright 9197543Sbz * notice, this list of conditions and the following disclaimer. 10197543Sbz * 2. Redistributions in binary form must reproduce the above copyright 11197543Sbz * notice, this list of conditions and the following disclaimer in the 12197543Sbz * documentation and/or other materials provided with the distribution. 13197543Sbz * 14197543Sbz * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15197543Sbz * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16197543Sbz * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17197543Sbz * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18197543Sbz * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19197543Sbz * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20197543Sbz * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21197543Sbz * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22197543Sbz * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23197543Sbz * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24197543Sbz * SUCH DAMAGE. 25197543Sbz * 26197543Sbz * $FreeBSD: stable/11/tests/sys/vm/mmap_test.c 313233 2017-02-04 16:58:06Z ngie $ 27197543Sbz */ 28197543Sbz 29197543Sbz#include <sys/param.h> 30197543Sbz#include <sys/mman.h> 31197543Sbz#include <sys/sysctl.h> 32197543Sbz 33286369Sjhb#include <atf-c.h> 34282075Sngie#include <errno.h> 35286370Sjhb#include <fcntl.h> 36286370Sjhb#include <stdarg.h> 37286370Sjhb#include <stdio.h> 38286370Sjhb#include <stdlib.h> 39197543Sbz 40282075Sngiestatic const struct { 41197543Sbz void *addr; 42197713Sbz int ok[2]; /* Depending on security.bsd.map_at_zero {0, !=0}. */ 43286369Sjhb} map_at_zero_tests[] = { 44197543Sbz { (void *)0, { 0, 1 } }, /* Test sysctl. */ 45197543Sbz { (void *)1, { 0, 0 } }, 46197543Sbz { (void *)(PAGE_SIZE - 1), { 0, 0 } }, 47197543Sbz { (void *)PAGE_SIZE, { 1, 1 } }, 48197543Sbz { (void *)-1, { 0, 0 } }, 49197543Sbz { (void *)(-PAGE_SIZE), { 0, 0 } }, 50197543Sbz { (void *)(-1 - PAGE_SIZE), { 0, 0 } }, 51197543Sbz { (void *)(-1 - PAGE_SIZE - 1), { 0, 0 } }, 52197543Sbz { (void *)(0x1000 * PAGE_SIZE), { 1, 1 } }, 53197543Sbz}; 54197543Sbz 55282075Sngie#define MAP_AT_ZERO "security.bsd.map_at_zero" 56282075Sngie 57286369SjhbATF_TC_WITHOUT_HEAD(mmap__map_at_zero); 58286369SjhbATF_TC_BODY(mmap__map_at_zero, tc) 59197543Sbz{ 60197543Sbz void *p; 61197543Sbz size_t len; 62286369Sjhb unsigned int i; 63286369Sjhb int map_at_zero; 64197543Sbz 65197713Sbz len = sizeof(map_at_zero); 66286369Sjhb if (sysctlbyname(MAP_AT_ZERO, &map_at_zero, &len, NULL, 0) == -1) { 67286369Sjhb atf_tc_skip("sysctl for %s failed: %s\n", MAP_AT_ZERO, 68282075Sngie strerror(errno)); 69286369Sjhb return; 70282075Sngie } 71197543Sbz 72197543Sbz /* Normalize to 0 or 1 for array access. */ 73197713Sbz map_at_zero = !!map_at_zero; 74197543Sbz 75286369Sjhb for (i = 0; i < nitems(map_at_zero_tests); i++) { 76286369Sjhb p = mmap((void *)map_at_zero_tests[i].addr, PAGE_SIZE, 77197543Sbz PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANON | MAP_FIXED, 78197543Sbz -1, 0); 79197543Sbz if (p == MAP_FAILED) { 80286369Sjhb ATF_CHECK_MSG(map_at_zero_tests[i].ok[map_at_zero] == 0, 81286369Sjhb "mmap(%p, ...) failed", map_at_zero_tests[i].addr); 82197543Sbz } else { 83286369Sjhb ATF_CHECK_MSG(map_at_zero_tests[i].ok[map_at_zero] == 1, 84286369Sjhb "mmap(%p, ...) succeeded: p=%p\n", 85286369Sjhb map_at_zero_tests[i].addr, p); 86197543Sbz } 87197543Sbz } 88286369Sjhb} 89197543Sbz 90286370Sjhbstatic void 91286370Sjhbchecked_mmap(int prot, int flags, int fd, int error, const char *msg) 92286370Sjhb{ 93286370Sjhb void *p; 94298301Sngie int pagesize; 95286370Sjhb 96298301Sngie ATF_REQUIRE((pagesize = getpagesize()) > 0); 97298301Sngie p = mmap(NULL, pagesize, prot, flags, fd, 0); 98286370Sjhb if (p == MAP_FAILED) { 99286370Sjhb if (error == 0) 100286370Sjhb ATF_CHECK_MSG(0, "%s failed with errno %d", msg, 101286370Sjhb errno); 102286370Sjhb else 103286370Sjhb ATF_CHECK_EQ_MSG(error, errno, 104286370Sjhb "%s failed with wrong errno %d (expected %d)", msg, 105286370Sjhb errno, error); 106286370Sjhb } else { 107286370Sjhb ATF_CHECK_MSG(error == 0, "%s succeeded", msg); 108298301Sngie munmap(p, pagesize); 109286370Sjhb } 110286370Sjhb} 111286370Sjhb 112286370SjhbATF_TC_WITHOUT_HEAD(mmap__bad_arguments); 113286370SjhbATF_TC_BODY(mmap__bad_arguments, tc) 114286370Sjhb{ 115298301Sngie int devstatfd, pagesize, shmfd, zerofd; 116286370Sjhb 117298301Sngie ATF_REQUIRE((pagesize = getpagesize()) > 0); 118287448Sjhb ATF_REQUIRE((devstatfd = open("/dev/devstat", O_RDONLY)) >= 0); 119287448Sjhb ATF_REQUIRE((shmfd = shm_open(SHM_ANON, O_RDWR, 0644)) >= 0); 120298301Sngie ATF_REQUIRE(ftruncate(shmfd, pagesize) == 0); 121287448Sjhb ATF_REQUIRE((zerofd = open("/dev/zero", O_RDONLY)) >= 0); 122286370Sjhb 123286370Sjhb /* These should work. */ 124286370Sjhb checked_mmap(PROT_READ | PROT_WRITE, MAP_ANON, -1, 0, 125286370Sjhb "simple MAP_ANON"); 126287448Sjhb checked_mmap(PROT_READ | PROT_WRITE, MAP_SHARED, shmfd, 0, 127286370Sjhb "simple shm fd shared"); 128287448Sjhb checked_mmap(PROT_READ | PROT_WRITE, MAP_PRIVATE, shmfd, 0, 129286370Sjhb "simple shm fd private"); 130287448Sjhb checked_mmap(PROT_READ, MAP_SHARED, zerofd, 0, 131287448Sjhb "simple /dev/zero shared"); 132287448Sjhb checked_mmap(PROT_READ | PROT_WRITE, MAP_PRIVATE, zerofd, 0, 133287448Sjhb "simple /dev/zero private"); 134287448Sjhb checked_mmap(PROT_READ, MAP_SHARED, devstatfd, 0, 135287448Sjhb "simple /dev/devstat shared"); 136286370Sjhb 137286370Sjhb /* Extra PROT flags. */ 138286370Sjhb checked_mmap(PROT_READ | PROT_WRITE | 0x100000, MAP_ANON, -1, EINVAL, 139286370Sjhb "MAP_ANON with extra PROT flags"); 140287448Sjhb checked_mmap(0xffff, MAP_SHARED, shmfd, EINVAL, 141286370Sjhb "shm fd with garbage PROT"); 142286370Sjhb 143286370Sjhb /* Undefined flag. */ 144286370Sjhb checked_mmap(PROT_READ | PROT_WRITE, MAP_ANON | MAP_RESERVED0080, -1, 145286370Sjhb EINVAL, "Undefined flag"); 146286370Sjhb 147286370Sjhb /* Both MAP_SHARED and MAP_PRIVATE */ 148286370Sjhb checked_mmap(PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE | 149286370Sjhb MAP_SHARED, -1, EINVAL, "MAP_ANON with both SHARED and PRIVATE"); 150287448Sjhb checked_mmap(PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_SHARED, shmfd, 151286370Sjhb EINVAL, "shm fd with both SHARED and PRIVATE"); 152286370Sjhb 153286370Sjhb /* At least one of MAP_SHARED or MAP_PRIVATE without ANON */ 154287448Sjhb checked_mmap(PROT_READ | PROT_WRITE, 0, shmfd, EINVAL, 155286370Sjhb "shm fd without sharing flag"); 156286370Sjhb 157286370Sjhb /* MAP_ANON with either sharing flag (impacts fork). */ 158286370Sjhb checked_mmap(PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED, -1, 0, 159286370Sjhb "shared MAP_ANON"); 160286370Sjhb checked_mmap(PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0, 161286370Sjhb "private MAP_ANON"); 162286370Sjhb 163286370Sjhb /* MAP_ANON should require an fd of -1. */ 164286370Sjhb checked_mmap(PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, 0, EINVAL, 165286370Sjhb "MAP_ANON with fd != -1"); 166287448Sjhb 167287448Sjhb /* Writable MAP_SHARED should fail on read-only descriptors. */ 168287448Sjhb checked_mmap(PROT_READ | PROT_WRITE, MAP_SHARED, zerofd, EACCES, 169287448Sjhb "MAP_SHARED of read-only /dev/zero"); 170287448Sjhb 171287448Sjhb /* 172287448Sjhb * Character devices other than /dev/zero do not support private 173287448Sjhb * mappings. 174287448Sjhb */ 175287448Sjhb checked_mmap(PROT_READ, MAP_PRIVATE, devstatfd, EINVAL, 176287448Sjhb "MAP_PRIVATE of /dev/devstat"); 177298301Sngie 178298301Sngie close(devstatfd); 179298301Sngie close(shmfd); 180298301Sngie close(zerofd); 181286370Sjhb} 182286370Sjhb 183287448SjhbATF_TC_WITHOUT_HEAD(mmap__dev_zero_private); 184287448SjhbATF_TC_BODY(mmap__dev_zero_private, tc) 185287448Sjhb{ 186287448Sjhb char *p1, *p2, *p3; 187313233Sngie int fd, i, pagesize; 188287448Sjhb 189298301Sngie ATF_REQUIRE((pagesize = getpagesize()) > 0); 190287448Sjhb ATF_REQUIRE((fd = open("/dev/zero", O_RDONLY)) >= 0); 191287448Sjhb 192298301Sngie p1 = mmap(NULL, pagesize, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); 193287448Sjhb ATF_REQUIRE(p1 != MAP_FAILED); 194287448Sjhb 195298301Sngie p2 = mmap(NULL, pagesize, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); 196287448Sjhb ATF_REQUIRE(p2 != MAP_FAILED); 197287448Sjhb 198298301Sngie for (i = 0; i < pagesize; i++) 199313233Sngie ATF_REQUIRE_EQ_MSG(0, p1[i], "byte at p1[%d] is %x", i, p1[i]); 200287448Sjhb 201298301Sngie ATF_REQUIRE(memcmp(p1, p2, pagesize) == 0); 202287448Sjhb 203287448Sjhb p1[0] = 1; 204287448Sjhb 205287448Sjhb ATF_REQUIRE(p2[0] == 0); 206287448Sjhb 207287448Sjhb p2[0] = 2; 208287448Sjhb 209287448Sjhb ATF_REQUIRE(p1[0] == 1); 210287448Sjhb 211298301Sngie p3 = mmap(NULL, pagesize, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); 212287448Sjhb ATF_REQUIRE(p3 != MAP_FAILED); 213287448Sjhb 214287448Sjhb ATF_REQUIRE(p3[0] == 0); 215298301Sngie 216298301Sngie munmap(p1, pagesize); 217298301Sngie munmap(p2, pagesize); 218298301Sngie munmap(p3, pagesize); 219298301Sngie close(fd); 220287448Sjhb} 221287448Sjhb 222287448SjhbATF_TC_WITHOUT_HEAD(mmap__dev_zero_shared); 223287448SjhbATF_TC_BODY(mmap__dev_zero_shared, tc) 224287448Sjhb{ 225287448Sjhb char *p1, *p2, *p3; 226313233Sngie int fd, i, pagesize; 227287448Sjhb 228298301Sngie ATF_REQUIRE((pagesize = getpagesize()) > 0); 229287448Sjhb ATF_REQUIRE((fd = open("/dev/zero", O_RDWR)) >= 0); 230287448Sjhb 231298301Sngie p1 = mmap(NULL, pagesize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 232287448Sjhb ATF_REQUIRE(p1 != MAP_FAILED); 233287448Sjhb 234298301Sngie p2 = mmap(NULL, pagesize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 235287448Sjhb ATF_REQUIRE(p2 != MAP_FAILED); 236287448Sjhb 237298301Sngie for (i = 0; i < pagesize; i++) 238313233Sngie ATF_REQUIRE_EQ_MSG(0, p1[i], "byte at p1[%d] is %x", i, p1[i]); 239287448Sjhb 240298301Sngie ATF_REQUIRE(memcmp(p1, p2, pagesize) == 0); 241287448Sjhb 242287448Sjhb p1[0] = 1; 243287448Sjhb 244287448Sjhb ATF_REQUIRE(p2[0] == 0); 245287448Sjhb 246287448Sjhb p2[0] = 2; 247287448Sjhb 248287448Sjhb ATF_REQUIRE(p1[0] == 1); 249287448Sjhb 250298301Sngie p3 = mmap(NULL, pagesize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 251287448Sjhb 0); 252287448Sjhb ATF_REQUIRE(p3 != MAP_FAILED); 253287448Sjhb 254287448Sjhb ATF_REQUIRE(p3[0] == 0); 255298301Sngie 256298301Sngie munmap(p1, pagesize); 257298301Sngie munmap(p2, pagesize); 258298301Sngie munmap(p3, pagesize); 259298301Sngie close(fd); 260287448Sjhb} 261287448Sjhb 262286369SjhbATF_TP_ADD_TCS(tp) 263286369Sjhb{ 264286369Sjhb 265286369Sjhb ATF_TP_ADD_TC(tp, mmap__map_at_zero); 266286370Sjhb ATF_TP_ADD_TC(tp, mmap__bad_arguments); 267287448Sjhb ATF_TP_ADD_TC(tp, mmap__dev_zero_private); 268287448Sjhb ATF_TP_ADD_TC(tp, mmap__dev_zero_shared); 269286369Sjhb 270286369Sjhb return (atf_no_error()); 271197543Sbz} 272