1 /* 2 * Copyright (c) 2015-2016 Dmitry V. Levin <ldv (at) altlinux.org> 3 * Copyright (c) 2016 Red Hat, Inc. 4 * Copyright (c) 2016-2017 The strace developers. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 #include "tests.h" 31 #include <asm/unistd.h> 32 33 #if defined __NR_userfaultfd && defined HAVE_LINUX_USERFAULTFD_H 34 35 # include <fcntl.h> 36 # include <inttypes.h> 37 # include <stdint.h> 38 # include <stdio.h> 39 # include <string.h> 40 # include <unistd.h> 41 42 # include <sys/ioctl.h> 43 # include <sys/mman.h> 44 # include <linux/ioctl.h> 45 # include <linux/userfaultfd.h> 46 47 #include "xlat.h" 48 #include "xlat/uffd_api_features.h" 49 50 int 51 main(void) 52 { 53 int rc; 54 int fd = syscall(__NR_userfaultfd, O_NONBLOCK); 55 size_t pagesize = getpagesize(); 56 57 if (fd < 0) 58 perror_msg_and_skip("userfaultfd"); 59 60 /* ---- API ---- */ 61 TAIL_ALLOC_OBJECT_CONST_PTR(struct uffdio_api, api_struct); 62 63 /* With a bad fd */ 64 memset(api_struct, 0, sizeof(*api_struct)); 65 rc = ioctl(-1, UFFDIO_API, api_struct); 66 printf("ioctl(-1, UFFDIO_API, {api=0, features=0}) = %d %s (%m)\n", 67 rc, errno2name()); 68 /* With a bad pointer */ 69 rc = ioctl(fd, UFFDIO_API, NULL); 70 printf("ioctl(%d, UFFDIO_API, NULL) = %d %s (%m)\n", 71 fd, rc, errno2name()); 72 /* Normal call */ 73 api_struct->api = UFFD_API; 74 api_struct->features = 0; 75 rc = ioctl(fd, UFFDIO_API, api_struct); 76 printf("ioctl(%d, UFFDIO_API, {api=0xaa, features=0", fd); 77 if (api_struct->features) { 78 printf(" => features="); 79 printflags(uffd_api_features, api_struct->features, 80 "UFFD_FEATURE_???"); 81 } 82 printf(", ioctls=1<<_UFFDIO_REGISTER|" 83 "1<<_UFFDIO_UNREGISTER|1<<_UFFDIO_API"); 84 api_struct->ioctls &= ~(1ull<<_UFFDIO_REGISTER| 85 1ull<<_UFFDIO_UNREGISTER| 86 1ull<<_UFFDIO_API); 87 if (api_struct->ioctls) 88 printf("|%#" PRIx64, (uint64_t)api_struct->ioctls); 89 printf("}) = %d\n", rc); 90 91 /* For the rest of the tests we need some anonymous memory */ 92 void *area1 = mmap(NULL, pagesize, PROT_READ|PROT_WRITE, 93 MAP_PRIVATE|MAP_ANONYMOUS, 94 -1, 0); 95 if (area1 == MAP_FAILED) 96 perror_msg_and_fail("mmap area1"); 97 void *area2 = mmap(NULL, pagesize, PROT_READ|PROT_WRITE, 98 MAP_PRIVATE|MAP_ANONYMOUS, 99 -1, 0); 100 if (area2 == MAP_FAILED) 101 perror_msg_and_fail("mmap area2"); 102 madvise(area2, pagesize, MADV_DONTNEED); 103 *(char *)area1 = 42; 104 105 /* ---- REGISTER ---- */ 106 struct uffdio_register *register_struct = 107 tail_alloc(sizeof(*register_struct)); 108 memset(register_struct, 0, sizeof(*register_struct)); 109 110 rc = ioctl(-1, UFFDIO_REGISTER, register_struct); 111 printf("ioctl(-1, UFFDIO_REGISTER, {range={start=0, len=0}, " 112 "mode=0}) = %d %s (%m)\n", rc, errno2name()); 113 114 rc = ioctl(fd, UFFDIO_REGISTER, NULL); 115 printf("ioctl(%d, UFFDIO_REGISTER, NULL) = %d %s (%m)\n", 116 fd, rc, errno2name()); 117 118 register_struct->range.start = (uint64_t)(uintptr_t)area2; 119 register_struct->range.len = pagesize; 120 register_struct->mode = UFFDIO_REGISTER_MODE_MISSING; 121 rc = ioctl(fd, UFFDIO_REGISTER, register_struct); 122 printf("ioctl(%d, UFFDIO_REGISTER, {range={start=%p, len=%#zx}, " 123 "mode=UFFDIO_REGISTER_MODE_MISSING, ioctls=" 124 "1<<_UFFDIO_WAKE|1<<_UFFDIO_COPY|1<<_UFFDIO_ZEROPAGE", 125 fd, area2, pagesize); 126 register_struct->ioctls &= ~(1ull<<_UFFDIO_WAKE| 127 1ull<<_UFFDIO_COPY| 128 1ull<<_UFFDIO_ZEROPAGE); 129 if (register_struct->ioctls) 130 printf("|%#" PRIx64, (uint64_t)register_struct->ioctls); 131 printf("}) = %d\n", rc); 132 133 /* With area2 registered we can now do the atomic copies onto it 134 * but be careful not to access it in any other way otherwise 135 * userfaultfd will cause us to stall. 136 */ 137 /* ---- COPY ---- */ 138 TAIL_ALLOC_OBJECT_CONST_PTR(struct uffdio_copy, copy_struct); 139 140 memset(copy_struct, 0, sizeof(*copy_struct)); 141 rc = ioctl(-1, UFFDIO_COPY, copy_struct); 142 printf("ioctl(-1, UFFDIO_COPY, {dst=0, src=0, len=0, mode=0" 143 "}) = %d %s (%m)\n", rc, errno2name()); 144 145 rc = ioctl(fd, UFFDIO_COPY, NULL); 146 printf("ioctl(%d, UFFDIO_COPY, NULL) = %d %s (%m)\n", 147 fd, rc, errno2name()); 148 149 copy_struct->dst = (uint64_t)(uintptr_t)area2; 150 copy_struct->src = (uint64_t)(uintptr_t)area1; 151 copy_struct->len = pagesize; 152 copy_struct->mode = UFFDIO_COPY_MODE_DONTWAKE; 153 rc = ioctl(fd, UFFDIO_COPY, copy_struct); 154 printf("ioctl(%d, UFFDIO_COPY, {dst=%p, src=%p, len=%#zx," 155 " mode=UFFDIO_COPY_MODE_DONTWAKE, copy=%#zx}) = %d\n", 156 fd, area2, area1, pagesize, pagesize, rc); 157 158 /* ---- ZEROPAGE ---- */ 159 TAIL_ALLOC_OBJECT_CONST_PTR(struct uffdio_zeropage, zero_struct); 160 madvise(area2, pagesize, MADV_DONTNEED); 161 162 memset(zero_struct, 0, sizeof(*zero_struct)); 163 rc = ioctl(-1, UFFDIO_ZEROPAGE, zero_struct); 164 printf("ioctl(-1, UFFDIO_ZEROPAGE, {range={start=0, len=0}, mode=0" 165 "}) = %d %s (%m)\n", rc, errno2name()); 166 167 rc = ioctl(fd, UFFDIO_ZEROPAGE, NULL); 168 printf("ioctl(%d, UFFDIO_ZEROPAGE, NULL) = %d %s (%m)\n", 169 fd, rc, errno2name()); 170 171 zero_struct->range.start = (uint64_t)(uintptr_t)area2; 172 zero_struct->range.len = pagesize; 173 zero_struct->mode = UFFDIO_ZEROPAGE_MODE_DONTWAKE; 174 rc = ioctl(fd, UFFDIO_ZEROPAGE, zero_struct); 175 printf("ioctl(%d, UFFDIO_ZEROPAGE, {range={start=%p, len=%#zx}," 176 " mode=UFFDIO_ZEROPAGE_MODE_DONTWAKE, zeropage=%#zx}) = %d\n", 177 fd, area2, pagesize, pagesize, rc); 178 179 /* ---- WAKE ---- */ 180 TAIL_ALLOC_OBJECT_CONST_PTR(struct uffdio_range, range_struct); 181 memset(range_struct, 0, sizeof(*range_struct)); 182 183 rc = ioctl(-1, UFFDIO_WAKE, range_struct); 184 printf("ioctl(-1, UFFDIO_WAKE, {start=0, len=0}) = %d %s (%m)\n", 185 rc, errno2name()); 186 187 rc = ioctl(fd, UFFDIO_WAKE, NULL); 188 printf("ioctl(%d, UFFDIO_WAKE, NULL) = %d %s (%m)\n", 189 fd, rc, errno2name()); 190 191 range_struct->start = (uint64_t)(uintptr_t)area2; 192 range_struct->len = pagesize; 193 rc = ioctl(fd, UFFDIO_WAKE, range_struct); 194 printf("ioctl(%d, UFFDIO_WAKE, {start=%p, len=%#zx}) = %d\n", 195 fd, area2, pagesize, rc); 196 197 /* ---- UNREGISTER ---- */ 198 memset(range_struct, 0, sizeof(*range_struct)); 199 200 rc = ioctl(-1, UFFDIO_UNREGISTER, range_struct); 201 printf("ioctl(-1, UFFDIO_UNREGISTER, {start=0, len=0}) = %d %s (%m)\n", 202 rc, errno2name()); 203 204 rc = ioctl(fd, UFFDIO_UNREGISTER, NULL); 205 printf("ioctl(%d, UFFDIO_UNREGISTER, NULL) = %d %s (%m)\n", 206 fd, rc, errno2name()); 207 208 range_struct->start = (uint64_t)(uintptr_t)area2; 209 range_struct->len = pagesize; 210 rc = ioctl(fd, UFFDIO_UNREGISTER, range_struct); 211 printf("ioctl(%d, UFFDIO_UNREGISTER, {start=%p, len=%#zx}) = %d\n", 212 fd, area2, pagesize, rc); 213 puts("+++ exited with 0 +++"); 214 return 0; 215 } 216 217 #else 218 219 SKIP_MAIN_UNDEFINED("__NR_userfaultfd && HAVE_LINUX_USERFAULTFD_H") 220 221 #endif 222