Merge upstream Atmosphere master into boot-storage

This commit is contained in:
2026-10-16 20:19:15 +02:00
14 changed files with 178 additions and 98 deletions

View File

@@ -1,4 +1,26 @@
# Changelog
## 1.12.1
+ Support was added for the new c-ares resolver in `dns.mitm`.
+ Firmware 23.0.0 introduced a new set of commands to the `sfdnsres` service. These commands provide c-ares async support for DNS resolution and are now used by most sysmodules.
+ This resulted in host redirection not being applied at all and without warning since we simply were not intercepting the new commands.
+ `dns.mitm` now fully reimplements the c-ares serialization code and intercepts the relevant commands. In tandem with the `bsdsocket` sysmodule, we now keep track of resolution queries and redirect their results.
+ Support was added for the new "BatchRead" storage in `fs.mitm`.
+ Firmware 23.0.0 introduced a new type of filesystem storage object abstracted by the interface "IStorageForBatchRead". This is a derived class from "IStorage" with the purpose of adding the new "BatchRead" command.
+ Anything that uses the filesystem API now attempts to use this type of storage instead of the old one. This is of particular relevance for `qlaunch` and for supporting custom themes which were broken as a consequence of this change.
+ `fs.mitm` was updated and extended to not only support the new storage type but also intercept a few newer commands that were previously missing.
+ The patches for the browser applets were redesigned.
+ The introduction of these patches in the previous release led to several issues and crashes, notably during media playback in the eshop and within games that use LibAppletOff.
+ After extensive analysis and testing it was concluded that the browser applets were running out of memory and still required reducing the memory we reserve for custom sysmodules.
+ New patches have been devised and introduced in this release.
+ Instead of patching size checks, we now trick the browser applets into thinking there is 1GB of free memory available to them.
+ Unused memory is still being reclaimed and discounted from the root heap, but now more realistically.
+ The browser engine's heap is now being shrunk with no noticeable downsides to media playback nor web page rendering.
+ Thanks to these changes we can now provide 40MB for custom system modules once again.
+ A number of minor issues were fixed and improvements were made, such as:
+ Automatic PRODINFO backup was fixed for recent console models that no longer use the ECC device certificate (thanks @chrisbraucker).
+ State initialization for SharedMemory and TransferMemory was fixed (thanks @fl0be).
+ Compatibility was fixed for Trails in the Sky 2nd Chapter (thanks @masagrator).
+ General system stability improvements to enhance the user's experience.
## 1.12.0
+ Support was added for 23.0.0.
+ Special thanks to @alula for handling the implementation of several kernel changes.

4
emummc/.gitrepo vendored
View File

@@ -6,7 +6,7 @@
[subrepo]
remote = https://github.com/m4xw/emummc
branch = develop
commit = 5b966b6f3f83349ec65066a1877f7f948b48d08c
parent = 7442487ace6b79ddddf2cd0007b8dade8150bf5c
commit = 11a2fd2a25a526c9df92506d69da1f679b1bd997
parent = 6eb8c3e7ce4209c60bac362f1b88804318cccad2
method = merge
cmdver = 0.4.9

2
emummc/README.md vendored
View File

@@ -2,7 +2,7 @@
*A SDMMC driver replacement for Nintendo's Filesystem Services, by **m4xw***
### Supported Horizon Versions
**1.0.0 - 23.0.0**
**1.0.0 - 23.0.1**
## Features
* Arbitrary SDMMC backend selection

View File

@@ -6,7 +6,7 @@
[subrepo]
remote = https://github.com/Atmosphere-NX/Atmosphere-libs
branch = master
commit = aae2da0155a490abd3bfd17a70ccd16bb73c916a
parent = c68e08a101353a89777eb118d6bd21d1dba98ce5
commit = cf48d23375cf36742876f4b014971b2ebabc6dc8
parent = ff43bc566adb33c51a43b9ef45b0d3898ad39040
method = merge
cmdver = 0.4.9

View File

@@ -358,9 +358,10 @@ namespace ams::kern::board::nintendo::nx {
/* NOTE: On 20.0.0+ (and even more-so 21.0.0+) the browser requires much more memory in the applet pool in order to function. */
/* Thus, we have to reduce our extra system memory size by 26 MB to compensate. */
/* NOTE: On 23.0.0+ we are patching memory allocation for each browser applet since there are only 3 of them now. */
/* Given that the root "Reserved" region is 0x43E000 bytes and the "ReservedTbd" subregion is 0x540000 bytes, we can safely reclaim 9MB.*/
/* Reclaiming unused memory and lying to the browser about memory limits allows us to go back to 40 MB of extra system memory. */
/* TODO: Deduplicate post 23.0.0 and pre 20.0.0. For now, this structure helps with readability and is still subject to change. */
if (kern::GetTargetFirmware() >= ams::TargetFirmware_23_0_0) {
constexpr size_t ExtraSystemMemoryForAtmosphere_23_0_0 = 16_MB;
constexpr size_t ExtraSystemMemoryForAtmosphere_23_0_0 = 40_MB;
return base_pool_size - ExtraSystemMemoryForAtmosphere_23_0_0 - KTraceBufferSize;
} else if (kern::GetTargetFirmware() >= ams::TargetFirmware_21_0_0) {
constexpr size_t ExtraSystemMemoryForAtmosphere_21_0_0 = 7_MB;

View File

@@ -104,6 +104,7 @@ namespace ams::hos {
Version_22_1_0 = ::ams::TargetFirmware_22_1_0,
Version_22_5_0 = ::ams::TargetFirmware_22_5_0,
Version_23_0_0 = ::ams::TargetFirmware_23_0_0,
Version_23_0_1 = ::ams::TargetFirmware_23_0_1,
Version_Current = ::ams::TargetFirmware_Current,

View File

@@ -167,8 +167,13 @@ namespace ams::socket {
int ai_family;
int ai_socktype;
int ai_protocol;
#if defined(ATMOSPHERE_OS_WINDOWS)
int ai_addrlen;
void *ai_addr;
#else
socklen_t ai_addrlen;
struct sockaddr *ai_addr;
#endif
struct ares_addrinfo_node *ai_next;
};

View File

@@ -46857,14 +46857,18 @@ size_t ZSTD_decompressBlock(ZSTD_DCtx* dctx,
/*-*************************************
* Dependencies
***************************************/
/* qsort_r is an extension. */
#if defined(__linux) || defined(__linux__) || defined(linux) || defined(__gnu_linux__) || \
defined(__CYGWIN__) || defined(__MSYS__)
#if !defined(_GNU_SOURCE) && !defined(__ANDROID__) /* NDK doesn't ship qsort_r(). */
#define _GNU_SOURCE
#endif
/* qsort_r is an extension.
*
* Android NDK does not ship qsort_r().
*/
#if (defined(__linux__) && !defined(__ANDROID__)) || defined(__CYGWIN__) || defined(__MSYS__)
# ifndef _GNU_SOURCE
# define _GNU_SOURCE
# endif
#endif
#define __STDC_WANT_LIB_EXT1__ 1 /* request C11 Annex K, which includes qsort_s() */
#include <stdio.h> /* fprintf */
#include <stdlib.h> /* malloc, free, qsort_r */
@@ -46875,6 +46879,7 @@ size_t ZSTD_decompressBlock(ZSTD_DCtx* dctx,
# define ZDICT_STATIC_LINKING_ONLY
#endif
/**** skipping file: ../common/debug.h ****/
/**** skipping file: ../common/mem.h ****/
/**** skipping file: ../common/pool.h ****/
/**** skipping file: ../common/threading.h ****/
@@ -47531,6 +47536,31 @@ void COVER_dictSelectionFree(COVER_dictSelection_t selection);
#define COVER_MAX_SAMPLES_SIZE (sizeof(size_t) == 8 ? ((unsigned)-1) : ((unsigned)1 GB))
#define COVER_DEFAULT_SPLITPOINT 1.0
/**
* Select the qsort() variant used by cover
*/
#define ZDICT_QSORT_MIN 0
#define ZDICT_QSORT_C90 ZDICT_QSORT_MIN
#define ZDICT_QSORT_GNU 1
#define ZDICT_QSORT_APPLE 2
#define ZDICT_QSORT_MSVC 3
#define ZDICT_QSORT_C11 ZDICT_QSORT_MAX
#define ZDICT_QSORT_MAX 4
#ifndef ZDICT_QSORT
# if defined(__APPLE__)
# define ZDICT_QSORT ZDICT_QSORT_APPLE /* uses qsort_r() with a different order for parameters */
# elif (defined(__linux__) && !defined(__ANDROID__)) || defined(__CYGWIN__) || defined(__MSYS__)
# define ZDICT_QSORT ZDICT_QSORT_GNU /* uses qsort_r() */
# elif defined(_WIN32) && defined(_MSC_VER)
# define ZDICT_QSORT ZDICT_QSORT_MSVC /* uses qsort_s() with a different order for parameters */
# elif defined(STDC_LIB_EXT1) && (STDC_LIB_EXT1 > 0) /* C11 Annex K */
# define ZDICT_QSORT ZDICT_QSORT_C11 /* uses qsort_s() */
# else
# define ZDICT_QSORT ZDICT_QSORT_C90 /* uses standard qsort() which is not re-entrant (requires global variable) */
# endif
#endif
/*-*************************************
* Console display
***************************************/
@@ -47712,8 +47742,8 @@ typedef struct {
unsigned d;
} COVER_ctx_t;
#if !defined(_GNU_SOURCE) && !defined(__APPLE__) && !defined(_MSC_VER)
/* C90 only offers qsort() that needs a global context. */
#if ZDICT_QSORT == ZDICT_QSORT_C90
/* Use global context for non-reentrant sort functions */
static COVER_ctx_t *g_coverCtx = NULL;
#endif
@@ -47759,9 +47789,9 @@ static int COVER_cmp8(COVER_ctx_t *ctx, const void *lp, const void *rp) {
/**
* Same as COVER_cmp() except ties are broken by pointer value
*/
#if (defined(_WIN32) && defined(_MSC_VER)) || defined(__APPLE__)
#if (ZDICT_QSORT == ZDICT_QSORT_MSVC) || (ZDICT_QSORT == ZDICT_QSORT_APPLE)
static int WIN_CDECL COVER_strict_cmp(void* g_coverCtx, const void* lp, const void* rp) {
#elif defined(_GNU_SOURCE)
#elif (ZDICT_QSORT == ZDICT_QSORT_GNU) || (ZDICT_QSORT == ZDICT_QSORT_C11)
static int COVER_strict_cmp(const void *lp, const void *rp, void *g_coverCtx) {
#else /* C90 fallback.*/
static int COVER_strict_cmp(const void *lp, const void *rp) {
@@ -47775,9 +47805,9 @@ static int COVER_strict_cmp(const void *lp, const void *rp) {
/**
* Faster version for d <= 8.
*/
#if (defined(_WIN32) && defined(_MSC_VER)) || defined(__APPLE__)
#if (ZDICT_QSORT == ZDICT_QSORT_MSVC) || (ZDICT_QSORT == ZDICT_QSORT_APPLE)
static int WIN_CDECL COVER_strict_cmp8(void* g_coverCtx, const void* lp, const void* rp) {
#elif defined(_GNU_SOURCE)
#elif (ZDICT_QSORT == ZDICT_QSORT_GNU) || (ZDICT_QSORT == ZDICT_QSORT_C11)
static int COVER_strict_cmp8(const void *lp, const void *rp, void *g_coverCtx) {
#else /* C90 fallback.*/
static int COVER_strict_cmp8(const void *lp, const void *rp) {
@@ -47794,26 +47824,28 @@ static int COVER_strict_cmp8(const void *lp, const void *rp) {
* Hopefully when C11 become the norm, we will be able
* to clean it up.
*/
static void stableSort(COVER_ctx_t *ctx) {
#if defined(__APPLE__)
static void stableSort(COVER_ctx_t *ctx)
{
DEBUG_STATIC_ASSERT(ZDICT_QSORT_MIN <= ZDICT_QSORT && ZDICT_QSORT <= ZDICT_QSORT_MAX);
#if (ZDICT_QSORT == ZDICT_QSORT_APPLE)
qsort_r(ctx->suffix, ctx->suffixSize, sizeof(U32),
ctx,
(ctx->d <= 8 ? &COVER_strict_cmp8 : &COVER_strict_cmp));
#elif defined(_GNU_SOURCE)
#elif (ZDICT_QSORT == ZDICT_QSORT_GNU)
qsort_r(ctx->suffix, ctx->suffixSize, sizeof(U32),
(ctx->d <= 8 ? &COVER_strict_cmp8 : &COVER_strict_cmp),
ctx);
#elif defined(_WIN32) && defined(_MSC_VER)
#elif (ZDICT_QSORT == ZDICT_QSORT_MSVC)
qsort_s(ctx->suffix, ctx->suffixSize, sizeof(U32),
(ctx->d <= 8 ? &COVER_strict_cmp8 : &COVER_strict_cmp),
ctx);
#elif (ZDICT_QSORT == ZDICT_QSORT_C11)
qsort_s(ctx->suffix, ctx->suffixSize, sizeof(U32),
(ctx->d <= 8 ? &COVER_strict_cmp8 : &COVER_strict_cmp),
ctx);
#elif defined(__OpenBSD__)
g_coverCtx = ctx;
mergesort(ctx->suffix, ctx->suffixSize, sizeof(U32),
(ctx->d <= 8 ? &COVER_strict_cmp8 : &COVER_strict_cmp));
#else /* C90 fallback.*/
g_coverCtx = ctx;
/* TODO(cavalcanti): implement a reentrant qsort() when is not available. */
/* TODO(cavalcanti): implement a reentrant qsort() when _r is not available. */
qsort(ctx->suffix, ctx->suffixSize, sizeof(U32),
(ctx->d <= 8 ? &COVER_strict_cmp8 : &COVER_strict_cmp));
#endif

View File

@@ -17,10 +17,10 @@
#define ATMOSPHERE_RELEASE_VERSION_MAJOR 1
#define ATMOSPHERE_RELEASE_VERSION_MINOR 12
#define ATMOSPHERE_RELEASE_VERSION_MICRO 0
#define ATMOSPHERE_RELEASE_VERSION_MICRO 1
#define ATMOSPHERE_RELEASE_VERSION ATMOSPHERE_RELEASE_VERSION_MAJOR, ATMOSPHERE_RELEASE_VERSION_MINOR, ATMOSPHERE_RELEASE_VERSION_MICRO
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MAJOR 23
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MINOR 0
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MICRO 0
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MICRO 1

View File

@@ -102,8 +102,9 @@
#define ATMOSPHERE_TARGET_FIRMWARE_22_1_0 ATMOSPHERE_TARGET_FIRMWARE(22, 1, 0)
#define ATMOSPHERE_TARGET_FIRMWARE_22_5_0 ATMOSPHERE_TARGET_FIRMWARE(22, 5, 0)
#define ATMOSPHERE_TARGET_FIRMWARE_23_0_0 ATMOSPHERE_TARGET_FIRMWARE(23, 0, 0)
#define ATMOSPHERE_TARGET_FIRMWARE_23_0_1 ATMOSPHERE_TARGET_FIRMWARE(23, 0, 1)
#define ATMOSPHERE_TARGET_FIRMWARE_CURRENT ATMOSPHERE_TARGET_FIRMWARE_23_0_0
#define ATMOSPHERE_TARGET_FIRMWARE_CURRENT ATMOSPHERE_TARGET_FIRMWARE_23_0_1
#define ATMOSPHERE_TARGET_FIRMWARE_MIN ATMOSPHERE_TARGET_FIRMWARE(0, 0, 0)
#define ATMOSPHERE_TARGET_FIRMWARE_MAX ATMOSPHERE_TARGET_FIRMWARE_CURRENT
@@ -198,6 +199,7 @@ namespace ams {
TargetFirmware_22_1_0 = ATMOSPHERE_TARGET_FIRMWARE_22_1_0,
TargetFirmware_22_5_0 = ATMOSPHERE_TARGET_FIRMWARE_22_5_0,
TargetFirmware_23_0_0 = ATMOSPHERE_TARGET_FIRMWARE_23_0_0,
TargetFirmware_23_0_1 = ATMOSPHERE_TARGET_FIRMWARE_23_0_1,
TargetFirmware_Current = ATMOSPHERE_TARGET_FIRMWARE_CURRENT,

View File

@@ -256,7 +256,6 @@ namespace ams::mitm {
bool IsValid(const CalibrationInfo &cal) {
return IsValidHeader(cal) &&
IsValid(cal.GetBlock<SerialNumberBlock>()) &&
IsValid(cal.GetBlock<EccB233DeviceCertificateBlock>()) &&
IsValid(cal.GetBlock<SslKeyBlock>()) &&
IsValid(cal.GetBlock<SslCertificateSizeBlock>()) &&
cal.GetBlock<SslCertificateSizeBlock>().ssl_certificate_size <= sizeof(cal.GetBlock<SslCertificateBlock>().ssl_certificate) &&
@@ -267,7 +266,8 @@ namespace ams::mitm {
IsValidSerialNumber(cal);
}
bool ContainsCorrectDeviceId(const EccB233DeviceCertificateBlock &block, u64 device_id) {
template<typename Block>
bool ContainsCorrectDeviceId(const Block &block, u64 device_id) {
static constexpr size_t DeviceIdOffset = 0xC6;
char found_device_id_str[sizeof("0011223344556677")] = {};
ON_SCOPE_EXIT { std::memset(found_device_id_str, 0, sizeof(found_device_id_str)); };
@@ -279,7 +279,14 @@ namespace ams::mitm {
}
bool ContainsCorrectDeviceId(const CalibrationInfo &cal) {
return ContainsCorrectDeviceId(cal.GetBlock<EccB233DeviceCertificateBlock>(), exosphere::GetDeviceId());
const auto &ecc = cal.GetBlock<EccB233DeviceCertificateBlock>();
if (!IsBlank(ecc)) {
return IsValid(ecc) && ContainsCorrectDeviceId(ecc, exosphere::GetDeviceId());
}
/* Newer consoles may leave the ECC certificate unprogrammed. */
const auto &rsa = cal.GetBlock<Rsa2048DeviceCertificateBlock>();
return !IsBlank(rsa) && IsValid(rsa) && ContainsCorrectDeviceId(rsa, exosphere::GetDeviceId());
}
bool IsValidForSecureBackup(const CalibrationInfo &cal) {

View File

@@ -28,11 +28,11 @@ namespace ams::mitm::socket::resolver {
std::string hostname;
ams::socket::InAddrT redirect_addr;
u16 redirect_port;
const struct ams::socket::ares_addrinfo_hints *hint;
bool use_hint;
struct ams::socket::ares_addrinfo_hints hint;
};
std::map<ssize_t, std::unique_ptr<AresAddrInfoQuery>> g_ares_addr_info_queries;
ssize_t g_current_ares_addr_info_query_id;
}
@@ -100,21 +100,17 @@ namespace ams::mitm::socket::resolver {
return result;
}
ssize_t QueueAresAddrInfoQuery(const char *hostname, ams::socket::InAddrT redirect_addr, u16 redirect_port, const struct ams::socket::ares_addrinfo_hints *hint) {
ssize_t query_id = g_current_ares_addr_info_query_id;
void QueueAresAddrInfoQuery(ssize_t query_id, const char *hostname, ams::socket::InAddrT redirect_addr, u16 redirect_port, const struct ams::socket::ares_addrinfo_hints *hint) {
AresAddrInfoQuery query;
query.hostname = hostname;
query.redirect_addr = redirect_addr;
query.redirect_port = redirect_port;
query.hint = hint;
query.use_hint = hint != nullptr;
if (query.use_hint) {
query.hint = *hint;
}
g_ares_addr_info_queries.emplace(query_id, std::make_unique<AresAddrInfoQuery>(query));
/* NOTE: This really just increases ad infinitum. Should we bother checking it? */
++g_current_ares_addr_info_query_id;
return query_id;
}
ssize_t DequeueAresAddrInfoQuery(u8 * const dst, size_t dst_size, u32 query_id) {
@@ -128,7 +124,7 @@ namespace ams::mitm::socket::resolver {
}
if (query == nullptr) {
return 0;
return -1;
}
struct ams::socket::ares_addrinfo_node node = {
@@ -141,8 +137,8 @@ namespace ams::mitm::socket::resolver {
.ai_next = nullptr,
};
if (query->hint != nullptr) {
std::memcpy(reinterpret_cast<void *>(std::addressof(node.ai_flags)), reinterpret_cast<const void *>(query->hint), sizeof(struct ams::socket::ares_addrinfo_hints));
if (query->use_hint) {
std::memcpy(std::addressof(node.ai_flags), std::addressof(query->hint), sizeof(query->hint));
}
switch (node.ai_family) {
@@ -178,17 +174,19 @@ namespace ams::mitm::socket::resolver {
const auto result = serializer::DNSSerializer::ToBuffer(dst, dst_size, ai);
AMS_ABORT_UNLESS(result >= 0);
g_ares_addr_info_queries.erase(query_id);
g_ares_addr_info_queries.erase(static_cast<ssize_t>(query_id));
return result;
}
void CancelAresAddrInfoQuery(u32 query_id) {
bool CancelAresAddrInfoQuery(u32 query_id) {
for (auto it = g_ares_addr_info_queries.begin(); it != g_ares_addr_info_queries.end(); ++it) {
if (it->first == static_cast<ssize_t>(query_id)) {
g_ares_addr_info_queries.erase(it);
break;
return true;
}
}
return false;
}
Result ResolverImpl::GetHostByNameRequest(u32 cancel_handle, const sf::ClientProcessId &client_pid, bool use_nsd_resolve, const sf::InBuffer &name, sf::Out<u32> out_host_error, sf::Out<u32> out_errno, const sf::OutBuffer &out_hostent, sf::Out<u32> out_size) {
@@ -321,8 +319,6 @@ namespace ams::mitm::socket::resolver {
}
Result ResolverImpl::QueryAddrInfoRequestWithOptions(const sf::ClientProcessId &client_pid, const sf::InAutoSelectBuffer &node, const sf::InAutoSelectBuffer &srv, const sf::InAutoSelectBuffer &serialized_hint, sf::Out<u32> out_query_id, u32 fd, u32 options_version, const sf::InAutoSelectBuffer &options, u32 num_options, sf::Out<s32> out_retval, sf::Out<s32> out_errno) {
AMS_UNUSED(client_pid, fd, options_version, options, num_options);
const char *hostname = reinterpret_cast<const char *>(node.GetPointer());
LogDebug("[%016lx]: QueryAddrInfoRequestWithOptions(%s, %s)\n", m_client_info.program_id.value, hostname, reinterpret_cast<const char *>(srv.GetPointer()));
@@ -341,7 +337,7 @@ namespace ams::mitm::socket::resolver {
}
}
LogDebug("[%016lx]: Queueing redirection %s:%u to %u.%u.%u.%u\n", m_client_info.program_id.value, hostname, port, (redirect_addr >> 0) & 0xFF, (redirect_addr >> 8) & 0xFF, (redirect_addr >> 16) & 0xFF, (redirect_addr >> 24) & 0xFF);
LogDebug("[%016lx]: Queueing query for redirecting %s:%u to %u.%u.%u.%u\n", m_client_info.program_id.value, hostname, port, (redirect_addr >> 0) & 0xFF, (redirect_addr >> 8) & 0xFF, (redirect_addr >> 16) & 0xFF, (redirect_addr >> 24) & 0xFF);
const bool use_hint = serialized_hint.GetPointer() != nullptr;
struct ams::socket::ares_addrinfo_hints hint = {};
@@ -349,30 +345,39 @@ namespace ams::mitm::socket::resolver {
AMS_ABORT_UNLESS(serializer::DNSSerializer::FromBuffer(hint, serialized_hint.GetPointer(), serialized_hint.GetSize()) >= 0);
}
const auto query_id = QueueAresAddrInfoQuery(hostname, redirect_addr, port, use_hint ? std::addressof(hint) : nullptr);
LogDebug("[%016lx]: Queued query with id 0x%lx\n", m_client_info.program_id.value, query_id);
/* Forward the query. The provided socket EventFd must be signalled by having bsdsocket write 1 to the associated socket. */
/* This is fine though, we only care about replacing with our redirection during fetch. */
/* Forward to session. The provided socket EventFd must be signalled by having bsdsocket write 1 to the associated socket. */
/* This is fine though, we only care about replacing with our redirection during fetch. */
/* Additionally, a failure at this point can be safely handled by bsdsocket, it simply won't create a new query. */
R_TRY(sfdnsresQueryAddrInfoRequestWithOptionsFwd(m_forward_service.get(), static_cast<u64>(client_pid.GetValue().value), node.GetPointer(), node.GetSize(), srv.GetPointer(), srv.GetSize(), serialized_hint.GetPointer(), serialized_hint.GetSize(), reinterpret_cast<u32 *>(out_query_id.GetPointer()), fd, options_version, options.GetPointer(), options.GetSize(), num_options, reinterpret_cast<s32 *>(out_retval.GetPointer()), reinterpret_cast<s32 *>(out_errno.GetPointer())));
/* Replace with our own query. */
*out_query_id = query_id;
*out_retval = 0;
*out_errno = 0;
/* If no errors were returned, trust the id bsdsocket generated and queue the query. */
/* When bsdsocket's queue is full, retval and errno will reflect that and the returned query id will be -1. */
/* This is expected by the client. We must drop this query and let the client see the errors for it to schedule a new query. */
if ((*out_retval == 0) && (*out_errno == 0)) {
ssize_t query_id = static_cast<ssize_t>(*out_query_id);
QueueAresAddrInfoQuery(query_id, hostname, redirect_addr, port, use_hint ? std::addressof(hint) : nullptr);
LogDebug("[%016lx]: Queued query with id 0x%lx\n", m_client_info.program_id.value, query_id);
} else {
LogDebug("[%016lx]: Dropping last query, queue is full\n", m_client_info.program_id.value);
}
R_SUCCEED();
}
Result ResolverImpl::FetchAddrInfoRequestWithOptions(const sf::ClientProcessId &client_pid, u32 query_id, u32 version, const sf::OutAutoSelectBuffer &out_addrinfo, sf::Out<u32> out_size, sf::Out<s32> out_retval, sf::Out<s32> out_errno) {
AMS_UNUSED(client_pid, version);
LogDebug("[%016lx]: FetchAddrInfoRequestWithOptions(%d)\n", m_client_info.program_id.value, query_id);
LogDebug("[%016lx]: FetchAddrInfoRequestWithOptions(0x%x)\n", m_client_info.program_id.value, query_id);
const auto size = DequeueAresAddrInfoQuery(out_addrinfo.GetPointer(), out_addrinfo.GetSize(), query_id);
/* If we don't have this query queued, then the hostname is not in the hosts file. Forward to session. */
R_UNLESS(size >= 0, sm::mitm::ResultShouldForwardToSession());
LogDebug("[%016lx]: Dequeued query with size 0x%lx\n", m_client_info.program_id.value, size);
LogDebug("[%016lx]: Dequeued query 0x%x with size 0x%lx\n", m_client_info.program_id.value, query_id, size);
/* Forward to session. The socket EventFd associated with this query must be cleared by having bsdsocket write 0 to the socket. */
/* However, we want to keep our redirection, so we pass nullptr to bsdsocket forcing the command to end early with an error. */
/* We discard the error and replace the output, pretending the command was successful while returning our redirected addrinfo to the client instead. */
R_DISCARD(sfdnsresFetchAddrInfoRequestWithOptionsFwd(m_forward_service.get(), static_cast<u64>(client_pid.GetValue().value), query_id, version, nullptr, 0, reinterpret_cast<u32 *>(out_size.GetPointer()), reinterpret_cast<s32 *>(out_retval.GetPointer()), reinterpret_cast<s32 *>(out_errno.GetPointer())));
*out_size = size;
*out_retval = 0;
@@ -382,11 +387,18 @@ namespace ams::mitm::socket::resolver {
}
Result ResolverImpl::CancelQuery(const sf::ClientProcessId &client_pid, u32 query_id) {
AMS_UNUSED(client_pid);
LogDebug("[%016lx]: CancelQuery(%d)\n", m_client_info.program_id.value, query_id);
LogDebug("[%016lx]: CancelQuery(0x%x)\n", m_client_info.program_id.value, query_id);
CancelAresAddrInfoQuery(query_id);
const auto found = CancelAresAddrInfoQuery(query_id);
/* If we don't have this query queued, then we never intercepted it. Forward to session. */
R_UNLESS(found, sm::mitm::ResultShouldForwardToSession());
LogDebug("[%016lx]: Cancelled query 0x%x\n", m_client_info.program_id.value, query_id);
/* Forward to session. Ensures that bsdsocket cleans up. */
/* We still want to discard any errors and return success in case this was a query we had queued. */
R_DISCARD(sfdnsresCancelQueryFwd(m_forward_service.get(), static_cast<u64>(client_pid.GetValue().value), query_id));
R_SUCCEED();
}

View File

@@ -51,10 +51,12 @@ namespace ams::mitm::fs {
/* Unknown heap sensitivity. */
{ 0x01002C9022770000, 16_MB, 0_MB },
/* Trails in the Sky 2nd Chapter. */
/* Trails in the Sky 2nd Chapter (Global, Asia and Japan versions). */
/* Requirement ~16 MB.*/
/* No particular heap sensitivity. */
{ 0x01007A2027548000, 8_MB, 0_MB },
{ 0x0100E8B028B54000, 8_MB, 0_MB },
{ 0x01002270268E0000, 8_MB, 0_MB },
/* STAR WARS: Knights of the Old Republic II: The Sith Lords. */
/* Requirement ? MB. 16 MB stolen heap fixes a crash, though. */

View File

@@ -15,41 +15,37 @@
*/
/* Breakdown of each patch in order: */
/* #1 - Patch the 0xDEEF000 size check branch to NOP. */
/* #1 - Set TotalAvailableMemorySize to 1GB. */
/* #2 - Change the root heap "Reserved" region allocation size from 0x43E000 to 0. */
/* #3 - Change the root heap "Scene" size from 0x4580000 to 0x4040000. */
/* #4 - Change the scene heap "ReservedTbd" region allocation size from 0x540000 to 0. */
/* #5 - Patch the linking of "ReservedTbd" to the parent heap with a NOP. */
/* #6 - Patch the initial memory block allocation size from 0xB400000 to 0xAC00000. */
/* #7 - Patch the initial memory block initialization size from 0xB400000 to 0xAC00000. */
/* #3 - Patch the initial memory block allocation size from 0xB400000 to 0xB000000. */
/* #4 - Patch the initial memory block heap size from 0xB400000 to 0xB000000. */
/* #5 - Patch the browser engine memory capacity from 0xAA00000 to 0x9000000. */
/* #6 - Patch the browser engine memory allocation size from 0xAA00000 to 0x9000000. */
constexpr inline const EmbeddedPatchEntry SystemWebMemoryPatches_23_0_0[] = {
{ 0x861DD4, "\x1F\x20\x03\xD5", 4 },
{ 0x6113A8, "\x09\x00\xA8\xD2", 4 },
{ 0x861E80, "\x02\x00\x80\x52", 4 },
{ 0x861E6C, "\x82\x80\xA0\x52", 4 },
{ 0x8C1718, "\x02\x00\x80\x52", 4 },
{ 0x8C172C, "\x1F\x20\x03\xD5", 4 },
{ 0x861D44, "\x01\x58\xA1\x52", 4 },
{ 0x861D5C, "\x03\x58\xA1\x52", 4 },
{ 0x861D44, "\x01\x60\xA1\x52", 4 },
{ 0x861D5C, "\x03\x60\xA1\x52", 4 },
{ 0x8623D0, "\x01\x20\xA1\x52", 4 },
{ 0x862498, "\x01\x20\xA1\x52", 4 },
};
constexpr inline const EmbeddedPatchEntry OpenWebMemoryPatches_23_0_0[] = {
{ 0x828DBC, "\x1F\x20\x03\xD5", 4 },
{ 0x611428, "\x09\x00\xA8\xD2", 4 },
{ 0x828E68, "\x02\x00\x80\x52", 4 },
{ 0x828E54, "\x82\x80\xA0\x52", 4 },
{ 0x74C564, "\x02\x00\x80\x52", 4 },
{ 0x74C578, "\x1F\x20\x03\xD5", 4 },
{ 0x828D2C, "\x01\x58\xA1\x52", 4 },
{ 0x828D44, "\x03\x58\xA1\x52", 4 },
{ 0x828D2C, "\x01\x60\xA1\x52", 4 },
{ 0x828D44, "\x03\x60\xA1\x52", 4 },
{ 0x8293B8, "\x01\x20\xA1\x52", 4 },
{ 0x829480, "\x01\x20\xA1\x52", 4 },
};
constexpr inline const EmbeddedPatchEntry OfflineWebMemoryPatches_23_0_0[] = {
{ 0x130698, "\x1F\x20\x03\xD5", 4 },
{ 0x6DE0DC, "\x09\x00\xA8\xD2", 4 },
{ 0x130744, "\x02\x00\x80\x52", 4 },
{ 0x130730, "\x82\x80\xA0\x52", 4 },
{ 0x4D728, "\x02\x00\x80\x52", 4 },
{ 0x4D738, "\x1F\x20\x03\xD5", 4 },
{ 0x130614, "\x01\x58\xA1\x52", 4 },
{ 0x130624, "\x02\x58\xA1\x52", 4 },
{ 0x130614, "\x01\x60\xA1\x52", 4 },
{ 0x130624, "\x02\x60\xA1\x52", 4 },
{ 0x130C30, "\x01\x20\xA1\x52", 4 },
{ 0x130CD0, "\x01\x20\xA1\x52", 4 },
};
constexpr inline const EmbeddedPatch WebMemoryPatches[] = {