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