Merge pull request #10005 from liamwhite/kernel-atomics

kernel: fix unbounded stack usage in atomics
This commit is contained in:
bunnei 2023-04-01 01:54:36 -07:00 committed by GitHub
commit 0730dc6c44
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 54 additions and 37 deletions

View file

@ -35,8 +35,11 @@ bool DecrementIfLessThan(Core::System& system, s32* out, KProcessAddress address
// TODO(bunnei): We should call CanAccessAtomic(..) here. // TODO(bunnei): We should call CanAccessAtomic(..) here.
s32 current_value{};
while (true) {
// Load the value from the address. // Load the value from the address.
const s32 current_value = current_value =
static_cast<s32>(monitor.ExclusiveRead32(current_core, GetInteger(address))); static_cast<s32>(monitor.ExclusiveRead32(current_core, GetInteger(address)));
// Compare it to the desired one. // Compare it to the desired one.
@ -45,14 +48,17 @@ bool DecrementIfLessThan(Core::System& system, s32* out, KProcessAddress address
const s32 decrement_value = current_value - 1; const s32 decrement_value = current_value - 1;
// Decrement and try to store. // Decrement and try to store.
if (!monitor.ExclusiveWrite32(current_core, GetInteger(address), if (monitor.ExclusiveWrite32(current_core, GetInteger(address),
static_cast<u32>(decrement_value))) { static_cast<u32>(decrement_value))) {
// If we failed to store, try again. break;
DecrementIfLessThan(system, out, address, value);
} }
// If we failed to store, try again.
} else { } else {
// Otherwise, clear our exclusive hold and finish // Otherwise, clear our exclusive hold and finish
monitor.ClearExclusive(current_core); monitor.ClearExclusive(current_core);
break;
}
} }
// We're done. // We're done.
@ -70,8 +76,11 @@ bool UpdateIfEqual(Core::System& system, s32* out, KProcessAddress address, s32
// TODO(bunnei): We should call CanAccessAtomic(..) here. // TODO(bunnei): We should call CanAccessAtomic(..) here.
s32 current_value{};
// Load the value from the address. // Load the value from the address.
const s32 current_value = while (true) {
current_value =
static_cast<s32>(monitor.ExclusiveRead32(current_core, GetInteger(address))); static_cast<s32>(monitor.ExclusiveRead32(current_core, GetInteger(address)));
// Compare it to the desired one. // Compare it to the desired one.
@ -79,14 +88,17 @@ bool UpdateIfEqual(Core::System& system, s32* out, KProcessAddress address, s32
// If equal, we want to try to write the new value. // If equal, we want to try to write the new value.
// Try to store. // Try to store.
if (!monitor.ExclusiveWrite32(current_core, GetInteger(address), if (monitor.ExclusiveWrite32(current_core, GetInteger(address),
static_cast<u32>(new_value))) { static_cast<u32>(new_value))) {
// If we failed to store, try again. break;
UpdateIfEqual(system, out, address, value, new_value);
} }
// If we failed to store, try again.
} else { } else {
// Otherwise, clear our exclusive hold and finish. // Otherwise, clear our exclusive hold and finish.
monitor.ClearExclusive(current_core); monitor.ClearExclusive(current_core);
break;
}
} }
// We're done. // We're done.

View file

@ -33,8 +33,11 @@ bool UpdateLockAtomic(Core::System& system, u32* out, KProcessAddress address, u
auto& monitor = system.Monitor(); auto& monitor = system.Monitor();
const auto current_core = system.Kernel().CurrentPhysicalCoreIndex(); const auto current_core = system.Kernel().CurrentPhysicalCoreIndex();
u32 expected{};
while (true) {
// Load the value from the address. // Load the value from the address.
const auto expected = monitor.ExclusiveRead32(current_core, GetInteger(address)); expected = monitor.ExclusiveRead32(current_core, GetInteger(address));
// Orr in the new mask. // Orr in the new mask.
u32 value = expected | new_orr_mask; u32 value = expected | new_orr_mask;
@ -45,9 +48,11 @@ bool UpdateLockAtomic(Core::System& system, u32* out, KProcessAddress address, u
} }
// Try to store. // Try to store.
if (!monitor.ExclusiveWrite32(current_core, GetInteger(address), value)) { if (monitor.ExclusiveWrite32(current_core, GetInteger(address), value)) {
break;
}
// If we failed to store, try again. // If we failed to store, try again.
return UpdateLockAtomic(system, out, address, if_zero, new_orr_mask);
} }
// We're done. // We're done.