1 /* $OpenBSD: t_msync.c,v 1.2 2021/12/13 16:56:48 deraadt Exp $ */ 2 /* $NetBSD: t_msync.c,v 1.3 2017/01/14 20:52:42 christos Exp $ */ 3 4 /*- 5 * Copyright (c) 2011 The NetBSD Foundation, Inc. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to The NetBSD Foundation 9 * by Jukka Ruohonen. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 #include "macros.h" 34 35 #include <sys/mman.h> 36 37 #include "atf-c.h" 38 #include <errno.h> 39 #include <fcntl.h> 40 #include <limits.h> 41 #include <stdlib.h> 42 #include <string.h> 43 #include <unistd.h> 44 45 static long page = 0; 46 static const off_t off = 512; 47 static const char path[] = "msync"; 48 49 static const char *msync_sync(const char *, int); 50 51 static const char * 52 msync_sync(const char *garbage, int flags) 53 { 54 char *buf, *map = MAP_FAILED; 55 const char *str = NULL; 56 size_t len; 57 int fd, rv; 58 59 /* 60 * Create a temporary file, write 61 * one page to it, and map the file. 62 */ 63 buf = malloc(page); 64 65 if (buf == NULL) 66 return NULL; 67 68 memset(buf, 'x', page); 69 70 fd = open(path, O_RDWR | O_CREAT, 0700); 71 72 if (fd < 0) { 73 free(buf); 74 return "failed to open"; 75 } 76 77 ATF_REQUIRE_MSG(write(fd, buf, page) != -1, "write(2) failed: %s", 78 strerror(errno)); 79 80 map = mmap(NULL, page, PROT_READ | PROT_WRITE, MAP_FILE|MAP_PRIVATE, 81 fd, 0); 82 83 if (map == MAP_FAILED) { 84 str = "failed to map"; 85 goto out; 86 } 87 88 /* 89 * Seek to an arbitrary offset and 90 * write garbage to this position. 91 */ 92 if (lseek(fd, off, SEEK_SET) != off) { 93 str = "failed to seek"; 94 goto out; 95 } 96 97 len = strlen(garbage); 98 rv = write(fd, garbage, len); 99 100 if (rv != (ssize_t)len) { 101 str = "failed to write garbage"; 102 goto out; 103 } 104 105 /* 106 * Synchronize the mapping and verify 107 * that garbage is at the given offset. 108 */ 109 if (msync(map, page, flags) != 0) { 110 str = "failed to msync"; 111 goto out; 112 } 113 114 if (memcmp(map + off, garbage, len) != 0) { 115 str = "msync did not synchronize"; 116 goto out; 117 } 118 119 out: 120 free(buf); 121 122 (void)close(fd); 123 (void)unlink(path); 124 125 if (map != MAP_FAILED) 126 (void)munmap(map, page); 127 128 return str; 129 } 130 131 ATF_TC(msync_async); 132 ATF_TC_HEAD(msync_async, tc) 133 { 134 atf_tc_set_md_var(tc, "descr", "Test of msync(2), MS_ASYNC"); 135 } 136 137 ATF_TC_BODY(msync_async, tc) 138 { 139 const char *str; 140 141 str = msync_sync("garbage", MS_ASYNC); 142 143 if (str != NULL) 144 atf_tc_fail("%s", str); 145 } 146 147 ATF_TC(msync_err); 148 ATF_TC_HEAD(msync_err, tc) 149 { 150 atf_tc_set_md_var(tc, "descr", "Test error conditions in msync(2)"); 151 } 152 153 ATF_TC_BODY(msync_err, tc) 154 { 155 156 char *map = MAP_FAILED; 157 158 /* 159 * Test that invalid flags error out. 160 */ 161 ATF_REQUIRE(msync_sync("error", -1) != NULL); 162 ATF_REQUIRE(msync_sync("error", INT_MAX) != NULL); 163 164 errno = 0; 165 166 /* 167 * Map a page and then unmap to get an unmapped address. 168 */ 169 map = mmap(NULL, page, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, 170 -1, 0); 171 ATF_REQUIRE(map != MAP_FAILED); 172 173 (void)munmap(map, page); 174 175 ATF_REQUIRE(msync(map, page, MS_SYNC) != 0); 176 ATF_REQUIRE(errno == EFAULT); 177 } 178 179 ATF_TC(msync_invalidate); 180 ATF_TC_HEAD(msync_invalidate, tc) 181 { 182 atf_tc_set_md_var(tc, "descr", "Test of msync(2), MS_INVALIDATE"); 183 } 184 185 ATF_TC_BODY(msync_invalidate, tc) 186 { 187 const char *str; 188 189 str = msync_sync("garbage", MS_INVALIDATE); 190 191 if (str != NULL) 192 atf_tc_fail("%s", str); 193 } 194 195 ATF_TC(msync_sync); 196 ATF_TC_HEAD(msync_sync, tc) 197 { 198 atf_tc_set_md_var(tc, "descr", "Test of msync(2), MS_SYNC"); 199 } 200 201 ATF_TC_BODY(msync_sync, tc) 202 { 203 const char *str; 204 205 str = msync_sync("garbage", MS_SYNC); 206 207 if (str != NULL) 208 atf_tc_fail("%s", str); 209 } 210 211 ATF_TP_ADD_TCS(tp) 212 { 213 214 page = sysconf(_SC_PAGESIZE); 215 216 ATF_REQUIRE(page >= 0); 217 ATF_REQUIRE(page > off); 218 219 ATF_TP_ADD_TC(tp, msync_async); 220 ATF_TP_ADD_TC(tp, msync_err); 221 ATF_TP_ADD_TC(tp, msync_invalidate); 222 ATF_TP_ADD_TC(tp, msync_sync); 223 224 return atf_no_error(); 225 } 226