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)
Output on host-generic-pc:
Extracted family: 1 (Expected: 1)
Extracted path: '/tmp/c' (Expected: '/tmp/c')
Extracted length: 9 (Expected: >2)
Revision
62b46f9
Description
When accepting a connection over an
AF_UNIXsocket viaaccept(), 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 usingbind()(giving it a formal identity),accept()leaves thesockaddrbuffer completely unmodified and fails to update theaddrlenvalue-result parameter.NOTE:
AF_INETsockets behave correctly and extract the peer address as expected.Expected Behavior
AF_UNIX,SOCK_STREAM).accept().accept()successfully returns a new file descriptor, populates the user-providedsockaddrbuffer with the client's bound path, and updates theaddrlenparameter to reflect the actual size of the stored address.Actual Behavior
sockaddrbuffer remains completely unmodified (e.g., pre-filled0xffmemory stays0xff).addrlenvalue-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)
Output on
ia32-generic-qemu:Output on
host-generic-pc:Revision
62b46f9