Skip to content

Commit

Permalink
Added option to use network namespace when connecting to parasite
Browse files Browse the repository at this point in the history
With this option you can connect to a parasite which is in a
different network namespace from memcr, for example when the
parasite is running in a container.
  • Loading branch information
bgray-sky authored and Mariusz Kozłowski committed Jan 19, 2024
1 parent 3ddcf69 commit 4cd8d83
Showing 1 changed file with 57 additions and 3 deletions.
60 changes: 57 additions & 3 deletions memcr.c
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ struct vm_area {

static char *dump_dir;
static char *parasite_socket_dir;
static int parasite_socket_use_netns;
static int no_wait;
static int proc_mem;
static int rss_file;
Expand Down Expand Up @@ -591,16 +592,62 @@ static int unseize_target(void)
return ret;
}

static int parasite_socket_create(pid_t pid)
{
int pid_netns = -1;
int cur_netns = -1;
char netns_path[64];
int cd;

if (parasite_socket_use_netns) {
/* get both current and parasite network namespaces */
snprintf(netns_path, sizeof(netns_path), "/proc/%d/ns/net", pid);
pid_netns = open(netns_path, O_CLOEXEC | O_RDONLY);
if (pid_netns < 0) {
fprintf(stderr, "open('%s', ) failed: %m\n", netns_path);
} else {
cur_netns = open("/proc/self/ns/net", O_CLOEXEC | O_RDONLY);
if (cur_netns < 0) {
fprintf(stderr, "open('/proc/self/ns/net', ) failed: %m\n");
close(pid_netns);
pid_netns = -1;
}
}

/* switch to network namespace of parasite if available */
if (pid_netns >= 0) {
if (setns(pid_netns, CLONE_NEWNET) != 0) {
fprintf(stderr, "setns() failed: %m\n");
}
close(pid_netns);
}
}

cd = socket(PF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
if (cd < 0) {
fprintf(stderr, "socket() failed: %m\n");
}

/* restore original network namespace if available */
if (cur_netns >= 0) {
if (setns(cur_netns, CLONE_NEWNET) != 0) {
fprintf(stderr, "setns() failed: %m\n");
}
close(cur_netns);
}

return cd;
}

static int parasite_connect(pid_t pid)
{
int cd;
struct sockaddr_un addr;
int ret;
int cnt = 0;

cd = socket(PF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0);
cd = parasite_socket_create(pid);
if (cd < 0) {
fprintf(stderr, "socket() failed: %m\n");
return -1;
}

Expand Down Expand Up @@ -2743,6 +2790,8 @@ static void usage(const char *name, int status)
" -d --dir dir where memory dump is stored (defaults to /tmp)\n" \
" -S --parasite-socket-dir dir where socket to communicate with parasite is created\n" \
" (abstract socket will be used if no path specified)\n" \
" -N --parasite-socket-netns use network namespace of parasite when connecting to socket\n" \
" (useful if parasite is running in a container with netns)\n" \
" -l --listen work as a service waiting for requests on a socket\n" \
" -l PORT: TCP port number to listen for requests on\n" \
" -l PATH: filesystem path for UNIX domain socket file (will be created)\n" \
Expand Down Expand Up @@ -2783,6 +2832,7 @@ int main(int argc, char *argv[])
{ "pid", 1, NULL, 'p'},
{ "dir", 1, NULL, 'd'},
{ "parasite-socket-dir", 1, NULL, 'S'},
{ "parasite-socket-netns", 0, NULL, 'N'},
{ "listen", 1, NULL, 'l'},
{ "no-wait", 0, NULL, 'n'},
{ "proc-mem", 0, NULL, 'm'},
Expand All @@ -2795,8 +2845,9 @@ int main(int argc, char *argv[])

dump_dir = "/tmp";
parasite_socket_dir = NULL;
parasite_socket_use_netns = 0;

while ((opt = getopt_long(argc, argv, "hp:d:S:l:nmfzce::", long_options, &option_index)) != -1) {
while ((opt = getopt_long(argc, argv, "hp:d:S:Nl:nmfzce::", long_options, &option_index)) != -1) {
switch (opt) {
case 'h':
usage(argv[0], 0);
Expand All @@ -2810,6 +2861,9 @@ int main(int argc, char *argv[])
case 'S':
parasite_socket_dir = optarg;
break;
case 'N':
parasite_socket_use_netns = 1;
break;
case 'l':
listen_location = optarg;
service = 1;
Expand Down

0 comments on commit 4cd8d83

Please sign in to comment.