All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/1] pgo: Fix allocate_node() handling of non-vmlinux nodes
@ 2021-06-02  0:57 Jarmo Tiitto
  2021-06-02  0:57 ` [PATCH 1/1] " Jarmo Tiitto
  0 siblings, 1 reply; 4+ messages in thread
From: Jarmo Tiitto @ 2021-06-02  0:57 UTC (permalink / raw)
  To: Nathan Chancellor, Nick Desaulniers, clang-built-linux
  Cc: Jarmo Tiitto, samitolvanen, morbo, keescook, linux-kernel

Currently allocate_node() will reserve nodes even if *p
doesn't point into __llvm_prf_data_start - __llvm_prf_data_end
range.

This is wrong:

Any instrumented modules that are not part of vmlinux
(built-in) will "steal" available nodes away from vmlinux.
This can result in exhaustion of nodes for vmlinux
and less accurate profile data.

Either way, any profiling data generated by loaded modules, 
if any, is unusable from vmlinux.profraw.
So just filtter them out.

Jarmo Tiitto (1):
  pgo: Fix allocate_node() handling of non-vmlinux nodes.

 kernel/pgo/instrument.c | 4 ++++
 1 file changed, 4 insertions(+)

-- 
2.31.1


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

* [PATCH 1/1] pgo: Fix allocate_node() handling of non-vmlinux nodes.
  2021-06-02  0:57 [PATCH 0/1] pgo: Fix allocate_node() handling of non-vmlinux nodes Jarmo Tiitto
@ 2021-06-02  0:57 ` Jarmo Tiitto
  2021-06-02 17:41   ` Kees Cook
  0 siblings, 1 reply; 4+ messages in thread
From: Jarmo Tiitto @ 2021-06-02  0:57 UTC (permalink / raw)
  To: Sami Tolvanen, Bill Wendling, Kees Cook, Nathan Chancellor,
	Nick Desaulniers, clang-built-linux, linux-kernel
  Cc: Jarmo Tiitto, morbo

Currently allocate_node() will reserve nodes even if *p
doesn't point into __llvm_prf_data_start - __llvm_prf_data_end
range.

Fix it by checking if p points into vmlinux range
and otherwise return NULL.

Signed-off-by: Jarmo Tiitto <jarmo.tiitto@gmail.com>
---
 kernel/pgo/instrument.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/kernel/pgo/instrument.c b/kernel/pgo/instrument.c
index 0e07ee1b17d9..9bca535dfa91 100644
--- a/kernel/pgo/instrument.c
+++ b/kernel/pgo/instrument.c
@@ -55,6 +55,10 @@ void prf_unlock(unsigned long flags)
 static struct llvm_prf_value_node *allocate_node(struct llvm_prf_data *p,
 						 u32 index, u64 value)
 {
+	/* check if p points into vmlinux. If not, don't allocate. */
+	if (p < __llvm_prf_data_start || p >= __llvm_prf_data_end)
+		return NULL;
+
 	if (&__llvm_prf_vnds_start[current_node + 1] >= __llvm_prf_vnds_end)
 		return NULL; /* Out of nodes */
 
-- 
2.31.1


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

* Re: [PATCH 1/1] pgo: Fix allocate_node() handling of non-vmlinux nodes.
  2021-06-02  0:57 ` [PATCH 1/1] " Jarmo Tiitto
@ 2021-06-02 17:41   ` Kees Cook
  2021-06-02 18:52     ` jarmo.tiitto
  0 siblings, 1 reply; 4+ messages in thread
From: Kees Cook @ 2021-06-02 17:41 UTC (permalink / raw)
  To: Jarmo Tiitto
  Cc: Sami Tolvanen, Bill Wendling, Nathan Chancellor,
	Nick Desaulniers, clang-built-linux, linux-kernel, morbo

On Wed, Jun 02, 2021 at 03:57:04AM +0300, Jarmo Tiitto wrote:
> Currently allocate_node() will reserve nodes even if *p
> doesn't point into __llvm_prf_data_start - __llvm_prf_data_end
> range.
> 
> Fix it by checking if p points into vmlinux range
> and otherwise return NULL.
> 
> Signed-off-by: Jarmo Tiitto <jarmo.tiitto@gmail.com>
> ---
>  kernel/pgo/instrument.c | 4 ++++
>  1 file changed, 4 insertions(+)
> 
> diff --git a/kernel/pgo/instrument.c b/kernel/pgo/instrument.c
> index 0e07ee1b17d9..9bca535dfa91 100644
> --- a/kernel/pgo/instrument.c
> +++ b/kernel/pgo/instrument.c
> @@ -55,6 +55,10 @@ void prf_unlock(unsigned long flags)
>  static struct llvm_prf_value_node *allocate_node(struct llvm_prf_data *p,
>  						 u32 index, u64 value)
>  {
> +	/* check if p points into vmlinux. If not, don't allocate. */
> +	if (p < __llvm_prf_data_start || p >= __llvm_prf_data_end)
> +		return NULL;

This should be a tighter check (struct llvm_prf_data has size, so just
checking for p < __llvm_prf_data_end isn't sufficient. I recommend using
the memory_contains() helper.

And I think this should be louder as it's entirely unexpected right
now. Perhaps:

	if (WARN_ON_ONCE(!memory_contains(__llvm_prf_data_start,
					  __llvm_prf_data_end,
					  p, sizeof(*p))))
		return NULL;

> +
>  	if (&__llvm_prf_vnds_start[current_node + 1] >= __llvm_prf_vnds_end)
>  		return NULL; /* Out of nodes */
>  
> -- 
> 2.31.1
> 

-- 
Kees Cook

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

* Re: [PATCH 1/1] pgo: Fix allocate_node() handling of non-vmlinux nodes.
  2021-06-02 17:41   ` Kees Cook
@ 2021-06-02 18:52     ` jarmo.tiitto
  0 siblings, 0 replies; 4+ messages in thread
From: jarmo.tiitto @ 2021-06-02 18:52 UTC (permalink / raw)
  To: Jarmo Tiitto, Kees Cook
  Cc: Sami Tolvanen, Bill Wendling, Nathan Chancellor,
	Nick Desaulniers, clang-built-linux, linux-kernel, morbo

Kees Cook wrote keskiviikkona 2. kesäkuuta 2021 20.41.28 EEST:
> On Wed, Jun 02, 2021 at 03:57:04AM +0300, Jarmo Tiitto wrote:
> > Currently allocate_node() will reserve nodes even if *p
> > doesn't point into __llvm_prf_data_start - __llvm_prf_data_end
> > range.
> > 
> > Fix it by checking if p points into vmlinux range
> > and otherwise return NULL.
> > 
> > Signed-off-by: Jarmo Tiitto <jarmo.tiitto@gmail.com>
> > ---
> >  kernel/pgo/instrument.c | 4 ++++
> >  1 file changed, 4 insertions(+)
> > 
> > diff --git a/kernel/pgo/instrument.c b/kernel/pgo/instrument.c
> > index 0e07ee1b17d9..9bca535dfa91 100644
> > --- a/kernel/pgo/instrument.c
> > +++ b/kernel/pgo/instrument.c
> > @@ -55,6 +55,10 @@ void prf_unlock(unsigned long flags)
> >  static struct llvm_prf_value_node *allocate_node(struct llvm_prf_data *p,
> >  						 u32 index, u64 value)
> >  {
> > +	/* check if p points into vmlinux. If not, don't allocate. */
> > +	if (p < __llvm_prf_data_start || p >= __llvm_prf_data_end)
> > +		return NULL;
> 
> This should be a tighter check (struct llvm_prf_data has size, so just
> checking for p < __llvm_prf_data_end isn't sufficient. I recommend using
> the memory_contains() helper.
> 
> And I think this should be louder as it's entirely unexpected right
> now. Perhaps:
> 
> 	if (WARN_ON_ONCE(!memory_contains(__llvm_prf_data_start,
> 					  __llvm_prf_data_end,
> 					  p, sizeof(*p))))
> 		return NULL;
> 
> > +
> >  	if (&__llvm_prf_vnds_start[current_node + 1] >= __llvm_prf_vnds_end)
> >  		return NULL; /* Out of nodes */
> >  
> > -- 
> > 2.31.1
> > 
> 
> -- 
> Kees Cook
> 


Well, if you do that the WARN_ON_ONCE() will always trigger, unless CONFIG_MODULES=n 😇

This is because 'struct llvm_prf_data *p' argument is expected
(at least I think so) to point into __llvm_prf_data section in vmlinux
and also into each module's own __llvm_prf_data section.

So in the end the compiler supplied pointer is likely correct,
but the current v9 PGO patch attempts to reserve all vnodes
from vmlinux __llvm_prf_vnds section, instead of respective module section.

I think it would be normal to ignore pointers here,
until my module PGO machinery is ready.

But I agree on using memory_contains() for checking if p is within bounds.
I will follow on with v2 of this patch. :-)

-Jarmo




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

end of thread, other threads:[~2021-06-02 18:53 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-06-02  0:57 [PATCH 0/1] pgo: Fix allocate_node() handling of non-vmlinux nodes Jarmo Tiitto
2021-06-02  0:57 ` [PATCH 1/1] " Jarmo Tiitto
2021-06-02 17:41   ` Kees Cook
2021-06-02 18:52     ` jarmo.tiitto

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.