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