source: webkit/trunk/Source/JavaScriptCore/tools/IntegrityInlines.h

Last change on this file was 294017, checked in by [email protected], 3 years ago

Add optional Integrity checks at JSC API boundaries.
https://bugs.webkit.org/show_bug.cgi?id=240264

Reviewed by Yusuke Suzuki.

  1. Defined ENABLE_EXTRA_INTEGRITY_CHECKS in Integrity.h. JSC developers can enable this for their local build if they want to enable more prolific Integrity audits. This is disabled by default.

This feature is currently only supported for USE(JSVALUE64) targets.

The following changes only take effect if ENABLE(EXTRA_INTEGRITY_CHECKS) is enabled.
Otherwise, these are no-ops.

  1. Added Integrity audits to all toJS and toRef conversion functions in APICast.h. This will help us detect if bad values are passed across the API boundary.
  1. Added some Integrity audits in JSValue.mm where the APICast ones were insufficient.

The following changes are in effect even when ENABLE(EXTRA_INTEGRITY_CHECKS) is
disabled. Some of these were made to support ENABLE(EXTRA_INTEGRITY_CHECKS), and
some are just clean up in related code that I had to touch along the way.

  1. Moved isSanePointer() to Integrity.h so that it can be used in more places.
  1. Changed VM registration with the VMInspector so that it's registered earlier and removed later. Integrity audits may need to audit VM pointers while the VM is being constructed and destructed.
  1. Added VM::m_isInService to track when the VM is fully constructed or about to be destructed since the VM is now registered with the VMInspector differently (see (4) above). Applied this check in places that need it.
  1. Fixed VMInspector::isValidExecutableMemory() to check the ExecutableAllocator directly without iterating VMs (which is completely unnecessary).
  1. Fixed VMInspector::isValidExecutableMemory() and VMInspector::codeBlockForMachinePC() to use AdoptLock. This fixes a race condition where the lock can be contended after ensureIsSafeToLock() succeeds.
  1. Added VMInspector::isValidVM() to check if a VM pointer is registered or not. VMInspector caches the most recently added or found VM so that isValidVM() can just check the cache for its fast path.
  1. Moved the implementation of VMInspector::verifyCell() to Integrity::analyzeCell()

and add more checks to it. VMInspector::verifyCell() now calls Integrity::verifyCell()
which uses Integrity::analyzeCell() to do the real cell analysis.

  1. Also strengten Integrity::auditStructureID() so that it will check if a

Structure's memory has been released. This change is enabled on Debug builds
by default as well as when ENABLE(EXTRA_INTEGRITY_CHECKS). It is disabled
on Release builds.

  • API/APICast.h:

(toJS):
(toJSForGC):
(uncheckedToJS):
(toRef):
(toGlobalRef):

  • API/JSContext.mm:
  • API/JSContextRef.cpp:
  • API/JSScript.mm:
  • API/JSValue.mm:

(ObjcContainerConvertor::convert):
(objectToValueWithoutCopy):
(objectToValue):

  • API/JSVirtualMachine.mm:
  • API/JSWeakPrivate.cpp:
  • API/glib/JSCContext.cpp:
  • API/glib/JSCWrapperMap.cpp:
  • API/tests/JSObjectGetProxyTargetTest.cpp:
  • bytecode/SpeculatedType.cpp:

(JSC::speculationFromCell):
(JSC::isSanePointer): Deleted.

  • heap/HeapFinalizerCallback.cpp:
  • heap/WeakSet.h:
  • runtime/Structure.h:
  • runtime/VM.cpp:

(JSC::VM::VM):
(JSC::VM::~VM):

  • runtime/VM.h:

(JSC::VM::isInService const):

  • tools/HeapVerifier.cpp:

(JSC::HeapVerifier::checkIfRecorded):

  • tools/Integrity.cpp:

(JSC::Integrity::Random::reloadAndCheckShouldAuditSlow):
(JSC::Integrity::auditCellMinimallySlow):
(JSC::Integrity::doAudit):
(JSC::Integrity::Analyzer::analyzeVM):
(JSC::Integrity::Analyzer::analyzeCell):
(JSC::Integrity::doAuditSlow):
(JSC::Integrity::verifyCell):
(): Deleted.
(JSC::Integrity::auditCellFully): Deleted.

  • tools/Integrity.h:

(JSC::isSanePointer):
(JSC::Integrity::auditCell):
(JSC::Integrity::audit):

  • tools/IntegrityInlines.h:

(JSC::Integrity::auditCell):
(JSC::Integrity::auditCellFully):
(JSC::Integrity::auditStructureID):
(JSC::Integrity::doAudit):

  • tools/VMInspector.cpp:

(JSC::VMInspector::add):
(JSC::VMInspector::remove):
(JSC::VMInspector::isValidVMSlow):
(JSC::VMInspector::dumpVMs):
(JSC::VMInspector::isValidExecutableMemory):
(JSC::VMInspector::codeBlockForMachinePC):
(JSC::ensureIsSafeToLock): Deleted.

  • tools/VMInspector.h:

(JSC::VMInspector::isValidVM):
(): Deleted.
(JSC::VMInspector::unusedVerifier): Deleted.

  • tools/VMInspectorInlines.h:

(JSC::VMInspector::verifyCell):
(JSC::VMInspector::verifyCellSize): Deleted.

File size: 4.2 KB
Line 
1/*
2 * Copyright (C) 2019-2022 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#pragma once
27
28#include "Integrity.h"
29#include "JSCJSValue.h"
30#include "StructureID.h"
31#include "VM.h"
32#include "VMInspector.h"
33#include <wtf/Atomics.h>
34#include <wtf/Gigacage.h>
35
36namespace JSC {
37namespace Integrity {
38
39ALWAYS_INLINE bool Random::shouldAudit(VM& vm)
40{
41 // If auditing is enabled, then the top bit of m_triggerBits is always set
42 // to 1 on reload. When this top bit reaches the bottom, it does not
43 // indicate that we should trigger an audit but rather that we've shifted
44 // out all the available trigger bits and hence, need to reload. Instead,
45 // reloadAndCheckShouldAuditSlow() will return whether we actually need to
46 // trigger an audit this turn.
47 //
48 // This function can be called concurrently from different threads and can
49 // be racy. For that reason, we intentionally do not write back to
50 // m_triggerBits if newTriggerBits is null. This ensures that if
51 // Options::randomIntegrityAuditRate() is non-zero, then m_triggerBits will
52 // always have at least 1 bit to trigger a reload.
53
54 uint64_t newTriggerBits = m_triggerBits;
55 bool shouldAudit = newTriggerBits & 1;
56 newTriggerBits = newTriggerBits >> 1;
57 if (LIKELY(!shouldAudit)) {
58 m_triggerBits = newTriggerBits;
59 return false;
60 }
61
62 if (!newTriggerBits)
63 return reloadAndCheckShouldAuditSlow(vm);
64
65 m_triggerBits = newTriggerBits;
66 return true;
67}
68
69template<AuditLevel auditLevel>
70ALWAYS_INLINE void auditCell(VM& vm, JSValue value)
71{
72 if constexpr (auditLevel == AuditLevel::None)
73 return;
74
75 if (value.isCell())
76 auditCell<auditLevel>(vm, value.asCell());
77}
78
79ALWAYS_INLINE void auditCellMinimally(VM& vm, JSCell* cell)
80{
81 if (UNLIKELY(Gigacage::contains(cell)))
82 auditCellMinimallySlow(vm, cell);
83}
84
85ALWAYS_INLINE void auditCellRandomly(VM& vm, JSCell* cell)
86{
87 if (UNLIKELY(vm.integrityRandom().shouldAudit(vm)))
88 auditCellFully(vm, cell);
89}
90
91ALWAYS_INLINE void auditCellFully(VM& vm, JSCell* cell)
92{
93#if USE(JSVALUE64)
94 doAudit(vm, cell);
95#else
96 auditCellMinimally(vm, cell);
97#endif
98}
99
100ALWAYS_INLINE void auditStructureID(StructureID structureID)
101{
102 UNUSED_PARAM(structureID);
103#if CPU(ADDRESS64) && !ENABLE(STRUCTURE_ID_WITH_SHIFT)
104 ASSERT(static_cast<uintptr_t>(structureID.bits()) <= structureHeapAddressSize + StructureID::nukedStructureIDBit);
105#endif
106#if ENABLE(EXTRA_INTEGRITY_CHECKS) || ASSERT_ENABLED
107 Structure* structure = structureID.tryDecode();
108 IA_ASSERT(structure, "structureID.bits 0x%x", structureID.bits());
109 // structure should be pointing to readable memory. Force a read.
110 WTF::opaque(*bitwise_cast<uintptr_t*>(structure));
111#endif
112}
113
114#if USE(JSVALUE64)
115
116JS_EXPORT_PRIVATE VM* doAuditSlow(VM*);
117
118ALWAYS_INLINE VM* doAudit(VM* vm)
119{
120 if (UNLIKELY(!VMInspector::isValidVM(vm)))
121 return doAuditSlow(vm);
122 return vm;
123}
124
125#endif // USE(JSVALUE64)
126
127} // namespace Integrity
128} // namespace JSC
Note: See TracBrowser for help on using the repository browser.