1 /* Test svc_register/svc_unregister rpcbind interaction (bug 5010).
2    Copyright (C) 2017-2021 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4 
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.
9 
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.
14 
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/>.  */
18 
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.  */
24 
25 #include <errno.h>
26 #include <netinet/in.h>
27 #include <rpc/clnt.h>
28 #include <rpc/pmap_prot.h>
29 #include <rpc/svc.h>
30 #include <signal.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>
38 #include <sys/wait.h>
39 #include <unistd.h>
40 
41 #include <libc-symbols.h>
42 #include <shlib-compat.h>
43 
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);
47 
48 /* Server callback for the unused RPC service which is registered and
49    unregistered.  */
50 static void
server_dispatch(struct svc_req * request,SVCXPRT * transport)51 server_dispatch (struct svc_req *request, SVCXPRT *transport)
52 {
53   FAIL_EXIT1 ("server_dispatch called");
54 }
55 
56 /* The port on which rpcbind listens for incoming requests.  */
57 static inline struct sockaddr_in
rpcbind_address(void)58 rpcbind_address (void)
59 {
60   return (struct sockaddr_in)
61     {
62       .sin_family = AF_INET,
63       .sin_addr.s_addr = htonl (INADDR_LOOPBACK),
64       .sin_port = htons (PMAPPORT)
65     };
66 }
67 
68 /* Data provided by the test server after running the test, to see
69    that the expected calls (and only those) happened.  */
70 struct test_state
71 {
72   bool_t set_called;
73   bool_t unset_called;
74 };
75 
76 static bool_t
xdr_test_state(XDR * xdrs,void * data,...)77 xdr_test_state (XDR *xdrs, void *data, ...)
78 {
79   struct test_state *p = data;
80   return xdr_bool (xdrs, &p->set_called)
81     && xdr_bool (xdrs, &p->unset_called);
82 }
83 
84 enum
85 {
86   /* Coordinates of our test service.  These numbers are
87      arbitrary.  */
88   PROGNUM = 123,
89   VERSNUM = 456,
90 
91   /* Extension for this test.  */
92   PROC_GET_STATE_AND_EXIT = 10760
93 };
94 
95 /* Dummy implementation of the rpcbind service, with the
96    PROC_GET_STATE_AND_EXIT extension.  */
97 static void
rpcbind_dispatch(struct svc_req * request,SVCXPRT * transport)98 rpcbind_dispatch (struct svc_req *request, SVCXPRT *transport)
99 {
100   static struct test_state state = { 0, };
101 
102   if (test_verbose)
103     printf ("info: rpcbind request %lu\n", request->rq_proc);
104 
105   switch (request->rq_proc)
106     {
107     case PMAPPROC_SET:
108     case PMAPPROC_UNSET:
109       TEST_VERIFY (state.set_called == (request->rq_proc == PMAPPROC_UNSET));
110       TEST_VERIFY (!state.unset_called);
111 
112       struct pmap query = { 0, };
113       TEST_VERIFY
114         (svc_getargs (transport, (xdrproc_t) xdr_pmap, (void *) &query));
115       if (test_verbose)
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);
120 
121       if (request->rq_proc == PMAPPROC_SET)
122         state.set_called = TRUE;
123       else
124         state.unset_called = TRUE;
125 
126       bool_t result = TRUE;
127       TEST_VERIFY (svc_sendreply (transport,
128                                   (xdrproc_t) xdr_bool, (void *) &result));
129       break;
130 
131     case PROC_GET_STATE_AND_EXIT:
132       TEST_VERIFY (svc_sendreply (transport,
133                                   xdr_test_state, (void *) &state));
134       _exit (0);
135       break;
136 
137     default:
138       FAIL_EXIT1 ("invalid rq_proc value: %lu", request->rq_proc);
139     }
140 }
141 
142 /* Run the rpcbind test server.  */
143 static void
run_rpcbind(int rpcbind_sock)144 run_rpcbind (int rpcbind_sock)
145 {
146   SVCXPRT *rpcbind_transport = svcudp_create (rpcbind_sock);
147   TEST_VERIFY (svc_register (rpcbind_transport, PMAPPROG, PMAPVERS,
148                              rpcbind_dispatch,
149                              /* Do not register with rpcbind.  */
150                              0));
151   svc_run ();
152 }
153 
154 /* Call out to the rpcbind test server to retrieve the test status
155    information.  */
156 static struct test_state
get_test_state(void)157 get_test_state (void)
158 {
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}))
168                == RPC_SUCCESS);
169   clnt_destroy (client);
170   return result;
171 }
172 
173 /* Used by test_server_thread to receive test parameters.  */
174 struct test_server_args
175 {
176   bool use_rpcbind;
177   bool use_unregister;
178 };
179 
180 /* RPC test server.  Used to verify the svc_unregister behavior during
181    thread cleanup.  */
182 static void *
test_server_thread(void * closure)183 test_server_thread (void *closure)
184 {
185   struct test_server_args *args = closure;
186   SVCXPRT *transport = svcudp_create (RPC_ANYSOCK);
187   int protocol;
188   if (args->use_rpcbind)
189     protocol = IPPROTO_UDP;
190   else
191     /* Do not register with rpcbind.  */
192     protocol = 0;
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);
198   return NULL;
199 }
200 
201 static int
do_test(void)202 do_test (void)
203 {
204   support_become_root ();
205   support_enter_network_namespace ();
206 
207   /* Try to bind to the rpcbind port.  */
208   int rpcbind_sock = xsocket (AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
209   {
210     struct sockaddr_in sin = rpcbind_address ();
211     if (bind (rpcbind_sock, (struct sockaddr *) &sin, sizeof (sin)) != 0)
212       {
213         /* If the port is not available, we cannot run this test.  */
214         printf ("warning: could not bind to rpcbind port %d: %m\n",
215                 (int) PMAPPORT);
216         return EXIT_UNSUPPORTED;
217       }
218   }
219 
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)
223         {
224           if (test_verbose)
225             printf ("info: * use_thread=%d use_rpcbind=%d use_unregister=%d\n",
226                     use_thread, use_rpcbind, use_unregister);
227 
228           /* Create the subprocess which runs the actual test.  The
229              kernel will queue the UDP packets to the rpcbind
230              process.  */
231           pid_t svc_pid = xfork ();
232           if (svc_pid == 0)
233             {
234               struct test_server_args args =
235                 {
236                   .use_rpcbind = use_rpcbind,
237                   .use_unregister = use_unregister,
238                 };
239               if (use_thread)
240                 xpthread_join (xpthread_create
241                                (NULL, test_server_thread, &args));
242               else
243                 test_server_thread (&args);
244               /* We cannnot use _exit here because we want to test the
245                  process cleanup.  */
246               exit (0);
247             }
248 
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);
253 
254           int status;
255           xwaitpid (svc_pid, &status, 0);
256           TEST_VERIFY (WIFEXITED (status) && WEXITSTATUS (status) == 0);
257 
258           if (!use_rpcbind)
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
265                reply.  */
266             usleep (300 * 1000);
267 
268           struct test_state state = get_test_state ();
269           if (use_rpcbind)
270             {
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);
276               else
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_subfreeres
280                    callback, and this only happens when running under
281                    memory debuggers such as valgrind.  */
282                 TEST_VERIFY (!state.unset_called);
283             }
284           else
285             {
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);
290             }
291 
292           xwaitpid (rpcbind_pid, &status, 0);
293           TEST_VERIFY (WIFEXITED (status) && WEXITSTATUS (status) == 0);
294         }
295 
296   return 0;
297 }
298 
299 #include <support/test-driver.c>
300