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:
SciresM
2020-04-22 16:22:14 -07:00
committed by GitHub
parent 6ac1ff6f24
commit 3bc2d79384
42 changed files with 1355 additions and 142 deletions

View File

@@ -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. */

View File

@@ -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;

View File

@@ -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);
}
}

View File

@@ -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;
};
}