From 281eb020ea6576e9525e35e4973313c39a553e8d Mon Sep 17 00:00:00 2001
From: german77 <juangerman-13@hotmail.com>
Date: Sat, 25 Nov 2023 22:19:46 -0600
Subject: [PATCH] service: nfc: Validate mii data

---
 .../hle/service/am/applets/applet_cabinet.cpp |  2 +-
 .../hle/service/mii/types/ver3_store_data.cpp |  2 +-
 src/core/hle/service/nfc/common/device.cpp    | 70 ++++++++++---------
 src/core/hle/service/nfc/common/device.h      |  1 -
 4 files changed, 40 insertions(+), 35 deletions(-)

diff --git a/src/core/hle/service/am/applets/applet_cabinet.cpp b/src/core/hle/service/am/applets/applet_cabinet.cpp
index b379dadebe..a88d9d2ce3 100644
--- a/src/core/hle/service/am/applets/applet_cabinet.cpp
+++ b/src/core/hle/service/am/applets/applet_cabinet.cpp
@@ -130,7 +130,7 @@ void Cabinet::DisplayCompleted(bool apply_changes, std::string_view amiibo_name)
         nfp_device->DeleteApplicationArea();
         break;
     case Service::NFP::CabinetMode::StartRestorer:
-        nfp_device->RestoreAmiibo();
+        nfp_device->Restore();
         break;
     case Service::NFP::CabinetMode::StartFormatter:
         nfp_device->Format();
diff --git a/src/core/hle/service/mii/types/ver3_store_data.cpp b/src/core/hle/service/mii/types/ver3_store_data.cpp
index a019cc9f71..c27646fcfd 100644
--- a/src/core/hle/service/mii/types/ver3_store_data.cpp
+++ b/src/core/hle/service/mii/types/ver3_store_data.cpp
@@ -98,7 +98,7 @@ void Ver3StoreData::BuildToStoreData(StoreData& out_store_data) const {
 }
 
 void Ver3StoreData::BuildFromStoreData(const StoreData& store_data) {
-    version = 1;
+    version = 3;
     mii_information.gender.Assign(static_cast<u8>(store_data.GetGender()));
     mii_information.favorite_color.Assign(static_cast<u8>(store_data.GetFavoriteColor()));
     height = store_data.GetHeight();
diff --git a/src/core/hle/service/nfc/common/device.cpp b/src/core/hle/service/nfc/common/device.cpp
index e7a00deb38..47516f8836 100644
--- a/src/core/hle/service/nfc/common/device.cpp
+++ b/src/core/hle/service/nfc/common/device.cpp
@@ -401,6 +401,12 @@ Result NfcDevice::SendCommandByPassThrough(const Time::Clock::TimeSpanType& time
 }
 
 Result NfcDevice::Mount(NFP::ModelType model_type, NFP::MountTarget mount_target_) {
+    bool is_corrupted = false;
+
+    if (model_type != NFP::ModelType::Amiibo) {
+        return ResultInvalidArgument;
+    }
+
     if (device_state != DeviceState::TagFound) {
         LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
         return ResultWrongDeviceState;
@@ -420,26 +426,32 @@ Result NfcDevice::Mount(NFP::ModelType model_type, NFP::MountTarget mount_target
     if (is_plain_amiibo) {
         std::vector<u8> data(sizeof(NFP::NTAG215File));
         memcpy(data.data(), &tag_data, sizeof(tag_data));
-        WriteBackupData(tag_data.uid, data);
-
-        device_state = DeviceState::TagMounted;
-        mount_target = mount_target_;
-        return ResultSuccess;
     }
 
-    if (!NFP::AmiiboCrypto::DecodeAmiibo(encrypted_tag_data, tag_data)) {
-        bool has_backup = HasBackup(encrypted_tag_data.uuid).IsSuccess();
-        LOG_ERROR(Service_NFP, "Can't decode amiibo, has_backup= {}", has_backup);
-        return has_backup ? ResultCorruptedDataWithBackup : ResultCorruptedData;
+    if (!is_plain_amiibo && !NFP::AmiiboCrypto::DecodeAmiibo(encrypted_tag_data, tag_data)) {
+        LOG_ERROR(Service_NFP, "Can't decode amiibo");
+        is_corrupted = true;
     }
 
-    std::vector<u8> data(sizeof(NFP::EncryptedNTAG215File));
-    memcpy(data.data(), &encrypted_tag_data, sizeof(encrypted_tag_data));
-    WriteBackupData(encrypted_tag_data.uuid, data);
+    if (tag_data.settings.settings.amiibo_initialized && !tag_data.owner_mii.IsValid()) {
+        LOG_ERROR(Service_NFP, "Invalid mii data");
+        is_corrupted = true;
+    }
+
+    if (!is_corrupted) {
+        std::vector<u8> data(sizeof(NFP::EncryptedNTAG215File));
+        memcpy(data.data(), &encrypted_tag_data, sizeof(encrypted_tag_data));
+        WriteBackupData(encrypted_tag_data.uuid, data);
+    }
 
     device_state = DeviceState::TagMounted;
     mount_target = mount_target_;
 
+    if (is_corrupted) {
+        bool has_backup = HasBackup(encrypted_tag_data.uuid).IsSuccess();
+        return has_backup ? ResultCorruptedDataWithBackup : ResultCorruptedData;
+    }
+
     return ResultSuccess;
 }
 
@@ -606,6 +618,17 @@ Result NfcDevice::Restore() {
         }
     }
 
+    // Restore mii data in case is corrupted by previous instances of yuzu
+    if (tag_data.settings.settings.amiibo_initialized && !tag_data.owner_mii.IsValid()) {
+        LOG_ERROR(Service_NFP, "Regenerating mii data");
+        Mii::StoreData new_mii{};
+        new_mii.BuildRandom(Mii::Age::All, Mii::Gender::All, Mii::Race::All);
+        new_mii.SetNickname({u'y', u'u', u'z', u'u', u'\0'});
+
+        tag_data.owner_mii.BuildFromStoreData(new_mii);
+        tag_data.mii_extension.SetFromStoreData(new_mii);
+    }
+
     // Overwrite tag contents with backup and mount the tag
     tag_data = temporary_tag_data;
     encrypted_tag_data = temporary_encrypted_tag_data;
@@ -851,25 +874,6 @@ Result NfcDevice::SetRegisterInfoPrivate(const NFP::RegisterInfoPrivate& registe
     return Flush();
 }
 
-Result NfcDevice::RestoreAmiibo() {
-    if (device_state != DeviceState::TagMounted) {
-        LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
-        if (device_state == DeviceState::TagRemoved) {
-            return ResultTagRemoved;
-        }
-        return ResultWrongDeviceState;
-    }
-
-    if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
-        LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
-        return ResultWrongDeviceState;
-    }
-
-    // TODO: Load amiibo from backup on system
-    LOG_ERROR(Service_NFP, "Not Implemented");
-    return ResultSuccess;
-}
-
 Result NfcDevice::Format() {
     Result result = ResultSuccess;
 
@@ -877,7 +881,9 @@ Result NfcDevice::Format() {
         result = Mount(NFP::ModelType::Amiibo, NFP::MountTarget::All);
     }
 
-    if (result.IsError()) {
+    // We are formatting all data. Corruption is not an issue.
+    if (result.IsError() &&
+        (result != ResultCorruptedData && result != ResultCorruptedDataWithBackup)) {
         return result;
     }
 
diff --git a/src/core/hle/service/nfc/common/device.h b/src/core/hle/service/nfc/common/device.h
index 0ed1ff34ca..d8efe25ec6 100644
--- a/src/core/hle/service/nfc/common/device.h
+++ b/src/core/hle/service/nfc/common/device.h
@@ -68,7 +68,6 @@ public:
 
     Result DeleteRegisterInfo();
     Result SetRegisterInfoPrivate(const NFP::RegisterInfoPrivate& register_info);
-    Result RestoreAmiibo();
     Result Format();
 
     Result OpenApplicationArea(u32 access_id);