diff --git a/libraries/libstratosphere/source/util/util_compression_lz4.cpp b/libraries/libstratosphere/source/util/util_compression_lz4.cpp index 46950e180..97f3f6034 100644 --- a/libraries/libstratosphere/source/util/util_compression_lz4.cpp +++ b/libraries/libstratosphere/source/util/util_compression_lz4.cpp @@ -45,19 +45,24 @@ namespace ams::util { /* Destination buffer must be behind source buffer. */ if (dst_buffer > src_buffer) { - std::memset(dst, 0, dst_size); + std::memset(dst_buffer, 0, dst_size); return -1; } + const u8 *src_buffer_start = src_buffer; + const u8 *src_buffer_end = src_buffer + src_size; + const u8 *dst_buffer_start = dst_buffer; + const u8 *dst_buffer_end = dst_buffer + dst_size; + /* Size checks. */ - if (((src_buffer + src_size) != (dst_buffer + dst_size)) || (src_work_size != 0x10000) || (dst_work_size != 0x10000)) { - std::memset(dst, 0, dst_size); + if ((src_buffer_end != dst_buffer_end) || (src_work_size != 0x10000) || (dst_work_size != 0x10000)) { + std::memset(dst_buffer, 0, dst_size); return -1; } /* Source size must at least include one frame header. */ if (src_size < 7) { - std::memset(dst, 0, dst_size); + std::memset(dst_buffer, 0, dst_size); return -2; } @@ -68,34 +73,34 @@ namespace ams::util { /* Check for LZ4F_MAGICNUMBER, validate flags and block size. */ if ((magic != 0x184D2204) || ((flg & 1) != 0) || (flg != 0x60) || (bd != 0x40)) { - std::memset(dst, 0, dst_size); + std::memset(dst_buffer, 0, dst_size); return -2; } /* TODO: Implement header checksum validation. This requires xxhash, do we want to have xxhash in util? */ AMS_UNUSED(header_checksum); - u32 src_pos = 7; /* Skip the header. */ - u32 dst_pos = 0; + /* Skip the frame header. */ + src_buffer += 7; - /* Destination size is too small. */ - if (dst_size < src_pos) { - std::memset(dst, 0, dst_size); + /* Destination is too small. */ + if (src_buffer >= dst_buffer_end) { + std::memset(dst_buffer, 0, dst_size); return -2; } while (true) { /* Not enough space left. */ - if ((dst_size - src_pos) < 4) { - std::memset(dst, 0, dst_size); + if ((dst_buffer_end - src_buffer) < 4) { + std::memset(dst_buffer, 0, dst_size); return -4; } - src_buffer += src_pos; - dst_buffer += dst_pos; - const u32 block_header = *reinterpret_cast(src_buffer); + /* Advance the block. */ + src_buffer += sizeof(block_header); + /* We've reached the end. */ if (!block_header) { break; @@ -105,16 +110,13 @@ namespace ams::util { /* Block size is invalid. */ if (block_size > 0x10000) { - std::memset(dst, 0, dst_size); + std::memset(dst_buffer, 0, dst_size); return -3; } - /* Advance the data block. */ - src_buffer += sizeof(block_header); - /* Block size is invalid. */ - if (((dst_buffer + dst_size) - src_buffer) < block_size) { - std::memset(dst, 0, dst_size); + if ((dst_buffer_end - src_buffer) < block_size) { + std::memset(dst_buffer, 0, dst_size); return -4; } @@ -123,65 +125,67 @@ namespace ams::util { if ((block_header & 0x80000000) != 0) { /* Block size is invalid. */ - if (dst_size < block_size) { - std::memset(dst, 0, dst_size); + if ((dst_buffer_end - dst_buffer) < block_size) { + std::memset(dst_buffer, 0, dst_size); return -4; } - dst_pos += block_size; - src_pos += block_size; - /* Destination is overrunning source. */ - if (dst_pos > src_pos) { - std::memset(dst, 0, dst_size); + if ((dst_buffer + block_size) > (src_buffer + block_size)) { + std::memset(dst_buffer, 0, dst_size); return -5; } /* This is a raw block, copy it. */ - std::memmove(dst_buffer, src_buffer, block_size); + std::memmove(dst_buffer, src_buffer, block_size); + + /* Advance buffers. */ + dst_buffer += block_size; + src_buffer += block_size; } else { /* This is a compressed block, decompress it. */ int decompressed_size = LZ4_decompress_safe(reinterpret_cast(src_work), reinterpret_cast(dst_work), static_cast(block_size), 0x10000); /* Decompressed size is invalid. */ if (decompressed_size < 1) { - std::memset(dst, 0, dst_size); + std::memset(dst_buffer, 0, dst_size); return -3; } /* Decompressed size is invalid. */ - if (dst_size < static_cast(decompressed_size)) { - std::memset(dst, 0, dst_size); + if (static_cast(dst_buffer_end - dst_buffer) < static_cast(decompressed_size)) { + std::memset(dst_buffer, 0, dst_size); return -4; } - dst_pos += decompressed_size; - src_pos += block_size; - /* Destination is overrunning source. */ - if (dst_pos > src_pos) { - std::memset(dst, 0, dst_size); + if ((dst_buffer + decompressed_size) > (src_buffer + block_size)) { + std::memset(dst_buffer, 0, dst_size); return -5; } /* Copy the decompressed data back. */ std::memcpy(dst_buffer, static_cast(dst_work), decompressed_size); + + /* Advance buffers. */ + dst_buffer += decompressed_size; + src_buffer += block_size; } /* We've exceeded the destination's size. */ - if (src_pos >= dst_size) { - std::memset(dst, 0, dst_size); + if (src_buffer >= dst_buffer_end) { + std::memset(dst_buffer, 0, dst_size); return -2; } } /* We didn't consume all data. */ - if (src_pos != src_size) { - std::memset(dst, 0, dst_size); + if (static_cast(src_buffer - src_buffer_start) != src_size) { + std::memset(dst_buffer, 0, dst_size); return -2; } - *out_size = dst_pos; + *out_size = dst_buffer - dst_buffer_start; return 0; } } \ No newline at end of file diff --git a/stratosphere/ro/source/impl/ro_service_impl.cpp b/stratosphere/ro/source/impl/ro_service_impl.cpp index ef1a6afb1..e8c0b45c7 100644 --- a/stratosphere/ro/source/impl/ro_service_impl.cpp +++ b/stratosphere/ro/source/impl/ro_service_impl.cpp @@ -449,6 +449,7 @@ namespace ams::ro::impl { /* CheckAdditionalHeaderHash */ if (nro_header->GetAdditionalHeaderOffset() != 0) { R_TRY(this->CheckAdditionalHeaderHash(static_cast(mapped_memory), std::addressof(additional_nro_header_hash), sizeof(additional_nro_header_hash), nro_header->GetRwOffset(), nro_header->GetRwSize())); + ON_RESULT_FAILURE { std::memset(static_cast(mapped_memory) + 0x1000, 0, total_size - 0x1000); }; } } @@ -707,16 +708,17 @@ namespace ams::ro::impl { /* Map the NRO. */ R_TRY(MapNro(std::addressof(nro_info->base_address), context->GetProcessHandle(), nro_address, nro_size, bss_address, bss_size)); - ON_RESULT_FAILURE { R_DISCARD(UnmapNro(context->GetProcessHandle(), nro_info->base_address, nro_address, nro_size, bss_address, bss_size)); }; - + /* Parse the NRO. */ u64 nro_rx_size = 0, nro_ro_size = 0, nro_rw_size = 0, nro_bss_size = 0; bool nro_aligned_header = false; bool nro_is_compress = false; R_TRY(context->ParseNro(std::addressof(nro_info->module_id), std::addressof(nro_rx_size), std::addressof(nro_ro_size), std::addressof(nro_rw_size), std::addressof(nro_bss_size), std::addressof(nro_aligned_header), std::addressof(nro_is_compress), nro_info->base_address, total_size, nro_size, bss_size)); - + ON_RESULT_FAILURE { R_DISCARD(UnmapNro(context->GetProcessHandle(), nro_info->base_address, nro_address, nro_size, bss_address, bss_size)); }; + /* Set NRO perms. */ R_TRY(SetNroPerms(context->GetProcessHandle(), nro_info->base_address, nro_rx_size, nro_ro_size, nro_rw_size + nro_bss_size, nro_aligned_header)); + ON_RESULT_FAILURE_2 { if (!nro_is_compress) { R_DISCARD(UnmapNro(context->GetProcessHandle(), nro_info->base_address, nro_address, nro_size, bss_address, bss_size)); } }; context->SetNroInfoInUse(nro_info, true); nro_info->nro_heap_address = nro_address;