mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2024-11-22 20:06:40 +00:00
Merge branch 'bis_protect'
This commit is contained in:
commit
7bc95f35d7
23 changed files with 1012 additions and 49 deletions
3
Makefile
3
Makefile
|
@ -48,7 +48,8 @@ dist: all
|
|||
cp stratosphere/creport/creport.nsp atmosphere-$(AMSVER)/atmosphere/titles/0100000000000036/exefs.nsp
|
||||
cp stratosphere/fatal/fatal.nsp atmosphere-$(AMSVER)/atmosphere/titles/0100000000000034/exefs.nsp
|
||||
cp stratosphere/set_mitm/set_mitm.nsp atmosphere-$(AMSVER)/atmosphere/titles/0100000000000032/exefs.nsp
|
||||
touch atmosphere-$(AMSVER)/atmosphere/titles/0100000000000032/boot2.flag
|
||||
mkdir -p atmosphere-$(AMSVER)/atmosphere/titles/0100000000000032/flags
|
||||
touch atmosphere-$(AMSVER)/atmosphere/titles/0100000000000032/flags/boot2.flag
|
||||
cd atmosphere-$(AMSVER); zip -r ../atmosphere-$(AMSVER).zip ./*; cd ../;
|
||||
rm -r atmosphere-$(AMSVER)
|
||||
mkdir out
|
||||
|
|
|
@ -61,7 +61,6 @@ class IStorageInterface : public IServiceObject {
|
|||
};
|
||||
virtual Result Write(InBuffer<u8, BufferType_Type1> buffer, u64 offset, u64 size) final {
|
||||
return this->base_storage->Write(buffer.buffer, std::min(buffer.num_elements, size), offset);
|
||||
|
||||
};
|
||||
virtual Result Flush() final {
|
||||
return this->base_storage->Flush();
|
||||
|
@ -108,3 +107,65 @@ class IROStorage : public IStorage {
|
|||
virtual Result GetSize(u64 *out_size) = 0;
|
||||
virtual Result OperateRange(u32 operation_type, u64 offset, u64 size, FsRangeInfo *out_range_info) = 0;
|
||||
};
|
||||
|
||||
|
||||
class ProxyStorage : public IStorage {
|
||||
private:
|
||||
FsStorage *base_storage;
|
||||
public:
|
||||
ProxyStorage(FsStorage *s) : base_storage(s) {
|
||||
/* ... */
|
||||
};
|
||||
ProxyStorage(FsStorage s) {
|
||||
this->base_storage = new FsStorage(s);
|
||||
};
|
||||
virtual ~ProxyStorage() {
|
||||
fsStorageClose(base_storage);
|
||||
delete base_storage;
|
||||
};
|
||||
public:
|
||||
virtual Result Read(void *buffer, size_t size, u64 offset) override {
|
||||
return fsStorageRead(this->base_storage, offset, buffer, size);
|
||||
};
|
||||
virtual Result Write(void *buffer, size_t size, u64 offset) override {
|
||||
return fsStorageWrite(this->base_storage, offset, buffer, size);
|
||||
};
|
||||
virtual Result Flush() override {
|
||||
return fsStorageFlush(this->base_storage);
|
||||
};
|
||||
virtual Result GetSize(u64 *out_size) override {
|
||||
return fsStorageGetSize(this->base_storage, out_size);
|
||||
};
|
||||
virtual Result SetSize(u64 size) override {
|
||||
return fsStorageSetSize(this->base_storage, size);
|
||||
};
|
||||
virtual Result OperateRange(u32 operation_type, u64 offset, u64 size, FsRangeInfo *out_range_info) override {
|
||||
return fsStorageOperateRange(this->base_storage, operation_type, offset, size, out_range_info);
|
||||
};
|
||||
};
|
||||
|
||||
class ROProxyStorage : public IROStorage {
|
||||
private:
|
||||
FsStorage *base_storage;
|
||||
public:
|
||||
ROProxyStorage(FsStorage *s) : base_storage(s) {
|
||||
/* ... */
|
||||
};
|
||||
ROProxyStorage(FsStorage s) {
|
||||
this->base_storage = new FsStorage(s);
|
||||
};
|
||||
virtual ~ROProxyStorage() {
|
||||
fsStorageClose(base_storage);
|
||||
delete base_storage;
|
||||
};
|
||||
public:
|
||||
virtual Result Read(void *buffer, size_t size, u64 offset) override {
|
||||
return fsStorageRead(this->base_storage, offset, buffer, size);
|
||||
};
|
||||
virtual Result GetSize(u64 *out_size) override {
|
||||
return fsStorageGetSize(this->base_storage, out_size);
|
||||
};
|
||||
virtual Result OperateRange(u32 operation_type, u64 offset, u64 size, FsRangeInfo *out_range_info) override {
|
||||
return fsStorageOperateRange(this->base_storage, operation_type, offset, size, out_range_info);
|
||||
};
|
||||
};
|
|
@ -18,6 +18,44 @@
|
|||
#include "fs_shim.h"
|
||||
|
||||
/* Missing fsp-srv commands. */
|
||||
Result fsOpenBisStorageFwd(Service* s, FsStorage* out, u32 PartitionId) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u32 PartitionId;
|
||||
} *raw;
|
||||
|
||||
raw = serviceIpcPrepareHeader(s, &c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 12;
|
||||
raw->PartitionId = PartitionId;
|
||||
|
||||
Result rc = serviceIpcDispatch(s);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp;
|
||||
|
||||
serviceIpcParse(s, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
serviceCreateSubservice(&out->s, s, &r, 0);
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result fsOpenDataStorageByCurrentProcessFwd(Service* s, FsStorage* out) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
|
|
@ -17,6 +17,7 @@ typedef struct {
|
|||
} FsRangeInfo;
|
||||
|
||||
/* Missing fsp-srv commands. */
|
||||
Result fsOpenBisStorageFwd(Service* s, FsStorage* out, u32 PartitionId);
|
||||
Result fsOpenDataStorageByCurrentProcessFwd(Service* s, FsStorage* out);
|
||||
Result fsOpenDataStorageByDataIdFwd(Service* s, FsStorageId storage_id, u64 data_id, FsStorage* out);
|
||||
|
||||
|
|
108
stratosphere/fs_mitm/source/fsmitm_boot0storage.cpp
Normal file
108
stratosphere/fs_mitm/source/fsmitm_boot0storage.cpp
Normal file
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <switch.h>
|
||||
#include <cstring>
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
#include "fsmitm_boot0storage.hpp"
|
||||
|
||||
static HosMutex g_boot0_mutex;
|
||||
static u8 g_boot0_bct_buffer[Boot0Storage::BctEndOffset];
|
||||
|
||||
bool Boot0Storage::CanModifyBctPubks() {
|
||||
return this->title_id != 0x010000000000001FULL;
|
||||
}
|
||||
|
||||
Result Boot0Storage::Read(void *_buffer, size_t size, u64 offset) {
|
||||
std::scoped_lock<HosMutex> lk{g_boot0_mutex};
|
||||
|
||||
return Base::Read(_buffer, size, offset);
|
||||
}
|
||||
|
||||
Result Boot0Storage::Write(void *_buffer, size_t size, u64 offset) {
|
||||
std::scoped_lock<HosMutex> lk{g_boot0_mutex};
|
||||
|
||||
Result rc = 0;
|
||||
u8 *buffer = static_cast<u8 *>(_buffer);
|
||||
|
||||
/* Protect the keyblob region from writes. */
|
||||
if (offset <= EksStart) {
|
||||
if (offset + size < EksStart) {
|
||||
/* Fall through, no need to do anything here. */
|
||||
} else {
|
||||
if (offset + size < EksEnd) {
|
||||
/* Adjust size to avoid writing end of data. */
|
||||
size = EksStart - offset;
|
||||
} else {
|
||||
/* Perform portion of write falling past end of keyblobs. */
|
||||
const u64 diff = EksEnd - offset;
|
||||
if (R_FAILED((rc = Base::Write(buffer + diff, size - diff, EksEnd)))) {
|
||||
return rc;
|
||||
}
|
||||
/* Adjust size to avoid writing end of data. */
|
||||
size = EksStart - offset;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (offset < EksEnd) {
|
||||
if (offset + size < EksEnd) {
|
||||
/* Ignore writes falling strictly within the region. */
|
||||
return 0;
|
||||
} else {
|
||||
/* Only write past the end of the keyblob region. */
|
||||
buffer = buffer + (EksEnd - offset);
|
||||
size -= (EksEnd - offset);
|
||||
offset = EksEnd;
|
||||
}
|
||||
} else {
|
||||
/* Fall through, no need to do anything here. */
|
||||
}
|
||||
}
|
||||
|
||||
if (size == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* We care about protecting autorcm from NS. */
|
||||
if (CanModifyBctPubks() || offset >= BctEndOffset || (offset + BctSize >= BctEndOffset && offset % BctSize >= BctPubkEnd)) {
|
||||
return Base::Write(buffer, size, offset);
|
||||
}
|
||||
|
||||
/* First, let's deal with the data past the end. */
|
||||
if (offset + size >= BctEndOffset) {
|
||||
const u64 diff = BctEndOffset - offset;
|
||||
if (R_FAILED((rc = ProxyStorage::Write(buffer + diff, size - diff, BctEndOffset)))) {
|
||||
return rc;
|
||||
}
|
||||
size -= diff;
|
||||
}
|
||||
|
||||
/* Read in the current BCT region. */
|
||||
if (R_FAILED((rc = ProxyStorage::Read(g_boot0_bct_buffer, BctEndOffset, 0)))) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Update the bct buffer. */
|
||||
for (u64 cur_ofs = offset; cur_ofs < BctEndOffset && cur_ofs < offset + size; cur_ofs++) {
|
||||
const u64 cur_bct_rel_ofs = cur_ofs % BctSize;
|
||||
if (cur_bct_rel_ofs < BctPubkStart || BctPubkEnd <= cur_bct_rel_ofs) {
|
||||
g_boot0_bct_buffer[cur_ofs] = buffer[cur_ofs - offset];
|
||||
}
|
||||
}
|
||||
|
||||
return ProxyStorage::Write(g_boot0_bct_buffer, BctEndOffset, 0);
|
||||
}
|
159
stratosphere/fs_mitm/source/fsmitm_boot0storage.hpp
Normal file
159
stratosphere/fs_mitm/source/fsmitm_boot0storage.hpp
Normal file
|
@ -0,0 +1,159 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <switch.h>
|
||||
#include <cstring>
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
#include "fs_istorage.hpp"
|
||||
|
||||
/* Represents a sectored storage. */
|
||||
template<u64 SectorSize>
|
||||
class SectoredProxyStorage : public ProxyStorage {
|
||||
private:
|
||||
u64 cur_seek = 0;
|
||||
u64 cur_sector = 0;
|
||||
u64 cur_sector_ofs = 0;
|
||||
u8 sector_buf[SectorSize];
|
||||
private:
|
||||
void Seek(u64 offset) {
|
||||
this->cur_sector_ofs = offset % SectorSize;
|
||||
this->cur_seek = offset - this->cur_sector_ofs;
|
||||
}
|
||||
public:
|
||||
SectoredProxyStorage(FsStorage *s) : ProxyStorage(s) { }
|
||||
SectoredProxyStorage(FsStorage s) : ProxyStorage(s) { }
|
||||
public:
|
||||
virtual Result Read(void *_buffer, size_t size, u64 offset) override {
|
||||
Result rc = 0;
|
||||
u8 *buffer = static_cast<u8 *>(_buffer);
|
||||
this->Seek(offset);
|
||||
|
||||
if (this->cur_sector_ofs == 0 && size % SectorSize == 0) {
|
||||
/* Fast case. */
|
||||
return ProxyStorage::Read(buffer, size, offset);
|
||||
}
|
||||
|
||||
if (R_FAILED((rc = ProxyStorage::Read(this->sector_buf, SectorSize, this->cur_seek)))) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (size + this->cur_sector_ofs <= SectorSize) {
|
||||
memcpy(buffer, sector_buf + this->cur_sector_ofs, size);
|
||||
} else {
|
||||
/* Leaving the sector... */
|
||||
size_t ofs = SectorSize - this->cur_sector_ofs;
|
||||
memcpy(buffer, sector_buf + this->cur_sector_ofs, ofs);
|
||||
size -= ofs;
|
||||
|
||||
/* We're guaranteed alignment, here. */
|
||||
const size_t aligned_remaining_size = size - (size % SectorSize);
|
||||
if (aligned_remaining_size) {
|
||||
if (R_FAILED((rc = ProxyStorage::Read(buffer + ofs, aligned_remaining_size, offset + ofs)))) {
|
||||
return rc;
|
||||
}
|
||||
ofs += aligned_remaining_size;
|
||||
size -= aligned_remaining_size;
|
||||
}
|
||||
|
||||
/* Read any leftover data. */
|
||||
if (size) {
|
||||
if (R_FAILED((rc = ProxyStorage::Read(this->sector_buf, SectorSize, offset + ofs)))) {
|
||||
return rc;
|
||||
}
|
||||
memcpy(buffer + ofs, sector_buf, size);
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
};
|
||||
virtual Result Write(void *_buffer, size_t size, u64 offset) override {
|
||||
Result rc = 0;
|
||||
u8 *buffer = static_cast<u8 *>(_buffer);
|
||||
this->Seek(offset);
|
||||
|
||||
if (this->cur_sector_ofs == 0 && size % SectorSize == 0) {
|
||||
/* Fast case. */
|
||||
return ProxyStorage::Write(buffer, size, offset);
|
||||
}
|
||||
|
||||
if (R_FAILED((rc = ProxyStorage::Read(this->sector_buf, SectorSize, this->cur_seek)))) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
if (size + this->cur_sector_ofs <= SectorSize) {
|
||||
memcpy(this->sector_buf + this->cur_sector_ofs, buffer, size);
|
||||
rc = ProxyStorage::Write(this->sector_buf, SectorSize, this->cur_seek);
|
||||
} else {
|
||||
/* Leaving the sector... */
|
||||
size_t ofs = SectorSize - this->cur_sector_ofs;
|
||||
memcpy(this->sector_buf + this->cur_sector_ofs, buffer, ofs);
|
||||
if (R_FAILED((rc = ProxyStorage::Write(this->sector_buf, ofs, this->cur_seek)))) {
|
||||
return rc;
|
||||
}
|
||||
size -= ofs;
|
||||
|
||||
/* We're guaranteed alignment, here. */
|
||||
const size_t aligned_remaining_size = size - (size % SectorSize);
|
||||
if (aligned_remaining_size) {
|
||||
if (R_FAILED((rc = ProxyStorage::Write(buffer + ofs, aligned_remaining_size, offset + ofs)))) {
|
||||
return rc;
|
||||
}
|
||||
ofs += aligned_remaining_size;
|
||||
size -= aligned_remaining_size;
|
||||
}
|
||||
|
||||
/* Write any leftover data. */
|
||||
if (size) {
|
||||
if (R_FAILED((rc = ProxyStorage::Read(this->sector_buf, SectorSize, offset + ofs)))) {
|
||||
return rc;
|
||||
}
|
||||
memcpy(this->sector_buf, buffer + ofs, size);
|
||||
rc = ProxyStorage::Write(this->sector_buf, SectorSize, this->cur_seek);
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
};
|
||||
};
|
||||
|
||||
/* Represents an RCM-preserving BOOT0 partition. */
|
||||
class Boot0Storage : public SectoredProxyStorage<0x200> {
|
||||
using Base = SectoredProxyStorage<0x200>;
|
||||
|
||||
public:
|
||||
static constexpr u64 BctEndOffset = 0xFC000;
|
||||
static constexpr u64 BctSize = 0x4000;
|
||||
static constexpr u64 BctPubkStart = 0x210;
|
||||
static constexpr u64 BctPubkSize = 0x100;
|
||||
static constexpr u64 BctPubkEnd = BctPubkStart + BctPubkSize;
|
||||
|
||||
static constexpr u64 EksStart = 0x180000;
|
||||
static constexpr u64 EksSize = 0x4000;
|
||||
static constexpr u64 EksEnd = EksStart + EksSize;
|
||||
private:
|
||||
u64 title_id;
|
||||
private:
|
||||
bool CanModifyBctPubks();
|
||||
public:
|
||||
Boot0Storage(FsStorage *s, u64 t) : Base(s), title_id(t) { }
|
||||
Boot0Storage(FsStorage s, u64 t) : Base(s), title_id(t) { }
|
||||
public:
|
||||
virtual Result Read(void *_buffer, size_t size, u64 offset) override;
|
||||
virtual Result Write(void *_buffer, size_t size, u64 offset) override;
|
||||
};
|
|
@ -78,7 +78,7 @@ void __appExit(void) {
|
|||
|
||||
struct FsMitmManagerOptions {
|
||||
static const size_t PointerBufferSize = 0x800;
|
||||
static const size_t MaxDomains = 0x10;
|
||||
static const size_t MaxDomains = 0x40;
|
||||
static const size_t MaxDomainObjects = 0x4000;
|
||||
};
|
||||
using FsMitmManager = WaitableManager<FsMitmManagerOptions>;
|
||||
|
@ -88,7 +88,7 @@ int main(int argc, char **argv)
|
|||
Thread sd_initializer_thread = {0};
|
||||
Thread hid_initializer_thread = {0};
|
||||
consoleDebugInit(debugDevice_SVC);
|
||||
|
||||
|
||||
if (R_FAILED(threadCreate(&sd_initializer_thread, &Utils::InitializeSdThreadFunc, NULL, 0x4000, 0x15, 0))) {
|
||||
/* TODO: Panic. */
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ class RomFileStorage : public IROStorage {
|
|||
RomFileStorage(FsFile f) {
|
||||
this->base_file = new FsFile(f);
|
||||
};
|
||||
~RomFileStorage() {
|
||||
virtual ~RomFileStorage() {
|
||||
fsFileClose(base_file);
|
||||
delete base_file;
|
||||
};
|
||||
|
@ -54,30 +54,4 @@ class RomFileStorage : public IROStorage {
|
|||
};
|
||||
|
||||
/* Represents a RomFS accessed via some IStorage. */
|
||||
class RomInterfaceStorage : public IROStorage {
|
||||
private:
|
||||
FsStorage *base_storage;
|
||||
public:
|
||||
RomInterfaceStorage(FsStorage *s) : base_storage(s) {
|
||||
/* ... */
|
||||
};
|
||||
RomInterfaceStorage(FsStorage s) {
|
||||
this->base_storage = new FsStorage(s);
|
||||
};
|
||||
~RomInterfaceStorage() {
|
||||
fsStorageClose(base_storage);
|
||||
delete base_storage;
|
||||
};
|
||||
public:
|
||||
Result Read(void *buffer, size_t size, u64 offset) override {
|
||||
return fsStorageRead(this->base_storage, offset, buffer, size);
|
||||
};
|
||||
Result GetSize(u64 *out_size) override {
|
||||
/* TODO: Merge into libnx? */
|
||||
return fsStorageGetSize(this->base_storage, out_size);
|
||||
};
|
||||
Result OperateRange(u32 operation_type, u64 offset, u64 size, FsRangeInfo *out_range_info) override {
|
||||
/* TODO: Merge into libnx? */
|
||||
return fsStorageOperateRange(this->base_storage, operation_type, offset, size, out_range_info);
|
||||
};
|
||||
};
|
||||
using RomInterfaceStorage = ROProxyStorage;
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "fs_shim.h"
|
||||
|
||||
#include "fsmitm_utils.hpp"
|
||||
#include "fsmitm_boot0storage.hpp"
|
||||
#include "fsmitm_romstorage.hpp"
|
||||
#include "fsmitm_layeredrom.hpp"
|
||||
|
||||
|
@ -79,12 +80,67 @@ void FsMitmService::PostProcess(IMitmServiceObject *obj, IpcResponseContext *ctx
|
|||
}
|
||||
}
|
||||
|
||||
/* Gate access to the BIS partitions. */
|
||||
Result FsMitmService::OpenBisStorage(Out<std::shared_ptr<IStorageInterface>> out_storage, u32 bis_partition_id) {
|
||||
std::shared_ptr<IStorageInterface> storage = nullptr;
|
||||
u32 out_domain_id = 0;
|
||||
Result rc = 0;
|
||||
|
||||
ON_SCOPE_EXIT {
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
out_storage.SetValue(std::move(storage));
|
||||
if (out_storage.IsDomain()) {
|
||||
out_storage.ChangeObjectId(out_domain_id);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
{
|
||||
FsStorage bis_storage;
|
||||
rc = fsOpenBisStorageFwd(this->forward_service.get(), &bis_storage, bis_partition_id);
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
const bool is_sysmodule = this->title_id < 0x0100000000001000;
|
||||
const bool has_bis_write_flag = Utils::HasFlag(this->title_id, "bis_write");
|
||||
const bool has_cal0_read_flag = Utils::HasFlag(this->title_id, "cal_read");
|
||||
if (bis_partition_id == BisStorageId_Boot0) {
|
||||
storage = std::make_shared<IStorageInterface>(new Boot0Storage(bis_storage, this->title_id));
|
||||
} else if (bis_partition_id == BisStorageId_Prodinfo) {
|
||||
/* PRODINFO should *never* be writable. */
|
||||
if (is_sysmodule || has_cal0_read_flag) {
|
||||
storage = std::make_shared<IStorageInterface>(new ROProxyStorage(bis_storage));
|
||||
} else {
|
||||
/* Do not allow non-sysmodules to read *or* write CAL0. */
|
||||
fsStorageClose(&bis_storage);
|
||||
return 0x320002;
|
||||
}
|
||||
} else {
|
||||
if (is_sysmodule || has_bis_write_flag) {
|
||||
/* Sysmodules should still be allowed to read and write. */
|
||||
storage = std::make_shared<IStorageInterface>(new ProxyStorage(bis_storage));
|
||||
} else {
|
||||
/* Non-sysmodules should be allowed to read. */
|
||||
storage = std::make_shared<IStorageInterface>(new ROProxyStorage(bis_storage));
|
||||
}
|
||||
}
|
||||
if (out_storage.IsDomain()) {
|
||||
out_domain_id = bis_storage.s.object_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Add redirection for RomFS to the SD card. */
|
||||
Result FsMitmService::OpenDataStorageByCurrentProcess(Out<std::shared_ptr<IStorageInterface>> out_storage) {
|
||||
std::shared_ptr<IStorageInterface> storage = nullptr;
|
||||
u32 out_domain_id = 0;
|
||||
Result rc = 0;
|
||||
|
||||
if (!this->should_override_contents) {
|
||||
return RESULT_FORWARD_TO_SESSION;
|
||||
}
|
||||
|
||||
bool has_cache = StorageCacheGetEntry(this->title_id, &storage);
|
||||
|
||||
ON_SCOPE_EXIT {
|
||||
|
@ -148,6 +204,10 @@ Result FsMitmService::OpenDataStorageByDataId(Out<std::shared_ptr<IStorageInterf
|
|||
FsStorageId storage_id = (FsStorageId)sid;
|
||||
FsStorage data_storage;
|
||||
FsFile data_file;
|
||||
|
||||
if (!this->should_override_contents) {
|
||||
return RESULT_FORWARD_TO_SESSION;
|
||||
}
|
||||
|
||||
std::shared_ptr<IStorageInterface> storage = nullptr;
|
||||
u32 out_domain_id = 0;
|
||||
|
|
|
@ -22,33 +22,51 @@
|
|||
|
||||
enum FspSrvCmd : u32 {
|
||||
FspSrvCmd_SetCurrentProcess = 1,
|
||||
FspSrvCmd_OpenBisStorage = 12,
|
||||
FspSrvCmd_OpenDataStorageByCurrentProcess = 200,
|
||||
FspSrvCmd_OpenDataStorageByDataId = 202,
|
||||
};
|
||||
|
||||
class FsMitmService : public IMitmServiceObject {
|
||||
class FsMitmService : public IMitmServiceObject {
|
||||
private:
|
||||
bool has_initialized = false;
|
||||
bool should_override_contents;
|
||||
public:
|
||||
FsMitmService(std::shared_ptr<Service> s) : IMitmServiceObject(s) {
|
||||
/* ... */
|
||||
FsMitmService(std::shared_ptr<Service> s, u64 pid) : IMitmServiceObject(s, pid) {
|
||||
if (Utils::HasSdDisableMitMFlag(this->title_id)) {
|
||||
this->should_override_contents = false;
|
||||
} else {
|
||||
this->should_override_contents = (this->title_id >= 0x0100000000010000ULL || Utils::HasSdMitMFlag(this->title_id)) && Utils::HasOverrideButton(this->title_id);
|
||||
}
|
||||
}
|
||||
|
||||
static bool ShouldMitm(u64 pid, u64 tid) {
|
||||
if (Utils::HasSdDisableMitMFlag(tid)) {
|
||||
/* Don't Mitm KIPs */
|
||||
if (pid < 0x50) {
|
||||
return false;
|
||||
}
|
||||
return (tid >= 0x0100000000010000ULL || Utils::HasSdMitMFlag(tid)) && Utils::HasOverrideButton(tid);
|
||||
|
||||
static std::atomic_bool has_launched_qlaunch = false;
|
||||
|
||||
/* TODO: intercepting everything seems to cause issues with sleep mode, for some reason. */
|
||||
/* Figure out why, and address it. */
|
||||
if (tid == 0x0100000000001000ULL) {
|
||||
has_launched_qlaunch = true;
|
||||
}
|
||||
|
||||
return has_launched_qlaunch || tid == 0x010000000000001FULL || tid >= 0x0100000000010000ULL || Utils::HasSdMitMFlag(tid);
|
||||
}
|
||||
|
||||
static void PostProcess(IMitmServiceObject *obj, IpcResponseContext *ctx);
|
||||
|
||||
protected:
|
||||
/* Overridden commands. */
|
||||
Result OpenBisStorage(Out<std::shared_ptr<IStorageInterface>> out, u32 bis_partition_id);
|
||||
Result OpenDataStorageByCurrentProcess(Out<std::shared_ptr<IStorageInterface>> out);
|
||||
Result OpenDataStorageByDataId(Out<std::shared_ptr<IStorageInterface>> out, u64 data_id, u8 storage_id);
|
||||
public:
|
||||
DEFINE_SERVICE_DISPATCH_TABLE {
|
||||
MakeServiceCommandMeta<FspSrvCmd_OpenBisStorage, &FsMitmService::OpenBisStorage>(),
|
||||
MakeServiceCommandMeta<FspSrvCmd_OpenDataStorageByCurrentProcess, &FsMitmService::OpenDataStorageByCurrentProcess>(),
|
||||
MakeServiceCommandMeta<FspSrvCmd_OpenDataStorageByDataId, &FsMitmService::OpenDataStorageByDataId>(),
|
||||
};
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "debug.hpp"
|
||||
#include "fsmitm_utils.hpp"
|
||||
#include "ini.h"
|
||||
#include "sha256.h"
|
||||
|
||||
static FsFileSystem g_sd_filesystem = {0};
|
||||
static std::vector<u64> g_mitm_flagged_tids;
|
||||
|
@ -31,11 +32,18 @@ static std::atomic_bool g_has_initialized = false;
|
|||
static std::atomic_bool g_has_hid_session = false;
|
||||
|
||||
static u64 g_override_key_combination = KEY_R;
|
||||
static u64 g_override_hbl_tid = 0x010000000000100DULL;
|
||||
static bool g_override_by_default = true;
|
||||
|
||||
/* Static buffer for loader.ini contents at runtime. */
|
||||
static char g_config_ini_data[0x800];
|
||||
|
||||
/* Backup file for CAL0 partition. */
|
||||
static constexpr size_t ProdinfoSize = 0x8000;
|
||||
static FsFile g_cal0_file = {0};
|
||||
static u8 g_cal0_storage_backup[ProdinfoSize];
|
||||
static u8 g_cal0_backup[ProdinfoSize];
|
||||
|
||||
static bool IsHexadecimal(const char *str) {
|
||||
while (*str) {
|
||||
if (isxdigit(*str)) {
|
||||
|
@ -64,6 +72,60 @@ void Utils::InitializeSdThreadFunc(void *args) {
|
|||
svcSleepThread(1000ULL);
|
||||
}
|
||||
|
||||
/* Back up CAL0, if it's not backed up already. */
|
||||
fsFsCreateDirectory(&g_sd_filesystem, "/atmosphere/automatic_backups");
|
||||
{
|
||||
FsStorage cal0_storage;
|
||||
if (R_FAILED(fsOpenBisStorage(&cal0_storage, BisStorageId_Prodinfo)) || R_FAILED(fsStorageRead(&cal0_storage, 0, g_cal0_storage_backup, ProdinfoSize))) {
|
||||
std::abort();
|
||||
}
|
||||
fsStorageClose(&cal0_storage);
|
||||
|
||||
char serial_number[0x40] = {0};
|
||||
memcpy(serial_number, g_cal0_storage_backup + 0x250, 0x18);
|
||||
|
||||
|
||||
char prodinfo_backup_path[FS_MAX_PATH] = {0};
|
||||
if (strlen(serial_number) > 0) {
|
||||
snprintf(prodinfo_backup_path, sizeof(prodinfo_backup_path) - 1, "/atmosphere/automatic_backups/%s_PRODINFO.bin", serial_number);
|
||||
} else {
|
||||
snprintf(prodinfo_backup_path, sizeof(prodinfo_backup_path) - 1, "/atmosphere/automatic_backups/PRODINFO.bin");
|
||||
}
|
||||
|
||||
fsFsCreateFile(&g_sd_filesystem, prodinfo_backup_path, ProdinfoSize, 0);
|
||||
if (R_SUCCEEDED(fsFsOpenFile(&g_sd_filesystem, prodinfo_backup_path, FS_OPEN_READ | FS_OPEN_WRITE, &g_cal0_file))) {
|
||||
bool has_auto_backup = false;
|
||||
size_t read = 0;
|
||||
if (R_SUCCEEDED(fsFileRead(&g_cal0_file, 0, g_cal0_backup, sizeof(g_cal0_backup), &read)) && read == sizeof(g_cal0_backup)) {
|
||||
bool is_cal0_valid = true;
|
||||
is_cal0_valid &= memcmp(g_cal0_backup, "CAL0", 4) == 0;
|
||||
is_cal0_valid &= memcmp(g_cal0_backup + 0x250, serial_number, 0x18) == 0;
|
||||
u32 cal0_size = ((u32 *)g_cal0_backup)[2];
|
||||
is_cal0_valid &= cal0_size + 0x40 <= ProdinfoSize;
|
||||
if (is_cal0_valid) {
|
||||
struct sha256_state sha_ctx;
|
||||
u8 calc_hash[0x20];
|
||||
sha256_init(&sha_ctx);
|
||||
sha256_update(&sha_ctx, g_cal0_backup + 0x40, cal0_size);
|
||||
sha256_finalize(&sha_ctx);
|
||||
sha256_finish(&sha_ctx, calc_hash);
|
||||
is_cal0_valid &= memcmp(calc_hash, g_cal0_backup + 0x20, sizeof(calc_hash)) == 0;
|
||||
}
|
||||
has_auto_backup = is_cal0_valid;
|
||||
}
|
||||
|
||||
if (!has_auto_backup) {
|
||||
fsFileSetSize(&g_cal0_file, ProdinfoSize);
|
||||
fsFileWrite(&g_cal0_file, 0, g_cal0_backup, ProdinfoSize);
|
||||
fsFileFlush(&g_cal0_file);
|
||||
}
|
||||
|
||||
/* NOTE: g_cal0_file is intentionally not closed here. This prevents any other process from opening it. */
|
||||
memset(g_cal0_storage_backup, 0, sizeof(g_cal0_storage_backup));
|
||||
memset(g_cal0_backup, 0, sizeof(g_cal0_backup));
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for MitM flags. */
|
||||
FsDir titles_dir;
|
||||
if (R_SUCCEEDED(fsFsOpenDirectory(&g_sd_filesystem, "/atmosphere/titles", FS_DIROPEN_DIRECTORY, &titles_dir))) {
|
||||
|
@ -76,19 +138,39 @@ void Utils::InitializeSdThreadFunc(void *args) {
|
|||
char title_path[FS_MAX_PATH] = {0};
|
||||
strcpy(title_path, "/atmosphere/titles/");
|
||||
strcat(title_path, dir_entry.name);
|
||||
strcat(title_path, "/fsmitm.flag");
|
||||
strcat(title_path, "/flags/fsmitm.flag");
|
||||
if (R_SUCCEEDED(fsFsOpenFile(&g_sd_filesystem, title_path, FS_OPEN_READ, &f))) {
|
||||
g_mitm_flagged_tids.push_back(title_id);
|
||||
fsFileClose(&f);
|
||||
} else {
|
||||
/* TODO: Deprecate. */
|
||||
memset(title_path, 0, sizeof(title_path));
|
||||
strcpy(title_path, "/atmosphere/titles/");
|
||||
strcat(title_path, dir_entry.name);
|
||||
strcat(title_path, "/fsmitm.flag");
|
||||
if (R_SUCCEEDED(fsFsOpenFile(&g_sd_filesystem, title_path, FS_OPEN_READ, &f))) {
|
||||
g_mitm_flagged_tids.push_back(title_id);
|
||||
fsFileClose(&f);
|
||||
}
|
||||
}
|
||||
|
||||
memset(title_path, 0, sizeof(title_path));
|
||||
strcpy(title_path, "/atmosphere/titles/");
|
||||
strcat(title_path, dir_entry.name);
|
||||
strcat(title_path, "/fsmitm_disable.flag");
|
||||
strcat(title_path, "/flags/fsmitm_disable.flag");
|
||||
if (R_SUCCEEDED(fsFsOpenFile(&g_sd_filesystem, title_path, FS_OPEN_READ, &f))) {
|
||||
g_disable_mitm_flagged_tids.push_back(title_id);
|
||||
fsFileClose(&f);
|
||||
} else {
|
||||
/* TODO: Deprecate. */
|
||||
memset(title_path, 0, sizeof(title_path));
|
||||
strcpy(title_path, "/atmosphere/titles/");
|
||||
strcat(title_path, dir_entry.name);
|
||||
strcat(title_path, "/fsmitm_disable.flag");
|
||||
if (R_SUCCEEDED(fsFsOpenFile(&g_sd_filesystem, title_path, FS_OPEN_READ, &f))) {
|
||||
g_disable_mitm_flagged_tids.push_back(title_id);
|
||||
fsFileClose(&f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -264,7 +346,56 @@ Result Utils::SaveSdFileForAtmosphere(u64 title_id, const char *fn, void *data,
|
|||
return rc;
|
||||
}
|
||||
|
||||
bool Utils::HasTitleFlag(u64 tid, const char *flag) {
|
||||
if (IsSdInitialized()) {
|
||||
FsFile f;
|
||||
char flag_path[FS_MAX_PATH];
|
||||
|
||||
memset(flag_path, 0, sizeof(flag_path));
|
||||
snprintf(flag_path, sizeof(flag_path) - 1, "flags/%s.flag", flag);
|
||||
if (OpenSdFileForAtmosphere(tid, flag_path, FS_OPEN_READ, &f)) {
|
||||
fsFileClose(&f);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* TODO: Deprecate. */
|
||||
snprintf(flag_path, sizeof(flag_path) - 1, "%s.flag", flag);
|
||||
if (OpenSdFileForAtmosphere(tid, flag_path, FS_OPEN_READ, &f)) {
|
||||
fsFileClose(&f);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Utils::HasGlobalFlag(const char *flag) {
|
||||
if (IsSdInitialized()) {
|
||||
FsFile f;
|
||||
char flag_path[FS_MAX_PATH] = {0};
|
||||
snprintf(flag_path, sizeof(flag_path), "/atmosphere/flags/%s.flag", flag);
|
||||
if (fsFsOpenFile(&g_sd_filesystem, flag_path, FS_OPEN_READ, &f)) {
|
||||
fsFileClose(&f);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Utils::HasHblFlag(const char *flag) {
|
||||
char hbl_flag[FS_MAX_PATH] = {0};
|
||||
snprintf(hbl_flag, sizeof(hbl_flag), "hbl_%s", flag);
|
||||
return HasGlobalFlag(hbl_flag);
|
||||
}
|
||||
|
||||
bool Utils::HasFlag(u64 tid, const char *flag) {
|
||||
return HasTitleFlag(tid, flag) || (tid == g_override_hbl_tid && HasHblFlag(flag));
|
||||
}
|
||||
|
||||
bool Utils::HasSdMitMFlag(u64 tid) {
|
||||
if (tid == g_override_hbl_tid) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (IsSdInitialized()) {
|
||||
return std::find(g_mitm_flagged_tids.begin(), g_mitm_flagged_tids.end(), tid) != g_mitm_flagged_tids.end();
|
||||
}
|
||||
|
@ -306,7 +437,12 @@ bool Utils::HasOverrideButton(u64 tid) {
|
|||
static int FsMitMIniHandler(void *user, const char *section, const char *name, const char *value) {
|
||||
/* Taken and modified, with love, from Rajkosto's implementation. */
|
||||
if (strcasecmp(section, "config") == 0) {
|
||||
if (strcasecmp(name, "override_key") == 0) {
|
||||
if (strcasecmp(name, "hbl_tid") == 0) {
|
||||
u64 override_tid = strtoul(value, NULL, 16);
|
||||
if (override_tid != 0) {
|
||||
g_override_hbl_tid = override_tid;
|
||||
}
|
||||
} else if (strcasecmp(name, "override_key") == 0) {
|
||||
if (value[0] == '!') {
|
||||
g_override_by_default = true;
|
||||
value++;
|
||||
|
|
|
@ -18,6 +18,25 @@
|
|||
#include <switch.h>
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
enum BisStorageId : u32 {
|
||||
BisStorageId_Boot0 = 0,
|
||||
BisStorageId_Boot1 = 10,
|
||||
BisStorageId_RawNand = 20,
|
||||
BisStorageId_BcPkg2_1 = 21,
|
||||
BisStorageId_BcPkg2_2 = 22,
|
||||
BisStorageId_BcPkg2_3 = 23,
|
||||
BisStorageId_BcPkg2_4 = 24,
|
||||
BisStorageId_BcPkg2_5 = 25,
|
||||
BisStorageId_BcPkg2_6 = 26,
|
||||
BisStorageId_Prodinfo = 27,
|
||||
BisStorageId_ProdinfoF = 28,
|
||||
BisStorageId_Safe = 29,
|
||||
BisStorageId_User = 30,
|
||||
BisStorageId_System = 31,
|
||||
BisStorageId_SystemProperEncryption = 32,
|
||||
BisStorageId_SystemProperPartition = 33,
|
||||
};
|
||||
|
||||
class Utils {
|
||||
public:
|
||||
static bool IsSdInitialized();
|
||||
|
@ -38,6 +57,12 @@ class Utils {
|
|||
|
||||
/* SD card Initialization + MitM detection. */
|
||||
static void InitializeSdThreadFunc(void *args);
|
||||
|
||||
static bool HasTitleFlag(u64 tid, const char *flag);
|
||||
static bool HasHblFlag(const char *flag);
|
||||
static bool HasGlobalFlag(const char *flag);
|
||||
static bool HasFlag(u64 tid, const char *flag);
|
||||
|
||||
static bool HasSdMitMFlag(u64 tid);
|
||||
static bool HasSdDisableMitMFlag(u64 tid);
|
||||
|
||||
|
|
113
stratosphere/fs_mitm/source/sha256.c
Normal file
113
stratosphere/fs_mitm/source/sha256.c
Normal file
|
@ -0,0 +1,113 @@
|
|||
/* Based on linux source code */
|
||||
/*
|
||||
* sha256_base.h - core logic for SHA-256 implementations
|
||||
*
|
||||
* Copyright (C) 2015 Linaro Ltd <ard.biesheuvel@linaro.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
#include "sha256.h"
|
||||
|
||||
#define unlikely(x) __builtin_expect(!!(x), 0)
|
||||
|
||||
void sha256_block_data_order (uint32_t *ctx, const void *in, size_t num);
|
||||
|
||||
int sha256_init(struct sha256_state *sctx)
|
||||
{
|
||||
sctx->state[0] = SHA256_H0;
|
||||
sctx->state[1] = SHA256_H1;
|
||||
sctx->state[2] = SHA256_H2;
|
||||
sctx->state[3] = SHA256_H3;
|
||||
sctx->state[4] = SHA256_H4;
|
||||
sctx->state[5] = SHA256_H5;
|
||||
sctx->state[6] = SHA256_H6;
|
||||
sctx->state[7] = SHA256_H7;
|
||||
sctx->count = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sha256_update(struct sha256_state *sctx,
|
||||
const void *data,
|
||||
size_t len)
|
||||
{
|
||||
const u8 *data8 = (const u8 *)data;
|
||||
unsigned int len32 = (unsigned int)len;
|
||||
unsigned int partial = sctx->count % SHA256_BLOCK_SIZE;
|
||||
|
||||
sctx->count += len32;
|
||||
|
||||
if (unlikely((partial + len32) >= SHA256_BLOCK_SIZE)) {
|
||||
int blocks;
|
||||
|
||||
if (partial) {
|
||||
int p = SHA256_BLOCK_SIZE - partial;
|
||||
|
||||
memcpy(sctx->buf + partial, data8, p);
|
||||
data8 += p;
|
||||
len32 -= p;
|
||||
|
||||
sha256_block_data_order(sctx->state, sctx->buf, 1);
|
||||
}
|
||||
|
||||
blocks = len32 / SHA256_BLOCK_SIZE;
|
||||
len32 %= SHA256_BLOCK_SIZE;
|
||||
|
||||
if (blocks) {
|
||||
sha256_block_data_order(sctx->state, data8, blocks);
|
||||
data8 += blocks * SHA256_BLOCK_SIZE;
|
||||
}
|
||||
partial = 0;
|
||||
}
|
||||
if (len32)
|
||||
memcpy(sctx->buf + partial, data8, len32);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sha256_finalize(struct sha256_state *sctx)
|
||||
{
|
||||
const int bit_offset = SHA256_BLOCK_SIZE - sizeof(u64);
|
||||
u64 *bits = (u64 *)(sctx->buf + bit_offset);
|
||||
unsigned int partial = sctx->count % SHA256_BLOCK_SIZE;
|
||||
|
||||
sctx->buf[partial++] = 0x80;
|
||||
if (partial > bit_offset) {
|
||||
memset(sctx->buf + partial, 0x0, SHA256_BLOCK_SIZE - partial);
|
||||
partial = 0;
|
||||
|
||||
sha256_block_data_order(sctx->state, sctx->buf, 1);
|
||||
}
|
||||
|
||||
memset(sctx->buf + partial, 0x0, bit_offset - partial);
|
||||
*bits = __builtin_bswap64(sctx->count << 3);
|
||||
sha256_block_data_order(sctx->state, sctx->buf, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sha256_finish(struct sha256_state *sctx, void *out)
|
||||
{
|
||||
unsigned int digest_size = 32;
|
||||
u32 *digest = (u32 *)out;
|
||||
int i;
|
||||
|
||||
// Switch: misalignment shouldn't be a problem here...
|
||||
for (i = 0; digest_size > 0; i++, digest_size -= sizeof(u32))
|
||||
*digest++ = __builtin_bswap32(sctx->state[i]);
|
||||
|
||||
*sctx = (struct sha256_state){};
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
36
stratosphere/fs_mitm/source/sha256.h
Normal file
36
stratosphere/fs_mitm/source/sha256.h
Normal file
|
@ -0,0 +1,36 @@
|
|||
#pragma once
|
||||
|
||||
/* Based on linux source code */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <switch/types.h>
|
||||
|
||||
#define SHA256_DIGEST_SIZE 32
|
||||
#define SHA256_BLOCK_SIZE 64
|
||||
|
||||
#define SHA256_H0 0x6a09e667UL
|
||||
#define SHA256_H1 0xbb67ae85UL
|
||||
#define SHA256_H2 0x3c6ef372UL
|
||||
#define SHA256_H3 0xa54ff53aUL
|
||||
#define SHA256_H4 0x510e527fUL
|
||||
#define SHA256_H5 0x9b05688cUL
|
||||
#define SHA256_H6 0x1f83d9abUL
|
||||
#define SHA256_H7 0x5be0cd19UL
|
||||
|
||||
struct sha256_state {
|
||||
u32 state[SHA256_DIGEST_SIZE / 4];
|
||||
u64 count;
|
||||
u8 buf[SHA256_BLOCK_SIZE];
|
||||
};
|
||||
|
||||
int sha256_init(struct sha256_state *sctx);
|
||||
int sha256_update(struct sha256_state *sctx, const void *data, size_t len);
|
||||
int sha256_finalize(struct sha256_state *sctx);
|
||||
int sha256_finish(struct sha256_state *sctx, void *out);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
163
stratosphere/fs_mitm/source/sha256_armv8.s
Normal file
163
stratosphere/fs_mitm/source/sha256_armv8.s
Normal file
|
@ -0,0 +1,163 @@
|
|||
.section .text.sha256_armv8, "ax", %progbits
|
||||
.align 5
|
||||
.arch armv8-a+crypto
|
||||
|
||||
# SHA256 assembly implementation for ARMv8 AArch64 (based on linux source code)
|
||||
|
||||
.global sha256_block_data_order
|
||||
.type sha256_block_data_order,%function
|
||||
sha256_block_data_order:
|
||||
|
||||
.Lsha256prolog:
|
||||
|
||||
stp x29, x30, [sp,#-64]!
|
||||
mov x29, sp
|
||||
adr x3, .LKConstant256
|
||||
str q8, [sp, #16]
|
||||
ld1 {v16.4s-v19.4s}, [x3], #64
|
||||
ld1 {v0.4s}, [x0], #16
|
||||
ld1 {v20.4s-v23.4s}, [x3], #64
|
||||
add x2, x1, x2, lsl #6
|
||||
ld1 {v1.4s}, [x0]
|
||||
ld1 {v24.4s-v27.4s}, [x3], #64
|
||||
sub x0, x0, #16
|
||||
str q9, [sp, #32]
|
||||
str q10, [sp, #48]
|
||||
ld1 {v28.4s-v31.4s}, [x3], #64
|
||||
|
||||
.Lsha256loop:
|
||||
|
||||
ld1 {v5.16b-v8.16b}, [x1], #64
|
||||
mov v2.16b, v0.16b
|
||||
mov v3.16b, v1.16b
|
||||
|
||||
rev32 v5.16b, v5.16b
|
||||
rev32 v6.16b, v6.16b
|
||||
add v9.4s, v5.4s, v16.4s
|
||||
rev32 v7.16b, v7.16b
|
||||
add v10.4s, v6.4s, v17.4s
|
||||
mov v4.16b, v2.16b
|
||||
sha256h q2, q3, v9.4s
|
||||
sha256h2 q3, q4, v9.4s
|
||||
sha256su0 v5.4s, v6.4s
|
||||
rev32 v8.16b, v8.16b
|
||||
add v9.4s, v7.4s, v18.4s
|
||||
mov v4.16b, v2.16b
|
||||
sha256h q2, q3, v10.4s
|
||||
sha256h2 q3, q4, v10.4s
|
||||
sha256su0 v6.4s, v7.4s
|
||||
sha256su1 v5.4s, v7.4s, v8.4s
|
||||
add v10.4s, v8.4s, v19.4s
|
||||
mov v4.16b, v2.16b
|
||||
sha256h q2, q3, v9.4s
|
||||
sha256h2 q3, q4, v9.4s
|
||||
sha256su0 v7.4s, v8.4s
|
||||
sha256su1 v6.4s, v8.4s, v5.4s
|
||||
add v9.4s, v5.4s, v20.4s
|
||||
mov v4.16b, v2.16b
|
||||
sha256h q2, q3, v10.4s
|
||||
sha256h2 q3, q4, v10.4s
|
||||
sha256su0 v8.4s, v5.4s
|
||||
sha256su1 v7.4s, v5.4s, v6.4s
|
||||
add v10.4s, v6.4s, v21.4s
|
||||
mov v4.16b, v2.16b
|
||||
sha256h q2, q3, v9.4s
|
||||
sha256h2 q3, q4, v9.4s
|
||||
sha256su0 v5.4s, v6.4s
|
||||
sha256su1 v8.4s, v6.4s, v7.4s
|
||||
add v9.4s, v7.4s, v22.4s
|
||||
mov v4.16b, v2.16b
|
||||
sha256h q2, q3, v10.4s
|
||||
sha256h2 q3, q4, v10.4s
|
||||
sha256su0 v6.4s, v7.4s
|
||||
sha256su1 v5.4s, v7.4s, v8.4s
|
||||
add v10.4s, v8.4s, v23.4s
|
||||
mov v4.16b, v2.16b
|
||||
sha256h q2, q3, v9.4s
|
||||
sha256h2 q3, q4, v9.4s
|
||||
sha256su0 v7.4s, v8.4s
|
||||
sha256su1 v6.4s, v8.4s, v5.4s
|
||||
add v9.4s, v5.4s, v24.4s
|
||||
mov v4.16b, v2.16b
|
||||
sha256h q2, q3, v10.4s
|
||||
sha256h2 q3, q4, v10.4s
|
||||
sha256su0 v8.4s, v5.4s
|
||||
sha256su1 v7.4s, v5.4s, v6.4s
|
||||
add v10.4s, v6.4s, v25.4s
|
||||
mov v4.16b, v2.16b
|
||||
sha256h q2, q3, v9.4s
|
||||
sha256h2 q3, q4, v9.4s
|
||||
sha256su0 v5.4s, v6.4s
|
||||
sha256su1 v8.4s, v6.4s, v7.4s
|
||||
add v9.4s, v7.4s, v26.4s
|
||||
mov v4.16b, v2.16b
|
||||
sha256h q2, q3, v10.4s
|
||||
sha256h2 q3, q4, v10.4s
|
||||
sha256su0 v6.4s, v7.4s
|
||||
sha256su1 v5.4s, v7.4s, v8.4s
|
||||
add v10.4s, v8.4s, v27.4s
|
||||
mov v4.16b, v2.16b
|
||||
sha256h q2, q3, v9.4s
|
||||
sha256h2 q3, q4, v9.4s
|
||||
sha256su0 v7.4s, v8.4s
|
||||
sha256su1 v6.4s, v8.4s, v5.4s
|
||||
add v9.4s, v5.4s, v28.4s
|
||||
mov v4.16b, v2.16b
|
||||
sha256h q2, q3, v10.4s
|
||||
sha256h2 q3, q4, v10.4s
|
||||
sha256su0 v8.4s, v5.4s
|
||||
sha256su1 v7.4s, v5.4s, v6.4s
|
||||
add v10.4s, v6.4s, v29.4s
|
||||
mov v4.16b, v2.16b
|
||||
sha256h q2, q3, v9.4s
|
||||
sha256h2 q3, q4, v9.4s
|
||||
sha256su1 v8.4s, v6.4s, v7.4s
|
||||
add v9.4s, v7.4s, v30.4s
|
||||
mov v4.16b, v2.16b
|
||||
sha256h q2, q3, v10.4s
|
||||
sha256h2 q3, q4, v10.4s
|
||||
add v10.4s, v8.4s, v31.4s
|
||||
mov v4.16b, v2.16b
|
||||
sha256h q2, q3, v9.4s
|
||||
sha256h2 q3, q4, v9.4s
|
||||
mov v4.16b, v2.16b
|
||||
sha256h q2, q3, v10.4s
|
||||
sha256h2 q3, q4, v10.4s
|
||||
cmp x1, x2
|
||||
add v1.4s, v1.4s, v3.4s
|
||||
add v0.4s, v0.4s, v2.4s
|
||||
b.ne .Lsha256loop
|
||||
|
||||
.Lsha256epilog:
|
||||
|
||||
st1 {v0.4s,v1.4s}, [x0]
|
||||
ldr q10, [sp, #48]
|
||||
ldr q9, [sp, #32]
|
||||
ldr q8, [sp, #16]
|
||||
ldr x29, [sp], #64
|
||||
ret
|
||||
|
||||
.align 5
|
||||
.LKConstant256:
|
||||
.word 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5
|
||||
.word 0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5
|
||||
.word 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3
|
||||
.word 0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174
|
||||
.word 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc
|
||||
.word 0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da
|
||||
.word 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7
|
||||
.word 0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967
|
||||
.word 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13
|
||||
.word 0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85
|
||||
.word 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3
|
||||
.word 0xd192e819,0xd6990624,0xf40e3585,0x106aa070
|
||||
.word 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5
|
||||
.word 0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3
|
||||
.word 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208
|
||||
.word 0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2
|
||||
|
||||
.size sha256_block_data_order,.-sha256_block_data_order
|
||||
.align 2
|
||||
|
||||
|
||||
|
|
@ -1 +1 @@
|
|||
Subproject commit 0fb33e9c094bffde737c7a73cd5ccce4d7cbae33
|
||||
Subproject commit 0bec72ca36084e9780a8c28abd4a0b24c03c18af
|
|
@ -163,11 +163,22 @@ void EmbeddedBoot2::Main() {
|
|||
char title_path[FS_MAX_PATH] = {0};
|
||||
strcpy(title_path, "sdmc:/atmosphere/titles/");
|
||||
strcat(title_path, ent->d_name);
|
||||
strcat(title_path, "/boot2.flag");
|
||||
strcat(title_path, "/flags/boot2.flag");
|
||||
FILE *f_flag = fopen(title_path, "rb");
|
||||
if (f_flag != NULL) {
|
||||
fclose(f_flag);
|
||||
LaunchTitle((Boot2KnownTitleId)title_id, FsStorageId_None, 0, NULL);
|
||||
} else {
|
||||
/* TODO: Deprecate this in the future. */
|
||||
memset(title_path, 0, FS_MAX_PATH);
|
||||
strcpy(title_path, "sdmc:/atmosphere/titles/");
|
||||
strcat(title_path, ent->d_name);
|
||||
strcat(title_path, "/boot2.flag");
|
||||
f_flag = fopen(title_path, "rb");
|
||||
if (f_flag != NULL) {
|
||||
fclose(f_flag);
|
||||
LaunchTitle((Boot2KnownTitleId)title_id, FsStorageId_None, 0, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ enum SetSysCmd : u32 {
|
|||
|
||||
class SetSysMitmService : public IMitmServiceObject {
|
||||
public:
|
||||
SetSysMitmService(std::shared_ptr<Service> s) : IMitmServiceObject(s) {
|
||||
SetSysMitmService(std::shared_ptr<Service> s, u64 pid) : IMitmServiceObject(s, pid) {
|
||||
/* ... */
|
||||
}
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ ARCH := -march=armv8-a -mtune=cortex-a57 -mtp=soft -fPIE
|
|||
CFLAGS := -g -Wall -O2 -ffunction-sections \
|
||||
$(ARCH) $(DEFINES)
|
||||
|
||||
CFLAGS += $(INCLUDE) -D__SWITCH__ -DSM_ENABLE_SMHAX -DSM_ENABLE_MITM -DSM_ENABLE_INIT_DEFERS -DSM_MINIMUM_SESSION_LIMIT=8
|
||||
CFLAGS += $(INCLUDE) -D__SWITCH__ -DSM_ENABLE_MITM -DSM_ENABLE_INIT_DEFERS -DSM_MINIMUM_SESSION_LIMIT=8
|
||||
|
||||
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++17
|
||||
|
||||
|
|
|
@ -221,13 +221,11 @@ bool Registration::HasService(u64 service) {
|
|||
|
||||
Result Registration::GetServiceHandle(u64 pid, u64 service, Handle *out) {
|
||||
Registration::Service *target_service = GetService(service);
|
||||
if (target_service == NULL || ShouldInitDefer(service)) {
|
||||
if (target_service == NULL || ShouldInitDefer(service) || target_service->mitm_waiting_ack) {
|
||||
/* Note: This defers the result until later. */
|
||||
return RESULT_DEFER_SESSION;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
*out = 0;
|
||||
Result rc;
|
||||
if (target_service->mitm_pid == 0 || target_service->mitm_pid == pid) {
|
||||
|
@ -255,7 +253,17 @@ Result Registration::GetServiceHandle(u64 pid, u64 service, Handle *out) {
|
|||
rc = resp->result;
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
if (resp->should_mitm) {
|
||||
rc = svcConnectToPort(out, target_service->mitm_port_h);
|
||||
rc = svcConnectToPort(&target_service->mitm_fwd_sess_h, target_service->port_h);
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
rc = svcConnectToPort(out, target_service->mitm_port_h);
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
target_service->mitm_waiting_ack_pid = pid;
|
||||
target_service->mitm_waiting_ack = true;
|
||||
} else {
|
||||
svcCloseHandle(target_service->mitm_fwd_sess_h);
|
||||
target_service->mitm_fwd_sess_h = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
rc = svcConnectToPort(out, target_service->port_h);
|
||||
}
|
||||
|
@ -497,6 +505,35 @@ Result Registration::UninstallMitmForPid(u64 pid, u64 service) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
Result Registration::AcknowledgeMitmSessionForPid(u64 pid, u64 service, Handle *out, u64 *out_pid) {
|
||||
if (!service) {
|
||||
return 0xC15;
|
||||
}
|
||||
|
||||
u64 service_name_len = GetServiceNameLength(service);
|
||||
|
||||
/* If the service has bytes after a null terminator, that's no good. */
|
||||
if (service_name_len != 8 && (service >> (8 * service_name_len))) {
|
||||
return 0xC15;
|
||||
}
|
||||
|
||||
Registration::Service *target_service = GetService(service);
|
||||
if (target_service == NULL) {
|
||||
return 0xE15;
|
||||
}
|
||||
|
||||
if ((!IsInitialProcess(pid) && target_service->mitm_pid != pid) || !target_service->mitm_waiting_ack) {
|
||||
return 0x1015;
|
||||
}
|
||||
|
||||
*out = target_service->mitm_fwd_sess_h;
|
||||
*out_pid = target_service->mitm_waiting_ack_pid;
|
||||
target_service->mitm_fwd_sess_h = 0;
|
||||
target_service->mitm_waiting_ack_pid = 0;
|
||||
target_service->mitm_waiting_ack = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
Result Registration::AssociatePidTidForMitm(u64 pid, u64 tid) {
|
||||
for (auto &service : g_service_list) {
|
||||
if (service.mitm_pid) {
|
||||
|
|
|
@ -43,6 +43,10 @@ class Registration {
|
|||
u64 mitm_pid;
|
||||
Handle mitm_port_h;
|
||||
Handle mitm_query_h;
|
||||
|
||||
bool mitm_waiting_ack;
|
||||
u64 mitm_waiting_ack_pid;
|
||||
Handle mitm_fwd_sess_h;
|
||||
};
|
||||
|
||||
/* Utilities. */
|
||||
|
@ -74,5 +78,6 @@ class Registration {
|
|||
/* Extension. */
|
||||
static Result InstallMitmForPid(u64 pid, u64 service, Handle *out, Handle *query_out);
|
||||
static Result UninstallMitmForPid(u64 pid, u64 service);
|
||||
static Result AcknowledgeMitmSessionForPid(u64 pid, u64 service, Handle *out, u64 *out_pid);
|
||||
static Result AssociatePidTidForMitm(u64 pid, u64 tid);
|
||||
};
|
||||
|
|
|
@ -98,6 +98,20 @@ Result UserService::AtmosphereUninstallMitm(SmServiceName service) {
|
|||
return rc;
|
||||
}
|
||||
|
||||
Result UserService::AtmosphereAcknowledgeMitmSession(Out<u64> client_pid, Out<MovedHandle> fwd_h, SmServiceName service) {
|
||||
Result rc = 0x415;
|
||||
Handle out_fwd_h = 0;
|
||||
if (this->has_initialized) {
|
||||
rc = Registration::AcknowledgeMitmSessionForPid(this->pid, smEncodeName(service.name), &out_fwd_h, client_pid.GetPointer());
|
||||
}
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
fwd_h.SetValue(out_fwd_h);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result UserService::AtmosphereAssociatePidTidForMitm(u64 pid, u64 tid) {
|
||||
Result rc = 0x415;
|
||||
if (this->has_initialized) {
|
||||
|
|
|
@ -27,7 +27,8 @@ enum UserServiceCmd {
|
|||
|
||||
User_Cmd_AtmosphereInstallMitm = 65000,
|
||||
User_Cmd_AtmosphereUninstallMitm = 65001,
|
||||
User_Cmd_AtmosphereAssociatePidTidForMitm = 65002
|
||||
User_Cmd_AtmosphereAssociatePidTidForMitm = 65002,
|
||||
User_Cmd_AtmosphereAcknowledgeMitmSession = 65003,
|
||||
};
|
||||
|
||||
class UserService final : public IServiceObject {
|
||||
|
@ -45,6 +46,7 @@ class UserService final : public IServiceObject {
|
|||
virtual Result AtmosphereInstallMitm(Out<MovedHandle> srv_h, Out<MovedHandle> qry_h, SmServiceName service);
|
||||
virtual Result AtmosphereUninstallMitm(SmServiceName service);
|
||||
virtual Result AtmosphereAssociatePidTidForMitm(u64 pid, u64 tid);
|
||||
virtual Result AtmosphereAcknowledgeMitmSession(Out<u64> client_pid, Out<MovedHandle> fwd_h, SmServiceName service);
|
||||
public:
|
||||
DEFINE_SERVICE_DISPATCH_TABLE {
|
||||
MakeServiceCommandMeta<User_Cmd_Initialize, &UserService::Initialize>(),
|
||||
|
@ -56,6 +58,7 @@ class UserService final : public IServiceObject {
|
|||
MakeServiceCommandMeta<User_Cmd_AtmosphereInstallMitm, &UserService::AtmosphereInstallMitm>(),
|
||||
MakeServiceCommandMeta<User_Cmd_AtmosphereUninstallMitm, &UserService::AtmosphereUninstallMitm>(),
|
||||
MakeServiceCommandMeta<User_Cmd_AtmosphereAssociatePidTidForMitm, &UserService::AtmosphereAssociatePidTidForMitm>(),
|
||||
MakeServiceCommandMeta<User_Cmd_AtmosphereAcknowledgeMitmSession, &UserService::AtmosphereAcknowledgeMitmSession>(),
|
||||
#endif
|
||||
};
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue