Date: Mon, 30 Mar 2015 03:55:52 +0000 (UTC) From: Mark Johnston <markj@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r280834 - in head/sys/cddl/dev/dtrace: amd64 i386 Message-ID: <201503300355.t2U3tqo2026383@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: markj Date: Mon Mar 30 03:55:51 2015 New Revision: 280834 URL: https://svnweb.freebsd.org/changeset/base/280834 Log: Import a missing piece of commit b8fac8e162eda7e98d from illumos-gate. This adds an upper bound, dtrace_ustackdepth_max, to the number of frames traversed when computing the userland stack depth. Some programs - notably firefox - are otherwise able to trigger an infinite loop in dtrace_getustack_common(), causing a panic. MFC after: 1 week Modified: head/sys/cddl/dev/dtrace/amd64/dtrace_isa.c head/sys/cddl/dev/dtrace/i386/dtrace_isa.c Modified: head/sys/cddl/dev/dtrace/amd64/dtrace_isa.c ============================================================================== --- head/sys/cddl/dev/dtrace/amd64/dtrace_isa.c Sun Mar 29 22:46:07 2015 (r280833) +++ head/sys/cddl/dev/dtrace/amd64/dtrace_isa.c Mon Mar 30 03:55:51 2015 (r280834) @@ -49,6 +49,8 @@ uint16_t dtrace_fuword16_nocheck(void *) uint32_t dtrace_fuword32_nocheck(void *); uint64_t dtrace_fuword64_nocheck(void *); +int dtrace_ustackdepth_max = 2048; + void dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes, uint32_t *intrpc) @@ -102,14 +104,25 @@ static int dtrace_getustack_common(uint64_t *pcstack, int pcstack_limit, uintptr_t pc, uintptr_t sp) { + uintptr_t oldsp; volatile uint16_t *flags = (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags; int ret = 0; ASSERT(pcstack == NULL || pcstack_limit > 0); + ASSERT(dtrace_ustackdepth_max > 0); while (pc != 0) { - ret++; + /* + * We limit the number of times we can go around this + * loop to account for a circular stack. + */ + if (ret++ >= dtrace_ustackdepth_max) { + *flags |= CPU_DTRACE_BADSTACK; + cpu_core[curcpu].cpuc_dtrace_illval = sp; + break; + } + if (pcstack != NULL) { *pcstack++ = (uint64_t)pc; pcstack_limit--; @@ -120,10 +133,18 @@ dtrace_getustack_common(uint64_t *pcstac if (sp == 0) break; + oldsp = sp; + pc = dtrace_fuword64((void *)(sp + offsetof(struct amd64_frame, f_retaddr))); sp = dtrace_fuword64((void *)sp); + if (sp == oldsp) { + *flags |= CPU_DTRACE_BADSTACK; + cpu_core[curcpu].cpuc_dtrace_illval = sp; + break; + } + /* * This is totally bogus: if we faulted, we're going to clear * the fault and break. This is to deal with the apparently Modified: head/sys/cddl/dev/dtrace/i386/dtrace_isa.c ============================================================================== --- head/sys/cddl/dev/dtrace/i386/dtrace_isa.c Sun Mar 29 22:46:07 2015 (r280833) +++ head/sys/cddl/dev/dtrace/i386/dtrace_isa.c Mon Mar 30 03:55:51 2015 (r280834) @@ -55,6 +55,8 @@ uint16_t dtrace_fuword16_nocheck(void *) uint32_t dtrace_fuword32_nocheck(void *); uint64_t dtrace_fuword64_nocheck(void *); +int dtrace_ustackdepth_max = 2048; + void dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes, uint32_t *intrpc) @@ -113,11 +115,13 @@ dtrace_getustack_common(uint64_t *pcstac uintptr_t oldcontext = lwp->lwp_oldcontext; /* XXX signal stack. */ size_t s1, s2; #endif + uintptr_t oldsp; volatile uint16_t *flags = (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags; int ret = 0; ASSERT(pcstack == NULL || pcstack_limit > 0); + ASSERT(dtrace_ustackdepth_max > 0); #ifdef notyet /* XXX signal stack. */ if (p->p_model == DATAMODEL_NATIVE) { @@ -130,7 +134,16 @@ dtrace_getustack_common(uint64_t *pcstac #endif while (pc != 0) { - ret++; + /* + * We limit the number of times we can go around this + * loop to account for a circular stack. + */ + if (ret++ >= dtrace_ustackdepth_max) { + *flags |= CPU_DTRACE_BADSTACK; + cpu_core[curcpu].cpuc_dtrace_illval = sp; + break; + } + if (pcstack != NULL) { *pcstack++ = (uint64_t)pc; pcstack_limit--; @@ -141,6 +154,8 @@ dtrace_getustack_common(uint64_t *pcstac if (sp == 0) break; + oldsp = sp; + #ifdef notyet /* XXX signal stack. */ if (oldcontext == sp + s1 || oldcontext == sp + s2) { if (p->p_model == DATAMODEL_NATIVE) { @@ -179,6 +194,12 @@ dtrace_getustack_common(uint64_t *pcstac sp = dtrace_fuword32((void *)sp); #endif /* ! notyet */ + if (sp == oldsp) { + *flags |= CPU_DTRACE_BADSTACK; + cpu_core[curcpu].cpuc_dtrace_illval = sp; + break; + } + /* * This is totally bogus: if we faulted, we're going to clear * the fault and break. This is to deal with the apparently
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201503300355.t2U3tqo2026383>