[PATCH] af_unix: Don't set err in unix_stream_read_generic unless there was an error

Subsystems: networking [general], networking [unix sockets], the rest

STALE3852d

4 messages, 3 authors, 2016-02-17 · open the first message on its own page

[PATCH] af_unix: Don't set err in unix_stream_read_generic unless there was an error

From: Rainer Weikusat <hidden>
Date: 2016-02-08 18:47:41

The present unix_stream_read_generic contains various code sequences of
the form

err = -EDISASTER;
if (<test>)
	goto out;

This has the unfortunate side effect of possibly causing the error code
to bleed through to the final

out:
	return copied ? : err;

and then to be wrongly returned if no data was copied because the caller
didn't supply a data buffer, as demonstrated by the program available at

http://pad.lv/1540731

Change it such that err is only set if an error condition was detected.

Fixes: 3822b5c2fc62 ("af_unix: Revert 'lock_interruptible' in stream receive code")
Reported-by: Joseph Salisbury <redacted>
Signed-off-by: Rainer Weikusat <redacted>
---

And the subject again fixed and, since another correction was necessary,
anyway, a Reported-by added. 
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 49d5093..c1e4dd7 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -2277,13 +2277,15 @@ static int unix_stream_read_generic(struct unix_stream_read_state *state)
 	size_t size = state->size;
 	unsigned int last_len;
 
-	err = -EINVAL;
-	if (sk->sk_state != TCP_ESTABLISHED)
+	if (unlikely(sk->sk_state != TCP_ESTABLISHED)) {
+		err = -EINVAL;
 		goto out;
+	}
 
-	err = -EOPNOTSUPP;
-	if (flags & MSG_OOB)
+	if (unlikely(flags & MSG_OOB)) {
+		err = -EOPNOTSUPP;
 		goto out;
+	}
 
 	target = sock_rcvlowat(sk, flags & MSG_WAITALL, size);
 	timeo = sock_rcvtimeo(sk, noblock);
@@ -2329,9 +2331,11 @@ again:
 				goto unlock;
 
 			unix_state_unlock(sk);
-			err = -EAGAIN;
-			if (!timeo)
+			if (!timeo) {
+				err = -EAGAIN;
 				break;
+			}
+
 			mutex_unlock(&u->readlock);
 
 			timeo = unix_stream_data_wait(sk, timeo, last,

Re: [PATCH] af_unix: Don't set err in unix_stream_read_generic unless there was an error

From: David Miller <davem@davemloft.net>
Date: 2016-02-16 17:52:05

From: Rainer Weikusat <redacted>
Date: Mon, 08 Feb 2016 18:47:19 +0000
The present unix_stream_read_generic contains various code sequences of
the form

err = -EDISASTER;
if (<test>)
	goto out;

This has the unfortunate side effect of possibly causing the error code
to bleed through to the final

out:
	return copied ? : err;

and then to be wrongly returned if no data was copied because the caller
didn't supply a data buffer, as demonstrated by the program available at

http://pad.lv/1540731

Change it such that err is only set if an error condition was detected.

Fixes: 3822b5c2fc62 ("af_unix: Revert 'lock_interruptible' in stream receive code")
Reported-by: Joseph Salisbury <redacted>
Signed-off-by: Rainer Weikusat <redacted>
Applied, thanks Rainer.

And BTW I disagree with some of the feedback I saw in these threads
about "if (x) goto out;" being unreadable and that it should be avoided.

That's completely wrong.

Fact is, we've all been reading code of that form for multiple decades.
So it's the style we are _MOST_ familiar with, and it is therefore the
style that is the easiest and clearest for kernel developers to understand.

Especially those of us who review hundreds of patches per day.

And it doesn't matter at all what the compiler does underneath.

Furthermore, such a style works best in the long term because if real
cleanup operations are added for exit from the function, less has to
change and such patches are therefore significantly easier to review.

Re: [PATCH] af_unix: Don't set err in unix_stream_read_generic unless there was an error

From: Ben Hutchings <hidden>
Date: 2016-02-17 00:25:17

On Tue, 2016-02-16 at 12:51 -0500, David Miller wrote:
From: Rainer Weikusat <redacted>
Date: Mon, 08 Feb 2016 18:47:19 +0000
quoted
The present unix_stream_read_generic contains various code sequences of
the form

err = -EDISASTER;
if ()
      goto out;

This has the unfortunate side effect of possibly causing the error code
to bleed through to the final

out:
      return copied ? : err;

and then to be wrongly returned if no data was copied because the caller
didn't supply a data buffer, as demonstrated by the program available at

http://pad.lv/1540731

Change it such that err is only set if an error condition was detected.

Fixes: 3822b5c2fc62 ("af_unix: Revert 'lock_interruptible' in stream receive code")
Reported-by: Joseph Salisbury <redacted>
Signed-off-by: Rainer Weikusat <redacted>
Applied, thanks Rainer.

And BTW I disagree with some of the feedback I saw in these threads
about "if (x) goto out;" being unreadable and that it should be avoided.
That's not what I said.
That's completely wrong.

Fact is, we've all been reading code of that form for multiple decades.
So it's the style we are _MOST_ familiar with, and it is therefore the
style that is the easiest and clearest for kernel developers to understand.
[...]

I agree that 'if (err) goto cleanup;' is widely used and is generally
understandable (though more creative uses of goto are often not).

My objection was to 'err = -EFOO; if (cond) goto cleanup;'.  That is definitely not clear and it hides mistakes like this.

Ben.

-- 
Ben Hutchings
Lowery's Law:
             If it jams, force it. If it breaks, it needed replacing anyway.

Re: [PATCH] af_unix: Don't set err in unix_stream_read_generic unless there was an error

From: David Miller <davem@davemloft.net>
Date: 2016-02-17 01:07:12

From: Ben Hutchings <redacted>
Date: Wed, 17 Feb 2016 00:24:51 +0000
I agree that 'if (err) goto cleanup;' is widely used and is generally
understandable (though more creative uses of goto are often not).

My objection was to 'err = -EFOO; if (cond) goto cleanup;'.  That is
definitely not clear and it hides mistakes like this.
I don't see any difference whatsoever.

Part of the convention of the cleanup blob at the end of the
function is that error propagate to it's return statement via
a variable.

If this code wanted to handle that in more than one way, it is
the problem of this function, not of the convention itself.
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help