]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - gdb/nat/linux-namespaces.c
Automatic Copyright Year update after running gdb/copyright.py
[thirdparty/binutils-gdb.git] / gdb / nat / linux-namespaces.c
CommitLineData
4b8b5e72
GB
1/* Linux namespaces(7) support.
2
4a94e368 3 Copyright (C) 2015-2022 Free Software Foundation, Inc.
4b8b5e72
GB
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
268a13a5 20#include "gdbsupport/common-defs.h"
4b8b5e72 21#include "nat/linux-namespaces.h"
268a13a5 22#include "gdbsupport/filestuff.h"
4b8b5e72
GB
23#include <fcntl.h>
24#include <sys/syscall.h>
25#include <sys/types.h>
26#include <sys/stat.h>
27#include <sys/socket.h>
268a13a5 28#include "gdbsupport/gdb_wait.h"
4b8b5e72
GB
29#include <signal.h>
30#include <sched.h>
268a13a5 31#include "gdbsupport/scope-exit.h"
4b8b5e72
GB
32
33/* See nat/linux-namespaces.h. */
491144b5 34bool debug_linux_namespaces;
4b8b5e72 35
eb0edac8
GB
36/* Handle systems without fork. */
37
38static inline pid_t
39do_fork (void)
40{
41#ifdef HAVE_FORK
42 return fork ();
43#else
44 errno = ENOSYS;
45 return -1;
46#endif
47}
48
4b8b5e72
GB
49/* Handle systems without setns. */
50
99fe86f7
PB
51static inline int
52do_setns (int fd, int nstype)
4b8b5e72 53{
99fe86f7
PB
54#ifdef HAVE_SETNS
55 return setns (fd, nstype);
56#elif defined __NR_setns
4b8b5e72
GB
57 return syscall (__NR_setns, fd, nstype);
58#else
59 errno = ENOSYS;
60 return -1;
61#endif
62}
4b8b5e72 63
4da680ad
ME
64/* Handle systems without MSG_CMSG_CLOEXEC. */
65
66#ifndef MSG_CMSG_CLOEXEC
67#define MSG_CMSG_CLOEXEC 0
68#endif
69
4b8b5e72
GB
70/* A Linux namespace. */
71
72struct 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
94static const char *
95linux_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
109static struct linux_ns *
110linux_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
145int
146linux_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
dda83cd7 210 values whose meaning is message-type-dependent.
4b8b5e72
GB
211 See enum mnsh_msg_type documentation below.
212 - FD (int, optional, sent using SCM_RIGHTS) - an open file
dda83cd7 213 descriptor.
4b8b5e72 214 - BUF (unstructured data, optional) - some data with message-
dda83cd7 215 type-dependent meaning.
4b8b5e72
GB
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
222enum 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
272static void
273mnsh_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
328static 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
336static ssize_t
337mnsh_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);
6449ed0d 397 debug_printf (" -> %s\n", pulongest (size));
4b8b5e72
GB
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
411static ssize_t
412mnsh_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)
6449ed0d
GB
449 debug_printf ("namespace-helper: recv failed (%s)\n",
450 pulongest (size));
4b8b5e72
GB
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)
6449ed0d
GB
461 debug_printf ("namespace-helper: recv truncated (%s 0x%x)\n",
462 pulongest (size), msg.msg_flags);
4b8b5e72
GB
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
509static ssize_t
510mnsh_handle_setns (int sock, int fd, int nstype)
511{
99fe86f7 512 int result = do_setns (fd, nstype);
4b8b5e72
GB
513
514 return mnsh_return_int (sock, result, errno);
515}
516
517/* Handle a MNSH_REQ_OPEN message. Must be async-signal-safe. */
518
519static ssize_t
520mnsh_handle_open (int sock, const char *filename,
521 int flags, mode_t mode)
522{
13084383
SM
523 scoped_fd fd = gdb_open_cloexec (filename, flags, mode);
524 return mnsh_return_fd (sock, fd.get (), errno);
4b8b5e72
GB
525}
526
527/* Handle a MNSH_REQ_UNLINK message. Must be async-signal-safe. */
528
529static ssize_t
530mnsh_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
539static ssize_t
540mnsh_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
552static void mnsh_main (int sock) ATTRIBUTE_NORETURN;
553
554static void
555mnsh_main (int sock)
556{
557 while (1)
558 {
559 enum mnsh_msg_type type;
550105b7 560 int fd = -1, int1, int2;
4b8b5e72
GB
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
615struct 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. */
630static 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
637static struct linux_mnsh *
638linux_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
eb0edac8 656 h.pid = do_fork ();
4b8b5e72
GB
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
700static void
701mnsh_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 (__FILE__, __LINE__,
738 _("unhandled error %d"), errno);
739 }
740 else if (pid == helper->pid)
741 {
742 if (WIFEXITED (status))
743 warning (_("mount namespace helper exited with status %d"),
744 WEXITSTATUS (status));
745 else if (WIFSIGNALED (status))
746 warning (_("mount namespace helper killed by signal %d"),
747 WTERMSIG (status));
748 else
749 internal_warning (__FILE__, __LINE__,
750 _("unhandled status %d"), status);
751 }
752 else
753 internal_warning (__FILE__, __LINE__,
754 _("unknown pid %d"), pid);
755
756 /* Something unrecoverable happened. */
757 helper->pid = -1;
758 }
759}
760
761/* Shortcuts for sending messages to the helper. */
762
763#define mnsh_send_setns(helper, fd, nstype) \
764 mnsh_send_message (helper->sock, MNSH_REQ_SETNS, fd, nstype, 0, \
765 NULL, 0)
766
767#define mnsh_send_open(helper, filename, flags, mode) \
768 mnsh_send_message (helper->sock, MNSH_REQ_OPEN, -1, flags, mode, \
24b21115 769 filename, strlen (filename) + 1)
4b8b5e72
GB
770
771#define mnsh_send_unlink(helper, filename) \
772 mnsh_send_message (helper->sock, MNSH_REQ_UNLINK, -1, 0, 0, \
24b21115 773 filename, strlen (filename) + 1)
4b8b5e72
GB
774
775#define mnsh_send_readlink(helper, filename) \
776 mnsh_send_message (helper->sock, MNSH_REQ_READLINK, -1, 0, 0, \
24b21115 777 filename, strlen (filename) + 1)
4b8b5e72
GB
778
779/* Receive a message from the helper. Issue an assertion failure if
780 the message isn't a correctly-formatted MNSH_RET_INT. Set RESULT
781 and ERROR and return 0 on success. Set errno and return -1 on
782 failure. */
783
784static int
785mnsh_recv_int (struct linux_mnsh *helper, int *result, int *error)
786{
787 enum mnsh_msg_type type;
788 char buf[PATH_MAX];
789 ssize_t size;
790 int fd;
791
792 size = mnsh_recv_message (helper->sock, &type, &fd,
793 result, error,
794 buf, sizeof (buf));
795 if (size < 0)
796 return -1;
797
798 gdb_assert (type == MNSH_RET_INT);
799 gdb_assert (fd == -1);
800 gdb_assert (size == 0);
801
802 return 0;
803}
804
805/* Receive a message from the helper. Issue an assertion failure if
806 the message isn't a correctly-formatted MNSH_RET_FD. Set FD and
807 ERROR and return 0 on success. Set errno and return -1 on
808 failure. */
809
810static int
811mnsh_recv_fd (struct linux_mnsh *helper, int *fd, int *error)
812{
813 enum mnsh_msg_type type;
814 char buf[PATH_MAX];
815 ssize_t size;
816 int result;
817
818 size = mnsh_recv_message (helper->sock, &type, fd,
819 &result, error,
820 buf, sizeof (buf));
821 if (size < 0)
822 return -1;
823
824 gdb_assert (type == MNSH_RET_FD);
825 gdb_assert (size == 0);
826
827 if (*fd < 0)
828 {
829 gdb_assert (result < 0);
830 *fd = result;
831 }
832
833 return 0;
834}
835
836/* Receive a message from the helper. Issue an assertion failure if
837 the message isn't a correctly-formatted MNSH_RET_INTSTR. Set
838 RESULT and ERROR and optionally store data in BUF, then return
839 the number of bytes stored in BUF on success (this may be zero).
840 Set errno and return -1 on error. */
841
842static ssize_t
843mnsh_recv_intstr (struct linux_mnsh *helper,
844 int *result, int *error,
845 void *buf, int bufsiz)
846{
847 enum mnsh_msg_type type;
848 ssize_t size;
849 int fd;
850
851 size = mnsh_recv_message (helper->sock, &type, &fd,
852 result, error,
853 buf, bufsiz);
854
855 if (size < 0)
856 return -1;
857
858 gdb_assert (type == MNSH_RET_INTSTR);
859 gdb_assert (fd == -1);
860
861 return size;
862}
863
864/* Return values for linux_mntns_access_fs. */
865
866enum mnsh_fs_code
867 {
868 /* Something went wrong, errno is set. */
869 MNSH_FS_ERROR = -1,
870
871 /* The main process is in the correct mount namespace.
872 The caller should access the filesystem directly. */
873 MNSH_FS_DIRECT,
874
875 /* The helper is in the correct mount namespace.
876 The caller should access the filesystem via the helper. */
877 MNSH_FS_HELPER
878 };
879
880/* Return a value indicating how the caller should access the
881 mount namespace of process PID. */
882
883static enum mnsh_fs_code
884linux_mntns_access_fs (pid_t pid)
885{
4b8b5e72
GB
886 struct linux_ns *ns;
887 struct stat sb;
888 struct linux_mnsh *helper;
889 ssize_t size;
6cceac94 890 int fd;
4b8b5e72
GB
891
892 if (pid == getpid ())
893 return MNSH_FS_DIRECT;
894
895 ns = linux_ns_get_namespace (LINUX_NS_MNT);
896 if (ns == NULL)
897 return MNSH_FS_DIRECT;
898
13084383 899 fd = gdb_open_cloexec (linux_ns_filename (ns, pid), O_RDONLY, 0).release ();
4b8b5e72 900 if (fd < 0)
6cceac94 901 return MNSH_FS_ERROR;
4b8b5e72 902
6cceac94
TT
903 SCOPE_EXIT
904 {
905 int save_errno = errno;
906 close (fd);
907 errno = save_errno;
908 };
4b8b5e72
GB
909
910 if (fstat (fd, &sb) != 0)
6cceac94 911 return MNSH_FS_ERROR;
4b8b5e72
GB
912
913 if (sb.st_ino == ns->id)
6cceac94 914 return MNSH_FS_DIRECT;
4b8b5e72
GB
915
916 helper = linux_mntns_get_helper ();
917 if (helper == NULL)
6cceac94 918 return MNSH_FS_ERROR;
4b8b5e72
GB
919
920 if (sb.st_ino != helper->nsid)
921 {
922 int result, error;
923
924 size = mnsh_send_setns (helper, fd, 0);
925 if (size < 0)
6cceac94 926 return MNSH_FS_ERROR;
4b8b5e72
GB
927
928 if (mnsh_recv_int (helper, &result, &error) != 0)
6cceac94 929 return MNSH_FS_ERROR;
4b8b5e72
GB
930
931 if (result != 0)
932 {
933 /* ENOSYS indicates that an entire function is unsupported
934 (it's not appropriate for our versions of open/unlink/
935 readlink to sometimes return with ENOSYS depending on how
936 they're called) so we convert ENOSYS to ENOTSUP if setns
937 fails. */
938 if (error == ENOSYS)
939 error = ENOTSUP;
940
941 errno = error;
6cceac94 942 return MNSH_FS_ERROR;
4b8b5e72
GB
943 }
944
945 helper->nsid = sb.st_ino;
946 }
947
4b8b5e72 948 return MNSH_FS_HELPER;
4b8b5e72
GB
949}
950
951/* See nat/linux-namespaces.h. */
952
953int
954linux_mntns_open_cloexec (pid_t pid, const char *filename,
955 int flags, mode_t mode)
956{
957 enum mnsh_fs_code access = linux_mntns_access_fs (pid);
958 struct linux_mnsh *helper;
959 int fd, error;
960 ssize_t size;
961
962 if (access == MNSH_FS_ERROR)
963 return -1;
964
965 if (access == MNSH_FS_DIRECT)
13084383 966 return gdb_open_cloexec (filename, flags, mode).release ();
4b8b5e72
GB
967
968 gdb_assert (access == MNSH_FS_HELPER);
969
970 helper = linux_mntns_get_helper ();
971
972 size = mnsh_send_open (helper, filename, flags, mode);
973 if (size < 0)
974 return -1;
975
976 if (mnsh_recv_fd (helper, &fd, &error) != 0)
977 return -1;
978
979 if (fd < 0)
980 errno = error;
981
982 return fd;
983}
984
985/* See nat/linux-namespaces.h. */
986
987int
988linux_mntns_unlink (pid_t pid, const char *filename)
989{
990 enum mnsh_fs_code access = linux_mntns_access_fs (pid);
991 struct linux_mnsh *helper;
992 int ret, error;
993 ssize_t size;
994
995 if (access == MNSH_FS_ERROR)
996 return -1;
997
998 if (access == MNSH_FS_DIRECT)
999 return unlink (filename);
1000
1001 gdb_assert (access == MNSH_FS_HELPER);
1002
1003 helper = linux_mntns_get_helper ();
1004
1005 size = mnsh_send_unlink (helper, filename);
1006 if (size < 0)
1007 return -1;
1008
1009 if (mnsh_recv_int (helper, &ret, &error) != 0)
1010 return -1;
1011
1012 if (ret != 0)
1013 errno = error;
1014
1015 return ret;
1016}
1017
1018/* See nat/linux-namespaces.h. */
1019
1020ssize_t
1021linux_mntns_readlink (pid_t pid, const char *filename,
1022 char *buf, size_t bufsiz)
1023{
1024 enum mnsh_fs_code access = linux_mntns_access_fs (pid);
1025 struct linux_mnsh *helper;
1026 int ret, error;
1027 ssize_t size;
1028
1029 if (access == MNSH_FS_ERROR)
1030 return -1;
1031
1032 if (access == MNSH_FS_DIRECT)
1033 return readlink (filename, buf, bufsiz);
1034
1035 gdb_assert (access == MNSH_FS_HELPER);
1036
1037 helper = linux_mntns_get_helper ();
1038
1039 size = mnsh_send_readlink (helper, filename);
1040 if (size < 0)
1041 return -1;
1042
1043 size = mnsh_recv_intstr (helper, &ret, &error, buf, bufsiz);
1044
1045 if (size < 0)
1046 {
1047 ret = -1;
1048 errno = error;
1049 }
1050 else
1051 gdb_assert (size == ret);
1052
1053 return ret;
1054}