All of lore.kernel.org
 help / color / mirror / Atom feed
From: Kees Cook <kees@kernel.org>
To: Tom Rix <trix@redhat.com>
Cc: Qing Zhao <qing.zhao@oracle.com>,
	mhiramat@kernel.org, akpm@linux-foundation.org,
	ndesaulniers@google.com, masahiroy@kernel.org,
	paulmck@kernel.org, hannes@cmpxchg.org, ojeda@kernel.org,
	thunder.leizhen@huawei.com, christophe.leroy@csgroup.eu,
	vbabka@suse.cz, linux-kernel@vger.kernel.org,
	linux-hardening@vger.kernel.org
Subject: Re: [PATCH] init/Kconfig: extend -Wno-array-bounds to gcc 13
Date: Mon, 17 Jun 2024 14:02:51 -0700	[thread overview]
Message-ID: <202406171348.8D43518308@keescook> (raw)
In-Reply-To: <20230306220947.1982272-1-trix@redhat.com>

*thread necromancy*

On Mon, Mar 06, 2023 at 05:09:47PM -0500, Tom Rix wrote:
> With gcc 13.0.1 on x86, there are several false positives like
> 
> drivers/net/ethernet/microchip/sparx5/sparx5_psfp.c:167:31:
>   error: array subscript 4 is above array bounds of ‘const struct sparx5_psfp_gce[4]’ [-Werror=array-bounds=]
>   167 |                 gce = &sg->gce[i];
>       |                        ~~~~~~~^~~
> In file included from drivers/net/ethernet/microchip/sparx5/sparx5_psfp.c:8:
> drivers/net/ethernet/microchip/sparx5/sparx5_main.h:506:32: note: while referencing ‘gce’
>   506 |         struct sparx5_psfp_gce gce[SPX5_PSFP_GCE_CNT];
>       |                                ^~~
> 
> The code lines for the reported problem
> 	/* For each scheduling entry */
> 	for (i = 0; i < sg->num_entries; i++) {
> 		gce = &sg->gce[i];
> 
> i is bounded by num_entries, which is set in sparx5_tc_flower.c
> 	if (act->gate.num_entries >= SPX5_PSFP_GCE_CNT) {
> 		NL_SET_ERR_MSG_MOD(extack, "Invalid number of gate entries");
> 		return -EINVAL;
> 	}
> ..
> 	sg->num_entries = act->gate.num_entries;
> 
> So disable array-bounds as was done on gcc 11 and 12

So, as it turns out, after much discussion with GCC devs (and Qing's great
patience with me), I finally see that this is not a false positive. GCC
correctly sees a test for "i >= SPX5_PSFP_GCE_CNT", hidden away in the
macros and inlines, and is reporting "Look, you have an execution path
where i is out of bounds."

(It is not a result of the shift sanitizer nor the array bounds sanitizer
-- I was convinced these were responsible, but I was wrong.)

Here are the details:


"gce" is this array of size 4:

struct sparx5_psfp_sg {
	...
        u32 num_entries;            /* PSFPAdminControlListLength */
        struct sparx5_psfp_gce gce[SPX5_PSFP_GCE_CNT];
};

#define SPX5_PSFP_GCE_CNT 4

with the loop:

        for (i = 0; i < sg->num_entries; i++) {
                gce = &sg->gce[i];
		...
                spx5_wr(ANA_AC_SG_GCL_GS_CONFIG_IPS_SET(ips) |
                        ANA_AC_SG_GCL_GS_CONFIG_GATE_STATE_SET(gce->gate_state),
                        sparx5, ANA_AC_SG_GCL_GS_CONFIG(i));

That last macro is:

#define ANA_AC_SG_GCL_GS_CONFIG(r) __REG(TARGET_ANA_AC,\
                                        0, 1, 851584, 0, 1, 128, 0, r, 4, 4)

Note the "r, 4", which is actually "i, 4". These are passed into
spx5_wr() as rinst and rcnt respectively:

static inline void spx5_wr(u32 val, struct sparx5 *sparx5,
                           int id, int tinst, int tcnt,
                           int gbase, int ginst, int gcnt, int gwidth,
                           int raddr, int rinst, int rcnt, int rwidth)
{
        writel(val, spx5_addr(sparx5->regs, id, tinst, tcnt,
                              gbase, ginst, gcnt, gwidth,
                              raddr, rinst, rcnt, rwidth));
}

and spx5_addr() does:

static inline void __iomem *spx5_addr(void __iomem *base[],
                                      int id, int tinst, int tcnt,
                                      int gbase, int ginst,
                                      int gcnt, int gwidth,
                                      int raddr, int rinst,
                                      int rcnt, int rwidth)
{
	...
        WARN_ON((rinst) >= rcnt);


It is specifically checking for "i >= 4", and GCC is correctly reporting
that this is therefore a reachable path.

So, the correct fix here is to do the check up front and make sure an
invalid array indexing cannot happen:

diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_psfp.c b/drivers/net/ethernet/microchip/sparx5/sparx5_psfp.c
index 8dee1ab1fa75..23c40b9b74d5 100644
--- a/drivers/net/ethernet/microchip/sparx5/sparx5_psfp.c
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_psfp.c
@@ -163,7 +163,7 @@ static int sparx5_psfp_sg_set(struct sparx5 *sparx5, u32 id,
 	spx5_wr(sg->cycletimeext, sparx5, ANA_AC_SG_CONFIG_REG_5);
 
 	/* For each scheduling entry */
-	for (i = 0; i < sg->num_entries; i++) {
+	for (i = 0; i < ARRAY_SIZE(sg->gce) && i < sg->num_entries; i++) {
 		gce = &sg->gce[i];
 		ips = sparx5_psfp_ipv_to_ips(gce->ipv);
 		/* hardware needs TimeInterval to be cumulative */

Or, if you want to retain the WARN:


diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_psfp.c b/drivers/net/ethernet/microchip/sparx5/sparx5_psfp.c
index 8dee1ab1fa75..5ffeb299fcb4 100644
--- a/drivers/net/ethernet/microchip/sparx5/sparx5_psfp.c
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_psfp.c
@@ -164,6 +164,8 @@ static int sparx5_psfp_sg_set(struct sparx5 *sparx5, u32 id,
 
 	/* For each scheduling entry */
 	for (i = 0; i < sg->num_entries; i++) {
+		if (WARN_ON_ONCE(i >= ARRAY_SIZE(sg->gce)))
+			break;
 		gce = &sg->gce[i];
 		ips = sparx5_psfp_ipv_to_ips(gce->ipv);
 		/* hardware needs TimeInterval to be cumulative */


-- 
Kees Cook

      parent reply	other threads:[~2024-06-17 21:02 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-03-06 22:09 [PATCH] init/Kconfig: extend -Wno-array-bounds to gcc 13 Tom Rix
2023-03-06 22:20 ` Nick Desaulniers
2023-03-06 23:02   ` Kees Cook
2023-03-07  1:07     ` Tom Rix
2023-03-07 11:42       ` Miguel Ojeda
2023-03-07 13:28         ` Tom Rix
2024-06-17 21:02 ` Kees Cook [this message]

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=202406171348.8D43518308@keescook \
    --to=kees@kernel.org \
    --cc=akpm@linux-foundation.org \
    --cc=christophe.leroy@csgroup.eu \
    --cc=hannes@cmpxchg.org \
    --cc=linux-hardening@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=masahiroy@kernel.org \
    --cc=mhiramat@kernel.org \
    --cc=ndesaulniers@google.com \
    --cc=ojeda@kernel.org \
    --cc=paulmck@kernel.org \
    --cc=qing.zhao@oracle.com \
    --cc=thunder.leizhen@huawei.com \
    --cc=trix@redhat.com \
    --cc=vbabka@suse.cz \
    /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.