xref: /linux/tools/testing/selftests/net/af_unix/unix_listen.c (revision fab183d632628381b466a41479489541ac0e29a0)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Tests for the state checks in AF_UNIX listen().
4  *
5  * The central case is a regression test: listen() on a bound socket that
6  * is already connected (i.e. not in TCP_CLOSE or TCP_LISTEN state) must
7  * fail with EINVAL.  A prior change accidentally let it return success
8  * without doing anything, because a helper called in between reset the
9  * error code to 0.  The neighbouring checks (unbound, already listening)
10  * are tested too so they cannot silently regress the same way.
11  *
12  * Every case runs for both listenable socket types (SOCK_STREAM and
13  * SOCK_SEQPACKET) and both pathname and abstract addresses.
14  */
15 #define _GNU_SOURCE
16 
17 #include <errno.h>
18 #include <stddef.h>
19 #include <stdio.h>
20 #include <string.h>
21 #include <unistd.h>
22 
23 #include <sys/socket.h>
24 #include <sys/un.h>
25 
26 #include "kselftest_harness.h"
27 
28 #define SK_NAME		"unix_listen_sk"
29 #define SRV_NAME	"unix_listen_srv"
30 
FIXTURE(unix_listen)31 FIXTURE(unix_listen)
32 {
33 	int sk;			/* socket under test */
34 	int server;		/* a listening peer, when a test needs one */
35 	struct sockaddr_un addr, srv_addr;
36 	socklen_t addrlen, srv_addrlen;
37 };
38 
FIXTURE_VARIANT(unix_listen)39 FIXTURE_VARIANT(unix_listen)
40 {
41 	int type;
42 	int abstract;
43 };
44 
FIXTURE_VARIANT_ADD(unix_listen,stream_pathname)45 FIXTURE_VARIANT_ADD(unix_listen, stream_pathname)
46 {
47 	.type = SOCK_STREAM,
48 	.abstract = 0,
49 };
50 
FIXTURE_VARIANT_ADD(unix_listen,stream_abstract)51 FIXTURE_VARIANT_ADD(unix_listen, stream_abstract)
52 {
53 	.type = SOCK_STREAM,
54 	.abstract = 1,
55 };
56 
FIXTURE_VARIANT_ADD(unix_listen,seqpacket_pathname)57 FIXTURE_VARIANT_ADD(unix_listen, seqpacket_pathname)
58 {
59 	.type = SOCK_SEQPACKET,
60 	.abstract = 0,
61 };
62 
FIXTURE_VARIANT_ADD(unix_listen,seqpacket_abstract)63 FIXTURE_VARIANT_ADD(unix_listen, seqpacket_abstract)
64 {
65 	.type = SOCK_SEQPACKET,
66 	.abstract = 1,
67 };
68 
69 /* Fill @addr with a pathname or abstract address named @name. */
unix_set_addr(struct sockaddr_un * addr,const char * name,int abstract)70 static socklen_t unix_set_addr(struct sockaddr_un *addr, const char *name,
71 			       int abstract)
72 {
73 	size_t len = strlen(name);
74 
75 	memset(addr, 0, sizeof(*addr));
76 	addr->sun_family = AF_UNIX;
77 	/* An abstract address leads with a NUL and has no filesystem entry. */
78 	memcpy(addr->sun_path + (abstract ? 1 : 0), name, len);
79 
80 	return offsetof(struct sockaddr_un, sun_path) + len + 1;
81 }
82 
FIXTURE_SETUP(unix_listen)83 FIXTURE_SETUP(unix_listen)
84 {
85 	self->sk = -1;
86 	self->server = -1;
87 	self->addrlen = unix_set_addr(&self->addr, SK_NAME, variant->abstract);
88 	self->srv_addrlen = unix_set_addr(&self->srv_addr, SRV_NAME,
89 					  variant->abstract);
90 }
91 
FIXTURE_TEARDOWN(unix_listen)92 FIXTURE_TEARDOWN(unix_listen)
93 {
94 	if (self->sk >= 0)
95 		close(self->sk);
96 	if (self->server >= 0)
97 		close(self->server);
98 
99 	/* Pathname sockets leave a filesystem entry behind; abstract ones do not. */
100 	if (!variant->abstract) {
101 		remove(SK_NAME);
102 		remove(SRV_NAME);
103 	}
104 }
105 
106 /* A bound socket in TCP_CLOSE is the normal, allowed case. */
TEST_F(unix_listen,bound_is_ok)107 TEST_F(unix_listen, bound_is_ok)
108 {
109 	int err;
110 
111 	self->sk = socket(AF_UNIX, variant->type, 0);
112 	ASSERT_LE(0, self->sk);
113 
114 	err = bind(self->sk, (struct sockaddr *)&self->addr, self->addrlen);
115 	ASSERT_EQ(0, err);
116 
117 	err = listen(self->sk, 8);
118 	EXPECT_EQ(0, err);
119 }
120 
121 /* Listening again on an already-listening socket (TCP_LISTEN) is allowed. */
TEST_F(unix_listen,relisten_is_ok)122 TEST_F(unix_listen, relisten_is_ok)
123 {
124 	int err;
125 
126 	self->sk = socket(AF_UNIX, variant->type, 0);
127 	ASSERT_LE(0, self->sk);
128 
129 	err = bind(self->sk, (struct sockaddr *)&self->addr, self->addrlen);
130 	ASSERT_EQ(0, err);
131 
132 	err = listen(self->sk, 8);
133 	ASSERT_EQ(0, err);
134 
135 	err = listen(self->sk, 16);
136 	EXPECT_EQ(0, err);
137 }
138 
139 /* listen() on an unbound socket fails: there is nothing to listen on. */
TEST_F(unix_listen,unbound_is_einval)140 TEST_F(unix_listen, unbound_is_einval)
141 {
142 	int err;
143 
144 	self->sk = socket(AF_UNIX, variant->type, 0);
145 	ASSERT_LE(0, self->sk);
146 
147 	err = listen(self->sk, 8);
148 	EXPECT_EQ(-1, err);
149 	EXPECT_EQ(EINVAL, errno);
150 }
151 
152 /*
153  * The regression: a bound socket that has already been connected is not in
154  * TCP_CLOSE or TCP_LISTEN, so listen() must reject it with EINVAL rather
155  * than quietly succeeding.
156  */
TEST_F(unix_listen,connected_is_einval)157 TEST_F(unix_listen, connected_is_einval)
158 {
159 	int err;
160 
161 	self->server = socket(AF_UNIX, variant->type, 0);
162 	ASSERT_LE(0, self->server);
163 
164 	err = bind(self->server, (struct sockaddr *)&self->srv_addr,
165 		   self->srv_addrlen);
166 	ASSERT_EQ(0, err);
167 
168 	err = listen(self->server, 8);
169 	ASSERT_EQ(0, err);
170 
171 	self->sk = socket(AF_UNIX, variant->type, 0);
172 	ASSERT_LE(0, self->sk);
173 
174 	/* Bind first so the unbound check does not mask the state check. */
175 	err = bind(self->sk, (struct sockaddr *)&self->addr, self->addrlen);
176 	ASSERT_EQ(0, err);
177 
178 	err = connect(self->sk, (struct sockaddr *)&self->srv_addr,
179 		      self->srv_addrlen);
180 	ASSERT_EQ(0, err);
181 
182 	err = listen(self->sk, 8);
183 	EXPECT_EQ(-1, err);
184 	EXPECT_EQ(EINVAL, errno);
185 }
186 
187 TEST_HARNESS_MAIN
188