diff --git a/stratosphere/loader/source/ldr_nso.cpp b/stratosphere/loader/source/ldr_nso.cpp index 08e0de419..782ad6ba8 100644 --- a/stratosphere/loader/source/ldr_nso.cpp +++ b/stratosphere/loader/source/ldr_nso.cpp @@ -2,6 +2,7 @@ #include #include #include "ldr_nso.hpp" +#include "ldr_random.hpp" static NsoUtils::NsoHeader g_nso_headers[NSO_NUM_MAX] = {0}; static bool g_nso_present[NSO_NUM_MAX] = {0}; @@ -118,7 +119,7 @@ Result NsoUtils::CalculateNsoLoadExtents(u32 addspace_type, u32 args_size, NsoLo } /* Calculate ASLR extents for address space type. */ - u64 addspace_start, addspace_size, addspace_end; + u64 addspace_start, addspace_size; if (kernelAbove200()) { switch (addspace_type & 0xE) { case 0: @@ -147,14 +148,13 @@ Result NsoUtils::CalculateNsoLoadExtents(u32 addspace_type, u32 args_size, NsoLo addspace_size = 0x3FE00000ULL; } } - addspace_end = addspace_start + addspace_size; - if (addspace_start + extents->total_size > addspace_end) { + if (extents->total_size > addspace_size) { return 0xD001; } u64 aslr_slide = 0; if (addspace_type & 0x20) { - /* TODO: Apply a random ASLR slide. */ + aslr_slide = RandomUtils::GetRandomU64((addspace_size - extents->total_size) >> 21) << 21; } extents->base_address = addspace_start + aslr_slide; diff --git a/stratosphere/loader/source/ldr_random.cpp b/stratosphere/loader/source/ldr_random.cpp new file mode 100644 index 000000000..3839c677b --- /dev/null +++ b/stratosphere/loader/source/ldr_random.cpp @@ -0,0 +1,49 @@ +#include + +#include "ldr_random.hpp" + +/* Official HOS uses TinyMT. This is high effort. Let's just use XorShift. */ +/* https://en.wikipedia.org/wiki/Xorshift */ + +static u32 g_random_state[4] = {0}; +static bool g_has_initialized = false; + +static void EnsureRandomState() { + if (g_has_initialized) { + return; + } + + /* Retrieve process entropy with svcGetInfo. */ + u64 val = 0; + for (unsigned int i = 0; i < 4; i++) { + if (R_FAILED(svcGetInfo(&val, 0xB, 0, i))) { + /* TODO: Panic? */ + } + g_random_state[i] = val & 0xFFFFFFFF; + } + + g_has_initialized = true; +} + +u32 RandomUtils::GetNext() { + EnsureRandomState(); + u32 s, t = g_random_state[3]; + t ^= t << 11; + t ^= t >> 8; + g_random_state[3] = g_random_state[2]; g_random_state[2] = g_random_state[1]; g_random_state[1] = (s = g_random_state[0]); + t ^= s; + t ^= s >> 19; + g_random_state[0] = t; + return t; +} + +/* These are slightly biased, but I think that's totally okay. */ +u32 RandomUtils::GetRandomU32(u32 max) { + return GetNext() % max; +} + +u32 RandomUtils::GetRandomU64(u64 max) { + u64 val = GetNext(); + val |= ((u64)GetNext()) << 32; + return val % max; +} diff --git a/stratosphere/loader/source/ldr_random.hpp b/stratosphere/loader/source/ldr_random.hpp new file mode 100644 index 000000000..63c0911af --- /dev/null +++ b/stratosphere/loader/source/ldr_random.hpp @@ -0,0 +1,9 @@ +#pragma once +#include + +class RandomUtils { + public: + static u32 GetNext(); + static u32 GetRandomU32(u32 max); + static u32 GetRandomU64(u64 max); +}; \ No newline at end of file