Devicetree
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Ali Rouhi" <rouhi.ali@gmail.com>
Cc: krzk+dt@kernel.org, devicetree@vger.kernel.org, robh@kernel.org,
	conor+dt@kernel.org
Subject: Re: [PATCH net-next 3/3] dpll: add SiTime SiT9531x DPLL clock driver
Date: Wed, 13 May 2026 00:52:51 +0000	[thread overview]
Message-ID: <20260513005252.34EA0C2BCB0@smtp.kernel.org> (raw)
In-Reply-To: <20260511211453.20671-2-arouhi@sitime.com>

Thank you for your contribution! Sashiko AI review found 9 potential issue(s) to consider:
- [Critical] DPLL pin properties (`package_label` and `freq_supported`) are freed immediately after registration, causing a critical use-after-free vulnerability.
- [High] The driver uses a non-existent macro `kzalloc_obj` for memory allocation, causing a build failure.
- [High] The crystal oscillator frequency (`xtal_freq`) is never initialized, permanently breaking core frequency and phase calculations.
- [High] The INTRB threaded IRQ is registered before the kthread worker is initialized and torn down after the worker is destroyed, causing a NULL pointer dereference race.
- [High] The driver fails to clear hardware interrupt notifications, causing an unhandled interrupt storm.
- [High] Phase adjustments are written to the wrong hardware registers because the logical output index is used instead of the physical slot.
- [High] Unsigned 32-bit hardware fractional numerators are read into signed integers, causing a sign-extension bug that corrupts DCO math.
- [Medium] Hardware state cache arrays are updated and read concurrently without locking, leading to data races.
- [Medium] DCO frequency adjustment and SYSREF/SYNCB output modes are fully implemented but entirely unreachable (Dead Code).
--

commit 7809f8a3992ad8b550d7f2507263595d95f3b3d8
Author: Ali Rouhi <rouhi.ali@gmail.com>

dpll: add SiTime SiT9531x DPLL clock driver

Adds a DPLL subsystem driver for the SiTime SiT95316 and SiT95317
clock generators.

The driver exposes all inputs and outputs through the Linux DPLL
subsystem, supporting:
[ ... ]
 - DCO (digitally controlled oscillator) frequency adjustment
[ ... ]
 - SYSREF/SYNCB/Pulser output mode control

This isn't a bug, but the commit message indicates that the driver supports
DCO frequency adjustment and SYSREF/SYNCB output mode control. However,
these features do not appear to be hooked into sit9531x_dpll_device_ops or
otherwise exposed to the DPLL subsystem.

> diff --git a/drivers/dpll/sit9531x/core.c b/drivers/dpll/sit9531x/core.c
> new file mode 100644
> index 0000000000000..4c15a10aaa0ae
> --- /dev/null
> +++ b/drivers/dpll/sit9531x/core.c
[ ... ]
> +static int sit9531x_dco_read_divn(struct sit9531x_dev *sitdev, u8 pll_idx,
> +				  u32 *int_part, s32 *fracn, u32 *fracd)
> +{
[ ... ]
> +	/* Numerator (4 bytes, little-endian) */
> +	*fracn = 0;
> +	for (i = 3; i >= 0; i--) {
> +		rc = sit9531x_read_pll_u8(sitdev, pll_idx,
> +					  SIT9531X_PLL_REG_DIVN_NUM + i, &v);
> +		if (rc)
> +			return rc;
> +		*fracn = (*fracn << 8) | v;
> +	}

Could this left shift into a signed 32-bit integer result in a negative
value?

If the hardware fractional numerator represents a value greater than or
equal to 0.5, the most significant bit will be set. This might sign-extend
when cast later and alter the calculation in sit9531x_dco_calc_inner.

[ ... ]
> +static u64 sit9531x_get_fvco(struct sit9531x_dev *sitdev, u8 pll_idx)
> +{
[ ... ]
> +	doubler = sit9531x_is_xo_doubler_enabled(sitdev);
> +	if (doubler < 0)
> +		return 0;
> +
> +	fref = (u64)sitdev->xtal_freq << doubler;

Where is sitdev->xtal_freq populated?

If it remains zero-initialized from the initial allocation, fref will
evaluate to zero. This would cause fvco to return zero and affect
subsequent frequency calculations and hardware state updates.

[ ... ]
> +int sit9531x_output_phase_adjust_set(struct sit9531x_dev *sitdev,
> +				     u8 out_idx, s32 phase_ps)
> +{
[ ... ]
> +	page = (out_idx < 6) ? SIT9531X_PAGE_OUTSYS0
> +			     : SIT9531X_PAGE_OUTSYS1;
> +	base = SIT9531X_OUT_PRG_DELAY_BASE +
> +	       SIT9531X_OUT_PRG_SLOT_STRIDE * (out_idx % 6);

Should this use the physical slot mapping instead of the logical index?

Using out_idx directly here might cause the driver to write to the phase
delay registers of a different output port. sit9531x_output_freq_set() uses
info->clkout_map to resolve this correctly.

[ ... ]
> +static irqreturn_t sit9531x_irq_thread_fn(int irq, void *data)
> +{
> +	struct sit9531x_dev *sitdev = data;
> +
> +	kthread_mod_delayed_work(sitdev->kworker, &sitdev->work, 0);
> +	return IRQ_HANDLED;
> +}

Does the hardware require interrupt notifications to be explicitly cleared?

The handler returns IRQ_HANDLED after waking the worker, but
sit9531x_clear_notifications() is never called. If this is a level-triggered
interrupt line, leaving the notification active might cause an interrupt
storm.

[ ... ]
> +int sit9531x_dev_probe(struct sit9531x_dev *sitdev)
> +{
[ ... ]
> +	if (sitdev->irq > 0) {
> +		rc = devm_request_threaded_irq(sitdev->dev, sitdev->irq,
> +					       NULL, sit9531x_irq_thread_fn,
> +					       IRQF_ONESHOT,
> +					       dev_name(sitdev->dev), sitdev);
> +		if (rc)
> +			return dev_err_probe(sitdev->dev, rc,
> +					     "Failed to request IRQ %d\n",
> +					     sitdev->irq);
> +		dev_info(sitdev->dev,
> +			 "INTRB IRQ %d wired (threaded handler kicks periodic poll)\n",
> +			 sitdev->irq);
> +	}
> +
> +	/* Register DPLL channels */
> +	rc = sit9531x_devm_dpll_init(sitdev);

What happens if the interrupt fires right after it is registered?

Since devm_request_threaded_irq is called before the kworker is initialized
inside sit9531x_devm_dpll_init, an early interrupt could cause the thread
handler to dereference a null pointer when interacting with the worker.

> diff --git a/drivers/dpll/sit9531x/dpll.c b/drivers/dpll/sit9531x/dpll.c
> new file mode 100644
> index 0000000000000..c766c7c2dd366
> --- /dev/null
> +++ b/drivers/dpll/sit9531x/dpll.c
[ ... ]
> +static int
> +sit9531x_dpll_lock_status_get(const struct dpll_device *dpll, void *dpll_priv,
> +			      enum dpll_lock_status *status,
> +			      enum dpll_lock_status_error *status_error,
> +			      struct netlink_ext_ack *extack)
> +{
> +	struct sit9531x_dpll *sitdpll = dpll_priv;
> +	const struct sit9531x_chan *chan;
> +
> +	if (status_error)
> +		*status_error = DPLL_LOCK_STATUS_ERROR_NONE;
> +
> +	chan = sit9531x_chan_state_get(sitdpll->dev, sitdpll->id);
> +
> +	if (chan->locked) {

Is it safe to read the channel state here without holding a lock?

The periodic worker locklessly updates the hardware state cache arrays.
Concurrent reads in the netlink callbacks could potentially see torn data
or mismatched state vectors.

[ ... ]
> +static struct sit9531x_dpll_pin *
> +sit9531x_dpll_pin_alloc(struct sit9531x_dpll *sitdpll,
> +			enum dpll_pin_direction dir, u8 id)
> +{
> +	struct sit9531x_dpll_pin *pin;
> +
> +	pin = kzalloc_obj(*pin, GFP_KERNEL);
> +	if (!pin)
> +		return ERR_PTR(-ENOMEM);

Does the macro kzalloc_obj exist in the tree?

It looks like this might cause a build failure since kzalloc is the standard
allocation macro. This same pattern seems to be used in sit9531x_dpll_alloc
and sit9531x_pin_props_get.

[ ... ]
> +static int sit9531x_dpll_pin_register(struct sit9531x_dpll_pin *pin,
> +				      u32 index)
> +{
[ ... ]
> +	/* Register the pin */
> +	rc = dpll_pin_register(sitdpll->dpll_dev, pin->dpll_pin, ops, pin);
> +	if (rc)
> +		goto err_register;
> +
> +	/* Free pin properties */
> +	sit9531x_pin_props_put(props);
> +
> +	return 0;

Are the pointers for package_label and freq_supported safely copied?

Looking at the DPLL core, dpll_pin_get() appears to perform a shallow copy.
Freeing the properties right after registration could result in a use after
free when the subsystem later attempts to read them.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260511211453.20671-1-arouhi@sitime.com?part=3

  reply	other threads:[~2026-05-13  0:52 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-05-11 21:11 [PATCH net-next 0/3] dpll: add SiTime SiT9531x DPLL clock driver Ali Rouhi
2026-05-11 21:11 ` [PATCH net-next 1/3] dt-bindings: vendor-prefixes: add SiTime Corporation Ali Rouhi
2026-05-12 17:46   ` Conor Dooley
2026-05-13  0:09   ` sashiko-bot
2026-05-11 21:14 ` [PATCH net-next 2/3] dt-bindings: dpll: add SiTime SiT9531x clock generator Ali Rouhi
2026-05-11 21:14   ` [PATCH net-next 3/3] dpll: add SiTime SiT9531x DPLL clock driver Ali Rouhi
2026-05-13  0:52     ` sashiko-bot [this message]
2026-05-12 17:52   ` [PATCH net-next 2/3] dt-bindings: dpll: add SiTime SiT9531x clock generator Conor Dooley
     [not found]     ` <CALFSGurCGzyk3mOPnyP_p2o+s9kCCQZc4MjBsDpPxqSPV1ZseA@mail.gmail.com>
2026-05-12 20:23       ` Ali Rouhi
2026-05-13  0:18   ` sashiko-bot

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=20260513005252.34EA0C2BCB0@smtp.kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=conor+dt@kernel.org \
    --cc=devicetree@vger.kernel.org \
    --cc=krzk+dt@kernel.org \
    --cc=robh@kernel.org \
    --cc=rouhi.ali@gmail.com \
    --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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox