1/*
2 * Copyright (C) 2019 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 "VM.h"
30
31namespace JSC {
32namespace Integrity {
33
34ALWAYS_INLINE bool Random::shouldAudit(VM& vm)
35{
36 // If auditing is enabled, then the top bit of m_triggerBits is always set
37 // to 1 on reload. When this top bit reaches the bottom, it does not
38 // indicate that we should trigger an audit but rather that we've shifted
39 // out all the available trigger bits and hence, need to reload. Instead,
40 // reloadAndCheckShouldAuditSlow() will return whether we actually need to
41 // trigger an audit this turn.
42 //
43 // This function can be called concurrently from different threads and can
44 // be racy. For that reason, we intentionally do not write back to
45 // m_triggerBits if newTriggerBits is null. This ensures that if
46 // Options::randomIntegrityAuditRate() is non-zero, then m_triggerBits will
47 // always have at least 1 bit to trigger a reload.
48
49 uint64_t newTriggerBits = m_triggerBits;
50 bool shouldAudit = newTriggerBits & 1;
51 newTriggerBits = newTriggerBits >> 1;
52 if (LIKELY(!shouldAudit)) {
53 m_triggerBits = newTriggerBits;
54 return false;
55 }
56
57 if (!newTriggerBits)
58 return reloadAndCheckShouldAuditSlow(vm);
59
60 m_triggerBits = newTriggerBits;
61 return true;
62}
63
64ALWAYS_INLINE void auditCellMinimally(VM& vm, JSCell* cell)
65{
66 if (UNLIKELY(Gigacage::contains(cell)))
67 auditCellMinimallySlow(vm, cell);
68}
69
70ALWAYS_INLINE void auditCellRandomly(VM& vm, JSCell* cell)
71{
72 if (UNLIKELY(vm.integrityRandom().shouldAudit(vm)))
73 auditCellFully(vm, cell);
74}
75
76} // namespace Integrity
77} // namespace JSC
78