1 /* $NetBSD: t_user_ldt.c,v 1.2 2020/04/26 12:13:10 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 != ENOTSUP); 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_fs(unsigned int val) 96 { 97 __asm volatile("mov %0,%%fs"::"r" ((unsigned short)val)); 98 } 99 100 static uint8_t __noinline 101 get_fs_byte(const char *addr) 102 { 103 uint8_t val; 104 __asm volatile ( 105 ".globl fs_read_begin; fs_read_begin:\n" 106 "movb %%fs:%1,%0\n" 107 ".globl fs_read_end; fs_read_end:\n" 108 : "=q" (val) : "m" (*addr) 109 ); 110 return val; 111 } 112 113 /* -------------------------------------------------------------------------- */ 114 115 ATF_TC(filter_ops); 116 ATF_TC_HEAD(filter_ops, tc) 117 { 118 atf_tc_set_md_var(tc, "descr", 119 "Ensure that the kernel correctly filters the descriptors"); 120 } 121 ATF_TC_BODY(filter_ops, tc) 122 { 123 union descriptor desc; 124 const int forbidden_types[] = { 125 SDT_SYS286TSS, 126 SDT_SYSLDT, 127 SDT_SYS286BSY, 128 SDT_SYS286CGT, 129 SDT_SYSTASKGT, 130 SDT_SYS286IGT, 131 SDT_SYS286TGT, 132 SDT_SYSNULL2, 133 SDT_SYS386TSS, 134 SDT_SYSNULL3, 135 SDT_SYS386BSY, 136 SDT_SYS386CGT, 137 SDT_SYSNULL4, 138 SDT_SYS386IGT, 139 SDT_SYS386TGT 140 }; 141 size_t i; 142 143 if (!user_ldt_supported) { 144 atf_tc_skip("USER_LDT disabled"); 145 } 146 147 /* The first LDT slots should not be settable. */ 148 for (i = 0; i < 10; i++) { 149 build_desc(&desc, ldt_base, PAGE_SIZE, SDT_MEMRW, 150 SEL_UPL, 1, 0); 151 ATF_REQUIRE_EQ(i386_set_ldt(i, &desc, 1), -1); 152 ATF_REQUIRE_EQ(errno, EINVAL); 153 } 154 155 /* SEL_KPL should not be allowed. */ 156 build_desc(&desc, ldt_base, PAGE_SIZE, SDT_MEMRW, SEL_KPL, 1, 0); 157 ATF_REQUIRE_EQ(i386_set_ldt(256, &desc, 1), -1); 158 ATF_REQUIRE_EQ(errno, EACCES); 159 160 /* Long-mode segments should not be allowed. */ 161 build_desc(&desc, ldt_base, PAGE_SIZE, SDT_MEMRW, SEL_UPL, 1, 0); 162 desc.sd.sd_xx = 0b11; /* sd_avl | sd_long */ 163 ATF_REQUIRE_EQ(i386_set_ldt(256, &desc, 1), -1); 164 ATF_REQUIRE_EQ(errno, EACCES); 165 166 /* No forbidden type should be allowed. */ 167 for (i = 0; i < __arraycount(forbidden_types); i++) { 168 build_desc(&desc, ldt_base, PAGE_SIZE, forbidden_types[i], 169 SEL_UPL, 1, 0); 170 ATF_REQUIRE_EQ(i386_set_ldt(256, &desc, 1), -1); 171 ATF_REQUIRE_EQ(errno, EACCES); 172 } 173 174 /* Check the slot limit. */ 175 build_desc(&desc, ldt_base, PAGE_SIZE, SDT_MEMRW, SEL_UPL, 1, 0); 176 ATF_REQUIRE_EQ(i386_set_ldt(MAX_USERLDT_SLOTS-1, &desc, 1), 177 MAX_USERLDT_SLOTS-1); 178 ATF_REQUIRE_EQ(i386_set_ldt(MAX_USERLDT_SLOTS, &desc, 1), -1); 179 ATF_REQUIRE_EQ(errno, EINVAL); 180 } 181 182 /* -------------------------------------------------------------------------- */ 183 184 static volatile bool expect_crash; 185 186 static void 187 gp_handler(int signo, siginfo_t *sig, void *ctx) 188 { 189 ucontext_t *uctx = ctx; 190 extern uint8_t fs_read_begin; 191 192 if (!expect_crash) { 193 atf_tc_fail("unexpected #GP"); 194 } 195 196 ATF_REQUIRE(sig->si_signo == SIGSEGV); 197 ATF_REQUIRE(sig->si_code == SEGV_ACCERR); 198 199 if (uctx->uc_mcontext.__gregs[_REG_EIP] != (intptr_t)&fs_read_begin) { 200 atf_tc_fail("got #GP on the wrong instruction"); 201 } 202 203 set_fs(GSEL(GUDATA_SEL, SEL_UPL)); 204 205 atf_tc_pass(); 206 /* NOTREACHED */ 207 } 208 209 ATF_TC(user_ldt); 210 ATF_TC_HEAD(user_ldt, tc) 211 { 212 atf_tc_set_md_var(tc, "descr", 213 "Ensure that USER_LDT works as expected"); 214 } 215 ATF_TC_BODY(user_ldt, tc) 216 { 217 union descriptor desc; 218 struct sigaction act; 219 220 if (!user_ldt_supported) { 221 atf_tc_skip("USER_LDT disabled"); 222 } 223 224 memset(&act, 0, sizeof(act)); 225 act.sa_sigaction = gp_handler; 226 act.sa_flags = SA_SIGINFO; 227 ATF_REQUIRE_EQ(sigaction(SIGSEGV, &act, NULL), 0); 228 229 build_desc(&desc, ldt_base, PAGE_SIZE, SDT_MEMRW, SEL_UPL, 1, 0); 230 ATF_REQUIRE_EQ(i386_set_ldt(256, &desc, 1), 256); 231 232 set_fs(LSEL(256, SEL_UPL)); 233 234 ldt_base[666] = 123; 235 ldt_base[PAGE_SIZE-1] = 213; 236 __insn_barrier(); 237 ATF_REQUIRE_EQ(get_fs_byte((char *)666), 123); 238 ATF_REQUIRE_EQ(get_fs_byte((char *)PAGE_SIZE-1), 213); 239 240 /* This one should fault, and it concludes our test case. */ 241 expect_crash = true; 242 get_fs_byte((char *)PAGE_SIZE); 243 244 atf_tc_fail("test did not fault as expected"); 245 } 246 247 /* -------------------------------------------------------------------------- */ 248 249 ATF_TP_ADD_TCS(tp) 250 { 251 user_ldt_detect(); 252 init_ldt_base(); 253 254 ATF_TP_ADD_TC(tp, filter_ops); 255 ATF_TP_ADD_TC(tp, user_ldt); 256 257 return atf_no_error(); 258 } 259