diff mbox series

[net] net: ethernet: adi: adin1110: Fix some error handling path in adin1110_read_fifo()

Message ID 8ff73b40f50d8fa994a454911b66adebce8da266.1727981562.git.christophe.jaillet@wanadoo.fr (mailing list archive)
State Accepted
Commit 83211ae1640516accae645de82f5a0a142676897
Delegated to: Netdev Maintainers
Headers show
Series [net] net: ethernet: adi: adin1110: Fix some error handling path in adin1110_read_fifo() | expand

Checks

Context Check Description
netdev/series_format success Single patches do not need cover letters
netdev/tree_selection success Clearly marked for net
netdev/ynl success Generated files up to date; no warnings/errors; no diff in generated;
netdev/fixes_present success Fixes tag present in non-next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 6 this patch: 6
netdev/build_tools success No tools touched, skip
netdev/cc_maintainers warning 1 maintainers not CCed: ciprian.regus@analog.com
netdev/build_clang success Errors and warnings before: 6 this patch: 6
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success Fixes tag looks correct
netdev/build_allmodconfig_warn success Errors and warnings before: 5 this patch: 5
netdev/checkpatch success total: 0 errors, 0 warnings, 0 checks, 13 lines checked
netdev/build_clang_rust success No Rust files in patch. Skipping build
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0
netdev/contest success net-next-2024-10-06--15-00 (tests: 775)

Commit Message

Christophe JAILLET Oct. 3, 2024, 6:53 p.m. UTC
If 'frame_size' is too small or if 'round_len' is an error code, it is
likely that an error code should be returned to the caller.

Actually, 'ret' is likely to be 0, so if one of these sanity checks fails,
'success' is returned.

Return -EINVAL instead.

Fixes: bc93e19d088b ("net: ethernet: adi: Add ADIN1110 support")
Signed-off-by: Christophe JAILLET <christophe.jaillet@wanadoo.fr>
---
This patch is speculative.
If returning 0 is what was intended, then an explicit 0 would be better.
---
 drivers/net/ethernet/adi/adin1110.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

Comments

Simon Horman Oct. 4, 2024, 11:37 a.m. UTC | #1
On Thu, Oct 03, 2024 at 08:53:15PM +0200, Christophe JAILLET wrote:
> If 'frame_size' is too small or if 'round_len' is an error code, it is
> likely that an error code should be returned to the caller.
> 
> Actually, 'ret' is likely to be 0, so if one of these sanity checks fails,
> 'success' is returned.

Hi Christophe,

I think we can say "'ret' will be 0".
At least that is what my brief investigation tells me.

> 
> Return -EINVAL instead.

Please include some information on how this was found and tested.
e.g.

Found by inspection / Found using widget-ng.
Compile tested only.

> 
> Fixes: bc93e19d088b ("net: ethernet: adi: Add ADIN1110 support")
> Signed-off-by: Christophe JAILLET <christophe.jaillet@wanadoo.fr>
> ---
> This patch is speculative.
> If returning 0 is what was intended, then an explicit 0 would be better.

In my brief investigation I see that adin1110_read_fifo()
is only called by adin1110_read_frames(), like this:

	while (budget) {
		...

		ret = adin1110_read_fifo(port_priv);
		if (ret < 0)
			return;

		budget--;
	}

So the question becomes, should a failure in reading the fifo,
because of an invalid frame size, be treated as an error
and terminate reading frames.

Like you, I speculate the answer is yes.
But I think we need a bit more certainty to take this patch.
Dan Carpenter Oct. 4, 2024, 11:47 a.m. UTC | #2
On Thu, Oct 03, 2024 at 08:53:15PM +0200, Christophe JAILLET wrote:
> If 'frame_size' is too small or if 'round_len' is an error code, it is
> likely that an error code should be returned to the caller.
> 
> Actually, 'ret' is likely to be 0, so if one of these sanity checks fails,
> 'success' is returned.
> 
> Return -EINVAL instead.
> 
> Fixes: bc93e19d088b ("net: ethernet: adi: Add ADIN1110 support")
> Signed-off-by: Christophe JAILLET <christophe.jaillet@wanadoo.fr>
> ---
> This patch is speculative.
> If returning 0 is what was intended, then an explicit 0 would be better.

I have an unpublished Smatch warning for these:

drivers/net/ethernet/adi/adin1110.c:321 adin1110_read_fifo() info: returning a literal zero is cleaner
drivers/net/ethernet/adi/adin1110.c:325 adin1110_read_fifo() info: returning a literal zero is cleaner

It's a pity that deliberately doing a "return ret;" when ret is zero is so
common.  Someone explained to me that it was "done deliberately to express that
we were propagating the success from frob_whatever()".  No no no!

I don't review these warnings unless I'm fixing a bug in the driver because
they're too common.  The only ones I review are:

	ret = frob();
	if (!ret)
		return ret;

Maybe 20% of the time those warnings indicate a reversed if statement.

Your heuristic here is very clever and I'll try steal it to create a new more
specific warning.

regards,
dan carpenter
Christophe JAILLET Oct. 4, 2024, 1:15 p.m. UTC | #3
Le 04/10/2024 à 13:37, Simon Horman a écrit :
> On Thu, Oct 03, 2024 at 08:53:15PM +0200, Christophe JAILLET wrote:
>> If 'frame_size' is too small or if 'round_len' is an error code, it is
>> likely that an error code should be returned to the caller.
>>
>> Actually, 'ret' is likely to be 0, so if one of these sanity checks fails,
>> 'success' is returned.
> 
> Hi Christophe,
> 
> I think we can say "'ret' will be 0".

Agreed.

	ret = adin1110_read_reg()
	--> spi_sync_transfer()
	--> spi_sync()

which explicitly documents "zero on success, else a negative error code."

> At least that is what my brief investigation tells me.
> 
>>
>> Return -EINVAL instead.
> 

If the patch is considered as correct, can you confirm that -EINVAL is 
the correct error code to use? If not, which one would be preferred?


> Please include some information on how this was found and tested.
> e.g.
> 
> Found by inspection / Found using widget-ng.

I would say: found by luck! :)

The explanation below will be of no help in the commit message and won't 
be added. I just give you all the gory details because you asked for it ;-)

(and after reading bellow, you can call me crazy!)



I was looking at functions that propagate error codes as their last 
argument. The idea came after submitting [1].

I read cci_read() and wondered if functions with such a semantic could 
use an un-initialized last argument. In such a case, this function could 
not behave as expected if the initial value of "err" was not 0.

So I wrote the following coccinelle script and several other variations.


// Options: --include-headers

@ok@
identifier fct, err;
type T;
@@

	int fct(..., T *err)
	{
		...
	}

@test depends on ok@
identifier x, fct = ok.fct;
expression res;
type T = ok.T;
@@

*	T x;
	...
(
	fct(..., &x);
|
	res = fct(..., &x);
)

(For the record, I have not found any issue with it...)


BUT, adin1110_read_fifo() was spotted because of the prototype of 
adin1110_read_reg().

When I reviewed the code, I quickly saw that it was a false positive and 
that using "type T" in my script was not that logical...

Anyway, when reviewing the code, I saw:

	if (ret < 0)
		return ret;

	/* The read frame size includes the extra 2 bytes
	 * from the  ADIN1110 frame header.
	 */
	if (frame_size < ADIN1110_FRAME_HEADER_LEN + ADIN1110_FEC_LEN)
		return ret;

	round_len = adin1110_round_len(frame_size);
	if (round_len < 0)
		return ret;

which looks really strange and likely broken...

Then I sent the patch we are talking about!


(yes some real people really search such things and write such 
coccinelle scripts, and now you can call me crazy)


[1]: 
https://lore.kernel.org/all/666ac169157f0af1c2e1d47926b68870cb39d587.1727977974.git.christophe.jaillet@wanadoo.fr/

> Compile tested only.

As a "speculative" patch, it was only compile tested, you are correct.

> 
>>
>> Fixes: bc93e19d088b ("net: ethernet: adi: Add ADIN1110 support")
>> Signed-off-by: Christophe JAILLET <christophe.jaillet@wanadoo.fr>
>> ---
>> This patch is speculative.
>> If returning 0 is what was intended, then an explicit 0 would be better.
> 
> In my brief investigation I see that adin1110_read_fifo()
> is only called by adin1110_read_frames(), like this:
> 
> 	while (budget) {
> 		...
> 
> 		ret = adin1110_read_fifo(port_priv);
> 		if (ret < 0)
> 			return;
> 
> 		budget--;
> 	}
> 
> So the question becomes, should a failure in reading the fifo,
> because of an invalid frame size, be treated as an error
> and terminate reading frames.
> 
> Like you, I speculate the answer is yes.
> But I think we need a bit more certainty to take this patch.

I won't be of any help here.

I can just say that "it looks strange" and is "certainly" bogus, but 
won't be able the prove it nor test it.


I'll wait a bit before sending a v2. If confirming this point is a 
requirement for accepting the patch, there is no need to urge for a v2 
if no-one cares about answering your point.

CJ


>
Christophe JAILLET Oct. 4, 2024, 1:27 p.m. UTC | #4
Le 04/10/2024 à 13:47, Dan Carpenter a écrit :
> On Thu, Oct 03, 2024 at 08:53:15PM +0200, Christophe JAILLET wrote:
>> If 'frame_size' is too small or if 'round_len' is an error code, it is
>> likely that an error code should be returned to the caller.
>>
>> Actually, 'ret' is likely to be 0, so if one of these sanity checks fails,
>> 'success' is returned.
>>
>> Return -EINVAL instead.
>>
>> Fixes: bc93e19d088b ("net: ethernet: adi: Add ADIN1110 support")
>> Signed-off-by: Christophe JAILLET <christophe.jaillet@wanadoo.fr>
>> ---
>> This patch is speculative.
>> If returning 0 is what was intended, then an explicit 0 would be better.
> 
> I have an unpublished Smatch warning for these:
> 
> drivers/net/ethernet/adi/adin1110.c:321 adin1110_read_fifo() info: returning a literal zero is cleaner
> drivers/net/ethernet/adi/adin1110.c:325 adin1110_read_fifo() info: returning a literal zero is cleaner
> 
> It's a pity that deliberately doing a "return ret;" when ret is zero is so
> common.  Someone explained to me that it was "done deliberately to express that
> we were propagating the success from frob_whatever()".  No no no!
> 
> I don't review these warnings unless I'm fixing a bug in the driver because
> they're too common.  The only ones I review are:
> 
> 	ret = frob();
> 	if (!ret)
> 		return ret;
> 
> Maybe 20% of the time those warnings indicate a reversed if statement.
> 
> Your heuristic here is very clever and I'll try steal it to create a new more
> specific warning.

Well my heuristic is mostly luck, here ;-)

Anyway, what I was looking for (un-initialized last argument in some 
function) could be nice to have in smatch, if not already present.


Finally, if you want, I can give a look at the warnings if you share the 
log.

CJ

> 
> regards,
> dan carpenter
> 
> 
>
Jakub Kicinski Oct. 4, 2024, 6:09 p.m. UTC | #5
On Fri, 4 Oct 2024 14:47:22 +0300 Dan Carpenter wrote:
> It's a pity that deliberately doing a "return ret;" when ret is zero is so
> common.  Someone explained to me that it was "done deliberately to express that
> we were propagating the success from frob_whatever()".  No no no!

FWIW I pitched to Linus that we should have a err_t of some sort for
int variables which must never be returned with value of 0.
He wasn't impressed, but I still think it would be useful :)
Simon Horman Oct. 7, 2024, 3:45 p.m. UTC | #6
On Fri, Oct 04, 2024 at 03:15:39PM +0200, Christophe JAILLET wrote:
> Le 04/10/2024 à 13:37, Simon Horman a écrit :
> > On Thu, Oct 03, 2024 at 08:53:15PM +0200, Christophe JAILLET wrote:
> > > If 'frame_size' is too small or if 'round_len' is an error code, it is
> > > likely that an error code should be returned to the caller.
> > > 
> > > Actually, 'ret' is likely to be 0, so if one of these sanity checks fails,
> > > 'success' is returned.
> > 
> > Hi Christophe,
> > 
> > I think we can say "'ret' will be 0".
> 
> Agreed.
> 
> 	ret = adin1110_read_reg()
> 	--> spi_sync_transfer()
> 	--> spi_sync()
> 
> which explicitly documents "zero on success, else a negative error code."
> 
> > At least that is what my brief investigation tells me.
> > 
> > > 
> > > Return -EINVAL instead.
> > 
> 
> If the patch is considered as correct, can you confirm that -EINVAL is the
> correct error code to use? If not, which one would be preferred?

-EINVAL seems reasonable to me.

> > Please include some information on how this was found and tested.
> > e.g.
> > 
> > Found by inspection / Found using widget-ng.
> 
> I would say: found by luck! :)
> 
> The explanation below will be of no help in the commit message and won't be
> added. I just give you all the gory details because you asked for it ;-)
> 
> (and after reading bellow, you can call me crazy!)

:)
Simon Horman Oct. 7, 2024, 3:46 p.m. UTC | #7
On Fri, Oct 04, 2024 at 11:09:52AM -0700, Jakub Kicinski wrote:
> On Fri, 4 Oct 2024 14:47:22 +0300 Dan Carpenter wrote:
> > It's a pity that deliberately doing a "return ret;" when ret is zero is so
> > common.  Someone explained to me that it was "done deliberately to express that
> > we were propagating the success from frob_whatever()".  No no no!
> 
> FWIW I pitched to Linus that we should have a err_t of some sort for
> int variables which must never be returned with value of 0.
> He wasn't impressed, but I still think it would be useful :)

FWIIW, I think something like that would be quite nice.
Julia Lawall Oct. 7, 2024, 5:35 p.m. UTC | #8
On Mon, 7 Oct 2024, Simon Horman wrote:

> On Fri, Oct 04, 2024 at 11:09:52AM -0700, Jakub Kicinski wrote:
> > On Fri, 4 Oct 2024 14:47:22 +0300 Dan Carpenter wrote:
> > > It's a pity that deliberately doing a "return ret;" when ret is zero is so
> > > common.  Someone explained to me that it was "done deliberately to express that
> > > we were propagating the success from frob_whatever()".  No no no!
> >
> > FWIW I pitched to Linus that we should have a err_t of some sort for
> > int variables which must never be returned with value of 0.
> > He wasn't impressed, but I still think it would be useful :)
>
> FWIIW, I think something like that would be quite nice.

Likewise.

julia
patchwork-bot+netdevbpf@kernel.org Oct. 8, 2024, 12:10 a.m. UTC | #9
Hello:

This patch was applied to netdev/net.git (main)
by Jakub Kicinski <kuba@kernel.org>:

On Thu,  3 Oct 2024 20:53:15 +0200 you wrote:
> If 'frame_size' is too small or if 'round_len' is an error code, it is
> likely that an error code should be returned to the caller.
> 
> Actually, 'ret' is likely to be 0, so if one of these sanity checks fails,
> 'success' is returned.
> 
> Return -EINVAL instead.
> 
> [...]

Here is the summary with links:
  - [net] net: ethernet: adi: adin1110: Fix some error handling path in adin1110_read_fifo()
    https://git.kernel.org/netdev/net/c/83211ae16405

You are awesome, thank you!
diff mbox series

Patch

diff --git a/drivers/net/ethernet/adi/adin1110.c b/drivers/net/ethernet/adi/adin1110.c
index 3431a7e62b0d..c04036b687dd 100644
--- a/drivers/net/ethernet/adi/adin1110.c
+++ b/drivers/net/ethernet/adi/adin1110.c
@@ -318,11 +318,11 @@  static int adin1110_read_fifo(struct adin1110_port_priv *port_priv)
 	 * from the  ADIN1110 frame header.
 	 */
 	if (frame_size < ADIN1110_FRAME_HEADER_LEN + ADIN1110_FEC_LEN)
-		return ret;
+		return -EINVAL;
 
 	round_len = adin1110_round_len(frame_size);
 	if (round_len < 0)
-		return ret;
+		return -EINVAL;
 
 	frame_size_no_fcs = frame_size - ADIN1110_FRAME_HEADER_LEN - ADIN1110_FEC_LEN;
 	memset(priv->data, 0, ADIN1110_RD_HEADER_LEN);