nvdrv, video_core: Don't index out of bounds when given invalid syncpoint ID
- Use .at() instead of raw indexing when dealing with untrusted indices. - For the special case of WaitFence with syncpoint id UINT32_MAX, instead of crashing, log an error and ignore. This is what I get when running Super Mario Maker 2.
This commit is contained in:
		| @@ -37,7 +37,7 @@ public: | |||||||
|      * @returns The lower bound for the specified syncpoint. |      * @returns The lower bound for the specified syncpoint. | ||||||
|      */ |      */ | ||||||
|     u32 GetSyncpointMin(u32 syncpoint_id) const { |     u32 GetSyncpointMin(u32 syncpoint_id) const { | ||||||
|         return syncpoints[syncpoint_id].min.load(std::memory_order_relaxed); |         return syncpoints.at(syncpoint_id).min.load(std::memory_order_relaxed); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
| @@ -46,7 +46,7 @@ public: | |||||||
|      * @returns The upper bound for the specified syncpoint. |      * @returns The upper bound for the specified syncpoint. | ||||||
|      */ |      */ | ||||||
|     u32 GetSyncpointMax(u32 syncpoint_id) const { |     u32 GetSyncpointMax(u32 syncpoint_id) const { | ||||||
|         return syncpoints[syncpoint_id].max.load(std::memory_order_relaxed); |         return syncpoints.at(syncpoint_id).max.load(std::memory_order_relaxed); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|   | |||||||
| @@ -95,22 +95,29 @@ void GPU::WaitFence(u32 syncpoint_id, u32 value) { | |||||||
|     if (!is_async) { |     if (!is_async) { | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|  |     if (syncpoint_id == UINT32_MAX) { | ||||||
|  |         // TODO: Research what this does. | ||||||
|  |         LOG_ERROR(HW_GPU, "Waiting for syncpoint -1 not implemented"); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|     MICROPROFILE_SCOPE(GPU_wait); |     MICROPROFILE_SCOPE(GPU_wait); | ||||||
|     std::unique_lock lock{sync_mutex}; |     std::unique_lock lock{sync_mutex}; | ||||||
|     sync_cv.wait(lock, [=, this] { return syncpoints[syncpoint_id].load() >= value; }); |     sync_cv.wait(lock, [=, this] { return syncpoints.at(syncpoint_id).load() >= value; }); | ||||||
| } | } | ||||||
|  |  | ||||||
| void GPU::IncrementSyncPoint(const u32 syncpoint_id) { | void GPU::IncrementSyncPoint(const u32 syncpoint_id) { | ||||||
|     syncpoints[syncpoint_id]++; |     auto& syncpoint = syncpoints.at(syncpoint_id); | ||||||
|  |     syncpoint++; | ||||||
|     std::lock_guard lock{sync_mutex}; |     std::lock_guard lock{sync_mutex}; | ||||||
|     sync_cv.notify_all(); |     sync_cv.notify_all(); | ||||||
|     if (!syncpt_interrupts[syncpoint_id].empty()) { |     auto& interrupt = syncpt_interrupts.at(syncpoint_id); | ||||||
|         u32 value = syncpoints[syncpoint_id].load(); |     if (!interrupt.empty()) { | ||||||
|         auto it = syncpt_interrupts[syncpoint_id].begin(); |         u32 value = syncpoint.load(); | ||||||
|         while (it != syncpt_interrupts[syncpoint_id].end()) { |         auto it = interrupt.begin(); | ||||||
|  |         while (it != interrupt.end()) { | ||||||
|             if (value >= *it) { |             if (value >= *it) { | ||||||
|                 TriggerCpuInterrupt(syncpoint_id, *it); |                 TriggerCpuInterrupt(syncpoint_id, *it); | ||||||
|                 it = syncpt_interrupts[syncpoint_id].erase(it); |                 it = interrupt.erase(it); | ||||||
|                 continue; |                 continue; | ||||||
|             } |             } | ||||||
|             it++; |             it++; | ||||||
| @@ -119,22 +126,22 @@ void GPU::IncrementSyncPoint(const u32 syncpoint_id) { | |||||||
| } | } | ||||||
|  |  | ||||||
| u32 GPU::GetSyncpointValue(const u32 syncpoint_id) const { | u32 GPU::GetSyncpointValue(const u32 syncpoint_id) const { | ||||||
|     return syncpoints[syncpoint_id].load(); |     return syncpoints.at(syncpoint_id).load(); | ||||||
| } | } | ||||||
|  |  | ||||||
| void GPU::RegisterSyncptInterrupt(const u32 syncpoint_id, const u32 value) { | void GPU::RegisterSyncptInterrupt(const u32 syncpoint_id, const u32 value) { | ||||||
|     auto& interrupt = syncpt_interrupts[syncpoint_id]; |     auto& interrupt = syncpt_interrupts.at(syncpoint_id); | ||||||
|     bool contains = std::any_of(interrupt.begin(), interrupt.end(), |     bool contains = std::any_of(interrupt.begin(), interrupt.end(), | ||||||
|                                 [value](u32 in_value) { return in_value == value; }); |                                 [value](u32 in_value) { return in_value == value; }); | ||||||
|     if (contains) { |     if (contains) { | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|     syncpt_interrupts[syncpoint_id].emplace_back(value); |     interrupt.emplace_back(value); | ||||||
| } | } | ||||||
|  |  | ||||||
| bool GPU::CancelSyncptInterrupt(const u32 syncpoint_id, const u32 value) { | bool GPU::CancelSyncptInterrupt(const u32 syncpoint_id, const u32 value) { | ||||||
|     std::lock_guard lock{sync_mutex}; |     std::lock_guard lock{sync_mutex}; | ||||||
|     auto& interrupt = syncpt_interrupts[syncpoint_id]; |     auto& interrupt = syncpt_interrupts.at(syncpoint_id); | ||||||
|     const auto iter = |     const auto iter = | ||||||
|         std::find_if(interrupt.begin(), interrupt.end(), |         std::find_if(interrupt.begin(), interrupt.end(), | ||||||
|                      [value](u32 interrupt_value) { return value == interrupt_value; }); |                      [value](u32 interrupt_value) { return value == interrupt_value; }); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user