From: sashiko-bot@kernel.org
To: "Jacopo Mondi" <jacopo.mondi@ideasonboard.com>
Cc: devicetree@vger.kernel.org, robh@kernel.org, conor+dt@kernel.org,
media-ci@linuxtv.org
Subject: Re: [PATCH v2 2/2] media: i2c: mira016: Add driver for Mira016
Date: Fri, 04 Sep 2026 11:02:27 +0000 [thread overview]
Message-ID: <20260904110228.5BF0C1F00A3D@smtp.kernel.org> (raw)
In-Reply-To: <20260904-mira016-v2-2-1dcf7b3a807e@ideasonboard.com>
Thank you for your contribution! Sashiko AI review found 6 potential issue(s) to consider:
- [Critical] The set_fmt pad operation corrupts the active subdevice state if called while streaming, leading to an out-of-bounds array access.
- [High] V4L2 control handler is freed before unregistering the subdevice, allowing a use-after-free race condition.
- [High] mira016_init_state() calls set_pad_format() with V4L2_SUBDEV_FORMAT_TRY, skipping the active state control range and internal timing initialization.
- [High] Missing stabilization delay after de-asserting hardware reset and enabling clocks before accessing I2C registers.
- [High] I2C errors are silently swallowed by read_poll_timeout macro in mira016_configure_timings.
- [Medium] Missing pm_runtime_mark_last_busy() causes immediate suspend when dropping the runtime PM reference.
--
commit e3f67c157423cc82225f8c12e6de36ab28b0fded
Author: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
media: i2c: mira016: Add driver for Mira016
Add driver for the ams OSRAM Mira016 sensor.
> diff --git a/drivers/media/i2c/mira016.c b/drivers/media/i2c/mira016.c
> new file mode 100644
> index 0000000000000..8b8fcbd50fe23
> --- /dev/null
> +++ b/drivers/media/i2c/mira016.c
> @@ -0,0 +1,2294 @@
[ ... ]
> +static int mira016_configure_timings(struct mira016 *mira016)
> +{
[ ... ]
> + cci_write(mira016->regmap, MIRA016_PLL_PD_REG, 0, &ret);
> + if (ret)
> + return ret;
> +
> + ret = read_poll_timeout(cci_read, ret,
> + ((ret < 0 || (val & MIRA016_PLL_LOCKED))),
> + 1000, 1000, false, mira016->regmap,
> + MIRA016_PLL_LOCK_REG, &val, NULL);
> + if (ret < 0)
> + return ret;
[Severity: High]
Does this read_poll_timeout loop unintentionally swallow I2C errors?
If cci_read() fails (for example, returning -EIO), the error is assigned
to ret, making the condition (ret < 0 || ...) evaluate to true. This
causes the loop to break successfully, and the macro evaluates to 0.
Because the return value of read_poll_timeout is stored in ret, it overwrites
the original I2C error with 0, completely defeating the check
if (ret < 0) below. This would cause the driver to silently ignore failures
during PLL configuration.
[ ... ]
> +static int mira016_write_analogue_gain(struct mira016 *mira016,
> + struct v4l2_subdev_state *state,
> + u32 gain)
> +{
> + const struct mira016_gain_lut *lut;
> + struct v4l2_mbus_framefmt *format;
> + int ret = 0;
> +
> + /*
> + * Use 'gain - 1' as the gain control values are indexed from 1
> + * while the gain luts are 0-indexed.
> + */
> + format = v4l2_subdev_state_get_format(state, 0);
> + switch (format->code) {
> + case MEDIA_BUS_FMT_Y8_1X8:
> + lut = &mira016_gain_lut_8bit[gain - 1];
> + break;
> + case MEDIA_BUS_FMT_Y10_1X10:
> + lut = &mira016_gain_lut_10bit[gain - 1];
[Severity: Critical]
Can this code trigger an out-of-bounds array read if userspace changes the
image format while the device is streaming?
Looking at mira016_set_pad_format(), the requested format is written to the
active subdevice state BEFORE the driver checks if the subdevice is currently
streaming:
mira016_update_pad_format(mira016, &fmt->format, fmt->format.code);
*v4l2_subdev_state_get_format(state, 0) = fmt->format;
...
if (v4l2_subdev_is_streaming(sd))
return -EBUSY;
If the subdevice is streaming, it returns -EBUSY and skips updating the
analog gain control limits. The state has already been corrupted, though.
If userspace changes an 8-bit format to a 10-bit format while streaming,
the active state changes to 10-bit, but the control handler range remains
bound to the wider limits of the 8-bit format (max 83).
A subsequent call to VIDIOC_S_CTRL setting the gain to 83 would pass the
V4L2 core range check. Here in mira016_write_analogue_gain(), it would index
into the 49-element mira016_gain_lut_10bit array using 82, leading to an
out-of-bounds kernel memory read and an invalid hardware state.
[ ... ]
> +static int mira016_set_pad_format(struct v4l2_subdev *sd,
> + struct v4l2_subdev_state *state,
> + struct v4l2_subdev_format *fmt)
> +{
[ ... ]
> + crop = v4l2_subdev_state_get_crop(state, 0);
> + crop->width = fmt->format.width;
> + crop->height = fmt->format.height;
> + crop->left = MIRA016_PIXEL_ARRAY_LEFT;
> + crop->top = MIRA016_PIXEL_ARRAY_TOP;
> +
> + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
> + return 0;
[Severity: High]
Does this early return prevent the active state from being fully initialized?
During probe, v4l2_subdev_init_finalize() calls mira016_init_state() to
populate the active state. However, mira016_init_state() constructs a
dummy format using V4L2_SUBDEV_FORMAT_TRY:
struct v4l2_subdev_format fmt = {
.which = V4L2_SUBDEV_FORMAT_TRY,
...
mira016_set_pad_format(sd, state, &fmt);
Because mira016_set_pad_format() immediately returns when it sees
V4L2_SUBDEV_FORMAT_TRY, it skips updating the analog gain control limit
and fails to set mira016->timings.row_length for the active state.
This leaves the control range incorrectly clamped to default probe limits
and breaks pixel rate calculations until userspace explicitly issues a
VIDIOC_SUBDEV_S_FMT to override it.
[ ... ]
> +static int mira016_power_on(struct device *dev)
> +{
[ ... ]
> + ret = clk_prepare_enable(mira016->xclk);
> + if (ret) {
> + dev_err(&client->dev, "%s: failed to enable clock\n", __func__);
> + goto reg_off;
> + }
> +
> + gpiod_set_value_cansleep(mira016->reset_gpio, 0);
> +
> + return 0;
> +}
[Severity: High]
Should there be a delay here to allow the hardware to stabilize after
de-asserting the reset line?
Looking at mira016_probe(), the driver immediately issues I2C reads to the
sensor using mira016_identify_module() right after calling mira016_power_on():
ret = mira016_power_on(dev);
if (ret)
return ret;
...
ret = mira016_identify_module(mira016);
Without a stabilization delay (e.g., usleep_range()) after de-asserting
reset and before sending I2C commands, this may cause sporadic or consistent
probe failures due to I2C timeouts or NACKs.
[ ... ]
> +static int mira016_disable_streams(struct v4l2_subdev *sd,
> + struct v4l2_subdev_state *state, u32 pad,
> + u64 streams_mask)
> +{
> + struct mira016 *mira016 = to_mira016(sd);
> + struct i2c_client *client = v4l2_get_subdevdata(&mira016->sd);
> +
> + mira016_stop_streaming(mira016);
> +
> + __v4l2_ctrl_grab(mira016->hflip, false);
> + __v4l2_ctrl_grab(mira016->vflip, false);
> +
> + pm_runtime_put_autosuspend(&client->dev);
[Severity: Medium]
Will this bypass the configured autosuspend delay of 1000ms?
The driver drops its PM reference here without first calling
pm_runtime_mark_last_busy(&client->dev).
If the streaming duration exceeds the autosuspend delay configured at probe
time, the runtime PM core will calculate the delay expiration against an old
last_busy timestamp. This will evaluate as already expired, causing the
device to immediately suspend rather than honoring the timeout.
[ ... ]
> +static void mira016_remove(struct i2c_client *client)
> +{
> + struct v4l2_subdev *sd = i2c_get_clientdata(client);
> + struct mira016 *mira016 = to_mira016(sd);
> +
> + v4l2_ctrl_handler_free(mira016->sd.ctrl_handler);
> +
> + v4l2_async_unregister_subdev(sd);
[Severity: High]
Does this sequence open a use-after-free race condition?
The control handler and its active state mutex are destroyed by
v4l2_ctrl_handler_free(), but this happens before the subdevice is
unregistered via v4l2_async_unregister_subdev().
Until the subdevice is unregistered, it remains fully visible to userspace.
If an ioctl (like VIDIOC_S_CTRL) is executed concurrently by userspace
while remove() is running, the V4L2 core will access the already-freed
control handler structures and attempt to acquire a destroyed mutex.
Unregistering the subdevice first would prevent userspace from accessing it
while it's being dismantled.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260904-mira016-v2-0-1dcf7b3a807e@ideasonboard.com?part=2
next prev parent reply other threads:[~2026-09-04 11:02 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-04 10:43 [PATCH v2 0/2] media: i2c: Add driver for Mira016 Jacopo Mondi
2026-09-04 10:43 ` [PATCH v2 1/2] dt-bindings: media: i2c: Add Mira016 image sensor Jacopo Mondi
2026-09-04 15:13 ` Conor Dooley
2026-09-04 10:43 ` [PATCH v2 2/2] media: i2c: mira016: Add driver for Mira016 Jacopo Mondi
2026-09-04 11:02 ` sashiko-bot [this message]
2026-09-06 20:28 ` Sakari Ailus
2026-09-07 7:45 ` Jacopo Mondi
2026-09-07 8:50 ` Sakari Ailus
2026-09-07 9:16 ` Jacopo Mondi
2026-09-08 8:09 ` Sakari Ailus
2026-09-08 7:17 ` Jacopo Mondi
2026-09-08 8:12 ` Sakari Ailus
2026-09-08 9:21 ` Jacopo Mondi
2026-09-08 10:10 ` Sakari Ailus
2026-09-08 10:34 ` Jacopo Mondi
2026-09-12 11:47 ` Sakari Ailus
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260904110228.5BF0C1F00A3D@smtp.kernel.org \
--to=sashiko-bot@kernel.org \
--cc=conor+dt@kernel.org \
--cc=devicetree@vger.kernel.org \
--cc=jacopo.mondi@ideasonboard.com \
--cc=media-ci@linuxtv.org \
--cc=robh@kernel.org \
--cc=sashiko-reviews@lists.linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.