bool CThreadDebugger::CurrentFrameIsChildOf(JSStackFrame* pParentFrame) { JSStackFrame* iter = NULL; JSStackFrame* fp = JS_FrameIterator(m->m_pScriptInterface->GetContext(), &iter); // Get the first parent Frame fp = JS_FrameIterator(m->m_pScriptInterface->GetContext(), &iter); while (fp) { if (fp == pParentFrame) return true; fp = JS_FrameIterator(m->m_pScriptInterface->GetContext(), &iter); } return false; }
nsresult XPCJSStackFrame::CreateStack(JSContext* cx, JSStackFrame* fp, XPCJSStackFrame** stack) { static const unsigned MAX_FRAMES = 100; unsigned numFrames = 0; nsRefPtr<XPCJSStackFrame> first = new XPCJSStackFrame(); nsRefPtr<XPCJSStackFrame> self = first; while (fp && self) { if (!JS_IsScriptFrame(cx, fp)) { self->mLanguage = nsIProgrammingLanguage::CPLUSPLUS; } else { self->mLanguage = nsIProgrammingLanguage::JAVASCRIPT; JSScript* script = JS_GetFrameScript(cx, fp); jsbytecode* pc = JS_GetFramePC(cx, fp); if (script && pc) { JS::AutoEnterFrameCompartment ac; if (ac.enter(cx, fp)) { const char* filename = JS_GetScriptFilename(cx, script); if (filename) { self->mFilename = (char*) nsMemory::Clone(filename, sizeof(char)*(strlen(filename)+1)); } self->mLineno = (int32_t) JS_PCToLineNumber(cx, script, pc); JSFunction* fun = JS_GetFrameFunction(cx, fp); if (fun) { JSString *funid = JS_GetFunctionId(fun); if (funid) { size_t length = JS_GetStringEncodingLength(cx, funid); if (length != size_t(-1)) { self->mFunname = static_cast<char *>(nsMemory::Alloc(length + 1)); if (self->mFunname) { JS_EncodeStringToBuffer(funid, self->mFunname, length); self->mFunname[length] = '\0'; } } } } } } else { self->mLanguage = nsIProgrammingLanguage::CPLUSPLUS; } } if (++numFrames > MAX_FRAMES) { fp = NULL; } else if (JS_FrameIterator(cx, &fp)) { XPCJSStackFrame* frame = new XPCJSStackFrame(); self->mCaller = frame; self = frame; } } *stack = first.forget().get(); return NS_OK; }
void gjs_context_print_stack_to_buffer(GjsContext* context, void *initial, GString *buf) { JSContext *js_context = (JSContext*)gjs_context_get_native_context(context); JSStackFrame *fp = initial; int num = 0; if (fp == NULL) JS_FrameIterator(js_context, &fp); while (fp) { format_frame(js_context, fp, buf, num); num++; JS_FrameIterator(js_context, &fp); } }
void CThreadDebugger::SaveStackFrameData(STACK_INFO stackInfo, uint nestingLevel) { ENSURE(GetIsInBreak()); CScopeLock lock(m->m_Mutex); JSStackFrame *fp; JSStackFrame *iter = 0; uint counter = 0; jsval val; if (stackInfo == STACK_INFO_GLOBALOBJECT) { JSObject* obj; obj = JS_GetGlobalForScopeChain(m->m_pScriptInterface->GetContext()); m->m_StackFrameData[stackInfo][nestingLevel] = StringifyCyclicJSON(OBJECT_TO_JSVAL(obj), false); } else { fp = JS_FrameIterator(m->m_pScriptInterface->GetContext(), &iter); while (fp) { if (counter == nestingLevel) { if (stackInfo == STACK_INFO_LOCALS) { JSObject* obj; obj = JS_GetFrameCallObject(m->m_pScriptInterface->GetContext(), fp); //obj = JS_GetFrameScopeChain(m->m_pScriptInterface->GetContext(), fp); m->m_StackFrameData[stackInfo][nestingLevel] = StringifyCyclicJSON(OBJECT_TO_JSVAL(obj), false); } else if (stackInfo == STACK_INFO_THIS) { if (JS_GetFrameThis(m->m_pScriptInterface->GetContext(), fp, &val)) m->m_StackFrameData[stackInfo][nestingLevel] = StringifyCyclicJSON(val, false); else m->m_StackFrameData[stackInfo][nestingLevel] = ""; } } counter++; fp = JS_FrameIterator(m->m_pScriptInterface->GetContext(), &iter); } } }
nsresult XPCJSStack::CreateStack(JSContext* cx, nsIStackFrame** stack) { if (!cx) return NS_ERROR_FAILURE; JSStackFrame *fp = NULL; if (!JS_FrameIterator(cx, &fp)) return NS_ERROR_FAILURE; return XPCJSStackFrame::CreateStack(cx, fp, (XPCJSStackFrame**) stack); }
void CThreadDebugger::SaveCallstack() { ENSURE(GetIsInBreak()); CScopeLock lock(m->m_Mutex); JSStackFrame *fp; JSStackFrame *iter = 0; std::string functionName; jsint counter = 0; JSObject* jsArray; jsArray = JS_NewArrayObject(m->m_pScriptInterface->GetContext(), 0, 0); JSString* functionID; fp = JS_FrameIterator(m->m_pScriptInterface->GetContext(), &iter); while (fp) { JSFunction* fun = 0; fun = JS_GetFrameFunction(m->m_pScriptInterface->GetContext(), fp); if (NULL == fun) functionID = JS_NewStringCopyZ(m->m_pScriptInterface->GetContext(), "null"); else { functionID = JS_GetFunctionId(fun); if (NULL == functionID) functionID = JS_NewStringCopyZ(m->m_pScriptInterface->GetContext(), "anonymous"); } JSBool ret = JS_DefineElement(m->m_pScriptInterface->GetContext(), jsArray, counter, STRING_TO_JSVAL(functionID), NULL, NULL, 0); ENSURE(ret); fp = JS_FrameIterator(m->m_pScriptInterface->GetContext(), &iter); counter++; } m->m_Callstack = ""; m->m_Callstack = m->m_pScriptInterface->StringifyJSON(OBJECT_TO_JSVAL(jsArray), false).c_str(); }
const char* __Core_getScriptName (JSContext* cx) { JSStackFrame* fp = NULL; JSScript* script = NULL; do { fp = JS_FrameIterator(cx, &fp); script = JS_GetFrameScript(cx, fp); } while (!script && fp); return JS_GetScriptFilename(cx, script); }
JSTrapStatus CThreadDebugger::StepOutHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval, void* UNUSED(closure)) { // We break when we are in a different Frame and m_pLastBreakFrame is not a parent of the current frame // (because we stepped out of the function) JSStackFrame* iter = NULL; JSStackFrame* pStackFrame; pStackFrame = JS_FrameIterator(m->m_pScriptInterface->GetContext(), &iter); if (pStackFrame != *m->m_pLastBreakFrame && !CurrentFrameIsChildOf(*m->m_pLastBreakFrame)) { jsval val = JSVAL_VOID; return BreakHandler(cx, script, pc, rval, val, BREAK_SRC_INTERRUP); } else return JSTRAP_CONTINUE; }
JSBool xpc_DumpEvalInJSStackFrame(JSContext* cx, JSUint32 frameno, const char* text) { JSStackFrame* fp; JSStackFrame* iter = nsnull; JSUint32 num = 0; if(!cx || !text) { puts("invalid params passed to xpc_DumpEvalInJSStackFrame!"); return JS_FALSE; } printf("js[%d]> %s\n", frameno, text); while(nsnull != (fp = JS_FrameIterator(cx, &iter))) { if(num == frameno) break; num++; } if(!fp) { puts("invalid frame number!"); return JS_FALSE; } JSAutoRequest ar(cx); JSExceptionState* exceptionState = JS_SaveExceptionState(cx); JSErrorReporter older = JS_SetErrorReporter(cx, xpcDumpEvalErrorReporter); jsval rval; JSString* str; JSAutoByteString bytes; if(JS_EvaluateInStackFrame(cx, fp, text, strlen(text), "eval", 1, &rval) && nsnull != (str = JS_ValueToString(cx, rval)) && bytes.encode(cx, str)) { printf("%s\n", bytes.ptr()); } else puts("eval failed!"); JS_SetErrorReporter(cx, older); JS_RestoreExceptionState(cx, exceptionState); return JS_TRUE; }
JSTrapStatus CThreadDebugger::StepIntoHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval, void* UNUSED(closure)) { // We break when we are on the same stack frame but not on the same line // or when we are on another stack frame. uint line = JS_PCToLineNumber(cx, script, pc); JSStackFrame* iter = NULL; JSStackFrame* pStackFrame; pStackFrame = JS_FrameIterator(m->m_pScriptInterface->GetContext(), &iter); uint lastBreakLine = GetLastBreakLine(); jsval val = JSVAL_VOID; if ((*m->m_pLastBreakFrame == pStackFrame && lastBreakLine != line) || *m->m_pLastBreakFrame != pStackFrame) return BreakHandler(cx, script, pc, rval, val, BREAK_SRC_INTERRUP); else return JSTRAP_CONTINUE; }
/* define properties that JS Error() expose, such as fileName, lineNumber and stack */ static void define_error_properties(JSContext *context, JSObject *obj) { JSStackFrame *frame; JSScript *script; jsbytecode *pc; jsval v; GString *stack; const char *filename; GjsContext *gjs_context; /* find the JS frame that triggered the error */ frame = NULL; while (JS_FrameIterator(context, &frame)) { if (JS_IsScriptFrame(context, frame)) break; } /* someone called gjs_throw at top of the stack? well, no stack in that case */ if (!frame) return; script = JS_GetFrameScript(context, frame); pc = JS_GetFramePC(context, frame); stack = g_string_new(NULL); gjs_context = JS_GetContextPrivate(context); gjs_context_print_stack_to_buffer(gjs_context, frame, stack); if (gjs_string_from_utf8(context, stack->str, stack->len, &v)) JS_DefineProperty(context, obj, "stack", v, NULL, NULL, JSPROP_ENUMERATE); filename = JS_GetScriptFilename(context, script); if (gjs_string_from_filename(context, filename, -1, &v)) JS_DefineProperty(context, obj, "fileName", v, NULL, NULL, JSPROP_ENUMERATE); v = INT_TO_JSVAL(JS_PCToLineNumber(context, script, pc)); JS_DefineProperty(context, obj, "lineNumber", v, NULL, NULL, JSPROP_ENUMERATE); g_string_free(stack, TRUE); }
static JSDObject* _createJSDObject(JSDContext* jsdc, JSContext *cx, JSObject *obj) { JSDObject* jsdobj; JSStackFrame* fp; JSStackFrame* iter = NULL; const char* newURL; jsbytecode* pc; JS_ASSERT(JSD_OBJECTS_LOCKED(jsdc)); jsdobj = (JSDObject*) calloc(1, sizeof(JSDObject)); if (jsdobj) { JS_INIT_CLIST(&jsdobj->links); JS_APPEND_LINK(&jsdobj->links, &jsdc->objectsList); jsdobj->obj = obj; JS_HashTableAdd(jsdc->objectsTable, obj, jsdobj); if (jsdc->flags & JSD_DISABLE_OBJECT_TRACE) return jsdobj; /* walk the stack to find js frame (if any) causing creation */ while (NULL != (fp = JS_FrameIterator(cx, &iter))) { if( !JS_IsNativeFrame(cx, fp) ) { JSScript* script = JS_GetFrameScript(cx, fp); if( !script ) continue; newURL = JS_GetScriptFilename(cx, script); if( newURL ) jsdobj->newURL = jsd_AddAtom(jsdc, newURL); pc = JS_GetFramePC(cx, fp); if( pc ) jsdobj->newLineno = JS_PCToLineNumber(cx, script, pc); break; } } } return jsdobj; }
static char* FormatJSStackDump(JSContext* cx, char* buf, JSBool showArgs, JSBool showLocals, JSBool showThisProps) { JSStackFrame* fp; JSStackFrame* iter = nsnull; int num = 0; while (nsnull != (fp = JS_FrameIterator(cx, &iter))) { buf = FormatJSFrame(cx, fp, buf, num, showArgs, showLocals, showThisProps); num++; } if (!num) buf = JS_sprintf_append(buf, "JavaScript stack is empty\n"); return buf; }
JSTrapStatus CThreadDebugger::StepHandler(JSContext* cx, JSScript* script, jsbytecode* pc, jsval* rval, void* UNUSED(closure)) { // We break in two conditions // 1. We are in the same frame but on a different line // Note: On loops for example, we can go a few lines up again without leaving the current stack frame, so it's not necessarily // a higher line number. // 2. We are in a different Frame and m_pLastBreakFrame is not a parent of the current frame (because we stepped out of the function) uint line = JS_PCToLineNumber(cx, script, pc); JSStackFrame* iter = NULL; JSStackFrame* pStackFrame; pStackFrame = JS_FrameIterator(m->m_pScriptInterface->GetContext(), &iter); uint lastBreakLine = GetLastBreakLine() ; jsval val = JSVAL_VOID; if ((*m->m_pLastBreakFrame == pStackFrame && lastBreakLine != line) || (*m->m_pLastBreakFrame != pStackFrame && !CurrentFrameIsChildOf(*m->m_pLastBreakFrame))) return BreakHandler(cx, script, pc, rval, val, BREAK_SRC_INTERRUP); else return JSTRAP_CONTINUE; }
NS_IMETHODIMP nsJSON::EncodeFromJSVal(JS::Value *value, JSContext *cx, nsAString &result) { result.Truncate(); // Begin a new request JSAutoRequest ar(cx); JSAutoEnterCompartment ac; nsIScriptSecurityManager *ssm = nsnull; if (value->isObject()) { JSObject *obj = &value->toObject(); if (!ac.enter(cx, obj)) { return NS_ERROR_FAILURE; } nsCOMPtr<nsIPrincipal> principal; ssm = nsContentUtils::GetSecurityManager(); nsresult rv = ssm->GetObjectPrincipal(cx, obj, getter_AddRefs(principal)); NS_ENSURE_SUCCESS(rv, rv); JSStackFrame *fp = nsnull; rv = ssm->PushContextPrincipal(cx, JS_FrameIterator(cx, &fp), principal); NS_ENSURE_SUCCESS(rv, rv); } nsJSONWriter writer; JSBool ok = JS_Stringify(cx, value, NULL, JSVAL_NULL, WriteCallback, &writer); if (ssm) { ssm->PopContextPrincipal(cx); } if (!ok) { return NS_ERROR_XPC_BAD_CONVERT_JS; } NS_ENSURE_TRUE(writer.DidWrite(), NS_ERROR_UNEXPECTED); writer.FlushBuffer(); result.Assign(writer.mOutputString); return NS_OK; }
JSDScript * jsd_FindOrCreateJSDScript(JSDContext *jsdc, JSContext *cx, JSScript *script, JSStackFrame *fp) { JSDScript *jsdscript; JS_ASSERT(JSD_SCRIPTS_LOCKED(jsdc)); jsdscript = jsd_FindJSDScript(jsdc, script); if (jsdscript) return jsdscript; /* Fallback for unknown scripts: create a new script. */ if (!fp) JS_FrameIterator(cx, &fp); if (fp) jsdscript = _newJSDScript(jsdc, cx, script); return jsdscript; }
static inline JSBool EnsureLegalActivity(JSContext *cx, JSObject *obj) { jsval flags; ::JS_GetReservedSlot(cx, obj, 0, &flags); if (HAS_FLAGS(flags, FLAG_EXPLICIT)) { // Can't make any assertions about the owner of this wrapper. return JS_TRUE; } JSStackFrame *frame = nsnull; uint32 fileFlags = JS_GetTopScriptFilenameFlags(cx, NULL); if (!JS_FrameIterator(cx, &frame) || fileFlags == JSFILENAME_NULL || (fileFlags & JSFILENAME_SYSTEM)) { // We expect implicit native wrappers in system files. return JS_TRUE; } nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager(); if (!ssm) { // If there's no security manager, then we're not running in a browser // context: allow access. return JS_TRUE; } // A last ditch effort to allow access: if the currently-running code // has UniversalXPConnect privileges, then allow access. PRBool isPrivileged; nsresult rv = ssm->IsCapabilityEnabled("UniversalXPConnect", &isPrivileged); if (NS_SUCCEEDED(rv) && isPrivileged) { return JS_TRUE; } // Otherwise, we're looking at a non-system file with a handle on an // implicit wrapper. This is a bug! Deny access. return ThrowException(NS_ERROR_XPC_SECURITY_MANAGER_VETO, cx); }
bool NoWaiverWrapper::enter(JSContext *cx, JSObject *wrapper, jsid id, Action act, bool *bp) { *bp = true; // always allowed nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager(); if (!ssm) { return true; } // Note: By the time enter is called here, JSCrossCompartmentWrapper has // already pushed the fake stack frame onto cx. Because of this, the frame // that we're clamping is the one that we want (the one in our compartment). JSStackFrame *fp = NULL; nsIPrincipal *principal = GetCompartmentPrincipal(wrappedObject(wrapper)->compartment()); nsresult rv = ssm->PushContextPrincipal(cx, JS_FrameIterator(cx, &fp), principal); if (NS_FAILED(rv)) { NS_WARNING("Not allowing call because we're out of memory"); JS_ReportOutOfMemory(cx); return false; } return true; }
JSTrapStatus CThreadDebugger::BreakHandler(JSContext* cx, JSScript* script, jsbytecode* pc, jsval* UNUSED(rval), jsval UNUSED(closure), BREAK_SRC breakSrc) { uint line = JS_PCToLineNumber(cx, script, pc); std::string filename(JS_GetScriptFilename(cx, script)); SetIsInBreak(true); SaveCallstack(); SetLastBreakLine(line); SetBreakFileName(filename); *m->m_pLastBreakFrame = NULL; if (breakSrc == BREAK_SRC_INTERRUP) { JS_ClearInterrupt(m->m_pScriptInterface->GetRuntime(), NULL, NULL); JS_SetSingleStepMode(cx, script, false); } if (m->m_pDebuggingServer->GetSettingSimultaneousThreadBreak()) { m->m_pDebuggingServer->SetBreakRequestedByThread(true); } // Wait until the user continues the execution while (1) { DBGCMD nextDbgCmd = GetNextDbgCmd(); while (!m->m_StackInfoRequests.empty()) { StackInfoRequest request = m->m_StackInfoRequests.front(); SaveStackFrameData(request.requestType, request.nestingLevel); SDL_SemPost(request.semaphore); m->m_StackInfoRequests.pop(); } if (nextDbgCmd == DBG_CMD_NONE) { // Wait a while before checking for new m_NextDbgCmd again. // We don't want this loop to take 100% of a CPU core for each thread that is in break mode. // On the other hande we don't want the debugger to become unresponsive. SDL_Delay(100); } else if (nextDbgCmd == DBG_CMD_SINGLESTEP || nextDbgCmd == DBG_CMD_STEPINTO || nextDbgCmd == DBG_CMD_STEPOUT) { JSStackFrame* iter = NULL; *m->m_pLastBreakFrame = JS_FrameIterator(m->m_pScriptInterface->GetContext(), &iter); if (!JS_SetSingleStepMode(cx, script, true)) LOGERROR(L"JS_SetSingleStepMode returned false!"); // TODO: When can this happen? else { if (nextDbgCmd == DBG_CMD_SINGLESTEP) { JS_SetInterrupt(m->m_pScriptInterface->GetRuntime(), StepHandler_, this); break; } else if (nextDbgCmd == DBG_CMD_STEPINTO) { JS_SetInterrupt(m->m_pScriptInterface->GetRuntime(), StepIntoHandler_, this); break; } else if (nextDbgCmd == DBG_CMD_STEPOUT) { JS_SetInterrupt(m->m_pScriptInterface->GetRuntime(), StepOutHandler_, this); break; } } } else if (nextDbgCmd == DBG_CMD_CONTINUE) { if (!JS_SetSingleStepMode(cx, script, true)) LOGERROR(L"JS_SetSingleStepMode returned false!"); // TODO: When can this happen? else { // Setup a handler to check for break-requests from the DebuggingServer regularly JS_SetInterrupt(m->m_pScriptInterface->GetRuntime(), CheckForBreakRequestHandler_, this); } break; } else debug_warn("Invalid DBGCMD found in CThreadDebugger::BreakHandler!"); } ClearTrapsToRemove(); SetAllNewTraps(); SetNextDbgCmd(DBG_CMD_NONE); SetIsInBreak(false); SetBreakFileName(""); // All saved stack data becomes invalid { CScopeLock lock(m->m_Mutex); m->m_StackFrameData.clear(); } return JSTRAP_CONTINUE; }
// If you change this code, change also nsContentUtils::CanAccessNativeAnon()! JSBool AllowedToAct(JSContext *cx, jsid id) { // TODO bug 508928: Refactor this with the XOW security checking code. nsIScriptSecurityManager *ssm = GetSecurityManager(); if (!ssm) { return JS_TRUE; } JSStackFrame *fp; nsIPrincipal *principal = ssm->GetCxSubjectPrincipalAndFrame(cx, &fp); if (!principal) { return ThrowException(NS_ERROR_UNEXPECTED, cx); } if (!fp) { if (!JS_FrameIterator(cx, &fp)) { // No code at all is running. So we must be arriving here as the result // of C++ code asking us to do something. Allow access. return JS_TRUE; } // Some code is running, we can't make the assumption, as above, but we // can't use a native frame, so clear fp. fp = nsnull; } else if (!fp->hasScript()) { fp = nsnull; } PRBool privileged; if (NS_SUCCEEDED(ssm->IsSystemPrincipal(principal, &privileged)) && privileged) { // Chrome things are allowed to touch us. return JS_TRUE; } // XXX HACK EWW! Allow chrome://global/ access to these things, even // if they've been cloned into less privileged contexts. const char *filename; if (fp && (filename = fp->getScript()->filename) && !strncmp(filename, prefix, NS_ARRAY_LENGTH(prefix) - 1)) { return JS_TRUE; } // Before we throw, check for UniversalXPConnect. nsresult rv = ssm->IsCapabilityEnabled("UniversalXPConnect", &privileged); if (NS_SUCCEEDED(rv) && privileged) { return JS_TRUE; } if (JSID_IS_VOID(id)) { ThrowException(NS_ERROR_XPC_SECURITY_MANAGER_VETO, cx); } else { // TODO Localize me? jsval idval; JSString *str; if (JS_IdToValue(cx, id, &idval) && (str = JS_ValueToString(cx, idval))) { JS_ReportError(cx, "Permission denied to access property '%hs' from a non-chrome context", JS_GetStringChars(str)); } } return JS_FALSE; }
JSBool XPC_SJOW_Construct(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { if (argc < 1) { return ThrowException(NS_ERROR_XPC_NOT_ENOUGH_ARGS, cx); } // |obj| almost always has the wrong proto and parent so we have to create // our own object anyway. Set |obj| to null so we don't use it by accident. obj = nsnull; if (JSVAL_IS_PRIMITIVE(argv[0])) { JSStackFrame *fp = nsnull; if (JS_FrameIterator(cx, &fp) && JS_IsConstructorFrame(cx, fp)) { return ThrowException(NS_ERROR_ILLEGAL_VALUE, cx); } *rval = argv[0]; return JS_TRUE; } JSObject *objToWrap = JSVAL_TO_OBJECT(argv[0]); // Prevent script created Script objects from ever being wrapped // with XPCSafeJSObjectWrapper, and never let the eval function // object be directly wrapped. if (STOBJ_GET_CLASS(objToWrap) == &js_ScriptClass || (::JS_ObjectIsFunction(cx, objToWrap) && ::JS_GetFunctionNative(cx, ::JS_ValueToFunction(cx, argv[0])) == XPCWrapper::sEvalNative)) { return ThrowException(NS_ERROR_INVALID_ARG, cx); } SLIM_LOG_WILL_MORPH(cx, objToWrap); if(IS_SLIM_WRAPPER(objToWrap) && !MorphSlimWrapper(cx, objToWrap)) { return ThrowException(NS_ERROR_FAILURE, cx); } // Check that the caller can access the unsafe object. if (!CanCallerAccess(cx, objToWrap)) { // CanCallerAccess() already threw for us. return JS_FALSE; } JSObject *unsafeObj = GetUnsafeObject(objToWrap); if (unsafeObj) { // We're asked to wrap an already wrapped object. Re-wrap the // object wrapped by the given wrapper. objToWrap = unsafeObj; } // Don't use the object the JS engine created for us, it is in most // cases incorectly parented and has a proto from the wrong scope. JSObject *wrapperObj = ::JS_NewObjectWithGivenProto(cx, &sXPC_SJOW_JSClass.base, nsnull, objToWrap); if (!wrapperObj) { // JS_NewObjectWithGivenProto already threw. return JS_FALSE; } if (!::JS_SetReservedSlot(cx, wrapperObj, XPC_SJOW_SLOT_IS_RESOLVING, JSVAL_ZERO)) { return JS_FALSE; } *rval = OBJECT_TO_JSVAL(wrapperObj); return JS_TRUE; }
JSDThreadState* jsd_NewThreadState(JSDContext* jsdc, JSContext *cx ) { JSDThreadState* jsdthreadstate; JSStackFrame * iter = NULL; JSStackFrame * fp; jsdthreadstate = (JSDThreadState*)calloc(1, sizeof(JSDThreadState)); if( ! jsdthreadstate ) return NULL; jsdthreadstate->context = cx; jsdthreadstate->thread = JSD_CURRENT_THREAD(); JS_INIT_CLIST(&jsdthreadstate->stack); jsdthreadstate->stackDepth = 0; JS_BeginRequest(jsdthreadstate->context); while( NULL != (fp = JS_FrameIterator(cx, &iter)) ) { JSScript* script = JS_GetFrameScript(cx, fp); jsuword pc = (jsuword) JS_GetFramePC(cx, fp); /* * don't construct a JSDStackFrame for dummy frames (those without a * |this| object, or native frames, if JSD_INCLUDE_NATIVE_FRAMES * isn't set. */ if (JS_GetFrameThis(cx, fp) && ((jsdc->flags & JSD_INCLUDE_NATIVE_FRAMES) || !JS_IsNativeFrame(cx, fp))) { JSDStackFrameInfo *frame; frame = _addNewFrame( jsdc, jsdthreadstate, script, pc, fp ); if ((jsdthreadstate->stackDepth == 0 && !frame) || (jsdthreadstate->stackDepth == 1 && frame && frame->jsdscript && !JSD_IS_DEBUG_ENABLED(jsdc, frame->jsdscript))) { /* * if we failed to create the first frame, or the top frame * is not enabled for debugging, fail the entire thread state. */ JS_INIT_CLIST(&jsdthreadstate->links); JS_EndRequest(jsdthreadstate->context); jsd_DestroyThreadState(jsdc, jsdthreadstate); return NULL; } } } JS_EndRequest(jsdthreadstate->context); if (jsdthreadstate->stackDepth == 0) { free(jsdthreadstate); return NULL; } JSD_LOCK_THREADSTATES(jsdc); JS_APPEND_LINK(&jsdthreadstate->links, &jsdc->threadsStates); JSD_UNLOCK_THREADSTATES(jsdc); return jsdthreadstate; }
JSTrapStatus doi_check_sc_hs(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval,void *closure) { JSOp opcode = 0; JSStackFrame * fp = NULL; jsval r_val = 0; size_t l_val = 0; const JSCodeSpec *cs; char *updatetype = "R"; opcode = (JSOp)*pc;//JS_GetTrapOpcode(cx, script, pc);//in 1.8.0, use this cs = &js_CodeSpec[opcode]; //fprintf(stderr, "DEBUG:now %s\n", cs->name); fp = NULL; JS_FrameIterator(cx,&fp); r_val = l_val = 0; switch(opcode) { case JSOP_SETNAME: case JSOP_SETPROP: { r_val = FETCH_OPND(-1); l_val = get_opcode_arg(cx,script,pc); updatetype = "R"; break; } case JSOP_SETGVAR: { r_val = FETCH_OPND(-1); l_val = (size_t)&(fp->vars[GET_VARNO(pc)]); // TODO: FIXIT this is not l_val, setgvar is more than that updatetype = "R"; break; } case JSOP_SETELEM: { r_val = FETCH_OPND(-1); l_val = FETCH_OPND(-3); updatetype = "A"; break; } case JSOP_SETVAR: { r_val = FETCH_OPND(-1); l_val = (size_t)&(fp->vars[GET_VARNO(pc)]); // TODO: FIXIT updatetype = "R"; break; } case JSOP_SETLOCALPOP: case JSOP_SETLOCAL: { r_val = FETCH_OPND(-1); l_val = (size_t)&(fp->spbase[GET_UINT16(pc)]); updatetype = "R"; break; } case JSOP_SETARG: { r_val = FETCH_OPND(-1); l_val = (size_t)&(fp->argv[GET_ARGNO(pc)]); // TODO: FIXIT updatetype = "R"; break; } case JSOP_SETCONST: { // Errr.... actually i don't know what's the meaning of setconst etc, // if you know, please email me :) fprintf(stderr, "DEBUG: found %s\n", cs->name); r_val = FETCH_OPND(-1); l_val = 0; updatetype = "R"; break; } case JSOP_ENUMELEM: case JSOP_ENUMCONSTELEM: { fprintf(stderr, "DEBUG: found %s\n", cs->name); r_val = FETCH_OPND(-3); l_val = FETCH_OPND(-2); updatetype = "A"; break; } case JSOP_SETXMLNAME: case JSOP_SETMETHOD: { l_val = FETCH_OPND(-2); r_val = FETCH_OPND(-1); updatetype = "R"; break; } default: if(0&&cs->format & JOF_SET){ fprintf(stderr, "DEBUG: %s interpreted but not checked\n", cs->name); } break; } if(r_val != 0 && JSVAL_IS_STRING(r_val)) { uint32_t length = 0; length = JS_GetStringLength(JSVAL_TO_STRING(r_val)) * sizeof(jschar); if(length < MIN_STR_LEN_TO_CHECK){ goto end; } int r = 0; unsigned char *bytes = NULL; jschar *jschars = NULL; jschars = JS_GetStringChars(JSVAL_TO_STRING(r_val)); bytes = (unsigned char *)jschars; if(length > 65535){ //Heapspray DETECTED! /* fprintf(stderr,"\nDEBUG: HEAPSPRAY DETECTED!\n"); */ heapspray_info hsinfo; hsinfo = check_heapspray(bytes,length); PyObject* alert = NULL; PyObject* param = NULL; Context* pycx = NULL; pycx = (Context*) JS_GetContextPrivate(cx); size_t uniqueid = (size_t)pycx + (size_t)l_val; PyObject *str = PyString_FromString("alert_by_uid"); PyObject *alert_by_uid = NULL; if (str == NULL) goto error; alert_by_uid = PyObject_GetAttr((PyObject *)HeapsprayAlertType,str); Py_DECREF(str); str = NULL; if (alert_by_uid == NULL) goto error; PyObject *pyuid = Py_BuildValue("i",uniqueid); if (PyDict_Contains(alert_by_uid,pyuid)){ alert = PyDict_GetItem(alert_by_uid,pyuid); if(alert == NULL) goto error; PyObject *raiseret = PyObject_CallMethod(alert, "reraise", "sdi{s:s#,s:i,s:s#,s:i}", "Previous", hsinfo.entropy, length, "sledge_char", &(hsinfo.most_char), 1, "sledge_cnt", hsinfo.most_char_cnt, "sec_char", &(hsinfo.sec_char), 1, "sec_char_cnt", hsinfo.sec_char_cnt); if(raiseret == NULL) goto error; Py_DECREF(raiseret); raiseret = NULL; }else{ param = Py_BuildValue("isdii{s:s#,s:i,s:s#,s:i}s", -1, "Heapspray Detected!", hsinfo.entropy, length, uniqueid, "sledge_char", &(hsinfo.most_char), 1, "sledge_cnt", hsinfo.most_char_cnt, "sec_char", &(hsinfo.sec_char), 1, "sec_char_cnt", hsinfo.sec_char_cnt, updatetype); if(param == NULL) goto error; alert = PyObject_CallObject((PyObject*)HeapsprayAlertType,param); Py_DECREF(param); param = NULL; if(alert == NULL) goto error; if(PyList_Append(pycx->alertlist,alert) != 0) { goto error; } Py_DECREF(alert); alert = NULL; } Py_DECREF(pyuid); pyuid = NULL; }else{ /* FILE *f; */ /* char path[100]; */ /* sprintf(path,"debug/%d.sc",l_val); */ /* f = fopen(path,"wb"); */ /* fwrite(bytes,length,1,f); */ /* fclose(f); */ r = check_buffer(bytes,length); if(r >= 0) { //Shellcode DETECTED! /* fprintf(stderr,"\nDEBUG: SHELLCODE DETECTED!\n"); */ PyObject* alert = NULL; PyObject* param = NULL; Context* pycx = NULL; param = Py_BuildValue("iss#i", -1, "Shellcode Detected!", bytes, length, r); if(param == NULL) goto error; alert = PyObject_CallObject((PyObject*)ShellcodeAlertType,param); Py_DECREF(param); param = NULL; if(alert == NULL) goto error; pycx = (Context*) JS_GetContextPrivate(cx); if(PyList_Append(pycx->alertlist,alert) != 0) { goto error; } Py_DECREF(alert); alert = NULL; //TODO: FIXME: is it necesary to DECREF alert? /* if rt.malvariables.has_key(l_val): */ /* alert = rt.malvariables[l_val] */ /* else: */ /* alert = Alert(0,l_val,"Shellcode Detected",{"hit":0}) */ /* rt.malvariables[l_val]=alert */ /* rt.alerts.append(alert) */ /* alert.misc["hit"]+=1 */ /* jschars = JS_GetStringChars(JSVAL_TO_STRING(r_val)) */ /* bytes = <char *>jschars */ /* length = JS_GetStringLength(JSVAL_TO_STRING(r_val)) */ /* s = PyString_FromStringAndSize(bytes, length*2)#sizeof(jschar)) */ /* alert.misc["contents"] = s */ /* alert.misc["offset"] = r */ /* #f = open("shellcodes/"+str(l_val)+".sc","w") */ /* #f.write(s) */ /* #f.close() */ /* #print "DEBUG: !!!SC DETECTED at "+str(l_val)+"="+str(r_val)+"size:"+str(length*2) */ } } } end: return JSTRAP_CONTINUE; error: return JSTRAP_ERROR; }