libcamera: pipeline: ipu3: Free internal buffers after stopping streaming

The internal buffers between the CIO2 and ImgU are freed by the
CIO2Device::stop() method, which is called first when stopping
streaming. The ImgUDevice::stop() method is then called, and attempts to
report completion for all queued buffers, which we have just freed. The
use-after-free corrupts memory, leading to crashes.

Fix this by moving the vector of internal buffers to the IPU3CameraData
where it belongs, and free the buffers after stopping both devices.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>
This commit is contained in:
Laurent Pinchart 2019-07-16 08:36:31 +03:00
parent d55c8018cd
commit 124336329c

View file

@ -122,7 +122,7 @@ public:
BufferPool *exportBuffers(); BufferPool *exportBuffers();
void freeBuffers(); void freeBuffers();
int start(); int start(std::vector<std::unique_ptr<Buffer>> *buffer);
int stop(); int stop();
static int mediaBusToFormat(unsigned int code); static int mediaBusToFormat(unsigned int code);
@ -132,7 +132,6 @@ public:
CameraSensor *sensor_; CameraSensor *sensor_;
BufferPool pool_; BufferPool pool_;
std::vector<std::unique_ptr<Buffer>> buffers_;
}; };
class IPU3Stream : public Stream class IPU3Stream : public Stream
@ -165,6 +164,8 @@ public:
IPU3Stream outStream_; IPU3Stream outStream_;
IPU3Stream vfStream_; IPU3Stream vfStream_;
std::vector<std::unique_ptr<Buffer>> rawBuffers_;
}; };
class IPU3CameraConfiguration : public CameraConfiguration class IPU3CameraConfiguration : public CameraConfiguration
@ -688,7 +689,7 @@ int PipelineHandlerIPU3::start(Camera *camera)
* Start the ImgU video devices, buffers will be queued to the * Start the ImgU video devices, buffers will be queued to the
* ImgU output and viewfinder when requests will be queued. * ImgU output and viewfinder when requests will be queued.
*/ */
ret = cio2->start(); ret = cio2->start(&data->rawBuffers_);
if (ret) if (ret)
goto error; goto error;
@ -704,6 +705,7 @@ int PipelineHandlerIPU3::start(Camera *camera)
error: error:
LOG(IPU3, Error) << "Failed to start camera " << camera->name(); LOG(IPU3, Error) << "Failed to start camera " << camera->name();
data->rawBuffers_.clear();
return ret; return ret;
} }
@ -717,6 +719,8 @@ void PipelineHandlerIPU3::stop(Camera *camera)
if (ret) if (ret)
LOG(IPU3, Warning) << "Failed to stop camera " LOG(IPU3, Warning) << "Failed to stop camera "
<< camera->name(); << camera->name();
data->rawBuffers_.clear();
} }
int PipelineHandlerIPU3::queueRequest(Camera *camera, Request *request) int PipelineHandlerIPU3::queueRequest(Camera *camera, Request *request)
@ -1454,26 +1458,18 @@ void CIO2Device::freeBuffers()
LOG(IPU3, Error) << "Failed to release CIO2 buffers"; LOG(IPU3, Error) << "Failed to release CIO2 buffers";
} }
int CIO2Device::start() int CIO2Device::start(std::vector<std::unique_ptr<Buffer>> *buffers)
{ {
int ret; *buffers = output_->queueAllBuffers();
if (buffers->empty())
buffers_ = output_->queueAllBuffers();
if (buffers_.empty())
return -EINVAL; return -EINVAL;
ret = output_->streamOn(); return output_->streamOn();
if (ret)
return ret;
return 0;
} }
int CIO2Device::stop() int CIO2Device::stop()
{ {
int ret = output_->streamOff(); return output_->streamOff();
buffers_.clear();
return ret;
} }
int CIO2Device::mediaBusToFormat(unsigned int code) int CIO2Device::mediaBusToFormat(unsigned int code)