Changeset 294017 in webkit for trunk/Source/JavaScriptCore/tools/Integrity.cpp
- Timestamp:
- May 10, 2022, 2:55:45 PM (3 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/tools/Integrity.cpp
r288815 r294017 1 1 /* 2 * Copyright (C) 2019-202 1Apple Inc. All rights reserved.2 * Copyright (C) 2019-2022 Apple Inc. All rights reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 27 27 #include "Integrity.h" 28 28 29 #include "APICast.h" 30 #include "CellSize.h" 31 #include "IntegrityInlines.h" 32 #include "JSCast.h" 29 33 #include "JSCellInlines.h" 34 #include "JSGlobalObject.h" 30 35 #include "Options.h" 31 36 #include "VMInspectorInlines.h" … … 34 39 namespace Integrity { 35 40 36 namespace {37 constexpr bool verbose = false;41 namespace IntegrityInternal { 42 static constexpr bool verbose = false; 38 43 } 39 44 … … 49 54 if (!Options::randomIntegrityAuditRate()) { 50 55 m_triggerBits = 0; // Never trigger, and don't bother reloading. 51 if ( verbose)56 if (IntegrityInternal::verbose) 52 57 dataLogLn("disabled Integrity audits: trigger bits ", RawPointer(reinterpret_cast<void*>(m_triggerBits))); 53 58 return false; … … 62 67 m_triggerBits = m_triggerBits | (static_cast<uint64_t>(trigger) << i); 63 68 } 64 if ( verbose)69 if (IntegrityInternal::verbose) 65 70 dataLogLn("reloaded Integrity trigger bits ", RawPointer(reinterpret_cast<void*>(m_triggerBits))); 66 71 ASSERT(m_triggerBits >= (1ull << 63)); … … 68 73 } 69 74 70 void auditCellFully(VM& vm, JSCell* cell)71 {72 VMInspector::verifyCell<VMInspector::ReleaseAssert>(vm, cell);73 }74 75 75 void auditCellMinimallySlow(VM&, JSCell* cell) 76 76 { 77 77 if (Gigacage::contains(cell)) { 78 78 if (cell->type() != JSImmutableButterflyType) { 79 if ( verbose)80 dataLogLn(" Bad cell ", RawPointer(cell), " ", JSValue(cell));79 if (IntegrityInternal::verbose) 80 dataLogLn("Integrity ERROR: Bad cell ", RawPointer(cell), " ", JSValue(cell)); 81 81 CRASH(); 82 82 } … … 84 84 } 85 85 86 #if USE(JSVALUE64) 87 88 JSContextRef doAudit(JSContextRef ctx) 89 { 90 IA_ASSERT(ctx, "NULL JSContextRef"); 91 toJS(ctx); // toJS will trigger an audit. 92 return ctx; 93 } 94 95 JSGlobalContextRef doAudit(JSGlobalContextRef ctx) 96 { 97 IA_ASSERT(ctx, "NULL JSGlobalContextRef"); 98 toJS(ctx); // toJS will trigger an audit. 99 return ctx; 100 } 101 102 JSObjectRef doAudit(JSObjectRef objectRef) 103 { 104 if (!objectRef) 105 return objectRef; 106 toJS(objectRef); // toJS will trigger an audit. 107 return objectRef; 108 } 109 110 JSValueRef doAudit(JSValueRef valueRef) 111 { 112 #if CPU(ADDRESS64) 113 if (!valueRef) 114 return valueRef; 115 toJS(valueRef); // toJS will trigger an audit. 116 #endif 117 return valueRef; 118 } 119 120 JSValue doAudit(JSValue value) 121 { 122 if (value.isCell()) 123 doAudit(value.asCell()); 124 return value; 125 } 126 127 bool Analyzer::analyzeVM(VM& vm, Analyzer::Action action) 128 { 129 IA_ASSERT_WITH_ACTION(VMInspector::isValidVM(&vm), { 130 VMInspector::dumpVMs(); 131 if (action == Action::LogAndCrash) 132 RELEASE_ASSERT(VMInspector::isValidVM(&vm)); 133 else 134 return false; 135 }, "Invalid VM %p", &vm); 136 return true; 137 } 138 139 #if COMPILER(MSVC) || !VA_OPT_SUPPORTED 140 141 #define AUDIT_VERIFY(cond, format, ...) do { \ 142 IA_ASSERT_WITH_ACTION(cond, { \ 143 WTFLogAlways(" cell %p", cell); \ 144 if (action == Action::LogAndCrash) \ 145 RELEASE_ASSERT((cond), ##__VA_ARGS__); \ 146 else \ 147 return false; \ 148 }, format, ##__VA_ARGS__); \ 149 } while (false) 150 151 #else // not (COMPILER(MSVC) || !VA_OPT_SUPPORTED) 152 153 #define AUDIT_VERIFY(cond, format, ...) do { \ 154 IA_ASSERT_WITH_ACTION(cond, { \ 155 WTFLogAlways(" cell %p", cell); \ 156 if (action == Action::LogAndCrash) \ 157 RELEASE_ASSERT((cond) __VA_OPT__(,) __VA_ARGS__); \ 158 else \ 159 return false; \ 160 }, format __VA_OPT__(,) __VA_ARGS__); \ 161 } while (false) 162 163 #endif // COMPILER(MSVC) || !VA_OPT_SUPPORTED 164 165 bool Analyzer::analyzeCell(VM& vm, JSCell* cell, Analyzer::Action action) 166 { 167 AUDIT_VERIFY(isSanePointer(cell), "cell %p cell.type %d", cell, cell->type()); 168 169 size_t allocatorCellSize = 0; 170 if (cell->isPreciseAllocation()) { 171 PreciseAllocation& preciseAllocation = cell->preciseAllocation(); 172 AUDIT_VERIFY(&preciseAllocation.vm() == &vm, 173 "cell %p cell.type %d preciseAllocation.vm %p vm %p", cell, cell->type(), &preciseAllocation.vm(), &vm); 174 175 bool isValidPreciseAllocation = false; 176 for (auto* i : vm.heap.objectSpace().preciseAllocations()) { 177 if (i == &preciseAllocation) { 178 isValidPreciseAllocation = true; 179 break; 180 } 181 } 182 AUDIT_VERIFY(isValidPreciseAllocation, "cell %p cell.type %d", cell, cell->type()); 183 184 allocatorCellSize = preciseAllocation.cellSize(); 185 } else { 186 MarkedBlock& block = cell->markedBlock(); 187 MarkedBlock::Handle& blockHandle = block.handle(); 188 AUDIT_VERIFY(&block.vm() == &vm, 189 "cell %p cell.type %d markedBlock.vm %p vm %p", cell, cell->type(), &block.vm(), &vm); 190 191 uintptr_t blockStartAddress = reinterpret_cast<uintptr_t>(blockHandle.start()); 192 AUDIT_VERIFY(blockHandle.contains(cell), 193 "cell %p cell.type %d markedBlock.start %p markedBlock.end %p", cell, cell->type(), blockHandle.start(), blockHandle.end()); 194 195 uintptr_t cellAddress = reinterpret_cast<uintptr_t>(cell); 196 uintptr_t cellOffset = cellAddress - blockStartAddress; 197 allocatorCellSize = block.cellSize(); 198 bool cellIsProperlyAligned = !(cellOffset % allocatorCellSize); 199 AUDIT_VERIFY(cellIsProperlyAligned, 200 "cell %p cell.type %d allocator.cellSize %zu", cell, cell->type(), allocatorCellSize); 201 } 202 203 JSType cellType = cell->type(); 204 if (cell->type() != JSImmutableButterflyType) 205 AUDIT_VERIFY(!Gigacage::contains(cell), "cell %p cell.type %d", cell, cellType); 206 207 WeakSet& weakSet = cell->cellContainer().weakSet(); 208 AUDIT_VERIFY(!weakSet.m_allocator || isSanePointer(weakSet.m_allocator), 209 "cell %p cell.type %d weakSet.allocator %p", cell, cell->type(), weakSet.m_allocator); 210 AUDIT_VERIFY(!weakSet.m_nextAllocator || isSanePointer(weakSet.m_nextAllocator), 211 "cell %p cell.type %d weakSet.allocator %p", cell, cell->type(), weakSet.m_nextAllocator); 212 213 // If we're currently destructing the cell, then we can't rely on its 214 // structure being good. Skip the following tests which rely on structure. 215 if (vm.currentlyDestructingCallbackObject == cell) 216 return true; 217 218 auto structureID = cell->structureID(); 219 220 Structure* structure = structureID.tryDecode(); 221 AUDIT_VERIFY(structure, 222 "cell %p cell.type %d structureID.bits 0x%x", cell, cellType, structureID.bits()); 223 if (action == Analyzer::Action::LogAndCrash) { 224 // structure should be pointing to readable memory. Force a read. 225 WTF::opaque(*bitwise_cast<uintptr_t*>(structure)); 226 } 227 228 const ClassInfo* classInfo = structure->classInfoForCells(); 229 AUDIT_VERIFY(cellType == structure->m_blob.type(), 230 "cell %p cell.type %d structureBlob.type %d", cell, cellType, structure->m_blob.type()); 231 232 size_t size = cellSize(cell); 233 AUDIT_VERIFY(size <= allocatorCellSize, 234 "cell %p cell.type %d cell.size %zu allocator.cellSize %zu, classInfo.cellSize %u", cell, cellType, size, allocatorCellSize, classInfo->staticClassSize); 235 if (isDynamicallySizedType(cellType)) { 236 AUDIT_VERIFY(size >= classInfo->staticClassSize, 237 "cell %p cell.type %d cell.size %zu classInfo.cellSize %u", cell, cellType, size, classInfo->staticClassSize); 238 } 239 240 if (cell->isObject()) { 241 AUDIT_VERIFY(jsDynamicCast<JSObject*>(cell), 242 "cell %p cell.type %d", cell, cell->type()); 243 244 if (Gigacage::isEnabled(Gigacage::JSValue)) { 245 JSObject* object = bitwise_cast<JSObject*>(cell); 246 const Butterfly* butterfly = object->butterfly(); 247 AUDIT_VERIFY(!butterfly || Gigacage::isCaged(Gigacage::JSValue, butterfly), 248 "cell %p cell.type %d butterfly %p", cell, cell->type(), butterfly); 249 } 250 } 251 252 return true; 253 } 254 255 bool Analyzer::analyzeCell(JSCell* cell, Analyzer::Action action) 256 { 257 if (!cell) 258 return cell; 259 260 JSValue value = JSValue::decode(static_cast<EncodedJSValue>(bitwise_cast<uintptr_t>(cell))); 261 AUDIT_VERIFY(value.isCell(), "Invalid cell address: cell %p", cell); 262 263 VM& vm = cell->vm(); 264 analyzeVM(vm, action); 265 return analyzeCell(vm, cell, action); 266 } 267 268 #undef AUDIT_VERIFY 269 270 VM* doAuditSlow(VM* vm) 271 { 272 Analyzer::analyzeVM(*vm, Analyzer::Action::LogAndCrash); 273 return vm; 274 } 275 276 JSCell* doAudit(JSCell* cell) 277 { 278 Analyzer::analyzeCell(cell, Analyzer::Action::LogAndCrash); 279 return cell; 280 } 281 282 JSCell* doAudit(VM& vm, JSCell* cell) 283 { 284 if (!cell) 285 return cell; 286 Analyzer::analyzeCell(vm, cell, Analyzer::Action::LogAndCrash); 287 return cell; 288 } 289 290 bool verifyCell(JSCell* cell) 291 { 292 bool valid = Analyzer::analyzeCell(cell, Analyzer::Action::LogOnly); 293 WTFLogAlways("Cell %p is %s", cell, valid ? "VALID" : "INVALID"); 294 return valid; 295 } 296 297 bool verifyCell(VM& vm, JSCell* cell) 298 { 299 bool valid = Analyzer::analyzeCell(vm, cell, Analyzer::Action::LogOnly); 300 WTFLogAlways("Cell %p is %s", cell, valid ? "VALID" : "INVALID"); 301 return valid; 302 } 303 304 JSObject* doAudit(JSObject* object) 305 { 306 if (!object) 307 return object; 308 JSCell* cell = doAudit(reinterpret_cast<JSCell*>(object)); 309 IA_ASSERT(cell->isObject(), "Invalid JSObject %p", object); 310 return object; 311 } 312 313 JSGlobalObject* doAudit(JSGlobalObject* globalObject) 314 { 315 doAudit(reinterpret_cast<JSCell*>(globalObject)); 316 IA_ASSERT(globalObject->isGlobalObject(), "Invalid JSGlobalObject %p", globalObject); 317 return globalObject; 318 } 319 320 #endif // USE(JSVALUE64) 321 86 322 } // namespace Integrity 87 323 } // namespace JSC
Note:
See TracChangeset
for help on using the changeset viewer.