controllers/npad: Validate device handles before use

Some games such as NEKOPARA Vol. 3 send invalid device handles when calling InitializeVibrationDevice. Introduce a check to validate the device handle before use.
master
Morph 2020-12-12 06:37:08 +07:00
parent 69b46dd607
commit 1c773c0869
2 changed files with 45 additions and 0 deletions

@ -116,6 +116,31 @@ u32 Controller_NPad::IndexToNPad(std::size_t index) {
} }
} }
bool Controller_NPad::IsNpadIdValid(u32 npad_id) {
switch (npad_id) {
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
case NPAD_UNKNOWN:
case NPAD_HANDHELD:
return true;
default:
LOG_ERROR(Service_HID, "Invalid npad id {}", npad_id);
return false;
}
}
bool Controller_NPad::IsDeviceHandleValid(const DeviceHandle& device_handle) {
return IsNpadIdValid(device_handle.npad_id) &&
device_handle.npad_type < NpadType::MaxNpadType &&
device_handle.device_index < DeviceIndex::MaxDeviceIndex;
}
Controller_NPad::Controller_NPad(Core::System& system) : ControllerBase(system), system(system) {} Controller_NPad::Controller_NPad(Core::System& system) : ControllerBase(system), system(system) {}
Controller_NPad::~Controller_NPad() { Controller_NPad::~Controller_NPad() {
@ -742,6 +767,10 @@ bool Controller_NPad::VibrateControllerAtIndex(std::size_t npad_index, std::size
void Controller_NPad::VibrateController(const DeviceHandle& vibration_device_handle, void Controller_NPad::VibrateController(const DeviceHandle& vibration_device_handle,
const VibrationValue& vibration_value) { const VibrationValue& vibration_value) {
if (!IsDeviceHandleValid(vibration_device_handle)) {
return;
}
if (!Settings::values.vibration_enabled.GetValue() && !permit_vibration_session_enabled) { if (!Settings::values.vibration_enabled.GetValue() && !permit_vibration_session_enabled) {
return; return;
} }
@ -798,12 +827,20 @@ void Controller_NPad::VibrateControllers(const std::vector<DeviceHandle>& vibrat
Controller_NPad::VibrationValue Controller_NPad::GetLastVibration( Controller_NPad::VibrationValue Controller_NPad::GetLastVibration(
const DeviceHandle& vibration_device_handle) const { const DeviceHandle& vibration_device_handle) const {
if (!IsDeviceHandleValid(vibration_device_handle)) {
return {};
}
const auto npad_index = NPadIdToIndex(vibration_device_handle.npad_id); const auto npad_index = NPadIdToIndex(vibration_device_handle.npad_id);
const auto device_index = static_cast<std::size_t>(vibration_device_handle.device_index); const auto device_index = static_cast<std::size_t>(vibration_device_handle.device_index);
return latest_vibration_values[npad_index][device_index]; return latest_vibration_values[npad_index][device_index];
} }
void Controller_NPad::InitializeVibrationDevice(const DeviceHandle& vibration_device_handle) { void Controller_NPad::InitializeVibrationDevice(const DeviceHandle& vibration_device_handle) {
if (!IsDeviceHandleValid(vibration_device_handle)) {
return;
}
const auto npad_index = NPadIdToIndex(vibration_device_handle.npad_id); const auto npad_index = NPadIdToIndex(vibration_device_handle.npad_id);
const auto device_index = static_cast<std::size_t>(vibration_device_handle.device_index); const auto device_index = static_cast<std::size_t>(vibration_device_handle.device_index);
InitializeVibrationDeviceAtIndex(npad_index, device_index); InitializeVibrationDeviceAtIndex(npad_index, device_index);
@ -824,6 +861,10 @@ void Controller_NPad::SetPermitVibrationSession(bool permit_vibration_session) {
} }
bool Controller_NPad::IsVibrationDeviceMounted(const DeviceHandle& vibration_device_handle) const { bool Controller_NPad::IsVibrationDeviceMounted(const DeviceHandle& vibration_device_handle) const {
if (!IsDeviceHandleValid(vibration_device_handle)) {
return false;
}
const auto npad_index = NPadIdToIndex(vibration_device_handle.npad_id); const auto npad_index = NPadIdToIndex(vibration_device_handle.npad_id);
const auto device_index = static_cast<std::size_t>(vibration_device_handle.device_index); const auto device_index = static_cast<std::size_t>(vibration_device_handle.device_index);
return vibration_devices_mounted[npad_index][device_index]; return vibration_devices_mounted[npad_index][device_index];

@ -56,12 +56,14 @@ public:
JoyconLeft = 6, JoyconLeft = 6,
JoyconRight = 7, JoyconRight = 7,
Pokeball = 9, Pokeball = 9,
MaxNpadType = 10,
}; };
enum class DeviceIndex : u8 { enum class DeviceIndex : u8 {
Left = 0, Left = 0,
Right = 1, Right = 1,
None = 2, None = 2,
MaxDeviceIndex = 3,
}; };
enum class GyroscopeZeroDriftMode : u32 { enum class GyroscopeZeroDriftMode : u32 {
@ -213,6 +215,8 @@ public:
static Settings::ControllerType MapNPadToSettingsType(Controller_NPad::NPadControllerType type); static Settings::ControllerType MapNPadToSettingsType(Controller_NPad::NPadControllerType type);
static std::size_t NPadIdToIndex(u32 npad_id); static std::size_t NPadIdToIndex(u32 npad_id);
static u32 IndexToNPad(std::size_t index); static u32 IndexToNPad(std::size_t index);
static bool IsNpadIdValid(u32 npad_id);
static bool IsDeviceHandleValid(const DeviceHandle& device_handle);
private: private:
struct CommonHeader { struct CommonHeader {