Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at master 180 lines 3.9 kB view raw
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Selftest for AF_UNIX socket close and ECONNRESET behaviour. 4 * 5 * This test verifies: 6 * 1. SOCK_STREAM returns EOF when the peer closes normally. 7 * 2. SOCK_STREAM returns ECONNRESET if peer closes with unread data. 8 * 3. SOCK_SEQPACKET returns EOF when the peer closes normally. 9 * 4. SOCK_SEQPACKET returns ECONNRESET if the peer closes with unread data. 10 * 5. SOCK_DGRAM does not return ECONNRESET when the peer closes. 11 * 12 * These tests document the intended Linux behaviour. 13 * 14 */ 15 16#define _GNU_SOURCE 17#include <string.h> 18#include <fcntl.h> 19#include <unistd.h> 20#include <errno.h> 21#include <sys/socket.h> 22#include <sys/un.h> 23#include "../../kselftest_harness.h" 24 25#define SOCK_PATH "/tmp/af_unix_connreset.sock" 26 27static void remove_socket_file(void) 28{ 29 unlink(SOCK_PATH); 30} 31 32FIXTURE(unix_sock) 33{ 34 int server; 35 int client; 36 int child; 37}; 38 39FIXTURE_VARIANT(unix_sock) 40{ 41 int socket_type; 42 const char *name; 43}; 44 45FIXTURE_VARIANT_ADD(unix_sock, stream) { 46 .socket_type = SOCK_STREAM, 47 .name = "SOCK_STREAM", 48}; 49 50FIXTURE_VARIANT_ADD(unix_sock, dgram) { 51 .socket_type = SOCK_DGRAM, 52 .name = "SOCK_DGRAM", 53}; 54 55FIXTURE_VARIANT_ADD(unix_sock, seqpacket) { 56 .socket_type = SOCK_SEQPACKET, 57 .name = "SOCK_SEQPACKET", 58}; 59 60FIXTURE_SETUP(unix_sock) 61{ 62 struct sockaddr_un addr = {}; 63 int err; 64 65 addr.sun_family = AF_UNIX; 66 strcpy(addr.sun_path, SOCK_PATH); 67 remove_socket_file(); 68 69 self->server = socket(AF_UNIX, variant->socket_type, 0); 70 ASSERT_LT(-1, self->server); 71 72 err = bind(self->server, (struct sockaddr *)&addr, sizeof(addr)); 73 ASSERT_EQ(0, err); 74 75 if (variant->socket_type == SOCK_STREAM || 76 variant->socket_type == SOCK_SEQPACKET) { 77 err = listen(self->server, 1); 78 ASSERT_EQ(0, err); 79 } 80 81 self->client = socket(AF_UNIX, variant->socket_type | SOCK_NONBLOCK, 0); 82 ASSERT_LT(-1, self->client); 83 84 err = connect(self->client, (struct sockaddr *)&addr, sizeof(addr)); 85 ASSERT_EQ(0, err); 86} 87 88FIXTURE_TEARDOWN(unix_sock) 89{ 90 if (variant->socket_type == SOCK_STREAM || 91 variant->socket_type == SOCK_SEQPACKET) 92 close(self->child); 93 94 close(self->client); 95 close(self->server); 96 remove_socket_file(); 97} 98 99/* Test 1: peer closes normally */ 100TEST_F(unix_sock, eof) 101{ 102 char buf[16] = {}; 103 ssize_t n; 104 105 if (variant->socket_type == SOCK_STREAM || 106 variant->socket_type == SOCK_SEQPACKET) { 107 self->child = accept(self->server, NULL, NULL); 108 ASSERT_LT(-1, self->child); 109 110 close(self->child); 111 } else { 112 close(self->server); 113 } 114 115 n = recv(self->client, buf, sizeof(buf), 0); 116 117 if (variant->socket_type == SOCK_STREAM || 118 variant->socket_type == SOCK_SEQPACKET) { 119 ASSERT_EQ(0, n); 120 } else { 121 ASSERT_EQ(-1, n); 122 ASSERT_EQ(EAGAIN, errno); 123 } 124} 125 126/* Test 2: peer closes with unread data */ 127TEST_F(unix_sock, reset_unread_behavior) 128{ 129 char buf[16] = {}; 130 ssize_t n; 131 132 /* Send data that will remain unread */ 133 send(self->client, "hello", 5, 0); 134 135 if (variant->socket_type == SOCK_DGRAM) { 136 /* No real connection, just close the server */ 137 close(self->server); 138 } else { 139 self->child = accept(self->server, NULL, NULL); 140 ASSERT_LT(-1, self->child); 141 142 /* Peer closes before client reads */ 143 close(self->child); 144 } 145 146 n = recv(self->client, buf, sizeof(buf), 0); 147 ASSERT_EQ(-1, n); 148 149 if (variant->socket_type == SOCK_STREAM || 150 variant->socket_type == SOCK_SEQPACKET) { 151 ASSERT_EQ(ECONNRESET, errno); 152 } else { 153 ASSERT_EQ(EAGAIN, errno); 154 } 155} 156 157/* Test 3: closing unaccepted (embryo) server socket should reset client. */ 158TEST_F(unix_sock, reset_closed_embryo) 159{ 160 char buf[16] = {}; 161 ssize_t n; 162 163 if (variant->socket_type == SOCK_DGRAM) { 164 snprintf(_metadata->results->reason, 165 sizeof(_metadata->results->reason), 166 "Test only applies to SOCK_STREAM and SOCK_SEQPACKET"); 167 exit(KSFT_XFAIL); 168 } 169 170 /* Close server without accept()ing */ 171 close(self->server); 172 173 n = recv(self->client, buf, sizeof(buf), 0); 174 175 ASSERT_EQ(-1, n); 176 ASSERT_EQ(ECONNRESET, errno); 177} 178 179TEST_HARNESS_MAIN 180