sprofile: fix off-by-one in struct definition, fix GetImportableProfileUrls

This commit is contained in:
Michael Scire 2021-10-29 15:41:25 -07:00
parent d1f3c4904b
commit 2a0b99d9f9
5 changed files with 59 additions and 18 deletions

View file

@ -19,7 +19,7 @@
#define AMS_SPROFILE_I_SPROFILE_SERVICE_FOR_BG_AGENT_INTERFACE_INFO(C, H) \ #define AMS_SPROFILE_I_SPROFILE_SERVICE_FOR_BG_AGENT_INTERFACE_INFO(C, H) \
AMS_SF_METHOD_INFO(C, H, 100, Result, OpenProfileImporter, (sf::Out<sf::SharedPointer<::ams::sprofile::IProfileImporter>> out), (out)) \ AMS_SF_METHOD_INFO(C, H, 100, Result, OpenProfileImporter, (sf::Out<sf::SharedPointer<::ams::sprofile::IProfileImporter>> out), (out)) \
AMS_SF_METHOD_INFO(C, H, 200, Result, GetMetadataEntryData, (sf::Out<u32> out_count, const sf::OutArray<sprofile::srv::ProfileMetadataEntryData> &out, const sprofile::srv::ProfileMetadataForImportMetadata &arg), (out_count, out, arg)) \ AMS_SF_METHOD_INFO(C, H, 200, Result, GetImportableProfileUrls, (sf::Out<u32> out_count, const sf::OutArray<sprofile::srv::ProfileUrl> &out, const sprofile::srv::ProfileMetadataForImportMetadata &arg), (out_count, out, arg)) \
AMS_SF_METHOD_INFO(C, H, 201, Result, IsUpdateNeeded, (sf::Out<bool> out, sprofile::Identifier revision_key), (out, revision_key)) \ AMS_SF_METHOD_INFO(C, H, 201, Result, IsUpdateNeeded, (sf::Out<bool> out, sprofile::Identifier revision_key), (out, revision_key)) \
AMS_SF_METHOD_INFO(C, H, 2000, Result, Reset, (), ()) AMS_SF_METHOD_INFO(C, H, 2000, Result, Reset, (), ())

View file

@ -260,7 +260,7 @@ namespace ams::sprofile::srv {
crypto::Md5Generator md5; crypto::Md5Generator md5;
md5.Update(std::addressof(import.header), sizeof(import.header)); md5.Update(std::addressof(import.header), sizeof(import.header));
md5.Update(std::addressof(import.metadata), sizeof(import.metadata)); md5.Update(std::addressof(import.metadata), sizeof(import.metadata));
md5.Update(std::addressof(import.entries), sizeof(import.entries[0]) * std::min<size_t>(import.metadata.num_entries, util::size(import.metadata.entries))); md5.Update(std::addressof(import.profile_urls), sizeof(import.profile_urls[0]) * std::min<size_t>(import.metadata.num_entries, util::size(import.metadata.entries)));
u8 hash[crypto::Md5Generator::HashSize]; u8 hash[crypto::Md5Generator::HashSize];
md5.GetHash(hash, sizeof(hash)); md5.GetHash(hash, sizeof(hash));

View file

@ -34,7 +34,7 @@ namespace ams::sprofile::srv {
return ResultSuccess(); return ResultSuccess();
} }
Result ServiceForBgAgent::GetMetadataEntryData(sf::Out<u32> out_count, const sf::OutArray<sprofile::srv::ProfileMetadataEntryData> &out, const sprofile::srv::ProfileMetadataForImportMetadata &arg) { Result ServiceForBgAgent::GetImportableProfileUrls(sf::Out<u32> out_count, const sf::OutArray<sprofile::srv::ProfileUrl> &out, const sprofile::srv::ProfileMetadataForImportMetadata &arg) {
/* Check size. */ /* Check size. */
R_UNLESS(out.GetSize() >= arg.metadata.num_entries, sprofile::ResultInvalidArgument()); R_UNLESS(out.GetSize() >= arg.metadata.num_entries, sprofile::ResultInvalidArgument());
@ -42,25 +42,31 @@ namespace ams::sprofile::srv {
sprofile::srv::ProfileMetadata primary_metadata; sprofile::srv::ProfileMetadata primary_metadata;
R_TRY_CATCH(m_profile_manager->LoadPrimaryMetadata(std::addressof(primary_metadata))) { R_TRY_CATCH(m_profile_manager->LoadPrimaryMetadata(std::addressof(primary_metadata))) {
R_CATCH(fs::ResultPathNotFound) { R_CATCH(fs::ResultPathNotFound) {
/* If we have no metadata, we can't get any entries. */ /* It's okay if we have no primary metadata -- this means that all profiles are importable. */
*out_count = 0; primary_metadata.num_entries = 0;
return ResultSuccess();
} }
} R_END_TRY_CATCH; } R_END_TRY_CATCH;
/* Copy matching entries. */ /* We want to return the set of profiles that can be imported, which is just the profiles we don't already have. */
u32 count = 0; u32 count = 0;
for (u32 i = 0; i < arg.metadata.num_entries; ++i) { for (u32 i = 0; i < arg.metadata.num_entries; ++i) {
const auto &arg_entry = arg.metadata.entries[i]; const auto &arg_entry = arg.metadata.entries[i];
/* Check if we have the entry. */
bool have_entry = false;
for (u32 j = 0; j < primary_metadata.num_entries; ++j) { for (u32 j = 0; j < primary_metadata.num_entries; ++j) {
const auto &pri_entry = primary_metadata.entries[j]; const auto &pri_entry = primary_metadata.entries[j];
if (pri_entry.identifier_0 == arg_entry.identifier_0 && pri_entry.identifier_1 == arg_entry.identifier_1) { if (pri_entry.identifier_0 == arg_entry.identifier_0 && pri_entry.identifier_1 == arg_entry.identifier_1) {
out[count++] = arg.entries[i]; have_entry = true;
break; break;
} }
} }
/* If we don't already have the entry, it's importable -- copy it out. */
if (!have_entry) {
out[count++] = arg.profile_urls[i];
}
} }
/* Set output count. */ /* Set output count. */

View file

@ -29,7 +29,7 @@ namespace ams::sprofile::srv {
constexpr ServiceForBgAgent(MemoryResource *mr, ProfileManager *pm) : m_memory_resource(mr), m_profile_manager(pm) { /* ... */ } constexpr ServiceForBgAgent(MemoryResource *mr, ProfileManager *pm) : m_memory_resource(mr), m_profile_manager(pm) { /* ... */ }
public: public:
Result OpenProfileImporter(sf::Out<sf::SharedPointer<::ams::sprofile::IProfileImporter>> out); Result OpenProfileImporter(sf::Out<sf::SharedPointer<::ams::sprofile::IProfileImporter>> out);
Result GetMetadataEntryData(sf::Out<u32> out_count, const sf::OutArray<sprofile::srv::ProfileMetadataEntryData> &out, const sprofile::srv::ProfileMetadataForImportMetadata &arg); Result GetImportableProfileUrls(sf::Out<u32> out_count, const sf::OutArray<sprofile::srv::ProfileUrl> &out, const sprofile::srv::ProfileMetadataForImportMetadata &arg);
Result IsUpdateNeeded(sf::Out<bool> out, Identifier revision_key); Result IsUpdateNeeded(sf::Out<bool> out, Identifier revision_key);
Result Reset(); Result Reset();
}; };

View file

@ -46,6 +46,10 @@ namespace ams::sprofile::srv {
static_assert(util::is_pod<ProfileDataEntry>::value); static_assert(util::is_pod<ProfileDataEntry>::value);
static_assert(sizeof(ProfileDataEntry) == 0x10); static_assert(sizeof(ProfileDataEntry) == 0x10);
static_assert(AMS_OFFSETOF(ProfileDataEntry, key) == 0x00);
static_assert(AMS_OFFSETOF(ProfileDataEntry, type) == 0x07);
static_assert(AMS_OFFSETOF(ProfileDataEntry, value_s64) == 0x08);
struct ProfileData { struct ProfileData {
u32 num_entries; u32 num_entries;
u8 unk_04[0x0C]; u8 unk_04[0x0C];
@ -55,6 +59,11 @@ namespace ams::sprofile::srv {
static_assert(util::is_pod<ProfileData>::value); static_assert(util::is_pod<ProfileData>::value);
static_assert(sizeof(ProfileData) == 0x4000); static_assert(sizeof(ProfileData) == 0x4000);
static_assert(AMS_OFFSETOF(ProfileData, num_entries) == 0x00);
static_assert(AMS_OFFSETOF(ProfileData, unk_04) == 0x04);
static_assert(AMS_OFFSETOF(ProfileData, unk_10) == 0x10);
static_assert(AMS_OFFSETOF(ProfileData, entries) == 0x30);
struct ServiceProfile { struct ServiceProfile {
Identifier name; Identifier name;
ProfileData data; ProfileData data;
@ -62,6 +71,9 @@ namespace ams::sprofile::srv {
static_assert(util::is_pod<ServiceProfile>::value); static_assert(util::is_pod<ServiceProfile>::value);
static_assert(sizeof(ServiceProfile) == 0x4008); static_assert(sizeof(ServiceProfile) == 0x4008);
static_assert(AMS_OFFSETOF(ServiceProfile, name) == 0x00);
static_assert(AMS_OFFSETOF(ServiceProfile, data) == 0x08);
struct ProfileDataForImportData : public sf::LargeData, public sf::PrefersMapAliasTransferMode { struct ProfileDataForImportData : public sf::LargeData, public sf::PrefersMapAliasTransferMode {
struct { struct {
Identifier identifier_0; Identifier identifier_0;
@ -77,6 +89,11 @@ namespace ams::sprofile::srv {
static_assert(util::is_pod<ProfileDataForImportData>::value); static_assert(util::is_pod<ProfileDataForImportData>::value);
static_assert(sizeof(ProfileDataForImportData) == 0x4400); static_assert(sizeof(ProfileDataForImportData) == 0x4400);
static_assert(AMS_OFFSETOF(ProfileDataForImportData, header) == 0x00);
static_assert(AMS_OFFSETOF(ProfileDataForImportData, hash) == 0x30);
static_assert(AMS_OFFSETOF(ProfileDataForImportData, data) == 0x40);
static_assert(AMS_OFFSETOF(ProfileDataForImportData, unk_4040) == 0x4040);
struct ProfileMetadataEntry { struct ProfileMetadataEntry {
Identifier identifier_0; Identifier identifier_0;
Identifier identifier_1; Identifier identifier_1;
@ -85,22 +102,34 @@ namespace ams::sprofile::srv {
static_assert(util::is_pod<ProfileMetadataEntry>::value); static_assert(util::is_pod<ProfileMetadataEntry>::value);
static_assert(sizeof(ProfileMetadataEntry) == 0x40); static_assert(sizeof(ProfileMetadataEntry) == 0x40);
struct ProfileMetadataEntryData : public sf::PrefersMapAliasTransferMode { static_assert(AMS_OFFSETOF(ProfileMetadataEntry, identifier_0) == 0x00);
u8 unk[0x100]; static_assert(AMS_OFFSETOF(ProfileMetadataEntry, identifier_1) == 0x07);
static_assert(AMS_OFFSETOF(ProfileMetadataEntry, unk_0E) == 0x0E);
struct ProfileUrl : public sf::PrefersMapAliasTransferMode {
char url[0x100];
}; };
static_assert(util::is_pod<ProfileMetadataEntryData>::value); static_assert(util::is_pod<ProfileUrl>::value);
static_assert(sizeof(ProfileMetadataEntryData) == 0x100); static_assert(sizeof(ProfileUrl) == 0x100);
struct ProfileMetadata { struct ProfileMetadata {
u32 num_entries; u32 num_entries;
u32 unk_04; u32 unk_04;
Identifier revision_key; Identifier revision_key;
u8 unk_0F[0x1];
u8 unk_10[0x30]; u8 unk_10[0x30];
ProfileMetadataEntry entries[50]; ProfileMetadataEntry entries[50];
}; };
static_assert(util::is_pod<ProfileMetadata>::value); static_assert(util::is_pod<ProfileMetadata>::value);
static_assert(sizeof(ProfileMetadata) == 0xCC0); static_assert(sizeof(ProfileMetadata) == 0xCC0);
static_assert(AMS_OFFSETOF(ProfileMetadata, num_entries) == 0x00);
static_assert(AMS_OFFSETOF(ProfileMetadata, unk_04) == 0x04);
static_assert(AMS_OFFSETOF(ProfileMetadata, revision_key) == 0x08);
static_assert(AMS_OFFSETOF(ProfileMetadata, unk_0F) == 0x0F);
static_assert(AMS_OFFSETOF(ProfileMetadata, unk_10) == 0x10);
static_assert(AMS_OFFSETOF(ProfileMetadata, entries) == 0x40);
struct ProfileMetadataForImportMetadata : public sf::LargeData, public sf::PrefersMapAliasTransferMode { struct ProfileMetadataForImportMetadata : public sf::LargeData, public sf::PrefersMapAliasTransferMode {
struct { struct {
u32 version; u32 version;
@ -108,10 +137,16 @@ namespace ams::sprofile::srv {
} header; } header;
u8 hash[crypto::Md5Generator::HashSize]; u8 hash[crypto::Md5Generator::HashSize];
ProfileMetadata metadata; ProfileMetadata metadata;
ProfileMetadataEntryData entries[50]; ProfileUrl profile_urls[50];
u8 unk[0x8000 - 0x3EF0]; u8 unk_3EF0[0x8000 - 0x3EF0];
}; };
static_assert(util::is_pod<ProfileMetadataForImportMetadata>::value); static_assert(util::is_pod<ProfileMetadataForImportMetadata>::value);
static_assert(sizeof(ProfileMetadataForImportMetadata) == 0x8000); static_assert(sizeof(ProfileMetadataForImportMetadata) == 0x8000);
static_assert(AMS_OFFSETOF(ProfileMetadataForImportMetadata, header) == 0x00);
static_assert(AMS_OFFSETOF(ProfileMetadataForImportMetadata, hash) == 0x20);
static_assert(AMS_OFFSETOF(ProfileMetadataForImportMetadata, metadata) == 0x30);
static_assert(AMS_OFFSETOF(ProfileMetadataForImportMetadata, profile_urls) == 0xCF0);
static_assert(AMS_OFFSETOF(ProfileMetadataForImportMetadata, unk_3EF0) == 0x3EF0);
} }