// tests/cefclient/browser/osr_renderer.cc
void OsrRenderer::OnPaint(CefRefPtr<CefBrowser> browser,
CefRenderHandler::PaintElementType type,
const CefRenderHandler::RectList& dirtyRects,
const void* buffer,
int width,
int height) {
// ......
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, view_width_, view_height_, 0,
GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, buffer); // [3]
// ......
}
#0 0x00000000405c8eb1 in ()
#1 0x00007f01280201a0 in ()
#2 0x0000561f81c745e0 in ()
#3 0x00007ffe85534100 in ()
#4 0x00000000000003e8 in ()
#5 0x00007f00fa8628ed in ()
at /lib/x86_64-linux-gnu/libnvidia-glcore.so.470.223.02
#6 0x00007f00fa86c901 in ()
at /lib/x86_64-linux-gnu/libnvidia-glcore.so.470.223.02
#7 0x00007f00fa9817c0 in ()
at /lib/x86_64-linux-gnu/libnvidia-glcore.so.470.223.02
#8 0x00007f00fa98cc0d in ()
at /lib/x86_64-linux-gnu/libnvidia-glcore.so.470.223.02
#9 0x00007f00fa98e184 in ()
at /lib/x86_64-linux-gnu/libnvidia-glcore.so.470.223.02
#10 0x00007f00fa98e508 in ()
at /lib/x86_64-linux-gnu/libnvidia-glcore.so.470.223.02
#11 0x0000561f80869074 in client::OsrRenderer::OnPaint(scoped_refptr<CefBrowser>, cef_paint_element_type_t, std::__Cr::vector<CefRect, std::__Cr::allocator<CefRect> > const&, void const*, int, int)
(this=0x561f80c8b458, browser=..., type=<optimized out>, dirtyRects=..., buffer=0x7f0127e5a000, width=0x3e8, height=0x3e8)
at ../../cef/tests/cefclient/browser/osr_renderer.cc:337
#12 0x0000561f8088f98b in client::BrowserWindowOsrGtk::OnPaint(scoped_refptr<CefBrowser>, cef_paint_element_type_t, std::__Cr::vector<CefRect, std::__Cr::allocator<CefRect> > const&, void const*, int, int)
(this=0x561f80c8b420, browser=..., type=PET_VIEW, dirtyRects=..., buffer=0x7f0127e5a000, width=0x3e8, height=0x3e8)
at ../../cef/tests/cefclient/browser/browser_window_osr_gtk.cc:1254
#13 0x0000561f8085b4d3 in non-virtual thunk to client::ClientHandlerOsr::OnPaint(scoped_refptr<CefBrowser>, cef_paint_element_type_t, std::__Cr::vector<CefRect, std::__Cr::allocator<CefRect> > const&, void const*, int, int) () at ../../cef/tests/cefclient/browser/client_handler_osr.cc:118
#14 0x0000561f808eea95 in (anonymous namespace)::render_handler_on_paint(_cef_render_handler_t*, _cef_browser_t*, cef_paint_element_type_t, unsigned long, _cef_rect_t const*, void const*, int, int)
(self=<optimized out>, browser=0x561f811a2840, type=PET_VIEW, dirtyRectsCount=<optimized out>, dirtyRects=<optimized out>, buffer=0x7f0127e5a000, width=0x3e8, height=0x3e8)
at ../../cef/libcef_dll/cpptoc/render_handler_cpptoc.cc:307
#15 0x00007f0168b9d5f1 in CefRenderHandlerCToCpp::OnPaint(scoped_refptr<CefBrowser>, cef_paint_element_type_t, std::__Cr::vector<CefRect, std::__Cr::allocator<CefRect> > const&, void const*, int, int)
(this=<optimized out>, browser=..., type=PET_VIEW, dirtyRects=<optimized out>, buffer=0x7f0127e5a000, width=0x3e8, height=0x3e8)
at ../../cef/libcef_dll/ctocpp/render_handler_ctocpp.cc:232
#16 0x00007f0168c74ada in CefRenderWidgetHostViewOSR::OnPaint(gfx::Rect const&, gfx::Size const&, void const*)
(this=0x561f81585150, damage_rect=<optimized out>, pixel_size=..., pixels=0x7f0127e5a000)
at ../../cef/libcef/browser/osr/render_widget_host_view_osr.cc:1577
#17 0x00007f0168c79841 in CefVideoConsumerOSR::OnFrameCaptured(mojo::StructPtr<media::mojom::VideoBufferHandle>, mojo::StructPtr<media::mojom::VideoFrameInfo>, gfx::Rect const&, mojo::PendingRemote<viz::mojom::FrameSinkVideoConsumerFrameCallbacks>)
(this=0x561f815cae70, data=..., info=..., content_rect=<optimized out>, callbacks=...)
at ../../cef/libcef/browser/osr/video_consumer_osr.cc:141
Summary
CefVideoConsumerOSR::OnFrameCaptured
does not checkpixel_format
properly, which leads to out-of-bounds read out of the sandbox.Details
CefVideoConsumerOSR::OnFrameCaptured
handles the frame data received from GPU Process when OSR is enabled.data
is the handle of the shared buffer,info->pixel_format
is the format, such asARGB
, andinfo->coded_size
holds the width and height. It will callmedia::VideoFrame::AllocationSize
to calculate the size of the frame with certainpixel_format
andcoded_size
and checks that it is not bigger than the size of the shared memory [1]. However, it callsview_->OnPaint
without thepixel_format
[2]. Finally, inOsrRenderer::OnPaint
(The default implementation incefclient
), it assumes the format isARGB
[3].A compromised GPU process can send a malicious frame with a different
pixel_format
. For example,UNKNOWN
, which will letAllocationSize
always return zero. Thus, a buffer smaller than theAllocationSize
ofARGB
can pass the check[1] and lead to out-of-bounds read.VERSION: latest (121.0.0-HEAD.2874+ge4acace+chromium-121.0.6167.0)
PoC
Build cefclient
Run cefclient with
--enable-gpu
and--off-screen-rendering-enabled
, then visit an arbitrary web page.Crash Backtrace:
SUGGESTED FIX
Check if
info->pixel_format
isARGB
inCefVideoConsumerOSR::OnFrameCaptured
.