From ecab9e3570cbd60fd8700f97d0137cba7db8a1ae Mon Sep 17 00:00:00 2001 From: Dmitry Sepp Date: Tue, 10 Feb 2026 14:28:42 +0000 Subject: [PATCH] criu: kerndat: add kerndat_has_binfmt_misc_sandboxing() Detect if the kernel supports binfmt_misc sandboxing and store the result in kerndat. The result will be used by the code that dumps and restores binfmt_misc entries. Signed-off-by: Dmitry Sepp --- criu/cr-check.c | 11 ++++++ criu/include/kerndat.h | 1 + criu/kerndat.c | 90 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 102 insertions(+) diff --git a/criu/cr-check.c b/criu/cr-check.c index 7c3dc76dd..6c9c01756 100644 --- a/criu/cr-check.c +++ b/criu/cr-check.c @@ -1810,6 +1810,16 @@ static int check_external_net_ns(void) return 0; } +static int check_binfmt_misc_sandboxing(void) +{ + if (!kdat.has_binfmt_misc_sandboxing) { + pr_info("binfmt_misc sandboxing isn't supported\n"); + return -1; + } + + return 0; +} + struct feature_list { char *name; int (*func)(void); @@ -1861,6 +1871,7 @@ static struct feature_list feature_list[] = { { "overlayfs_maps", check_overlayfs_maps }, { "breakpoints", check_breakpoints }, { "pagemap_scan_guard_pages", check_pagemap_scan_guard_pages }, + { "binfmt_misc_sandboxing", check_binfmt_misc_sandboxing }, { NULL, NULL }, }; diff --git a/criu/include/kerndat.h b/criu/include/kerndat.h index e4922f401..7ede28e2e 100644 --- a/criu/include/kerndat.h +++ b/criu/include/kerndat.h @@ -93,6 +93,7 @@ struct kerndat_s { bool has_breakpoints; bool has_madv_guard; bool has_pagemap_scan_guard_pages; + bool has_binfmt_misc_sandboxing; }; extern struct kerndat_s kdat; diff --git a/criu/kerndat.c b/criu/kerndat.c index 4e4efff40..7cb05047d 100644 --- a/criu/kerndat.c +++ b/criu/kerndat.c @@ -1848,6 +1848,92 @@ void kerndat_warn_about_madv_guards(void) "Please, consider updating your kernel.\n"); } +/* Keep the fd open so that it can be closed by the caller (required by the parent process) */ +static int __mount_and_stat_detached_binfmt_misc(struct stat *st, int *mnt_fd) +{ + int fd; + + fd = mount_detached_fs("binfmt_misc"); + if (fd < 0) { + /* Most likely a permission error, so we can't use binfmt_misc */ + return 1; + } + + if (fstat(fd, st) < 0) { + pr_perror("Failed to stat a binfmt_misc mountpoint"); + close(fd); + return -1; + } + + *mnt_fd = fd; + + return 0; +} + +struct has_binfmt_misc_arg { + dev_t st_dev; + bool has; +}; + +static int __has_binfmt_misc_sandboxing(void *arg) +{ + struct has_binfmt_misc_arg *has_arg = (struct has_binfmt_misc_arg *)arg; + struct stat st; + int ret, mnt_fd; + + if (unshare(CLONE_NEWNS | CLONE_NEWUSER)) { + pr_perror("Failed to unshare namespaces"); + return 1; + } + + ret = __mount_and_stat_detached_binfmt_misc(&st, &mnt_fd); + if (ret < 0) { + return 1; + } else if (ret == 1) { + has_arg->has = false; + return 0; + } + + if (has_arg->st_dev != st.st_dev) + has_arg->has = true; + else + has_arg->has = false; + + close(mnt_fd); + + return 0; +} + +static int kerndat_has_binfmt_misc_sandboxing(void) +{ + int ret, mnt_fd; + struct stat st; + struct has_binfmt_misc_arg arg; + + ret = __mount_and_stat_detached_binfmt_misc(&st, &mnt_fd); + if (ret < 0) { + return -1; + } else if (ret == 1) { + arg.has = false; + goto out; + } + + arg.st_dev = st.st_dev; + + ret = call_in_child_process(__has_binfmt_misc_sandboxing, (void *)&arg); + close(mnt_fd); + if (ret < 0) { + pr_err("Failed to check binfmt_misc sandboxing support in child process\n"); + return -1; + } + +out: + pr_info("binfmt_misc sandboxing is %s supported\n", arg.has ? "" : "not"); + kdat.has_binfmt_misc_sandboxing = arg.has; + + return 0; +} + /* * Some features depend on resource that can be dynamically changed * at the OS runtime. There are cases that we cannot determine the @@ -2121,6 +2207,10 @@ int kerndat_init(void) pr_err("kerndat_has_madv_guard has failed when initializing kerndat.\n"); ret = -1; } + if (!ret && kerndat_has_binfmt_misc_sandboxing()) { + pr_err("kerndat_has_binfmt_misc_sandboxing has failed when initializing kerndat.\n"); + ret = -1; + } kerndat_lsm(); kerndat_mmap_min_addr();