Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

criu: Add pidfd support #2259

Draft
wants to merge 2 commits into
base: criu-dev
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions criu/Makefile.crtools
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ obj-$(CONFIG_COMPAT) += vdso-compat.o
CFLAGS_REMOVE_vdso-compat.o += $(CFLAGS-ASAN) $(CFLAGS-GCOV)
obj-y += pidfd-store.o
obj-y += hugetlb.o
obj-y += pidfd.o

PROTOBUF_GEN := scripts/protobuf-gen.sh

Expand Down
3 changes: 2 additions & 1 deletion criu/cr-restore.c
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@
#include "timens.h"
#include "bpfmap.h"
#include "apparmor.h"
#include "pidfd.h"

#include "parasite-syscall.h"
#include "files-reg.h"
Expand Down Expand Up @@ -279,7 +280,7 @@ static struct collect_image_info *cinfos_files[] = {
&unix_sk_cinfo, &fifo_cinfo, &pipe_cinfo, &nsfile_cinfo, &packet_sk_cinfo,
&netlink_sk_cinfo, &eventfd_cinfo, &epoll_cinfo, &epoll_tfd_cinfo, &signalfd_cinfo,
&tunfile_cinfo, &timerfd_cinfo, &inotify_cinfo, &inotify_mark_cinfo, &fanotify_cinfo,
&fanotify_mark_cinfo, &ext_file_cinfo, &memfd_cinfo,
&fanotify_mark_cinfo, &ext_file_cinfo, &memfd_cinfo, &pidfd_cinfo
};

/* These images are required to restore namespaces */
Expand Down
6 changes: 6 additions & 0 deletions criu/files.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
#include "kerndat.h"
#include "fdstore.h"
#include "bpfmap.h"
#include "pidfd.h"

#include "protobuf.h"
#include "util.h"
Expand Down Expand Up @@ -544,6 +545,8 @@ static int dump_one_file(struct pid *pid, int fd, int lfd, struct fd_opts *opts,
ops = &signalfd_dump_ops;
else if (is_timerfd_link(link))
ops = &timerfd_dump_ops;
else if (is_pidfd_link(link))
ops = &pidfd_dump_ops;
#ifdef CONFIG_HAS_LIBBPF
else if (is_bpfmap_link(link))
ops = &bpfmap_dump_ops;
Expand Down Expand Up @@ -1778,6 +1781,9 @@ static int collect_one_file(void *o, ProtobufCMessage *base, struct cr_img *i)
case FD_TYPES__MEMFD:
ret = collect_one_file_entry(fe, fe->memfd->id, &fe->memfd->base, &memfd_cinfo);
break;
case FD_TYPES__PIDFD:
ret = collect_one_file_entry(fe, fe->pidfd->id, &fe->pidfd->base, &pidfd_cinfo);
break;
#ifdef CONFIG_HAS_LIBBPF
case FD_TYPES__BPFMAP:
ret = collect_one_file_entry(fe, fe->bpf->id, &fe->bpf->base, &bpfmap_cinfo);
Expand Down
1 change: 1 addition & 0 deletions criu/image-desc.c
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ struct cr_fd_desc_tmpl imgset_template[CR_FD_MAX] = {
FD_ENTRY_F(BPFMAP_FILE, "bpfmap-file", O_NOBUF),
FD_ENTRY_F(BPFMAP_DATA, "bpfmap-data", O_NOBUF),
FD_ENTRY(APPARMOR, "apparmor"),
FD_ENTRY(PIDFD, "pidfd-%u"),

[CR_FD_STATS] = {
.fmt = "stats-%s",
Expand Down
1 change: 1 addition & 0 deletions criu/include/fdinfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "images/signalfd.pb-c.h"
#include "images/fsnotify.pb-c.h"
#include "images/timerfd.pb-c.h"
#include "images/pidfd.pb-c.h"

struct fdinfo_common {
off64_t pos;
Expand Down
1 change: 1 addition & 0 deletions criu/include/image-desc.h
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ enum {
CR_FD_PIPES,
CR_FD_TTY_FILES,
CR_FD_MEMFD_FILE,
CR_FD_PIDFD,

CR_FD_AUTOFS,

Expand Down
1 change: 1 addition & 0 deletions criu/include/magic.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@
#define BPFMAP_FILE_MAGIC 0x57506142 /* Alapayevsk */
#define BPFMAP_DATA_MAGIC 0x64324033 /* Arkhangelsk */
#define APPARMOR_MAGIC 0x59423047 /* Nikolskoye */
#define PIDFD_MAGIC 0x52253735 /* Livny */

#define IFADDR_MAGIC RAW_IMAGE_MAGIC
#define ROUTE_MAGIC RAW_IMAGE_MAGIC
Expand Down
19 changes: 19 additions & 0 deletions criu/include/pidfd.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#ifndef __CR_PIDFD_H__
#define __CR_PIDFD_H__

#include <sys/stat.h>
#include "images/pidfd.pb-c.h"
#include <sys/syscall.h>
#include <unistd.h>

struct fd_parms;

extern const struct fdtype_ops pidfd_dump_ops;
extern struct collect_image_info pidfd_cinfo;
extern int is_pidfd_link(char *link);

static inline int pidfd_open(pid_t pid, unsigned int flags)
{
return syscall(__NR_pidfd_open, pid, flags);
}
#endif
1 change: 1 addition & 0 deletions criu/include/protobuf-desc.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ enum {
PB_SK_QUEUES,
PB_IPCNS_MSG,
PB_IPCNS_MSG_ENT,
PB_PIDFD,

PB_MAX,
};
Expand Down
81 changes: 81 additions & 0 deletions criu/pidfd.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
#include "pidfd.h"
#include "util.h"

#include "fdinfo.h"
#include "files.h"
#include "imgset.h"
#include "protobuf.h"
#include "fdinfo.pb-c.h"

int is_pidfd_link(char *link)
{
return is_anon_link_type(link, "[pidfd]");
}

static int dump_one_pidfd(int lfd, u32 id, const struct fd_parms *p)
{
PidfdEntry tfe = PIDFD_ENTRY__INIT;
FileEntry fe = FILE_ENTRY__INIT;

if (parse_fdinfo(lfd, FD_TYPES__PIDFD, &tfe))
return -1;

tfe.id = id;
tfe.flags = p->flags;
tfe.inode = p->stat.st_ino;
tfe.mnt_id = p->mnt_id;
tfe.fown = (FownEntry *)&p->fown;

fe.type = FD_TYPES__PIDFD;
fe.id = tfe.id;
fe.pidfd = &tfe;

return pb_write_one(img_from_set(glob_imgset, CR_FD_FILES), &fe, PB_FILE);
}

const struct fdtype_ops pidfd_dump_ops = {
.type = FD_TYPES__PIDFD,
.dump = dump_one_pidfd,
};

struct pidfd_info {
PidfdEntry *pidfde;
struct file_desc d;
};

static int open_pidfd_fd(struct file_desc *d, int *new_fd)
{
int fd = -1;
struct pidfd_info *info = container_of(d, struct pidfd_info, d);
PidfdEntry *pidfde = info->pidfde;

pr_info("Creating new pidfd %" PRId64 "\n", pidfde->pid);
fd = pidfd_open(pidfde->pid, 0);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a task linked to fd can be dead and pidfd_open will fail in this case.

if (fd < 0) {
pr_perror("Cannot create pidfd %" PRId64, pidfde->pid);
return -1;
}

*new_fd = fd;
return 0;
}

static struct file_desc_ops pidfd_desc_ops = {
.type = FD_TYPES__PIDFD,
.open = open_pidfd_fd,
};

static int collect_one_pidfd(void *o, ProtobufCMessage *msg, struct cr_img *i)
{
struct pidfd_info *info = o;

info->pidfde = pb_msg(msg, PidfdEntry);
return file_desc_add(&info->d, info->pidfde->id, &pidfd_desc_ops);
}

struct collect_image_info pidfd_cinfo = {
.fd_type = CR_FD_PIDFD,
.pb_type = PB_PIDFD,
.priv_size = sizeof(struct pidfd_info),
.collect = collect_one_pidfd,
};
19 changes: 19 additions & 0 deletions criu/proc_parse.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
#include "protobuf.h"
#include "images/fdinfo.pb-c.h"
#include "images/mnt.pb-c.h"
#include "images/pidfd.pb-c.h"
#include "plugin.h"

#include <stdlib.h>
Expand Down Expand Up @@ -2160,6 +2161,24 @@ static int parse_fdinfo_pid_s(int pid, int fd, int type, void *arg)
entry_met = true;
continue;
}
if (fdinfo_field(str, "Pid") || fdinfo_field(str, "NSpid")) {
unsigned long long val;
PidfdEntry *pfd = arg;

if (type != FD_TYPES__PIDFD)
continue;
ret = sscanf(str, "%*s %lli", &val);
if (ret != 1)
goto parse_err;

if (fdinfo_field(str, "Pid"))
pfd->pid = val;
else if (fdinfo_field(str, "NSpid"))
pfd->nspid = val;

entry_met = true;
continue;
}
}

exit_code = 0;
Expand Down
1 change: 1 addition & 0 deletions images/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ proto-obj-y += bpfmap-file.o
proto-obj-y += bpfmap-data.o
proto-obj-y += apparmor.o
proto-obj-y += rseq.o
proto-obj-y += pidfd.o

CFLAGS += -iquote $(obj)/

Expand Down
3 changes: 3 additions & 0 deletions images/fdinfo.proto
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import "pipe.proto";
import "tty.proto";
import "memfd.proto";
import "bpfmap-file.proto";
import "pidfd.proto";

enum fd_types {
UND = 0;
Expand All @@ -42,6 +43,7 @@ enum fd_types {
TIMERFD = 17;
MEMFD = 18;
BPFMAP = 19;
PIDFD = 20;

/* Any number above the real used. Not stored to image */
CTL_TTY = 65534;
Expand Down Expand Up @@ -78,4 +80,5 @@ message file_entry {
optional tty_file_entry tty = 19;
optional memfd_file_entry memfd = 20;
optional bpfmap_file_entry bpf = 21;
optional pidfd_entry pidfd = 22;
}
16 changes: 16 additions & 0 deletions images/pidfd.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// SPDX-License-Identifier: MIT

syntax = "proto2";

import "fown.proto";

message pidfd_entry {
required uint32 id = 1;
required uint64 pos = 2;
required uint32 flags = 3;
required uint32 mnt_id = 4;
required uint64 inode = 5;
required int64 pid = 6;
required int64 nspid = 7;
required fown_entry fown = 8;
}
1 change: 1 addition & 0 deletions test/zdtm/static/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,7 @@ TST_NOFILE := \
sigtrap \
sigtrap01 \
change_mnt_context \
pidfd00 \
# jobctl00 \

PKG_CONFIG ?= pkg-config
Expand Down
64 changes: 64 additions & 0 deletions test/zdtm/static/pidfd00.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <string.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>
#include <poll.h>

#include "zdtmtst.h"

static int pidfd_open(pid_t pid, unsigned int flags)
{
return syscall(SYS_pidfd_open, pid, flags);
}

const char *test_doc = "Pidfd ";
const char *test_author = "Suraj Shirvankar <surajshirvankar@gmail.com>";

int main(int argc, char **argv)
{
int pidfd, errcode = 42;
int status;
int ret;
struct pollfd pollfd;

test_init(argc, argv);

pidfd = pidfd_open(1, 0);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test has to create more than one pidfd linked to different tasks and then checks that they are linked to proper tasks after C/R.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@avagin I tried to write a test that would create a fork of a process and the parent process would monitor the pid of the child process. The dumping and restore process would first restore the parent process and the child process would still not be restored, hence the restore would fail.
I was thinking of restoring the pidfd after all the child processes have been restored, does that make sense.
To do this I would have to dump the pidfd seperate from the regular fd dump process.

if (pidfd == -1) {
perror("Couldnt open pidfd");
exit(1);
}

test_daemon();
test_waitsig();

pollfd.fd = pidfd;
pollfd.events = POLLIN;

ret = poll(&pollfd, 1, -1);
if (ret == -1) {
pr_perror("Poll error");
fail();
}

if (pollfd.revents & POLLIN) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why can it be triggered?

if (read(pidfd, &status, sizeof(status)) != sizeof(status)) {
fail("pidfd read error");
}
if (status == errcode) {
printf("Status code is %d", status);
pass();
} else {
fail("Exit code mismatch");
}
}

return 0;
}