2022-12-14 09:08:32

by Paulo Miguel Almeida

[permalink] [raw]
Subject: [PATCH] [next] pcmcia: synclink_cs: replace 1-element array with flex-array member

One-element arrays are deprecated, and we are replacing them with
flexible array members instead. So, replace one-element array with
flexible-array member in struct RXBUF and refactor the rest of the code
accordingly.

It's worth mentioning that doing a build before/after this patch
results in no binary output differences.

This helps with the ongoing efforts to tighten the FORTIFY_SOURCE
routines on memcpy() and help us make progress towards globally
enabling -fstrict-flex-arrays=3 [1].

Link: https://github.com/KSPP/linux/issues/79
Link: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101836 [1]

Signed-off-by: Paulo Miguel Almeida <[email protected]>
---
drivers/char/pcmcia/synclink_cs.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
index b2735be81ab2..1ab2d552f498 100644
--- a/drivers/char/pcmcia/synclink_cs.c
+++ b/drivers/char/pcmcia/synclink_cs.c
@@ -105,7 +105,7 @@ static MGSL_PARAMS default_params = {
typedef struct {
int count;
unsigned char status;
- char data[1];
+ char data[];
} RXBUF;

/* The queue of BH actions to be performed */
@@ -2611,7 +2611,8 @@ static int mgslpc_proc_show(struct seq_file *m, void *v)
static int rx_alloc_buffers(MGSLPC_INFO *info)
{
/* each buffer has header and data */
- info->rx_buf_size = sizeof(RXBUF) + info->max_frame_size;
+ info->rx_buf_size = max(offsetof(typeof(RXBUF), data) + 1, sizeof(RXBUF))
+ + info->max_frame_size;

/* calculate total allocation size for 8 buffers */
info->rx_buf_total_size = info->rx_buf_size * 8;
--
2.38.1


2022-12-14 09:14:26

by Paulo Miguel Almeida

[permalink] [raw]
Subject: [PATCH v2] [next] pcmcia: synclink_cs: replace 1-element array with flex-array member

One-element arrays are deprecated, and we are replacing them with
flexible array members instead. So, replace one-element array with
flexible-array member in struct RXBUF. No changes were required
within the source code because of the existing padding in RXBUF struct

It's worth mentioning that doing a build before/after this patch
results in no binary output differences.

This helps with the ongoing efforts to tighten the FORTIFY_SOURCE
routines on memcpy() and help us make progress towards globally
enabling -fstrict-flex-arrays=3 [1].

Link: https://github.com/KSPP/linux/issues/79
Link: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101836 [1]

Signed-off-by: Paulo Miguel Almeida <[email protected]>
---
Changelog:

- v2: removed changes to how the size of RXBUF was calculated. I
changed my mind after thinking about the existing padding in the
struct. Happy to discuss it if anyone sees it differently.

- v1: https://lore.kernel.org/lkml/[email protected]/
---
drivers/char/pcmcia/synclink_cs.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
index b2735be81ab2..0b03c6d13d59 100644
--- a/drivers/char/pcmcia/synclink_cs.c
+++ b/drivers/char/pcmcia/synclink_cs.c
@@ -105,7 +105,7 @@ static MGSL_PARAMS default_params = {
typedef struct {
int count;
unsigned char status;
- char data[1];
+ char data[];
} RXBUF;

/* The queue of BH actions to be performed */
--
2.38.1

2022-12-14 11:20:47

by Andy Shevchenko

[permalink] [raw]
Subject: Re: [PATCH v2] [next] pcmcia: synclink_cs: replace 1-element array with flex-array member

On Wed, Dec 14, 2022 at 10:58 AM Paulo Miguel Almeida
<[email protected]> wrote:
>
> One-element arrays are deprecated, and we are replacing them with
> flexible array members instead. So, replace one-element array with
> flexible-array member in struct RXBUF. No changes were required
> within the source code because of the existing padding in RXBUF struct

You shouldn't rely on padding. Make you change robust independently on
the padding. See also below.

> It's worth mentioning that doing a build before/after this patch
> results in no binary output differences.

This is interesting...

> This helps with the ongoing efforts to tighten the FORTIFY_SOURCE
> routines on memcpy() and help us make progress towards globally
> enabling -fstrict-flex-arrays=3 [1].
>
> Link: https://github.com/KSPP/linux/issues/79
> Link: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101836 [1]

>

The blank lines are not allowed in the tag block (in case you want to
have Link: to be recognized as a tag).

> Signed-off-by: Paulo Miguel Almeida <[email protected]>
> ---
> Changelog:
>
> - v2: removed changes to how the size of RXBUF was calculated. I
> changed my mind after thinking about the existing padding in the
> struct. Happy to discuss it if anyone sees it differently.

I feel worried about in particular this code:

/* each buffer has header and data */
info->rx_buf_size = sizeof(RXBUF) + info->max_frame_size;

which means that entire rx_alloc_buffers() should be revisited. Also
take into account the use of one or more macros from overflow.h for
memory allocation.

--
With Best Regards,
Andy Shevchenko

2022-12-14 20:36:14

by Kees Cook

[permalink] [raw]
Subject: Re: [PATCH] [next] pcmcia: synclink_cs: replace 1-element array with flex-array member

On Wed, Dec 14, 2022 at 09:42:00PM +1300, Paulo Miguel Almeida wrote:
> One-element arrays are deprecated, and we are replacing them with
> flexible array members instead. So, replace one-element array with
> flexible-array member in struct RXBUF and refactor the rest of the code
> accordingly.
>
> It's worth mentioning that doing a build before/after this patch
> results in no binary output differences.
>
> This helps with the ongoing efforts to tighten the FORTIFY_SOURCE
> routines on memcpy() and help us make progress towards globally
> enabling -fstrict-flex-arrays=3 [1].
>
> Link: https://github.com/KSPP/linux/issues/79
> Link: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101836 [1]
>
> Signed-off-by: Paulo Miguel Almeida <[email protected]>
> ---
> drivers/char/pcmcia/synclink_cs.c | 5 +++--
> 1 file changed, 3 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
> index b2735be81ab2..1ab2d552f498 100644
> --- a/drivers/char/pcmcia/synclink_cs.c
> +++ b/drivers/char/pcmcia/synclink_cs.c
> @@ -105,7 +105,7 @@ static MGSL_PARAMS default_params = {
> typedef struct {
> int count;
> unsigned char status;
> - char data[1];
> + char data[];
> } RXBUF;
>
> /* The queue of BH actions to be performed */
> @@ -2611,7 +2611,8 @@ static int mgslpc_proc_show(struct seq_file *m, void *v)
> static int rx_alloc_buffers(MGSLPC_INFO *info)
> {
> /* each buffer has header and data */
> - info->rx_buf_size = sizeof(RXBUF) + info->max_frame_size;
> + info->rx_buf_size = max(offsetof(typeof(RXBUF), data) + 1, sizeof(RXBUF))
> + + info->max_frame_size;

It seems like there is an existing size bug here, and likely should be
fixed separately?

i.e. this was already allocating 1 byte "too much". I'd expect this
first:

- info->rx_buf_size = sizeof(RXBUF) + info->max_frame_size;
+ info->rx_buf_size = sizeof(RXBUF) - 1 + info->max_frame_size;

and then the next patch:

- char data[1];
+ char data[];
...
- info->rx_buf_size = sizeof(RXBUF) - 1 + info->max_frame_size;
+ info->rx_buf_size = sizeof(RXBUF) + info->max_frame_size;

The above would induce a binary output change, and the second would not.

Though this results in what you had for the v2 patch (but I can't
believe it had no binary changes...)

--
Kees Cook

2022-12-14 20:37:47

by Paulo Miguel Almeida

[permalink] [raw]
Subject: Re: [PATCH] [next] pcmcia: synclink_cs: replace 1-element array with flex-array member

On Wed, Dec 14, 2022 at 11:29:37AM -0800, Kees Cook wrote:
> On Wed, Dec 14, 2022 at 09:42:00PM +1300, Paulo Miguel Almeida wrote:
> > One-element arrays are deprecated, and we are replacing them with
> > flexible array members instead. So, replace one-element array with
> > flexible-array member in struct RXBUF and refactor the rest of the code
> > accordingly.
> >
> > It's worth mentioning that doing a build before/after this patch
> > results in no binary output differences.
> >
> > This helps with the ongoing efforts to tighten the FORTIFY_SOURCE
> > routines on memcpy() and help us make progress towards globally
> > enabling -fstrict-flex-arrays=3 [1].
> >
> > Link: https://github.com/KSPP/linux/issues/79
> > Link: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101836 [1]
> >
> > Signed-off-by: Paulo Miguel Almeida <[email protected]>
> > ---
> > drivers/char/pcmcia/synclink_cs.c | 5 +++--
> > 1 file changed, 3 insertions(+), 2 deletions(-)
> >
> > diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
> > index b2735be81ab2..1ab2d552f498 100644
> > --- a/drivers/char/pcmcia/synclink_cs.c
> > +++ b/drivers/char/pcmcia/synclink_cs.c
> > @@ -105,7 +105,7 @@ static MGSL_PARAMS default_params = {
> > typedef struct {
> > int count;
> > unsigned char status;
> > - char data[1];
> > + char data[];
> > } RXBUF;
> >
> > /* The queue of BH actions to be performed */
> > @@ -2611,7 +2611,8 @@ static int mgslpc_proc_show(struct seq_file *m, void *v)
> > static int rx_alloc_buffers(MGSLPC_INFO *info)
> > {
> > /* each buffer has header and data */
> > - info->rx_buf_size = sizeof(RXBUF) + info->max_frame_size;
> > + info->rx_buf_size = max(offsetof(typeof(RXBUF), data) + 1, sizeof(RXBUF))
> > + + info->max_frame_size;
>
> It seems like there is an existing size bug here, and likely should be
> fixed separately?
>
> i.e. this was already allocating 1 byte "too much". I'd expect this
> first:
>
> - info->rx_buf_size = sizeof(RXBUF) + info->max_frame_size;
> + info->rx_buf_size = sizeof(RXBUF) - 1 + info->max_frame_size;
>
> and then the next patch:
>
> - char data[1];
> + char data[];
> ...
> - info->rx_buf_size = sizeof(RXBUF) - 1 + info->max_frame_size;
> + info->rx_buf_size = sizeof(RXBUF) + info->max_frame_size;
>
> The above would induce a binary output change, and the second would not.
>
> Though this results in what you had for the v2 patch (but I can't
> believe it had no binary changes...)
>
> --
> Kees Cook

Hi Kees, Hi Andy, Thanks for taking the time to review this patch.

As both of you had similar points, I will reply them here.

The reasons why it had no binary changes was because of the combination
of this 2 things:

1) Existing padding - so sizeof(RXBUF) returned 8 bytes in both cases.

pahole -C RXBUF gcc/before/drivers/char/pcmcia/synclink_cs.ko
typedef struct {
int count; /* 0 4 */
unsigned char status; /* 4 1 */
char data[1]; /* 5 1 */

/* size: 8, cachelines: 1, members: 3 */
/* padding: 2 */
/* last cacheline: 8 bytes */
} RXBUF;

pahole -C RXBUF gcc/after/drivers/char/pcmcia/synclink_cs.ko
typedef struct {
int count; /* 0 4 */
unsigned char status; /* 4 1 */
char data[]; /* 5 0 */

/* size: 8, cachelines: 1, members: 3 */
/* padding: 3 */
/* last cacheline: 8 bytes */
} RXBUF;

2) RXBUF (as implemented now) is just like a pair of lenses from which a
developer can have access to one of the circular buffers in MGSLPC_INFO
struct called 'rx_buf'.

2611 static int rx_alloc_buffers(MGSLPC_INFO *info)
2612 {
2613 /* each buffer has header and data */
2614 info->rx_buf_size = sizeof(RXBUF) + info->max_frame_size;
2615
2616 /* calculate total allocation size for 8 buffers */
2617 info->rx_buf_total_size = info->rx_buf_size * 8;
2618
2619 /* limit total allocated memory */
2620 if (info->rx_buf_total_size > 0x10000)
2621 info->rx_buf_total_size = 0x10000;
2622
2623 /* calculate number of buffers */
2624 info->rx_buf_count = info->rx_buf_total_size / info->rx_buf_size;
2625
2626 info->rx_buf = kmalloc(info->rx_buf_total_size, GFP_KERNEL);

To be honest, char data[_1_] in RXBUF was never required to be there.
The code base seems to make sure that it doesn't run past its limits by
keeping track of size buffer on MGSLPC_INFO->rx_buf_size (and sometimes
RXBUF->count)

(Addressing one point made by Andy about using of of the macros in
overflow.h)
struct_size(buf, data, 1) would return 9 bytes which could
potentially break the existing driver as it produces binary
changes.

Let me know your thoughts

thanks!

- Paulo A.

2022-12-14 20:42:24

by Kees Cook

[permalink] [raw]
Subject: Re: [PATCH] [next] pcmcia: synclink_cs: replace 1-element array with flex-array member

On Thu, Dec 15, 2022 at 09:09:46AM +1300, Paulo Miguel Almeida wrote:
> On Wed, Dec 14, 2022 at 11:29:37AM -0800, Kees Cook wrote:
> > On Wed, Dec 14, 2022 at 09:42:00PM +1300, Paulo Miguel Almeida wrote:
> > > One-element arrays are deprecated, and we are replacing them with
> > > flexible array members instead. So, replace one-element array with
> > > flexible-array member in struct RXBUF and refactor the rest of the code
> > > accordingly.
> > >
> > > It's worth mentioning that doing a build before/after this patch
> > > results in no binary output differences.
> > >
> > > This helps with the ongoing efforts to tighten the FORTIFY_SOURCE
> > > routines on memcpy() and help us make progress towards globally
> > > enabling -fstrict-flex-arrays=3 [1].
> > >
> > > Link: https://github.com/KSPP/linux/issues/79
> > > Link: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101836 [1]
> > >
> > > Signed-off-by: Paulo Miguel Almeida <[email protected]>
> > > ---
> > > drivers/char/pcmcia/synclink_cs.c | 5 +++--
> > > 1 file changed, 3 insertions(+), 2 deletions(-)
> > >
> > > diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
> > > index b2735be81ab2..1ab2d552f498 100644
> > > --- a/drivers/char/pcmcia/synclink_cs.c
> > > +++ b/drivers/char/pcmcia/synclink_cs.c
> > > @@ -105,7 +105,7 @@ static MGSL_PARAMS default_params = {
> > > typedef struct {
> > > int count;
> > > unsigned char status;
> > > - char data[1];
> > > + char data[];
> > > } RXBUF;
> > >
> > > /* The queue of BH actions to be performed */
> > > @@ -2611,7 +2611,8 @@ static int mgslpc_proc_show(struct seq_file *m, void *v)
> > > static int rx_alloc_buffers(MGSLPC_INFO *info)
> > > {
> > > /* each buffer has header and data */
> > > - info->rx_buf_size = sizeof(RXBUF) + info->max_frame_size;
> > > + info->rx_buf_size = max(offsetof(typeof(RXBUF), data) + 1, sizeof(RXBUF))
> > > + + info->max_frame_size;
> >
> > It seems like there is an existing size bug here, and likely should be
> > fixed separately?
> >
> > i.e. this was already allocating 1 byte "too much". I'd expect this
> > first:
> >
> > - info->rx_buf_size = sizeof(RXBUF) + info->max_frame_size;
> > + info->rx_buf_size = sizeof(RXBUF) - 1 + info->max_frame_size;
> >
> > and then the next patch:
> >
> > - char data[1];
> > + char data[];
> > ...
> > - info->rx_buf_size = sizeof(RXBUF) - 1 + info->max_frame_size;
> > + info->rx_buf_size = sizeof(RXBUF) + info->max_frame_size;
> >
> > The above would induce a binary output change, and the second would not.
> >
> > Though this results in what you had for the v2 patch (but I can't
> > believe it had no binary changes...)
> >
> > --
> > Kees Cook
>
> Hi Kees, Hi Andy, Thanks for taking the time to review this patch.
>
> As both of you had similar points, I will reply them here.
>
> The reasons why it had no binary changes was because of the combination
> of this 2 things:
>
> 1) Existing padding - so sizeof(RXBUF) returned 8 bytes in both cases.
>
> pahole -C RXBUF gcc/before/drivers/char/pcmcia/synclink_cs.ko
> typedef struct {
> int count; /* 0 4 */
> unsigned char status; /* 4 1 */
> char data[1]; /* 5 1 */
>
> /* size: 8, cachelines: 1, members: 3 */
> /* padding: 2 */
> /* last cacheline: 8 bytes */
> } RXBUF;
>
> pahole -C RXBUF gcc/after/drivers/char/pcmcia/synclink_cs.ko
> typedef struct {
> int count; /* 0 4 */
> unsigned char status; /* 4 1 */
> char data[]; /* 5 0 */
>
> /* size: 8, cachelines: 1, members: 3 */
> /* padding: 3 */
> /* last cacheline: 8 bytes */
> } RXBUF;

Ah-ha, now I see.

>
> 2) RXBUF (as implemented now) is just like a pair of lenses from which a
> developer can have access to one of the circular buffers in MGSLPC_INFO
> struct called 'rx_buf'.
>
> 2611 static int rx_alloc_buffers(MGSLPC_INFO *info)
> 2612 {
> 2613 /* each buffer has header and data */
> 2614 info->rx_buf_size = sizeof(RXBUF) + info->max_frame_size;
> 2615
> 2616 /* calculate total allocation size for 8 buffers */
> 2617 info->rx_buf_total_size = info->rx_buf_size * 8;
> 2618
> 2619 /* limit total allocated memory */
> 2620 if (info->rx_buf_total_size > 0x10000)
> 2621 info->rx_buf_total_size = 0x10000;
> 2622
> 2623 /* calculate number of buffers */
> 2624 info->rx_buf_count = info->rx_buf_total_size / info->rx_buf_size;
> 2625
> 2626 info->rx_buf = kmalloc(info->rx_buf_total_size, GFP_KERNEL);
>
> To be honest, char data[_1_] in RXBUF was never required to be there.
> The code base seems to make sure that it doesn't run past its limits by
> keeping track of size buffer on MGSLPC_INFO->rx_buf_size (and sometimes
> RXBUF->count)
>
> (Addressing one point made by Andy about using of of the macros in
> overflow.h)
> struct_size(buf, data, 1) would return 9 bytes which could
> potentially break the existing driver as it produces binary
> changes.

Yeah, I think your v2 is fine. Perhaps explicitly repeat the notes about
struct size padding in a v3 commit log?

--
Kees Cook

2022-12-14 20:53:29

by Paulo Miguel Almeida

[permalink] [raw]
Subject: Re: [PATCH] [next] pcmcia: synclink_cs: replace 1-element array with flex-array member

On Wed, Dec 14, 2022 at 11:29:37AM -0800, Kees Cook wrote:
> On Wed, Dec 14, 2022 at 09:42:00PM +1300, Paulo Miguel Almeida wrote:
> > One-element arrays are deprecated, and we are replacing them with
> > flexible array members instead. So, replace one-element array with
> > flexible-array member in struct RXBUF and refactor the rest of the code
> > accordingly.
> >
> > It's worth mentioning that doing a build before/after this patch
> > results in no binary output differences.
> >
> > This helps with the ongoing efforts to tighten the FORTIFY_SOURCE
> > routines on memcpy() and help us make progress towards globally
> > enabling -fstrict-flex-arrays=3 [1].
> >
> > Link: https://github.com/KSPP/linux/issues/79
> > Link: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101836 [1]
> >
> > Signed-off-by: Paulo Miguel Almeida <[email protected]>
> > ---
> > drivers/char/pcmcia/synclink_cs.c | 5 +++--
> > 1 file changed, 3 insertions(+), 2 deletions(-)
> >
> > diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
> > index b2735be81ab2..1ab2d552f498 100644
> > --- a/drivers/char/pcmcia/synclink_cs.c
> > +++ b/drivers/char/pcmcia/synclink_cs.c
> > @@ -105,7 +105,7 @@ static MGSL_PARAMS default_params = {
> > typedef struct {
> > int count;
> > unsigned char status;
> > - char data[1];
> > + char data[];
> > } RXBUF;
> >
> > /* The queue of BH actions to be performed */
> > @@ -2611,7 +2611,8 @@ static int mgslpc_proc_show(struct seq_file *m, void *v)
> > static int rx_alloc_buffers(MGSLPC_INFO *info)
> > {
> > /* each buffer has header and data */
> > - info->rx_buf_size = sizeof(RXBUF) + info->max_frame_size;
> > + info->rx_buf_size = max(offsetof(typeof(RXBUF), data) + 1, sizeof(RXBUF))
> > + + info->max_frame_size;
>
> It seems like there is an existing size bug here, and likely should be
> fixed separately?
>
> i.e. this was already allocating 1 byte "too much". I'd expect this
> first:
>
> - info->rx_buf_size = sizeof(RXBUF) + info->max_frame_size;
> + info->rx_buf_size = sizeof(RXBUF) - 1 + info->max_frame_size;
>
> and then the next patch:
>
> - char data[1];
> + char data[];
> ...
> - info->rx_buf_size = sizeof(RXBUF) - 1 + info->max_frame_size;
> + info->rx_buf_size = sizeof(RXBUF) + info->max_frame_size;
>
> The above would induce a binary output change, and the second would not.
>
> Though this results in what you had for the v2 patch (but I can't
> believe it had no binary changes...)
>
> --
> Kees Cook

Just realised that you made a comment on PATCH v1 and Andy made a
comment on PATCH v2. Please conside my answer for PATCH v2 as I have
abandoned the v1. Apologies for the confusion.

thanks!

- Paulo A.

2022-12-14 20:54:33

by Paulo Miguel Almeida

[permalink] [raw]
Subject: Re: [PATCH v2] [next] pcmcia: synclink_cs: replace 1-element array with flex-array member

On Wed, Dec 14, 2022 at 12:43:48PM +0200, Andy Shevchenko wrote:
> On Wed, Dec 14, 2022 at 10:58 AM Paulo Miguel Almeida
> <[email protected]> wrote:
> >
> > One-element arrays are deprecated, and we are replacing them with
> > flexible array members instead. So, replace one-element array with
> > flexible-array member in struct RXBUF. No changes were required
> > within the source code because of the existing padding in RXBUF struct
>
> You shouldn't rely on padding. Make you change robust independently on
> the padding. See also below.
>
> > It's worth mentioning that doing a build before/after this patch
> > results in no binary output differences.
>
> This is interesting...
>
> > This helps with the ongoing efforts to tighten the FORTIFY_SOURCE
> > routines on memcpy() and help us make progress towards globally
> > enabling -fstrict-flex-arrays=3 [1].
> >
> > Link: https://github.com/KSPP/linux/issues/79
> > Link: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101836 [1]
>
> >
>
> The blank lines are not allowed in the tag block (in case you want to
> have Link: to be recognized as a tag).
>
> > Signed-off-by: Paulo Miguel Almeida <[email protected]>
> > ---
> > Changelog:
> >
> > - v2: removed changes to how the size of RXBUF was calculated. I
> > changed my mind after thinking about the existing padding in the
> > struct. Happy to discuss it if anyone sees it differently.
>
> I feel worried about in particular this code:
>
> /* each buffer has header and data */
> info->rx_buf_size = sizeof(RXBUF) + info->max_frame_size;
>
> which means that entire rx_alloc_buffers() should be revisited. Also
> take into account the use of one or more macros from overflow.h for
> memory allocation.
>
> --
> With Best Regards,
> Andy Shevchenko

Hi Kees, Hi Andy, Thanks for taking the time to review this patch.

As both of you had similar points, I will reply them here.

The reasons why it had no binary changes was because of the combination
of this 2 things:

1) Existing padding - so sizeof(RXBUF) returned 8 bytes in both cases.

pahole -C RXBUF gcc/before/drivers/char/pcmcia/synclink_cs.ko
typedef struct {
int count; /* 0 4 */
unsigned char status; /* 4 1 */
char data[1]; /* 5 1 */

/* size: 8, cachelines: 1, members: 3 */
/* padding: 2 */
/* last cacheline: 8 bytes */
} RXBUF;

pahole -C RXBUF gcc/after/drivers/char/pcmcia/synclink_cs.ko
typedef struct {
int count; /* 0 4 */
unsigned char status; /* 4 1 */
char data[]; /* 5 0 */

/* size: 8, cachelines: 1, members: 3 */
/* padding: 3 */
/* last cacheline: 8 bytes */
} RXBUF;

2) RXBUF (as implemented now) is just like a pair of lenses from which a
developer can have access to one of the circular buffers in MGSLPC_INFO
struct called 'rx_buf'.

2611 static int rx_alloc_buffers(MGSLPC_INFO *info)
2612 {
2613 /* each buffer has header and data */
2614 info->rx_buf_size = sizeof(RXBUF) + info->max_frame_size;
2615
2616 /* calculate total allocation size for 8 buffers */
2617 info->rx_buf_total_size = info->rx_buf_size * 8;
2618
2619 /* limit total allocated memory */
2620 if (info->rx_buf_total_size > 0x10000)
2621 info->rx_buf_total_size = 0x10000;
2622
2623 /* calculate number of buffers */
2624 info->rx_buf_count = info->rx_buf_total_size / info->rx_buf_size;
2625
2626 info->rx_buf = kmalloc(info->rx_buf_total_size, GFP_KERNEL);

To be honest, char data[_1_] in RXBUF was never required to be there.
The code base seems to make sure that it doesn't run past its limits by
keeping track of size buffer on MGSLPC_INFO->rx_buf_size (and sometimes
RXBUF->count)

(Addressing one point made by Andy about using of of the macros in
overflow.h)
struct_size(buf, data, 1) would return 9 bytes which could
potentially break the existing driver as it produces binary
changes.

Let me know your thoughts

thanks!

- Paulo A.

2022-12-14 20:56:33

by Andy Shevchenko

[permalink] [raw]
Subject: Re: [PATCH] [next] pcmcia: synclink_cs: replace 1-element array with flex-array member

On Wed, Dec 14, 2022 at 10:09 PM Paulo Miguel Almeida
<[email protected]> wrote:
> On Wed, Dec 14, 2022 at 11:29:37AM -0800, Kees Cook wrote:
> > On Wed, Dec 14, 2022 at 09:42:00PM +1300, Paulo Miguel Almeida wrote:
> > > One-element arrays are deprecated, and we are replacing them with
> > > flexible array members instead. So, replace one-element array with
> > > flexible-array member in struct RXBUF and refactor the rest of the code
> > > accordingly.
> > >
> > > It's worth mentioning that doing a build before/after this patch
> > > results in no binary output differences.
> > >
> > > This helps with the ongoing efforts to tighten the FORTIFY_SOURCE
> > > routines on memcpy() and help us make progress towards globally
> > > enabling -fstrict-flex-arrays=3 [1].

...

> > > typedef struct {
> > > int count;
> > > unsigned char status;
> > > - char data[1];
> > > + char data[];
> > > } RXBUF;

...

> As both of you had similar points, I will reply them here.
>
> The reasons why it had no binary changes was because of the combination
> of this 2 things:
>
> 1) Existing padding - so sizeof(RXBUF) returned 8 bytes in both cases.
>
> pahole -C RXBUF gcc/before/drivers/char/pcmcia/synclink_cs.ko
> typedef struct {
> int count; /* 0 4 */
> unsigned char status; /* 4 1 */
> char data[1]; /* 5 1 */
>
> /* size: 8, cachelines: 1, members: 3 */
> /* padding: 2 */
> /* last cacheline: 8 bytes */
> } RXBUF;
>
> pahole -C RXBUF gcc/after/drivers/char/pcmcia/synclink_cs.ko
> typedef struct {
> int count; /* 0 4 */
> unsigned char status; /* 4 1 */
> char data[]; /* 5 0 */
>
> /* size: 8, cachelines: 1, members: 3 */
> /* padding: 3 */
> /* last cacheline: 8 bytes */
> } RXBUF;

Yes, and Try to make it work with __packed. As I said, the problem is
that the code is relying on something which is architecture dependent
strictly speaking. And hence I disagree with Kees that v2 is okay to
go.

> 2) RXBUF (as implemented now) is just like a pair of lenses from which a
> developer can have access to one of the circular buffers in MGSLPC_INFO
> struct called 'rx_buf'.

> 2611 static int rx_alloc_buffers(MGSLPC_INFO *info)
> 2612 {
> 2613 /* each buffer has header and data */
> 2614 info->rx_buf_size = sizeof(RXBUF) + info->max_frame_size;
> 2615
> 2616 /* calculate total allocation size for 8 buffers */
> 2617 info->rx_buf_total_size = info->rx_buf_size * 8;
> 2618
> 2619 /* limit total allocated memory */
> 2620 if (info->rx_buf_total_size > 0x10000)
> 2621 info->rx_buf_total_size = 0x10000;
> 2622
> 2623 /* calculate number of buffers */
> 2624 info->rx_buf_count = info->rx_buf_total_size / info->rx_buf_size;
> 2625
> 2626 info->rx_buf = kmalloc(info->rx_buf_total_size, GFP_KERNEL);
>
> To be honest, char data[_1_] in RXBUF was never required to be there.
> The code base seems to make sure that it doesn't run past its limits by
> keeping track of size buffer on MGSLPC_INFO->rx_buf_size (and sometimes
> RXBUF->count)
>
> (Addressing one point made by Andy about using of of the macros in
> overflow.h)
> struct_size(buf, data, 1) would return 9 bytes which could
> potentially break the existing driver as it produces binary
> changes.

You got it incorrectly. I believe you should use something different than 1.
In previous lines in the function it multiplies sizeof + max_frame_size by 8.

The full change should be something like

check_add(sizeof(), max_frame_size)
kcalloc(8, size)

Think about it.

> Let me know your thoughts

--
With Best Regards,
Andy Shevchenko

2022-12-14 22:08:50

by Kees Cook

[permalink] [raw]
Subject: Re: [PATCH] [next] pcmcia: synclink_cs: replace 1-element array with flex-array member

On Wed, Dec 14, 2022 at 10:39:52PM +0200, Andy Shevchenko wrote:
> Yes, and Try to make it work with __packed. As I said, the problem is
> that the code is relying on something which is architecture dependent
> strictly speaking. And hence I disagree with Kees that v2 is okay to
> go.

I meant that v2 is functionally identical to the existing code.

> The full change should be something like
>
> check_add(sizeof(), max_frame_size)
> kcalloc(8, size)

Right -- this would fix the existing mistakes in size calculation (and
is certainly better).

--
Kees Cook

2022-12-14 22:40:00

by Andy Shevchenko

[permalink] [raw]
Subject: Re: [PATCH] [next] pcmcia: synclink_cs: replace 1-element array with flex-array member

On Wed, Dec 14, 2022 at 11:49 PM Kees Cook <[email protected]> wrote:
> On Wed, Dec 14, 2022 at 10:39:52PM +0200, Andy Shevchenko wrote:
> > Yes, and Try to make it work with __packed. As I said, the problem is
> > that the code is relying on something which is architecture dependent
> > strictly speaking. And hence I disagree with Kees that v2 is okay to
> > go.
>
> I meant that v2 is functionally identical to the existing code.

Ah, sorry for misunderstanding.

> > The full change should be something like
> >
> > check_add(sizeof(), max_frame_size)
> > kcalloc(8, size)
>
> Right -- this would fix the existing mistakes in size calculation (and
> is certainly better).

Glad to hear that we are on the same page.

--
With Best Regards,
Andy Shevchenko

2022-12-15 04:38:49

by Paulo Miguel Almeida

[permalink] [raw]
Subject: Re: [PATCH] [next] pcmcia: synclink_cs: replace 1-element array with flex-array member

On Thu, Dec 15, 2022 at 12:06:46AM +0200, Andy Shevchenko wrote:
> On Wed, Dec 14, 2022 at 11:49 PM Kees Cook <[email protected]> wrote:
> > On Wed, Dec 14, 2022 at 10:39:52PM +0200, Andy Shevchenko wrote:
> > > Yes, and Try to make it work with __packed. As I said, the problem is
> > > that the code is relying on something which is architecture dependent
> > > strictly speaking. And hence I disagree with Kees that v2 is okay to
> > > go.
> >
> > I meant that v2 is functionally identical to the existing code.
>
> Ah, sorry for misunderstanding.
>

I agree with using __packed attribute to remove the extra padding (and
for the reasons you mentioned before). That would reduce the sizeof(RXBUF)
from 8 to 5 (which is good) but that is still 1 byte "too much".

Piggying back on a suggestion Kees gave before:

- info->rx_buf_size = sizeof(RXBUF) + info->max_frame_size;
+ info->rx_buf_size = sizeof(RXBUF) - 1 + info->max_frame_size;

That way RXBUF->data will point to the first byte of the frame_size
(MGSLPC_INFO->max_frame_size) which is what is actually needed.

> > > The full change should be something like
> > >
> > > check_add(sizeof(), max_frame_size)
> > > kcalloc(8, size)
> >
> > Right -- this would fix the existing mistakes in size calculation (and
> > is certainly better).
>
> Glad to hear that we are on the same page.
>

That makes sense to me.

thanks!

- Paulo A.

2022-12-15 06:40:48

by Paulo Miguel Almeida

[permalink] [raw]
Subject: Re: [PATCH] [next] pcmcia: synclink_cs: replace 1-element array with flex-array member

On Thu, Dec 15, 2022 at 05:29:15PM +1300, Paulo Miguel Almeida wrote:
> On Thu, Dec 15, 2022 at 12:06:46AM +0200, Andy Shevchenko wrote:
> > On Wed, Dec 14, 2022 at 11:49 PM Kees Cook <[email protected]> wrote:
> > > On Wed, Dec 14, 2022 at 10:39:52PM +0200, Andy Shevchenko wrote:
> > > > Yes, and Try to make it work with __packed. As I said, the problem is
> > > > that the code is relying on something which is architecture dependent
> > > > strictly speaking. And hence I disagree with Kees that v2 is okay to
> > > > go.
> > >
> > > I meant that v2 is functionally identical to the existing code.
> >
> > Ah, sorry for misunderstanding.
> >
>
> I agree with using __packed attribute to remove the extra padding (and
> for the reasons you mentioned before). That would reduce the sizeof(RXBUF)
> from 8 to 5 (which is good) but that is still 1 byte "too much".
>
> Piggying back on a suggestion Kees gave before:
>
> - info->rx_buf_size = sizeof(RXBUF) + info->max_frame_size;
> + info->rx_buf_size = sizeof(RXBUF) - 1 + info->max_frame_size;
>
> That way RXBUF->data will point to the first byte of the frame_size
> (MGSLPC_INFO->max_frame_size) which is what is actually needed.
>

I chose my words poorly here... sorry my brain is a bit fried today.

Let me rephrase that last sentence. After that change (or similar
change), RXBUF->data will point to the first byte of the buffer
allocated during the initialisation process. (which is
limited/controlled by the size of MGSLPC_INFO->max_frame_size)...
so no 'extra byte/padding' will be there.

- Paulo A.

> > > > The full change should be something like
> > > >
> > > > check_add(sizeof(), max_frame_size)
> > > > kcalloc(8, size)
> > >
> > > Right -- this would fix the existing mistakes in size calculation (and
> > > is certainly better).
> >
> > Glad to hear that we are on the same page.
> >
>
> That makes sense to me.
>
> thanks!
>
> - Paulo A.

2022-12-15 09:02:28

by Andy Shevchenko

[permalink] [raw]
Subject: Re: [PATCH] [next] pcmcia: synclink_cs: replace 1-element array with flex-array member

On Thu, Dec 15, 2022 at 6:29 AM Paulo Miguel Almeida
<[email protected]> wrote:
> On Thu, Dec 15, 2022 at 12:06:46AM +0200, Andy Shevchenko wrote:
> > On Wed, Dec 14, 2022 at 11:49 PM Kees Cook <[email protected]> wrote:
> > > On Wed, Dec 14, 2022 at 10:39:52PM +0200, Andy Shevchenko wrote:

...

> > > > Yes, and Try to make it work with __packed. As I said, the problem is
> > > > that the code is relying on something which is architecture dependent
> > > > strictly speaking. And hence I disagree with Kees that v2 is okay to
> > > > go.
> > >
> > > I meant that v2 is functionally identical to the existing code.
> >
> > Ah, sorry for misunderstanding.
>
> I agree with using __packed attribute to remove the extra padding (and
> for the reasons you mentioned before). That would reduce the sizeof(RXBUF)
> from 8 to 5 (which is good) but that is still 1 byte "too much".

What I meant with the above is that the code has to work properly with
or without __packed. It's just to show you that this code has flaws if
it relies on the padding.

--
With Best Regards,
Andy Shevchenko

2022-12-15 21:33:51

by Paulo Miguel Almeida

[permalink] [raw]
Subject: Re: [PATCH] [next] pcmcia: synclink_cs: replace 1-element array with flex-array member

On Thu, Dec 15, 2022 at 10:57:57AM +0200, Andy Shevchenko wrote:
> On Thu, Dec 15, 2022 at 6:29 AM Paulo Miguel Almeida
> <[email protected]> wrote:
> > On Thu, Dec 15, 2022 at 12:06:46AM +0200, Andy Shevchenko wrote:
> > > On Wed, Dec 14, 2022 at 11:49 PM Kees Cook <[email protected]> wrote:
> > > > On Wed, Dec 14, 2022 at 10:39:52PM +0200, Andy Shevchenko wrote:
>
> ...
>
> > > > > Yes, and Try to make it work with __packed. As I said, the problem is
> > > > > that the code is relying on something which is architecture dependent
> > > > > strictly speaking. And hence I disagree with Kees that v2 is okay to
> > > > > go.
> > > >
> > > > I meant that v2 is functionally identical to the existing code.
> > >
> > > Ah, sorry for misunderstanding.
> >
> > I agree with using __packed attribute to remove the extra padding (and
> > for the reasons you mentioned before). That would reduce the sizeof(RXBUF)
> > from 8 to 5 (which is good) but that is still 1 byte "too much".
>
> What I meant with the above is that the code has to work properly with
> or without __packed. It's just to show you that this code has flaws if
> it relies on the padding.
>

Right - that would work just as well. I will work on v3 with the
suggestions given by you (sizing calculation amendments using overflow.h
macros) and kees (adding the notes regarding the padding) then.

- Paulo A.

2022-12-17 00:03:50

by Paulo Miguel Almeida

[permalink] [raw]
Subject: [PATCH v3] [next] pcmcia: synclink_cs: replace 1-element array with flex-array member

One-element arrays are deprecated, and we are replacing them with
flexible array members instead. So, replace one-element array with
flexible-array member in struct RXBUF and refactor the rest of the code
accordingly. While at it, fix an edge case which could cause
rx_buf_count to be 0 when max_frame_size was set to the maximum
allowed value (65535).

It's worth mentioning that struct RXBUF was allocating 1 byte "too much"
for what is required (ignoring bytes added by padding).

This helps with the ongoing efforts to tighten the FORTIFY_SOURCE
routines on memcpy() and help us make progress towards globally
enabling -fstrict-flex-arrays=3 [1].

Link: https://github.com/KSPP/linux/issues/79
Link: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101836 [1]
Signed-off-by: Paulo Miguel Almeida <[email protected]>
---
Changelog:

- v3:
fix size calculation mistakes using overflow.h macros: (Req: Andy
Shevchenko, Kees Cook)
add notes struct RXBUF size (Kees Cook)

- v2: removed changes to how the size of RXBUF was calculated. I
changed my mind after thinking about the existing padding in the
struct. Happy to discuss it if anyone sees it differently.

- v1: https://lore.kernel.org/lkml/[email protected]/
---
drivers/char/pcmcia/synclink_cs.c | 33 +++++++++++++++++++------------
1 file changed, 20 insertions(+), 13 deletions(-)

diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
index b2735be81ab2..eee6772a0978 100644
--- a/drivers/char/pcmcia/synclink_cs.c
+++ b/drivers/char/pcmcia/synclink_cs.c
@@ -105,7 +105,7 @@ static MGSL_PARAMS default_params = {
typedef struct {
int count;
unsigned char status;
- char data[1];
+ char data[];
} RXBUF;

/* The queue of BH actions to be performed */
@@ -229,12 +229,18 @@ typedef struct _mgslpc_info {
} MGSLPC_INFO;

#define MGSLPC_MAGIC 0x5402
+#define MGSLPC_MAX_FRAME_SIZE 65535
+#define MGSLPC_MIN_FRAME_SIZE 4096

/*
* The size of the serial xmit buffer is 1 page, or 4096 bytes
*/
#define TXBUFSIZE 4096

+/*
+ * RXBUF accommodates at least 1 buffer (header+data) of MGSLPC_MAX_FRAME_SIZE
+ */
+#define RXBUF_MAX_SIZE (sizeof(RXBUF) + MGSLPC_MAX_FRAME_SIZE)

#define CHA 0x00 /* channel A offset */
#define CHB 0x40 /* channel B offset */
@@ -529,7 +535,7 @@ static int mgslpc_probe(struct pcmcia_device *link)
tty_port_init(&info->port);
info->port.ops = &mgslpc_port_ops;
INIT_WORK(&info->task, bh_handler);
- info->max_frame_size = 4096;
+ info->max_frame_size = MGSLPC_MIN_FRAME_SIZE;
init_waitqueue_head(&info->status_event_wait_q);
init_waitqueue_head(&info->event_wait_q);
spin_lock_init(&info->lock);
@@ -2611,19 +2617,20 @@ static int mgslpc_proc_show(struct seq_file *m, void *v)
static int rx_alloc_buffers(MGSLPC_INFO *info)
{
/* each buffer has header and data */
- info->rx_buf_size = sizeof(RXBUF) + info->max_frame_size;
+ if (check_add_overflow(sizeof(RXBUF), info->max_frame_size, &info->rx_buf_size))
+ return -EINVAL;

- /* calculate total allocation size for 8 buffers */
- info->rx_buf_total_size = info->rx_buf_size * 8;
+ /* try to alloc as many buffers that can fit within RXBUF_MAX_SIZE (up to 8) */
+ if (check_mul_overflow(info->rx_buf_size, 8, &info->rx_buf_total_size))
+ return -EINVAL;

- /* limit total allocated memory */
- if (info->rx_buf_total_size > 0x10000)
- info->rx_buf_total_size = 0x10000;
+ if (info->rx_buf_total_size > RXBUF_MAX_SIZE)
+ info->rx_buf_total_size = RXBUF_MAX_SIZE;

/* calculate number of buffers */
info->rx_buf_count = info->rx_buf_total_size / info->rx_buf_size;

- info->rx_buf = kmalloc(info->rx_buf_total_size, GFP_KERNEL);
+ info->rx_buf = kcalloc(info->rx_buf_count, info->rx_buf_size, GFP_KERNEL);
if (info->rx_buf == NULL)
return -ENOMEM;

@@ -2695,10 +2702,10 @@ static int mgslpc_add_device(MGSLPC_INFO *info)
current_dev->next_device = info;
}

- if (info->max_frame_size < 4096)
- info->max_frame_size = 4096;
- else if (info->max_frame_size > 65535)
- info->max_frame_size = 65535;
+ if (info->max_frame_size < MGSLPC_MIN_FRAME_SIZE)
+ info->max_frame_size = MGSLPC_MIN_FRAME_SIZE;
+ else if (info->max_frame_size > MGSLPC_MAX_FRAME_SIZE)
+ info->max_frame_size = MGSLPC_MAX_FRAME_SIZE;

printk("SyncLink PC Card %s:IO=%04X IRQ=%d\n",
info->device_name, info->io_base, info->irq_level);
--
2.38.1

2022-12-17 12:00:05

by Andy Shevchenko

[permalink] [raw]
Subject: Re: [PATCH v3] [next] pcmcia: synclink_cs: replace 1-element array with flex-array member

On Sat, Dec 17, 2022 at 12:59 AM Paulo Miguel Almeida
<[email protected]> wrote:
>
> One-element arrays are deprecated, and we are replacing them with
> flexible array members instead. So, replace one-element array with
> flexible-array member in struct RXBUF and refactor the rest of the code
> accordingly. While at it, fix an edge case which could cause
> rx_buf_count to be 0 when max_frame_size was set to the maximum
> allowed value (65535).
>
> It's worth mentioning that struct RXBUF was allocating 1 byte "too much"
> for what is required (ignoring bytes added by padding).
>
> This helps with the ongoing efforts to tighten the FORTIFY_SOURCE
> routines on memcpy() and help us make progress towards globally
> enabling -fstrict-flex-arrays=3 [1].

...

> static int rx_alloc_buffers(MGSLPC_INFO *info)
> {
> /* each buffer has header and data */
> - info->rx_buf_size = sizeof(RXBUF) + info->max_frame_size;
> + if (check_add_overflow(sizeof(RXBUF), info->max_frame_size, &info->rx_buf_size))
> + return -EINVAL;
>
> - /* calculate total allocation size for 8 buffers */
> - info->rx_buf_total_size = info->rx_buf_size * 8;

> + /* try to alloc as many buffers that can fit within RXBUF_MAX_SIZE (up to 8) */
> + if (check_mul_overflow(info->rx_buf_size, 8, &info->rx_buf_total_size))
> + return -EINVAL;

This check is implied by kcalloc(). But to make it effective we
probably need to get a count first.

> - /* limit total allocated memory */
> - if (info->rx_buf_total_size > 0x10000)
> - info->rx_buf_total_size = 0x10000;
> + if (info->rx_buf_total_size > RXBUF_MAX_SIZE)
> + info->rx_buf_total_size = RXBUF_MAX_SIZE;

If max_frame_size > 8192 - sizeof(RXBUF), we bump into this condition...

> /* calculate number of buffers */
> info->rx_buf_count = info->rx_buf_total_size / info->rx_buf_size;

...which means that rx_buf_count < 8...
(and if max_frame_size > RXBUF_MAX_SIZE - sizeof(RXBUF), count becomes
0, I don't know if below clamp_val() is the only place to guarantee
that)

> - info->rx_buf = kmalloc(info->rx_buf_total_size, GFP_KERNEL);
> + info->rx_buf = kcalloc(info->rx_buf_count, info->rx_buf_size, GFP_KERNEL);

...hence rx_buf size will be less than rx_buf_total_size.

That is probably not an issue per se, but I'm wondering if the
(bigger) value of rx_buf_total_size is the problem further in the
code.

> if (info->rx_buf == NULL)
> return -ENOMEM;

Maybe something like

static int rx_alloc_buffers(MGSLPC_INFO *info)
{
/* Prevent count from being 0 */
if (->max_frame_size > MAX_FRAME_SIZE)
return -EINVAL;
...
count = ...;
...
rx_total_size = ...
rx_buf = kcalloc(...);

Then you don't need to check overflow with check_add_overflow() and
check_mul_overflow() will be inside the kcalloc.

...

> - if (info->max_frame_size < 4096)
> - info->max_frame_size = 4096;
> - else if (info->max_frame_size > 65535)
> - info->max_frame_size = 65535;
> + if (info->max_frame_size < MGSLPC_MIN_FRAME_SIZE)
> + info->max_frame_size = MGSLPC_MIN_FRAME_SIZE;
> + else if (info->max_frame_size > MGSLPC_MAX_FRAME_SIZE)
> + info->max_frame_size = MGSLPC_MAX_FRAME_SIZE;

You can use clamp_val() macro here.

--
With Best Regards,
Andy Shevchenko

2022-12-17 20:37:59

by Paulo Miguel Almeida

[permalink] [raw]
Subject: Re: [PATCH v3] [next] pcmcia: synclink_cs: replace 1-element array with flex-array member

On Sat, Dec 17, 2022 at 01:43:40PM +0200, Andy Shevchenko wrote:
> On Sat, Dec 17, 2022 at 12:59 AM Paulo Miguel Almeida
> <[email protected]> wrote:
> >
> > One-element arrays are deprecated, and we are replacing them with
> > flexible array members instead. So, replace one-element array with
> > flexible-array member in struct RXBUF and refactor the rest of the code
> > accordingly. While at it, fix an edge case which could cause
> > rx_buf_count to be 0 when max_frame_size was set to the maximum
> > allowed value (65535).
> >
> > It's worth mentioning that struct RXBUF was allocating 1 byte "too much"
> > for what is required (ignoring bytes added by padding).
> >
> > This helps with the ongoing efforts to tighten the FORTIFY_SOURCE
> > routines on memcpy() and help us make progress towards globally
> > enabling -fstrict-flex-arrays=3 [1].
>
> ...
>
> > static int rx_alloc_buffers(MGSLPC_INFO *info)
> > {
> > /* each buffer has header and data */
> > - info->rx_buf_size = sizeof(RXBUF) + info->max_frame_size;
> > + if (check_add_overflow(sizeof(RXBUF), info->max_frame_size, &info->rx_buf_size))
> > + return -EINVAL;
> >
> > - /* calculate total allocation size for 8 buffers */
> > - info->rx_buf_total_size = info->rx_buf_size * 8;
>
> > + /* try to alloc as many buffers that can fit within RXBUF_MAX_SIZE (up to 8) */
> > + if (check_mul_overflow(info->rx_buf_size, 8, &info->rx_buf_total_size))
> > + return -EINVAL;
>
> This check is implied by kcalloc(). But to make it effective we
> probably need to get a count first.
>
> > - /* limit total allocated memory */
> > - if (info->rx_buf_total_size > 0x10000)
> > - info->rx_buf_total_size = 0x10000;
> > + if (info->rx_buf_total_size > RXBUF_MAX_SIZE)
> > + info->rx_buf_total_size = RXBUF_MAX_SIZE;
>
> If max_frame_size > 8192 - sizeof(RXBUF), we bump into this condition...
>
> > /* calculate number of buffers */
> > info->rx_buf_count = info->rx_buf_total_size / info->rx_buf_size;
>
> ...which means that rx_buf_count < 8...

that's correct. My reading of what the original author intended is the
following:

- rx_buf_count can be < 8 if max_frame_size needs to be > 8192 so that
userspace tools don't need to collate the different packets together
then again, SyncLink_CS supports a variety of protocols.

- the more circular buffers, the better, but it looks perfectly acceptable
to have 1 big rx_buf (max_frame_size possible) if the communication is
orchestrated nicely (which part sends what and when) especially for
RS-232-based communications.


> (and if max_frame_size > RXBUF_MAX_SIZE - sizeof(RXBUF), count becomes
> 0, I don't know if below clamp_val() is the only place to guarantee
> that)
>

I can confirm that the clamp_val() below is the only place that
guarantees the max_frame_size isn't greater than RXBUF_MAX_SIZE. That
happens at the device probing stage:

( mgslpc_probe > mgslpc_add_device > clamp_val-like routine )

As max_frame_size can only be set as a module parameter and no other way
is exposed to userspace to tweak that afterwards, my 2 cents is that
clamp_val() routine should be fine as rx_buf_count will always be > 0
after this fix.

> > - info->rx_buf = kmalloc(info->rx_buf_total_size, GFP_KERNEL);
> > + info->rx_buf = kcalloc(info->rx_buf_count, info->rx_buf_size, GFP_KERNEL);
>
> ...hence rx_buf size will be less than rx_buf_total_size.
>
> That is probably not an issue per se, but I'm wondering if the
> (bigger) value of rx_buf_total_size is the problem further in the
> code.
>

rx_buf_total_size isn't used outside of this function so it
could be a local variable IMO.. so I would say that this wouldn't be a
problem.

I had noticed that rx_buf_total_size could be moved into a local
variable before but I thought that removing it from MGSLPC struct
should be part of a separate patch instead.

> > if (info->rx_buf == NULL)
> > return -ENOMEM;
>
> Maybe something like
>
> static int rx_alloc_buffers(MGSLPC_INFO *info)
> {
> /* Prevent count from being 0 */
> if (->max_frame_size > MAX_FRAME_SIZE)
> return -EINVAL;

This boils down to whether having the clamp_val() on the probe method is
sufficient in your point of view. You make the final call on this :-)

> ...
> count = ...;
> ...
> rx_total_size = ...
> rx_buf = kcalloc(...);
>
> Then you don't need to check overflow with check_add_overflow() and
> check_mul_overflow() will be inside the kcalloc.
>

check_mul_overflow point -> agreed.

check_add_overflow -> similar suggestion as my previous point, if the
clamp_val on probe is sufficient for you, I would say that we don't need
it as of now too. But if you still think that we need it, I'm flexible
with that too.

> ...
>
> > - if (info->max_frame_size < 4096)
> > - info->max_frame_size = 4096;
> > - else if (info->max_frame_size > 65535)
> > - info->max_frame_size = 65535;
> > + if (info->max_frame_size < MGSLPC_MIN_FRAME_SIZE)
> > + info->max_frame_size = MGSLPC_MIN_FRAME_SIZE;
> > + else if (info->max_frame_size > MGSLPC_MAX_FRAME_SIZE)
> > + info->max_frame_size = MGSLPC_MAX_FRAME_SIZE;
>
> You can use clamp_val() macro here.
>

Nice, I didn't know about this macro. I will make that change for v4.

All really nice points you've made Andy, I'm learning heaps of new
things with this patch :-)

thanks!

- Paulo A.