PRODINFO: Revamp blanking/write disallow policy. (#913)
* exo/fusee: hookup new prodinfo settings * fusee: new scheme doesn't need FLAGS_DEFAULT * fusee: fix c/p errors * ams.mitm: completely revamp prodinfo backup mechanism * ams.mitm: Implement revamped blanking/write policy * strat: make early boot more debuggable * exo: condense flag logic
This commit is contained in:
@@ -14,9 +14,11 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "../amsmitm_fs_utils.hpp"
|
||||
#include "../amsmitm_initialization.hpp"
|
||||
#include "fs_shim.h"
|
||||
#include "fs_mitm_service.hpp"
|
||||
#include "fsmitm_boot0storage.hpp"
|
||||
#include "fsmitm_calibration_binary_storage.hpp"
|
||||
#include "fsmitm_layered_romfs_storage.hpp"
|
||||
#include "fsmitm_save_utils.hpp"
|
||||
#include "fsmitm_readonly_layered_filesystem.hpp"
|
||||
@@ -252,7 +254,6 @@ namespace ams::mitm::fs {
|
||||
const bool is_sysmodule = ncm::IsSystemProgramId(this->client_info.program_id);
|
||||
const bool is_hbl = this->client_info.override_status.IsHbl();
|
||||
const bool can_write_bis = is_sysmodule || (is_hbl && GetSettingsItemBooleanValue("atmosphere", "enable_hbl_bis_write"));
|
||||
const bool can_read_cal = is_sysmodule || (is_hbl && GetSettingsItemBooleanValue("atmosphere", "enable_hbl_cal_read"));
|
||||
|
||||
/* Allow HBL to write to boot1 (safe firm) + package2. */
|
||||
/* This is needed to not break compatibility with ChoiDujourNX, which does not check for write access before beginning an update. */
|
||||
@@ -265,15 +266,7 @@ namespace ams::mitm::fs {
|
||||
if (bis_partition_id == FsBisPartitionId_BootPartition1Root) {
|
||||
out.SetValue(std::make_shared<IStorageInterface>(new Boot0Storage(bis_storage, this->client_info)), target_object_id);
|
||||
} else if (bis_partition_id == FsBisPartitionId_CalibrationBinary) {
|
||||
/* PRODINFO should *never* be writable. */
|
||||
/* If we have permissions, create a read only storage. */
|
||||
if (can_read_cal) {
|
||||
out.SetValue(std::make_shared<IStorageInterface>(new ReadOnlyStorageAdapter(new RemoteStorage(bis_storage))), target_object_id);
|
||||
} else {
|
||||
/* If we can't read cal, return permission denied. */
|
||||
fsStorageClose(&bis_storage);
|
||||
return fs::ResultPermissionDenied();
|
||||
}
|
||||
out.SetValue(std::make_shared<IStorageInterface>(new CalibrationBinaryStorage(bis_storage, this->client_info)), target_object_id);
|
||||
} else {
|
||||
if (can_write_bis || can_write_bis_for_choi_support) {
|
||||
/* We can write, so create a writable storage. */
|
||||
|
||||
@@ -54,6 +54,11 @@ namespace ams::mitm::fs {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* We want to mitm settings, to intercept CAL0. */
|
||||
if (program_id == ncm::SystemProgramId::Settings) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* We want to mitm sdb, to support sd-romfs redirection of common system archives (like system font, etc). */
|
||||
if (program_id == ncm::SystemProgramId::Sdb) {
|
||||
return true;
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 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 <stratosphere.hpp>
|
||||
#include "fsmitm_calibration_binary_storage.hpp"
|
||||
|
||||
namespace ams::mitm::fs {
|
||||
|
||||
using namespace ams::fs;
|
||||
|
||||
namespace {
|
||||
|
||||
os::Mutex g_cal0_access_mutex(false);
|
||||
|
||||
}
|
||||
Result CalibrationBinaryStorage::Read(s64 offset, void *_buffer, size_t size) {
|
||||
/* Acquire exclusive calibration binary access. */
|
||||
std::scoped_lock lk(g_cal0_access_mutex);
|
||||
|
||||
/* Get u8 buffer. */
|
||||
u8 *buffer = static_cast<u8 *>(_buffer);
|
||||
|
||||
/* Succeed on zero-size. */
|
||||
R_SUCCEED_IF(size == 0);
|
||||
|
||||
/* Handle the blank region. */
|
||||
if (this->read_blank) {
|
||||
if (BlankStartOffset <= offset && offset < BlankEndOffset) {
|
||||
const size_t blank_size = std::min(size, static_cast<size_t>(BlankEndOffset - offset));
|
||||
mitm::ReadFromBlankCalibrationBinary(offset, buffer, blank_size);
|
||||
size -= blank_size;
|
||||
buffer += blank_size;
|
||||
offset += blank_size;
|
||||
}
|
||||
}
|
||||
|
||||
/* Succeed if we're done. */
|
||||
R_SUCCEED_IF(size == 0);
|
||||
|
||||
/* Handle any in-between data. */
|
||||
if (BlankEndOffset <= offset && offset < FakeSecureStartOffset) {
|
||||
const size_t mid_size = std::min(size, static_cast<size_t>(FakeSecureStartOffset - offset));
|
||||
R_TRY(Base::Read(offset, buffer, mid_size));
|
||||
size -= mid_size;
|
||||
buffer += mid_size;
|
||||
offset += mid_size;
|
||||
}
|
||||
|
||||
/* Succeed if we're done. */
|
||||
R_SUCCEED_IF(size == 0);
|
||||
|
||||
/* Handle the secure region. */
|
||||
if (FakeSecureStartOffset <= offset && offset < FakeSecureEndOffset) {
|
||||
const size_t fake_size = std::min(size, static_cast<size_t>(FakeSecureEndOffset - offset));
|
||||
mitm::ReadFromFakeSecureBackupStorage(offset, buffer, fake_size);
|
||||
size -= fake_size;
|
||||
buffer += fake_size;
|
||||
offset += fake_size;
|
||||
}
|
||||
|
||||
/* Succeed if we're done. */
|
||||
R_SUCCEED_IF(size == 0);
|
||||
|
||||
/* Handle any remaining data. */
|
||||
return Base::Read(offset, buffer, size);
|
||||
}
|
||||
|
||||
Result CalibrationBinaryStorage::Write(s64 offset, const void *_buffer, size_t size) {
|
||||
/* Acquire exclusive calibration binary access. */
|
||||
std::scoped_lock lk(g_cal0_access_mutex);
|
||||
|
||||
/* Get const u8 buffer. */
|
||||
const u8 *buffer = static_cast<const u8 *>(_buffer);
|
||||
|
||||
/* Succeed on zero-size. */
|
||||
R_SUCCEED_IF(size == 0);
|
||||
|
||||
/* Only allow writes if we should. */
|
||||
R_UNLESS(this->allow_writes, fs::ResultUnsupportedOperation());
|
||||
|
||||
/* Handle the blank region. */
|
||||
if (this->read_blank) {
|
||||
if (BlankStartOffset <= offset && offset < BlankEndOffset) {
|
||||
const size_t blank_size = std::min(size, static_cast<size_t>(BlankEndOffset - offset));
|
||||
mitm::WriteToBlankCalibrationBinary(offset, buffer, blank_size);
|
||||
size -= blank_size;
|
||||
buffer += blank_size;
|
||||
offset += blank_size;
|
||||
}
|
||||
}
|
||||
|
||||
/* Succeed if we're done. */
|
||||
R_SUCCEED_IF(size == 0);
|
||||
|
||||
/* Handle any in-between data. */
|
||||
if (BlankEndOffset <= offset && offset < FakeSecureStartOffset) {
|
||||
const size_t mid_size = std::min(size, static_cast<size_t>(FakeSecureStartOffset - offset));
|
||||
R_TRY(Base::Write(offset, buffer, mid_size));
|
||||
size -= mid_size;
|
||||
buffer += mid_size;
|
||||
offset += mid_size;
|
||||
}
|
||||
|
||||
/* Succeed if we're done. */
|
||||
R_SUCCEED_IF(size == 0);
|
||||
|
||||
/* Handle the secure region. */
|
||||
if (FakeSecureStartOffset <= offset && offset < FakeSecureEndOffset) {
|
||||
const size_t fake_size = std::min(size, static_cast<size_t>(FakeSecureEndOffset - offset));
|
||||
mitm::WriteToFakeSecureBackupStorage(offset, buffer, fake_size);
|
||||
size -= fake_size;
|
||||
buffer += fake_size;
|
||||
offset += fake_size;
|
||||
}
|
||||
|
||||
/* Succeed if we're done. */
|
||||
R_SUCCEED_IF(size == 0);
|
||||
|
||||
/* Handle any remaining data. */
|
||||
return Base::Write(offset, buffer, size);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 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 <stratosphere.hpp>
|
||||
#include "fsmitm_boot0storage.hpp"
|
||||
#include "../amsmitm_prodinfo_utils.hpp"
|
||||
|
||||
namespace ams::mitm::fs {
|
||||
|
||||
/* Represents a protected calibration binary partition. */
|
||||
class CalibrationBinaryStorage : public SectoredStorageAdapter<ams::fs::RemoteStorage, 0x200> {
|
||||
public:
|
||||
using Base = SectoredStorageAdapter<ams::fs::RemoteStorage, 0x200>;
|
||||
|
||||
static constexpr s64 BlankStartOffset = 0x0;
|
||||
static constexpr s64 BlankSize = static_cast<s64>(CalibrationBinarySize);
|
||||
static constexpr s64 BlankEndOffset = BlankStartOffset + BlankSize;
|
||||
|
||||
static constexpr s64 FakeSecureStartOffset = SecureCalibrationInfoBackupOffset;
|
||||
static constexpr s64 FakeSecureSize = static_cast<s64>(SecureCalibrationBinaryBackupSize);
|
||||
static constexpr s64 FakeSecureEndOffset = FakeSecureStartOffset + FakeSecureSize;
|
||||
private:
|
||||
sm::MitmProcessInfo client_info;
|
||||
bool read_blank;
|
||||
bool allow_writes;
|
||||
public:
|
||||
CalibrationBinaryStorage(FsStorage &s, const sm::MitmProcessInfo &c)
|
||||
: Base(s), client_info(c),
|
||||
read_blank(mitm::ShouldReadBlankCalibrationBinary()),
|
||||
allow_writes(mitm::IsWriteToCalibrationBinaryAllowed())
|
||||
{
|
||||
/* ... */
|
||||
}
|
||||
public:
|
||||
virtual Result Read(s64 offset, void *_buffer, size_t size) override;
|
||||
virtual Result Write(s64 offset, const void *_buffer, size_t size) override;
|
||||
};
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user