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
This commit is contained in:
Mark Johnston 2015-03-30 03:55:51 +00:00
parent 53b2405ec0
commit 09a15aa38d
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=280834
2 changed files with 44 additions and 2 deletions

View File

@ -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 *pcstack, int pcstack_limit, uintptr_t pc,
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

View File

@ -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 *pcstack, int pcstack_limit, uintptr_t pc,
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 *pcstack, int pcstack_limit, uintptr_t pc,
#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 *pcstack, int pcstack_limit, uintptr_t pc,
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 *pcstack, int pcstack_limit, uintptr_t pc,
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