xref: /netbsd-src/external/gpl3/gdb/dist/gdb/nat/linux-namespaces.c (revision 0e2e28bced52bda3788c857106bde6c44d2df3b8)
1 /* Linux namespaces(7) support.
2 
3    Copyright (C) 2015-2023 Free Software Foundation, Inc.
4 
5    This file is part of GDB.
6 
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11 
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16 
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
19 
20 #include "gdbsupport/common-defs.h"
21 #include "nat/linux-namespaces.h"
22 #include "gdbsupport/filestuff.h"
23 #include <fcntl.h>
24 #include <sys/syscall.h>
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <sys/socket.h>
28 #include "gdbsupport/gdb_wait.h"
29 #include <signal.h>
30 #include <sched.h>
31 #include "gdbsupport/scope-exit.h"
32 
33 /* See nat/linux-namespaces.h.  */
34 bool debug_linux_namespaces;
35 
36 /* Handle systems without fork.  */
37 
38 static inline pid_t
39 do_fork (void)
40 {
41 #ifdef HAVE_FORK
42   return fork ();
43 #else
44   errno = ENOSYS;
45   return -1;
46 #endif
47 }
48 
49 /* Handle systems without setns.  */
50 
51 static inline int
52 do_setns (int fd, int nstype)
53 {
54 #ifdef HAVE_SETNS
55   return setns (fd, nstype);
56 #elif defined __NR_setns
57   return syscall (__NR_setns, fd, nstype);
58 #else
59   errno = ENOSYS;
60   return -1;
61 #endif
62 }
63 
64 /* Handle systems without MSG_CMSG_CLOEXEC.  */
65 
66 #ifndef MSG_CMSG_CLOEXEC
67 #define MSG_CMSG_CLOEXEC 0
68 #endif
69 
70 /* A Linux namespace.  */
71 
72 struct linux_ns
73 {
74   /* Filename of this namespace's entries in /proc/PID/ns.  */
75   const char *filename;
76 
77   /* Nonzero if this object has been initialized.  */
78   int initialized;
79 
80   /* Nonzero if this namespace is supported on this system.  */
81   int supported;
82 
83   /* ID of the namespace the calling process is in, used to
84      see if other processes share the namespace.  The code in
85      this file assumes that the calling process never changes
86      namespace.  */
87   ino_t id;
88 };
89 
90 /* Return the absolute filename of process PID's /proc/PID/ns
91    entry for namespace NS.  The returned value persists until
92    this function is next called.  */
93 
94 static const char *
95 linux_ns_filename (struct linux_ns *ns, int pid)
96 {
97   static char filename[PATH_MAX];
98 
99   gdb_assert (pid > 0);
100   xsnprintf (filename, sizeof (filename), "/proc/%d/ns/%s", pid,
101 	     ns->filename);
102 
103   return filename;
104 }
105 
106 /* Return a representation of the caller's TYPE namespace, or
107    NULL if TYPE namespaces are not supported on this system.  */
108 
109 static struct linux_ns *
110 linux_ns_get_namespace (enum linux_ns_type type)
111 {
112   static struct linux_ns namespaces[NUM_LINUX_NS_TYPES] =
113     {
114       { "ipc" },
115       { "mnt" },
116       { "net" },
117       { "pid" },
118       { "user" },
119       { "uts" },
120     };
121   struct linux_ns *ns;
122 
123   gdb_assert (type >= 0 && type < NUM_LINUX_NS_TYPES);
124   ns = &namespaces[type];
125 
126   if (!ns->initialized)
127     {
128       struct stat sb;
129 
130       if (stat (linux_ns_filename (ns, getpid ()), &sb) == 0)
131 	{
132 	  ns->id = sb.st_ino;
133 
134 	  ns->supported = 1;
135 	}
136 
137       ns->initialized = 1;
138     }
139 
140   return ns->supported ? ns : NULL;
141 }
142 
143 /* See nat/linux-namespaces.h.  */
144 
145 int
146 linux_ns_same (pid_t pid, enum linux_ns_type type)
147 {
148   struct linux_ns *ns = linux_ns_get_namespace (type);
149   const char *filename;
150   struct stat sb;
151 
152   /* If the kernel does not support TYPE namespaces then there's
153      effectively only one TYPE namespace that all processes on
154      the system share.  */
155   if (ns == NULL)
156     return 1;
157 
158   /* Stat PID's TYPE namespace entry to get the namespace ID.  This
159      might fail if the process died, or if we don't have the right
160      permissions (though we should be attached by this time so this
161      seems unlikely).  In any event, we can't make any decisions and
162      must throw.  */
163   filename = linux_ns_filename (ns, pid);
164   if (stat (filename, &sb) != 0)
165     perror_with_name (filename);
166 
167   return sb.st_ino == ns->id;
168 }
169 
170 /* We need to use setns(2) to handle filesystem access in mount
171    namespaces other than our own, but this isn't permitted for
172    multithreaded processes.  GDB is multithreaded when compiled
173    with Guile support, and may become multithreaded if compiled
174    with Python support.  We deal with this by spawning a single-
175    threaded helper process to access mount namespaces other than
176    our own.
177 
178    The helper process is started the first time a call to setns
179    is required.  The main process (GDB or gdbserver) communicates
180    with the helper via sockets, passing file descriptors where
181    necessary using SCM_RIGHTS.  Once started the helper process
182    runs until the main process terminates; when this happens the
183    helper will receive socket errors, notice that its parent died,
184    and exit accordingly (see mnsh_maybe_mourn_peer).
185 
186    The protocol is that the main process sends a request in a
187    single message, and the helper replies to every message it
188    receives with a single-message response.  If the helper
189    receives a message it does not understand it will reply with
190    a MNSH_MSG_ERROR message.  The main process checks all
191    responses it receives with gdb_assert, so if the main process
192    receives something unexpected (which includes MNSH_MSG_ERROR)
193    the main process will call internal_error.
194 
195    For avoidance of doubt, if the helper process receives a
196    message it doesn't handle it will reply with MNSH_MSG_ERROR.
197    If the main process receives MNSH_MSG_ERROR at any time then
198    it will call internal_error.  If internal_error causes the
199    main process to exit, the helper will notice this and also
200    exit.  The helper will not exit until the main process
201    terminates, so if the user continues through internal_error
202    the helper will still be there awaiting requests from the
203    main process.
204 
205    Messages in both directions have the following payload:
206 
207    - TYPE (enum mnsh_msg_type, always sent) - the message type.
208    - INT1 and
209    - INT2 (int, always sent, though not always used) - two
210 	   values whose meaning is message-type-dependent.
211 	   See enum mnsh_msg_type documentation below.
212    - FD (int, optional, sent using SCM_RIGHTS) - an open file
213 	 descriptor.
214    - BUF (unstructured data, optional) - some data with message-
215 	  type-dependent meaning.
216 
217    Note that the helper process is the child of a call to fork,
218    so all code in the helper must be async-signal-safe.  */
219 
220 /* Mount namespace helper message types.  */
221 
222 enum mnsh_msg_type
223   {
224     /* A communication error occurred.  Receipt of this message
225        by either end will cause an assertion failure in the main
226        process.  */
227     MNSH_MSG_ERROR,
228 
229     /* Requests, sent from the main process to the helper.  */
230 
231     /* A request that the helper call setns.  Arguments should
232        be passed in FD and INT1.  Helper should respond with a
233        MNSH_RET_INT.  */
234     MNSH_REQ_SETNS,
235 
236     /* A request that the helper call open.  Arguments should
237        be passed in BUF, INT1 and INT2.  The filename (in BUF)
238        should include a terminating NUL character.  The helper
239        should respond with a MNSH_RET_FD.  */
240     MNSH_REQ_OPEN,
241 
242     /* A request that the helper call unlink.  The single
243        argument (the filename) should be passed in BUF, and
244        should include a terminating NUL character.  The helper
245        should respond with a MNSH_RET_INT.  */
246     MNSH_REQ_UNLINK,
247 
248     /* A request that the helper call readlink.  The single
249        argument (the filename) should be passed in BUF, and
250        should include a terminating NUL character.  The helper
251        should respond with a MNSH_RET_INTSTR.  */
252     MNSH_REQ_READLINK,
253 
254     /* Responses, sent to the main process from the helper.  */
255 
256     /* Return an integer in INT1 and errno in INT2.  */
257     MNSH_RET_INT,
258 
259     /* Return a file descriptor in FD if one was opened or an
260        integer in INT1 otherwise.  Return errno in INT2.  */
261     MNSH_RET_FD,
262 
263     /* Return an integer in INT1, errno in INT2, and optionally
264        some data in BUF.  */
265     MNSH_RET_INTSTR,
266   };
267 
268 /* Print a string representation of a message using debug_printf.
269    This function is not async-signal-safe so should never be
270    called from the helper.  */
271 
272 static void
273 mnsh_debug_print_message (enum mnsh_msg_type type,
274 			  int fd, int int1, int int2,
275 			  const void *buf, int bufsiz)
276 {
277   gdb_byte *c = (gdb_byte *) buf;
278   gdb_byte *cl = c + bufsiz;
279 
280   switch (type)
281     {
282     case MNSH_MSG_ERROR:
283       debug_printf ("ERROR");
284       break;
285 
286     case MNSH_REQ_SETNS:
287       debug_printf ("SETNS");
288       break;
289 
290     case MNSH_REQ_OPEN:
291       debug_printf ("OPEN");
292       break;
293 
294     case MNSH_REQ_UNLINK:
295       debug_printf ("UNLINK");
296       break;
297 
298     case MNSH_REQ_READLINK:
299       debug_printf ("READLINK");
300       break;
301 
302     case MNSH_RET_INT:
303       debug_printf ("INT");
304       break;
305 
306     case MNSH_RET_FD:
307       debug_printf ("FD");
308       break;
309 
310     case MNSH_RET_INTSTR:
311       debug_printf ("INTSTR");
312       break;
313 
314     default:
315       debug_printf ("unknown-packet-%d", type);
316     }
317 
318   debug_printf (" %d %d %d \"", fd, int1, int2);
319 
320   for (; c < cl; c++)
321     debug_printf (*c >= ' ' && *c <= '~' ? "%c" : "\\%o", *c);
322 
323   debug_printf ("\"");
324 }
325 
326 /* Forward declaration.  */
327 
328 static void mnsh_maybe_mourn_peer (void);
329 
330 /* Send a message.  The argument SOCK is the file descriptor of the
331    sending socket, the other arguments are the payload to send.
332    Return the number of bytes sent on success.  Return -1 on failure
333    and set errno appropriately.  This function is called by both the
334    main process and the helper so must be async-signal-safe.  */
335 
336 static ssize_t
337 mnsh_send_message (int sock, enum mnsh_msg_type type,
338 		   int fd, int int1, int int2,
339 		   const void *buf, int bufsiz)
340 {
341   struct msghdr msg;
342   struct iovec iov[4];
343   char fdbuf[CMSG_SPACE (sizeof (fd))];
344   ssize_t size;
345 
346   /* Build the basic TYPE, INT1, INT2 message.  */
347   memset (&msg, 0, sizeof (msg));
348   msg.msg_iov = iov;
349 
350   iov[0].iov_base = &type;
351   iov[0].iov_len = sizeof (type);
352   iov[1].iov_base = &int1;
353   iov[1].iov_len = sizeof (int1);
354   iov[2].iov_base = &int2;
355   iov[2].iov_len = sizeof (int2);
356 
357   msg.msg_iovlen = 3;
358 
359   /* Append BUF if supplied.  */
360   if (buf != NULL && bufsiz > 0)
361     {
362       iov[3].iov_base = alloca (bufsiz);
363       memcpy (iov[3].iov_base, buf, bufsiz);
364       iov[3].iov_len = bufsiz;
365 
366       msg.msg_iovlen ++;
367     }
368 
369   /* Attach FD if supplied.  */
370   if (fd >= 0)
371     {
372       struct cmsghdr *cmsg;
373 
374       msg.msg_control = fdbuf;
375       msg.msg_controllen = sizeof (fdbuf);
376 
377       cmsg = CMSG_FIRSTHDR (&msg);
378       cmsg->cmsg_level = SOL_SOCKET;
379       cmsg->cmsg_type = SCM_RIGHTS;
380       cmsg->cmsg_len = CMSG_LEN (sizeof (int));
381 
382       memcpy (CMSG_DATA (cmsg), &fd, sizeof (int));
383 
384       msg.msg_controllen = cmsg->cmsg_len;
385     }
386 
387   /* Send the message.  */
388   size = sendmsg (sock, &msg, 0);
389 
390   if (size < 0)
391     mnsh_maybe_mourn_peer ();
392 
393   if (debug_linux_namespaces)
394     {
395       debug_printf ("mnsh: send: ");
396       mnsh_debug_print_message (type, fd, int1, int2, buf, bufsiz);
397       debug_printf (" -> %s\n", pulongest (size));
398     }
399 
400   return size;
401 }
402 
403 /* Receive a message.  The argument SOCK is the file descriptor of
404    the receiving socket, the other arguments point to storage for
405    the received payload.  Returns the number of bytes stored into
406    BUF on success, which may be zero in the event no BUF was sent.
407    Return -1 on failure and set errno appropriately.  This function
408    is called from both the main process and the helper and must be
409    async-signal-safe.  */
410 
411 static ssize_t
412 mnsh_recv_message (int sock, enum mnsh_msg_type *type,
413 		   int *fd, int *int1, int *int2,
414 		   void *buf, int bufsiz)
415 {
416   struct msghdr msg;
417   struct iovec iov[4];
418   char fdbuf[CMSG_SPACE (sizeof (*fd))];
419   struct cmsghdr *cmsg;
420   ssize_t size, fixed_size;
421   int i;
422 
423   /* Build the message to receive data into.  */
424   memset (&msg, 0, sizeof (msg));
425   msg.msg_iov = iov;
426 
427   iov[0].iov_base = type;
428   iov[0].iov_len = sizeof (*type);
429   iov[1].iov_base = int1;
430   iov[1].iov_len = sizeof (*int1);
431   iov[2].iov_base = int2;
432   iov[2].iov_len = sizeof (*int2);
433   iov[3].iov_base = buf;
434   iov[3].iov_len = bufsiz;
435 
436   msg.msg_iovlen = 4;
437 
438   for (fixed_size = i = 0; i < msg.msg_iovlen - 1; i++)
439     fixed_size += iov[i].iov_len;
440 
441   msg.msg_control = fdbuf;
442   msg.msg_controllen = sizeof (fdbuf);
443 
444   /* Receive the message.  */
445   size = recvmsg (sock, &msg, MSG_CMSG_CLOEXEC);
446   if (size < 0)
447     {
448       if (debug_linux_namespaces)
449 	debug_printf ("namespace-helper: recv failed (%s)\n",
450 		      pulongest (size));
451 
452       mnsh_maybe_mourn_peer ();
453 
454       return size;
455     }
456 
457   /* Check for truncation.  */
458   if (size < fixed_size || (msg.msg_flags & (MSG_TRUNC | MSG_CTRUNC)))
459     {
460       if (debug_linux_namespaces)
461 	debug_printf ("namespace-helper: recv truncated (%s 0x%x)\n",
462 		      pulongest (size), msg.msg_flags);
463 
464       mnsh_maybe_mourn_peer ();
465 
466       errno = EBADMSG;
467       return -1;
468     }
469 
470   /* Unpack the file descriptor if supplied.  */
471   cmsg = CMSG_FIRSTHDR (&msg);
472   if (cmsg != NULL
473       && cmsg->cmsg_len == CMSG_LEN (sizeof (int))
474       && cmsg->cmsg_level == SOL_SOCKET
475       && cmsg->cmsg_type == SCM_RIGHTS)
476     memcpy (fd, CMSG_DATA (cmsg), sizeof (int));
477   else
478     *fd = -1;
479 
480   if (debug_linux_namespaces)
481     {
482       debug_printf ("mnsh: recv: ");
483       mnsh_debug_print_message (*type, *fd, *int1, *int2, buf,
484 				size - fixed_size);
485       debug_printf ("\n");
486     }
487 
488   /* Return the number of bytes of data in BUF.  */
489   return size - fixed_size;
490 }
491 
492 /* Shortcuts for returning results from the helper.  */
493 
494 #define mnsh_return_int(sock, result, error) \
495   mnsh_send_message (sock, MNSH_RET_INT, -1, result, error, NULL, 0)
496 
497 #define mnsh_return_fd(sock, fd, error) \
498   mnsh_send_message (sock, MNSH_RET_FD, \
499 		     (fd) < 0 ? -1 : (fd), \
500 		     (fd) < 0 ? (fd) : 0, \
501 		     error, NULL, 0)
502 
503 #define mnsh_return_intstr(sock, result, buf, bufsiz, error) \
504   mnsh_send_message (sock, MNSH_RET_INTSTR, -1, result, error, \
505 		     buf, bufsiz)
506 
507 /* Handle a MNSH_REQ_SETNS message.  Must be async-signal-safe.  */
508 
509 static ssize_t
510 mnsh_handle_setns (int sock, int fd, int nstype)
511 {
512   int result = do_setns (fd, nstype);
513 
514   return mnsh_return_int (sock, result, errno);
515 }
516 
517 /* Handle a MNSH_REQ_OPEN message.  Must be async-signal-safe.  */
518 
519 static ssize_t
520 mnsh_handle_open (int sock, const char *filename,
521 		  int flags, mode_t mode)
522 {
523   scoped_fd fd = gdb_open_cloexec (filename, flags, mode);
524   return mnsh_return_fd (sock, fd.get (), errno);
525 }
526 
527 /* Handle a MNSH_REQ_UNLINK message.  Must be async-signal-safe.  */
528 
529 static ssize_t
530 mnsh_handle_unlink (int sock, const char *filename)
531 {
532   int result = unlink (filename);
533 
534   return mnsh_return_int (sock, result, errno);
535 }
536 
537 /* Handle a MNSH_REQ_READLINK message.  Must be async-signal-safe.  */
538 
539 static ssize_t
540 mnsh_handle_readlink (int sock, const char *filename)
541 {
542   char buf[PATH_MAX];
543   int len = readlink (filename, buf, sizeof (buf));
544 
545   return mnsh_return_intstr (sock, len,
546 			     buf, len < 0 ? 0 : len,
547 			     errno);
548 }
549 
550 /* The helper process.  Never returns.  Must be async-signal-safe.  */
551 
552 static void mnsh_main (int sock) ATTRIBUTE_NORETURN;
553 
554 static void
555 mnsh_main (int sock)
556 {
557   while (1)
558     {
559       enum mnsh_msg_type type;
560       int fd = -1, int1, int2;
561       char buf[PATH_MAX];
562       ssize_t size, response = -1;
563 
564       size = mnsh_recv_message (sock, &type,
565 				&fd, &int1, &int2,
566 				buf, sizeof (buf));
567 
568       if (size >= 0 && size < sizeof (buf))
569 	{
570 	  switch (type)
571 	    {
572 	    case MNSH_REQ_SETNS:
573 	      if (fd > 0)
574 		response = mnsh_handle_setns (sock, fd, int1);
575 	      break;
576 
577 	    case MNSH_REQ_OPEN:
578 	      if (size > 0 && buf[size - 1] == '\0')
579 		response = mnsh_handle_open (sock, buf, int1, int2);
580 	      break;
581 
582 	    case MNSH_REQ_UNLINK:
583 	      if (size > 0 && buf[size - 1] == '\0')
584 		response = mnsh_handle_unlink (sock, buf);
585 	      break;
586 
587 	    case MNSH_REQ_READLINK:
588 	      if (size > 0 && buf[size - 1] == '\0')
589 		response = mnsh_handle_readlink (sock, buf);
590 	      break;
591 
592 	    default:
593 	      break; /* Handled below.  */
594 	    }
595 	}
596 
597       /* Close any file descriptors we were passed.  */
598       if (fd >= 0)
599 	close (fd);
600 
601       /* Can't handle this message, bounce it back.  */
602       if (response < 0)
603 	{
604 	  if (size < 0)
605 	    size = 0;
606 
607 	  mnsh_send_message (sock, MNSH_MSG_ERROR,
608 			     -1, int1, int2, buf, size);
609 	}
610     }
611 }
612 
613 /* The mount namespace helper process.  */
614 
615 struct linux_mnsh
616 {
617   /* PID of helper.  */
618   pid_t pid;
619 
620   /* Socket for communication.  */
621   int sock;
622 
623   /* ID of the mount namespace the helper is currently in.  */
624   ino_t nsid;
625 };
626 
627 /* In the helper process this is set to the PID of the process that
628    created the helper (i.e. GDB or gdbserver).  In the main process
629    this is set to zero.  Used by mnsh_maybe_mourn_peer.  */
630 static int mnsh_creator_pid = 0;
631 
632 /* Return an object representing the mount namespace helper process.
633    If no mount namespace helper process has been started then start
634    one.  Return NULL if no mount namespace helper process could be
635    started.  */
636 
637 static struct linux_mnsh *
638 linux_mntns_get_helper (void)
639 {
640   static struct linux_mnsh *helper = NULL;
641 
642   if (helper == NULL)
643     {
644       static struct linux_mnsh h;
645       struct linux_ns *ns;
646       pid_t helper_creator = getpid ();
647       int sv[2];
648 
649       ns = linux_ns_get_namespace (LINUX_NS_MNT);
650       if (ns == NULL)
651 	return NULL;
652 
653       if (gdb_socketpair_cloexec (AF_UNIX, SOCK_STREAM, 0, sv) < 0)
654 	return NULL;
655 
656       h.pid = do_fork ();
657       if (h.pid < 0)
658 	{
659 	  int saved_errno = errno;
660 
661 	  close (sv[0]);
662 	  close (sv[1]);
663 
664 	  errno = saved_errno;
665 	  return NULL;
666 	}
667 
668       if (h.pid == 0)
669 	{
670 	  /* Child process.  */
671 	  close (sv[0]);
672 
673 	  mnsh_creator_pid = helper_creator;
674 
675 	  /* Debug printing isn't async-signal-safe.  */
676 	  debug_linux_namespaces = 0;
677 
678 	  mnsh_main (sv[1]);
679 	}
680 
681       /* Parent process.  */
682       close (sv[1]);
683 
684       helper = &h;
685       helper->sock = sv[0];
686       helper->nsid = ns->id;
687 
688       if (debug_linux_namespaces)
689 	debug_printf ("Started mount namespace helper process %d\n",
690 		      helper->pid);
691     }
692 
693   return helper;
694 }
695 
696 /* Check whether the other process died and act accordingly.  Called
697    whenever a socket error occurs, from both the main process and the
698    helper.  Must be async-signal-safe when called from the helper.  */
699 
700 static void
701 mnsh_maybe_mourn_peer (void)
702 {
703   if (mnsh_creator_pid != 0)
704     {
705       /* We're in the helper.  Check if our current parent is the
706 	 process that started us.  If it isn't, then our original
707 	 parent died and we've been reparented.  Exit immediately
708 	 if that's the case.  */
709       if (getppid () != mnsh_creator_pid)
710 	_exit (0);
711     }
712   else
713     {
714       /* We're in the main process.  */
715 
716       struct linux_mnsh *helper = linux_mntns_get_helper ();
717       int status;
718       pid_t pid;
719 
720       if (helper->pid < 0)
721 	{
722 	  /* We already mourned it.  */
723 	  return;
724 	}
725 
726       pid = waitpid (helper->pid, &status, WNOHANG);
727       if (pid == 0)
728 	{
729 	  /* The helper is still alive.  */
730 	  return;
731 	}
732       else if (pid == -1)
733 	{
734 	  if (errno == ECHILD)
735 	    warning (_("mount namespace helper vanished?"));
736 	  else
737 	    internal_warning (_("unhandled error %d"), errno);
738 	}
739       else if (pid == helper->pid)
740 	{
741 	  if (WIFEXITED (status))
742 	    warning (_("mount namespace helper exited with status %d"),
743 		     WEXITSTATUS (status));
744 	  else if (WIFSIGNALED (status))
745 	    warning (_("mount namespace helper killed by signal %d"),
746 		     WTERMSIG (status));
747 	  else
748 	    internal_warning (_("unhandled status %d"), status);
749 	}
750       else
751 	internal_warning (_("unknown pid %d"), pid);
752 
753       /* Something unrecoverable happened.  */
754       helper->pid = -1;
755     }
756 }
757 
758 /* Shortcuts for sending messages to the helper.  */
759 
760 #define mnsh_send_setns(helper, fd, nstype) \
761   mnsh_send_message (helper->sock, MNSH_REQ_SETNS, fd, nstype, 0, \
762 		     NULL, 0)
763 
764 #define mnsh_send_open(helper, filename, flags, mode) \
765   mnsh_send_message (helper->sock, MNSH_REQ_OPEN, -1, flags, mode, \
766 		     filename, strlen (filename) + 1)
767 
768 #define mnsh_send_unlink(helper, filename) \
769   mnsh_send_message (helper->sock, MNSH_REQ_UNLINK, -1, 0, 0, \
770 		     filename, strlen (filename) + 1)
771 
772 #define mnsh_send_readlink(helper, filename) \
773   mnsh_send_message (helper->sock, MNSH_REQ_READLINK, -1, 0, 0, \
774 		     filename, strlen (filename) + 1)
775 
776 /* Receive a message from the helper.  Issue an assertion failure if
777    the message isn't a correctly-formatted MNSH_RET_INT.  Set RESULT
778    and ERROR and return 0 on success.  Set errno and return -1 on
779    failure.  */
780 
781 static int
782 mnsh_recv_int (struct linux_mnsh *helper, int *result, int *error)
783 {
784   enum mnsh_msg_type type;
785   char buf[PATH_MAX];
786   ssize_t size;
787   int fd;
788 
789   size = mnsh_recv_message (helper->sock, &type, &fd,
790 			    result, error,
791 			    buf, sizeof (buf));
792   if (size < 0)
793     return -1;
794 
795   gdb_assert (type == MNSH_RET_INT);
796   gdb_assert (fd == -1);
797   gdb_assert (size == 0);
798 
799   return 0;
800 }
801 
802 /* Receive a message from the helper.  Issue an assertion failure if
803    the message isn't a correctly-formatted MNSH_RET_FD.  Set FD and
804    ERROR and return 0 on success.  Set errno and return -1 on
805    failure.  */
806 
807 static int
808 mnsh_recv_fd (struct linux_mnsh *helper, int *fd, int *error)
809 {
810   enum mnsh_msg_type type;
811   char buf[PATH_MAX];
812   ssize_t size;
813   int result;
814 
815   size = mnsh_recv_message (helper->sock, &type, fd,
816 			    &result, error,
817 			    buf, sizeof (buf));
818   if (size < 0)
819     return -1;
820 
821   gdb_assert (type == MNSH_RET_FD);
822   gdb_assert (size == 0);
823 
824   if (*fd < 0)
825     {
826       gdb_assert (result < 0);
827       *fd = result;
828     }
829 
830   return 0;
831 }
832 
833 /* Receive a message from the helper.  Issue an assertion failure if
834    the message isn't a correctly-formatted MNSH_RET_INTSTR.  Set
835    RESULT and ERROR and optionally store data in BUF, then return
836    the number of bytes stored in BUF on success (this may be zero).
837    Set errno and return -1 on error.  */
838 
839 static ssize_t
840 mnsh_recv_intstr (struct linux_mnsh *helper,
841 		  int *result, int *error,
842 		  void *buf, int bufsiz)
843 {
844   enum mnsh_msg_type type;
845   ssize_t size;
846   int fd;
847 
848   size = mnsh_recv_message (helper->sock, &type, &fd,
849 			    result, error,
850 			    buf, bufsiz);
851 
852   if (size < 0)
853     return -1;
854 
855   gdb_assert (type == MNSH_RET_INTSTR);
856   gdb_assert (fd == -1);
857 
858   return size;
859 }
860 
861 /* Return values for linux_mntns_access_fs.  */
862 
863 enum mnsh_fs_code
864   {
865     /* Something went wrong, errno is set.  */
866     MNSH_FS_ERROR = -1,
867 
868     /* The main process is in the correct mount namespace.
869        The caller should access the filesystem directly.  */
870     MNSH_FS_DIRECT,
871 
872     /* The helper is in the correct mount namespace.
873        The caller should access the filesystem via the helper.  */
874     MNSH_FS_HELPER
875   };
876 
877 /* Return a value indicating how the caller should access the
878    mount namespace of process PID.  */
879 
880 static enum mnsh_fs_code
881 linux_mntns_access_fs (pid_t pid)
882 {
883   struct linux_ns *ns;
884   struct stat sb;
885   struct linux_mnsh *helper;
886   ssize_t size;
887   int fd;
888 
889   if (pid == getpid ())
890     return MNSH_FS_DIRECT;
891 
892   ns = linux_ns_get_namespace (LINUX_NS_MNT);
893   if (ns == NULL)
894     return MNSH_FS_DIRECT;
895 
896   fd = gdb_open_cloexec (linux_ns_filename (ns, pid), O_RDONLY, 0).release ();
897   if (fd < 0)
898     return MNSH_FS_ERROR;
899 
900   SCOPE_EXIT
901     {
902       int save_errno = errno;
903       close (fd);
904       errno = save_errno;
905     };
906 
907   if (fstat (fd, &sb) != 0)
908     return MNSH_FS_ERROR;
909 
910   if (sb.st_ino == ns->id)
911     return MNSH_FS_DIRECT;
912 
913   helper = linux_mntns_get_helper ();
914   if (helper == NULL)
915     return MNSH_FS_ERROR;
916 
917   if (sb.st_ino != helper->nsid)
918     {
919       int result, error;
920 
921       size = mnsh_send_setns (helper, fd, 0);
922       if (size < 0)
923 	return MNSH_FS_ERROR;
924 
925       if (mnsh_recv_int (helper, &result, &error) != 0)
926 	return MNSH_FS_ERROR;
927 
928       if (result != 0)
929 	{
930 	  /* ENOSYS indicates that an entire function is unsupported
931 	     (it's not appropriate for our versions of open/unlink/
932 	     readlink to sometimes return with ENOSYS depending on how
933 	     they're called) so we convert ENOSYS to ENOTSUP if setns
934 	     fails.  */
935 	  if (error == ENOSYS)
936 	    error = ENOTSUP;
937 
938 	  errno = error;
939 	  return MNSH_FS_ERROR;
940 	}
941 
942       helper->nsid = sb.st_ino;
943     }
944 
945   return MNSH_FS_HELPER;
946 }
947 
948 /* See nat/linux-namespaces.h.  */
949 
950 int
951 linux_mntns_open_cloexec (pid_t pid, const char *filename,
952 			  int flags, mode_t mode)
953 {
954   enum mnsh_fs_code access = linux_mntns_access_fs (pid);
955   struct linux_mnsh *helper;
956   int fd, error;
957   ssize_t size;
958 
959   if (access == MNSH_FS_ERROR)
960     return -1;
961 
962   if (access == MNSH_FS_DIRECT)
963     return gdb_open_cloexec (filename, flags, mode).release ();
964 
965   gdb_assert (access == MNSH_FS_HELPER);
966 
967   helper = linux_mntns_get_helper ();
968 
969   size = mnsh_send_open (helper, filename, flags, mode);
970   if (size < 0)
971     return -1;
972 
973   if (mnsh_recv_fd (helper, &fd, &error) != 0)
974     return -1;
975 
976   if (fd < 0)
977     errno = error;
978 
979   return fd;
980 }
981 
982 /* See nat/linux-namespaces.h.  */
983 
984 int
985 linux_mntns_unlink (pid_t pid, const char *filename)
986 {
987   enum mnsh_fs_code access = linux_mntns_access_fs (pid);
988   struct linux_mnsh *helper;
989   int ret, error;
990   ssize_t size;
991 
992   if (access == MNSH_FS_ERROR)
993     return -1;
994 
995   if (access == MNSH_FS_DIRECT)
996     return unlink (filename);
997 
998   gdb_assert (access == MNSH_FS_HELPER);
999 
1000   helper = linux_mntns_get_helper ();
1001 
1002   size = mnsh_send_unlink (helper, filename);
1003   if (size < 0)
1004     return -1;
1005 
1006   if (mnsh_recv_int (helper, &ret, &error) != 0)
1007     return -1;
1008 
1009   if (ret != 0)
1010     errno = error;
1011 
1012   return ret;
1013 }
1014 
1015 /* See nat/linux-namespaces.h.  */
1016 
1017 ssize_t
1018 linux_mntns_readlink (pid_t pid, const char *filename,
1019 		      char *buf, size_t bufsiz)
1020 {
1021   enum mnsh_fs_code access = linux_mntns_access_fs (pid);
1022   struct linux_mnsh *helper;
1023   int ret, error;
1024   ssize_t size;
1025 
1026   if (access == MNSH_FS_ERROR)
1027     return -1;
1028 
1029   if (access == MNSH_FS_DIRECT)
1030     return readlink (filename, buf, bufsiz);
1031 
1032   gdb_assert (access == MNSH_FS_HELPER);
1033 
1034   helper = linux_mntns_get_helper ();
1035 
1036   size = mnsh_send_readlink (helper, filename);
1037   if (size < 0)
1038     return -1;
1039 
1040   size = mnsh_recv_intstr (helper, &ret, &error, buf, bufsiz);
1041 
1042   if (size < 0)
1043     {
1044       ret = -1;
1045       errno = error;
1046     }
1047   else
1048     gdb_assert (size == ret);
1049 
1050   return ret;
1051 }
1052