20#include "gdbsupport/common-defs.h"
22#include "gdbsupport/filestuff.h"
24#include <sys/syscall.h>
27#include <sys/socket.h>
28#include "gdbsupport/gdb_wait.h"
31#include "gdbsupport/scope-exit.h"
55 return setns (fd, nstype);
56#elif defined __NR_setns
57 return syscall (__NR_setns, fd, nstype);
66#ifndef MSG_CMSG_CLOEXEC
67#define MSG_CMSG_CLOEXEC 0
97 static char filename[PATH_MAX];
100 xsnprintf (filename,
sizeof (filename),
"/proc/%d/ns/%s", pid,
124 ns = &namespaces[type];
164 if (stat (filename, &sb) != 0)
165 perror_with_name (filename);
167 return sb.st_ino == ns->
id;
274 int fd,
int int1,
int int2,
275 const void *buf,
int bufsiz)
277 gdb_byte *c = (gdb_byte *) buf;
278 gdb_byte *cl = c + bufsiz;
283 debug_printf (
"ERROR");
287 debug_printf (
"SETNS");
291 debug_printf (
"OPEN");
295 debug_printf (
"UNLINK");
299 debug_printf (
"READLINK");
303 debug_printf (
"INT");
311 debug_printf (
"INTSTR");
315 debug_printf (
"unknown-packet-%d", type);
318 debug_printf (
" %d %d %d \"", fd, int1, int2);
321 debug_printf (*c >=
' ' && *c <=
'~' ?
"%c" :
"\\%o", *c);
338 int fd,
int int1,
int int2,
339 const void *buf,
int bufsiz)
343 char fdbuf[CMSG_SPACE (
sizeof (fd))];
347 memset (&msg, 0,
sizeof (msg));
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);
360 if (buf != NULL && bufsiz > 0)
362 iov[3].iov_base = alloca (bufsiz);
363 memcpy (iov[3].iov_base, buf, bufsiz);
364 iov[3].iov_len = bufsiz;
372 struct cmsghdr *cmsg;
374 msg.msg_control = fdbuf;
375 msg.msg_controllen =
sizeof (fdbuf);
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));
382 memcpy (CMSG_DATA (cmsg), &fd,
sizeof (
int));
384 msg.msg_controllen = cmsg->cmsg_len;
388 size = sendmsg (sock, &msg, 0);
395 debug_printf (
"mnsh: send: ");
397 debug_printf (
" -> %s\n", pulongest (size));
413 int *fd,
int *int1,
int *int2,
414 void *buf,
int bufsiz)
418 char fdbuf[CMSG_SPACE (
sizeof (*fd))];
419 struct cmsghdr *cmsg;
420 ssize_t size, fixed_size;
424 memset (&msg, 0,
sizeof (msg));
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;
438 for (fixed_size = i = 0; i < msg.msg_iovlen - 1; i++)
439 fixed_size += iov[i].iov_len;
441 msg.msg_control = fdbuf;
442 msg.msg_controllen =
sizeof (fdbuf);
449 debug_printf (
"namespace-helper: recv failed (%s)\n",
458 if (size < fixed_size || (msg.msg_flags & (MSG_TRUNC | MSG_CTRUNC)))
461 debug_printf (
"namespace-helper: recv truncated (%s 0x%x)\n",
462 pulongest (size), msg.msg_flags);
471 cmsg = CMSG_FIRSTHDR (&msg);
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));
482 debug_printf (
"mnsh: recv: ");
489 return size - fixed_size;
494#define mnsh_return_int(sock, result, error) \
495 mnsh_send_message (sock, MNSH_RET_INT, -1, result, error, NULL, 0)
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, \
503#define mnsh_return_intstr(sock, result, buf, bufsiz, error) \
504 mnsh_send_message (sock, MNSH_RET_INTSTR, -1, result, error, \
521 int flags, mode_t mode)
523 scoped_fd fd = gdb_open_cloexec (filename, flags, mode);
532 int result = unlink (filename);
543 int len = readlink (filename, buf,
sizeof (buf));
546 buf, len < 0 ? 0 : len,
552static void mnsh_main (
int sock) ATTRIBUTE_NORETURN;
560 int fd = -1, int1, int2;
562 ssize_t size, response = -1;
568 if (size >= 0 && size <
sizeof (buf))
578 if (size > 0 && buf[size - 1] ==
'\0')
583 if (size > 0 && buf[size - 1] ==
'\0')
588 if (size > 0 && buf[size - 1] ==
'\0')
608 -1, int1, int2, buf, size);
646 pid_t helper_creator = getpid ();
653 if (gdb_socketpair_cloexec (AF_UNIX, SOCK_STREAM, 0, sv) < 0)
659 int saved_errno = errno;
685 helper->
sock = sv[0];
689 debug_printf (
"Started mount namespace helper process %d\n",
726 pid = waitpid (helper->
pid, &status, WNOHANG);
735 warning (_(
"mount namespace helper vanished?"));
737 internal_warning (_(
"unhandled error %d"), errno);
739 else if (
pid == helper->
pid)
741 if (WIFEXITED (status))
742 warning (_(
"mount namespace helper exited with status %d"),
743 WEXITSTATUS (status));
744 else if (WIFSIGNALED (status))
745 warning (_(
"mount namespace helper killed by signal %d"),
748 internal_warning (_(
"unhandled status %d"), status);
751 internal_warning (_(
"unknown pid %d"),
pid);
760#define mnsh_send_setns(helper, fd, nstype) \
761 mnsh_send_message (helper->sock, MNSH_REQ_SETNS, fd, nstype, 0, \
764#define mnsh_send_open(helper, filename, flags, mode) \
765 mnsh_send_message (helper->sock, MNSH_REQ_OPEN, -1, flags, mode, \
766 filename, strlen (filename) + 1)
768#define mnsh_send_unlink(helper, filename) \
769 mnsh_send_message (helper->sock, MNSH_REQ_UNLINK, -1, 0, 0, \
770 filename, strlen (filename) + 1)
772#define mnsh_send_readlink(helper, filename) \
773 mnsh_send_message (helper->sock, MNSH_REQ_READLINK, -1, 0, 0, \
774 filename, strlen (filename) + 1)
796 gdb_assert (fd == -1);
797 gdb_assert (size == 0);
822 gdb_assert (size == 0);
826 gdb_assert (result < 0);
841 int *result,
int *error,
842 void *buf,
int bufsiz)
856 gdb_assert (fd == -1);
889 if (
pid == getpid ())
902 int save_errno = errno;
907 if (fstat (fd, &sb) != 0)
910 if (sb.st_ino == ns->
id)
917 if (sb.st_ino != helper->
nsid)
942 helper->
nsid = sb.st_ino;
952 int flags, mode_t mode)
963 return gdb_open_cloexec (filename, flags, mode).release ();
996 return unlink (filename);
1019 char *buf,
size_t bufsiz)
1030 return readlink (filename, buf, bufsiz);
1048 gdb_assert (size == ret);
static pid_t do_fork(void)
int linux_ns_same(pid_t pid, enum linux_ns_type type)
static ssize_t mnsh_handle_setns(int sock, int fd, int nstype)
static ssize_t mnsh_handle_readlink(int sock, const char *filename)
#define mnsh_send_unlink(helper, filename)
static struct linux_ns * linux_ns_get_namespace(enum linux_ns_type type)
ssize_t linux_mntns_readlink(pid_t pid, const char *filename, char *buf, size_t bufsiz)
#define mnsh_send_open(helper, filename, flags, mode)
static ssize_t mnsh_recv_intstr(struct linux_mnsh *helper, int *result, int *error, void *buf, int bufsiz)
static int mnsh_creator_pid
#define mnsh_send_setns(helper, fd, nstype)
static enum mnsh_fs_code linux_mntns_access_fs(pid_t pid)
static int mnsh_recv_fd(struct linux_mnsh *helper, int *fd, int *error)
static void mnsh_main(int sock) ATTRIBUTE_NORETURN
#define mnsh_return_intstr(sock, result, buf, bufsiz, error)
static ssize_t mnsh_handle_open(int sock, const char *filename, int flags, mode_t mode)
static struct linux_mnsh * linux_mntns_get_helper(void)
static ssize_t mnsh_handle_unlink(int sock, const char *filename)
#define mnsh_return_int(sock, result, error)
static const char * linux_ns_filename(struct linux_ns *ns, int pid)
static ssize_t mnsh_recv_message(int sock, enum mnsh_msg_type *type, int *fd, int *int1, int *int2, void *buf, int bufsiz)
#define mnsh_return_fd(sock, fd, error)
static ssize_t mnsh_send_message(int sock, enum mnsh_msg_type type, int fd, int int1, int int2, const void *buf, int bufsiz)
static int mnsh_recv_int(struct linux_mnsh *helper, int *result, int *error)
bool debug_linux_namespaces
static void mnsh_debug_print_message(enum mnsh_msg_type type, int fd, int int1, int int2, const void *buf, int bufsiz)
int linux_mntns_open_cloexec(pid_t pid, const char *filename, int flags, mode_t mode)
static void mnsh_maybe_mourn_peer(void)
#define mnsh_send_readlink(helper, filename)
static int do_setns(int fd, int nstype)
int linux_mntns_unlink(pid_t pid, const char *filename)