Module Name: src Committed By: maxv Date: Sun Apr 19 13:22:58 UTC 2020
Modified Files: src/distrib/sets/lists/debug: md.amd64 src/distrib/sets/lists/tests: md.amd64 mi src/etc/mtree: NetBSD.dist.tests src/tests/lib: Makefile Added Files: src/tests/lib/libi386: Makefile t_user_ldt.c Log Message: Add tests for USER_LDT. To generate a diff of this commit: cvs rdiff -u -r1.106 -r1.107 src/distrib/sets/lists/debug/md.amd64 cvs rdiff -u -r1.7 -r1.8 src/distrib/sets/lists/tests/md.amd64 cvs rdiff -u -r1.835 -r1.836 src/distrib/sets/lists/tests/mi cvs rdiff -u -r1.161 -r1.162 src/etc/mtree/NetBSD.dist.tests cvs rdiff -u -r1.32 -r1.33 src/tests/lib/Makefile cvs rdiff -u -r0 -r1.1 src/tests/lib/libi386/Makefile \ src/tests/lib/libi386/t_user_ldt.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/distrib/sets/lists/debug/md.amd64 diff -u src/distrib/sets/lists/debug/md.amd64:1.106 src/distrib/sets/lists/debug/md.amd64:1.107 --- src/distrib/sets/lists/debug/md.amd64:1.106 Mon Oct 28 15:42:07 2019 +++ src/distrib/sets/lists/debug/md.amd64 Sun Apr 19 13:22:58 2020 @@ -1,4 +1,4 @@ -# $NetBSD: md.amd64,v 1.106 2019/10/28 15:42:07 pgoyette Exp $ +# $NetBSD: md.amd64,v 1.107 2020/04/19 13:22:58 maxv Exp $ ./usr/lib/i386/12.202++_g.a comp-c-debuglib debuglib,compat,12.202xx ./usr/lib/i386/libi386_g.a comp-c-debuglib debuglib,compat ./usr/lib/i386/libiberty_g.a comp-obsolete obsolete @@ -25,5 +25,6 @@ ./usr/libdata/debug/usr/tests/kernel/arch/x86/t_ptrace_wait6.debug tests-obsolete obsolete ./usr/libdata/debug/usr/tests/kernel/arch/x86/t_ptrace_waitid.debug tests-obsolete obsolete ./usr/libdata/debug/usr/tests/kernel/arch/x86/t_ptrace_waitpid.debug tests-obsolete obsolete +./usr/libdata/debug/usr/tests/lib/libi386/t_user_ldt.debug tests-lib-debug debug,atf ./usr/libdata/debug/usr/tests/lib/libnvmm/h_io_assist.debug tests-lib-debug debug,atf ./usr/libdata/debug/usr/tests/lib/libnvmm/h_mem_assist.debug tests-lib-debug debug,atf Index: src/distrib/sets/lists/tests/md.amd64 diff -u src/distrib/sets/lists/tests/md.amd64:1.7 src/distrib/sets/lists/tests/md.amd64:1.8 --- src/distrib/sets/lists/tests/md.amd64:1.7 Tue Feb 5 13:00:03 2019 +++ src/distrib/sets/lists/tests/md.amd64 Sun Apr 19 13:22:58 2020 @@ -1,4 +1,4 @@ -# $NetBSD: md.amd64,v 1.7 2019/02/05 13:00:03 maxv Exp $ +# $NetBSD: md.amd64,v 1.8 2020/04/19 13:22:58 maxv Exp $ ./usr/tests/kernel/arch/x86/Atffile tests-obsolete obsolete ./usr/tests/kernel/arch/x86/Kyuafile tests-obsolete obsolete ./usr/tests/kernel/arch/x86/t_ptrace_wait tests-obsolete obsolete @@ -7,6 +7,7 @@ ./usr/tests/kernel/arch/x86/t_ptrace_wait6 tests-obsolete obsolete ./usr/tests/kernel/arch/x86/t_ptrace_waitid tests-obsolete obsolete ./usr/tests/kernel/arch/x86/t_ptrace_waitpid tests-obsolete obsolete +./usr/tests/lib/libi386/t_user_ldt tests-lib-tests compattestfile,atf ./usr/tests/lib/libnvmm/h_io_assist tests-lib-tests compattestfile,atf ./usr/tests/lib/libnvmm/t_io_assist tests-lib-tests compattestfile,atf ./usr/tests/lib/libnvmm/h_mem_assist tests-lib-tests compattestfile,atf Index: src/distrib/sets/lists/tests/mi diff -u src/distrib/sets/lists/tests/mi:1.835 src/distrib/sets/lists/tests/mi:1.836 --- src/distrib/sets/lists/tests/mi:1.835 Sat Apr 11 01:51:14 2020 +++ src/distrib/sets/lists/tests/mi Sun Apr 19 13:22:58 2020 @@ -1,4 +1,4 @@ -# $NetBSD: mi,v 1.835 2020/04/11 01:51:14 christos Exp $ +# $NetBSD: mi,v 1.836 2020/04/19 13:22:58 maxv Exp $ # # Note: don't delete entries from here - mark them as "obsolete" instead. # @@ -126,6 +126,7 @@ ./usr/libdata/debug/usr/tests/lib/libevent tests-lib-debug compattestfile,atf ./usr/libdata/debug/usr/tests/lib/libexecinfo tests-lib-debug compattestfile,atf ./usr/libdata/debug/usr/tests/lib/liblutok tests-lutok-debug compattestfile,atf +./usr/libdata/debug/usr/tests/lib/libi386 tests-lib-debug compattestfile,atf ./usr/libdata/debug/usr/tests/lib/libm tests-lib-debug compattestfile,atf ./usr/libdata/debug/usr/tests/lib/libnvmm tests-lib-debug compattestfile,atf ./usr/libdata/debug/usr/tests/lib/libobjc tests-lib-debug compattestfile,atf @@ -3467,6 +3468,9 @@ ./usr/tests/lib/libexecinfo/Atffile tests-lib-tests compattestfile,atf ./usr/tests/lib/libexecinfo/Kyuafile tests-lib-tests compattestfile,atf,kyua ./usr/tests/lib/libexecinfo/t_backtrace tests-lib-tests compattestfile,atf +./usr/tests/lib/libi386 tests-lib-tests compattestfile,atf +./usr/tests/lib/libi386/Atffile tests-lib-tests compattestfile,atf +./usr/tests/lib/libi386/Kyuafile tests-lib-tests compattestfile,atf,kyua ./usr/tests/lib/liblutok tests-lutok-tests compattestfile,atf ./usr/tests/lib/liblutok/Atffile tests-lutok-tests compattestfile,atf,kyua ./usr/tests/lib/liblutok/Kyuafile tests-lutok-tests compattestfile,atf,kyua Index: src/etc/mtree/NetBSD.dist.tests diff -u src/etc/mtree/NetBSD.dist.tests:1.161 src/etc/mtree/NetBSD.dist.tests:1.162 --- src/etc/mtree/NetBSD.dist.tests:1.161 Sun Mar 8 22:08:46 2020 +++ src/etc/mtree/NetBSD.dist.tests Sun Apr 19 13:22:58 2020 @@ -1,4 +1,4 @@ -# $NetBSD: NetBSD.dist.tests,v 1.161 2020/03/08 22:08:46 mgorny Exp $ +# $NetBSD: NetBSD.dist.tests,v 1.162 2020/04/19 13:22:58 maxv Exp $ ./usr/libdata/debug/usr/tests ./usr/libdata/debug/usr/tests/atf @@ -108,6 +108,7 @@ ./usr/libdata/debug/usr/tests/lib/libexecinfo ./usr/libdata/debug/usr/tests/lib/semaphore ./usr/libdata/debug/usr/tests/lib/semaphore/pthread +./usr/libdata/debug/usr/tests/lib/libi386 ./usr/libdata/debug/usr/tests/lib/liblutok ./usr/libdata/debug/usr/tests/lib/libm ./usr/libdata/debug/usr/tests/lib/libnvmm @@ -303,6 +304,7 @@ ./usr/tests/lib/libbpfjit ./usr/tests/lib/libevent ./usr/tests/lib/libexecinfo +./usr/tests/lib/libi386 ./usr/tests/lib/liblutok ./usr/tests/lib/libm ./usr/tests/lib/libnvmm Index: src/tests/lib/Makefile diff -u src/tests/lib/Makefile:1.32 src/tests/lib/Makefile:1.33 --- src/tests/lib/Makefile:1.32 Fri Jan 17 16:24:03 2020 +++ src/tests/lib/Makefile Sun Apr 19 13:22:58 2020 @@ -1,10 +1,10 @@ -# $NetBSD: Makefile,v 1.32 2020/01/17 16:24:03 christos Exp $ +# $NetBSD: Makefile,v 1.33 2020/04/19 13:22:58 maxv Exp $ .include <bsd.own.mk> TESTS_SUBDIRS= csu libarchive libbluetooth libc libcrypt libcurses \ - libexecinfo libm libnvmm libobjc libposix libppath libprop \ - libpthread librefuse librt libtre libusbhid libutil \ + libexecinfo libi386 libm libnvmm libobjc libposix libppath \ + libprop libpthread librefuse librt libtre libusbhid libutil \ semaphore TESTS_SUBDIR_INSTALL_ONLY= libevent Added files: Index: src/tests/lib/libi386/Makefile diff -u /dev/null src/tests/lib/libi386/Makefile:1.1 --- /dev/null Sun Apr 19 13:22:58 2020 +++ src/tests/lib/libi386/Makefile Sun Apr 19 13:22:58 2020 @@ -0,0 +1,13 @@ +# $NetBSD: Makefile,v 1.1 2020/04/19 13:22:58 maxv Exp $ + +.include <bsd.own.mk> + +.if ${MACHINE} == "amd64" +TESTSDIR= ${TESTSBASE}/lib/libi386 +COPTS+= -m32 +LDFLAGS+= -m32 +LDADD+= -li386 +TESTS_C+= t_user_ldt +.endif + +.include <bsd.test.mk> Index: src/tests/lib/libi386/t_user_ldt.c diff -u /dev/null src/tests/lib/libi386/t_user_ldt.c:1.1 --- /dev/null Sun Apr 19 13:22:58 2020 +++ src/tests/lib/libi386/t_user_ldt.c Sun Apr 19 13:22:58 2020 @@ -0,0 +1,247 @@ +/* $NetBSD: t_user_ldt.c,v 1.1 2020/04/19 13:22:58 maxv Exp $ */ + +/* + * Copyright (c) 2020 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Maxime Villard. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> +#include <signal.h> + +#include <sys/types.h> +#include <sys/mman.h> +#include <machine/segments.h> +#include <machine/sysarch.h> +#include <machine/vmparam.h> + +#include <atf-c.h> + +static uint8_t *ldt_base; +static bool user_ldt_supported; + +static void +user_ldt_detect(void) +{ + union descriptor desc; + int ret; + + ret = i386_get_ldt(0, &desc, 1); + user_ldt_supported = (ret != -1) || (errno != ENOTSUP); +} + +static void +init_ldt_base(void) +{ + ldt_base = (uint8_t *)mmap(NULL, 2 * PAGE_SIZE, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON, -1, 0); + if (ldt_base == MAP_FAILED) + atf_tc_fail("mmap failed"); + munmap(ldt_base + PAGE_SIZE, PAGE_SIZE); +} + +static void +build_desc(union descriptor *desc, void *basep, uint32_t limit, int type, + int dpl, int def32, int gran) +{ + uintptr_t base = (uintptr_t)basep; + + limit--; + + desc->sd.sd_lolimit = limit & 0x0000ffff; + desc->sd.sd_lobase = base & 0x00ffffff; + desc->sd.sd_type = type & 0x1F; + desc->sd.sd_dpl = dpl & 0x3; + desc->sd.sd_p = 1; + desc->sd.sd_hilimit = (limit & 0x00ff0000) >> 16; + desc->sd.sd_xx = 0; + desc->sd.sd_def32 = def32 ? 1 : 0; + desc->sd.sd_gran = gran ? 1 : 0; + desc->sd.sd_hibase = (base & 0xff000000) >> 24; +} + +static void +set_fs(unsigned int val) +{ + __asm volatile("mov %0,%%fs"::"r" ((unsigned short)val)); +} + +static uint8_t __noinline +get_fs_byte(const char *addr) +{ + uint8_t val; + __asm volatile ( + ".globl fs_read_begin; fs_read_begin:\n" + "movb %%fs:%1,%0\n" + ".globl fs_read_end; fs_read_end:\n" + : "=q" (val) : "m" (*addr) + ); + return val; +} + +/* -------------------------------------------------------------------------- */ + +ATF_TC(filter_ops); +ATF_TC_HEAD(filter_ops, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Ensure that the kernel correctly filters the descriptors"); +} +ATF_TC_BODY(filter_ops, tc) +{ + union descriptor desc; + const int forbidden_types[] = { + SDT_SYS286TSS, + SDT_SYSLDT, + SDT_SYS286BSY, + SDT_SYS286CGT, + SDT_SYSTASKGT, + SDT_SYS286IGT, + SDT_SYS286TGT, + SDT_SYSNULL2, + SDT_SYS386TSS, + SDT_SYSNULL3, + SDT_SYS386BSY, + SDT_SYS386CGT, + SDT_SYSNULL4, + SDT_SYS386IGT, + SDT_SYS386TGT + }; + size_t i; + + if (!user_ldt_supported) { + atf_tc_skip("USER_LDT disabled"); + } + + /* The first LDT slots should not be settable. */ + for (i = 0; i < 10; i++) { + build_desc(&desc, ldt_base, PAGE_SIZE, SDT_MEMRW, + SEL_UPL, 1, 0); + ATF_REQUIRE_EQ(i386_set_ldt(i, &desc, 1), -1); + ATF_REQUIRE_EQ(errno, EINVAL); + } + + /* SEL_KPL should not be allowed. */ + build_desc(&desc, ldt_base, PAGE_SIZE, SDT_MEMRW, SEL_KPL, 1, 0); + ATF_REQUIRE_EQ(i386_set_ldt(256, &desc, 1), -1); + ATF_REQUIRE_EQ(errno, EACCES); + + /* Long-mode segments should not be allowed. */ + build_desc(&desc, ldt_base, PAGE_SIZE, SDT_MEMRW, SEL_UPL, 1, 0); + desc.sd.sd_xx = 0b11; /* sd_avl | sd_long */ + ATF_REQUIRE_EQ(i386_set_ldt(256, &desc, 1), -1); + ATF_REQUIRE_EQ(errno, EACCES); + + /* No forbidden type should be allowed. */ + for (i = 0; i < __arraycount(forbidden_types); i++) { + build_desc(&desc, ldt_base, PAGE_SIZE, forbidden_types[i], + SEL_UPL, 1, 0); + ATF_REQUIRE_EQ(i386_set_ldt(256, &desc, 1), -1); + ATF_REQUIRE_EQ(errno, EACCES); + } +} + +/* -------------------------------------------------------------------------- */ + +static volatile bool expect_crash; + +static void +gp_handler(int signo, siginfo_t *sig, void *ctx) +{ + ucontext_t *uctx = ctx; + extern uint8_t fs_read_begin; + + if (!expect_crash) { + atf_tc_fail("unexpected #GP"); + } + + ATF_REQUIRE(sig->si_signo == SIGSEGV); + ATF_REQUIRE(sig->si_code == SEGV_ACCERR); + + if (uctx->uc_mcontext.__gregs[_REG_EIP] != (intptr_t)&fs_read_begin) { + atf_tc_fail("got #GP on the wrong instruction"); + } + + set_fs(GSEL(GUDATA_SEL, SEL_UPL)); + + atf_tc_pass(); + /* NOTREACHED */ +} + +ATF_TC(user_ldt); +ATF_TC_HEAD(user_ldt, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Ensure that USER_LDT works as expected"); +} +ATF_TC_BODY(user_ldt, tc) +{ + union descriptor desc; + struct sigaction act; + + if (!user_ldt_supported) { + atf_tc_skip("USER_LDT disabled"); + } + + memset(&act, 0, sizeof(act)); + act.sa_sigaction = gp_handler; + act.sa_flags = SA_SIGINFO; + ATF_REQUIRE_EQ(sigaction(SIGSEGV, &act, NULL), 0); + + build_desc(&desc, ldt_base, PAGE_SIZE, SDT_MEMRW, SEL_UPL, 1, 0); + ATF_REQUIRE_EQ(i386_set_ldt(256, &desc, 1), 256); + + set_fs(LSEL(256, SEL_UPL)); + + ldt_base[666] = 123; + ldt_base[PAGE_SIZE-1] = 213; + __insn_barrier(); + ATF_REQUIRE_EQ(get_fs_byte((char *)666), 123); + ATF_REQUIRE_EQ(get_fs_byte((char *)PAGE_SIZE-1), 213); + + /* This one should fault, and it concludes our test case. */ + expect_crash = true; + get_fs_byte((char *)PAGE_SIZE); + + atf_tc_fail("test did not fault as expected"); +} + +/* -------------------------------------------------------------------------- */ + +ATF_TP_ADD_TCS(tp) +{ + user_ldt_detect(); + init_ldt_base(); + + ATF_TP_ADD_TC(tp, filter_ops); + ATF_TP_ADD_TC(tp, user_ldt); + + return atf_no_error(); +}