256 lines
7.9 KiB
Diff
256 lines
7.9 KiB
Diff
From e522deb5680840e878b8f05c66f040cfd3b49d90 Mon Sep 17 00:00:00 2001
|
|
From: Jingxian He <hejingxian@huawei.com>
|
|
Date: Wed, 19 May 2021 21:47:28 +0800
|
|
Subject: [PATCH 29/72] cred: provide cred checkpoint restore method
|
|
|
|
criu checkpoint/restore the task, it only restore the context instead of
|
|
the memory address storing the context.
|
|
|
|
To handle the problem resulted by CVE bugfix, details:
|
|
- https://nvd.nist.gov/vuln/detail/CVE-2016-4565
|
|
- https://openfabrics.org/images/2018workshop/presentations/113_MRuhl_JourneytoVerbsIOCTL.pdf
|
|
|
|
Brief:
|
|
Refresh the security context address of file. The infiniband code use
|
|
write()` as bi-directional `ioctl()`, there is `struct cred` address
|
|
uring `write()` process. However, criu uses some syscall, such as
|
|
capset()` and `setgroups()`, to regenerate the new cred, the file
|
|
red is fixed by `fcntl(F_SETOWN)`, then the address of new cred is
|
|
ifferent from the file.
|
|
This patch fix the `struct cred` address checking problem resulted by
|
|
VE fixed in infiniband drivers.
|
|
|
|
Conflict:NA
|
|
Reference:https://gitee.com/src-openeuler/criu/pulls/21
|
|
Signed-off-by: luolongjun <luolongjun@huawei.com>
|
|
Signed-off-by: fu.lin <fu.lin10@huawei.com>
|
|
---
|
|
criu/config.c | 1 +
|
|
criu/cr-restore.c | 35 +++++++++++++++++++++++++++++++++++
|
|
criu/crtools.c | 1 +
|
|
criu/include/cr_options.h | 1 +
|
|
criu/include/fcntl.h | 4 ++++
|
|
criu/include/prctl.h | 4 ++++
|
|
criu/include/restorer.h | 3 +++
|
|
criu/pie/restorer.c | 38 ++++++++++++++++++++++++++++++++++++++
|
|
8 files changed, 87 insertions(+)
|
|
|
|
diff --git a/criu/config.c b/criu/config.c
|
|
index 03cad66..cf99fb1 100644
|
|
--- a/criu/config.c
|
|
+++ b/criu/config.c
|
|
@@ -702,6 +702,7 @@ int parse_options(int argc, char **argv, bool *usage_error, bool *has_exec_cmd,
|
|
BOOL_OPT("use-fork-pid", &opts.use_fork_pid),
|
|
BOOL_OPT("with-notifier", &opts.with_notifier_kup),
|
|
BOOL_OPT("dump-char-dev", &opts.dump_char_dev),
|
|
+ BOOL_OPT("with-fd-cred", &opts.with_fd_cred),
|
|
{},
|
|
};
|
|
|
|
diff --git a/criu/cr-restore.c b/criu/cr-restore.c
|
|
index 2904a75..ac677a1 100644
|
|
--- a/criu/cr-restore.c
|
|
+++ b/criu/cr-restore.c
|
|
@@ -692,6 +692,28 @@ static int __collect_child_pids(struct pstree_item *p, int state, unsigned int *
|
|
return 0;
|
|
}
|
|
|
|
+static int collect_child_fds(int state, unsigned int *n, struct pstree_item *me)
|
|
+{
|
|
+ struct list_head *list = &rsti(me)->fds;
|
|
+ struct fdinfo_list_entry *fle, *tmp;
|
|
+
|
|
+ *n = 0;
|
|
+ list_for_each_entry_safe(fle, tmp, list, ps_list) {
|
|
+ if (fle->fe->type == state) {
|
|
+ int *child;
|
|
+
|
|
+ child = rst_mem_alloc(sizeof(*child), RM_PRIVATE);
|
|
+ if (!child)
|
|
+ return -1;
|
|
+
|
|
+ (*n)++;
|
|
+ *child = fle->fe->fd;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
static int collect_child_pids(int state, unsigned int *n)
|
|
{
|
|
struct pstree_item *pi;
|
|
@@ -715,6 +737,12 @@ static int collect_child_pids(int state, unsigned int *n)
|
|
return __collect_child_pids(current, state, n);
|
|
}
|
|
|
|
+static int collect_chr_fds(struct pstree_item *me, struct task_restore_args *ta)
|
|
+{
|
|
+ ta->setcred_pids = (int *)rst_mem_align_cpos(RM_PRIVATE);
|
|
+ return collect_child_fds(FD_TYPES__CHR, &ta->setcred_pids_n, me);
|
|
+}
|
|
+
|
|
static int collect_helper_pids(struct task_restore_args *ta)
|
|
{
|
|
ta->helpers = (pid_t *)rst_mem_align_cpos(RM_PRIVATE);
|
|
@@ -939,6 +967,9 @@ static int restore_one_alive_task(int pid, CoreEntry *core)
|
|
if (collect_zombie_pids(ta) < 0)
|
|
return -1;
|
|
|
|
+ if (opts.with_fd_cred && collect_chr_fds(current, ta) < 0)
|
|
+ return -1;
|
|
+
|
|
if (collect_inotify_fds(ta) < 0)
|
|
return -1;
|
|
|
|
@@ -3746,6 +3777,10 @@ static int sigreturn_restore(pid_t pid, struct task_restore_args *task_args, uns
|
|
RST_MEM_FIXUP_PPTR(task_args->helpers);
|
|
RST_MEM_FIXUP_PPTR(task_args->zombies);
|
|
RST_MEM_FIXUP_PPTR(task_args->vma_ios);
|
|
+ if (opts.with_fd_cred)
|
|
+ RST_MEM_FIXUP_PPTR(task_args->setcred_pids);
|
|
+ else
|
|
+ task_args->setcred_pids_n = UINT_MAX;
|
|
RST_MEM_FIXUP_PPTR(task_args->inotify_fds);
|
|
|
|
task_args->compatible_mode = core_is_compat(core);
|
|
diff --git a/criu/crtools.c b/criu/crtools.c
|
|
index dc6d603..ed7bd99 100644
|
|
--- a/criu/crtools.c
|
|
+++ b/criu/crtools.c
|
|
@@ -453,6 +453,7 @@ usage:
|
|
" This feature needs the kernel assistance.\n"
|
|
" --dump-char-dev Dump char dev files as normal file with repair cmd\n"
|
|
\
|
|
+ " --with-fd-cred Allow to make the restored process has the same cred\n"
|
|
"\n"
|
|
"Check options:\n"
|
|
" Without options, \"criu check\" checks availability of absolutely required\n"
|
|
diff --git a/criu/include/cr_options.h b/criu/include/cr_options.h
|
|
index 226acb2..1d6ddcf 100644
|
|
--- a/criu/include/cr_options.h
|
|
+++ b/criu/include/cr_options.h
|
|
@@ -194,6 +194,7 @@ struct cr_options {
|
|
int use_fork_pid;
|
|
int with_notifier_kup;
|
|
int dump_char_dev;
|
|
+ int with_fd_cred;
|
|
};
|
|
|
|
extern struct cr_options opts;
|
|
diff --git a/criu/include/fcntl.h b/criu/include/fcntl.h
|
|
index 35f8805..568977c 100644
|
|
--- a/criu/include/fcntl.h
|
|
+++ b/criu/include/fcntl.h
|
|
@@ -19,6 +19,10 @@ struct f_owner_ex {
|
|
#define F_GETOWNER_UIDS 17
|
|
#endif
|
|
|
|
+#ifndef F_SETCRED
|
|
+#define F_SETCRED 18
|
|
+#endif
|
|
+
|
|
/*
|
|
* These things are required to compile on CentOS-6
|
|
*/
|
|
diff --git a/criu/include/prctl.h b/criu/include/prctl.h
|
|
index c843f40..81dda9d 100644
|
|
--- a/criu/include/prctl.h
|
|
+++ b/criu/include/prctl.h
|
|
@@ -82,4 +82,8 @@ struct prctl_mm_map {
|
|
#define PR_GET_THP_DISABLE 42
|
|
#endif
|
|
|
|
+#ifndef PR_DEFAULT_CRED
|
|
+#define PR_DEFAULT_CRED 54
|
|
+#endif
|
|
+
|
|
#endif /* __CR_PRCTL_H__ */
|
|
diff --git a/criu/include/restorer.h b/criu/include/restorer.h
|
|
index a81cc1b..60c1dab 100644
|
|
--- a/criu/include/restorer.h
|
|
+++ b/criu/include/restorer.h
|
|
@@ -193,6 +193,9 @@ struct task_restore_args {
|
|
pid_t *zombies;
|
|
unsigned int zombies_n;
|
|
|
|
+ int *setcred_pids;
|
|
+ unsigned int setcred_pids_n;
|
|
+
|
|
int *inotify_fds; /* fds to cleanup inotify events at CR_STATE_RESTORE_SIGCHLD stage */
|
|
unsigned int inotify_fds_n;
|
|
|
|
diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c
|
|
index dcc922e..fde6e30 100644
|
|
--- a/criu/pie/restorer.c
|
|
+++ b/criu/pie/restorer.c
|
|
@@ -101,6 +101,7 @@ static int restore_anon_mapping(VmaEntry *vma_entry, struct vma_names *vma_name)
|
|
static struct task_entries *task_entries_local;
|
|
static futex_t thread_inprogress;
|
|
static futex_t thread_start;
|
|
+static futex_t cred_set;
|
|
static pid_t *helpers;
|
|
static int n_helpers;
|
|
static pid_t *zombies;
|
|
@@ -365,6 +366,41 @@ static int restore_creds(struct thread_creds_args *args, int procfd, int lsm_typ
|
|
return 0;
|
|
}
|
|
|
|
+static int update_cred_ref(struct task_restore_args *ta)
|
|
+{
|
|
+ int i;
|
|
+ int ret;
|
|
+ int pid = sys_getpid();
|
|
+ long int tid = sys_gettid();
|
|
+
|
|
+ if (ta->setcred_pids_n == UINT_MAX) {
|
|
+ pr_info("no need to keep the same cred \n");
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ if (pid == tid) {
|
|
+ /* let main thread finish cred update first */
|
|
+ ret = sys_prctl(PR_DEFAULT_CRED, 0, 0, 0, 0);
|
|
+ pr_info("main cred restore \n");
|
|
+ futex_set_and_wake(&cred_set, 1);
|
|
+ } else {
|
|
+ futex_wait_until(&cred_set, 1);
|
|
+ pr_info("other cred restore \n");
|
|
+ ret = sys_prctl(PR_DEFAULT_CRED, 0, 0, 0, 0);
|
|
+ }
|
|
+
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ pr_info("%ld (%d) is going to update current cred \n", tid, pid);
|
|
+
|
|
+ for (i = 0; i < ta->setcred_pids_n; i++) {
|
|
+ sys_fcntl(ta->setcred_pids[i], F_SETCRED, 0);
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
/*
|
|
* This should be done after creds restore, as
|
|
* some creds changes might drop the value back
|
|
@@ -742,6 +778,7 @@ long __export_restore_thread(struct thread_restore_args *args)
|
|
BUG();
|
|
|
|
ret = restore_creds(args->creds_args, args->ta->proc_fd, args->ta->lsm_type);
|
|
+ ret = ret || update_cred_ref(args->ta);
|
|
ret = ret || restore_dumpable_flag(&args->ta->mm);
|
|
ret = ret || restore_pdeath_sig(args);
|
|
if (ret)
|
|
@@ -2221,6 +2258,7 @@ long __export_restore_task(struct task_restore_args *args)
|
|
* thus restore* creds _after_ all of the above.
|
|
*/
|
|
ret = restore_creds(args->t->creds_args, args->proc_fd, args->lsm_type);
|
|
+ ret = ret || update_cred_ref(args);
|
|
ret = ret || restore_dumpable_flag(&args->mm);
|
|
ret = ret || restore_pdeath_sig(args->t);
|
|
ret = ret || restore_child_subreaper(args->child_subreaper);
|
|
--
|
|
2.34.1
|
|
|