Skip to content

accept() fails to populate peer address (sockaddr) for bound AF_UNIX stream sockets #1666

Description

@lukkrusz

Description

When accepting a connection over an AF_UNIX socket via accept(), the kernel fails to populate the peer address structure and its corresponding length field. Even when the connecting client has explicitly bound to a valid filesystem path using bind() (giving it a formal identity), accept() leaves the sockaddr buffer completely unmodified and fails to update the addrlen value-result parameter.

NOTE: AF_INET sockets behave correctly and extract the peer address as expected.

Expected Behavior

  • Server and client sockets are created (AF_UNIX, SOCK_STREAM).
  • Both server and client are explicitly bound to valid filesystem paths.
  • Client initiates a non-blocking connection to the server.
  • Server accepts the connection using accept().
  • accept() successfully returns a new file descriptor, populates the user-provided sockaddr buffer with the client's bound path, and updates the addrlen parameter to reflect the actual size of the stored address.

Actual Behavior

  • Server and client sockets are created and bound.
  • Client connects to the server.
  • Server successfully accepts the connection and returns a valid file descriptor.
  • The sockaddr buffer remains completely unmodified (e.g., pre-filled 0xff memory stays 0xff).
  • The addrlen value-result parameter is not updated (remains at its input size), indicating the OS completely ignored the peer address extraction.

POSIX Requirement

According to the POSIX.1-2017 accept() specification:
"If address is not a null pointer, the address of the peer for the accepted connection shall be stored in the sockaddr structure pointed to by address, and the length of this address shall be stored in the object pointed to by address_len."

Minimal Reproduction (confirmed on target)

#include <stdio.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>

int main(void)
{
	/* Cleanup from previous runs */
	unlink("/tmp/s");
	unlink("/tmp/c");

	/* Setup Listener */
	int lfd = socket(AF_UNIX, SOCK_STREAM, 0);
	struct sockaddr_un srv = { .sun_family = AF_UNIX, .sun_path = "/tmp/s" };
	bind(lfd, (struct sockaddr *)&srv, sizeof(srv));
	listen(lfd, 5);

	/* Setup Client & Bind */
	int cfd = socket(AF_UNIX, SOCK_STREAM, 0);
	struct sockaddr_un cli = { .sun_family = AF_UNIX, .sun_path = "/tmp/c" };
	bind(cfd, (struct sockaddr *)&cli, sizeof(cli));

	/* Non-blocking Connect */
	fcntl(cfd, F_SETFL, fcntl(cfd, F_GETFL, 0) | O_NONBLOCK);
	connect(cfd, (struct sockaddr *)&srv, sizeof(srv));

	/* Prepare memory and Accept */
	struct sockaddr_un peer;
	memset(&peer, 0xff, sizeof(peer));
	socklen_t len = sizeof(peer);

	int afd = accept(lfd, (struct sockaddr *)&peer, &len);
	if (afd < 0) {
		perror("accept failed");
		return 1;
	}

	/* Terminate the path string safely just in case it's garbage */
	peer.sun_path[sizeof(peer.sun_path) - 1] = '\0';

	printf("Extracted family: %u (Expected: %u)\n", peer.sun_family, AF_UNIX);
	printf("Extracted path:   '%s' (Expected: '/tmp/c')\n", peer.sun_path);
	printf("Extracted length: %u (Expected: >2)\n", (unsigned int)len);

	return 0;
}

Output on ia32-generic-qemu:

Extracted family: 65535 (Expected: 1)
Extracted path:   '�����������������������������������������������������������������������������������������������������������' (Expected: '/tmp/c')
Extracted length: 110 (Expected: >2)
Image

Output on host-generic-pc:

Extracted family: 1 (Expected: 1)
Extracted path:   '/tmp/c' (Expected: '/tmp/c')
Extracted length: 9 (Expected: >2)

Revision

62b46f9

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    Fields

    No fields configured for Bug.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions