Dump/restore struct cred, struct user, struct user_namespace, struct group_info FIXME: restore struct user FIXME: restore struct file::f_cred Signed-off-by: Alexey Dobriyan <adobriyan@xxxxxxxxx> --- include/linux/cr.h | 46 ++++ include/linux/cred.h | 1 kernel/cr/Kconfig | 1 kernel/cr/Makefile | 1 kernel/cr/cpt-sys.c | 24 ++ kernel/cr/cr-cred.c | 514 +++++++++++++++++++++++++++++++++++++++++++++++++++ kernel/cr/cr-file.c | 2 kernel/cr/cr-task.c | 8 kernel/cr/cr.h | 14 + kernel/cred.c | 2 10 files changed, 612 insertions(+), 1 deletion(-) --- a/include/linux/cr.h +++ b/include/linux/cr.h @@ -44,6 +44,10 @@ struct cr_object_header { #define CR_OBJ_FS_STRUCT 13 #define CR_OBJ_SIGNAL_STRUCT 14 #define CR_OBJ_SIGHAND_STRUCT 15 +#define CR_OBJ_CRED 16 +#define CR_OBJ_GROUP_INFO 17 +#define CR_OBJ_USER_STRUCT 18 +#define CR_OBJ_USER_NS 19 __u32 cr_type; /* object type */ __u32 cr_len; /* object length in bytes including header */ } __packed; @@ -74,6 +78,9 @@ struct cr_image_task_struct { __u8 cr_real_blocked[16]; __u8 cr_saved_sigmask[16]; + cr_pos_t cr_pos_real_cred; + cr_pos_t cr_pos_cred; + __u8 cr_comm[16]; /* Native arch of task, one of CR_ARCH_*. */ @@ -288,6 +295,7 @@ struct cr_image_file { __u32 cr_euid; __u32 cr_signum; } cr_f_owner; + cr_pos_t cr_pos_f_cred; __u32 cr_name_len; /* __u8 cr_name[cr_name_len] */ } __packed; @@ -301,6 +309,44 @@ struct cr_image_fd { __u32 cr_fd_flags; } __packed; +struct cr_image_cred { + struct cr_object_header cr_hdr; + + __u32 cr_uid; + __u32 cr_gid; + __u32 cr_suid; + __u32 cr_sgid; + __u32 cr_euid; + __u32 cr_egid; + __u32 cr_fsuid; + __u32 cr_fsgid; + __u32 cr_securebits; + __u64 cr_cap_inheritable; + __u64 cr_cap_permitted; + __u64 cr_cap_effective; + __u64 cr_cap_bset; + cr_pos_t cr_pos_user; + cr_pos_t cr_pos_group_info; +} __packed; + +struct cr_image_group_info { + struct cr_object_header cr_hdr; + + __u32 cr_ngroups; + /* __u32 cr_gid[cr_ngroups]; */ +} __packed; + +struct cr_image_user_struct { + struct cr_object_header cr_hdr; + + cr_pos_t cr_pos_user_ns; + __u32 cr_uid; +} __packed; + +struct cr_image_user_ns { + struct cr_object_header cr_hdr; +} __packed; + struct cr_image_pid { struct cr_object_header cr_hdr; --- a/include/linux/cred.h +++ b/include/linux/cred.h @@ -142,6 +142,7 @@ struct cred { struct rcu_head rcu; /* RCU deletion hook */ }; +extern struct kmem_cache *cred_jar; extern void __put_cred(struct cred *); extern int copy_creds(struct task_struct *, unsigned long); extern struct cred *prepare_creds(void); --- a/kernel/cr/Kconfig +++ b/kernel/cr/Kconfig @@ -1,6 +1,7 @@ config CR bool "Container checkpoint/restart" depends on PID_NS + depends on USER_NS depends on UTS_NS select FREEZER help --- a/kernel/cr/Makefile +++ b/kernel/cr/Makefile @@ -1,6 +1,7 @@ obj-$(CONFIG_CR) += cr.o cr-y := cpt-sys.o rst-sys.o cr-y += cr-context.o +cr-y += cr-cred.o cr-y += cr-file.o cr-y += cr-fs.o cr-y += cr-mm.o --- a/kernel/cr/cpt-sys.c +++ b/kernel/cr/cpt-sys.c @@ -92,6 +92,18 @@ static int cr_collect(struct cr_context *ctx) rv = cr_collect_all_sighand_struct(ctx); if (rv < 0) return rv; + rv = cr_collect_all_cred(ctx); + if (rv < 0) + return rv; + rv = cr_collect_all_group_info(ctx); + if (rv < 0) + return rv; + rv = cr_collect_all_user_struct(ctx); + if (rv < 0) + return rv; + rv = cr_collect_all_user_ns(ctx); + if (rv < 0) + return rv; rv = cr_collect_all_pid(ctx); if (rv < 0) return rv; @@ -134,6 +146,18 @@ static int cr_dump(struct cr_context *ctx) rv = cr_dump_all_pid(ctx); if (rv < 0) return rv; + rv = cr_dump_all_user_ns(ctx); + if (rv < 0) + return rv; + rv = cr_dump_all_user_struct(ctx); + if (rv < 0) + return rv; + rv = cr_dump_all_group_info(ctx); + if (rv < 0) + return rv; + rv = cr_dump_all_cred(ctx); + if (rv < 0) + return rv; rv = cr_dump_all_file(ctx); if (rv < 0) return rv; new file mode 100644 --- /dev/null +++ b/kernel/cr/cr-cred.c @@ -0,0 +1,514 @@ +/* Copyright (C) 2000-2009 Parallels Holdings, Ltd. */ +#include <linux/cred.h> +#include <linux/fs.h> +#include <linux/sched.h> +#include <linux/user_namespace.h> + +#include <linux/cr.h> +#include "cr.h" + +static int cr_collect_group_info(struct cr_context *ctx, struct group_info *gi) +{ + int rv; + + rv = cr_collect_object(ctx, gi, CR_CTX_GROUP_INFO); + printk("collect group_info %p: rv %d\n", gi, rv); + return rv; +} + +int cr_collect_all_group_info(struct cr_context *ctx) +{ + struct cr_object *obj; + int rv; + + for_each_cr_object(ctx, obj, CR_CTX_CRED) { + struct cred *cred = obj->o_obj; + + rv = cr_collect_group_info(ctx, cred->group_info); + if (rv < 0) + return rv; + } + for_each_cr_object(ctx, obj, CR_CTX_GROUP_INFO) { + struct group_info *gi = obj->o_obj; + unsigned int cnt = atomic_read(&gi->usage); + + if (obj->o_count != cnt) { + printk("%s: group_info %p has external references %lu:%u\n", __func__, gi, obj->o_count, cnt); + /* return -EINVAL; */ + } + } + return 0; +} + +static int cr_dump_group_info(struct cr_context *ctx, struct cr_object *obj) +{ + struct group_info *gi = obj->o_obj; + struct cr_image_group_info *i; + __u32 *cr_gid; + size_t image_len; + int n; + int rv; + + printk("dump group_info %p: ngroups %d\n", gi, gi->ngroups); + + image_len = sizeof(*i) + gi->ngroups * sizeof(__u32); + i = cr_prepare_image(CR_OBJ_GROUP_INFO, image_len); + if (!i) + return -ENOMEM; + + i->cr_ngroups = gi->ngroups; + cr_gid = (__u32 *)(i + 1); + for (n = 0; n < gi->ngroups; n++) + cr_gid[n] = GROUP_AT(gi, n); + + obj->o_pos = ctx->cr_dump_file->f_pos; + rv = cr_write(ctx, i, image_len); + kfree(i); + return rv; +} + +int cr_dump_all_group_info(struct cr_context *ctx) +{ + struct cr_object *obj; + int rv; + + for_each_cr_object(ctx, obj, CR_CTX_GROUP_INFO) { + rv = cr_dump_group_info(ctx, obj); + if (rv < 0) + return rv; + } + return 0; +} + +int cr_restore_group_info(struct cr_context *ctx, loff_t pos) +{ + struct cr_image_group_info *i, *tmp; + struct group_info *gi; + struct cr_object *obj; + size_t image_len; + __u32 *cr_gid; + int n; + int rv; + + i = kzalloc(sizeof(*i), GFP_KERNEL); + if (!i) + return -ENOMEM; + rv = cr_pread(ctx, i, sizeof(*i), pos); + if (rv < 0) { + kfree(i); + return rv; + } + if (i->cr_hdr.cr_type != CR_OBJ_GROUP_INFO) { + kfree(i); + return -EINVAL; + } + /* struct cr_image_group_info is variable-sized. */ + image_len = sizeof(*i) + i->cr_ngroups * sizeof(__u32); + tmp = i; + i = krealloc(i, image_len, GFP_KERNEL); + if (!i) { + kfree(tmp); + return -ENOMEM; + } + rv = cr_pread(ctx, i + 1, image_len - sizeof(*i), pos + sizeof(*i)); + if (rv < 0) { + kfree(i); + return rv; + } + + gi = groups_alloc(i->cr_ngroups); + if (!gi) { + kfree(i); + return -ENOMEM; + } + cr_gid = (__u32 *)(i + 1); + for (n = 0; n < gi->ngroups; n++) + GROUP_AT(gi, n) = cr_gid[n]; + kfree(i); + + obj = cr_object_create(gi); + if (!obj) { + groups_free(gi); + return -ENOMEM; + } + obj->o_pos = pos; + list_add(&obj->o_list, &ctx->cr_obj[CR_CTX_GROUP_INFO]); + printk("restore group_info %p, pos %lld\n", gi, (long long)pos); + return 0; +} + +static int cr_check_user_struct(struct user_struct *user) +{ +#ifdef CONFIG_INOTIFY_USER + if (atomic_read(&user->inotify_watches) != 0) { + WARN_ON(1); + return -EINVAL; + } + if (atomic_read(&user->inotify_devs) != 0) { + WARN_ON(1); + return -EINVAL; + } +#endif +#ifdef CONFIG_EPOLL + if (atomic_read(&user->epoll_watches) != 0) { + WARN_ON(1); + return -EINVAL; + } +#endif +#ifdef CONFIG_KEYS + if (user->uid_keyring || user->session_keyring) { + WARN_ON(1); + return -EINVAL; + } +#endif + return 0; +} + +static int cr_collect_user_struct(struct cr_context *ctx, struct user_struct *user) +{ + int rv; + + rv = cr_check_user_struct(user); + if (rv < 0) + return rv; + rv = cr_collect_object(ctx, user, CR_CTX_USER_STRUCT); + printk("collect user_struct %p: rv %d\n", user, rv); + return rv; +} + +int cr_collect_all_user_struct(struct cr_context *ctx) +{ + struct cr_object *obj; + int rv; + + for_each_cr_object(ctx, obj, CR_CTX_CRED) { + struct cred *cred = obj->o_obj; + + rv = cr_collect_user_struct(ctx, cred->user); + if (rv < 0) + return rv; + } + for_each_cr_object(ctx, obj, CR_CTX_USER_STRUCT) { + struct user_struct *user = obj->o_obj; + unsigned int cnt = atomic_read(&user->__count); + + if (obj->o_count != cnt) { + printk("%s: user_struct %p/%d has external references %lu:%u\n", __func__, user, user->uid, obj->o_count, cnt); + return -EINVAL; + } + } + return 0; +} + +static int cr_dump_user_struct(struct cr_context *ctx, struct cr_object *obj) +{ + struct user_struct *user = obj->o_obj; + struct cr_image_user_struct *i; + struct cr_object *tmp; + int rv; + + printk("dump user_struct %p: uid %d\n", user, user->uid); + + i = cr_prepare_image(CR_OBJ_USER_STRUCT, sizeof(*i)); + if (!i) + return -ENOMEM; + + tmp = cr_find_obj_by_ptr(ctx, user->user_ns, CR_CTX_USER_NS); + i->cr_pos_user_ns = tmp->o_pos; + i->cr_uid = user->uid; + + obj->o_pos = ctx->cr_dump_file->f_pos; + rv = cr_write(ctx, i, sizeof(*i)); + kfree(i); + return rv; +} + +int cr_dump_all_user_struct(struct cr_context *ctx) +{ + struct cr_object *obj; + int rv; + + for_each_cr_object(ctx, obj, CR_CTX_USER_STRUCT) { + rv = cr_dump_user_struct(ctx, obj); + if (rv < 0) + return rv; + } + return 0; +} + +static int cr_collect_user_ns(struct cr_context *ctx, struct user_namespace *user_ns) +{ + int rv; + + rv = cr_collect_object(ctx, user_ns, CR_CTX_USER_NS); + printk("collect user_ns %p: rv %d\n", user_ns, rv); + return rv; +} + +int cr_collect_all_user_ns(struct cr_context *ctx) +{ + struct cr_object *obj; + int rv; + + for_each_cr_object(ctx, obj, CR_CTX_USER_STRUCT) { + struct user_struct *user = obj->o_obj; + + rv = cr_collect_user_ns(ctx, user->user_ns); + if (rv < 0) + return rv; + } + for_each_cr_object(ctx, obj, CR_CTX_USER_NS) { + struct user_namespace *user_ns = obj->o_obj; + unsigned int cnt = atomic_read(&user_ns->kref.refcount); + + if (obj->o_count != cnt) { + printk("%s: user_ns %p has external references %lu:%u\n", __func__, user_ns, obj->o_count, cnt); + /* return -EINVAL; */ + } + } + return 0; +} + +static int cr_dump_user_ns(struct cr_context *ctx, struct cr_object *obj) +{ + struct user_namespace *user_ns = obj->o_obj; + struct cr_image_user_ns *i; + int rv; + + printk("dump user_ns %p\n", user_ns); + + i = cr_prepare_image(CR_OBJ_USER_NS, sizeof(*i)); + if (!i) + return -ENOMEM; + + obj->o_pos = ctx->cr_dump_file->f_pos; + rv = cr_write(ctx, i, sizeof(*i)); + kfree(i); + return rv; +} + +int cr_dump_all_user_ns(struct cr_context *ctx) +{ + struct cr_object *obj; + int rv; + + for_each_cr_object(ctx, obj, CR_CTX_USER_NS) { + rv = cr_dump_user_ns(ctx, obj); + if (rv < 0) + return rv; + } + return 0; +} + +static int cr_check_cred(struct cred *cred) +{ +#ifdef CONFIG_KEYS + if (cred->thread_keyring || cred->request_key_auth || cred->tgcred) { + WARN_ON(1); + return -EINVAL; + } +#endif +#ifdef CONFIG_SECURITY + if (cred->security) { + WARN_ON(1); + return -EINVAL; + } +#endif + return 0; +} + +static int cr_collect_cred(struct cr_context *ctx, struct cred *cred) +{ + int rv; + + rv = cr_check_cred(cred); + if (rv < 0) + return rv; + rv = cr_collect_object(ctx, cred, CR_CTX_CRED); + printk("collect cred %p: rv %d\n", cred, rv); + return rv; +} + +int cr_collect_all_cred(struct cr_context *ctx) +{ + struct cr_object *obj; + int rv; + + for_each_cr_object(ctx, obj, CR_CTX_TASK_STRUCT) { + struct task_struct *tsk = obj->o_obj; + + rv = cr_collect_cred(ctx, (struct cred *)tsk->real_cred); + if (rv < 0) + return rv; + rv = cr_collect_cred(ctx, (struct cred *)tsk->cred); + if (rv < 0) + return rv; + } + for_each_cr_object(ctx, obj, CR_CTX_FILE) { + struct file *file = obj->o_obj; + + rv = cr_collect_cred(ctx, (struct cred *)file->f_cred); + if (rv < 0) + return rv; + } + for_each_cr_object(ctx, obj, CR_CTX_CRED) { + struct cred *cred = obj->o_obj; + unsigned int cnt = atomic_read(&cred->usage); + + if (obj->o_count != cnt) { + printk("%s: cred %p has external references %lu:%u\n", __func__, cred, obj->o_count, cnt); + return -EINVAL; + } + } + return 0; +} + +static int cr_dump_cred(struct cr_context *ctx, struct cr_object *obj) +{ + struct cred *cred = obj->o_obj; + struct cr_image_cred *i; + struct cr_object *tmp; + int rv; + + printk("dump cred %p\n", cred); + + i = cr_prepare_image(CR_OBJ_CRED, sizeof(*i)); + if (!i) + return -ENOMEM; + + i->cr_uid = cred->uid; + i->cr_gid = cred->gid; + i->cr_suid = cred->suid; + i->cr_sgid = cred->sgid; + i->cr_euid = cred->euid; + i->cr_egid = cred->egid; + i->cr_fsuid = cred->fsuid; + i->cr_fsgid = cred->fsgid; + i->cr_securebits = cred->securebits; + BUILD_BUG_ON(sizeof(cred->cap_inheritable) != 8); + memcpy(&i->cr_cap_inheritable, &cred->cap_inheritable, 8); + memcpy(&i->cr_cap_permitted, &cred->cap_permitted, 8); + memcpy(&i->cr_cap_effective, &cred->cap_effective, 8); + memcpy(&i->cr_cap_bset, &cred->cap_bset, 8); + tmp = cr_find_obj_by_ptr(ctx, cred->user, CR_CTX_USER_STRUCT); + i->cr_pos_user = tmp->o_pos; + tmp = cr_find_obj_by_ptr(ctx, cred->group_info, CR_CTX_GROUP_INFO); + i->cr_pos_group_info = tmp->o_pos; + + obj->o_pos = ctx->cr_dump_file->f_pos; + rv = cr_write(ctx, i, sizeof(*i)); + kfree(i); + return rv; +} + +int cr_dump_all_cred(struct cr_context *ctx) +{ + struct cr_object *obj; + int rv; + + for_each_cr_object(ctx, obj, CR_CTX_CRED) { + rv = cr_dump_cred(ctx, obj); + if (rv < 0) + return rv; + } + return 0; +} + +static int __cr_restore_cred(struct cr_context *ctx, loff_t pos) +{ + struct cr_image_cred *i; + struct cred *cred; + struct group_info *gi; + struct cr_object *obj, *tmp; + int rv; + + i = kzalloc(sizeof(*i), GFP_KERNEL); + if (!i) + return -ENOMEM; + rv = cr_pread(ctx, i, sizeof(*i), pos); + if (rv < 0) { + kfree(i); + return rv; + } + if (i->cr_hdr.cr_type != CR_OBJ_CRED) { + kfree(i); + return -EINVAL; + } + + cred = kmem_cache_zalloc(cred_jar, GFP_KERNEL); + if (!cred) { + kfree(i); + return -ENOMEM; + } + atomic_set(&cred->usage, 1); + + cred->uid = i->cr_uid; + cred->gid = i->cr_gid; + cred->suid = i->cr_suid; + cred->sgid = i->cr_sgid; + cred->euid = i->cr_euid; + cred->egid = i->cr_egid; + cred->fsuid = i->cr_fsuid; + cred->fsgid = i->cr_fsgid; + cred->securebits = i->cr_securebits; + memcpy(&cred->cap_inheritable, &i->cr_cap_inheritable, 8); + memcpy(&cred->cap_permitted, &i->cr_cap_permitted, 8); + memcpy(&cred->cap_effective, &i->cr_cap_effective, 8); + memcpy(&cred->cap_bset, &i->cr_cap_bset, 8); + atomic_inc(&root_user.__count); + cred->user = &root_user; /* FIXME */ + tmp = cr_find_obj_by_pos(ctx, i->cr_pos_group_info, CR_CTX_GROUP_INFO); + if (!tmp) { + rv = cr_restore_group_info(ctx, i->cr_pos_group_info); + if (rv < 0) { + free_uid(cred->user); + kmem_cache_free(cred_jar, cred); + return rv; + } + tmp = cr_find_obj_by_pos(ctx, i->cr_pos_group_info, CR_CTX_GROUP_INFO); + } + gi = tmp->o_obj; + cred->group_info = get_group_info(gi); + kfree(i); + + obj = cr_object_create(cred); + if (!obj) { + put_cred(cred); + return -ENOMEM; + } + obj->o_pos = pos; + list_add(&obj->o_list, &ctx->cr_obj[CR_CTX_CRED]); + printk("restore cred %p, pos %lld\n", cred, (long long)pos); + return 0; +} + +int cr_restore_cred(struct cr_context *ctx, struct cr_image_task_struct *i) +{ + struct task_struct *tsk = current; + struct cred *cred; + struct cr_object *tmp; + int rv; + + tmp = cr_find_obj_by_pos(ctx, i->cr_pos_cred, CR_CTX_CRED); + if (!tmp) { + rv = __cr_restore_cred(ctx, i->cr_pos_cred); + if (rv < 0) + return rv; + tmp = cr_find_obj_by_pos(ctx, i->cr_pos_cred, CR_CTX_CRED); + } + cred = tmp->o_obj; + put_cred(tsk->cred); + tsk->cred = get_cred(cred); + + tmp = cr_find_obj_by_pos(ctx, i->cr_pos_real_cred, CR_CTX_CRED); + if (!tmp) { + rv = __cr_restore_cred(ctx, i->cr_pos_real_cred); + if (rv < 0) + return rv; + tmp = cr_find_obj_by_pos(ctx, i->cr_pos_real_cred, CR_CTX_CRED); + } + cred = tmp->o_obj; + put_cred(tsk->real_cred); + tsk->real_cred = get_cred(cred); + return 0; +} --- a/kernel/cr/cr-file.c +++ b/kernel/cr/cr-file.c @@ -133,6 +133,8 @@ int generic_file_checkpoint(struct file *file, struct cr_context *ctx) i->cr_f_owner.cr_uid = file->f_owner.uid; i->cr_f_owner.cr_euid = file->f_owner.euid; i->cr_f_owner.cr_signum = file->f_owner.signum; + tmp = cr_find_obj_by_ptr(ctx, file->f_cred, CR_CTX_CRED); + i->cr_pos_f_cred = tmp->o_pos; buf = kmalloc(PAGE_SIZE, GFP_KERNEL); if (!buf) { --- a/kernel/cr/cr-task.c +++ b/kernel/cr/cr-task.c @@ -140,6 +140,11 @@ static int cr_dump_task_struct(struct cr_context *ctx, struct cr_object *obj) cr_dump_sigset(i->cr_real_blocked, &tsk->real_blocked); cr_dump_sigset(i->cr_saved_sigmask, &tsk->saved_sigmask); + tmp = cr_find_obj_by_ptr(ctx, tsk->real_cred, CR_CTX_CRED); + i->cr_pos_real_cred = tmp->o_pos; + tmp = cr_find_obj_by_ptr(ctx, tsk->cred, CR_CTX_CRED); + i->cr_pos_cred = tmp->o_pos; + BUILD_BUG_ON(TASK_COMM_LEN != 16); strlcpy((char *)i->cr_comm, (const char *)tsk->comm, sizeof(i->cr_comm)); @@ -210,6 +215,9 @@ static int task_struct_restorer(void *_tsk_ctx) cr_restore_sigset(&tsk->blocked, i->cr_blocked); cr_restore_sigset(&tsk->real_blocked, i->cr_real_blocked); cr_restore_sigset(&tsk->saved_sigmask, i->cr_saved_sigmask); + rv = cr_restore_cred(ctx, i); + if (rv < 0) + goto out; rv = 0; out: --- a/kernel/cr/cr.h +++ b/kernel/cr/cr.h @@ -22,9 +22,11 @@ struct cr_object { /* Not visible to userspace! */ enum cr_context_obj_type { + CR_CTX_CRED, CR_CTX_FILE, CR_CTX_FILES_STRUCT, CR_CTX_FS_STRUCT, + CR_CTX_GROUP_INFO, CR_CTX_MM_STRUCT, CR_CTX_NSPROXY, CR_CTX_PID, @@ -32,6 +34,8 @@ enum cr_context_obj_type { CR_CTX_SIGHAND_STRUCT, CR_CTX_SIGNAL_STRUCT, CR_CTX_TASK_STRUCT, + CR_CTX_USER_NS, + CR_CTX_USER_STRUCT, CR_CTX_UTS_NS, NR_CR_CTX_TYPES }; @@ -85,9 +89,11 @@ static inline void cr_restore_sigset(sigset_t *sig, __u8 *cr_image_sigset) memcpy(sig, cr_image_sigset, sizeof(sigset_t)); } +int cr_collect_all_cred(struct cr_context *ctx); int cr_collect_all_files_struct(struct cr_context *ctx); int cr_collect_all_file(struct cr_context *ctx); int cr_collect_all_fs_struct(struct cr_context *ctx); +int cr_collect_all_group_info(struct cr_context *ctx); int cr_collect_all_mm_struct(struct cr_context *ctx); int cr_collect_all_nsproxy(struct cr_context *ctx); int cr_collect_all_pid_ns(struct cr_context *ctx); @@ -95,11 +101,15 @@ int cr_collect_all_pid(struct cr_context *ctx); int cr_collect_all_sighand_struct(struct cr_context *ctx); int cr_collect_all_signal_struct(struct cr_context *ctx); int cr_collect_all_task_struct(struct cr_context *ctx); +int cr_collect_all_user_ns(struct cr_context *ctx); +int cr_collect_all_user_struct(struct cr_context *ctx); int cr_collect_all_uts_ns(struct cr_context *ctx); +int cr_dump_all_cred(struct cr_context *ctx); int cr_dump_all_files_struct(struct cr_context *ctx); int cr_dump_all_file(struct cr_context *ctx); int cr_dump_all_fs_struct(struct cr_context *ctx); +int cr_dump_all_group_info(struct cr_context *ctx); int cr_dump_all_mm_struct(struct cr_context *ctx); int cr_dump_all_nsproxy(struct cr_context *ctx); int cr_dump_all_pid_ns(struct cr_context *ctx); @@ -107,11 +117,15 @@ int cr_dump_all_pid(struct cr_context *ctx); int cr_dump_all_sighand_struct(struct cr_context *ctx); int cr_dump_all_signal_struct(struct cr_context *ctx); int cr_dump_all_task_struct(struct cr_context *ctx); +int cr_dump_all_user_ns(struct cr_context *ctx); +int cr_dump_all_user_struct(struct cr_context *ctx); int cr_dump_all_uts_ns(struct cr_context *ctx); +int cr_restore_cred(struct cr_context *ctx, struct cr_image_task_struct *i); int cr_restore_files_struct(struct cr_context *ctx, loff_t pos); int cr_restore_file(struct cr_context *ctx, loff_t pos); int cr_restore_fs_struct(struct cr_context *ctx, loff_t pos); +int cr_restore_group_info(struct cr_context *ctx, loff_t pos); int cr_restore_mm_struct(struct cr_context *ctx, loff_t pos); int cr_restore_nsproxy(struct cr_context *ctx, loff_t pos); int cr_restore_pid_ns(struct cr_context *ctx, loff_t pos); --- a/kernel/cred.c +++ b/kernel/cred.c @@ -18,7 +18,7 @@ #include <linux/cn_proc.h> #include "cred-internals.h" -static struct kmem_cache *cred_jar; +struct kmem_cache *cred_jar; /* * The common credentials for the initial task's thread group _______________________________________________ Containers mailing list Containers@xxxxxxxxxxxxxxxxxxxxxxxxxx https://lists.linux-foundation.org/mailman/listinfo/containers