1 /* $OpenBSD: minherit_zero.c,v 1.1 2014/06/13 07:17:54 matthew Exp $ */ 2 /* 3 * Copyright (c) 2014 Google Inc. 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/mman.h> 19 #include <sys/wait.h> 20 #include <assert.h> 21 #include <fcntl.h> 22 #include <paths.h> 23 #include <string.h> 24 #include <unistd.h> 25 26 #define CHECK(x) assert((x)) 27 #define CHECK_EQ(a, b) assert((a) == (b)) 28 #define CHECK_NE(a, b) assert((a) != (b)) 29 #define CHECK_GE(a, b) assert((a) >= (b)) 30 31 static int 32 ismemset(const void *s, int c, size_t n) 33 { 34 const unsigned char *p = s; 35 size_t i; 36 37 for (i = 0; i < n; i++) 38 if (p[i] != c) 39 return (0); 40 return (1); 41 } 42 43 static void 44 wait_for_clean_exit(pid_t pid) 45 { 46 int status; 47 CHECK_EQ(pid, waitpid(pid, &status, 0)); 48 CHECK(WIFEXITED(status)); 49 CHECK_EQ(0, WEXITSTATUS(status)); 50 } 51 52 enum { 53 NPAGES = 4, 54 55 PARENT_BYTE = 42, 56 CHILD_BYTE = 53, 57 GRANDCHILD_BYTE = 65 58 }; 59 60 /* 61 * We map some memory, configure it's inheritance for MAP_INHERIT_ZERO, 62 * then check that when we fork child or grandchild processes, that they 63 * receive new zero'd out memory mappings. Additionally, we sanity check 64 * that after the child (or grandchild) process exits, that the parent's 65 * memory is still in tact. 66 */ 67 static void 68 dotest(int fd, size_t len, int flags) 69 { 70 void *p; 71 pid_t pid; 72 73 p = mmap(NULL, len, PROT_READ|PROT_WRITE, flags, fd, 0); 74 CHECK_NE(MAP_FAILED, p); 75 76 CHECK_EQ(0, minherit(p, len, MAP_INHERIT_ZERO)); 77 78 memset(p, PARENT_BYTE, len); 79 80 pid = fork(); 81 CHECK_GE(pid, 0); 82 if (pid == 0) { 83 CHECK(ismemset(p, 0, len)); 84 memset(p, CHILD_BYTE, len); 85 86 pid = fork(); 87 CHECK_GE(pid, 0); 88 if (pid == 0) { 89 CHECK(ismemset(p, 0, len)); 90 memset(p, GRANDCHILD_BYTE, len); 91 _exit(0); 92 } 93 94 wait_for_clean_exit(pid); 95 CHECK(ismemset(p, CHILD_BYTE, len)); 96 memset(p, 0, len); 97 _exit(0); 98 } 99 100 wait_for_clean_exit(pid); 101 CHECK(ismemset(p, PARENT_BYTE, len)); 102 memset(p, 0, len); 103 104 CHECK_EQ(0, munmap(p, len)); 105 } 106 107 int 108 main() 109 { 110 long pagesize; 111 size_t len; 112 113 pagesize = sysconf(_SC_PAGESIZE); 114 CHECK_GE(pagesize, 1); 115 len = NPAGES * pagesize; 116 117 /* First run test with private anonymous memory. */ 118 dotest(-1, len, MAP_ANON|MAP_PRIVATE); 119 120 /* Test again with shared anonymous memory. */ 121 dotest(-1, len, MAP_ANON|MAP_SHARED); 122 123 /* Finally, test with private file mapping. */ 124 int fd = open(_PATH_BSHELL, O_RDONLY); 125 CHECK_GE(fd, 0); 126 dotest(fd, len, MAP_FILE|MAP_PRIVATE); 127 CHECK_EQ(0, close(fd)); 128 129 return (0); 130 } 131