All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/2] efi: remove use of list iterator variable after loop
@ 2022-03-31 22:10 Jakob Koschel
  2022-03-31 22:10 ` [PATCH 2/2] efi: replace usage of found with dedicated list iterator variable Jakob Koschel
  2022-04-13 17:05 ` [PATCH 1/2] efi: remove use of list iterator variable after loop Ard Biesheuvel
  0 siblings, 2 replies; 7+ messages in thread
From: Jakob Koschel @ 2022-03-31 22:10 UTC (permalink / raw)
  To: Ard Biesheuvel
  Cc: linux-efi, linux-kernel, Mike Rapoport, Brian Johannesmeyer,
	Cristiano Giuffrida, Bos, H.J.,
	Jakob Koschel

In preparation to limiting the scope of a list iterator to the list
traversal loop, use a dedicated pointer to iterate through the list [1].

In the current state the list_for_each_entry() is guaranteed to
hit a break or goto in order to work properly. If the list iterator
executes completely or the list is empty the iterator variable contains
a type confused bogus value infered from the head of the list.

With this patch the variable used past the list iterator is only set
if the list exists early and is NULL otherwise. It should therefore
be safe to just set *prev = NULL (as it was before).

Link: https://lore.kernel.org/all/CAHk-=wgRr_D8CB-D9Kg-c=EHreAsk5SqXPwr9Y7k9sA6cWXJ6w@mail.gmail.com/
Signed-off-by: Jakob Koschel <jakobkoschel@gmail.com>
---
 drivers/firmware/efi/vars.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/drivers/firmware/efi/vars.c b/drivers/firmware/efi/vars.c
index cae590bd08f2..3994aad38661 100644
--- a/drivers/firmware/efi/vars.c
+++ b/drivers/firmware/efi/vars.c
@@ -1081,14 +1081,16 @@ int __efivar_entry_iter(int (*func)(struct efivar_entry *, void *),
 			struct list_head *head, void *data,
 			struct efivar_entry **prev)
 {
-	struct efivar_entry *entry, *n;
+	struct efivar_entry *entry = NULL, *iter, *n;
 	int err = 0;
 
 	if (!prev || !*prev) {
-		list_for_each_entry_safe(entry, n, head, list) {
-			err = func(entry, data);
-			if (err)
+		list_for_each_entry_safe(iter, n, head, list) {
+			err = func(iter, data);
+			if (err) {
+				entry = iter;
 				break;
+			}
 		}
 
 		if (prev)

base-commit: d888c83fcec75194a8a48ccd283953bdba7b2550
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 2/2] efi: replace usage of found with dedicated list iterator variable
  2022-03-31 22:10 [PATCH 1/2] efi: remove use of list iterator variable after loop Jakob Koschel
@ 2022-03-31 22:10 ` Jakob Koschel
  2022-04-13 17:09   ` Ard Biesheuvel
  2022-04-13 17:05 ` [PATCH 1/2] efi: remove use of list iterator variable after loop Ard Biesheuvel
  1 sibling, 1 reply; 7+ messages in thread
From: Jakob Koschel @ 2022-03-31 22:10 UTC (permalink / raw)
  To: Ard Biesheuvel
  Cc: linux-efi, linux-kernel, Mike Rapoport, Brian Johannesmeyer,
	Cristiano Giuffrida, Bos, H.J.,
	Jakob Koschel

To move the list iterator variable into the list_for_each_entry_*()
macro in the future it should be avoided to use the list iterator
variable after the loop body.

To *never* use the list iterator variable after the loop it was
concluded to use a separate iterator variable instead of a
found boolean [1].

This removes the need to use a found variable and simply checking if
the variable was set, can determine if the break/goto was hit.

Link: https://lore.kernel.org/all/CAHk-=wgRr_D8CB-D9Kg-c=EHreAsk5SqXPwr9Y7k9sA6cWXJ6w@mail.gmail.com/
Signed-off-by: Jakob Koschel <jakobkoschel@gmail.com>
---
 drivers/firmware/efi/vars.c | 15 +++++++--------
 1 file changed, 7 insertions(+), 8 deletions(-)

diff --git a/drivers/firmware/efi/vars.c b/drivers/firmware/efi/vars.c
index 3994aad38661..e4e1cc593441 100644
--- a/drivers/firmware/efi/vars.c
+++ b/drivers/firmware/efi/vars.c
@@ -809,22 +809,21 @@ EXPORT_SYMBOL_GPL(efivar_entry_set_safe);
 struct efivar_entry *efivar_entry_find(efi_char16_t *name, efi_guid_t guid,
 				       struct list_head *head, bool remove)
 {
-	struct efivar_entry *entry, *n;
+	struct efivar_entry *entry = NULL, *iter, *n;
 	int strsize1, strsize2;
-	bool found = false;
 
-	list_for_each_entry_safe(entry, n, head, list) {
+	list_for_each_entry_safe(iter, n, head, list) {
 		strsize1 = ucs2_strsize(name, 1024);
-		strsize2 = ucs2_strsize(entry->var.VariableName, 1024);
+		strsize2 = ucs2_strsize(iter->var.VariableName, 1024);
 		if (strsize1 == strsize2 &&
-		    !memcmp(name, &(entry->var.VariableName), strsize1) &&
-		    !efi_guidcmp(guid, entry->var.VendorGuid)) {
-			found = true;
+		    !memcmp(name, &(iter->var.VariableName), strsize1) &&
+		    !efi_guidcmp(guid, iter->var.VendorGuid)) {
+			entry = iter;
 			break;
 		}
 	}
 
-	if (!found)
+	if (!entry)
 		return NULL;
 
 	if (remove) {
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH 1/2] efi: remove use of list iterator variable after loop
  2022-03-31 22:10 [PATCH 1/2] efi: remove use of list iterator variable after loop Jakob Koschel
  2022-03-31 22:10 ` [PATCH 2/2] efi: replace usage of found with dedicated list iterator variable Jakob Koschel
@ 2022-04-13 17:05 ` Ard Biesheuvel
  2022-04-13 18:08   ` Jakob Koschel
  1 sibling, 1 reply; 7+ messages in thread
From: Ard Biesheuvel @ 2022-04-13 17:05 UTC (permalink / raw)
  To: Jakob Koschel, Matthew Garrett, Peter Jones
  Cc: linux-efi, Linux Kernel Mailing List, Mike Rapoport,
	Brian Johannesmeyer, Cristiano Giuffrida, Bos, H.J.

On Fri, 1 Apr 2022 at 00:11, Jakob Koschel <jakobkoschel@gmail.com> wrote:
>
> In preparation to limiting the scope of a list iterator to the list
> traversal loop, use a dedicated pointer to iterate through the list [1].
>
> In the current state the list_for_each_entry() is guaranteed to
> hit a break or goto in order to work properly. If the list iterator
> executes completely or the list is empty the iterator variable contains
> a type confused bogus value infered from the head of the list.
>
> With this patch the variable used past the list iterator is only set
> if the list exists early and is NULL otherwise. It should therefore
> be safe to just set *prev = NULL (as it was before).
>

This generic boilerplate is fine to include, but it would help if you
could point out why repainting the current logic with your new brush
is appropriate here.

In this particular case, I wonder whether updating *prev makes sense
to begin with if we are returning an error, and if we fix that, the
issue disappears as well.


> Link: https://lore.kernel.org/all/CAHk-=wgRr_D8CB-D9Kg-c=EHreAsk5SqXPwr9Y7k9sA6cWXJ6w@mail.gmail.com/
> Signed-off-by: Jakob Koschel <jakobkoschel@gmail.com>
> ---
>  drivers/firmware/efi/vars.c | 10 ++++++----
>  1 file changed, 6 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/firmware/efi/vars.c b/drivers/firmware/efi/vars.c
> index cae590bd08f2..3994aad38661 100644
> --- a/drivers/firmware/efi/vars.c
> +++ b/drivers/firmware/efi/vars.c
> @@ -1081,14 +1081,16 @@ int __efivar_entry_iter(int (*func)(struct efivar_entry *, void *),
>                         struct list_head *head, void *data,
>                         struct efivar_entry **prev)
>  {
> -       struct efivar_entry *entry, *n;
> +       struct efivar_entry *entry = NULL, *iter, *n;
>         int err = 0;
>
>         if (!prev || !*prev) {
> -               list_for_each_entry_safe(entry, n, head, list) {
> -                       err = func(entry, data);
> -                       if (err)
> +               list_for_each_entry_safe(iter, n, head, list) {
> +                       err = func(iter, data);
> +                       if (err) {
> +                               entry = iter;
>                                 break;
> +                       }
>                 }
>
>                 if (prev)
>
> base-commit: d888c83fcec75194a8a48ccd283953bdba7b2550
> --
> 2.25.1
>

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 2/2] efi: replace usage of found with dedicated list iterator variable
  2022-03-31 22:10 ` [PATCH 2/2] efi: replace usage of found with dedicated list iterator variable Jakob Koschel
@ 2022-04-13 17:09   ` Ard Biesheuvel
  0 siblings, 0 replies; 7+ messages in thread
From: Ard Biesheuvel @ 2022-04-13 17:09 UTC (permalink / raw)
  To: Jakob Koschel
  Cc: linux-efi, Linux Kernel Mailing List, Mike Rapoport,
	Brian Johannesmeyer, Cristiano Giuffrida, Bos, H.J.

On Fri, 1 Apr 2022 at 00:11, Jakob Koschel <jakobkoschel@gmail.com> wrote:
>
> To move the list iterator variable into the list_for_each_entry_*()
> macro in the future it should be avoided to use the list iterator
> variable after the loop body.
>
> To *never* use the list iterator variable after the loop it was
> concluded to use a separate iterator variable instead of a
> found boolean [1].
>
> This removes the need to use a found variable and simply checking if
> the variable was set, can determine if the break/goto was hit.
>
> Link: https://lore.kernel.org/all/CAHk-=wgRr_D8CB-D9Kg-c=EHreAsk5SqXPwr9Y7k9sA6cWXJ6w@mail.gmail.com/
> Signed-off-by: Jakob Koschel <jakobkoschel@gmail.com>

Acked-by: Ard Biesheuvel <ardb@kernel.org>

I'll queue this up once we converge on a solution for the other patch.

> ---
>  drivers/firmware/efi/vars.c | 15 +++++++--------
>  1 file changed, 7 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/firmware/efi/vars.c b/drivers/firmware/efi/vars.c
> index 3994aad38661..e4e1cc593441 100644
> --- a/drivers/firmware/efi/vars.c
> +++ b/drivers/firmware/efi/vars.c
> @@ -809,22 +809,21 @@ EXPORT_SYMBOL_GPL(efivar_entry_set_safe);
>  struct efivar_entry *efivar_entry_find(efi_char16_t *name, efi_guid_t guid,
>                                        struct list_head *head, bool remove)
>  {
> -       struct efivar_entry *entry, *n;
> +       struct efivar_entry *entry = NULL, *iter, *n;
>         int strsize1, strsize2;
> -       bool found = false;
>
> -       list_for_each_entry_safe(entry, n, head, list) {
> +       list_for_each_entry_safe(iter, n, head, list) {
>                 strsize1 = ucs2_strsize(name, 1024);
> -               strsize2 = ucs2_strsize(entry->var.VariableName, 1024);
> +               strsize2 = ucs2_strsize(iter->var.VariableName, 1024);
>                 if (strsize1 == strsize2 &&
> -                   !memcmp(name, &(entry->var.VariableName), strsize1) &&
> -                   !efi_guidcmp(guid, entry->var.VendorGuid)) {
> -                       found = true;
> +                   !memcmp(name, &(iter->var.VariableName), strsize1) &&
> +                   !efi_guidcmp(guid, iter->var.VendorGuid)) {
> +                       entry = iter;
>                         break;
>                 }
>         }
>
> -       if (!found)
> +       if (!entry)
>                 return NULL;
>
>         if (remove) {
> --
> 2.25.1
>

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 1/2] efi: remove use of list iterator variable after loop
  2022-04-13 17:05 ` [PATCH 1/2] efi: remove use of list iterator variable after loop Ard Biesheuvel
@ 2022-04-13 18:08   ` Jakob Koschel
  2022-04-13 22:09     ` Ard Biesheuvel
  0 siblings, 1 reply; 7+ messages in thread
From: Jakob Koschel @ 2022-04-13 18:08 UTC (permalink / raw)
  To: Ard Biesheuvel
  Cc: Matthew Garrett, Peter Jones, linux-efi,
	Linux Kernel Mailing List, Mike Rapoport, Brian Johannesmeyer,
	Cristiano Giuffrida, Bos, H.J.



> On 13. Apr 2022, at 19:05, Ard Biesheuvel <ardb@kernel.org> wrote:
> 
> On Fri, 1 Apr 2022 at 00:11, Jakob Koschel <jakobkoschel@gmail.com> wrote:
>> 
>> In preparation to limiting the scope of a list iterator to the list
>> traversal loop, use a dedicated pointer to iterate through the list [1].
>> 
>> In the current state the list_for_each_entry() is guaranteed to
>> hit a break or goto in order to work properly. If the list iterator
>> executes completely or the list is empty the iterator variable contains
>> a type confused bogus value infered from the head of the list.
>> 
>> With this patch the variable used past the list iterator is only set
>> if the list exists early and is NULL otherwise. It should therefore
>> be safe to just set *prev = NULL (as it was before).
>> 
> 
> This generic boilerplate is fine to include, but it would help if you
> could point out why repainting the current logic with your new brush
> is appropriate here.

This makes sense, I can see that the commit message should be improved here.

> 
> In this particular case, I wonder whether updating *prev makes sense
> to begin with if we are returning an error, and if we fix that, the
> issue disappears as well.

Actually I'm rethinking this now. The only use of 'prev' that I can see is
in efi_pstore_erase_name(). It only uses it if found != 0
which would mean err != 0 in __efivar_entry_iter().

This would allow massively simplifying the entire function.
The valid case is updating *prev when there is an "error" as far as I can tell.

I've sketched up a rewritten function that should hopefully be more clear and
archive the same goal, I'm curious what you think:


	int __efivar_entry_iter(int (*func)(struct efivar_entry *, void *),
				struct list_head *head, void *data,
				struct efivar_entry **prev)
	{
		struct efivar_entry *entry, *n;
		int err = 0;

		/* If prev is set and *prev != NULL start iterating from there */
		if (prev)
			entry = list_prepare_entry(*prev, head, list);
		/* Otherwise start at the beginning */
		else
			entry = list_entry(head, typeof(*entry), list);
		list_for_each_entry_safe_continue(entry, n, head, list) {
			err = func(entry, data);
			if (err && prev)
				*prev = entry;
			if (err)
				return err;
		}

		return 0;
	}


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 1/2] efi: remove use of list iterator variable after loop
  2022-04-13 18:08   ` Jakob Koschel
@ 2022-04-13 22:09     ` Ard Biesheuvel
  2022-06-28  8:02       ` Ard Biesheuvel
  0 siblings, 1 reply; 7+ messages in thread
From: Ard Biesheuvel @ 2022-04-13 22:09 UTC (permalink / raw)
  To: Jakob Koschel, Kees Cook
  Cc: Matthew Garrett, Peter Jones, linux-efi,
	Linux Kernel Mailing List, Mike Rapoport, Brian Johannesmeyer,
	Cristiano Giuffrida, Bos, H.J.

(cc Kees for pstore)

On Wed, 13 Apr 2022 at 20:08, Jakob Koschel <jakobkoschel@gmail.com> wrote:
>
>
>
> > On 13. Apr 2022, at 19:05, Ard Biesheuvel <ardb@kernel.org> wrote:
> >
> > On Fri, 1 Apr 2022 at 00:11, Jakob Koschel <jakobkoschel@gmail.com> wrote:
> >>
> >> In preparation to limiting the scope of a list iterator to the list
> >> traversal loop, use a dedicated pointer to iterate through the list [1].
> >>
> >> In the current state the list_for_each_entry() is guaranteed to
> >> hit a break or goto in order to work properly. If the list iterator
> >> executes completely or the list is empty the iterator variable contains
> >> a type confused bogus value infered from the head of the list.
> >>
> >> With this patch the variable used past the list iterator is only set
> >> if the list exists early and is NULL otherwise. It should therefore
> >> be safe to just set *prev = NULL (as it was before).
> >>
> >
> > This generic boilerplate is fine to include, but it would help if you
> > could point out why repainting the current logic with your new brush
> > is appropriate here.
>
> This makes sense, I can see that the commit message should be improved here.
>
> >
> > In this particular case, I wonder whether updating *prev makes sense
> > to begin with if we are returning an error, and if we fix that, the
> > issue disappears as well.
>
> Actually I'm rethinking this now. The only use of 'prev' that I can see is
> in efi_pstore_erase_name(). It only uses it if found != 0
> which would mean err != 0 in __efivar_entry_iter().
>
> This would allow massively simplifying the entire function.
> The valid case is updating *prev when there is an "error" as far as I can tell.
>

OK, so in summary, the only user of that code that bothers to pass a
value for prev abuses it to implement its own version of
efivar_entry_find(), and so if we fix that caller, we can drop the
'prev' argument from this function altogether.


> I've sketched up a rewritten function that should hopefully be more clear and
> archive the same goal, I'm curious what you think:
>
>
>         int __efivar_entry_iter(int (*func)(struct efivar_entry *, void *),
>                                 struct list_head *head, void *data,
>                                 struct efivar_entry **prev)
>         {
>                 struct efivar_entry *entry, *n;
>                 int err = 0;
>
>                 /* If prev is set and *prev != NULL start iterating from there */
>                 if (prev)
>                         entry = list_prepare_entry(*prev, head, list);
>                 /* Otherwise start at the beginning */
>                 else
>                         entry = list_entry(head, typeof(*entry), list);
>                 list_for_each_entry_safe_continue(entry, n, head, list) {
>                         err = func(entry, data);
>                         if (err && prev)
>                                 *prev = entry;
>                         if (err)
>                                 return err;
>                 }
>
>                 return 0;
>         }
>

Thanks for this. I'll have a stab myself at fixing the EFI pstore
code, and hopefully we can clean up __efivar_entry_iter() as I
suggested.

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 1/2] efi: remove use of list iterator variable after loop
  2022-04-13 22:09     ` Ard Biesheuvel
@ 2022-06-28  8:02       ` Ard Biesheuvel
  0 siblings, 0 replies; 7+ messages in thread
From: Ard Biesheuvel @ 2022-06-28  8:02 UTC (permalink / raw)
  To: Jakob Koschel, Kees Cook
  Cc: Matthew Garrett, Peter Jones, linux-efi,
	Linux Kernel Mailing List, Mike Rapoport, Brian Johannesmeyer,
	Cristiano Giuffrida, Bos, H.J.

On Thu, 14 Apr 2022 at 00:09, Ard Biesheuvel <ardb@kernel.org> wrote:
>
> (cc Kees for pstore)
>
> On Wed, 13 Apr 2022 at 20:08, Jakob Koschel <jakobkoschel@gmail.com> wrote:
> >
> >
> >
> > > On 13. Apr 2022, at 19:05, Ard Biesheuvel <ardb@kernel.org> wrote:
> > >
> > > On Fri, 1 Apr 2022 at 00:11, Jakob Koschel <jakobkoschel@gmail.com> wrote:
> > >>
> > >> In preparation to limiting the scope of a list iterator to the list
> > >> traversal loop, use a dedicated pointer to iterate through the list [1].
> > >>
> > >> In the current state the list_for_each_entry() is guaranteed to
> > >> hit a break or goto in order to work properly. If the list iterator
> > >> executes completely or the list is empty the iterator variable contains
> > >> a type confused bogus value infered from the head of the list.
> > >>
> > >> With this patch the variable used past the list iterator is only set
> > >> if the list exists early and is NULL otherwise. It should therefore
> > >> be safe to just set *prev = NULL (as it was before).
> > >>
> > >
> > > This generic boilerplate is fine to include, but it would help if you
> > > could point out why repainting the current logic with your new brush
> > > is appropriate here.
> >
> > This makes sense, I can see that the commit message should be improved here.
> >
> > >
> > > In this particular case, I wonder whether updating *prev makes sense
> > > to begin with if we are returning an error, and if we fix that, the
> > > issue disappears as well.
> >
> > Actually I'm rethinking this now. The only use of 'prev' that I can see is
> > in efi_pstore_erase_name(). It only uses it if found != 0
> > which would mean err != 0 in __efivar_entry_iter().
> >
> > This would allow massively simplifying the entire function.
> > The valid case is updating *prev when there is an "error" as far as I can tell.
> >
>
> OK, so in summary, the only user of that code that bothers to pass a
> value for prev abuses it to implement its own version of
> efivar_entry_find(), and so if we fix that caller, we can drop the
> 'prev' argument from this function altogether.
>
>
> > I've sketched up a rewritten function that should hopefully be more clear and
> > archive the same goal, I'm curious what you think:
> >
> >
> >         int __efivar_entry_iter(int (*func)(struct efivar_entry *, void *),
> >                                 struct list_head *head, void *data,
> >                                 struct efivar_entry **prev)
> >         {
> >                 struct efivar_entry *entry, *n;
> >                 int err = 0;
> >
> >                 /* If prev is set and *prev != NULL start iterating from there */
> >                 if (prev)
> >                         entry = list_prepare_entry(*prev, head, list);
> >                 /* Otherwise start at the beginning */
> >                 else
> >                         entry = list_entry(head, typeof(*entry), list);
> >                 list_for_each_entry_safe_continue(entry, n, head, list) {
> >                         err = func(entry, data);
> >                         if (err && prev)
> >                                 *prev = entry;
> >                         if (err)
> >                                 return err;
> >                 }
> >
> >                 return 0;
> >         }
> >
>
> Thanks for this. I'll have a stab myself at fixing the EFI pstore
> code, and hopefully we can clean up __efivar_entry_iter() as I
> suggested.

This is now queued up in the EFI tree: the pstore driver no longer use
the efivar_entry API at all, and the remaining user of
efivar_entry_iter() does not use the value of the iterator variable in
the same way.

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2022-06-28  8:03 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-03-31 22:10 [PATCH 1/2] efi: remove use of list iterator variable after loop Jakob Koschel
2022-03-31 22:10 ` [PATCH 2/2] efi: replace usage of found with dedicated list iterator variable Jakob Koschel
2022-04-13 17:09   ` Ard Biesheuvel
2022-04-13 17:05 ` [PATCH 1/2] efi: remove use of list iterator variable after loop Ard Biesheuvel
2022-04-13 18:08   ` Jakob Koschel
2022-04-13 22:09     ` Ard Biesheuvel
2022-06-28  8:02       ` Ard Biesheuvel

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.