1 /* Test svc_register/svc_unregister rpcbind interaction (bug 5010).
2 Copyright (C) 2017-2024 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <https://www.gnu.org/licenses/>. */
19 /* This test uses a stub rpcbind server (implemented in a child
20 process using rpcbind_dispatch/run_rpcbind) to check how RPC
21 services are registered and unregistered using the rpcbind
22 protocol. For each subtest, a separate rpcbind test server is
23 spawned and terminated. */
26 #include <netinet/in.h>
28 #include <rpc/pmap_prot.h>
31 #include <support/check.h>
32 #include <support/namespace.h>
33 #include <support/test-driver.h>
34 #include <support/xsocket.h>
35 #include <support/xthread.h>
36 #include <support/xunistd.h>
37 #include <sys/socket.h>
41 #include <libc-symbols.h>
42 #include <shlib-compat.h>
44 /* These functions are only available as compat symbols. */
45 compat_symbol_reference (libc
, xdr_pmap
, xdr_pmap
, GLIBC_2_0
);
46 compat_symbol_reference (libc
, svc_unregister
, svc_unregister
, GLIBC_2_0
);
48 /* Server callback for the unused RPC service which is registered and
51 server_dispatch (struct svc_req
*request
, SVCXPRT
*transport
)
53 FAIL_EXIT1 ("server_dispatch called");
56 /* The port on which rpcbind listens for incoming requests. */
57 static inline struct sockaddr_in
58 rpcbind_address (void)
60 return (struct sockaddr_in
)
62 .sin_family
= AF_INET
,
63 .sin_addr
.s_addr
= htonl (INADDR_LOOPBACK
),
64 .sin_port
= htons (PMAPPORT
)
68 /* Data provided by the test server after running the test, to see
69 that the expected calls (and only those) happened. */
77 xdr_test_state (XDR
*xdrs
, void *data
, ...)
79 struct test_state
*p
= data
;
80 return xdr_bool (xdrs
, &p
->set_called
)
81 && xdr_bool (xdrs
, &p
->unset_called
);
86 /* Coordinates of our test service. These numbers are
91 /* Extension for this test. */
92 PROC_GET_STATE_AND_EXIT
= 10760
95 /* Dummy implementation of the rpcbind service, with the
96 PROC_GET_STATE_AND_EXIT extension. */
98 rpcbind_dispatch (struct svc_req
*request
, SVCXPRT
*transport
)
100 static struct test_state state
= { 0, };
103 printf ("info: rpcbind request %lu\n", request
->rq_proc
);
105 switch (request
->rq_proc
)
109 TEST_VERIFY (state
.set_called
== (request
->rq_proc
== PMAPPROC_UNSET
));
110 TEST_VERIFY (!state
.unset_called
);
112 struct pmap query
= { 0, };
114 (svc_getargs (transport
, (xdrproc_t
) xdr_pmap
, (void *) &query
));
116 printf (" pm_prog=%lu pm_vers=%lu pm_prot=%lu pm_port=%lu\n",
117 query
.pm_prog
, query
.pm_vers
, query
.pm_prot
, query
.pm_port
);
118 TEST_VERIFY (query
.pm_prog
== PROGNUM
);
119 TEST_VERIFY (query
.pm_vers
== VERSNUM
);
121 if (request
->rq_proc
== PMAPPROC_SET
)
122 state
.set_called
= TRUE
;
124 state
.unset_called
= TRUE
;
126 bool_t result
= TRUE
;
127 TEST_VERIFY (svc_sendreply (transport
,
128 (xdrproc_t
) xdr_bool
, (void *) &result
));
131 case PROC_GET_STATE_AND_EXIT
:
132 TEST_VERIFY (svc_sendreply (transport
,
133 xdr_test_state
, (void *) &state
));
138 FAIL_EXIT1 ("invalid rq_proc value: %lu", request
->rq_proc
);
142 /* Run the rpcbind test server. */
144 run_rpcbind (int rpcbind_sock
)
146 SVCXPRT
*rpcbind_transport
= svcudp_create (rpcbind_sock
);
147 TEST_VERIFY (svc_register (rpcbind_transport
, PMAPPROG
, PMAPVERS
,
149 /* Do not register with rpcbind. */
154 /* Call out to the rpcbind test server to retrieve the test status
156 static struct test_state
157 get_test_state (void)
159 int socket
= RPC_ANYSOCK
;
160 struct sockaddr_in address
= rpcbind_address ();
161 CLIENT
*client
= clntudp_create
162 (&address
, PMAPPROG
, PMAPVERS
, (struct timeval
) { 1, 0}, &socket
);
163 struct test_state result
= { 0 };
164 TEST_VERIFY (clnt_call (client
, PROC_GET_STATE_AND_EXIT
,
165 (xdrproc_t
) xdr_void
, NULL
,
166 xdr_test_state
, (void *) &result
,
167 ((struct timeval
) { 3, 0}))
169 clnt_destroy (client
);
173 /* Used by test_server_thread to receive test parameters. */
174 struct test_server_args
180 /* RPC test server. Used to verify the svc_unregister behavior during
183 test_server_thread (void *closure
)
185 struct test_server_args
*args
= closure
;
186 SVCXPRT
*transport
= svcudp_create (RPC_ANYSOCK
);
188 if (args
->use_rpcbind
)
189 protocol
= IPPROTO_UDP
;
191 /* Do not register with rpcbind. */
193 TEST_VERIFY (svc_register (transport
, PROGNUM
, VERSNUM
,
194 server_dispatch
, protocol
));
195 if (args
->use_unregister
)
196 svc_unregister (PROGNUM
, VERSNUM
);
197 SVC_DESTROY (transport
);
204 support_become_root ();
205 support_enter_network_namespace ();
207 /* Try to bind to the rpcbind port. */
208 int rpcbind_sock
= xsocket (AF_INET
, SOCK_DGRAM
| SOCK_CLOEXEC
, 0);
210 struct sockaddr_in sin
= rpcbind_address ();
211 if (bind (rpcbind_sock
, (struct sockaddr
*) &sin
, sizeof (sin
)) != 0)
213 /* If the port is not available, we cannot run this test. */
214 printf ("warning: could not bind to rpcbind port %d: %m\n",
216 return EXIT_UNSUPPORTED
;
220 for (int use_thread
= 0; use_thread
< 2; ++use_thread
)
221 for (int use_rpcbind
= 0; use_rpcbind
< 2; ++use_rpcbind
)
222 for (int use_unregister
= 0; use_unregister
< 2; ++use_unregister
)
225 printf ("info: * use_thread=%d use_rpcbind=%d use_unregister=%d\n",
226 use_thread
, use_rpcbind
, use_unregister
);
228 /* Create the subprocess which runs the actual test. The
229 kernel will queue the UDP packets to the rpcbind
231 pid_t svc_pid
= xfork ();
234 struct test_server_args args
=
236 .use_rpcbind
= use_rpcbind
,
237 .use_unregister
= use_unregister
,
240 xpthread_join (xpthread_create
241 (NULL
, test_server_thread
, &args
));
243 test_server_thread (&args
);
244 /* We cannot use _exit here because we want to test the
249 /* Create the subprocess for the rpcbind test server. */
250 pid_t rpcbind_pid
= xfork ();
251 if (rpcbind_pid
== 0)
252 run_rpcbind (rpcbind_sock
);
255 xwaitpid (svc_pid
, &status
, 0);
256 TEST_VERIFY (WIFEXITED (status
) && WEXITSTATUS (status
) == 0);
259 /* Wait a bit, to see if the packet arrives on the rpcbind
260 port. The choice is of the timeout is arbitrary, but
261 should be long enough even for slow/busy systems. For
262 the use_rpcbind case, waiting on svc_pid above makes
263 sure that the test server has responded because
264 svc_register/svc_unregister are supposed to wait for a
268 struct test_state state
= get_test_state ();
271 TEST_VERIFY (state
.set_called
);
272 if (use_thread
|| use_unregister
)
273 /* Thread cleanup or explicit svc_unregister will
274 result in a rpcbind unset RPC call. */
275 TEST_VERIFY (state
.unset_called
);
277 /* This is arguably a bug: Regular process termination
278 does not unregister the service with rpcbind. The
279 unset rpcbind call happens from a __libc_freeres,
280 and this only happens when running under memory debuggers
282 TEST_VERIFY (!state
.unset_called
);
286 /* If rpcbind registration is not requested, we do not
287 expect any rpcbind calls. */
288 TEST_VERIFY (!state
.set_called
);
289 TEST_VERIFY (!state
.unset_called
);
292 xwaitpid (rpcbind_pid
, &status
, 0);
293 TEST_VERIFY (WIFEXITED (status
) && WEXITSTATUS (status
) == 0);
299 #include <support/test-driver.c>