1/* 2 * Copyright (c) 2015-2016 Dmitry V. Levin <ldv@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 47int 48main(void) 49{ 50 int rc; 51 int fd = syscall(__NR_userfaultfd, O_NONBLOCK); 52 size_t pagesize = getpagesize(); 53 54 if (fd < 0) 55 perror_msg_and_skip("userfaultfd"); 56 57 /* ---- API ---- */ 58 TAIL_ALLOC_OBJECT_CONST_PTR(struct uffdio_api, api_struct); 59 60 /* With a bad fd */ 61 memset(api_struct, 0, sizeof(*api_struct)); 62 rc = ioctl(-1, UFFDIO_API, api_struct); 63 printf("ioctl(-1, UFFDIO_API, {api=0, features=0}) = %d %s (%m)\n", 64 rc, errno2name()); 65 /* With a bad pointer */ 66 rc = ioctl(fd, UFFDIO_API, NULL); 67 printf("ioctl(%d, UFFDIO_API, NULL) = %d %s (%m)\n", 68 fd, rc, errno2name()); 69 /* Normal call */ 70 api_struct->api = UFFD_API; 71 api_struct->features = 0; 72 rc = ioctl(fd, UFFDIO_API, api_struct); 73 printf("ioctl(%d, UFFDIO_API, {api=0xaa, features=0, " 74 "features.out=%#" PRIx64 ", ioctls=1<<_UFFDIO_REGISTER|" 75 "1<<_UFFDIO_UNREGISTER|1<<_UFFDIO_API", 76 fd, (uint64_t)api_struct->features); 77 api_struct->ioctls &= ~(1ull<<_UFFDIO_REGISTER| 78 1ull<<_UFFDIO_UNREGISTER| 79 1ull<<_UFFDIO_API); 80 if (api_struct->ioctls) 81 printf("|%#" PRIx64, (uint64_t)api_struct->ioctls); 82 printf("}) = %d\n", rc); 83 84 /* For the rest of the tests we need some anonymous memory */ 85 void *area1 = mmap(NULL, pagesize, PROT_READ|PROT_WRITE, 86 MAP_PRIVATE|MAP_ANONYMOUS, 87 -1, 0); 88 if (area1 == MAP_FAILED) 89 perror_msg_and_fail("mmap area1"); 90 void *area2 = mmap(NULL, pagesize, PROT_READ|PROT_WRITE, 91 MAP_PRIVATE|MAP_ANONYMOUS, 92 -1, 0); 93 if (area2 == MAP_FAILED) 94 perror_msg_and_fail("mmap area2"); 95 madvise(area2, pagesize, MADV_DONTNEED); 96 *(char *)area1 = 42; 97 98 /* ---- REGISTER ---- */ 99 struct uffdio_register *register_struct = 100 tail_alloc(sizeof(*register_struct)); 101 memset(register_struct, 0, sizeof(*register_struct)); 102 103 rc = ioctl(-1, UFFDIO_REGISTER, register_struct); 104 printf("ioctl(-1, UFFDIO_REGISTER, {range={start=0, len=0}, " 105 "mode=0}) = %d %s (%m)\n", rc, errno2name()); 106 107 rc = ioctl(fd, UFFDIO_REGISTER, NULL); 108 printf("ioctl(%d, UFFDIO_REGISTER, NULL) = %d %s (%m)\n", 109 fd, rc, errno2name()); 110 111 register_struct->range.start = (uint64_t)(uintptr_t)area2; 112 register_struct->range.len = pagesize; 113 register_struct->mode = UFFDIO_REGISTER_MODE_MISSING; 114 rc = ioctl(fd, UFFDIO_REGISTER, register_struct); 115 printf("ioctl(%d, UFFDIO_REGISTER, {range={start=%p, len=%#zx}, " 116 "mode=UFFDIO_REGISTER_MODE_MISSING, ioctls=" 117 "1<<_UFFDIO_WAKE|1<<_UFFDIO_COPY|1<<_UFFDIO_ZEROPAGE", 118 fd, area2, pagesize); 119 register_struct->ioctls &= ~(1ull<<_UFFDIO_WAKE| 120 1ull<<_UFFDIO_COPY| 121 1ull<<_UFFDIO_ZEROPAGE); 122 if (register_struct->ioctls) 123 printf("|%#" PRIx64, (uint64_t)register_struct->ioctls); 124 printf("}) = %d\n", rc); 125 126 /* With area2 registered we can now do the atomic copies onto it 127 * but be careful not to access it in any other way otherwise 128 * userfaultfd will cause us to stall. 129 */ 130 /* ---- COPY ---- */ 131 TAIL_ALLOC_OBJECT_CONST_PTR(struct uffdio_copy, copy_struct); 132 133 memset(copy_struct, 0, sizeof(*copy_struct)); 134 rc = ioctl(-1, UFFDIO_COPY, copy_struct); 135 printf("ioctl(-1, UFFDIO_COPY, {dst=0, src=0, len=0, mode=0" 136 "}) = %d %s (%m)\n", rc, errno2name()); 137 138 rc = ioctl(fd, UFFDIO_COPY, NULL); 139 printf("ioctl(%d, UFFDIO_COPY, NULL) = %d %s (%m)\n", 140 fd, rc, errno2name()); 141 142 copy_struct->dst = (uint64_t)(uintptr_t)area2; 143 copy_struct->src = (uint64_t)(uintptr_t)area1; 144 copy_struct->len = pagesize; 145 copy_struct->mode = UFFDIO_COPY_MODE_DONTWAKE; 146 rc = ioctl(fd, UFFDIO_COPY, copy_struct); 147 printf("ioctl(%d, UFFDIO_COPY, {dst=%p, src=%p, len=%#zx," 148 " mode=UFFDIO_COPY_MODE_DONTWAKE, copy=%#zx}) = %d\n", 149 fd, area2, area1, pagesize, pagesize, rc); 150 151 /* ---- ZEROPAGE ---- */ 152 TAIL_ALLOC_OBJECT_CONST_PTR(struct uffdio_zeropage, zero_struct); 153 madvise(area2, pagesize, MADV_DONTNEED); 154 155 memset(zero_struct, 0, sizeof(*zero_struct)); 156 rc = ioctl(-1, UFFDIO_ZEROPAGE, zero_struct); 157 printf("ioctl(-1, UFFDIO_ZEROPAGE, {range={start=0, len=0}, mode=0" 158 "}) = %d %s (%m)\n", rc, errno2name()); 159 160 rc = ioctl(fd, UFFDIO_ZEROPAGE, NULL); 161 printf("ioctl(%d, UFFDIO_ZEROPAGE, NULL) = %d %s (%m)\n", 162 fd, rc, errno2name()); 163 164 zero_struct->range.start = (uint64_t)(uintptr_t)area2; 165 zero_struct->range.len = pagesize; 166 zero_struct->mode = UFFDIO_ZEROPAGE_MODE_DONTWAKE; 167 rc = ioctl(fd, UFFDIO_ZEROPAGE, zero_struct); 168 printf("ioctl(%d, UFFDIO_ZEROPAGE, {range={start=%p, len=%#zx}," 169 " mode=UFFDIO_ZEROPAGE_MODE_DONTWAKE, zeropage=%#zx}) = %d\n", 170 fd, area2, pagesize, pagesize, rc); 171 172 /* ---- WAKE ---- */ 173 TAIL_ALLOC_OBJECT_CONST_PTR(struct uffdio_range, range_struct); 174 memset(range_struct, 0, sizeof(*range_struct)); 175 176 rc = ioctl(-1, UFFDIO_WAKE, range_struct); 177 printf("ioctl(-1, UFFDIO_WAKE, {start=0, len=0}) = %d %s (%m)\n", 178 rc, errno2name()); 179 180 rc = ioctl(fd, UFFDIO_WAKE, NULL); 181 printf("ioctl(%d, UFFDIO_WAKE, NULL) = %d %s (%m)\n", 182 fd, rc, errno2name()); 183 184 range_struct->start = (uint64_t)(uintptr_t)area2; 185 range_struct->len = pagesize; 186 rc = ioctl(fd, UFFDIO_WAKE, range_struct); 187 printf("ioctl(%d, UFFDIO_WAKE, {start=%p, len=%#zx}) = %d\n", 188 fd, area2, pagesize, rc); 189 190 /* ---- UNREGISTER ---- */ 191 memset(range_struct, 0, sizeof(*range_struct)); 192 193 rc = ioctl(-1, UFFDIO_UNREGISTER, range_struct); 194 printf("ioctl(-1, UFFDIO_UNREGISTER, {start=0, len=0}) = %d %s (%m)\n", 195 rc, errno2name()); 196 197 rc = ioctl(fd, UFFDIO_UNREGISTER, NULL); 198 printf("ioctl(%d, UFFDIO_UNREGISTER, NULL) = %d %s (%m)\n", 199 fd, rc, errno2name()); 200 201 range_struct->start = (uint64_t)(uintptr_t)area2; 202 range_struct->len = pagesize; 203 rc = ioctl(fd, UFFDIO_UNREGISTER, range_struct); 204 printf("ioctl(%d, UFFDIO_UNREGISTER, {start=%p, len=%#zx}) = %d\n", 205 fd, area2, pagesize, rc); 206 puts("+++ exited with 0 +++"); 207 return 0; 208} 209 210#else 211 212SKIP_MAIN_UNDEFINED("__NR_userfaultfd && HAVE_LINUX_USERFAULTFD_H") 213 214#endif 215