Video capture: validate SPA pod values to prevent OOB reads Add bounds checks when reading SPA pod choice values in OnNodeParam and ParseFormat. Validate that the pod value size matches the expected type using spa_pod_type_size() and that the number of choice items is sufficient before accessing the underlying arrays. Bug: chromium:545349644 Change-Id: I865e4736f52be1a0dfce47827181dc072630bb57 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/495620 Commit-Queue: Jan Grulich <grulja@gmail.com> Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> Reviewed-by: Andreas Pehrson <apehrson@mozilla.com> Reviewed-by: Per Kjellander <perkj@webrtc.org> Cr-Commit-Position: refs/heads/main@{#48344}
diff --git a/modules/video_capture/linux/pipewire_session.cc b/modules/video_capture/linux/pipewire_session.cc index ba841a7..e17bab8 100644 --- a/modules/video_capture/linux/pipewire_session.cc +++ b/modules/video_capture/linux/pipewire_session.cc
@@ -46,6 +46,11 @@ namespace webrtc { namespace videocapturemodule { +// Checks that the pod matches the expected type and is large enough to hold it. +static bool SpaValueIsType(const spa_pod* val, uint32_t type) { + return val->type == type && val->size >= spa_pod_type_size(type); +} + VideoType PipeWireRawFormatToVideoType(uint32_t id) { switch (id) { case SPA_VIDEO_FORMAT_I420: @@ -187,20 +192,21 @@ prop = spa_pod_object_find_prop(obj, prop, SPA_FORMAT_VIDEO_framerate); if (prop) { val = spa_pod_get_values(&prop->value, &n_items, &choice); - if (val->type == SPA_TYPE_Fraction) { + if (SpaValueIsType(val, SPA_TYPE_Fraction)) { spa_fraction* fract; fract = static_cast<spa_fraction*>(SPA_POD_BODY(val)); - if (choice == SPA_CHOICE_None) { + if (choice == SPA_CHOICE_None && n_items >= 1) { cap.maxFPS = 1.0 * fract[0].num / fract[0].denom; - } else if (choice == SPA_CHOICE_Enum) { + } else if (choice == SPA_CHOICE_Enum && n_items >= 2) { for (uint32_t i = 1; i < n_items; i++) { cap.maxFPS = std::max( static_cast<int32_t>(1.0 * fract[i].num / fract[i].denom), cap.maxFPS); } - } else if (choice == SPA_CHOICE_Range && fract[1].num > 0) { + } else if (choice == SPA_CHOICE_Range && n_items >= 2 && + fract[1].num > 0) { cap.maxFPS = 1.0 * fract[1].num / fract[1].denom; } } @@ -211,10 +217,10 @@ return; val = spa_pod_get_values(&prop->value, &n_items, &choice); - if (val->type != SPA_TYPE_Rectangle) + if (!SpaValueIsType(val, SPA_TYPE_Rectangle)) return; - if (choice != SPA_CHOICE_None) + if (choice != SPA_CHOICE_None || n_items < 1) return; if (!ParseFormat(param, &cap)) @@ -269,10 +275,10 @@ return false; val = spa_pod_get_values(&prop->value, &n_items, &choice); - if (val->type != SPA_TYPE_Id) + if (!SpaValueIsType(val, SPA_TYPE_Id)) return false; - if (choice != SPA_CHOICE_None) + if (choice != SPA_CHOICE_None || n_items < 1) return false; id = static_cast<uint32_t*>(SPA_POD_BODY(val));