Changeset 247041 in webkit


Ignore:
Timestamp:
Jul 2, 2019 12:00:14 AM (5 years ago)
Author:
keith_miller@apple.com
Message:

PACCage should first cage leaving PAC bits intact then authenticate
https://bugs.webkit.org/show_bug.cgi?id=199372

Reviewed by Saam Barati.

Source/bmalloc:

  • bmalloc/ProcessCheck.mm:

(bmalloc::shouldProcessUnconditionallyUseBmalloc):

Source/JavaScriptCore:

This ordering prevents someone from taking a signed pointer from
outside the gigacage and using it in a struct that expects a caged
pointer. Previously, the PACCaging just double checked that the PAC
bits were valid for the original pointer.

+---------------------------+
| | | |
| "PAC" | "base" | "offset" +----+
| | | | |
+---------------------------+ | Caging

| |
| |
| v
| +---------------------------+
| | | | |
| Bit Merge | 00000 | base | "offset" |
| | | | |
| +---------------------------+
| |
| |
v | Bit Merge

+---------------------------+ |
| | | | |
| "PAC" | base | "offset" +<--------+
| | | |
+---------------------------+

|
|
| Authenticate
|
v

+---------------------------+
| | | |
| Auth | base | "offset" |
| | | |
+---------------------------+

The above ascii art graph shows how the PACCage system works. The
key take away is that even if someone passes in a valid, signed
pointer outside the cage it will still fail to authenticate as the
"base" bits will change before authentication.

  • assembler/MacroAssemblerARM64E.h:
  • assembler/testmasm.cpp:

(JSC::testCagePreservesPACFailureBit):

  • ftl/FTLLowerDFGToB3.cpp:

(JSC::FTL::DFG::LowerDFGToB3::caged):

  • jit/AssemblyHelpers.h:

(JSC::AssemblyHelpers::cageConditionally):

  • llint/LowLevelInterpreter64.asm:

Source/WTF:

  • wtf/CagedPtr.h:

(WTF::CagedPtr::get const):
(WTF::CagedPtr::getMayBeNull const):
(WTF::CagedPtr::mergePointers):

Location:
trunk/Source
Files:
10 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r247036 r247041  
     12019-07-02  Keith Miller  <keith_miller@apple.com>
     2
     3        PACCage should first cage leaving PAC bits intact then authenticate
     4        https://bugs.webkit.org/show_bug.cgi?id=199372
     5
     6        Reviewed by Saam Barati.
     7
     8        This ordering prevents someone from taking a signed pointer from
     9        outside the gigacage and using it in a struct that expects a caged
     10        pointer. Previously, the PACCaging just double checked that the PAC
     11        bits were valid for the original pointer.
     12
     13
     14               +---------------------------+
     15               |       |        |          |
     16               | "PAC" | "base" | "offset" +----+
     17               |       |        |          |    |
     18               +---------------------------+    | Caging
     19                |                               |
     20                |                               |
     21                |                               v
     22                |                +---------------------------+
     23                |                |       |        |          |
     24                | Bit Merge      | 00000 |  base  | "offset" |
     25                |                |       |        |          |
     26                |                +---------------------------+
     27                |                               |
     28                |                               |
     29                v                               |  Bit Merge
     30          +---------------------------+         |
     31          |       |        |          |         |
     32          | "PAC" |  base  | "offset" +<--------+
     33          |       |        |          |
     34          +---------------------------+
     35                      |
     36                      |
     37                      | Authenticate
     38                      |
     39                      v
     40          +---------------------------+
     41          |       |        |          |
     42          | Auth  |  base  | "offset" |
     43          |       |        |          |
     44          +---------------------------+
     45
     46        The above ascii art graph shows how the PACCage system works. The
     47        key take away is that even if someone passes in a valid, signed
     48        pointer outside the cage it will still fail to authenticate as the
     49        "base" bits will change before authentication.
     50
     51
     52        * assembler/MacroAssemblerARM64E.h:
     53        * assembler/testmasm.cpp:
     54        (JSC::testCagePreservesPACFailureBit):
     55        * ftl/FTLLowerDFGToB3.cpp:
     56        (JSC::FTL::DFG::LowerDFGToB3::caged):
     57        * jit/AssemblyHelpers.h:
     58        (JSC::AssemblyHelpers::cageConditionally):
     59        * llint/LowLevelInterpreter64.asm:
     60
    1612019-07-01  Justin Michaud  <justin_michaud@apple.com>
    262
  • trunk/Source/JavaScriptCore/assembler/MacroAssemblerARM64E.h

    r246451 r247041  
    4141public:
    4242    static constexpr unsigned numberOfPACBits = 25;
     43    static constexpr uintptr_t nonPACBitsMask = (1ull << (64 - numberOfPACBits)) - 1;
    4344
    4445    ALWAYS_INLINE void tagReturnAddress()
  • trunk/Source/JavaScriptCore/assembler/testmasm.cpp

    r247011 r247041  
    10161016static void testCagePreservesPACFailureBit()
    10171017{
     1018#if GIGACAGE_ENABLED
     1019    ASSERT(!Gigacage::isDisablingPrimitiveGigacageDisabled());
    10181020    auto cage = compile([] (CCallHelpers& jit) {
    10191021        jit.emitFunctionPrologue();
     
    10261028    void* ptr = Gigacage::tryMalloc(Gigacage::Primitive, 1);
    10271029    void* taggedPtr = tagArrayPtr(ptr, 1);
    1028     dataLogLn("starting test");
     1030    ASSERT(hasOneBitSet(Gigacage::size(Gigacage::Primitive) << 2));
     1031    void* notCagedPtr = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(ptr) + (Gigacage::size(Gigacage::Primitive) << 2));
     1032    CHECK_NOT_EQ(Gigacage::caged(Gigacage::Primitive, notCagedPtr), notCagedPtr);
     1033    void* taggedNotCagedPtr = tagArrayPtr(notCagedPtr, 1);
     1034
    10291035    if (isARM64E()) {
    10301036        // FIXME: This won't work if authentication failures trap but I don't know how to test for that right now.
    10311037        CHECK_NOT_EQ(invoke<void*>(cage, taggedPtr, 2), ptr);
     1038        CHECK_EQ(invoke<void*>(cage, taggedNotCagedPtr, 1), untagArrayPtr(taggedPtr, 2));
    10321039    } else
    10331040        CHECK_EQ(invoke<void*>(cage, taggedPtr, 2), ptr);
     
    10431050    });
    10441051
     1052    CHECK_EQ(invoke<void*>(cageWithoutAuthentication, taggedPtr), taggedPtr);
    10451053    if (isARM64E()) {
    10461054        // FIXME: This won't work if authentication failures trap but I don't know how to test for that right now.
    1047         CHECK_NOT_EQ(invoke<void*>(cageWithoutAuthentication, untagArrayPtr(taggedPtr, 2)), ptr);
    1048     } else
    1049         CHECK_EQ(invoke<void*>(cageWithoutAuthentication, untagArrayPtr(taggedPtr, 2)), ptr);
    1050 
    1051     CHECK_EQ(untagArrayPtr(taggedPtr, 1), ptr);
    1052     CHECK_EQ(invoke<void*>(cageWithoutAuthentication, untagArrayPtr(taggedPtr, 1)), ptr);
     1055        CHECK_NOT_EQ(invoke<void*>(cageWithoutAuthentication, taggedNotCagedPtr), taggedNotCagedPtr);
     1056        CHECK_NOT_EQ(untagArrayPtr(invoke<void*>(cageWithoutAuthentication, taggedNotCagedPtr), 1), notCagedPtr);
     1057        CHECK_NOT_EQ(invoke<void*>(cageWithoutAuthentication, taggedNotCagedPtr), taggedPtr);
     1058        CHECK_NOT_EQ(untagArrayPtr(invoke<void*>(cageWithoutAuthentication, taggedNotCagedPtr), 1), ptr);
     1059    }
    10531060
    10541061    Gigacage::free(Gigacage::Primitive, ptr);
     1062#endif
    10551063}
    10561064
  • trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp

    r246910 r247041  
    1417814178    LValue caged(Gigacage::Kind kind, LValue ptr, LValue base)
    1417914179    {
    14180 #if CPU(ARM64E)
    14181         if (kind == Gigacage::Primitive) {
    14182             LValue size = m_out.load32(base, m_heaps.JSArrayBufferView_length);
    14183             ptr = untagArrayPtr(ptr, size);
    14184         }
    14185 #else
    14186         UNUSED_PARAM(kind);
    14187         UNUSED_PARAM(base);
    14188 #endif
    14189 
    1419014180#if GIGACAGE_ENABLED
    14191         UNUSED_PARAM(base);
    1419214181        if (!Gigacage::isEnabled(kind))
    1419314182            return ptr;
     
    1420714196
    1420814197#if CPU(ARM64E)
    14209         {
     14198        if (kind == Gigacage::Primitive) {
    1421014199            PatchpointValue* merge = m_out.patchpoint(pointerType());
    1421114200            merge->append(result, B3::ValueRep(B3::ValueRep::SomeLateRegister));
     
    1421514204                jit.bitFieldInsert64(params[1].gpr(), 0, 64 - MacroAssembler::numberOfPACBits, params[0].gpr());
    1421614205            });
    14217             result = merge;
    14218         }
    14219 #endif
     14206
     14207            LValue size = m_out.load32(base, m_heaps.JSArrayBufferView_length);
     14208            result = untagArrayPtr(merge, size);
     14209        }
     14210#endif // CPU(ARM64E)
     14211
    1422014212        // Make sure that B3 doesn't try to do smart reassociation of these pointer bits.
    1422114213        // FIXME: In an ideal world, B3 would not do harmful reassociations, and if it did, it would be able
     
    1423114223        return m_out.opaque(result);
    1423214224#endif
     14225
     14226        UNUSED_PARAM(kind);
     14227        UNUSED_PARAM(base);
    1423314228        return ptr;
    1423414229    }
  • trunk/Source/JavaScriptCore/jit/AssemblyHelpers.h

    r246451 r247041  
    15871587    void cageConditionally(Gigacage::Kind kind, GPRReg storage, GPRReg length, GPRReg scratch)
    15881588    {
     1589#if GIGACAGE_ENABLED
     1590        if (Gigacage::isEnabled(kind)) {
     1591            if (kind != Gigacage::Primitive || Gigacage::isDisablingPrimitiveGigacageDisabled())
     1592                cageWithoutUntagging(kind, storage);
     1593            else {
     1594#if CPU(ARM64E)
     1595                if (length == scratch)
     1596                    scratch = getCachedMemoryTempRegisterIDAndInvalidate();
     1597#endif
     1598                loadPtr(&Gigacage::basePtr(kind), scratch);
     1599                Jump done = branchTest64(Zero, scratch);
     1600#if CPU(ARM64E)
     1601                GPRReg tempReg = getCachedDataTempRegisterIDAndInvalidate();
     1602                move(storage, tempReg);
     1603                ASSERT(LogicalImmediate::create64(Gigacage::mask(kind)).isValid());
     1604                andPtr(TrustedImmPtr(Gigacage::mask(kind)), tempReg);
     1605                addPtr(scratch, tempReg);
     1606                bitFieldInsert64(tempReg, 0, 64 - numberOfPACBits, storage);
     1607#else
     1608                andPtr(TrustedImmPtr(Gigacage::mask(kind)), storage);
     1609                addPtr(scratch, storage);
     1610#endif // CPU(ARM64E)
     1611                done.link(this);
     1612            }
     1613        }
     1614#endif
     1615
    15891616#if CPU(ARM64E)
    15901617        if (kind == Gigacage::Primitive)
    15911618            untagArrayPtr(length, storage);
    1592 #else
     1619#endif
    15931620        UNUSED_PARAM(kind);
    15941621        UNUSED_PARAM(storage);
    15951622        UNUSED_PARAM(length);
    1596 #endif
    1597 
    1598 #if GIGACAGE_ENABLED
    1599         if (!Gigacage::isEnabled(kind))
    1600             return;
    1601        
    1602         if (kind != Gigacage::Primitive || Gigacage::isDisablingPrimitiveGigacageDisabled())
    1603             cageWithoutUntagging(kind, storage);
    1604         else {
    1605             loadPtr(&Gigacage::basePtr(kind), scratch);
    1606             Jump done = branchTestPtr(Zero, scratch);
    1607 #if CPU(ARM64E)
    1608             auto tempReg = getCachedMemoryTempRegisterIDAndInvalidate();
    1609             move(storage, tempReg);
    1610             andPtr(TrustedImmPtr(Gigacage::mask(kind)), tempReg);
    1611             addPtr(scratch, tempReg);
    1612             bitFieldInsert64(tempReg, 0, 64 - numberOfPACBits, storage);
    1613 #else
    1614             andPtr(TrustedImmPtr(Gigacage::mask(kind)), storage);
    1615             addPtr(scratch, storage);
    1616 #endif
    1617             done.link(this);
    1618 
    1619 
    1620         }
    1621 #else
    16221623        UNUSED_PARAM(scratch);
    1623 #endif
    1624 
    16251624    }
    16261625
  • trunk/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm

    r246451 r247041  
    423423end
    424424
    425 macro uncage(basePtr, mask, ptr, scratchOrLength)
     425macro cage(basePtr, mask, ptr, scratch)
    426426    if GIGACAGE_ENABLED and not (C_LOOP or C_LOOP_WIN)
    427         loadp basePtr, scratchOrLength
    428         btpz scratchOrLength, .done
     427        loadp basePtr, scratch
     428        btpz scratch, .done
    429429        andp mask, ptr
    430         addp scratchOrLength, ptr
     430        addp scratch, ptr
    431431    .done:
    432432    end
    433433end
    434434
    435 macro loadCagedPrimitive(source, dest, scratchOrLength)
    436     loadp source, dest
     435macro cagedPrimitive(ptr, length, scratch, scratch2)
    437436    if ARM64E
    438         const result = t7
    439         untagArrayPtr scratchOrLength, dest
    440         move dest, result
     437        const source = scratch2
     438        move ptr, scratch2
    441439    else
    442         const result = dest
     440        const source = ptr
    443441    end
    444442    if GIGACAGE_ENABLED
    445         uncage(_g_gigacageBasePtrs + Gigacage::BasePtrs::primitive, constexpr Gigacage::primitiveGigacageMask, result, scratchOrLength)
     443        cage(_g_gigacageBasePtrs + Gigacage::BasePtrs::primitive, constexpr Gigacage::primitiveGigacageMask, source, scratch)
    446444        if ARM64E
    447445            const numberOfPACBits = constexpr MacroAssembler::numberOfPACBits
    448             bfiq result, 0, 64 - numberOfPACBits, dest
     446            bfiq scratch2, 0, 64 - numberOfPACBits, ptr
     447            untagArrayPtr length, ptr
    449448        end
    450449    end
     
    453452macro loadCagedJSValue(source, dest, scratchOrLength)
    454453    loadp source, dest
    455     uncage(_g_gigacageBasePtrs + Gigacage::BasePtrs::jsValue, constexpr Gigacage::jsValueGigacageMask, dest, scratchOrLength)
     454    cage(_g_gigacageBasePtrs + Gigacage::BasePtrs::jsValue, constexpr Gigacage::jsValueGigacageMask, dest, scratchOrLength)
    456455end
    457456
     
    15231522
    15241523    if ARM64E
    1525         const scratchOrLength = t6
    1526         loadi JSArrayBufferView::m_length[t0], scratchOrLength
    1527         biaeq t1, scratchOrLength, .opGetByValSlow
     1524        const length = t6
     1525        const scratch = t7
     1526        loadi JSArrayBufferView::m_length[t0], length
     1527        biaeq t1, length, .opGetByValSlow
    15281528    else
    1529         const scratchOrLength = t0
     1529        # length and scratch are intentionally undefined on this branch because they are not used on other platforms.
    15301530        biaeq t1, JSArrayBufferView::m_length[t0], .opGetByValSlow
    15311531    end
    15321532
    1533     loadCagedPrimitive(JSArrayBufferView::m_vector[t0], t3, scratchOrLength)
     1533    loadp JSArrayBufferView::m_vector[t0], t3
     1534    cagedPrimitive(t3, length, t0, scratch)
    15341535
    15351536    # Now bisect through the various types:
  • trunk/Source/WTF/ChangeLog

    r247010 r247041  
     12019-07-02  Keith Miller  <keith_miller@apple.com>
     2
     3        PACCage should first cage leaving PAC bits intact then authenticate
     4        https://bugs.webkit.org/show_bug.cgi?id=199372
     5
     6        Reviewed by Saam Barati.
     7
     8        * wtf/CagedPtr.h:
     9        (WTF::CagedPtr::get const):
     10        (WTF::CagedPtr::getMayBeNull const):
     11        (WTF::CagedPtr::mergePointers):
     12
    1132019-07-01  Philippe Normand  <pnormand@igalia.com>
    214
  • trunk/Source/WTF/wtf/CagedPtr.h

    r246827 r247041  
    5050    { }
    5151
    52 
    5352    T* get(unsigned size) const
    5453    {
    5554        ASSERT(m_ptr);
    5655        T* ptr = PtrTraits::unwrap(m_ptr);
    57         T* untaggedPtr = shouldTag ? untagArrayPtr(ptr, size) : ptr;
    58         return mergePointers(untaggedPtr, Gigacage::caged(kind, ptr));
     56        T* cagedPtr = Gigacage::caged(kind, ptr);
     57        T* untaggedPtr = shouldTag ? untagArrayPtr(mergePointers(ptr, cagedPtr), size) : cagedPtr;
     58        return untaggedPtr;
    5959    }
    6060
     
    6262    {
    6363        T* ptr = PtrTraits::unwrap(m_ptr);
    64         T* untaggedPtr = shouldTag ? untagArrayPtr(ptr, size) : ptr;
    65         return mergePointers(untaggedPtr, Gigacage::cagedMayBeNull(kind, ptr));
     64        T* cagedPtr = Gigacage::cagedMayBeNull(kind, ptr);
     65        T* untaggedPtr = shouldTag ? untagArrayPtr(mergePointers(ptr, cagedPtr), size) : cagedPtr;
     66        return untaggedPtr;
    6667    }
    6768
     
    125126   
    126127protected:
    127     static inline T* mergePointers(const T* untaggedPtr, const T* uncagedPtr)
     128    static inline T* mergePointers(T* sourcePtr, T* cagedPtr)
    128129    {
     130#if CPU(ARM64E)
    129131        constexpr unsigned numberOfPACBits = 25;
    130132        constexpr uintptr_t mask = (1ull << ((sizeof(T*) * CHAR_BIT) - numberOfPACBits)) - 1;
    131         return reinterpret_cast<T*>((reinterpret_cast<uintptr_t>(untaggedPtr) & ~mask) | (reinterpret_cast<uintptr_t>(uncagedPtr) & mask));
     133        return reinterpret_cast<T*>((reinterpret_cast<uintptr_t>(sourcePtr) & ~mask) | (reinterpret_cast<uintptr_t>(cagedPtr) & mask));
     134#else
     135        UNUSED_PARAM(sourcePtr);
     136        return cagedPtr;
     137#endif
    132138    }
    133139
  • trunk/Source/bmalloc/ChangeLog

    r246892 r247041  
     12019-07-02  Keith Miller  <keith_miller@apple.com>
     2
     3        PACCage should first cage leaving PAC bits intact then authenticate
     4        https://bugs.webkit.org/show_bug.cgi?id=199372
     5
     6        Reviewed by Saam Barati.
     7
     8        * bmalloc/ProcessCheck.mm:
     9        (bmalloc::shouldProcessUnconditionallyUseBmalloc):
     10
    1112019-06-27  Beth Dakin  <bdakin@apple.com>
    212
  • trunk/Source/bmalloc/bmalloc/ProcessCheck.mm

    r245908 r247041  
    6767        } else {
    6868            NSString *processName = [[NSProcessInfo processInfo] processName];
    69             result = [processName isEqualToString:@"jsc"] || [processName isEqualToString:@"wasm"];
     69            result = [processName isEqualToString:@"jsc"]
     70                || [processName isEqualToString:@"wasm"]
     71                || [processName hasPrefix:@"test"];
    7072        }
    7173    });
Note: See TracChangeset for help on using the changeset viewer.