Netdev List
 help / color / mirror / Atom feed
From: Christian Brauner <brauner@kernel.org>
To: Eric Dumazet <edumazet@google.com>,
	Daniel Borkmann <daniel@iogearbox.net>,
	netdev@vger.kernel.org
Cc: Christian Brauner <brauner@kernel.org>,
	Lennart Poettering <lennart@poettering.net>,
	David Rheinsberg <david@readahead.eu>,
	Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>,
	Kuniyuki Iwashima <kuniyu@amazon.com>
Subject: af-unix: ECONNRESET with fully consumed out-of-band data
Date: Thu, 29 May 2025 12:37:54 +0200	[thread overview]
Message-ID: <20250529-sinkt-abfeuern-e7b08200c6b0@brauner> (raw)

Hey,

I've played with out-of-band data on unix sockets and I'm observing strange
behavior. Below is a minimal reproducer.

This is sending exactly one byte of out-of-band data from the client to the
server. The client shuts down the write side aftewards and issues a blocking
read waiting for the server to sever the connection.

The server consumes the single byte of out-of-band data sent by the client and
closes the connection.

The client should see a zero read as all data has been consumed but instead it
sees ECONNRESET indicating an unclean shutdown.

But it's even stranger. If the server issues a regular data read() after
consuming the single out-of-band byte it will get a zero read indicating EOF as
the child shutdown the write side. The fun part is that this zero read in the
parent also makes the child itself see a zero read/EOF after the client severs
the connection indicating a clean shutdown. Which makes no sense to me
whatsoever.

In contrast, when sending exactly one byte of regular data the client sees a
zero read aka EOF correctly indicating a clean shutdown.

It seems a bug to me that a single byte of out-of-band data leads to an unclean
shutdown even though it has been correctly consumed and there's no more data
left in the socket.

Maybe that's expected and there's a reasonable explanation but that's very
unexpected behavior.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <errno.h>
#include <sys/wait.h>

int main(void) {
	int sv[2];
	pid_t pid;
	char buf[16];
	ssize_t n;

	if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv) < 0)
		_exit(EXIT_FAILURE);

	pid = fork();
	if (pid < 0)
		_exit(EXIT_FAILURE);

	if (pid == 0) {
		close(sv[0]);

		/* Send OOB data to the server. */
		printf("child: %zd\n", send(sv[1], "1", 1, MSG_OOB));

		/* We're done sending data so shutdown the write side. */
		shutdown(sv[1], SHUT_WR);

		/* We expect to see EOF here, but we see ECONNRESET instead. */
		if (read(sv[1], buf, 1) != 0) {
			fprintf(stderr, "%d => %m - Child read did not return EOF\n", errno);
			_exit(EXIT_FAILURE);
		}

		_exit(EXIT_SUCCESS);
	}

	/* The parent acts as a client here. */
	close(sv[1]);

	/* Hack: MSG_OOB doesn't block, so we need to make sure the OOB data has arrived. */
	sleep(2);
	
	/* Read the OOB data. */
	printf("%zd\n", recv(sv[0], buf, sizeof(buf), MSG_OOB));

	/* If you uncomment the following code you can make the child see a zero read/EOF: */
	// printf("%zd\n", read(sv[0], buf, sizeof(buf)));

	/*
	 * Close the connection. The child should see EOF but sees ECONNRESET instead...
	 * Try removing MSG_OOB and see how the child sees EOF instead.
	 */
	close(sv[0]);

	waitpid(pid, NULL, 0);
	_exit(EXIT_SUCCESS);
}

             reply	other threads:[~2025-05-29 10:44 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-05-29 10:37 Christian Brauner [this message]
2025-05-30  2:21 ` af-unix: ECONNRESET with fully consumed out-of-band data Kuniyuki Iwashima

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=20250529-sinkt-abfeuern-e7b08200c6b0@brauner \
    --to=brauner@kernel.org \
    --cc=daniel@iogearbox.net \
    --cc=david@readahead.eu \
    --cc=edumazet@google.com \
    --cc=kuba@kernel.org \
    --cc=kuniyu@amazon.com \
    --cc=lennart@poettering.net \
    --cc=netdev@vger.kernel.org \
    --cc=pabeni@redhat.com \
    /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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox