All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Gustavo A. R. Silva" <gustavoars@kernel.org>
To: Kees Cook <keescook@chromium.org>
Cc: Dave Hansen <dave.hansen@linux.intel.com>,
	Andy Lutomirski <luto@kernel.org>,
	Peter Zijlstra <peterz@infradead.org>,
	Thomas Gleixner <tglx@linutronix.de>,
	Ingo Molnar <mingo@redhat.com>, Borislav Petkov <bp@alien8.de>,
	"H. Peter Anvin" <hpa@zytor.com>,
	x86@kernel.org, linux-kernel@vger.kernel.org,
	linux-hardening@vger.kernel.org
Subject: Re: [PATCH v2][next] x86/mm/pgtable: Fix -Wstringop-overflow warnings
Date: Mon, 9 May 2022 15:50:56 -0500	[thread overview]
Message-ID: <20220509205056.GA109715@embeddedor> (raw)
In-Reply-To: <202205091251.5703DE2@keescook>

On Mon, May 09, 2022 at 12:59:15PM -0700, Kees Cook wrote:
> On Mon, May 09, 2022 at 02:45:41PM -0500, Gustavo A. R. Silva wrote:
> > Fix the following -Wstringop-overflow warnings when building with GCC-12.1:
> > 
> > arch/x86/mm/pgtable.c:437:13: warning: 'preallocate_pmds' accessing 8 bytes in a region of size 0 [-Wstringop-overflow=]
> > arch/x86/mm/pgtable.c:440:13: warning: 'preallocate_pmds' accessing 8 bytes in a region of size 0 [-Wstringop-overflow=]
> > arch/x86/mm/pgtable.c:462:9: warning: 'free_pmds' accessing 8 bytes in a region of size 0 [-Wstringop-overflow=]
> > arch/x86/mm/pgtable.c:454:9: warning: 'pgd_prepopulate_pmd' accessing 8 bytes in a region of size 0 [-Wstringop-overflow=]
> > arch/x86/mm/pgtable.c:455:9: warning: 'pgd_prepopulate_user_pmd' accessing 8 bytes in a region of size 0 [-Wstringop-overflow=]
> > arch/x86/mm/pgtable.c:464:9: warning: 'free_pmds' accessing 8 bytes in a region of size 0 [-Wstringop-overflow=]
> > 
> > There is a case in which PREALLOCATED_PMDS, MAX_PREALLOCATED_PMDS,
> > PREALLOCATED_USER_PMDS and MAX_PREALLOCATED_USER_PMDS are defined as
> > zero:
> > 
> > 204 #else  /* !CONFIG_X86_PAE */
> > 205 
> > 206 /* No need to prepopulate any pagetable entries in non-PAE modes. */
> > 207 #define PREALLOCATED_PMDS       0
> > 208 #define MAX_PREALLOCATED_PMDS   0
> > 209 #define PREALLOCATED_USER_PMDS   0
> > 210 #define MAX_PREALLOCATED_USER_PMDS 0
> > 211 #endif  /* CONFIG_X86_PAE */
> > 
> > It seems that GCC is legitimately complaining about the fact that, under
> > certain circumstances, u_pmds and pmds are declared as zero-length arrays
> > in the stack and, of course, they are not flexible arrays.
> 
> Ah yeah, I've run into this a few times. Since the relationship between
> the macro pairs can't be seen by GCC, it gets upset (i.e. sizeof(u_pmds)
> has no relationship wtih PREALLOCATED_USER_PMDS and the calls weren't
> inlined, so it can't see that it'll always be 0 and 0).
> 
> > 424 pgd_t *pgd_alloc(struct mm_struct *mm)
> > 425 {
> > 426         pgd_t *pgd;
> > 427         pmd_t *u_pmds[MAX_PREALLOCATED_USER_PMDS];
> > 428         pmd_t *pmds[MAX_PREALLOCATED_PMDS];
> > 429
> > 
> > Notice that "Accessing elements of zero-length arrays declared in such
> > contexts is undefined and may be diagnosed."[1]
> > 
> > We can fix this by checking that MAX_PREALLOCATED_PMDS and MAX_PREALLOCATED_USER_PMDS
> > are different than zero, prior to passing u_pmds amd pmds as arguments to any
> > function, in this case to functions preallocate_pmds(), pgd_prepopulate_pmd()
> > and free_pmds().
> > 
> > This helps with the ongoing efforts to globally enable
> > -Wstringop-overflow.
> > 
> > [1] https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html
> > 
> > Link: https://github.com/KSPP/linux/issues/181
> > Signed-off-by: Gustavo A. R. Silva <gustavoars@kernel.org>
> > ---
> > Changes in v2:
> >  - Check MAX_PREALLOCATED_PMDS and MAX_PREALLOCATED_USER_PMDS
> >    instead of using pointer notation.
> >    Link: https://lore.kernel.org/linux-hardening/20220401005834.GA182932@embeddedor/
> >  - Update changelog text.
> > 
> >  arch/x86/mm/pgtable.c | 16 ++++++++++------
> >  1 file changed, 10 insertions(+), 6 deletions(-)
> > 
> > diff --git a/arch/x86/mm/pgtable.c b/arch/x86/mm/pgtable.c
> > index f16059e9a85e..96c3f402a1da 100644
> > --- a/arch/x86/mm/pgtable.c
> > +++ b/arch/x86/mm/pgtable.c
> > @@ -434,14 +434,18 @@ pgd_t *pgd_alloc(struct mm_struct *mm)
> >  
> >  	mm->pgd = pgd;
> >  
> > -	if (preallocate_pmds(mm, pmds, PREALLOCATED_PMDS) != 0)
> > -		goto out_free_pgd;
> > +	if (MAX_PREALLOCATED_PMDS != 0 && MAX_PREALLOCATED_USER_PMDS != 0) {
> > +		if (preallocate_pmds(mm, pmds, PREALLOCATED_PMDS) != 0)
> > +			goto out_free_pgd;
> >  
> > -	if (preallocate_pmds(mm, u_pmds, PREALLOCATED_USER_PMDS) != 0)
> > -		goto out_free_pmds;
> > +		if (preallocate_pmds(mm, u_pmds, PREALLOCATED_USER_PMDS) != 0)
> > +			goto out_free_pmds;
> >  
> > -	if (paravirt_pgd_alloc(mm) != 0)
> > -		goto out_free_user_pmds;
> > +		if (paravirt_pgd_alloc(mm) != 0)
> > +			goto out_free_user_pmds;
> > +	} else {
> > +		goto out_free_pgd;
> 
> The "all 0" case shouldn't be a failure mode; it should just skip the
> preallocate_pmds() calls.

Do you mean something like this:

diff --git a/arch/x86/mm/pgtable.c b/arch/x86/mm/pgtable.c
index f16059e9a85e..4dae168408f1 100644
--- a/arch/x86/mm/pgtable.c
+++ b/arch/x86/mm/pgtable.c
@@ -434,11 +434,13 @@ pgd_t *pgd_alloc(struct mm_struct *mm)

        mm->pgd = pgd;

-       if (preallocate_pmds(mm, pmds, PREALLOCATED_PMDS) != 0)
-               goto out_free_pgd;
+       if (MAX_PREALLOCATED_PMDS != 0 && MAX_PREALLOCATED_USER_PMDS != 0) {
+               if (preallocate_pmds(mm, pmds, PREALLOCATED_PMDS) != 0)
+                       goto out_free_pgd;

-       if (preallocate_pmds(mm, u_pmds, PREALLOCATED_USER_PMDS) != 0)
-               goto out_free_pmds;
+               if (preallocate_pmds(mm, u_pmds, PREALLOCATED_USER_PMDS) != 0)
+                       goto out_free_pmds;
+       }

        if (paravirt_pgd_alloc(mm) != 0)
                goto out_free_user_pmds;

It seems that the above is not enough, because we have the same issue
when calling pgd_prepopulate_pmd(), pgd_prepopulate_user_pmd() and
free_pmds():

  CC      arch/x86/mm/pgtable.o
arch/x86/mm/pgtable.c: In function 'pgd_alloc':
arch/x86/mm/pgtable.c:464:9: warning: 'free_pmds' accessing 8 bytes in a region of size 0 [-Wstringop-overflow=]
  464 |         free_pmds(mm, u_pmds, PREALLOCATED_USER_PMDS);
      |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
arch/x86/mm/pgtable.c:464:9: note: referencing argument 2 of type 'pmd_t *[0]'
arch/x86/mm/pgtable.c:213:13: note: in a call to function 'free_pmds'
  213 | static void free_pmds(struct mm_struct *mm, pmd_t *pmds[], int count)
      |             ^~~~~~~~~
arch/x86/mm/pgtable.c:466:9: warning: 'free_pmds' accessing 8 bytes in a region of size 0 [-Wstringop-overflow=]
  466 |         free_pmds(mm, pmds, PREALLOCATED_PMDS);
      |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
arch/x86/mm/pgtable.c:466:9: note: referencing argument 2 of type 'pmd_t *[0]'
arch/x86/mm/pgtable.c:213:13: note: in a call to function 'free_pmds'
  213 | static void free_pmds(struct mm_struct *mm, pmd_t *pmds[], int count)
      |             ^~~~~~~~~
arch/x86/mm/pgtable.c:456:9: warning: 'pgd_prepopulate_pmd' accessing 8 bytes in a region of size 0 [-Wstringop-overflow=]
  456 |         pgd_prepopulate_pmd(mm, pgd, pmds);
      |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
arch/x86/mm/pgtable.c:456:9: note: referencing argument 3 of type 'pmd_t *[0]'
arch/x86/mm/pgtable.c:296:13: note: in a call to function 'pgd_prepopulate_pmd'
  296 | static void pgd_prepopulate_pmd(struct mm_struct *mm, pgd_t *pgd, pmd_t *pmds[])
      |             ^~~~~~~~~~~~~~~~~~~
arch/x86/mm/pgtable.c:457:9: warning: 'pgd_prepopulate_user_pmd' accessing 8 bytes in a region of size 0 [-Wstringop-overflow=]
  457 |         pgd_prepopulate_user_pmd(mm, pgd, u_pmds);
      |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
arch/x86/mm/pgtable.c:457:9: note: referencing argument 3 of type 'pmd_t *[0]'
arch/x86/mm/pgtable.c:320:13: note: in a call to function 'pgd_prepopulate_user_pmd'
  320 | static void pgd_prepopulate_user_pmd(struct mm_struct *mm,
      |             ^~~~~~~~~~~~~~~~~~~~~~~~

--
Gustavo
> 
> > +	}
> >  
> >  	/*
> >  	 * Make sure that pre-populating the pmds is atomic with
> > -- 
> > 2.27.0
> > 
> 
> -- 
> Kees Cook

  reply	other threads:[~2022-05-09 20:42 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-05-09 19:45 [PATCH v2][next] x86/mm/pgtable: Fix -Wstringop-overflow warnings Gustavo A. R. Silva
2022-05-09 19:59 ` Kees Cook
2022-05-09 20:50   ` Gustavo A. R. Silva [this message]
2022-05-09 20:54     ` Kees Cook
2022-05-10 14:12       ` Gustavo A. R. Silva
2022-05-10 14:54         ` Gustavo A. R. Silva
2022-05-11 18:41         ` Kees Cook

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=20220509205056.GA109715@embeddedor \
    --to=gustavoars@kernel.org \
    --cc=bp@alien8.de \
    --cc=dave.hansen@linux.intel.com \
    --cc=hpa@zytor.com \
    --cc=keescook@chromium.org \
    --cc=linux-hardening@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=luto@kernel.org \
    --cc=mingo@redhat.com \
    --cc=peterz@infradead.org \
    --cc=tglx@linutronix.de \
    --cc=x86@kernel.org \
    /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.