diff --git a/criu/Makefile.crtools b/criu/Makefile.crtools index f5864491721..95362c896c9 100644 --- a/criu/Makefile.crtools +++ b/criu/Makefile.crtools @@ -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 diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 27004972160..6c6a18a2aa0 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -79,6 +79,7 @@ #include "timens.h" #include "bpfmap.h" #include "apparmor.h" +#include "pidfd.h" #include "parasite-syscall.h" #include "files-reg.h" @@ -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 */ diff --git a/criu/files.c b/criu/files.c index 3b653e24be8..9d65a9b7a72 100644 --- a/criu/files.c +++ b/criu/files.c @@ -49,6 +49,7 @@ #include "kerndat.h" #include "fdstore.h" #include "bpfmap.h" +#include "pidfd.h" #include "protobuf.h" #include "util.h" @@ -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; @@ -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); diff --git a/criu/image-desc.c b/criu/image-desc.c index d65d9c0986e..d8af326acc3 100644 --- a/criu/image-desc.c +++ b/criu/image-desc.c @@ -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", diff --git a/criu/image.c b/criu/image.c index 9fb390ab7e4..5ed72d31332 100644 --- a/criu/image.c +++ b/criu/image.c @@ -31,12 +31,14 @@ int check_img_inventory(bool restore) int ret = -1; struct cr_img *img; InventoryEntry *he; + int loaded; img = open_image(CR_FD_INVENTORY, O_RSTR); if (!img) return -1; - if (pb_read_one(img, &he, PB_INVENTORY) < 0) + loaded = pb_read_one(img, &he, PB_INVENTORY); + if (loaded < 0) goto out_close; if (!he->has_fdinfo_per_id || !he->fdinfo_per_id) { diff --git a/criu/include/fdinfo.h b/criu/include/fdinfo.h index 10fb31f682c..79be96e91c4 100644 --- a/criu/include/fdinfo.h +++ b/criu/include/fdinfo.h @@ -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; diff --git a/criu/include/image-desc.h b/criu/include/image-desc.h index 9f369be6458..79e1ac1113a 100644 --- a/criu/include/image-desc.h +++ b/criu/include/image-desc.h @@ -113,6 +113,7 @@ enum { CR_FD_PIPES, CR_FD_TTY_FILES, CR_FD_MEMFD_FILE, + CR_FD_PIDFD, CR_FD_AUTOFS, diff --git a/criu/include/magic.h b/criu/include/magic.h index 22d7218e45f..4d42bcf7555 100644 --- a/criu/include/magic.h +++ b/criu/include/magic.h @@ -100,6 +100,7 @@ #define BPFMAP_FILE_MAGIC 0x57506142 /* Alapayevsk */ #define BPFMAP_DATA_MAGIC 0x64324033 /* Arkhangelsk */ #define APPARMOR_MAGIC 0x59423047 /* Nikolskoye */ +#define PIDFD_MAGIC 0x59423447 #define IFADDR_MAGIC RAW_IMAGE_MAGIC #define ROUTE_MAGIC RAW_IMAGE_MAGIC diff --git a/criu/include/pidfd.h b/criu/include/pidfd.h new file mode 100644 index 00000000000..e759a2c33f8 --- /dev/null +++ b/criu/include/pidfd.h @@ -0,0 +1,19 @@ +#ifndef __CR_PIDFD_H__ +#define __CR_PIDFD_H__ + +#include +#include "images/pidfd.pb-c.h" +#include +#include + +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(SYS_pidfd_open, pid, flags); +} +#endif diff --git a/criu/include/protobuf-desc.h b/criu/include/protobuf-desc.h index 3824de101f3..9a275597449 100644 --- a/criu/include/protobuf-desc.h +++ b/criu/include/protobuf-desc.h @@ -81,6 +81,7 @@ enum { PB_SK_QUEUES, PB_IPCNS_MSG, PB_IPCNS_MSG_ENT, + PB_PIDFD, PB_MAX, }; diff --git a/criu/pidfd.c b/criu/pidfd.c new file mode 100644 index 00000000000..108053108bf --- /dev/null +++ b/criu/pidfd.c @@ -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); + if (fd < 0) { + pr_perror("Cannot create pidfd %" PRId64 "\n", 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, +}; diff --git a/criu/proc_parse.c b/criu/proc_parse.c index 16392e38647..e127b09cba2 100644 --- a/criu/proc_parse.c +++ b/criu/proc_parse.c @@ -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 @@ -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; diff --git a/images/Makefile b/images/Makefile index ca85b1a213b..855d894da6d 100644 --- a/images/Makefile +++ b/images/Makefile @@ -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)/ diff --git a/images/fdinfo.proto b/images/fdinfo.proto index 88f1c11860f..042f89e5a33 100644 --- a/images/fdinfo.proto +++ b/images/fdinfo.proto @@ -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; @@ -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; @@ -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; } diff --git a/images/pidfd.proto b/images/pidfd.proto new file mode 100644 index 00000000000..6898d7b074c --- /dev/null +++ b/images/pidfd.proto @@ -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; +}