Changeset 126852 in webkit


Ignore:
Timestamp:
Aug 28, 2012 12:11:28 AM (12 years ago)
Author:
commit-queue@webkit.org
Message:

Add call stacks to Content Security Policy checks when relevant.
https://bugs.webkit.org/show_bug.cgi?id=94433

Patch by Mike West <mkwst@chromium.org> on 2012-08-28
Reviewed by Adam Barth.

Source/WebCore:

Previously, we generated stack traces only for eval-related CSP
violations. As it turns out, we can call createScriptCallStack from
practically anywhere. This patch takes advantage of that to generate
stack traces whenever a warning is logged to the console. If we're in
a JavaScript stack, brilliant: we get a detailed warning. If not, the
stack trace is empty, and we don't pass it into the console logging
method.

This has the advantage of giving us good developer-facing logging for
any and all violations that result from script-based injection of
resources. Yay!

Tests: http/tests/inspector/csp-injected-content-warning-contains-stacktrace.html

http/tests/inspector/csp-inline-warning-contains-stacktrace.html

  • bindings/js/ScriptController.cpp:

(WebCore::ScriptController::initScript):

  • bindings/js/ScheduledAction.cpp:

(WebCore::ScheduledAction::create):

  • bindings/v8/V8DOMWindowShell.cpp:

(WebCore::V8DOMWindowShell::initContextIfNeeded):

  • bindings/v8/custom/V8DOMWindowCustom.cpp:

(WebCore::WindowSetTimeoutImpl):

Dropping stack trace from call to ContentSecurityPolicy::allowEval.

  • page/ContentSecurityPolicy.cpp:

(CSPDirectiveList):
(WebCore::CSPDirectiveList::reportViolation):
(WebCore::CSPDirectiveList::checkEvalAndReportViolation):
(WebCore::CSPDirectiveList::allowEval):

No longer piping a stack trace through CSPDirectiveList::allowEval
to reportViolation.

(WebCore::ContentSecurityPolicy::didReceiveHeader):

Dropping stack trace from call to ContentSecurityPolicy::allowEval.

(WebCore):
(WebCore::isAllowedByAll):
(WebCore::ContentSecurityPolicy::allowEval):
(WebCore::ContentSecurityPolicy::reportViolation):
(WebCore::ContentSecurityPolicy::logToConsole):

No longer piping a stack trace through ContentSecurityPolicy down to
the point where it would be logged. Instead, we simply generate the
stack trace just before logging it, and only pass it to
addConsoleMessage if it's non-empty.

  • page/ContentSecurityPolicy.h:

(WebCore):

  • page/DOMSecurityPolicy.cpp:

(WebCore::DOMSecurityPolicy::allowsEval):

Dropping stack trace from call to ContentSecurityPolicy::allowEval.

LayoutTests:

  • http/tests/inspector/csp-injected-content-warning-contains-stacktrace-expected.txt: Added.
  • http/tests/inspector/csp-injected-content-warning-contains-stacktrace.html: Added.
  • http/tests/inspector/csp-inline-warning-contains-stacktrace-expected.txt: Added.
  • http/tests/inspector/csp-inline-warning-contains-stacktrace.html: Added.
  • http/tests/inspector/resources/csp-inline-test.js: Added.

(thisTest):

  • http/tests/inspector/resources/csp-test.js: Added.

(test.addMessage):
(test):

Location:
trunk
Files:
6 added
9 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r126850 r126852  
     12012-08-28  Mike West  <mkwst@chromium.org>
     2
     3        Add call stacks to Content Security Policy checks when relevant.
     4        https://bugs.webkit.org/show_bug.cgi?id=94433
     5
     6        Reviewed by Adam Barth.
     7
     8        * http/tests/inspector/csp-injected-content-warning-contains-stacktrace-expected.txt: Added.
     9        * http/tests/inspector/csp-injected-content-warning-contains-stacktrace.html: Added.
     10        * http/tests/inspector/csp-inline-warning-contains-stacktrace-expected.txt: Added.
     11        * http/tests/inspector/csp-inline-warning-contains-stacktrace.html: Added.
     12        * http/tests/inspector/resources/csp-inline-test.js: Added.
     13        (thisTest):
     14        * http/tests/inspector/resources/csp-test.js: Added.
     15        (test.addMessage):
     16        (test):
     17
    1182012-08-27  Zan Dobersek  <zandobersek@gmail.com>
    219
  • trunk/Source/WebCore/ChangeLog

    r126851 r126852  
     12012-08-28  Mike West  <mkwst@chromium.org>
     2
     3        Add call stacks to Content Security Policy checks when relevant.
     4        https://bugs.webkit.org/show_bug.cgi?id=94433
     5
     6        Reviewed by Adam Barth.
     7
     8        Previously, we generated stack traces only for eval-related CSP
     9        violations. As it turns out, we can call createScriptCallStack from
     10        practically anywhere. This patch takes advantage of that to generate
     11        stack traces whenever a warning is logged to the console. If we're in
     12        a JavaScript stack, brilliant: we get a detailed warning. If not, the
     13        stack trace is empty, and we don't pass it into the console logging
     14        method.
     15
     16        This has the advantage of giving us good developer-facing logging for
     17        any and all violations that result from script-based injection of
     18        resources. Yay!
     19
     20        Tests: http/tests/inspector/csp-injected-content-warning-contains-stacktrace.html
     21               http/tests/inspector/csp-inline-warning-contains-stacktrace.html
     22
     23        * bindings/js/ScriptController.cpp:
     24        (WebCore::ScriptController::initScript):
     25        * bindings/js/ScheduledAction.cpp:
     26        (WebCore::ScheduledAction::create):
     27        * bindings/v8/V8DOMWindowShell.cpp:
     28        (WebCore::V8DOMWindowShell::initContextIfNeeded):
     29        * bindings/v8/custom/V8DOMWindowCustom.cpp:
     30        (WebCore::WindowSetTimeoutImpl):
     31            Dropping stack trace from call to ContentSecurityPolicy::allowEval.
     32        * page/ContentSecurityPolicy.cpp:
     33        (CSPDirectiveList):
     34        (WebCore::CSPDirectiveList::reportViolation):
     35        (WebCore::CSPDirectiveList::checkEvalAndReportViolation):
     36        (WebCore::CSPDirectiveList::allowEval):
     37            No longer piping a stack trace through CSPDirectiveList::allowEval
     38            to reportViolation.
     39        (WebCore::ContentSecurityPolicy::didReceiveHeader):
     40            Dropping stack trace from call to ContentSecurityPolicy::allowEval.
     41        (WebCore):
     42        (WebCore::isAllowedByAll):
     43        (WebCore::ContentSecurityPolicy::allowEval):
     44        (WebCore::ContentSecurityPolicy::reportViolation):
     45        (WebCore::ContentSecurityPolicy::logToConsole):
     46            No longer piping a stack trace through ContentSecurityPolicy down to
     47            the point where it would be logged. Instead, we simply generate the
     48            stack trace just before logging it, and only pass it to
     49            addConsoleMessage if it's non-empty.
     50        * page/ContentSecurityPolicy.h:
     51        (WebCore):
     52        * page/DOMSecurityPolicy.cpp:
     53        (WebCore::DOMSecurityPolicy::allowsEval):
     54            Dropping stack trace from call to ContentSecurityPolicy::allowEval.
     55
    1562012-08-27  Andrey Kosyakov  <caseq@chromium.org>
    257
  • trunk/Source/WebCore/bindings/js/ScheduledAction.cpp

    r121381 r126852  
    5656    CallData callData;
    5757    if (getCallData(v, callData) == CallTypeNone) {
    58         RefPtr<ScriptCallStack> callStack(createScriptCallStackForInspector(exec));
    59         if (policy && !policy->allowEval(callStack.release()))
     58        if (policy && !policy->allowEval())
    6059            return nullptr;
    6160        UString string = v.toString(exec)->value(exec);
  • trunk/Source/WebCore/bindings/js/ScriptController.cpp

    r126837 r126852  
    223223
    224224    if (m_frame->document())
    225         windowShell->window()->setEvalEnabled(m_frame->document()->contentSecurityPolicy()->allowEval(0, ContentSecurityPolicy::SuppressReport));   
     225        windowShell->window()->setEvalEnabled(m_frame->document()->contentSecurityPolicy()->allowEval(ContentSecurityPolicy::SuppressReport));
    226226
    227227    if (Page* page = m_frame->page()) {
  • trunk/Source/WebCore/bindings/v8/V8DOMWindowShell.cpp

    r126829 r126852  
    321321
    322322    if (m_frame->document())
    323         context->AllowCodeGenerationFromStrings(m_frame->document()->contentSecurityPolicy()->allowEval(0, ContentSecurityPolicy::SuppressReport));
     323        context->AllowCodeGenerationFromStrings(m_frame->document()->contentSecurityPolicy()->allowEval(ContentSecurityPolicy::SuppressReport));
    324324
    325325    m_frame->loader()->client()->didCreateScriptContext(m_context.get(), 0, 0);
  • trunk/Source/WebCore/bindings/v8/custom/V8DOMWindowCustom.cpp

    r126363 r126852  
    129129        id = DOMTimer::install(scriptContext, action.release(), timeout, singleShot);
    130130    } else {
    131         RefPtr<ScriptCallStack> callStack(createScriptCallStackForInspector());
    132         if (imp->document() && !imp->document()->contentSecurityPolicy()->allowEval(callStack.release()))
     131        if (imp->document() && !imp->document()->contentSecurityPolicy()->allowEval())
    133132            return v8Integer(0, args.GetIsolate());
    134133        ASSERT(imp->frame());
  • trunk/Source/WebCore/page/ContentSecurityPolicy.cpp

    r126785 r126852  
    3939#include "SchemeRegistry.h"
    4040#include "ScriptCallStack.h"
     41#include "ScriptCallStackFactory.h"
    4142#include "SecurityOrigin.h"
    4243#include "TextEncoding.h"
     
    711712    bool allowInlineScript(const String& contextURL, const WTF::OrdinalNumber& contextLine, ContentSecurityPolicy::ReportingStatus) const;
    712713    bool allowInlineStyle(const String& contextURL, const WTF::OrdinalNumber& contextLine, ContentSecurityPolicy::ReportingStatus) const;
    713     bool allowEval(PassRefPtr<ScriptCallStack>, ContentSecurityPolicy::ReportingStatus) const;
     714    bool allowEval(ContentSecurityPolicy::ReportingStatus) const;
    714715    bool allowScriptNonce(const String& nonce, const String& contextURL, const WTF::OrdinalNumber& contextLine, const KURL&) const;
    715716    bool allowPluginType(const String& type, const String& typeAttribute, const KURL&, ContentSecurityPolicy::ReportingStatus) const;
     
    743744
    744745    SourceListDirective* operativeDirective(SourceListDirective*) const;
    745     void reportViolation(const String& directiveText, const String& consoleMessage, const KURL& blockedURL = KURL(), const String& contextURL = String(), const WTF::OrdinalNumber& contextLine = WTF::OrdinalNumber::beforeFirst(), PassRefPtr<ScriptCallStack> = 0) const;
     746    void reportViolation(const String& directiveText, const String& consoleMessage, const KURL& blockedURL = KURL(), const String& contextURL = String(), const WTF::OrdinalNumber& contextLine = WTF::OrdinalNumber::beforeFirst()) const;
    746747
    747748    bool checkEval(SourceListDirective*) const;
     
    751752    bool checkMediaType(MediaListDirective*, const String& type, const String& typeAttribute) const;
    752753
    753     bool checkEvalAndReportViolation(SourceListDirective*, const String& consoleMessage, const String& contextURL = String(), const WTF::OrdinalNumber& contextLine = WTF::OrdinalNumber::beforeFirst(), PassRefPtr<ScriptCallStack> = 0) const;
     754    bool checkEvalAndReportViolation(SourceListDirective*, const String& consoleMessage, const String& contextURL = String(), const WTF::OrdinalNumber& contextLine = WTF::OrdinalNumber::beforeFirst()) const;
    754755    bool checkInlineAndReportViolation(SourceListDirective*, const String& consoleMessage, const String& contextURL, const WTF::OrdinalNumber& contextLine) const;
    755756    bool checkNonceAndReportViolation(NonceDirective*, const String& nonce, const String& consoleMessage, const String& contextURL, const WTF::OrdinalNumber& contextLine) const;
     
    806807}
    807808
    808 void CSPDirectiveList::reportViolation(const String& directiveText, const String& consoleMessage, const KURL& blockedURL, const String& contextURL, const WTF::OrdinalNumber& contextLine, PassRefPtr<ScriptCallStack> callStack) const
     809void CSPDirectiveList::reportViolation(const String& directiveText, const String& consoleMessage, const KURL& blockedURL, const String& contextURL, const WTF::OrdinalNumber& contextLine) const
    809810{
    810811    String message = m_reportOnly ? "[Report Only] " + consoleMessage : consoleMessage;
    811     m_policy->reportViolation(directiveText, message, blockedURL, m_reportURIs, m_header, contextURL, contextLine, callStack);
     812    m_policy->reportViolation(directiveText, message, blockedURL, m_reportURIs, m_header, contextURL, contextLine);
    812813}
    813814
     
    846847}
    847848
    848 bool CSPDirectiveList::checkEvalAndReportViolation(SourceListDirective* directive, const String& consoleMessage, const String& contextURL, const WTF::OrdinalNumber& contextLine, PassRefPtr<ScriptCallStack> callStack) const
     849bool CSPDirectiveList::checkEvalAndReportViolation(SourceListDirective* directive, const String& consoleMessage, const String& contextURL, const WTF::OrdinalNumber& contextLine) const
    849850{
    850851    if (checkEval(directive))
    851852        return true;
    852     reportViolation(directive->text(), consoleMessage + "\"" + directive->text() + "\".\n", KURL(), contextURL, contextLine, callStack);
     853    reportViolation(directive->text(), consoleMessage + "\"" + directive->text() + "\".\n", KURL(), contextURL, contextLine);
    853854    return denyIfEnforcingPolicy();
    854855}
     
    938939}
    939940
    940 bool CSPDirectiveList::allowEval(PassRefPtr<ScriptCallStack> callStack, ContentSecurityPolicy::ReportingStatus reportingStatus) const
     941bool CSPDirectiveList::allowEval(ContentSecurityPolicy::ReportingStatus reportingStatus) const
    941942{
    942943    DEFINE_STATIC_LOCAL(String, consoleMessage, ("Refused to evaluate script because it violates the following Content Security Policy directive: "));
    943944    return reportingStatus == ContentSecurityPolicy::SendReport ?
    944         checkEvalAndReportViolation(operativeDirective(m_scriptSrc.get()), consoleMessage, String(), WTF::OrdinalNumber::beforeFirst(), callStack) :
     945        checkEvalAndReportViolation(operativeDirective(m_scriptSrc.get()), consoleMessage, String(), WTF::OrdinalNumber::beforeFirst()) :
    945946        checkEval(operativeDirective(m_scriptSrc.get()));
    946947}
     
    12581259    }
    12591260
    1260     if (!allowEval(0, SuppressReport))
     1261    if (!allowEval(SuppressReport))
    12611262        m_scriptExecutionContext->disableEval();
    12621263}
     
    12771278}
    12781279
    1279 template<bool (CSPDirectiveList::*allowed)(PassRefPtr<ScriptCallStack>, ContentSecurityPolicy::ReportingStatus) const>
    1280 bool isAllowedByAllWithCallStack(const CSPDirectiveListVector& policies, PassRefPtr<ScriptCallStack> callStack, ContentSecurityPolicy::ReportingStatus reportingStatus)
     1280template<bool (CSPDirectiveList::*allowed)( ContentSecurityPolicy::ReportingStatus) const>
     1281bool isAllowedByAll(const CSPDirectiveListVector& policies, ContentSecurityPolicy::ReportingStatus reportingStatus)
    12811282{
    12821283    for (size_t i = 0; i < policies.size(); ++i) {
    1283         if (!(policies[i].get()->*allowed)(callStack, reportingStatus))
     1284        if (!(policies[i].get()->*allowed)(reportingStatus))
    12841285            return false;
    12851286    }
     
    13421343}
    13431344
    1344 bool ContentSecurityPolicy::allowEval(PassRefPtr<ScriptCallStack> callStack, ContentSecurityPolicy::ReportingStatus reportingStatus) const
    1345 {
    1346     return isAllowedByAllWithCallStack<&CSPDirectiveList::allowEval>(m_policies, callStack, reportingStatus);
     1345bool ContentSecurityPolicy::allowEval(ContentSecurityPolicy::ReportingStatus reportingStatus) const
     1346{
     1347    return isAllowedByAll<&CSPDirectiveList::allowEval>(m_policies, reportingStatus);
    13471348}
    13481349
     
    14371438}
    14381439
    1439 void ContentSecurityPolicy::reportViolation(const String& directiveText, const String& consoleMessage, const KURL& blockedURL, const Vector<KURL>& reportURIs, const String& header, const String& contextURL, const WTF::OrdinalNumber& contextLine, PassRefPtr<ScriptCallStack> callStack) const
    1440 {
    1441     logToConsole(consoleMessage, contextURL, contextLine, callStack);
     1440void ContentSecurityPolicy::reportViolation(const String& directiveText, const String& consoleMessage, const KURL& blockedURL, const Vector<KURL>& reportURIs, const String& header, const String& contextURL, const WTF::OrdinalNumber& contextLine) const
     1441{
     1442    logToConsole(consoleMessage, contextURL, contextLine);
    14421443
    14431444    if (reportURIs.isEmpty())
     
    15231524}
    15241525
    1525 void ContentSecurityPolicy::logToConsole(const String& message, const String& contextURL, const WTF::OrdinalNumber& contextLine, PassRefPtr<ScriptCallStack> callStack) const
    1526 {
    1527     m_scriptExecutionContext->addConsoleMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, message, contextURL, contextLine.oneBasedInt(), callStack);
    1528 }
    1529 
    1530 }
     1526void ContentSecurityPolicy::logToConsole(const String& message, const String& contextURL, const WTF::OrdinalNumber& contextLine) const
     1527{
     1528    RefPtr<ScriptCallStack> callStack;
     1529    if (InspectorInstrumentation::hasFrontends())
     1530        callStack = createScriptCallStack(ScriptCallStack::maxCallStackSizeToCapture, true);
     1531    m_scriptExecutionContext->addConsoleMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, message, contextURL, contextLine.oneBasedInt(), (callStack && callStack->size() > 0) ? callStack : 0);
     1532}
     1533
     1534}
  • trunk/Source/WebCore/page/ContentSecurityPolicy.h

    r125772 r126852  
    4141
    4242class CSPDirectiveList;
    43 class ScriptCallStack;
    4443class DOMStringList;
    4544class ScriptExecutionContext;
     
    8079    bool allowInlineScript(const String& contextURL, const WTF::OrdinalNumber& contextLine, ReportingStatus = SendReport) const;
    8180    bool allowInlineStyle(const String& contextURL, const WTF::OrdinalNumber& contextLine, ReportingStatus = SendReport) const;
    82     bool allowEval(PassRefPtr<ScriptCallStack>, ReportingStatus = SendReport) const;
     81    bool allowEval(ReportingStatus = SendReport) const;
    8382    bool allowScriptNonce(const String& nonce, const String& contextURL, const WTF::OrdinalNumber& contextLine, const KURL& = KURL()) const;
    8483    bool allowPluginType(const String& type, const String& typeAttribute, const KURL&, ReportingStatus = SendReport) const;
     
    105104    void reportInvalidSourceExpression(const String& directiveName, const String& source) const;
    106105    void reportUnrecognizedDirective(const String&) const;
    107     void reportViolation(const String& directiveText, const String& consoleMessage, const KURL& blockedURL, const Vector<KURL>& reportURIs, const String& header, const String& contextURL = String(), const WTF::OrdinalNumber& contextLine = WTF::OrdinalNumber::beforeFirst(), PassRefPtr<ScriptCallStack> = 0) const;
     106    void reportViolation(const String& directiveText, const String& consoleMessage, const KURL& blockedURL, const Vector<KURL>& reportURIs, const String& header, const String& contextURL = String(), const WTF::OrdinalNumber& contextLine = WTF::OrdinalNumber::beforeFirst()) const;
    108107
    109108    const KURL& url() const;
     
    115114    explicit ContentSecurityPolicy(ScriptExecutionContext*);
    116115
    117     void logToConsole(const String& message, const String& contextURL = String(), const WTF::OrdinalNumber& contextLine = WTF::OrdinalNumber::beforeFirst(), PassRefPtr<ScriptCallStack> = 0) const;
     116    void logToConsole(const String& message, const String& contextURL = String(), const WTF::OrdinalNumber& contextLine = WTF::OrdinalNumber::beforeFirst()) const;
    118117
    119118    ScriptExecutionContext* m_scriptExecutionContext;
  • trunk/Source/WebCore/page/DOMSecurityPolicy.cpp

    r125983 r126852  
    121121        return true;
    122122
    123     return scriptExecutionContext()->contentSecurityPolicy()->allowEval(0, ContentSecurityPolicy::SuppressReport);
     123    return scriptExecutionContext()->contentSecurityPolicy()->allowEval(ContentSecurityPolicy::SuppressReport);
    124124}
    125125
Note: See TracChangeset for help on using the changeset viewer.