* [PATCH net] net/mlx4: avoid GCC 10 __bad_copy_from() false positive
@ 2026-05-20 10:21 Yao Sang
2026-05-25 10:47 ` Tariq Toukan
` (2 more replies)
0 siblings, 3 replies; 7+ messages in thread
From: Yao Sang @ 2026-05-20 10:21 UTC (permalink / raw)
To: Tariq Toukan, David S . Miller, Jakub Kicinski, Paolo Abeni
Cc: Andrew Lunn, Eric Dumazet, Gustavo A . R . Silva, netdev,
linux-rdma, Yao Sang
mlx4_init_user_cqes() allocates a single PAGE_SIZE buffer and fills it
with the CQE initialization pattern. When entries_per_copy >= entries,
the function copies array_size(entries, cqe_size) bytes from that buffer
to userspace.
That copy is actually bounded by PAGE_SIZE in the else branch because
entries_per_copy >= entries implies entries * cqe_size <= PAGE_SIZE.
However, GCC 10 does not derive that constraint and falsely triggers
__bad_copy_from() in mlx4_init_user_cqes().
Cap the single copy_to_user() length to PAGE_SIZE to make that bound
explicit and avoid the GCC 10 false positive.
Fixes: f69bf5dee7ef ("net/mlx4: Use array_size() helper in copy_to_user()")
Signed-off-by: Yao Sang <sangyao@kylinos.cn>
---
drivers/net/ethernet/mellanox/mlx4/cq.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/mellanox/mlx4/cq.c b/drivers/net/ethernet/mellanox/mlx4/cq.c
index e130e7259275..7b024a5e13c8 100644
--- a/drivers/net/ethernet/mellanox/mlx4/cq.c
+++ b/drivers/net/ethernet/mellanox/mlx4/cq.c
@@ -314,8 +314,11 @@ static int mlx4_init_user_cqes(void *buf, int entries, int cqe_size)
buf += PAGE_SIZE;
}
} else {
+ size_t copy_bytes = min_t(size_t, array_size(entries, cqe_size),
+ PAGE_SIZE);
+
err = copy_to_user((void __user *)buf, init_ents,
- array_size(entries, cqe_size)) ?
+ copy_bytes) ?
-EFAULT : 0;
}
--
2.25.1
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH net] net/mlx4: avoid GCC 10 __bad_copy_from() false positive
2026-05-20 10:21 [PATCH net] net/mlx4: avoid GCC 10 __bad_copy_from() false positive Yao Sang
@ 2026-05-25 10:47 ` Tariq Toukan
2026-05-26 7:56 ` Paolo Abeni
2026-05-26 10:09 ` David Laight
[not found] ` <1780035629778309.247.seg@mailgw.kylinos.cn>
2 siblings, 1 reply; 7+ messages in thread
From: Tariq Toukan @ 2026-05-25 10:47 UTC (permalink / raw)
To: Yao Sang, Tariq Toukan, David S . Miller, Jakub Kicinski,
Paolo Abeni
Cc: Andrew Lunn, Eric Dumazet, Gustavo A . R . Silva, netdev,
linux-rdma
On 20/05/2026 13:21, Yao Sang wrote:
> mlx4_init_user_cqes() allocates a single PAGE_SIZE buffer and fills it
> with the CQE initialization pattern. When entries_per_copy >= entries,
> the function copies array_size(entries, cqe_size) bytes from that buffer
> to userspace.
>
> That copy is actually bounded by PAGE_SIZE in the else branch because
> entries_per_copy >= entries implies entries * cqe_size <= PAGE_SIZE.
> However, GCC 10 does not derive that constraint and falsely triggers
> __bad_copy_from() in mlx4_init_user_cqes().
>
> Cap the single copy_to_user() length to PAGE_SIZE to make that bound
> explicit and avoid the GCC 10 false positive.
>
> Fixes: f69bf5dee7ef ("net/mlx4: Use array_size() helper in copy_to_user()")
> Signed-off-by: Yao Sang <sangyao@kylinos.cn>
> ---
> drivers/net/ethernet/mellanox/mlx4/cq.c | 5 ++++-
> 1 file changed, 4 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/net/ethernet/mellanox/mlx4/cq.c b/drivers/net/ethernet/mellanox/mlx4/cq.c
> index e130e7259275..7b024a5e13c8 100644
> --- a/drivers/net/ethernet/mellanox/mlx4/cq.c
> +++ b/drivers/net/ethernet/mellanox/mlx4/cq.c
> @@ -314,8 +314,11 @@ static int mlx4_init_user_cqes(void *buf, int entries, int cqe_size)
> buf += PAGE_SIZE;
> }
> } else {
> + size_t copy_bytes = min_t(size_t, array_size(entries, cqe_size),
> + PAGE_SIZE);
> +
> err = copy_to_user((void __user *)buf, init_ents,
> - array_size(entries, cqe_size)) ?
> + copy_bytes) ?
> -EFAULT : 0;
> }
>
Thanks for your patch.
This is a compiler issue.
Did you try fixing it there first?
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH net] net/mlx4: avoid GCC 10 __bad_copy_from() false positive
2026-05-25 10:47 ` Tariq Toukan
@ 2026-05-26 7:56 ` Paolo Abeni
0 siblings, 0 replies; 7+ messages in thread
From: Paolo Abeni @ 2026-05-26 7:56 UTC (permalink / raw)
To: Tariq Toukan, Yao Sang, David S . Miller, Jakub Kicinski
Cc: Andrew Lunn, Eric Dumazet, Gustavo A . R . Silva, netdev,
linux-rdma
On 5/25/26 12:47 PM, Tariq Toukan wrote:
> On 20/05/2026 13:21, Yao Sang wrote:
>> mlx4_init_user_cqes() allocates a single PAGE_SIZE buffer and fills it
>> with the CQE initialization pattern. When entries_per_copy >= entries,
>> the function copies array_size(entries, cqe_size) bytes from that buffer
>> to userspace.
>>
>> That copy is actually bounded by PAGE_SIZE in the else branch because
>> entries_per_copy >= entries implies entries * cqe_size <= PAGE_SIZE.
>> However, GCC 10 does not derive that constraint and falsely triggers
>> __bad_copy_from() in mlx4_init_user_cqes().
>>
>> Cap the single copy_to_user() length to PAGE_SIZE to make that bound
>> explicit and avoid the GCC 10 false positive.
>>
>> Fixes: f69bf5dee7ef ("net/mlx4: Use array_size() helper in copy_to_user()")
>> Signed-off-by: Yao Sang <sangyao@kylinos.cn>
>> ---
>> drivers/net/ethernet/mellanox/mlx4/cq.c | 5 ++++-
>> 1 file changed, 4 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/net/ethernet/mellanox/mlx4/cq.c b/drivers/net/ethernet/mellanox/mlx4/cq.c
>> index e130e7259275..7b024a5e13c8 100644
>> --- a/drivers/net/ethernet/mellanox/mlx4/cq.c
>> +++ b/drivers/net/ethernet/mellanox/mlx4/cq.c
>> @@ -314,8 +314,11 @@ static int mlx4_init_user_cqes(void *buf, int entries, int cqe_size)
>> buf += PAGE_SIZE;
>> }
>> } else {
>> + size_t copy_bytes = min_t(size_t, array_size(entries, cqe_size),
>> + PAGE_SIZE);
>> +
>> err = copy_to_user((void __user *)buf, init_ents,
>> - array_size(entries, cqe_size)) ?
>> + copy_bytes) ?
>> -EFAULT : 0;
>> }
>>
>
> Thanks for your patch.
>
> This is a compiler issue.
> Did you try fixing it there first?
AFAICS gcc 10 is a supported version, the kernel should build correctly
with it, right?
Also AFAICS this is not fastpath so an additional check should not be
problematic? Perhaps a warn instead would be more palatable?
if (WARN_ON_ONCE(array_size(entries, cqe_size) > PAGE_SIZE))
// ...
/P
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH net] net/mlx4: avoid GCC 10 __bad_copy_from() false positive
2026-05-20 10:21 [PATCH net] net/mlx4: avoid GCC 10 __bad_copy_from() false positive Yao Sang
2026-05-25 10:47 ` Tariq Toukan
@ 2026-05-26 10:09 ` David Laight
[not found] ` <1780035629778309.247.seg@mailgw.kylinos.cn>
2 siblings, 0 replies; 7+ messages in thread
From: David Laight @ 2026-05-26 10:09 UTC (permalink / raw)
To: Yao Sang
Cc: Tariq Toukan, David S . Miller, Jakub Kicinski, Paolo Abeni,
Andrew Lunn, Eric Dumazet, Gustavo A . R . Silva, netdev,
linux-rdma
On Wed, 20 May 2026 18:21:30 +0800
Yao Sang <sangyao@kylinos.cn> wrote:
> mlx4_init_user_cqes() allocates a single PAGE_SIZE buffer and fills it
> with the CQE initialization pattern. When entries_per_copy >= entries,
> the function copies array_size(entries, cqe_size) bytes from that buffer
> to userspace.
>
> That copy is actually bounded by PAGE_SIZE in the else branch because
> entries_per_copy >= entries implies entries * cqe_size <= PAGE_SIZE.
> However, GCC 10 does not derive that constraint and falsely triggers
> __bad_copy_from() in mlx4_init_user_cqes().
>
> Cap the single copy_to_user() length to PAGE_SIZE to make that bound
> explicit and avoid the GCC 10 false positive.
Why not just calculate 'entries * cqe_size' and then do a memset_user() loop
for that many bytes.
(There might even be a memset_user() function, a quick search didn't find it,
but I didn't find a memzero_user() either - and I'm pretty sure that
will exist.)
-- David
>
> Fixes: f69bf5dee7ef ("net/mlx4: Use array_size() helper in copy_to_user()")
> Signed-off-by: Yao Sang <sangyao@kylinos.cn>
> ---
> drivers/net/ethernet/mellanox/mlx4/cq.c | 5 ++++-
> 1 file changed, 4 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/net/ethernet/mellanox/mlx4/cq.c b/drivers/net/ethernet/mellanox/mlx4/cq.c
> index e130e7259275..7b024a5e13c8 100644
> --- a/drivers/net/ethernet/mellanox/mlx4/cq.c
> +++ b/drivers/net/ethernet/mellanox/mlx4/cq.c
> @@ -314,8 +314,11 @@ static int mlx4_init_user_cqes(void *buf, int entries, int cqe_size)
> buf += PAGE_SIZE;
> }
> } else {
> + size_t copy_bytes = min_t(size_t, array_size(entries, cqe_size),
> + PAGE_SIZE);
> +
> err = copy_to_user((void __user *)buf, init_ents,
> - array_size(entries, cqe_size)) ?
> + copy_bytes) ?
> -EFAULT : 0;
> }
>
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH net] net/mlx4: avoid GCC 10 __bad_copy_from() false positive
[not found] ` <1780035629778309.247.seg@mailgw.kylinos.cn>
@ 2026-05-29 6:45 ` Yao Sang
2026-06-01 11:00 ` Tariq Toukan
0 siblings, 1 reply; 7+ messages in thread
From: Yao Sang @ 2026-05-29 6:45 UTC (permalink / raw)
To: Tariq Toukan
Cc: David S . Miller, Jakub Kicinski, Paolo Abeni, Andrew Lunn,
Eric Dumazet, Gustavo A . R . Silva, netdev, linux-rdma,
David Laight
On Mon, May 25, 2026 at 01:47:59PM +0300, Tariq Toukan wrote:
>
>
> On 20/05/2026 13:21, Yao Sang wrote:
> > mlx4_init_user_cqes() allocates a single PAGE_SIZE buffer and fills it
> > with the CQE initialization pattern. When entries_per_copy >= entries,
> > the function copies array_size(entries, cqe_size) bytes from that buffer
> > to userspace.
> >
> > That copy is actually bounded by PAGE_SIZE in the else branch because
> > entries_per_copy >= entries implies entries * cqe_size <= PAGE_SIZE.
> > However, GCC 10 does not derive that constraint and falsely triggers
> > __bad_copy_from() in mlx4_init_user_cqes().
> >
> > Cap the single copy_to_user() length to PAGE_SIZE to make that bound
> > explicit and avoid the GCC 10 false positive.
> >
> > Fixes: f69bf5dee7ef ("net/mlx4: Use array_size() helper in copy_to_user()")
> > Signed-off-by: Yao Sang <sangyao@kylinos.cn>
> > ---
> > drivers/net/ethernet/mellanox/mlx4/cq.c | 5 ++++-
> > 1 file changed, 4 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/net/ethernet/mellanox/mlx4/cq.c b/drivers/net/ethernet/mellanox/mlx4/cq.c
> > index e130e7259275..7b024a5e13c8 100644
> > --- a/drivers/net/ethernet/mellanox/mlx4/cq.c
> > +++ b/drivers/net/ethernet/mellanox/mlx4/cq.c
> > @@ -314,8 +314,11 @@ static int mlx4_init_user_cqes(void *buf, int entries, int cqe_size)
> > buf += PAGE_SIZE;
> > }
> > } else {
> > + size_t copy_bytes = min_t(size_t, array_size(entries, cqe_size),
> > + PAGE_SIZE);
> > +
> > err = copy_to_user((void __user *)buf, init_ents,
> > - array_size(entries, cqe_size)) ?
> > + copy_bytes) ?
> > -EFAULT : 0;
> > }
>
> Thanks for your patch.
>
> This is a compiler issue.
> Did you try fixing it there first?
Hi Tariq,
Thanks for the review.
Yes, I agree this is triggered by a GCC 10 limitation / false positive.
I have not tried to make a compiler-side fix the gating item here,
because GCC 10 is still within the documented compiler range for
building the kernel, so I think the kernel should still build cleanly
with it.
That said, I also agree that my v1 shape is not ideal. In particular,
the silent min_t(..., PAGE_SIZE) clamp is too implicit.
I think Paolo's suggested direction is a better shape here, i.e. keep
array_size(), but make the bound explicit with a runtime guard instead
of silently clamping it, e.g.
copy_bytes = array_size(entries, cqe_size);
if (WARN_ON_ONCE(copy_bytes > PAGE_SIZE))
return -EINVAL;
err = copy_to_user((void __user *)buf, init_ents, copy_bytes) ?
-EFAULT : 0;
That would keep the overflow-safe multiplication, avoid the silent
truncation in v1, and make the single-copy branch invariant explicit
for GCC 10.
Regarding David's suggestion of using a memset_user() loop, I've also
looked into it, but couldn't locate either of those APIs in the kernel
after check.Please let me know if you have any additional information
or suggestions.
If this approach looks good to you, I'll send out the full v2 patch shortly.
Thanks,
Yao
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH net] net/mlx4: avoid GCC 10 __bad_copy_from() false positive
2026-05-29 6:45 ` Yao Sang
@ 2026-06-01 11:00 ` Tariq Toukan
2026-06-01 12:14 ` David Laight
0 siblings, 1 reply; 7+ messages in thread
From: Tariq Toukan @ 2026-06-01 11:00 UTC (permalink / raw)
To: Yao Sang
Cc: David S . Miller, Jakub Kicinski, Paolo Abeni, Andrew Lunn,
Eric Dumazet, Gustavo A . R . Silva, netdev, linux-rdma,
David Laight
On 29/05/2026 9:45, Yao Sang wrote:
> On Mon, May 25, 2026 at 01:47:59PM +0300, Tariq Toukan wrote:
>>
>>
>> On 20/05/2026 13:21, Yao Sang wrote:
>>> mlx4_init_user_cqes() allocates a single PAGE_SIZE buffer and fills it
>>> with the CQE initialization pattern. When entries_per_copy >= entries,
>>> the function copies array_size(entries, cqe_size) bytes from that buffer
>>> to userspace.
>>>
>>> That copy is actually bounded by PAGE_SIZE in the else branch because
>>> entries_per_copy >= entries implies entries * cqe_size <= PAGE_SIZE.
>>> However, GCC 10 does not derive that constraint and falsely triggers
>>> __bad_copy_from() in mlx4_init_user_cqes().
>>>
>>> Cap the single copy_to_user() length to PAGE_SIZE to make that bound
>>> explicit and avoid the GCC 10 false positive.
>>>
>>> Fixes: f69bf5dee7ef ("net/mlx4: Use array_size() helper in copy_to_user()")
>>> Signed-off-by: Yao Sang <sangyao@kylinos.cn>
>>> ---
>>> drivers/net/ethernet/mellanox/mlx4/cq.c | 5 ++++-
>>> 1 file changed, 4 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/drivers/net/ethernet/mellanox/mlx4/cq.c b/drivers/net/ethernet/mellanox/mlx4/cq.c
>>> index e130e7259275..7b024a5e13c8 100644
>>> --- a/drivers/net/ethernet/mellanox/mlx4/cq.c
>>> +++ b/drivers/net/ethernet/mellanox/mlx4/cq.c
>>> @@ -314,8 +314,11 @@ static int mlx4_init_user_cqes(void *buf, int entries, int cqe_size)
>>> buf += PAGE_SIZE;
>>> }
>>> } else {
>>> + size_t copy_bytes = min_t(size_t, array_size(entries, cqe_size),
>>> + PAGE_SIZE);
>>> +
>>> err = copy_to_user((void __user *)buf, init_ents,
>>> - array_size(entries, cqe_size)) ?
>>> + copy_bytes) ?
>>> -EFAULT : 0;
>>> }
>>
>> Thanks for your patch.
>>
>> This is a compiler issue.
>> Did you try fixing it there first?
> Hi Tariq,
>
> Thanks for the review.
>
> Yes, I agree this is triggered by a GCC 10 limitation / false positive.
>
> I have not tried to make a compiler-side fix the gating item here,
> because GCC 10 is still within the documented compiler range for
> building the kernel, so I think the kernel should still build cleanly
> with it.
>
> That said, I also agree that my v1 shape is not ideal. In particular,
> the silent min_t(..., PAGE_SIZE) clamp is too implicit.
>
> I think Paolo's suggested direction is a better shape here, i.e. keep
> array_size(), but make the bound explicit with a runtime guard instead
> of silently clamping it, e.g.
>
> copy_bytes = array_size(entries, cqe_size);
> if (WARN_ON_ONCE(copy_bytes > PAGE_SIZE))
> return -EINVAL;
>
> err = copy_to_user((void __user *)buf, init_ents, copy_bytes) ?
> -EFAULT : 0;
>
> That would keep the overflow-safe multiplication, avoid the silent
> truncation in v1, and make the single-copy branch invariant explicit
> for GCC 10.
>
> Regarding David's suggestion of using a memset_user() loop, I've also
> looked into it, but couldn't locate either of those APIs in the kernel
> after check.Please let me know if you have any additional information
> or suggestions.
>
> If this approach looks good to you, I'll send out the full v2 patch shortly.
>
That would work.
Thanks.
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH net] net/mlx4: avoid GCC 10 __bad_copy_from() false positive
2026-06-01 11:00 ` Tariq Toukan
@ 2026-06-01 12:14 ` David Laight
0 siblings, 0 replies; 7+ messages in thread
From: David Laight @ 2026-06-01 12:14 UTC (permalink / raw)
To: Tariq Toukan
Cc: Yao Sang, David S . Miller, Jakub Kicinski, Paolo Abeni,
Andrew Lunn, Eric Dumazet, Gustavo A . R . Silva, netdev,
linux-rdma
On Mon, 1 Jun 2026 14:00:15 +0300
Tariq Toukan <tariqt@nvidia.com> wrote:
> On 29/05/2026 9:45, Yao Sang wrote:
> > On Mon, May 25, 2026 at 01:47:59PM +0300, Tariq Toukan wrote:
...
> > Regarding David's suggestion of using a memset_user() loop, I've also
> > looked into it, but couldn't locate either of those APIs in the kernel
> > after check.Please let me know if you have any additional information
> > or suggestions.
> >
> > If this approach looks good to you, I'll send out the full v2 patch shortly.
> >
>
> That would work.
> Thanks.
>
I wasn't at all sure there was one, but a loop using a 'reasonable size'
buffer will be reasonably simple and fast.
I suspect an on-stack 256 byte buffer would be good enough.
If it were a really hot path there are other options, but this looked
like initialisation so performance isn't that critical.
(But you don't want a loop of put_user() because that will be slow.)
-- David
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-06-01 12:14 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-20 10:21 [PATCH net] net/mlx4: avoid GCC 10 __bad_copy_from() false positive Yao Sang
2026-05-25 10:47 ` Tariq Toukan
2026-05-26 7:56 ` Paolo Abeni
2026-05-26 10:09 ` David Laight
[not found] ` <1780035629778309.247.seg@mailgw.kylinos.cn>
2026-05-29 6:45 ` Yao Sang
2026-06-01 11:00 ` Tariq Toukan
2026-06-01 12:14 ` David Laight
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox