[XAM] Validate buffer_size limit in XamEnumerate

This commit is contained in:
Adrian
2026-02-13 23:23:12 +00:00
committed by Radosław Gliński
parent 8351eec1ec
commit 54be3c57a0

View File

@@ -62,19 +62,28 @@ uint8_t* XStaticUntypedEnumerator::AppendItem() {
uint32_t XStaticUntypedEnumerator::WriteItems(uint8_t* buffer_data,
uint32_t buffer_size,
uint32_t* written_count) {
size_t count = std::min(item_count_ - current_item_, items_per_enumerate());
if (!count) {
const size_t actual_count =
std::min(item_count_ - current_item_, items_per_enumerate());
if (!actual_count) {
return X_ERROR_NO_MORE_FILES;
}
size_t size = count * item_size();
size_t offset = current_item_ * item_size();
// 4E4D07F0 does not respect buffer_size for XContentCreateEnumerator.
assert_false(buffer_size < item_size());
const size_t available_count = buffer_size / item_size();
const size_t size = actual_count * item_size();
const size_t offset = current_item_ * item_size();
// Some enumerators expect buffer_size to be respected for now assert.
assert_false(actual_count > available_count);
std::memcpy(buffer_data, buffer_.data() + offset, size);
current_item_ += count;
current_item_ += actual_count;
if (written_count) {
*written_count = static_cast<uint32_t>(count);
*written_count = static_cast<uint32_t>(actual_count);
}
return X_ERROR_SUCCESS;
@@ -83,19 +92,24 @@ uint32_t XStaticUntypedEnumerator::WriteItems(uint8_t* buffer_data,
uint32_t XAchievementEnumerator::WriteItems(uint8_t* buffer_data,
uint32_t buffer_size,
uint32_t* written_count) {
if (items_.size() - current_item_ <= 0) {
const size_t actual_count =
std::min(items_.size() - current_item_, items_per_enumerate());
if (!actual_count) {
return X_ERROR_NO_MORE_FILES;
}
const size_t count =
std::min(items_.size() - current_item_, items_per_enumerate());
const size_t available_count = buffer_size / item_size();
// Unknown if buffer_size should be respected.
assert_false(actual_count > available_count);
auto details = reinterpret_cast<xam::X_ACHIEVEMENT_DETAILS*>(buffer_data);
size_t string_offset =
items_per_enumerate() * sizeof(xam::X_ACHIEVEMENT_DETAILS);
auto string_buffer =
StringBuffer{&buffer_data[string_offset],
count * xam::X_ACHIEVEMENT_DETAILS::kStringBufferSize};
for (size_t i = 0; i < count; ++i, ++current_item_) {
auto string_buffer = StringBuffer{
&buffer_data[string_offset],
actual_count * xam::X_ACHIEVEMENT_DETAILS::kStringBufferSize};
for (size_t i = 0; i < actual_count; ++i, ++current_item_) {
const auto& item = items_[current_item_];
details[i].id = item.id;
details[i].label_ptr =
@@ -112,7 +126,7 @@ uint32_t XAchievementEnumerator::WriteItems(uint8_t* buffer_data,
}
if (written_count) {
*written_count = static_cast<uint32_t>(count);
*written_count = static_cast<uint32_t>(actual_count);
}
return X_ERROR_SUCCESS;
@@ -121,15 +135,20 @@ uint32_t XAchievementEnumerator::WriteItems(uint8_t* buffer_data,
uint32_t XTitleEnumerator::WriteItems(uint8_t* buffer_data,
uint32_t buffer_size,
uint32_t* written_count) {
size_t count = std::min(items_.size() - current_item_, items_per_enumerate());
if (!count) {
const size_t actual_count =
std::min(items_.size() - current_item_, items_per_enumerate());
if (!actual_count) {
return X_ERROR_NO_MORE_FILES;
}
size_t size = count * item_size();
const size_t available_count = buffer_size / item_size();
// Unknown if buffer_size should be respected.
assert_false(actual_count > available_count);
auto details = reinterpret_cast<XTITLE_PLAYED*>(buffer_data);
for (size_t i = 0; i < count; ++i, ++current_item_) {
for (size_t i = 0; i < actual_count; ++i, ++current_item_) {
const auto& item = items_[current_item_];
details[i].base.title_id = item.id;
details[i].base.achievements_count = item.achievements_count;
@@ -157,7 +176,7 @@ uint32_t XTitleEnumerator::WriteItems(uint8_t* buffer_data,
}
if (written_count) {
*written_count = static_cast<uint32_t>(count);
*written_count = static_cast<uint32_t>(actual_count);
}
return X_ERROR_SUCCESS;
@@ -182,18 +201,22 @@ uint32_t XMPCreateUserPlaylistEnumerator::WriteItems(uint8_t* buffer_data,
// Fixed 545408C0 freezing at main menu.
std::memset(buffer_data, 0, buffer_size);
size_t count = std::min(items_.size() - current_item_, items_per_enumerate());
if (!count) {
const size_t actual_count =
std::min(items_.size() - current_item_, items_per_enumerate());
if (!actual_count) {
return X_ERROR_NO_MORE_FILES;
}
const size_t available_count = buffer_size / item_size();
const size_t valid_count = std::min(actual_count, available_count);
xam::XMP_USER_PLAYLIST_INFO* results =
reinterpret_cast<xam::XMP_USER_PLAYLIST_INFO*>(buffer_data);
std::copy_n(items_.begin() + current_item_, count, results);
std::copy_n(items_.begin() + current_item_, valid_count, results);
if (written_count) {
*written_count = static_cast<uint32_t>(count);
*written_count = static_cast<uint32_t>(valid_count);
}
return X_ERROR_SUCCESS;