Tue, 06 Jan 2015 21:39:09 +0100
Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
michael@0 | 1 | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
michael@0 | 2 | /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
michael@0 | 3 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 4 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 5 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 6 | |
michael@0 | 7 | #include "LulDwarfSummariser.h" |
michael@0 | 8 | |
michael@0 | 9 | #include "mozilla/Assertions.h" |
michael@0 | 10 | |
michael@0 | 11 | // Set this to 1 for verbose logging |
michael@0 | 12 | #define DEBUG_SUMMARISER 0 |
michael@0 | 13 | |
michael@0 | 14 | namespace lul { |
michael@0 | 15 | |
michael@0 | 16 | Summariser::Summariser(SecMap* aSecMap, uintptr_t aTextBias, |
michael@0 | 17 | void(*aLog)(const char*)) |
michael@0 | 18 | : mSecMap(aSecMap) |
michael@0 | 19 | , mTextBias(aTextBias) |
michael@0 | 20 | , mLog(aLog) |
michael@0 | 21 | { |
michael@0 | 22 | mCurrAddr = 0; |
michael@0 | 23 | mMax1Addr = 0; // Gives an empty range. |
michael@0 | 24 | |
michael@0 | 25 | // Initialise the running RuleSet to "haven't got a clue" status. |
michael@0 | 26 | new (&mCurrRules) RuleSet(); |
michael@0 | 27 | } |
michael@0 | 28 | |
michael@0 | 29 | void |
michael@0 | 30 | Summariser::Entry(uintptr_t aAddress, uintptr_t aLength) |
michael@0 | 31 | { |
michael@0 | 32 | aAddress += mTextBias; |
michael@0 | 33 | if (DEBUG_SUMMARISER) { |
michael@0 | 34 | char buf[100]; |
michael@0 | 35 | snprintf(buf, sizeof(buf), "LUL Entry(%llx, %llu)\n", |
michael@0 | 36 | (unsigned long long int)aAddress, |
michael@0 | 37 | (unsigned long long int)aLength); |
michael@0 | 38 | buf[sizeof(buf)-1] = 0; |
michael@0 | 39 | mLog(buf); |
michael@0 | 40 | } |
michael@0 | 41 | // This throws away any previous summary, that is, assumes |
michael@0 | 42 | // that the previous summary, if any, has been properly finished |
michael@0 | 43 | // by a call to End(). |
michael@0 | 44 | mCurrAddr = aAddress; |
michael@0 | 45 | mMax1Addr = aAddress + aLength; |
michael@0 | 46 | new (&mCurrRules) RuleSet(); |
michael@0 | 47 | } |
michael@0 | 48 | |
michael@0 | 49 | void |
michael@0 | 50 | Summariser::Rule(uintptr_t aAddress, |
michael@0 | 51 | int aNewReg, int aOldReg, intptr_t aOffset, bool aDeref) |
michael@0 | 52 | { |
michael@0 | 53 | aAddress += mTextBias; |
michael@0 | 54 | if (DEBUG_SUMMARISER) { |
michael@0 | 55 | char buf[100]; |
michael@0 | 56 | snprintf(buf, sizeof(buf), |
michael@0 | 57 | "LUL 0x%llx old-r%d = %sr%d + %ld%s\n", |
michael@0 | 58 | (unsigned long long int)aAddress, aNewReg, |
michael@0 | 59 | aDeref ? "*(" : "", aOldReg, (long)aOffset, aDeref ? ")" : ""); |
michael@0 | 60 | buf[sizeof(buf)-1] = 0; |
michael@0 | 61 | mLog(buf); |
michael@0 | 62 | } |
michael@0 | 63 | if (mCurrAddr < aAddress) { |
michael@0 | 64 | // Flush the existing summary first. |
michael@0 | 65 | mCurrRules.mAddr = mCurrAddr; |
michael@0 | 66 | mCurrRules.mLen = aAddress - mCurrAddr; |
michael@0 | 67 | mSecMap->AddRuleSet(&mCurrRules); |
michael@0 | 68 | if (DEBUG_SUMMARISER) { |
michael@0 | 69 | mLog("LUL "); mCurrRules.Print(mLog); |
michael@0 | 70 | mLog("\n"); |
michael@0 | 71 | } |
michael@0 | 72 | mCurrAddr = aAddress; |
michael@0 | 73 | } |
michael@0 | 74 | |
michael@0 | 75 | // FIXME: factor out common parts of the arch-dependent summarisers. |
michael@0 | 76 | |
michael@0 | 77 | #if defined(LUL_ARCH_arm) |
michael@0 | 78 | |
michael@0 | 79 | // ----------------- arm ----------------- // |
michael@0 | 80 | |
michael@0 | 81 | // Now, can we add the rule to our summary? This depends on whether |
michael@0 | 82 | // the registers and the overall expression are representable. This |
michael@0 | 83 | // is the heart of the summarisation process. |
michael@0 | 84 | switch (aNewReg) { |
michael@0 | 85 | |
michael@0 | 86 | case DW_REG_CFA: |
michael@0 | 87 | // This is a rule that defines the CFA. The only forms we |
michael@0 | 88 | // choose to represent are: r7/11/12/13 + offset. The offset |
michael@0 | 89 | // must fit into 32 bits since 'uintptr_t' is 32 bit on ARM, |
michael@0 | 90 | // hence there is no need to check it for overflow. |
michael@0 | 91 | if (aDeref) { |
michael@0 | 92 | goto cant_summarise; |
michael@0 | 93 | } |
michael@0 | 94 | switch (aOldReg) { |
michael@0 | 95 | case DW_REG_ARM_R7: case DW_REG_ARM_R11: |
michael@0 | 96 | case DW_REG_ARM_R12: case DW_REG_ARM_R13: |
michael@0 | 97 | break; |
michael@0 | 98 | default: |
michael@0 | 99 | goto cant_summarise; |
michael@0 | 100 | } |
michael@0 | 101 | mCurrRules.mCfaExpr = LExpr(LExpr::NODEREF, aOldReg, aOffset); |
michael@0 | 102 | break; |
michael@0 | 103 | |
michael@0 | 104 | case DW_REG_ARM_R7: case DW_REG_ARM_R11: case DW_REG_ARM_R12: |
michael@0 | 105 | case DW_REG_ARM_R13: case DW_REG_ARM_R14: case DW_REG_ARM_R15: { |
michael@0 | 106 | // Check the aOldReg is valid. |
michael@0 | 107 | switch (aOldReg) { |
michael@0 | 108 | case DW_REG_CFA: |
michael@0 | 109 | case DW_REG_ARM_R7: case DW_REG_ARM_R11: case DW_REG_ARM_R12: |
michael@0 | 110 | case DW_REG_ARM_R13: case DW_REG_ARM_R14: case DW_REG_ARM_R15: |
michael@0 | 111 | break; |
michael@0 | 112 | default: |
michael@0 | 113 | goto cant_summarise; |
michael@0 | 114 | } |
michael@0 | 115 | // This is a new rule for one of r{7,11,12,13,14,15} and has a |
michael@0 | 116 | // representable offset. In particular the new value of r15 is |
michael@0 | 117 | // going to be the return address. |
michael@0 | 118 | LExpr expr = LExpr(aDeref ? LExpr::DEREF : LExpr::NODEREF, |
michael@0 | 119 | aOldReg, aOffset); |
michael@0 | 120 | switch (aNewReg) { |
michael@0 | 121 | case DW_REG_ARM_R7: mCurrRules.mR7expr = expr; break; |
michael@0 | 122 | case DW_REG_ARM_R11: mCurrRules.mR11expr = expr; break; |
michael@0 | 123 | case DW_REG_ARM_R12: mCurrRules.mR12expr = expr; break; |
michael@0 | 124 | case DW_REG_ARM_R13: mCurrRules.mR13expr = expr; break; |
michael@0 | 125 | case DW_REG_ARM_R14: mCurrRules.mR14expr = expr; break; |
michael@0 | 126 | case DW_REG_ARM_R15: mCurrRules.mR15expr = expr; break; |
michael@0 | 127 | default: MOZ_ASSERT(0); |
michael@0 | 128 | } |
michael@0 | 129 | break; |
michael@0 | 130 | } |
michael@0 | 131 | |
michael@0 | 132 | default: |
michael@0 | 133 | goto cant_summarise; |
michael@0 | 134 | } |
michael@0 | 135 | |
michael@0 | 136 | // Mark callee-saved registers (r4 .. r11) as unchanged, if there is |
michael@0 | 137 | // no other information about them. FIXME: do this just once, at |
michael@0 | 138 | // the point where the ruleset is committed. |
michael@0 | 139 | if (mCurrRules.mR7expr.mHow == LExpr::UNKNOWN) { |
michael@0 | 140 | mCurrRules.mR7expr = LExpr(LExpr::NODEREF, DW_REG_ARM_R7, 0); |
michael@0 | 141 | } |
michael@0 | 142 | if (mCurrRules.mR11expr.mHow == LExpr::UNKNOWN) { |
michael@0 | 143 | mCurrRules.mR11expr = LExpr(LExpr::NODEREF, DW_REG_ARM_R11, 0); |
michael@0 | 144 | } |
michael@0 | 145 | if (mCurrRules.mR12expr.mHow == LExpr::UNKNOWN) { |
michael@0 | 146 | mCurrRules.mR12expr = LExpr(LExpr::NODEREF, DW_REG_ARM_R12, 0); |
michael@0 | 147 | } |
michael@0 | 148 | |
michael@0 | 149 | // The old r13 (SP) value before the call is always the same as the |
michael@0 | 150 | // CFA. |
michael@0 | 151 | mCurrRules.mR13expr = LExpr(LExpr::NODEREF, DW_REG_CFA, 0); |
michael@0 | 152 | |
michael@0 | 153 | // If there's no information about R15 (the return address), say |
michael@0 | 154 | // it's a copy of R14 (the link register). |
michael@0 | 155 | if (mCurrRules.mR15expr.mHow == LExpr::UNKNOWN) { |
michael@0 | 156 | mCurrRules.mR15expr = LExpr(LExpr::NODEREF, DW_REG_ARM_R14, 0); |
michael@0 | 157 | } |
michael@0 | 158 | |
michael@0 | 159 | #elif defined(LUL_ARCH_x64) || defined(LUL_ARCH_x86) |
michael@0 | 160 | |
michael@0 | 161 | // ---------------- x64/x86 ---------------- // |
michael@0 | 162 | |
michael@0 | 163 | // Now, can we add the rule to our summary? This depends on whether |
michael@0 | 164 | // the registers and the overall expression are representable. This |
michael@0 | 165 | // is the heart of the summarisation process. In the 64 bit case |
michael@0 | 166 | // we need to check that aOffset will fit into an int32_t. In the |
michael@0 | 167 | // 32 bit case it is expected that the compiler will fold out the |
michael@0 | 168 | // test since it always succeeds. |
michael@0 | 169 | if (aNewReg == DW_REG_CFA) { |
michael@0 | 170 | // This is a rule that defines the CFA. The only forms we can |
michael@0 | 171 | // represent are: = SP+offset or = FP+offset. |
michael@0 | 172 | if (!aDeref && aOffset == (intptr_t)(int32_t)aOffset && |
michael@0 | 173 | (aOldReg == DW_REG_INTEL_XSP || aOldReg == DW_REG_INTEL_XBP)) { |
michael@0 | 174 | mCurrRules.mCfaExpr = LExpr(LExpr::NODEREF, aOldReg, aOffset); |
michael@0 | 175 | } else { |
michael@0 | 176 | goto cant_summarise; |
michael@0 | 177 | } |
michael@0 | 178 | } |
michael@0 | 179 | else |
michael@0 | 180 | if ((aNewReg == DW_REG_INTEL_XSP || |
michael@0 | 181 | aNewReg == DW_REG_INTEL_XBP || aNewReg == DW_REG_INTEL_XIP) && |
michael@0 | 182 | (aOldReg == DW_REG_CFA || |
michael@0 | 183 | aOldReg == DW_REG_INTEL_XSP || |
michael@0 | 184 | aOldReg == DW_REG_INTEL_XBP || aOldReg == DW_REG_INTEL_XIP) && |
michael@0 | 185 | aOffset == (intptr_t)(int32_t)aOffset) { |
michael@0 | 186 | // This is a new rule for SP, BP or the return address |
michael@0 | 187 | // respectively, and has a representable offset. |
michael@0 | 188 | LExpr expr = LExpr(aDeref ? LExpr::DEREF : LExpr::NODEREF, |
michael@0 | 189 | aOldReg, aOffset); |
michael@0 | 190 | switch (aNewReg) { |
michael@0 | 191 | case DW_REG_INTEL_XBP: mCurrRules.mXbpExpr = expr; break; |
michael@0 | 192 | case DW_REG_INTEL_XSP: mCurrRules.mXspExpr = expr; break; |
michael@0 | 193 | case DW_REG_INTEL_XIP: mCurrRules.mXipExpr = expr; break; |
michael@0 | 194 | default: MOZ_CRASH("impossible value for aNewReg"); |
michael@0 | 195 | } |
michael@0 | 196 | } |
michael@0 | 197 | else { |
michael@0 | 198 | goto cant_summarise; |
michael@0 | 199 | } |
michael@0 | 200 | |
michael@0 | 201 | // On Intel, it seems the old SP value before the call is always the |
michael@0 | 202 | // same as the CFA. Therefore, in the absence of any other way to |
michael@0 | 203 | // recover the SP, specify that the CFA should be copied. |
michael@0 | 204 | if (mCurrRules.mXspExpr.mHow == LExpr::UNKNOWN) { |
michael@0 | 205 | mCurrRules.mXspExpr = LExpr(LExpr::NODEREF, DW_REG_CFA, 0); |
michael@0 | 206 | } |
michael@0 | 207 | |
michael@0 | 208 | // Also, gcc says "Undef" for BP when it is unchanged. |
michael@0 | 209 | if (mCurrRules.mXbpExpr.mHow == LExpr::UNKNOWN) { |
michael@0 | 210 | mCurrRules.mXbpExpr = LExpr(LExpr::NODEREF, DW_REG_INTEL_XBP, 0); |
michael@0 | 211 | } |
michael@0 | 212 | |
michael@0 | 213 | #else |
michael@0 | 214 | |
michael@0 | 215 | # error "Unsupported arch" |
michael@0 | 216 | #endif |
michael@0 | 217 | |
michael@0 | 218 | return; |
michael@0 | 219 | cant_summarise: |
michael@0 | 220 | if (0) { |
michael@0 | 221 | mLog("LUL can't summarise\n"); |
michael@0 | 222 | } |
michael@0 | 223 | } |
michael@0 | 224 | |
michael@0 | 225 | void |
michael@0 | 226 | Summariser::End() |
michael@0 | 227 | { |
michael@0 | 228 | if (DEBUG_SUMMARISER) { |
michael@0 | 229 | mLog("LUL End\n"); |
michael@0 | 230 | } |
michael@0 | 231 | if (mCurrAddr < mMax1Addr) { |
michael@0 | 232 | mCurrRules.mAddr = mCurrAddr; |
michael@0 | 233 | mCurrRules.mLen = mMax1Addr - mCurrAddr; |
michael@0 | 234 | mSecMap->AddRuleSet(&mCurrRules); |
michael@0 | 235 | if (DEBUG_SUMMARISER) { |
michael@0 | 236 | mLog("LUL "); mCurrRules.Print(mLog); |
michael@0 | 237 | mLog("\n"); |
michael@0 | 238 | } |
michael@0 | 239 | } |
michael@0 | 240 | } |
michael@0 | 241 | |
michael@0 | 242 | } // namespace lul |