fix(relinker): validate SCE dynamic data segment
This commit is contained in:
parent
ef727569cc
commit
16adcd4871
|
|
@ -61,9 +61,15 @@ RelinkResult RelinkerPipeline::Relink(const std::vector<std::uint8_t>& sourceElf
|
|||
}
|
||||
|
||||
FileByteOffset sceTableBase = 0;
|
||||
for (const auto& ph : programHeaders)
|
||||
if (ph.Type == PT_SCE_DYNLIBDATA)
|
||||
sceTableBase = ph.Offset;
|
||||
bool hasSceDynlibData = false;
|
||||
for (const auto& ph : programHeaders) {
|
||||
if (ph.Type != PT_SCE_DYNLIBDATA)
|
||||
continue;
|
||||
if (hasSceDynlibData)
|
||||
throw RelinkerException("Multiple PT_SCE_DYNLIBDATA segments", ph.Offset);
|
||||
hasSceDynlibData = true;
|
||||
sceTableBase = ph.Offset;
|
||||
}
|
||||
|
||||
std::vector<DynamicTag> dynTags;
|
||||
bool hasDynamicSegment = false;
|
||||
|
|
@ -108,7 +114,7 @@ RelinkResult RelinkerPipeline::Relink(const std::vector<std::uint8_t>& sourceElf
|
|||
if (requireExactlyOneOf(osTag, sysvTag, name)) {
|
||||
const std::uint64_t value = getTagValue(osTag);
|
||||
if (value > std::numeric_limits<FileByteOffset>::max() - sceTableBase)
|
||||
throw RelinkerException(std::string(name) + " is outside the file", value);
|
||||
throw RelinkerException(std::string("Adding PT_SCE_DYNLIBDATA base to ") + name + " overflows", value);
|
||||
return sceTableBase + value;
|
||||
}
|
||||
return _elfReader->TranslateVirtualAddress(getTagValue(sysvTag));
|
||||
|
|
|
|||
|
|
@ -24,12 +24,12 @@ DT_OS_RELAENT = 0x61000033
|
|||
|
||||
|
||||
def fixture(os_tags=False, str_size=16, needed_offset=1, symbol_offset=8, table_bytes=None, outside_bytes=b"",
|
||||
block_offset=0, strtab_value=None):
|
||||
block_offset=0, strtab_value=None, duplicate_sce_dynlibdata=False):
|
||||
image = bytearray(0x1000)
|
||||
table_base = block_offset if os_tags else 0
|
||||
image[:16] = b"\x7fELF\x02\x01\x01" + bytes(9)
|
||||
struct.pack_into("<HHIQQQIHHHHHH", image, 16,
|
||||
3, 62, 1, 0x200, 64, 0, 0, 64, 56, 3, 64, 0, 0)
|
||||
3, 62, 1, 0x200, 64, 0, 0, 64, 56, 4 if duplicate_sce_dynlibdata else 3, 64, 0, 0)
|
||||
image[0x200:0x206] = b"\xff\x25\xfa\x00\x00\x00"
|
||||
tags = [
|
||||
(DT_NEEDED, needed_offset),
|
||||
|
|
@ -49,6 +49,9 @@ def fixture(os_tags=False, str_size=16, needed_offset=1, symbol_offset=8, table_
|
|||
2, 6, 0x400, 0x400, 0x400, len(tags) * 16, len(tags) * 16, 8)
|
||||
struct.pack_into("<IIQQQQQQ", image, 176,
|
||||
0x61000000, 0, block_offset, 0, 0, len(image) - block_offset, len(image) - block_offset, 1)
|
||||
if duplicate_sce_dynlibdata:
|
||||
struct.pack_into("<IIQQQQQQ", image, 232,
|
||||
0x61000000, 0, 0x500, 0, 0, len(image) - 0x500, len(image) - 0x500, 1)
|
||||
if table_base:
|
||||
image[0x100:0x200] = b"\xff" * 0x100
|
||||
for index, tag in enumerate(tags):
|
||||
|
|
@ -82,9 +85,14 @@ def main():
|
|||
run(relinker, work, "sysv-valid", fixture())
|
||||
run(relinker, work, "os-valid", fixture(os_tags=True))
|
||||
run(relinker, work, "os-tables-in-sce-block", fixture(os_tags=True, block_offset=0x500))
|
||||
run(relinker, work, "os-table-past-file", fixture(os_tags=True, block_offset=0x500,
|
||||
strtab_value=0xffffffffffffffff),
|
||||
"DT_STRTAB is outside the file")
|
||||
run(relinker, work, "os-table-addition-overflow", fixture(os_tags=True, block_offset=0x500,
|
||||
strtab_value=0xffffffffffffffff),
|
||||
"Adding PT_SCE_DYNLIBDATA base to DT_STRTAB overflows")
|
||||
run(relinker, work, "os-table-out-of-bounds", fixture(os_tags=True, block_offset=0x500,
|
||||
strtab_value=0xb00),
|
||||
"Dynamic string table is out of bounds")
|
||||
run(relinker, work, "duplicate-sce-dynlibdata", fixture(os_tags=True, duplicate_sce_dynlibdata=True),
|
||||
"Multiple PT_SCE_DYNLIBDATA segments")
|
||||
run(relinker, work, "needed-offset", fixture(needed_offset=16, outside_bytes=b"lib.so\x00"),
|
||||
"Dynamic string offset is outside DT_STRSZ")
|
||||
run(relinker, work, "needed-offset-max", fixture(needed_offset=0xffffffffffffffff,
|
||||
|
|
|
|||
|
|
@ -434,7 +434,7 @@ Throughout the project, every function at every stage either **does exactly what
|
|||
- [Image loads](../../core/shader/recompiler/Optimization/src/ResourceTracker.cpp) (shader recompiler) - an image_load reads a sampled binding, also of an image the shader stores to, so in a primitive-ordered pixel shader it misses an earlier overlapping primitive's image_store in the same draw.
|
||||
- [PA_SC_CONSERVATIVE_RASTERIZATION_CNTL](../../core/libs/prx/libSceAgcDriver/Graphics/src/State.cpp) (libSceAgcDriver) - 0x6001 uses Vulkan overestimation on devices that add at most 1/256 pixel and keep degenerate triangles; the console's uncertainty region and degenerate handling are unmeasured. A value with `OVER_RAST_ENABLE` and `UNDER_RAST_ENABLE` clear is decoded as disabled even when `UNCERTAINTY_REGION_MODE` or the `OUTER_`/`INNER_UNCERTAINTY_EDGERULE_OVERRIDE` bits (19:16) are set, as PPSA01474 writes 0xe6000; that these fields have no effect without over- or underestimation is assumed from their names, not measured.
|
||||
- The Linux placement of the `--to-intel` stubs in the [ELF patcher](../../core/relinker/elfpatcher/src/linux/LinuxElfPatcher.cpp) is covered only by a synthetic test.
|
||||
- The [relinker pipeline](../../core/relinker/relinker/src/pipeline/RelinkerPipeline.cpp) reads `DT_SCE_*` table addresses as offsets into the `PT_SCE_DYNLIBDATA` segment, where PS4 executables (CUSA00900) keep them; without that segment they are still read as file offsets. The `unused-filter=1` and `unused-filter=2` analyses do not: [RelativeRelocationIndex](../../core/relinker/relinker/src/analysis/UnusedNidFilter/RelativeRelocationIndex.cpp) reads `DT_SCE_RELA` and `DT_SCE_JMPREL` as virtual addresses and [StrictNidFilter](../../core/relinker/relinker/src/analysis/UnusedNidFilter/StrictNidFilter.cpp) reads the SCE tables as file offsets, so they misread a PS4 executable's tables.
|
||||
- The [relinker pipeline](../../core/relinker/relinker/src/pipeline/RelinkerPipeline.cpp) reads `DT_SCE_*` table addresses as offsets into the `PT_SCE_DYNLIBDATA` segment, where PS4 executables (CUSA00900) keep them; without that segment they are still read as file offsets. It rejects multiple `PT_SCE_DYNLIBDATA` segments, matching the single segment in the [documented PS4 ELF layout](https://github.com/OpenOrbis/OpenOrbis-PS4-Toolchain/wiki/PS4-ELF-Specification). The `unused-filter=1` and `unused-filter=2` analyses do not: [RelativeRelocationIndex](../../core/relinker/relinker/src/analysis/UnusedNidFilter/RelativeRelocationIndex.cpp) reads `DT_SCE_RELA` and `DT_SCE_JMPREL` as virtual addresses and [StrictNidFilter](../../core/relinker/relinker/src/analysis/UnusedNidFilter/StrictNidFilter.cpp) reads the SCE tables as file offsets, so they misread a PS4 executable's tables.
|
||||
- The libc [SSE4a trap emulation](../../core/libs/prx/libc/src/specifics/windows/Sse4aEmulation.hpp) on Windows is superseded by `--to-intel` and remains only until the relinked title has been verified without it.
|
||||
- [getifaddrs](../../core/libs/prx/libc/src/Interfaces.cpp) (libc) lists the host's IPv4 and IPv6 addresses in FreeBSD's `ifaddrs` and sockaddr layouts. FreeBSD's per-interface AF_LINK entries (MAC, index, MTU) and their `if_data` are not produced, so interfaces without an address are omitted. Names are the host's (Linux `lo`, `eth0`; Windows NDIS names such as `ethernet_32769`, or `if<index>` when one does not fit 15 bytes), not the console's. A Linux point-to-point address without a peer loses `IFF_POINTOPOINT`, and an IPv4 broadcast address the host omits is computed from the netmask. On Windows the flags are only `IFF_UP`, `IFF_RUNNING`, `IFF_LOOPBACK`, `IFF_BROADCAST` and `IFF_MULTICAST`, derived from the adapter: PPP and tunnel adapters get neither `IFF_BROADCAST` nor `IFF_POINTOPOINT` because their peer address is not reported, and an address whose prefix length the host reports as unspecified gets a host mask.
|
||||
- [gethostname](../../core/libs/prx/libc/src/Hostname.cpp) (libc) reports the fixed guest name `AnyPS5` without querying the host machine name. Buffer copying, null queries and `ENAMETOOLONG` follow [FreeBSD gethostname](https://github.com/freebsd/freebsd-src/blob/main/lib/libc/gen/gethostname.c); the console's configurable hostname and its integration with `sysctl` and name resolution are unverified and not implemented.
|
||||
|
|
|
|||
Loading…
Reference in New Issue