All of lore.kernel.org
 help / color / mirror / Atom feed
From: Rasmus Villemoes <ravi@prevas.dk>
To: Marek Vasut <marek.vasut+renesas@mailbox.org>
Cc: u-boot@lists.denx.de,  Aaron Williams <awilliams@marvell.com>,
	 Anatolij Gustschin <agust@denx.de>,
	 Angelo Dureghello <angelo@kernel-space.org>,
	Christian Marangi <ansuelsmth@gmail.com>,
	 Devarsh Thakkar <devarsht@ti.com>,
	 Heinrich Schuchardt <xypron.glpk@gmx.de>,
	 Jaehoon Chung <jh80.chung@samsung.com>,
	 Michael Polyntsov <michael.polyntsov@iopsys.eu>,
	 Michael Trimarchi <michael@amarulasolutions.com>,
	 Nikhil M Jain <n-jain1@ti.com>,  Peng Fan <peng.fan@nxp.com>,
	 Peter Robinson <pbrobinson@gmail.com>,
	 Ronald Wahl <ronald.wahl@legrand.com>,
	 Simon Glass <sjg@chromium.org>,  Stefan Roese <sr@denx.de>,
	 Tim Harvey <tharvey@gateworks.com>,
	 Tom Rini <trini@konsulko.com>
Subject: Re: [PATCH 1/8] cyclic: Prevent corruption of cyclic list on reassignment
Date: Mon, 20 Jan 2025 10:17:41 +0100	[thread overview]
Message-ID: <87cyghx2ru.fsf@prevas.dk> (raw)
In-Reply-To: <20250118040130.74921-1-marek.vasut+renesas@mailbox.org> (Marek Vasut's message of "Sat, 18 Jan 2025 05:00:55 +0100")

On Sat, Jan 18 2025, Marek Vasut <marek.vasut+renesas@mailbox.org> wrote:

> Make cyclic_register() return error code, 0 in case of success,
> -EALREADY in case the called attempts to re-register already
> registered struct cyclic_info. The re-registration would lead
> to corruption of gd->cyclic_list because the re-registration
> would memset() one of its nodes, prevent that. Unregister only
> initialized struct cyclic_info.

I had considered something like this, but I don't like it, because it
relies on the cyclic structure (or more likely whatever structure it is
embedded in) being initially zero-initialized. And if the caller doesn't
know whether the cyclic_info is already registered or not, he can't do a
memset() of it.

So my preference would be that we instead simply iterate the current
list to see if the struct cyclic_info is already registered that
way. Also, I think I'd prefer if double cyclic_register() is allowed and
always succeeds; this could be used to change the period of an already
registered instance, for example. Also, that avoids making the
interfaces fallible.

And cyclic_unregister() could similarly just check
whether the passed pointer is already on the list, and be a no-op in
case it's not. Those extra list traversals are not expensive (we're
traversing them thousands of times per second anyway in cyclic_run), and
I doubt one would ever has more than about 10 items on the list.

IOW, I'd suggest adding an internal

bool cyclic_is_registered(struct cyclic_info *info)
{
  struct cyclic_info *c;
  hlist_for_each(...) if (c == info) return true;
  return false;
}

add

  if (!cyclic_is_registered(c))
    return;

to cyclic_unregister(), and have cyclic_register() unconditionally start
by a

  cyclic_unregister(c);

and then proceed to initialize it as it does currently. No other
changes, apart from documentation, would be needed.
    


>  common/cyclic.c  | 14 +++++++++++---
>  include/cyclic.h |  9 ++++++---
>  2 files changed, 17 insertions(+), 6 deletions(-)
>
> diff --git a/common/cyclic.c b/common/cyclic.c
> index 196797fd61e..53156a704cc 100644
> --- a/common/cyclic.c
> +++ b/common/cyclic.c
> @@ -27,9 +27,13 @@ struct hlist_head *cyclic_get_list(void)
>  	return (struct hlist_head *)&gd->cyclic_list;
>  }
>  
> -void cyclic_register(struct cyclic_info *cyclic, cyclic_func_t func,
> -		     uint64_t delay_us, const char *name)
> +int cyclic_register(struct cyclic_info *cyclic, cyclic_func_t func,
> +		    uint64_t delay_us, const char *name)
>  {
> +	/* Reassignment of function would corrupt cyclic list, exit */
> +	if (cyclic->func)
> +		return -EALREADY;
> +
>  	memset(cyclic, 0, sizeof(*cyclic));
>  
>  	/* Store values in struct */
> @@ -38,11 +42,15 @@ void cyclic_register(struct cyclic_info *cyclic, cyclic_func_t func,
>  	cyclic->delay_us = delay_us;
>  	cyclic->start_time_us = timer_get_us();
>  	hlist_add_head(&cyclic->list, cyclic_get_list());
> +
> +	return 0;
>  }
>  
>  void cyclic_unregister(struct cyclic_info *cyclic)
>  {
> -	hlist_del(&cyclic->list);
> +	/* Unregister only initialized struct cyclic_info */
> +	if (cyclic->func)
> +		hlist_del(&cyclic->list);
>  }

So this already shows how error prone this approach is. You are not
clearing cyclic->func, so if the caller subsequently tries to register
that struct again, he would get -EALREADY, while a subsequent unregister
could would lead to exactly the list corruption you want to avoid.

And unless the caller immediately himself clears ->func, other code in
the client cannot rely on ->func being NULL or not as a proxy for
whether the struct is already registered (and the caller shouldn't do
either of those things, as the struct cyclic_info should be considered
opaque).

Rasmus


  parent reply	other threads:[~2025-01-20  9:17 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-01-18  4:00 [PATCH 1/8] cyclic: Prevent corruption of cyclic list on reassignment Marek Vasut
2025-01-18  4:00 ` [PATCH 2/8] cyclic: Handle return code from cyclic_register() in demo and docs Marek Vasut
2025-01-18  4:00 ` [PATCH 3/8] cyclic: Test return code from cyclic_register() in test Marek Vasut
2025-01-18  4:00 ` [PATCH 4/8] mips: octeon: nic23: Handle return value from cyclic_register() Marek Vasut
2025-01-18  4:00 ` [PATCH 5/8] led: " Marek Vasut
2025-01-18  4:01 ` [PATCH 6/8] mmc: " Marek Vasut
2025-01-18  4:01 ` [PATCH 7/8] video: " Marek Vasut
2025-01-18  4:01 ` [PATCH 8/8] wdt: " Marek Vasut
2025-01-20  9:17 ` Rasmus Villemoes [this message]
2025-01-22  9:25   ` [PATCH 1/8] cyclic: Prevent corruption of cyclic list on reassignment Stefan Roese
2025-01-25 13:23     ` Marek Vasut
2025-01-25 13:22   ` Marek Vasut
2025-01-26 21:49     ` Rasmus Villemoes
2025-01-27 11:44       ` Marek Vasut

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=87cyghx2ru.fsf@prevas.dk \
    --to=ravi@prevas.dk \
    --cc=agust@denx.de \
    --cc=angelo@kernel-space.org \
    --cc=ansuelsmth@gmail.com \
    --cc=awilliams@marvell.com \
    --cc=devarsht@ti.com \
    --cc=jh80.chung@samsung.com \
    --cc=marek.vasut+renesas@mailbox.org \
    --cc=michael.polyntsov@iopsys.eu \
    --cc=michael@amarulasolutions.com \
    --cc=n-jain1@ti.com \
    --cc=pbrobinson@gmail.com \
    --cc=peng.fan@nxp.com \
    --cc=ronald.wahl@legrand.com \
    --cc=sjg@chromium.org \
    --cc=sr@denx.de \
    --cc=tharvey@gateworks.com \
    --cc=trini@konsulko.com \
    --cc=u-boot@lists.denx.de \
    --cc=xypron.glpk@gmx.de \
    /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.