From 2118ab6722eb4b2d2f28e63436d94bfd0f36c928 Mon Sep 17 00:00:00 2001 From: ngie Date: Thu, 9 Feb 2017 22:04:56 +0000 Subject: [PATCH] MFC r258903,r264487,r271699,r288415: r258903 (by markj): Enable some previously-disabled DTrace tests for umod, ufunc and usym. They expect the installed ksh binary to be named "ksh", which is not the case when it's installed on FreeBSD via the shells/ksh93 port. Allow for it to be "ksh93" as well so that the tests can actually pass. r264487 (by markj): Replace a few Solarisisms with their corresponding FreeBSDisms to make a few printf tests pass. r271699 (by markj): Implement a workaround to allow this test program to be compiled with clang. It seems that if a pragma is used to define a weak alias for a local function, the pragma must appear after the function is defined. PR: 193056 r288415 (by markj): MFV r288408: 6266 harden dtrace_difo_chunksize() with respect to malicious DIF illumos/illumos-gate@395c7a3dcfc66b8b671dc4b3c4a2f0ca26449922 Author: Bryan Cantrill git-svn-id: svn://svn.freebsd.org/base/stable/10@313486 ccf9f872-aa2e-dd11-9fc8-001c23d0bc1f --- .../dtrace/test/tst/common/pid/tst.weak2.c | 4 +- .../test/tst/common/printf/tst.basics.d | 2 +- .../test/tst/common/printf/tst.basics.d.out | 2 +- .../dtrace/test/tst/common/printf/tst.str.d | 2 +- .../test/tst/common/printf/tst.str.d.out | 2 +- .../dtrace/test/tst/common/printf/tst.sym.d | 2 +- .../test/tst/common/printf/tst.sym.d.out | 2 +- .../test/tst/common/privs/tst.kpriv.ksh | 112 ++++++++++++++++++ .../test/tst/common/profile-n/tst.ufunc.ksh | 2 +- .../test/tst/common/profile-n/tst.umod.ksh | 2 +- .../test/tst/common/profile-n/tst.usym.ksh | 2 +- .../test/tst/common/scalars/err.bigglobal.d | 26 ++++ .../test/tst/common/scalars/err.biglocal.d | 26 ++++ .../opensolaris/uts/common/dtrace/dtrace.c | 67 +++++++++-- .../opensolaris/uts/common/sys/dtrace_impl.h | 19 +-- tools/test/dtrace/Makefile | 5 - 16 files changed, 245 insertions(+), 32 deletions(-) create mode 100644 cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/privs/tst.kpriv.ksh create mode 100644 cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/err.bigglobal.d create mode 100644 cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/err.biglocal.d diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.weak2.c b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.weak2.c index 42d8cde31..756745d99 100644 --- a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.weak2.c +++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.weak2.c @@ -35,14 +35,14 @@ * leading underscores. */ -#pragma weak _go = go - static int go(int a) { return (a + 1); } +#pragma weak _go = go + static void handle(int sig) { diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.basics.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.basics.d index 8d4bb819d..10dc61dab 100644 --- a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.basics.d +++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.basics.d @@ -44,7 +44,7 @@ BEGIN printf("\n"); - printf("%%a = %a\n", &`kmem_alloc); + printf("%%a = %a\n", &`malloc); printf("%%c = %c\n", i); printf("%%d = %d\n", i); printf("%%hd = %hd\n", (short)i); diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.basics.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.basics.d.out index 55c122223..1d2740578 100644 --- a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.basics.d.out +++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.basics.d.out @@ -1,5 +1,5 @@ -%a = genunix`kmem_alloc +%a = kernel`malloc %c = a %d = 97 %hd = 97 diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.str.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.str.d index a74041393..67d774910 100644 --- a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.str.d +++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.str.d @@ -36,6 +36,6 @@ BEGIN { - printf("sysname = %s", `utsname.sysname); + printf("sysname = %s", `ostype); exit(0); } diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.str.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.str.d.out index ba3198176..82d597b14 100644 --- a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.str.d.out +++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.str.d.out @@ -1 +1 @@ -sysname = SunOS +sysname = FreeBSD diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.sym.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.sym.d index 32bc682e8..c2cf77d63 100644 --- a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.sym.d +++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.sym.d @@ -38,6 +38,6 @@ BEGIN { - printf("symbol = %a", &`kmem_alloc); + printf("symbol = %a", &`malloc); exit(0); } diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.sym.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.sym.d.out index 5ed9d8ec5..7f645e170 100644 --- a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.sym.d.out +++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/printf/tst.sym.d.out @@ -1 +1 @@ -symbol = kernel`kmem_alloc +symbol = kernel`malloc diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/privs/tst.kpriv.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/privs/tst.kpriv.ksh new file mode 100644 index 000000000..da776d042 --- /dev/null +++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/privs/tst.kpriv.ksh @@ -0,0 +1,112 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright (c) 2015, Joyent, Inc. All rights reserved. +# + +err=/tmp/err.$$ + +ppriv -s A=basic,dtrace_user $$ + +# +# When we lack dtrace_kernel, we expect to not be able to get at kernel memory +# via any subroutine or other vector. +# +# trace(func((void *)&\`utsname)); } +/usr/sbin/dtrace -wq -Cs /dev/stdin 2> $err < /dev/null +script | tee /dev/fd/2 | egrep 'ksh(93)?`[a-zA-Z_]' > /dev/null status=$? kill $child diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.umod.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.umod.ksh index 6ca823f5d..8be34ec23 100644 --- a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.umod.ksh +++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.umod.ksh @@ -62,7 +62,7 @@ child=$! # # The only thing we can be sure of here is that ksh is doing some work. # -script | tee /dev/fd/2 | grep -w ksh > /dev/null +script | tee /dev/fd/2 | egrep -w 'ksh(93)?' > /dev/null status=$? kill $child diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.usym.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.usym.ksh index b1a3ab9de..8842d2b09 100644 --- a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.usym.ksh +++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.usym.ksh @@ -63,7 +63,7 @@ child=$! # This test is essentially the same as that in the ufunc test; see that # test for the rationale. # -script | tee /dev/fd/2 | grep 'ksh`[a-zA-Z_]' > /dev/null +script | tee /dev/fd/2 | egrep 'ksh(93)?`[a-zA-Z_]' > /dev/null status=$? kill $child diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/err.bigglobal.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/err.bigglobal.d new file mode 100644 index 000000000..a50a759e4 --- /dev/null +++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/err.bigglobal.d @@ -0,0 +1,26 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright (c) 2015, Joyent, Inc. All rights reserved. + */ + +struct mrbig { + char toomany[100000]; +}; + +struct mrbig mrbig; + +BEGIN +{ + mrbig.toomany[0] = '!'; + exit(0); +} diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/err.biglocal.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/err.biglocal.d new file mode 100644 index 000000000..08a2a4c2e --- /dev/null +++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/scalars/err.biglocal.d @@ -0,0 +1,26 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright (c) 2015, Joyent, Inc. All rights reserved. + */ + +struct mrbig { + char toomany[100000]; +}; + +this struct mrbig mrbig; + +BEGIN +{ + this->mrbig.toomany[0] = '!'; + exit(0); +} diff --git a/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c b/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c index a087e6ebb..cb12cee17 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c +++ b/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c @@ -155,7 +155,7 @@ int dtrace_destructive_disallow = 0; dtrace_optval_t dtrace_nonroot_maxsize = (16 * 1024 * 1024); size_t dtrace_difo_maxsize = (256 * 1024); dtrace_optval_t dtrace_dof_maxsize = (8 * 1024 * 1024); -size_t dtrace_global_maxsize = (16 * 1024); +size_t dtrace_statvar_maxsize = (16 * 1024); size_t dtrace_actions_max = (16 * 1024); size_t dtrace_retain_max = 1024; dtrace_optval_t dtrace_helper_actions_max = 128; @@ -699,13 +699,33 @@ dtrace_canstore_statvar(uint64_t addr, size_t sz, dtrace_statvar_t **svars, int nsvars) { int i; + size_t maxglobalsize, maxlocalsize; + + if (nsvars == 0) + return (0); + + maxglobalsize = dtrace_statvar_maxsize; + maxlocalsize = (maxglobalsize + sizeof (uint64_t)) * NCPU; for (i = 0; i < nsvars; i++) { dtrace_statvar_t *svar = svars[i]; + uint8_t scope; + size_t size; - if (svar == NULL || svar->dtsv_size == 0) + if (svar == NULL || (size = svar->dtsv_size) == 0) continue; + scope = svar->dtsv_var.dtdv_scope; + + /* + * We verify that our size is valid in the spirit of providing + * defense in depth: we want to prevent attackers from using + * DTrace to escalate an orthogonal kernel heap corruption bug + * into the ability to store to arbitrary locations in memory. + */ + VERIFY((scope == DIFV_SCOPE_GLOBAL && size < maxglobalsize) || + (scope == DIFV_SCOPE_LOCAL && size < maxlocalsize)); + if (DTRACE_INRANGE(addr, sz, svar->dtsv_data, svar->dtsv_size)) return (1); } @@ -4455,7 +4475,8 @@ dtrace_dif_subr(uint_t subr, uint_t rd, uint64_t *regs, if (!dtrace_destructive_disallow && dtrace_priv_proc_control(state) && - !dtrace_istoxic(kaddr, size)) { + !dtrace_istoxic(kaddr, size) && + dtrace_canload(kaddr, size, mstate, vstate)) { DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); dtrace_copyout(kaddr, uaddr, size, flags); DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); @@ -4470,7 +4491,8 @@ dtrace_dif_subr(uint_t subr, uint_t rd, uint64_t *regs, if (!dtrace_destructive_disallow && dtrace_priv_proc_control(state) && - !dtrace_istoxic(kaddr, size)) { + !dtrace_istoxic(kaddr, size) && + dtrace_strcanload(kaddr, size, mstate, vstate)) { DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); dtrace_copyoutstr(kaddr, uaddr, size, flags); DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); @@ -6458,6 +6480,11 @@ dtrace_dif_emulate(dtrace_difo_t *difo, dtrace_mstate_t *mstate, regs[r2] ? regs[r2] : dtrace_strsize_default) + 1; } else { + if (regs[r2] > LONG_MAX) { + *flags |= CPU_DTRACE_ILLOP; + break; + } + tupregs[ttop].dttk_size = regs[r2]; } @@ -9919,9 +9946,10 @@ dtrace_difo_validate(dtrace_difo_t *dp, dtrace_vstate_t *vstate, uint_t nregs, break; } - if (v->dtdv_scope == DIFV_SCOPE_GLOBAL && - vt->dtdt_size > dtrace_global_maxsize) { - err += efunc(i, "oversized by-ref global\n"); + if ((v->dtdv_scope == DIFV_SCOPE_GLOBAL || + v->dtdv_scope == DIFV_SCOPE_LOCAL) && + vt->dtdt_size > dtrace_statvar_maxsize) { + err += efunc(i, "oversized by-ref static\n"); break; } } @@ -10265,6 +10293,9 @@ dtrace_difo_chunksize(dtrace_difo_t *dp, dtrace_vstate_t *vstate) if (srd == 0) return; + if (sval > LONG_MAX) + return; + tupregs[ttop++].dttk_size = sval; } @@ -10326,6 +10357,19 @@ dtrace_difo_chunksize(dtrace_difo_t *dp, dtrace_vstate_t *vstate) */ size = P2ROUNDUP(size, sizeof (uint64_t)); + /* + * Before setting the chunk size, check that we're not going + * to set it to a negative value... + */ + if (size > LONG_MAX) + return; + + /* + * ...and make certain that we didn't badly overflow. + */ + if (size < ksize || size < sizeof (dtrace_dynvar_t)) + return; + if (size > vstate->dtvs_dynvars.dtds_chunksize) vstate->dtvs_dynvars.dtds_chunksize = size; } @@ -13945,6 +13989,8 @@ dtrace_dstate_init(dtrace_dstate_t *dstate, size_t size) if ((dstate->dtds_chunksize = chunksize) == 0) dstate->dtds_chunksize = DTRACE_DYNVAR_CHUNKSIZE; + VERIFY(dstate->dtds_chunksize < LONG_MAX); + if (size < (min = dstate->dtds_chunksize + sizeof (dtrace_dynhash_t))) size = min; @@ -13985,6 +14031,9 @@ dtrace_dstate_init(dtrace_dstate_t *dstate, size_t size) ((uintptr_t)base + hashsize * sizeof (dtrace_dynhash_t)); limit = (uintptr_t)base + size; + VERIFY((uintptr_t)start < limit); + VERIFY((uintptr_t)start >= (uintptr_t)base); + maxper = (limit - (uintptr_t)start) / NCPU; maxper = (maxper / dstate->dtds_chunksize) * dstate->dtds_chunksize; @@ -14010,7 +14059,7 @@ dtrace_dstate_init(dtrace_dstate_t *dstate, size_t size) start = (dtrace_dynvar_t *)limit; } - ASSERT(limit <= (uintptr_t)base + size); + VERIFY(limit <= (uintptr_t)base + size); for (;;) { next = (dtrace_dynvar_t *)((uintptr_t)dvar + @@ -14019,6 +14068,8 @@ dtrace_dstate_init(dtrace_dstate_t *dstate, size_t size) if ((uintptr_t)next + dstate->dtds_chunksize >= limit) break; + VERIFY((uintptr_t)dvar >= (uintptr_t)base && + (uintptr_t)dvar <= (uintptr_t)base + size); dvar->dtdv_next = next; dvar = next; } diff --git a/sys/cddl/contrib/opensolaris/uts/common/sys/dtrace_impl.h b/sys/cddl/contrib/opensolaris/uts/common/sys/dtrace_impl.h index a65d1ae16..1ec90914d 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/sys/dtrace_impl.h +++ b/sys/cddl/contrib/opensolaris/uts/common/sys/dtrace_impl.h @@ -1317,16 +1317,19 @@ extern void dtrace_copystr(uintptr_t, uintptr_t, size_t, volatile uint16_t *); /* * DTrace Assertions * - * DTrace calls ASSERT from probe context. To assure that a failed ASSERT - * does not induce a markedly more catastrophic failure (e.g., one from which - * a dump cannot be gleaned), DTrace must define its own ASSERT to be one that - * may safely be called from probe context. This header file must thus be - * included by any DTrace component that calls ASSERT from probe context, and - * _only_ by those components. (The only exception to this is kernel - * debugging infrastructure at user-level that doesn't depend on calling - * ASSERT.) + * DTrace calls ASSERT and VERIFY from probe context. To assure that a failed + * ASSERT or VERIFY does not induce a markedly more catastrophic failure (e.g., + * one from which a dump cannot be gleaned), DTrace must define its own ASSERT + * and VERIFY macros to be ones that may safely be called from probe context. + * This header file must thus be included by any DTrace component that calls + * ASSERT and/or VERIFY from probe context, and _only_ by those components. + * (The only exception to this is kernel debugging infrastructure at user-level + * that doesn't depend on calling ASSERT.) */ #undef ASSERT +#undef VERIFY +#define VERIFY(EX) ((void)((EX) || \ + dtrace_assfail(#EX, __FILE__, __LINE__))) #ifdef DEBUG #define ASSERT(EX) ((void)((EX) || \ dtrace_assfail(#EX, __FILE__, __LINE__))) diff --git a/tools/test/dtrace/Makefile b/tools/test/dtrace/Makefile index c82d6f7df..4b3842b0f 100644 --- a/tools/test/dtrace/Makefile +++ b/tools/test/dtrace/Makefile @@ -59,7 +59,6 @@ IGNORE= \ ${TESTSRCDIR}/tst/common/proc/tst.discard.ksh \ ${TESTSRCDIR}/tst/common/proc/tst.signal.ksh \ ${TESTSRCDIR}/tst/common/proc/tst.startexit.ksh \ - ${TESTSRCDIR}/tst/common/profile-n/tst.ufuncsort.c \ ${TESTSRCDIR}/tst/common/scalars/tst.misc.d \ ${TESTSRCDIR}/tst/common/scalars/tst.selfarray2.d \ ${TESTSRCDIR}/tst/common/sysevent/tst.post.c \ @@ -115,10 +114,6 @@ NOTWORK+= \ ${TESTSRCDIR}/tst/common/profile-n/tst.func.ksh \ ${TESTSRCDIR}/tst/common/profile-n/tst.mod.ksh \ ${TESTSRCDIR}/tst/common/profile-n/tst.sym.ksh \ - ${TESTSRCDIR}/tst/common/profile-n/tst.ufunc.ksh \ - ${TESTSRCDIR}/tst/common/profile-n/tst.ufuncsort.ksh \ - ${TESTSRCDIR}/tst/common/profile-n/tst.umod.ksh \ - ${TESTSRCDIR}/tst/common/profile-n/tst.usym.ksh \ ${TESTSRCDIR}/tst/common/safety/tst.basename.d \ ${TESTSRCDIR}/tst/common/safety/tst.caller.d \ ${TESTSRCDIR}/tst/common/safety/tst.cleanpath.d \ -- 2.45.0