GDBserver

linux-namespaces.c
Go to the documentation of this file.
1 /* Linux namespaces(7) support.
2
3 Copyright (C) 2015-2018 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 "common-defs.h"
21 #include "nat/linux-namespaces.h"
22 #include "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 "gdb_wait.h"
29 #include <signal.h>
30 #include <sched.h>
31
32 /* See nat/linux-namespaces.h. */
33 int 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 int fd = gdb_open_cloexec (filename, flags, mode);
523 ssize_t result = mnsh_return_fd (sock, fd, errno);
524
525 if (fd >= 0)
526 close (fd);
527
528 return result;
529 }
530
531 /* Handle a MNSH_REQ_UNLINK message. Must be async-signal-safe. */
532
533 static ssize_t
534 mnsh_handle_unlink (int sock, const char *filename)
535 {
536 int result = unlink (filename);
537
538 return mnsh_return_int (sock, result, errno);
539 }
540
541 /* Handle a MNSH_REQ_READLINK message. Must be async-signal-safe. */
542
543 static ssize_t
544 mnsh_handle_readlink (int sock, const char *filename)
545 {
546 char buf[PATH_MAX];
547 int len = readlink (filename, buf, sizeof (buf));
548
549 return mnsh_return_intstr (sock, len,
550 buf, len < 0 ? 0 : len,
551 errno);
552 }
553
554 /* The helper process. Never returns. Must be async-signal-safe. */
555
556 static void mnsh_main (int sock) ATTRIBUTE_NORETURN;
557
558 static void
559 mnsh_main (int sock)
560 {
561 while (1)
562 {
563 enum mnsh_msg_type type;
564 int fd, int1, int2;
565 char buf[PATH_MAX];
566 ssize_t size, response = -1;
567
568 size = mnsh_recv_message (sock, &type,
569 &fd, &int1, &int2,
570 buf, sizeof (buf));
571
572 if (size >= 0 && size < sizeof (buf))
573 {
574 switch (type)
575 {
576 case MNSH_REQ_SETNS:
577 if (fd > 0)
578 response = mnsh_handle_setns (sock, fd, int1);
579 break;
580
581 case MNSH_REQ_OPEN:
582 if (size > 0 && buf[size - 1] == '\0')
583 response = mnsh_handle_open (sock, buf, int1, int2);
584 break;
585
586 case MNSH_REQ_UNLINK:
587 if (size > 0 && buf[size - 1] == '\0')
588 response = mnsh_handle_unlink (sock, buf);
589 break;
590
591 case MNSH_REQ_READLINK:
592 if (size > 0 && buf[size - 1] == '\0')
593 response = mnsh_handle_readlink (sock, buf);
594 break;
595
596 default:
597 break; /* Handled below. */
598 }
599 }
600
601 /* Close any file descriptors we were passed. */
602 if (fd >= 0)
603 close (fd);
604
605 /* Can't handle this message, bounce it back. */
606 if (response < 0)
607 {
608 if (size < 0)
609 size = 0;
610
611 mnsh_send_message (sock, MNSH_MSG_ERROR,
612 -1, int1, int2, buf, size);
613 }
614 }
615 }
616
617 /* The mount namespace helper process. */
618
619 struct linux_mnsh
620 {
621 /* PID of helper. */
622 pid_t pid;
623
624 /* Socket for communication. */
625 int sock;
626
627 /* ID of the mount namespace the helper is currently in. */
628 ino_t nsid;
629 };
630
631 /* In the helper process this is set to the PID of the process that
632 created the helper (i.e. GDB or gdbserver). In the main process
633 this is set to zero. Used by mnsh_maybe_mourn_peer. */
634 static int mnsh_creator_pid = 0;
635
636 /* Return an object representing the mount namespace helper process.
637 If no mount namespace helper process has been started then start
638 one. Return NULL if no mount namespace helper process could be
639 started. */
640
641 static struct linux_mnsh *
642 linux_mntns_get_helper (void)
643 {
644 static struct linux_mnsh *helper = NULL;
645
646 if (helper == NULL)
647 {
648 static struct linux_mnsh h;
649 struct linux_ns *ns;
650 pid_t helper_creator = getpid ();
651 int sv[2];
652
653 ns = linux_ns_get_namespace (LINUX_NS_MNT);
654 if (ns == NULL)
655 return NULL;
656
657 if (gdb_socketpair_cloexec (AF_UNIX, SOCK_STREAM, 0, sv) < 0)
658 return NULL;
659
660 h.pid = do_fork ();
661 if (h.pid < 0)
662 {
663 int saved_errno = errno;
664
665 close (sv[0]);
666 close (sv[1]);
667
668 errno = saved_errno;
669 return NULL;
670 }
671
672 if (h.pid == 0)
673 {
674 /* Child process. */
675 close (sv[0]);
676
677 mnsh_creator_pid = helper_creator;
678
679 /* Debug printing isn't async-signal-safe. */
680 debug_linux_namespaces = 0;
681
682 mnsh_main (sv[1]);
683 }
684
685 /* Parent process. */
686 close (sv[1]);
687
688 helper = &h;
689 helper->sock = sv[0];
690 helper->nsid = ns->id;
691
692 if (debug_linux_namespaces)
693 debug_printf ("Started mount namespace helper process %d\n",
694 helper->pid);
695 }
696
697 return helper;
698 }
699
700 /* Check whether the other process died and act accordingly. Called
701 whenever a socket error occurs, from both the main process and the
702 helper. Must be async-signal-safe when called from the helper. */
703
704 static void
705 mnsh_maybe_mourn_peer (void)
706 {
707 if (mnsh_creator_pid != 0)
708 {
709 /* We're in the helper. Check if our current parent is the
710 process that started us. If it isn't, then our original
711 parent died and we've been reparented. Exit immediately
712 if that's the case. */
713 if (getppid () != mnsh_creator_pid)
714 _exit (0);
715 }
716 else
717 {
718 /* We're in the main process. */
719
720 struct linux_mnsh *helper = linux_mntns_get_helper ();
721 int status;
722 pid_t pid;
723
724 if (helper->pid < 0)
725 {
726 /* We already mourned it. */
727 return;
728 }
729
730 pid = waitpid (helper->pid, &status, WNOHANG);
731 if (pid == 0)
732 {
733 /* The helper is still alive. */
734 return;
735 }
736 else if (pid == -1)
737 {
738 if (errno == ECHILD)
739 warning (_("mount namespace helper vanished?"));
740 else
741 internal_warning (__FILE__, __LINE__,
742 _("unhandled error %d"), errno);
743 }
744 else if (pid == helper->pid)
745 {
746 if (WIFEXITED (status))
747 warning (_("mount namespace helper exited with status %d"),
748 WEXITSTATUS (status));
749 else if (WIFSIGNALED (status))
750 warning (_("mount namespace helper killed by signal %d"),
751 WTERMSIG (status));
752 else
753 internal_warning (__FILE__, __LINE__,
754 _("unhandled status %d"), status);
755 }
756 else
757 internal_warning (__FILE__, __LINE__,
758 _("unknown pid %d"), pid);
759
760 /* Something unrecoverable happened. */
761 helper->pid = -1;
762 }
763 }
764
765 /* Shortcuts for sending messages to the helper. */
766
767 #define mnsh_send_setns(helper, fd, nstype) \
768 mnsh_send_message (helper->sock, MNSH_REQ_SETNS, fd, nstype, 0, \
769 NULL, 0)
770
771 #define mnsh_send_open(helper, filename, flags, mode) \
772 mnsh_send_message (helper->sock, MNSH_REQ_OPEN, -1, flags, mode, \
773 filename, strlen (filename) + 1)
774
775 #define mnsh_send_unlink(helper, filename) \
776 mnsh_send_message (helper->sock, MNSH_REQ_UNLINK, -1, 0, 0, \
777 filename, strlen (filename) + 1)
778
779 #define mnsh_send_readlink(helper, filename) \
780 mnsh_send_message (helper->sock, MNSH_REQ_READLINK, -1, 0, 0, \
781 filename, strlen (filename) + 1)
782
783 /* Receive a message from the helper. Issue an assertion failure if
784 the message isn't a correctly-formatted MNSH_RET_INT. Set RESULT
785 and ERROR and return 0 on success. Set errno and return -1 on
786 failure. */
787
788 static int
789 mnsh_recv_int (struct linux_mnsh *helper, int *result, int *error)
790 {
791 enum mnsh_msg_type type;
792 char buf[PATH_MAX];
793 ssize_t size;
794 int fd;
795
796 size = mnsh_recv_message (helper->sock, &type, &fd,
797 result, error,
798 buf, sizeof (buf));
799 if (size < 0)
800 return -1;
801
802 gdb_assert (type == MNSH_RET_INT);
803 gdb_assert (fd == -1);
804 gdb_assert (size == 0);
805
806 return 0;
807 }
808
809 /* Receive a message from the helper. Issue an assertion failure if
810 the message isn't a correctly-formatted MNSH_RET_FD. Set FD and
811 ERROR and return 0 on success. Set errno and return -1 on
812 failure. */
813
814 static int
815 mnsh_recv_fd (struct linux_mnsh *helper, int *fd, int *error)
816 {
817 enum mnsh_msg_type type;
818 char buf[PATH_MAX];
819 ssize_t size;
820 int result;
821
822 size = mnsh_recv_message (helper->sock, &type, fd,
823 &result, error,
824 buf, sizeof (buf));
825 if (size < 0)
826 return -1;
827
828 gdb_assert (type == MNSH_RET_FD);
829 gdb_assert (size == 0);
830
831 if (*fd < 0)
832 {
833 gdb_assert (result < 0);
834 *fd = result;
835 }
836
837 return 0;
838 }
839
840 /* Receive a message from the helper. Issue an assertion failure if
841 the message isn't a correctly-formatted MNSH_RET_INTSTR. Set
842 RESULT and ERROR and optionally store data in BUF, then return
843 the number of bytes stored in BUF on success (this may be zero).
844 Set errno and return -1 on error. */
845
846 static ssize_t
847 mnsh_recv_intstr (struct linux_mnsh *helper,
848 int *result, int *error,
849 void *buf, int bufsiz)
850 {
851 enum mnsh_msg_type type;
852 ssize_t size;
853 int fd;
854
855 size = mnsh_recv_message (helper->sock, &type, &fd,
856 result, error,
857 buf, bufsiz);
858
859 if (size < 0)
860 return -1;
861
862 gdb_assert (type == MNSH_RET_INTSTR);
863 gdb_assert (fd == -1);
864
865 return size;
866 }
867
868 /* Return values for linux_mntns_access_fs. */
869
870 enum mnsh_fs_code
871 {
872 /* Something went wrong, errno is set. */
873 MNSH_FS_ERROR = -1,
874
875 /* The main process is in the correct mount namespace.
876 The caller should access the filesystem directly. */
877 MNSH_FS_DIRECT,
878
879 /* The helper is in the correct mount namespace.
880 The caller should access the filesystem via the helper. */
881 MNSH_FS_HELPER
882 };
883
884 /* Return a value indicating how the caller should access the
885 mount namespace of process PID. */
886
887 static enum mnsh_fs_code
888 linux_mntns_access_fs (pid_t pid)
889 {
890 struct cleanup *old_chain;
891 struct linux_ns *ns;
892 struct stat sb;
893 struct linux_mnsh *helper;
894 ssize_t size;
895 int fd, saved_errno;
896
897 if (pid == getpid ())
898 return MNSH_FS_DIRECT;
899
900 ns = linux_ns_get_namespace (LINUX_NS_MNT);
901 if (ns == NULL)
902 return MNSH_FS_DIRECT;
903
904 old_chain = make_cleanup (null_cleanup, NULL);
905
906 fd = gdb_open_cloexec (linux_ns_filename (ns, pid), O_RDONLY, 0);
907 if (fd < 0)
908 goto error;
909
910 make_cleanup_close (fd);
911
912 if (fstat (fd, &sb) != 0)
913 goto error;
914
915 if (sb.st_ino == ns->id)
916 {
917 do_cleanups (old_chain);
918
919 return MNSH_FS_DIRECT;
920 }
921
922 helper = linux_mntns_get_helper ();
923 if (helper == NULL)
924 goto error;
925
926 if (sb.st_ino != helper->nsid)
927 {
928 int result, error;
929
930 size = mnsh_send_setns (helper, fd, 0);
931 if (size < 0)
932 goto error;
933
934 if (mnsh_recv_int (helper, &result, &error) != 0)
935 goto error;
936
937 if (result != 0)
938 {
939 /* ENOSYS indicates that an entire function is unsupported
940 (it's not appropriate for our versions of open/unlink/
941 readlink to sometimes return with ENOSYS depending on how
942 they're called) so we convert ENOSYS to ENOTSUP if setns
943 fails. */
944 if (error == ENOSYS)
945 error = ENOTSUP;
946
947 errno = error;
948 goto error;
949 }
950
951 helper->nsid = sb.st_ino;
952 }
953
954 do_cleanups (old_chain);
955
956 return MNSH_FS_HELPER;
957
958 error:
959 saved_errno = errno;
960
961 do_cleanups (old_chain);
962
963 errno = saved_errno;
964 return MNSH_FS_ERROR;
965 }
966
967 /* See nat/linux-namespaces.h. */
968
969 int
970 linux_mntns_open_cloexec (pid_t pid, const char *filename,
971 int flags, mode_t mode)
972 {
973 enum mnsh_fs_code access = linux_mntns_access_fs (pid);
974 struct linux_mnsh *helper;
975 int fd, error;
976 ssize_t size;
977
978 if (access == MNSH_FS_ERROR)
979 return -1;
980
981 if (access == MNSH_FS_DIRECT)
982 return gdb_open_cloexec (filename, flags, mode);
983
984 gdb_assert (access == MNSH_FS_HELPER);
985
986 helper = linux_mntns_get_helper ();
987
988 size = mnsh_send_open (helper, filename, flags, mode);
989 if (size < 0)
990 return -1;
991
992 if (mnsh_recv_fd (helper, &fd, &error) != 0)
993 return -1;
994
995 if (fd < 0)
996 errno = error;
997
998 return fd;
999 }
1000
1001 /* See nat/linux-namespaces.h. */
1002
1003 int
1004 linux_mntns_unlink (pid_t pid, const char *filename)
1005 {
1006 enum mnsh_fs_code access = linux_mntns_access_fs (pid);
1007 struct linux_mnsh *helper;
1008 int ret, error;
1009 ssize_t size;
1010
1011 if (access == MNSH_FS_ERROR)
1012 return -1;
1013
1014 if (access == MNSH_FS_DIRECT)
1015 return unlink (filename);
1016
1017 gdb_assert (access == MNSH_FS_HELPER);
1018
1019 helper = linux_mntns_get_helper ();
1020
1021 size = mnsh_send_unlink (helper, filename);
1022 if (size < 0)
1023 return -1;
1024
1025 if (mnsh_recv_int (helper, &ret, &error) != 0)
1026 return -1;
1027
1028 if (ret != 0)
1029 errno = error;
1030
1031 return ret;
1032 }
1033
1034 /* See nat/linux-namespaces.h. */
1035
1036 ssize_t
1037 linux_mntns_readlink (pid_t pid, const char *filename,
1038 char *buf, size_t bufsiz)
1039 {
1040 enum mnsh_fs_code access = linux_mntns_access_fs (pid);
1041 struct linux_mnsh *helper;
1042 int ret, error;
1043 ssize_t size;
1044
1045 if (access == MNSH_FS_ERROR)
1046 return -1;
1047
1048 if (access == MNSH_FS_DIRECT)
1049 return readlink (filename, buf, bufsiz);
1050
1051 gdb_assert (access == MNSH_FS_HELPER);
1052
1053 helper = linux_mntns_get_helper ();
1054
1055 size = mnsh_send_readlink (helper, filename);
1056 if (size < 0)
1057 return -1;
1058
1059 size = mnsh_recv_intstr (helper, &ret, &error, buf, bufsiz);
1060
1061 if (size < 0)
1062 {
1063 ret = -1;
1064 errno = error;
1065 }
1066 else
1067 gdb_assert (size == ret);
1068
1069 return ret;
1070 }
mnsh_handle_unlink
static ssize_t mnsh_handle_unlink(int sock, const char *filename)
Definition: linux-namespaces.c:534
gdb_socketpair_cloexec
int gdb_socketpair_cloexec(int domain, int style, int protocol, int filedes[2])
mnsh_send_setns
#define mnsh_send_setns(helper, fd, nstype)
Definition: linux-namespaces.c:767
MNSH_RET_INT
Definition: linux-namespaces.c:256
linux_mntns_get_helper
static struct linux_mnsh * linux_mntns_get_helper(void)
Definition: linux-namespaces.c:642
types.h
WNOHANG
#define WNOHANG
Definition: gdb_wait.h:102
mnsh_send_open
#define mnsh_send_open(helper, filename, flags, mode)
Definition: linux-namespaces.c:771
mnsh_handle_readlink
static ssize_t mnsh_handle_readlink(int sock, const char *filename)
Definition: linux-namespaces.c:544
linux_ns_type
linux_ns_type
Definition: linux-namespaces.h:29
warning
void warning(const char *fmt,...)
Definition: errors.c:26
MNSH_RET_FD
Definition: linux-namespaces.c:260
MNSH_MSG_ERROR
Definition: linux-namespaces.c:226
memset
void * memset(T *s, int c, size_t n)=delete
mnsh_recv_fd
static int mnsh_recv_fd(struct linux_mnsh *helper, int *fd, int *error)
Definition: linux-namespaces.c:815
mnsh_creator_pid
static int mnsh_creator_pid
Definition: linux-namespaces.c:634
mnsh_recv_message
static ssize_t mnsh_recv_message(int sock, enum mnsh_msg_type *type, int *fd, int *int1, int *int2, void *buf, int bufsiz)
Definition: linux-namespaces.c:411
fcntl.h
cleanup
Definition: cleanups.c:38
linux_ns::id
ino_t id
Definition: linux-namespaces.c:86
_
#define _(String)
Definition: gdb_locale.h:35
mnsh_send_readlink
#define mnsh_send_readlink(helper, filename)
Definition: linux-namespaces.c:779
MNSH_REQ_UNLINK
Definition: linux-namespaces.c:245
mnsh_send_unlink
#define mnsh_send_unlink(helper, filename)
Definition: linux-namespaces.c:775
stat.h
debug_linux_namespaces
int debug_linux_namespaces
Definition: linux-namespaces.c:33
null_cleanup
void null_cleanup(void *arg)
Definition: cleanups.c:294
mnsh_handle_open
static ssize_t mnsh_handle_open(int sock, const char *filename, int flags, mode_t mode)
Definition: linux-namespaces.c:519
do_fork
static pid_t do_fork(void)
Definition: linux-namespaces.c:38
NUM_LINUX_NS_TYPES
Definition: linux-namespaces.h:50
WTERMSIG
#define WTERMSIG(w)
Definition: gdb_wait.h:71
mnsh_fs_code
mnsh_fs_code
Definition: linux-namespaces.c:870
linux_mntns_access_fs
static enum mnsh_fs_code linux_mntns_access_fs(pid_t pid)
Definition: linux-namespaces.c:888
linux_ns_same
int linux_ns_same(pid_t pid, enum linux_ns_type type)
Definition: linux-namespaces.c:145
mnsh_msg_type
mnsh_msg_type
Definition: linux-namespaces.c:221
WIFEXITED
#define WIFEXITED(w)
Definition: gdb_wait.h:44
linux_mnsh::pid
pid_t pid
Definition: linux-namespaces.c:622
linux_ns::supported
int supported
Definition: linux-namespaces.c:80
linux-namespaces.h
MNSH_RET_INTSTR
Definition: linux-namespaces.c:264
linux_ns_get_namespace
static struct linux_ns * linux_ns_get_namespace(enum linux_ns_type type)
Definition: linux-namespaces.c:109
MNSH_REQ_SETNS
Definition: linux-namespaces.c:233
mnsh_recv_int
static int mnsh_recv_int(struct linux_mnsh *helper, int *result, int *error)
Definition: linux-namespaces.c:789
signal.h
mnsh_main
static void mnsh_main(int sock) ATTRIBUTE_NORETURN
Definition: linux-namespaces.c:559
make_cleanup
struct cleanup * make_cleanup(make_cleanup_ftype *function, void *arg)
Definition: cleanups.c:116
pulongest
char * pulongest(ULONGEST u)
Definition: print-utils.c:129
make_cleanup_close
struct cleanup * make_cleanup_close(int fd)
Definition: filestuff.c:413
common-defs.h
MNSH_FS_DIRECT
Definition: linux-namespaces.c:877
MNSH_FS_HELPER
Definition: linux-namespaces.c:881
LINUX_NS_MNT
Definition: linux-namespaces.h:35
linux_ns_filename
static const char * linux_ns_filename(struct linux_ns *ns, int pid)
Definition: linux-namespaces.c:94
mnsh_maybe_mourn_peer
static void mnsh_maybe_mourn_peer(void)
Definition: linux-namespaces.c:705
WEXITSTATUS
#define WEXITSTATUS(w)
Definition: gdb_wait.h:67
mnsh_debug_print_message
static void mnsh_debug_print_message(enum mnsh_msg_type type, int fd, int int1, int int2, const void *buf, int bufsiz)
Definition: linux-namespaces.c:272
errno
#define errno
Definition: wincecompat.h:24
gdb_assert
#define gdb_assert(expr)
Definition: gdb_assert.h:32
linux_mntns_unlink
int linux_mntns_unlink(pid_t pid, const char *filename)
Definition: linux-namespaces.c:1004
MNSH_FS_ERROR
Definition: linux-namespaces.c:873
gdb_byte
bfd_byte gdb_byte
Definition: common-types.h:38
mnsh_return_fd
#define mnsh_return_fd(sock, fd, error)
Definition: linux-namespaces.c:496
mnsh_send_message
static ssize_t mnsh_send_message(int sock, enum mnsh_msg_type type, int fd, int int1, int int2, const void *buf, int bufsiz)
Definition: linux-namespaces.c:336
xsnprintf
int xsnprintf(char *str, size_t size, const char *format,...)
Definition: common-utils.c:134
linux_ns::filename
const char * filename
Definition: linux-namespaces.c:74
alloca
void * alloca(size_t)
linux_ns::initialized
int initialized
Definition: linux-namespaces.c:77
linux_mnsh::nsid
ino_t nsid
Definition: linux-namespaces.c:628
MSG_CMSG_CLOEXEC
#define MSG_CMSG_CLOEXEC
Definition: linux-namespaces.c:66
do_setns
static int do_setns(int fd, int nstype)
Definition: linux-namespaces.c:51
perror_with_name
void perror_with_name(const char *string)
Definition: utils.c:57
gdb_open_cloexec
int gdb_open_cloexec(const char *filename, int flags, unsigned long mode)
Definition: filestuff.c:283
mnsh_return_int
#define mnsh_return_int(sock, result, error)
Definition: linux-namespaces.c:493
linux_mntns_open_cloexec
int linux_mntns_open_cloexec(pid_t pid, const char *filename, int flags, mode_t mode)
Definition: linux-namespaces.c:970
mnsh_return_intstr
#define mnsh_return_intstr(sock, result, buf, bufsiz, error)
Definition: linux-namespaces.c:502
gdb_wait.h
WIFSIGNALED
#define WIFSIGNALED(w)
Definition: gdb_wait.h:48
linux_mnsh
Definition: linux-namespaces.c:619
linux_mntns_readlink
ssize_t linux_mntns_readlink(pid_t pid, const char *filename, char *buf, size_t bufsiz)
Definition: linux-namespaces.c:1037
MNSH_REQ_OPEN
Definition: linux-namespaces.c:239
mnsh_recv_intstr
static ssize_t mnsh_recv_intstr(struct linux_mnsh *helper, int *result, int *error, void *buf, int bufsiz)
Definition: linux-namespaces.c:847
debug_printf
void debug_printf(const char *fmt,...)
Definition: common-debug.c:30
filestuff.h
internal_warning
void internal_warning(const char *file, int line, const char *fmt,...)
Definition: errors.c:62
MNSH_REQ_READLINK
Definition: linux-namespaces.c:251
mnsh_handle_setns
static ssize_t mnsh_handle_setns(int sock, int fd, int nstype)
Definition: linux-namespaces.c:509
error
void error(const char *fmt,...)
Definition: errors.c:38
linux_ns
Definition: linux-namespaces.c:71
linux_mnsh::sock
int sock
Definition: linux-namespaces.c:625
do_cleanups
void do_cleanups(struct cleanup *old_chain)
Definition: cleanups.c:174