[PATCH 25/30] cr: deal with credentials

From: Alexey Dobriyan
Date: Thu Apr 09 2009 - 22:46:16 EST


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
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/