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
next prev 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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox