1 1.6 christos /* $NetBSD: t_user_ldt.c,v 1.6 2021/04/30 13:53:30 christos Exp $ */ 2 1.1 maxv 3 1.1 maxv /* 4 1.1 maxv * Copyright (c) 2020 The NetBSD Foundation, Inc. 5 1.1 maxv * All rights reserved. 6 1.1 maxv * 7 1.1 maxv * This code is derived from software contributed to The NetBSD Foundation 8 1.1 maxv * by Maxime Villard. 9 1.1 maxv * 10 1.1 maxv * Redistribution and use in source and binary forms, with or without 11 1.1 maxv * modification, are permitted provided that the following conditions 12 1.1 maxv * are met: 13 1.1 maxv * 1. Redistributions of source code must retain the above copyright 14 1.1 maxv * notice, this list of conditions and the following disclaimer. 15 1.1 maxv * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 maxv * notice, this list of conditions and the following disclaimer in the 17 1.1 maxv * documentation and/or other materials provided with the distribution. 18 1.1 maxv * 19 1.1 maxv * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.1 maxv * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.1 maxv * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.1 maxv * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.1 maxv * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.1 maxv * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.1 maxv * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.1 maxv * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.1 maxv * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.1 maxv * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.1 maxv * POSSIBILITY OF SUCH DAMAGE. 30 1.1 maxv */ 31 1.1 maxv 32 1.1 maxv #include <stdio.h> 33 1.1 maxv #include <stdlib.h> 34 1.1 maxv #include <string.h> 35 1.1 maxv #include <unistd.h> 36 1.1 maxv #include <errno.h> 37 1.1 maxv #include <signal.h> 38 1.1 maxv 39 1.1 maxv #include <sys/types.h> 40 1.1 maxv #include <sys/mman.h> 41 1.1 maxv #include <machine/segments.h> 42 1.1 maxv #include <machine/sysarch.h> 43 1.1 maxv #include <machine/vmparam.h> 44 1.2 maxv #include <machine/gdt.h> 45 1.2 maxv 46 1.1 maxv #include <atf-c.h> 47 1.1 maxv 48 1.1 maxv static uint8_t *ldt_base; 49 1.1 maxv static bool user_ldt_supported; 50 1.1 maxv 51 1.1 maxv static void 52 1.1 maxv user_ldt_detect(void) 53 1.1 maxv { 54 1.1 maxv union descriptor desc; 55 1.1 maxv int ret; 56 1.1 maxv 57 1.1 maxv ret = i386_get_ldt(0, &desc, 1); 58 1.5 maxv user_ldt_supported = (ret != -1) || (errno != ENOSYS && errno != EPERM); 59 1.1 maxv } 60 1.1 maxv 61 1.1 maxv static void 62 1.1 maxv init_ldt_base(void) 63 1.1 maxv { 64 1.1 maxv ldt_base = (uint8_t *)mmap(NULL, 2 * PAGE_SIZE, PROT_READ | PROT_WRITE, 65 1.1 maxv MAP_PRIVATE | MAP_ANON, -1, 0); 66 1.1 maxv if (ldt_base == MAP_FAILED) 67 1.1 maxv atf_tc_fail("mmap failed"); 68 1.1 maxv munmap(ldt_base + PAGE_SIZE, PAGE_SIZE); 69 1.1 maxv } 70 1.1 maxv 71 1.1 maxv static void 72 1.1 maxv build_desc(union descriptor *desc, void *basep, uint32_t limit, int type, 73 1.1 maxv int dpl, int def32, int gran) 74 1.1 maxv { 75 1.1 maxv uintptr_t base = (uintptr_t)basep; 76 1.1 maxv 77 1.1 maxv limit--; 78 1.1 maxv 79 1.1 maxv desc->sd.sd_lolimit = limit & 0x0000ffff; 80 1.1 maxv desc->sd.sd_lobase = base & 0x00ffffff; 81 1.1 maxv desc->sd.sd_type = type & 0x1F; 82 1.1 maxv desc->sd.sd_dpl = dpl & 0x3; 83 1.1 maxv desc->sd.sd_p = 1; 84 1.1 maxv desc->sd.sd_hilimit = (limit & 0x00ff0000) >> 16; 85 1.1 maxv desc->sd.sd_xx = 0; 86 1.1 maxv desc->sd.sd_def32 = def32 ? 1 : 0; 87 1.1 maxv desc->sd.sd_gran = gran ? 1 : 0; 88 1.1 maxv desc->sd.sd_hibase = (base & 0xff000000) >> 24; 89 1.1 maxv } 90 1.1 maxv 91 1.1 maxv static void 92 1.4 maxv set_ds(unsigned int val) 93 1.4 maxv { 94 1.4 maxv __asm volatile("mov %0,%%ds"::"r" ((unsigned short)val)); 95 1.4 maxv } 96 1.4 maxv 97 1.4 maxv static void 98 1.1 maxv set_fs(unsigned int val) 99 1.1 maxv { 100 1.1 maxv __asm volatile("mov %0,%%fs"::"r" ((unsigned short)val)); 101 1.1 maxv } 102 1.1 maxv 103 1.1 maxv static uint8_t __noinline 104 1.1 maxv get_fs_byte(const char *addr) 105 1.1 maxv { 106 1.1 maxv uint8_t val; 107 1.1 maxv __asm volatile ( 108 1.1 maxv ".globl fs_read_begin; fs_read_begin:\n" 109 1.1 maxv "movb %%fs:%1,%0\n" 110 1.1 maxv ".globl fs_read_end; fs_read_end:\n" 111 1.1 maxv : "=q" (val) : "m" (*addr) 112 1.1 maxv ); 113 1.1 maxv return val; 114 1.1 maxv } 115 1.1 maxv 116 1.1 maxv /* -------------------------------------------------------------------------- */ 117 1.1 maxv 118 1.1 maxv ATF_TC(filter_ops); 119 1.1 maxv ATF_TC_HEAD(filter_ops, tc) 120 1.1 maxv { 121 1.1 maxv atf_tc_set_md_var(tc, "descr", 122 1.1 maxv "Ensure that the kernel correctly filters the descriptors"); 123 1.1 maxv } 124 1.1 maxv ATF_TC_BODY(filter_ops, tc) 125 1.1 maxv { 126 1.1 maxv union descriptor desc; 127 1.1 maxv const int forbidden_types[] = { 128 1.1 maxv SDT_SYS286TSS, 129 1.1 maxv SDT_SYSLDT, 130 1.1 maxv SDT_SYS286BSY, 131 1.1 maxv SDT_SYS286CGT, 132 1.1 maxv SDT_SYSTASKGT, 133 1.1 maxv SDT_SYS286IGT, 134 1.1 maxv SDT_SYS286TGT, 135 1.1 maxv SDT_SYSNULL2, 136 1.1 maxv SDT_SYS386TSS, 137 1.1 maxv SDT_SYSNULL3, 138 1.1 maxv SDT_SYS386BSY, 139 1.1 maxv SDT_SYS386CGT, 140 1.1 maxv SDT_SYSNULL4, 141 1.1 maxv SDT_SYS386IGT, 142 1.1 maxv SDT_SYS386TGT 143 1.1 maxv }; 144 1.1 maxv size_t i; 145 1.1 maxv 146 1.1 maxv if (!user_ldt_supported) { 147 1.1 maxv atf_tc_skip("USER_LDT disabled"); 148 1.1 maxv } 149 1.1 maxv 150 1.1 maxv /* The first LDT slots should not be settable. */ 151 1.1 maxv for (i = 0; i < 10; i++) { 152 1.1 maxv build_desc(&desc, ldt_base, PAGE_SIZE, SDT_MEMRW, 153 1.1 maxv SEL_UPL, 1, 0); 154 1.1 maxv ATF_REQUIRE_EQ(i386_set_ldt(i, &desc, 1), -1); 155 1.1 maxv ATF_REQUIRE_EQ(errno, EINVAL); 156 1.1 maxv } 157 1.1 maxv 158 1.1 maxv /* SEL_KPL should not be allowed. */ 159 1.1 maxv build_desc(&desc, ldt_base, PAGE_SIZE, SDT_MEMRW, SEL_KPL, 1, 0); 160 1.1 maxv ATF_REQUIRE_EQ(i386_set_ldt(256, &desc, 1), -1); 161 1.1 maxv ATF_REQUIRE_EQ(errno, EACCES); 162 1.1 maxv 163 1.1 maxv /* Long-mode segments should not be allowed. */ 164 1.1 maxv build_desc(&desc, ldt_base, PAGE_SIZE, SDT_MEMRW, SEL_UPL, 1, 0); 165 1.1 maxv desc.sd.sd_xx = 0b11; /* sd_avl | sd_long */ 166 1.1 maxv ATF_REQUIRE_EQ(i386_set_ldt(256, &desc, 1), -1); 167 1.1 maxv ATF_REQUIRE_EQ(errno, EACCES); 168 1.1 maxv 169 1.1 maxv /* No forbidden type should be allowed. */ 170 1.1 maxv for (i = 0; i < __arraycount(forbidden_types); i++) { 171 1.1 maxv build_desc(&desc, ldt_base, PAGE_SIZE, forbidden_types[i], 172 1.1 maxv SEL_UPL, 1, 0); 173 1.1 maxv ATF_REQUIRE_EQ(i386_set_ldt(256, &desc, 1), -1); 174 1.1 maxv ATF_REQUIRE_EQ(errno, EACCES); 175 1.1 maxv } 176 1.2 maxv 177 1.2 maxv /* Check the slot limit. */ 178 1.2 maxv build_desc(&desc, ldt_base, PAGE_SIZE, SDT_MEMRW, SEL_UPL, 1, 0); 179 1.2 maxv ATF_REQUIRE_EQ(i386_set_ldt(MAX_USERLDT_SLOTS-1, &desc, 1), 180 1.2 maxv MAX_USERLDT_SLOTS-1); 181 1.2 maxv ATF_REQUIRE_EQ(i386_set_ldt(MAX_USERLDT_SLOTS, &desc, 1), -1); 182 1.2 maxv ATF_REQUIRE_EQ(errno, EINVAL); 183 1.1 maxv } 184 1.1 maxv 185 1.1 maxv /* -------------------------------------------------------------------------- */ 186 1.1 maxv 187 1.4 maxv static void 188 1.4 maxv iretq_gp__gp_handler(int signo, siginfo_t *sig, void *ctx) 189 1.4 maxv { 190 1.4 maxv ATF_REQUIRE(sig->si_signo == SIGSEGV); 191 1.4 maxv ATF_REQUIRE(sig->si_code == SEGV_ACCERR); 192 1.4 maxv atf_tc_pass(); 193 1.4 maxv /* NOTREACHED */ 194 1.4 maxv } 195 1.4 maxv 196 1.4 maxv ATF_TC(iretq_gp); 197 1.4 maxv ATF_TC_HEAD(iretq_gp, tc) 198 1.4 maxv { 199 1.4 maxv atf_tc_set_md_var(tc, "descr", 200 1.4 maxv "Ensure that the kernel correctly handles iretq #GP faults"); 201 1.4 maxv } 202 1.4 maxv ATF_TC_BODY(iretq_gp, tc) 203 1.4 maxv { 204 1.4 maxv union descriptor desc; 205 1.4 maxv struct sigaction act; 206 1.4 maxv 207 1.4 maxv if (!user_ldt_supported) { 208 1.4 maxv atf_tc_skip("USER_LDT disabled"); 209 1.4 maxv } 210 1.4 maxv 211 1.4 maxv /* Build a desc, set %ds to it. */ 212 1.4 maxv build_desc(&desc, 0, 0xFFFFFUL, SDT_MEMRWA, SEL_UPL, 1, 1); 213 1.4 maxv ATF_REQUIRE_EQ(i386_set_ldt(256, &desc, 1), 256); 214 1.4 maxv set_ds(LSEL(256, SEL_UPL)); 215 1.4 maxv 216 1.4 maxv /* Register the fault handler. */ 217 1.4 maxv memset(&act, 0, sizeof(act)); 218 1.4 maxv act.sa_sigaction = iretq_gp__gp_handler; 219 1.4 maxv act.sa_flags = SA_SIGINFO; 220 1.4 maxv ATF_REQUIRE_EQ(sigaction(SIGSEGV, &act, NULL), 0); 221 1.4 maxv 222 1.4 maxv /* Set NULL on %ds, iretq should fault. */ 223 1.4 maxv memset(&desc, 0, sizeof(desc)); 224 1.4 maxv ATF_REQUIRE_EQ(i386_set_ldt(256, &desc, 1), 256); 225 1.4 maxv 226 1.4 maxv atf_tc_fail("test did not fault as expected"); 227 1.4 maxv } 228 1.4 maxv 229 1.4 maxv /* -------------------------------------------------------------------------- */ 230 1.4 maxv 231 1.4 maxv static void 232 1.4 maxv iretq_np__np_handler(int signo, siginfo_t *sig, void *ctx) 233 1.4 maxv { 234 1.4 maxv ATF_REQUIRE(sig->si_signo == SIGBUS); 235 1.4 maxv ATF_REQUIRE(sig->si_code == BUS_ADRERR); 236 1.4 maxv atf_tc_pass(); 237 1.4 maxv /* NOTREACHED */ 238 1.4 maxv } 239 1.4 maxv 240 1.4 maxv ATF_TC(iretq_np); 241 1.4 maxv ATF_TC_HEAD(iretq_np, tc) 242 1.4 maxv { 243 1.4 maxv atf_tc_set_md_var(tc, "descr", 244 1.4 maxv "Ensure that the kernel correctly handles iretq #NP faults"); 245 1.4 maxv } 246 1.4 maxv ATF_TC_BODY(iretq_np, tc) 247 1.4 maxv { 248 1.4 maxv union descriptor desc; 249 1.4 maxv struct sigaction act; 250 1.4 maxv 251 1.4 maxv if (!user_ldt_supported) { 252 1.4 maxv atf_tc_skip("USER_LDT disabled"); 253 1.4 maxv } 254 1.4 maxv 255 1.4 maxv /* Build a desc, set %ds to it. */ 256 1.4 maxv build_desc(&desc, 0, 0xFFFFFFFFUL, SDT_MEMRWA, SEL_UPL, 1, 1); 257 1.4 maxv ATF_REQUIRE_EQ(i386_set_ldt(256, &desc, 1), 256); 258 1.4 maxv set_ds(LSEL(256, SEL_UPL)); 259 1.4 maxv 260 1.4 maxv /* Register the fault handler. */ 261 1.4 maxv memset(&act, 0, sizeof(act)); 262 1.4 maxv act.sa_sigaction = iretq_np__np_handler; 263 1.4 maxv act.sa_flags = SA_SIGINFO; 264 1.4 maxv ATF_REQUIRE_EQ(sigaction(SIGBUS, &act, NULL), 0); 265 1.4 maxv 266 1.4 maxv /* Set non-present on %ds, iretq should fault. */ 267 1.4 maxv desc.sd.sd_p = 0; 268 1.4 maxv ATF_REQUIRE_EQ(i386_set_ldt(256, &desc, 1), 256); 269 1.4 maxv 270 1.4 maxv atf_tc_fail("test did not fault as expected"); 271 1.4 maxv } 272 1.4 maxv 273 1.4 maxv /* -------------------------------------------------------------------------- */ 274 1.4 maxv 275 1.1 maxv static volatile bool expect_crash; 276 1.1 maxv 277 1.1 maxv static void 278 1.4 maxv user_ldt__gp_handler(int signo, siginfo_t *sig, void *ctx) 279 1.1 maxv { 280 1.1 maxv ucontext_t *uctx = ctx; 281 1.1 maxv extern uint8_t fs_read_begin; 282 1.1 maxv 283 1.1 maxv if (!expect_crash) { 284 1.1 maxv atf_tc_fail("unexpected #GP"); 285 1.1 maxv } 286 1.1 maxv 287 1.1 maxv ATF_REQUIRE(sig->si_signo == SIGSEGV); 288 1.1 maxv ATF_REQUIRE(sig->si_code == SEGV_ACCERR); 289 1.1 maxv 290 1.1 maxv if (uctx->uc_mcontext.__gregs[_REG_EIP] != (intptr_t)&fs_read_begin) { 291 1.1 maxv atf_tc_fail("got #GP on the wrong instruction"); 292 1.1 maxv } 293 1.1 maxv 294 1.1 maxv set_fs(GSEL(GUDATA_SEL, SEL_UPL)); 295 1.1 maxv 296 1.1 maxv atf_tc_pass(); 297 1.1 maxv /* NOTREACHED */ 298 1.1 maxv } 299 1.1 maxv 300 1.1 maxv ATF_TC(user_ldt); 301 1.1 maxv ATF_TC_HEAD(user_ldt, tc) 302 1.1 maxv { 303 1.1 maxv atf_tc_set_md_var(tc, "descr", 304 1.1 maxv "Ensure that USER_LDT works as expected"); 305 1.1 maxv } 306 1.1 maxv ATF_TC_BODY(user_ldt, tc) 307 1.1 maxv { 308 1.1 maxv union descriptor desc; 309 1.1 maxv struct sigaction act; 310 1.1 maxv 311 1.1 maxv if (!user_ldt_supported) { 312 1.1 maxv atf_tc_skip("USER_LDT disabled"); 313 1.1 maxv } 314 1.1 maxv 315 1.1 maxv memset(&act, 0, sizeof(act)); 316 1.4 maxv act.sa_sigaction = user_ldt__gp_handler; 317 1.1 maxv act.sa_flags = SA_SIGINFO; 318 1.1 maxv ATF_REQUIRE_EQ(sigaction(SIGSEGV, &act, NULL), 0); 319 1.1 maxv 320 1.1 maxv build_desc(&desc, ldt_base, PAGE_SIZE, SDT_MEMRW, SEL_UPL, 1, 0); 321 1.1 maxv ATF_REQUIRE_EQ(i386_set_ldt(256, &desc, 1), 256); 322 1.1 maxv 323 1.1 maxv set_fs(LSEL(256, SEL_UPL)); 324 1.1 maxv 325 1.1 maxv ldt_base[666] = 123; 326 1.1 maxv ldt_base[PAGE_SIZE-1] = 213; 327 1.1 maxv __insn_barrier(); 328 1.1 maxv ATF_REQUIRE_EQ(get_fs_byte((char *)666), 123); 329 1.1 maxv ATF_REQUIRE_EQ(get_fs_byte((char *)PAGE_SIZE-1), 213); 330 1.1 maxv 331 1.1 maxv /* This one should fault, and it concludes our test case. */ 332 1.1 maxv expect_crash = true; 333 1.1 maxv get_fs_byte((char *)PAGE_SIZE); 334 1.1 maxv 335 1.1 maxv atf_tc_fail("test did not fault as expected"); 336 1.1 maxv } 337 1.1 maxv 338 1.1 maxv /* -------------------------------------------------------------------------- */ 339 1.1 maxv 340 1.1 maxv ATF_TP_ADD_TCS(tp) 341 1.1 maxv { 342 1.1 maxv user_ldt_detect(); 343 1.1 maxv init_ldt_base(); 344 1.1 maxv 345 1.1 maxv ATF_TP_ADD_TC(tp, filter_ops); 346 1.4 maxv ATF_TP_ADD_TC(tp, iretq_gp); 347 1.4 maxv ATF_TP_ADD_TC(tp, iretq_np); 348 1.1 maxv ATF_TP_ADD_TC(tp, user_ldt); 349 1.1 maxv 350 1.1 maxv return atf_no_error(); 351 1.1 maxv } 352