Skip to content

Commit

Permalink
memfd_secret: add memfd_secret file support
Browse files Browse the repository at this point in the history
See "man 2 memfd_secret".

Fixes: checkpoint-restore#2188

Signed-off-by: Dhanuka Warusadura <csx@tuta.io>
  • Loading branch information
warusadura committed Oct 3, 2023
1 parent 1142f1b commit 8c0a1e6
Show file tree
Hide file tree
Showing 22 changed files with 628 additions and 6 deletions.
1 change: 1 addition & 0 deletions criu/Makefile.crtools
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ obj-y += log.o
obj-y += lsm.o
obj-y += mem.o
obj-y += memfd.o
obj-y += memfd-secret.o
obj-y += mount.o
obj-y += mount-v2.o
obj-y += filesystems.o
Expand Down
10 changes: 10 additions & 0 deletions criu/cr-check.c
Original file line number Diff line number Diff line change
Expand Up @@ -1340,6 +1340,14 @@ static int check_memfd_hugetlb(void)
return 0;
}

static int check_memfd_secret(void)
{
if (!kdat.has_memfd_secret)
return -1;

return 0;
}

static int check_network_lock_nftables(void)
{
if (!kdat.has_nftables_concat) {
Expand Down Expand Up @@ -1502,6 +1510,7 @@ int cr_check(void)
ret |= check_openat2();
ret |= check_ptrace_get_rseq_conf();
ret |= check_ipv6_freebind();
ret |= check_memfd_secret();

if (kdat.lsm == LSMTYPE__APPARMOR)
ret |= check_apparmor_stacking();
Expand Down Expand Up @@ -1623,6 +1632,7 @@ static struct feature_list feature_list[] = {
{ "openat2", check_openat2 },
{ "get_rseq_conf", check_ptrace_get_rseq_conf },
{ "ipv6_freebind", check_ipv6_freebind },
{ "memfd_secret", check_memfd_secret },
{ NULL, NULL },
};

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 "memfd-secret.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, &memfd_secret_cinfo,
};

/* These images are required to restore namespaces */
Expand Down
7 changes: 7 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 "memfd-secret.h"

#include "protobuf.h"
#include "util.h"
Expand Down Expand Up @@ -563,6 +564,9 @@ static int dump_one_file(struct pid *pid, int fd, int lfd, struct fd_opts *opts,
/* TODO: Dump for hugetlb fd when memfd hugetlb is not supported */
if (is_memfd(p.stat.st_dev) || (kdat.has_memfd_hugetlb && is_hugetlb_dev(p.stat.st_dev, NULL)))
ops = &memfd_dump_ops;
/* memfd_secret */
else if (is_memfd_secret(p.stat.st_dev) && kdat.has_memfd_secret)
ops = &memfd_secret_dump_ops;
else if (link.name[1] == '/')
ops = &regfile_dump_ops;
else if (check_ns_proc(&link))
Expand Down Expand Up @@ -1778,6 +1782,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__MEMFD_SECRET:
ret = collect_one_file_entry(fe, fe->memfd_secret->id, &fe->memfd_secret->base, &memfd_secret_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
2 changes: 2 additions & 0 deletions criu/image-desc.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ struct cr_fd_desc_tmpl imgset_template[CR_FD_MAX] = {
FD_ENTRY(FDINFO, "fdinfo-%u"),
FD_ENTRY(PAGEMAP, "pagemap-%lu"),
FD_ENTRY(SHMEM_PAGEMAP, "pagemap-shmem-%lu"),
FD_ENTRY(SECRETMEM_PAGEMAP, "pagemap-secretmem-%lu"),
FD_ENTRY(REG_FILES, "reg-files"),
FD_ENTRY(EXT_FILES, "ext-files"),
FD_ENTRY(NS_FILES, "ns-files"),
Expand Down Expand Up @@ -67,6 +68,7 @@ struct cr_fd_desc_tmpl imgset_template[CR_FD_MAX] = {
FD_ENTRY(REMAP_FPATH, "remap-fpath"),
FD_ENTRY_F(GHOST_FILE, "ghost-file-%x", O_NOBUF),
FD_ENTRY_F(MEMFD_INODE, "memfd", O_NOBUF),
FD_ENTRY_F(MEMFD_SECRET_INODE, "memfd-secret", O_NOBUF),
FD_ENTRY(TCP_STREAM, "tcp-stream-%x"),
FD_ENTRY(MNTS, "mountpoints-%u"),
FD_ENTRY(NETDEV, "netdev-%u"),
Expand Down
3 changes: 3 additions & 0 deletions criu/include/image-desc.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ enum {

CR_FD_PSTREE,
CR_FD_SHMEM_PAGEMAP,
CR_FD_SECRETMEM_PAGEMAP,
CR_FD_GHOST_FILE,
CR_FD_TCP_STREAM,
CR_FD_FDINFO,
Expand All @@ -69,6 +70,7 @@ enum {
CR_FD_SECCOMP,
CR_FD_APPARMOR,
CR_FD_MEMFD_INODE,
CR_FD_MEMFD_SECRET_INODE,
CR_FD_BPFMAP_FILE,
CR_FD_BPFMAP_DATA,
_CR_FD_GLOB_TO,
Expand Down Expand Up @@ -113,6 +115,7 @@ enum {
CR_FD_PIPES,
CR_FD_TTY_FILES,
CR_FD_MEMFD_FILE,
CR_FD_MEMFD_SECRET_FILE,

CR_FD_AUTOFS,

Expand Down
1 change: 1 addition & 0 deletions criu/include/image.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@
#define VMA_AREA_VVAR (1 << 12)
#define VMA_AREA_AIORING (1 << 13)
#define VMA_AREA_MEMFD (1 << 14)
#define VMA_AREA_MEMFD_SECRET (1 << 15)

#define VMA_EXT_PLUGIN (1 << 27)
#define VMA_CLOSE (1 << 28)
Expand Down
2 changes: 2 additions & 0 deletions criu/include/kerndat.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,13 @@ enum loginuid_func {
struct kerndat_s {
u32 magic1, magic2;
dev_t shmem_dev;
dev_t secretmem_dev;
int last_cap;
u64 zero_page_pfn;
bool has_dirty_track;
bool has_memfd;
bool has_memfd_hugetlb;
bool has_memfd_secret;
bool has_fdinfo_lock;
unsigned long task_size;
bool ipv6;
Expand Down
2 changes: 2 additions & 0 deletions criu/include/magic.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#define FDINFO_MAGIC 0x56213732 /* Dmitrov */
#define PAGEMAP_MAGIC 0x56084025 /* Vladimir */
#define SHMEM_PAGEMAP_MAGIC PAGEMAP_MAGIC
#define SECRETMEM_PAGEMAP_MAGIC PAGEMAP_MAGIC
#define PAGES_MAGIC RAW_IMAGE_MAGIC
#define CORE_MAGIC 0x55053847 /* Kolomna */
#define IDS_MAGIC 0x54432030 /* Konigsberg */
Expand Down Expand Up @@ -95,6 +96,7 @@
#define AUTOFS_MAGIC 0x49353943 /* Sochi */
#define FILES_MAGIC 0x56303138 /* Toropets */
#define MEMFD_INODE_MAGIC 0x48453499 /* Dnipro */
#define MEMFD_SECRET_INODE_MAGIC 0x44573468 /* Simferopol */
#define TIMENS_MAGIC 0x43114433 /* Beslan */
#define PIDNS_MAGIC 0x61157326 /* Surgut */
#define BPFMAP_FILE_MAGIC 0x57506142 /* Alapayevsk */
Expand Down
25 changes: 25 additions & 0 deletions criu/include/memfd-secret.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#ifndef __CR_MEMFD_SECRET_H__
#define __CR_MEMFD_SECRET_H__

#include <sys/types.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <errno.h>

#include "common/config.h"

extern int is_memfd_secret(dev_t dev);
extern const struct fdtype_ops memfd_secret_dump_ops;
extern struct collect_image_info memfd_secret_cinfo;

static inline int memfd_secret(unsigned int flags)
{
#ifdef __NR_memfd_secret
return syscall(__NR_memfd_secret, flags);
#else
errno = ENOSYS;
return -1;
#endif /* __NR_memfd_secret */
}

#endif /* __CR_MEMFD_SECRET_H__ */
1 change: 1 addition & 0 deletions criu/include/pagemap.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ struct page_read {
/* flags for open_page_read */
#define PR_SHMEM 0x1
#define PR_TASK 0x2
#define PR_SECRETMEM 0x3

#define PR_TYPE_MASK 0x3
#define PR_MOD 0x4 /* Will need to modify */
Expand Down
2 changes: 2 additions & 0 deletions criu/include/protobuf-desc.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ enum {
PB_SK_QUEUES,
PB_IPCNS_MSG,
PB_IPCNS_MSG_ENT,
PB_MEMFD_SECRET_FILE,
PB_MEMFD_SECRET_INODE,

PB_MAX,
};
Expand Down
67 changes: 67 additions & 0 deletions criu/kerndat.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
#include "kcmp.h"
#include "sched.h"
#include "memfd.h"
#include "memfd-secret.h"
#include "mount-v2.h"
#include "util-caps.h"

Expand Down Expand Up @@ -259,6 +260,33 @@ static int kerndat_get_shmemdev(void)
return -1;
}

static int kerndat_get_secretmem_dev(int fd)
{
void *secretmem = NULL;
dev_t dev;

if (ftruncate(fd, PAGE_SIZE) < 0)
goto err;

secretmem = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (secretmem == MAP_FAILED)
return -1;

if (kerndat_get_dev(&dev, secretmem, PAGE_SIZE))
goto err;

munmap(secretmem, PAGE_SIZE);
kdat.secretmem_dev = dev;
pr_info("Found secret-memory device at %ld\n", kdat.secretmem_dev);

return 0;

err:
if (secretmem)
munmap(secretmem, PAGE_SIZE);
return -1;
}

/* Return -1 -- error
* Return 0 -- successful but can't get any new device's numbers
* Return 1 -- successful and get new device's numbers
Expand Down Expand Up @@ -533,6 +561,41 @@ static bool kerndat_has_memfd_hugetlb(void)
return 0;
}

static bool kerndat_has_memfd_secret(void)
{
int fd, ret;

fd = memfd_secret(0);

if (errno == ENOSYS) {
pr_warn("CRIU was built without memfd_secret support\n");
kdat.has_memfd_secret = false;
kdat.secretmem_dev = 0;
return 0;
}

if (fd > 0) {
kdat.has_memfd_secret = true;
} else if (fd == -1 && (errno == EINVAL || errno == EMFILE || errno == ENOMEM)) {
kdat.has_memfd_secret = false;
kdat.secretmem_dev = 0;
return 0;
} else {
pr_perror("Unexpected error from memfd_secret(0)");
return -1;
}

ret = kerndat_get_secretmem_dev(fd);
if (ret) {
close(fd);
return -1;
}

close(fd);

return 0;
}

static int get_task_size(void)
{
kdat.task_size = compel_task_size();
Expand Down Expand Up @@ -1818,6 +1881,10 @@ int kerndat_init(void)
pr_err("kerndat_has_memfd_hugetlb failed when initializing kerndat.\n");
ret = -1;
}
if (!ret && kerndat_has_memfd_secret()) {
pr_err("kerndat_has_memfd_secret failed when initializing kerndat.\n");
ret = -1;
}
if (!ret && kerndat_detect_stack_guard_gap()) {
pr_err("kerndat_detect_stack_guard_gap failed when initializing kerndat.\n");
ret = -1;
Expand Down
Loading

0 comments on commit 8c0a1e6

Please sign in to comment.