Merge pull request 'picture: bounds-check codec_store_buffer slice writes against source_size (#13)' (#14) from claude-noether/libva-v4l2-request-fourier:noether/codec-store-buffer-bounds-check-13 into master
Reviewed-on: #14
This commit was merged in pull request #14.
This commit is contained in:
+43
-7
@@ -62,16 +62,37 @@ static VAStatus codec_store_buffer(struct request_data *driver_data,
|
|||||||
struct object_buffer *buffer_object)
|
struct object_buffer *buffer_object)
|
||||||
{
|
{
|
||||||
switch (buffer_object->type) {
|
switch (buffer_object->type) {
|
||||||
case VASliceDataBufferType:
|
case VASliceDataBufferType: {
|
||||||
/*
|
/*
|
||||||
* Since there is no guarantee that the allocation
|
* Since there is no guarantee that the allocation
|
||||||
* order is the same as the submission order (via
|
* order is the same as the submission order (via
|
||||||
* RenderPicture), we can't use a V4L2 buffer directly
|
* RenderPicture), we can't use a V4L2 buffer directly
|
||||||
* and have to copy from a regular buffer.
|
* and have to copy from a regular buffer.
|
||||||
|
*
|
||||||
|
* Bounds check (issue #13): surface_object->source_data points
|
||||||
|
* at an OUTPUT-pool mmap of fixed size source_size, negotiated
|
||||||
|
* at S_FMT time. A stream-level resolution upshift can produce
|
||||||
|
* a slice larger than this allocation; without the guard, the
|
||||||
|
* memcpy walks past the mmap and SIGSEGVs (mpv --hwdec=vaapi-
|
||||||
|
* copy) or corrupts adjacent heap (Firefox RDD). Each append
|
||||||
|
* site below checks the running total against source_size and
|
||||||
|
* fails the RenderPicture call instead of corrupting memory;
|
||||||
|
* libavcodec re-creates the surface at the new resolution on
|
||||||
|
* the next BeginPicture.
|
||||||
*/
|
*/
|
||||||
|
size_t cap = surface_object->source_size;
|
||||||
|
size_t need;
|
||||||
|
|
||||||
if (context->h264_start_code) {
|
if (context->h264_start_code) {
|
||||||
static const char start_code[3] = { 0x00, 0x00, 0x01 };
|
static const char start_code[3] = { 0x00, 0x00, 0x01 };
|
||||||
|
|
||||||
|
need = (size_t)surface_object->slices_size +
|
||||||
|
sizeof(start_code);
|
||||||
|
if (need > cap) {
|
||||||
|
request_log("codec_store_buffer: H.264 start code would overflow OUTPUT buffer (%zu > %zu) — resolution upshift mid-stream?\n",
|
||||||
|
need, cap);
|
||||||
|
return VA_STATUS_ERROR_ALLOCATION_FAILED;
|
||||||
|
}
|
||||||
memcpy(surface_object->source_data +
|
memcpy(surface_object->source_data +
|
||||||
surface_object->slices_size,
|
surface_object->slices_size,
|
||||||
start_code, sizeof(start_code));
|
start_code, sizeof(start_code));
|
||||||
@@ -105,19 +126,34 @@ static VAStatus codec_store_buffer(struct request_data *driver_data,
|
|||||||
unsigned int header_size =
|
unsigned int header_size =
|
||||||
surface_object->params.vp8.picture.pic_fields.bits.key_frame == 0 ?
|
surface_object->params.vp8.picture.pic_fields.bits.key_frame == 0 ?
|
||||||
10 : 3;
|
10 : 3;
|
||||||
|
need = (size_t)surface_object->slices_size + header_size;
|
||||||
|
if (need > cap) {
|
||||||
|
request_log("codec_store_buffer: VP8 header pad would overflow OUTPUT buffer (%zu > %zu)\n",
|
||||||
|
need, cap);
|
||||||
|
return VA_STATUS_ERROR_ALLOCATION_FAILED;
|
||||||
|
}
|
||||||
memset(surface_object->source_data +
|
memset(surface_object->source_data +
|
||||||
surface_object->slices_size,
|
surface_object->slices_size,
|
||||||
0, header_size);
|
0, header_size);
|
||||||
surface_object->slices_size += header_size;
|
surface_object->slices_size += header_size;
|
||||||
}
|
}
|
||||||
memcpy(surface_object->source_data +
|
{
|
||||||
surface_object->slices_size,
|
size_t payload = (size_t)buffer_object->size *
|
||||||
buffer_object->data,
|
buffer_object->count;
|
||||||
buffer_object->size * buffer_object->count);
|
need = (size_t)surface_object->slices_size + payload;
|
||||||
surface_object->slices_size +=
|
if (need > cap) {
|
||||||
buffer_object->size * buffer_object->count;
|
request_log("codec_store_buffer: slice payload would overflow OUTPUT buffer (%zu > %zu) — resolution upshift mid-stream?\n",
|
||||||
|
need, cap);
|
||||||
|
return VA_STATUS_ERROR_ALLOCATION_FAILED;
|
||||||
|
}
|
||||||
|
memcpy(surface_object->source_data +
|
||||||
|
surface_object->slices_size,
|
||||||
|
buffer_object->data, payload);
|
||||||
|
surface_object->slices_size += payload;
|
||||||
|
}
|
||||||
surface_object->slices_count++;
|
surface_object->slices_count++;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case VAPictureParameterBufferType:
|
case VAPictureParameterBufferType:
|
||||||
switch (profile) {
|
switch (profile) {
|
||||||
|
|||||||
Reference in New Issue
Block a user