Skip to contentSkip to conversation

cr: credentials

PATCH In review Serge E. Hallyn 3 participants 27 messages May 19, 2009 – May 21, 2009 16 messages not in the archive

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

cover cr: credentials

Here is my latest version of the task credentials c/r patchset. The last patch isn't meant to go upstream - it just helped me to straighten out the refcounting, to the point where nested user namespace c/r now appears to be robust.

thanks,
-serge

A message that is not in the archive (sent off-list or not yet received): 20090519014446.GA28277-r/[email protected]

#2 lore raw

PATCH 1/6 cr: break out new_user_ns()

Break out the core function which checks privilege and (if allowed) creates a new user namespace, with the passed-in creating user_struct. Note that a user_namespace, unlike other namespace pointers, is not stored in the nsproxy. Rather it is purely a property of user_structs.

This will let us keep the task restore code simpler.

---
 include/linux/user_namespace.h |    8 ++++++
 kernel/user_namespace.c        |   53 ++++++++++++++++++++++++++++------------
 2 files changed, 45 insertions(+), 16 deletions(-)
include/linux/user_namespace.h +8 -0
index cc4f453..a2b82d5 100644
@@ -20,6 +20,8 @@ extern struct user_namespace init_user_ns;
 
 #ifdef CONFIG_USER_NS
 
+struct user_namespace *new_user_ns(struct user_struct *creator,
+				   struct user_struct **newroot);
 static inline struct user_namespace *get_user_ns(struct user_namespace *ns)
 {
 	if (ns)
@@ -38,6 +40,12 @@ static inline void put_user_ns(struct user_namespace *ns)
 
 #else
 
+static inline struct user_namespace *new_user_ns(struct user_struct *creator,
+				   struct user_struct **newroot)
+{
+	return -EINVAL;
+}
+
 static inline struct user_namespace *get_user_ns(struct user_namespace *ns)
 {
 	return &init_user_ns;
kernel/user_namespace.c +37 -16

80 lines not on this page · raw message

Signature · 1 line
1.6.1
#3 lore raw

PATCH 2/6 cr: split core function out of some set*{u,g}id functions

In reply to a message not in the archive

When restarting tasks, we want to be able to change xuid and xgid in a struct cred, and do so with security checks. Break the core functionality of set{fs,res}{u,g}id into cred_setX which performs the access checks based on current_cred(), but performs the requested change on a passed-in cred.

This will allow us to securely construct struct creds based on a checkpoint image, constrained by the caller's permissions, and apply them to the caller at the end of sys_restart().

---
 include/linux/cred.h |    8 +++
 kernel/cred.c        |  114 ++++++++++++++++++++++++++++++++++++++++++
 kernel/sys.c         |  134 ++++++++------------------------------------------
 3 files changed, 143 insertions(+), 113 deletions(-)
include/linux/cred.h +8 -0
index 3282ee4..bc5ffc2 100644
@@ -20,6 +20,9 @@ struct user_struct;
 struct cred;
 struct inode;
 
+/* defined in sys.c, used in cred_setresuid */
+extern int set_user(struct cred *new);
+
 /*
  * COW Supplementary groups list
  */
@@ -343,4 +346,9 @@ do {						\
 	*(_fsgid) = __cred->fsgid;		\
 } while(0)
 
+int cred_setresuid(struct cred *new, uid_t ruid, uid_t euid, uid_t suid);
+int cred_setresgid(struct cred *new, gid_t rgid, gid_t egid, gid_t sgid);
+int cred_setfsuid(struct cred *new, uid_t uid, uid_t *old_fsuid);
+int cred_setfsgid(struct cred *new, gid_t gid, gid_t *old_fsgid);
+
 #endif /* _LINUX_CRED_H */
kernel/cred.c +114 -0

117 lines not on this page · raw message

kernel/sys.c +21 -113

210 lines not on this page · raw message

Signature · 1 line
1.6.1
#4 lore raw

PATCH 3/6 cr: capabilities: define checkpoint and restore fns

In reply to a message not in the archive

An application checkpoint image will store capability sets (and the bounding set) as __u64s. Define checkpoint and restart functions to translate between those and kernel_cap_t's.

Define a common function do_capset_tocred() which applies capability set changes to a passed-in struct cred.

The restore function uses do_capset_tocred() to apply the restored capabilities to the struct cred being crafted, subject to the current task's (task executing sys_restart()) permissions.

TODO: one day we'll want to c/r the securebits as well.

---
 include/linux/capability.h |    5 ++
 kernel/capability.c        |   94 +++++++++++++++++++++++++++++++++++++------
 2 files changed, 86 insertions(+), 13 deletions(-)
include/linux/capability.h +5 -0
index c302110..572b5a0 100644
@@ -536,6 +536,11 @@ extern const kernel_cap_t __cap_empty_set;
 extern const kernel_cap_t __cap_full_set;
 extern const kernel_cap_t __cap_init_eff_set;
 
+extern void checkpoint_save_cap(__u64 *dest, kernel_cap_t src);
+struct cred;
+extern int checkpoint_restore_cap(__u64 e, __u64 i, __u64 p, __u64 x,
+				struct cred *cred);
+
 /**
  * has_capability - Determine if a task has a superior capability available
  * @t: The task in question
kernel/capability.c +81 -13

116 lines not on this page · raw message

Signature · 1 line
1.6.1
#5 lore raw

PATCH 4/6 cr: checkpoint and restore task credentials

In reply to a message not in the archive

This patch adds the checkpointing and restart of credentials (uids, gids, and capabilities) to Oren's c/r patchset (on top of v14). It goes to great pains to re-use (and define when needed) common helpers, in order to make sure that as security code is modified, the cr code will be updated. Some of the helpers should still be moved (i.e. _creds() functions should be in kernel/cred.c).

When building the credentials for the restarted process, I
1. create a new struct cred as a copy of the running task's cred (using prepare_cred())
2. always authorize any changes to the new struct cred based on the permissions of current_cred() (not the current transient state of the new cred).

While this may mean that certain transient_cred1->transient_cred2 states are allowed which otherwise wouldn't be allowed, the fact remains that current_cred() is allowed to transition to transient_cred2.

The reconstructed creds are applied to the task at the very end of the sys_restart call. This ensures that any objects which need to be re-created (file, socket, etc) are re-created using the creds of the task calling sys_restart - preventing an unpriv user from creating a privileged object, and ensuring that a root task can restart a process which had started out privileged, created some privileged objects, then dropped its privilege.

With these patches, the root user can restart checkpoint images (created by either hallyn or root) of user hallyn's tasks, resulting in a program owned by hallyn.

Plenty of bugs to be found, no doubt.

Changelog:
May 18: fix more refcounting: if (userns 5, uid 0) had
no active tasks or child user_namespaces, then it shouldn't exist at restart or it, its namespace, and its whole chain of creators will be leaked.
May 14: fix some refcounting:
1. a new user_ns needs a ref to remain pinned by its root user
2. current_user_ns needs an extra ref bc objhash drops two on restart
3. cred needs a ref for the real credentials bc commit_creds eats one ref.
May 13: folded in fix to userns refcounting.

---
 checkpoint/objhash.c             |  119 ++++++++++-
 checkpoint/process.c             |  457 +++++++++++++++++++++++++++++++++++++-
 include/linux/checkpoint.h       |   11 +
 include/linux/checkpoint_hdr.h   |   57 +++++
 include/linux/checkpoint_types.h |    1 +
 5 files changed, 642 insertions(+), 3 deletions(-)
checkpoint/objhash.c +118 -1
index 5618fff..d2268c2 100644
@@ -16,6 +16,7 @@
 #include <linux/file.h>
 #include <linux/sched.h>
 #include <linux/ipc_namespace.h>
+#include <linux/user_namespace.h>
 #include <linux/checkpoint.h>
 #include <linux/checkpoint_hdr.h>
 
@@ -155,6 +156,71 @@ static int obj_ipc_ns_users(void *ptr)
 	return atomic_read(&((struct ipc_namespace *) ptr)->count);
 }
 
+static int obj_cred_grab(void *ptr)
+{
+	get_cred((struct cred *) ptr);
+	return 0;
+}
+
+static void obj_cred_drop(void *ptr)
+{
+	put_cred((struct cred *) ptr);
+}
+
+static int obj_cred_users(void *ptr)
+{
+	return atomic_read(&((struct cred *) ptr)->usage);
+}
+
+static int obj_user_grab(void *ptr)
+{
+	struct user_struct *u = ptr;
+	(void) get_uid(u);
+	return 0;
+}
+
+static void obj_user_drop(void *ptr)
+{
+	free_uid((struct user_struct *) ptr);
+}
+
+static int obj_user_users(void *ptr)
+{
+	return atomic_read(&((struct user_struct *) ptr)->__count);
+}
+
+static int obj_userns_grab(void *ptr)
+{
+	get_user_ns((struct user_namespace *) ptr);
+	return 0;
+}
+
+static void obj_userns_drop(void *ptr)
+{
+	put_user_ns((struct user_namespace *) ptr);
+}
+
+static int obj_user_ns_users(void *ptr)
+{
+	return atomic_read(&((struct user_namespace *) ptr)->kref.refcount);
+}
+
+static int obj_groupinfo_grab(void *ptr)
+{
+	get_group_info((struct group_info *) ptr);
+	return 0;
+}
+
+static void obj_groupinfo_drop(void *ptr)
+{
+	put_group_info((struct group_info *) ptr);
+}
+
+static int obj_groupinfo_users(void *ptr)
+{
+	return atomic_read(&((struct group_info *) ptr)->usage);
+}
+
 static struct ckpt_obj_ops ckpt_obj_ops[] = {
 	/* ignored object */
 	{
@@ -221,6 +287,46 @@ static struct ckpt_obj_ops ckpt_obj_ops[] = {
 		.checkpoint = checkpoint_bad,
 		.restore = restore_bad,
 	},
+	/* user_ns object */
+	{
+		.obj_name = "USER_NS",
+		.obj_type = CKPT_OBJ_USER_NS,
+		.ref_drop = obj_userns_drop,
+		.ref_grab = obj_userns_grab,
+		.ref_users = obj_user_ns_users,
+		.checkpoint = checkpoint_userns,
+		.restore = restore_userns,
+	},
+	/* struct cred */
+	{
+		.obj_name = "CRED",
+		.obj_type = CKPT_OBJ_CRED,
+		.ref_drop = obj_cred_drop,
+		.ref_grab = obj_cred_grab,
+		.ref_users = obj_cred_users,
+		.checkpoint = checkpoint_cred,
+		.restore = restore_cred,
+	},
+	/* user object */
+	{
+		.obj_name = "USER",
+		.obj_type = CKPT_OBJ_USER,
+		.ref_drop = obj_user_drop,
+		.ref_grab = obj_user_grab,
+		.ref_users = obj_user_users,
+		.checkpoint = checkpoint_user,
+		.restore = restore_user,
+	},
+	/* struct groupinfo */
+	{
+		.obj_name = "GROUPINFO",
+		.obj_type = CKPT_OBJ_GROUPINFO,
+		.ref_drop = obj_groupinfo_drop,
+		.ref_grab = obj_groupinfo_grab,
+		.ref_users = obj_groupinfo_users,
+		.checkpoint = checkpoint_groupinfo,
+		.restore = restore_groupinfo,
+	},
 };
 
 
@@ -290,6 +396,18 @@ static struct ckpt_obj *obj_find_by_ptr(struct ckpt_ctx *ctx, void *ptr)
 	return NULL;
 }
 
+/*
+ * look up an obj and return objref if in hash, else
+ * return 0.  Used during checkpoint.
+ */
+int obj_lookup_dontadd(struct ckpt_ctx *ctx, void *ptr)
+{
+	struct ckpt_obj *obj = obj_find_by_ptr(ctx, ptr);
+	if (obj)
+		return obj->objref;
+	return 0;
+}
+
 static struct ckpt_obj *obj_find_by_objref(struct ckpt_ctx *ctx, int objref)
 {
 	struct hlist_head *h;
@@ -389,7 +507,6 @@ int ckpt_obj_lookup_add(struct ckpt_ctx *ctx, void *ptr,
 		*first = 0;
 	}
 
-	ckpt_debug("%s objref %d first %d\n", ops->obj_name, objref, *first);
 	return objref;
 }
 
checkpoint/process.c +455 -2

511 lines not on this page · raw message

include/linux/checkpoint.h +11 -0
index d966f19..1b1326d 100644
@@ -53,6 +53,7 @@ extern void *ckpt_obj_fetch(struct ckpt_ctx *ctx, int objref,
 			    enum obj_type type);
 extern int ckpt_obj_lookup_add(struct ckpt_ctx *ctx, void *ptr,
 			       enum obj_type type, int *first);
+extern int obj_lookup_dontadd(struct ckpt_ctx *ctx, void *ptr);
 extern int ckpt_obj_insert(struct ckpt_ctx *ctx, void *ptr, int objref,
 			   enum obj_type type);
 
@@ -90,6 +91,16 @@ static inline int restore_ipc_ns(struct ckpt_ctx *ctx)
 extern int checkpoint_ipcns(struct ckpt_ctx *ctx, struct ipc_namespace *ipc_ns);
 extern int restore_ipcns(struct ckpt_ctx *ctx);
 
+/* credentials */
+int checkpoint_groupinfo(struct ckpt_ctx *ctx, void *ptr);
+int checkpoint_userns(struct ckpt_ctx *ctx, void *ptr);
+int checkpoint_user(struct ckpt_ctx *ctx, void *ptr);
+int checkpoint_cred(struct ckpt_ctx *ctx, void *ptr);
+void *restore_groupinfo(struct ckpt_ctx *ctx);
+void *restore_userns(struct ckpt_ctx *ctx);
+void *restore_user(struct ckpt_ctx *ctx);
+void *restore_cred(struct ckpt_ctx *ctx);
+
 /* memory */
 extern void ckpt_pgarr_free(struct ckpt_ctx *ctx);
 
include/linux/checkpoint_hdr.h +57 -0

79 lines not on this page · raw message

include/linux/checkpoint_types.h +1 -0
index 85ee304..2c4a9f0 100644
@@ -13,6 +13,7 @@
 #define CKPT_VERSION  1
 
 #define CHECKPOINT_SUBTREE	0x4
+#define RESTORE_CREATE_USERNS	0x8
 
 
 #ifdef __KERNEL__
Signature · 1 line
1.6.1
#6 lore raw

PATCH 5/6 cr: restore file->f_cred

In reply to a message not in the archive

Ony seems useful if you're using coda or hppfs, but go ahead and restore a file's f_cred. This is set to the cred of the task doing the open, so often it will be the same as that of the restarted task.

---
 checkpoint/files.c             |   16 ++++++++++++++--
 include/linux/checkpoint_hdr.h |    1 +
 2 files changed, 15 insertions(+), 2 deletions(-)
checkpoint/files.c +14 -2
index 6107361..edf81ce 100644
@@ -151,7 +151,11 @@ int checkpoint_file_common(struct ckpt_ctx *ctx, struct file *file,
 	h->f_pos = file->f_pos;
 	h->f_version = file->f_version;
 
-	/* FIX: need also file->uid, file->gid, file->f_owner, etc */
+	h->f_credref = checkpoint_obj(ctx, file->f_cred, CKPT_OBJ_CRED);
+	if (h->f_credref < 0)
+		return h->f_credref;
+
+	/* FIX: need also file->f_owner, etc */
 
 	return 0;
 }
@@ -359,8 +363,16 @@ int restore_file_common(struct ckpt_ctx *ctx, struct file *file,
 			struct ckpt_hdr_file *h)
 {
 	int ret;
+	struct cred *cred;
+
+	/* FIX: need to restore owner etc */
 
-	/* FIX: need to restore uid, gid, owner etc */
+	/* restore the cred */
+	cred = ckpt_obj_fetch(ctx, h->f_credref, CKPT_OBJ_CRED);
+	if (IS_ERR(cred))
+		return PTR_ERR(cred);
+	put_cred(file->f_cred);
+	file->f_cred = get_cred(cred);
 
 	/* safe to set 1st arg (fd) to 0, as command is F_SETFL */
 	ret = vfs_fcntl(0, F_SETFL, h->f_flags & CKPT_SETFL_MASK, file);
include/linux/checkpoint_hdr.h +1 -0
index 98fc0f7..2693a72 100644
@@ -341,6 +341,7 @@ struct ckpt_hdr_file {
 	__u32 _padding;
 	__u64 f_pos;
 	__u64 f_version;
+	__s32 f_credref;
 } __attribute__((aligned(8)));
 
 struct ckpt_hdr_file_generic {
Signature · 1 line
1.6.1

A message that is not in the archive (sent off-list or not yet received): 20090519014546.GE28312-r/[email protected]

Acked-by
#8 lore raw

Re: [PATCH 5/6] cr: restore file->f_cred

Quoted 1 line · Serge E. Hallyn

Ony seems useful if you're using coda or hppfs, but go ahead and

^^^

(It is also used in some place under net/*...)

Quoted 49 lines

restore a file's f_cred. This is set to the cred of the task doing the open, so often it will be the same as that of the restarted task.

---
 checkpoint/files.c             |   16 ++++++++++++++--
 include/linux/checkpoint_hdr.h |    1 +
 2 files changed, 15 insertions(+), 2 deletions(-)
checkpoint/files.c +14 -2
index 6107361..edf81ce 100644
@@ -151,7 +151,11 @@ int checkpoint_file_common(struct ckpt_ctx *ctx, struct file *file,
 	h->f_pos = file->f_pos;
 	h->f_version = file->f_version;
 
-	/* FIX: need also file->uid, file->gid, file->f_owner, etc */
+	h->f_credref = checkpoint_obj(ctx, file->f_cred, CKPT_OBJ_CRED);
+	if (h->f_credref < 0)
+		return h->f_credref;
+
+	/* FIX: need also file->f_owner, etc */
 
 	return 0;
 }
@@ -359,8 +363,16 @@ int restore_file_common(struct ckpt_ctx *ctx, struct file *file,
 			struct ckpt_hdr_file *h)
 {
 	int ret;
+	struct cred *cred;
+
+	/* FIX: need to restore owner etc */
 
-	/* FIX: need to restore uid, gid, owner etc */
+	/* restore the cred */
+	cred = ckpt_obj_fetch(ctx, h->f_credref, CKPT_OBJ_CRED);
+	if (IS_ERR(cred))
+		return PTR_ERR(cred);
+	put_cred(file->f_cred);
+	file->f_cred = get_cred(cred);
 
 	/* safe to set 1st arg (fd) to 0, as command is F_SETFL */
 	ret = vfs_fcntl(0, F_SETFL, h->f_flags & CKPT_SETFL_MASK, file);
include/linux/checkpoint_hdr.h +0 -0
index 98fc0f7..2693a72 100644

include/linux/checkpoint_hdr.h struct ckpt_hdr_file { · line 344

Quoted 4 lines
include/linux/checkpoint_hdr.h +1 -0
@@ -341,6 +341,7 @@ struct ckpt_hdr_file {
 	__u32 _padding;
 	__u64 f_pos;
 	__u64 f_version;
+	__s32 f_credref;

This can replace the unused _padding field above ?

include/linux/checkpoint_hdr.h struct ckpt_hdr_file { · line 347

Quoted 3 lines
include/linux/checkpoint_hdr.h +0 -0
 } __attribute__((aligned(8)));
 
 struct ckpt_hdr_file_generic {

A message that is not in the archive (sent off-list or not yet received): [email protected]

#10 lore raw

Re: [PATCH 5/6] cr: restore file->f_cred

Quoted 8 lines · Oren Laadan
Quoted 1 line · Serge E. Hallyn

Ony seems useful if you're using coda or hppfs, but go ahead and

^^^

(It is also used in some place under net/*...)

ok

Quoted 11 lines

include/linux/checkpoint_hdr.h struct ckpt_hdr_file { · line 344

Quoted 9 lines
include/linux/checkpoint_hdr.h +1 -0
index 98fc0f7..2693a72 100644
@@ -341,6 +341,7 @@ struct ckpt_hdr_file {
 	__u32 _padding;
 	__u64 f_pos;
 	__u64 f_version;
+	__s32 f_credref;

This can replace the unused _padding field above ?

Oh, of course.

Quoted 5 lines

include/linux/checkpoint_hdr.h struct ckpt_hdr_file { · line 347

Quoted 3 lines
include/linux/checkpoint_hdr.h +0 -0
 } __attribute__((aligned(8)));
 
 struct ckpt_hdr_file_generic {

Thanks - did you want me to send a new version, or will you apply the updated patch?

thanks,
-serge

A message that is not in the archive (sent off-list or not yet received): 20090520152527.GA28585-r/[email protected]

#12 lore raw

Re: [PATCH 5/6] cr: restore file->f_cred

Quoted 23 lines · Serge E. Hallyn
Quoted 6 lines · Oren Laadan
Quoted 1 line · Serge E. Hallyn

Ony seems useful if you're using coda or hppfs, but go ahead and

^^^

(It is also used in some place under net/*...)

ok

Quoted 10 lines

include/linux/checkpoint_hdr.h struct ckpt_hdr_file { · line 344

Quoted 9 lines
include/linux/checkpoint_hdr.h +1 -0
index 98fc0f7..2693a72 100644
@@ -341,6 +341,7 @@ struct ckpt_hdr_file {
 	__u32 _padding;
 	__u64 f_pos;
 	__u64 f_version;
+	__s32 f_credref;

This can replace the unused _padding field above ?

Oh, of course.

Quoted 7 lines
Quoted 4 lines

include/linux/checkpoint_hdr.h struct ckpt_hdr_file { · line 347

Quoted 3 lines
include/linux/checkpoint_hdr.h +0 -0
 } __attribute__((aligned(8)));
 
 struct ckpt_hdr_file_generic {

Thanks - did you want me to send a new version, or will you apply the updated patch?

I just assumed there will be a next version of the series :p

Oren.

#13 lore raw

PATCH 6/6 user namespaces: debug refcounts

In reply to a message not in the archive

Create /proc/userns, which prints out all user namespaces. It prints the address of the user_ns itself, the uid and userns address of the user who created it, and the reference count.

---
 include/linux/user_namespace.h |    2 +
 kernel/user.c                  |    1 +
 kernel/user_namespace.c        |   84 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 87 insertions(+), 0 deletions(-)
include/linux/user_namespace.h +2 -0
index a2b82d5..e64d602 100644
@@ -14,8 +14,10 @@ struct user_namespace {
 	struct hlist_head	uidhash_table[UIDHASH_SZ];
 	struct user_struct	*creator;
 	struct work_struct	destroyer;
+	struct list_head	list;
 };
 
+extern spinlock_t usernslist_lock;
 extern struct user_namespace init_user_ns;
 
 #ifdef CONFIG_USER_NS
kernel/user.c +1 -0
index 850e0ba..6474422 100644
@@ -23,6 +23,7 @@ struct user_namespace init_user_ns = {
 		.refcount	= ATOMIC_INIT(2),
 	},
 	.creator = &root_user,
+	.list = LIST_HEAD_INIT(init_user_ns.list),
 };
 EXPORT_SYMBOL_GPL(init_user_ns);
 
kernel/user_namespace.c +84 -0

105 lines not on this page · raw message

Signature · 1 line
1.6.1

A message that is not in the archive (sent off-list or not yet received): 20090519014538.GD28312-r/[email protected]

#15 lore raw

Re: [PATCH 4/6] cr: checkpoint and restore task credentials

Review

Quoted 3 lines · Serge E. Hallyn
(quoted diff) +3 -0
+/* move this code into kernel/cred.c and do proper perms checking of course */
+struct cred *restore_read_cred(struct ckpt_ctx *ctx)
+{

This function needs to fix up cred->security.

David

A message that is not in the archive (sent off-list or not yet received): [email protected]

#17 lore raw

Re: [PATCH 4/6] cr: checkpoint and restore task credentials

Quoted 7 lines · David Howells

Review

Quoted 3 lines · Serge E. Hallyn
(quoted diff) +3 -0
+/* move this code into kernel/cred.c and do proper perms checking of course */
+struct cred *restore_read_cred(struct ckpt_ctx *ctx)
+{

This function needs to fix up cred->security.

Yup -it's not at all clear to me yet how to go about that, so I'll need to have a discussion on the LSM list about whether a pair of new security_ops hook is called for. One to authorize restart, based on the current domain and the type of the mm->exe_file being executed (and maybe the type of the checkpoint image file), and one to calculate the new domain to enter at the end of restart.

Or did you mean something else by 'fix up' cred->security?

thanks,
-serge

A message that is not in the archive (sent off-list or not yet received): 20090519133526.GB32685-r/[email protected]

#19 lore raw

Re: [PATCH 4/6] cr: checkpoint and restore task credentials

Quoted 1 line · Serge E. Hallyn

Or did you mean something else by 'fix up' cred->security?

cred->security is inherited from the current process by virtue of calling prepare_creds() - as such, it is almost certainly going to be wrong. Can you just ask the LSM for a set of textual security labels when saving, and then set those back when restoring?

David

A message that is not in the archive (sent off-list or not yet received): [email protected]

#21 lore raw

Re: [PATCH 4/6] cr: checkpoint and restore task credentials

Quoted 8 lines · David Howells
Quoted 1 line · Serge E. Hallyn

Or did you mean something else by 'fix up' cred->security?

cred->security is inherited from the current process by virtue of calling prepare_creds() - as such, it is almost certainly going to be wrong. Can you just ask the LSM for a set of textual security labels when saving, and then set those back when restoring?

That would be too easy a way for users (even privileged root users but constrained by selinux) to bypass selinux restrictions. All they'd have to do is checkpoint their shell, and rewrite the ->security field in the checkpoint image with 'shadow_t', to get a shell that can write to the shadow file, for instance.

-serge

#22 lore raw

Re: [PATCH 4/6] cr: checkpoint and restore task credentials

In reply to a message not in the archive

Serge -

The 'creator' makes the 'struct user' recursive because to save an object you need to first save its creator etc. However the implementation may not call checkpoint_obj() recursively, if the depth isn't bound a-priory. You probably need to convert checkpoint_write_user() to do an iterative (loop) implementation of the recursion...

Oren.

Quoted 49 lines · Serge E. Hallyn

This patch adds the checkpointing and restart of credentials (uids, gids, and capabilities) to Oren's c/r patchset (on top of v14). It goes to great pains to re-use (and define when needed) common helpers, in order to make sure that as security code is modified, the cr code will be updated. Some of the helpers should still be moved (i.e. _creds() functions should be in kernel/cred.c).

When building the credentials for the restarted process, I
1. create a new struct cred as a copy of the running task's cred (using prepare_cred())
2. always authorize any changes to the new struct cred based on the permissions of current_cred() (not the current transient state of the new cred).

While this may mean that certain transient_cred1->transient_cred2 states are allowed which otherwise wouldn't be allowed, the fact remains that current_cred() is allowed to transition to transient_cred2.

The reconstructed creds are applied to the task at the very end of the sys_restart call. This ensures that any objects which need to be re-created (file, socket, etc) are re-created using the creds of the task calling sys_restart - preventing an unpriv user from creating a privileged object, and ensuring that a root task can restart a process which had started out privileged, created some privileged objects, then dropped its privilege.

With these patches, the root user can restart checkpoint images (created by either hallyn or root) of user hallyn's tasks, resulting in a program owned by hallyn.

Plenty of bugs to be found, no doubt.

Changelog:
May 18: fix more refcounting: if (userns 5, uid 0) had
no active tasks or child user_namespaces, then it shouldn't exist at restart or it, its namespace, and its whole chain of creators will be leaked.
May 14: fix some refcounting:
1. a new user_ns needs a ref to remain pinned by its root user
2. current_user_ns needs an extra ref bc objhash drops two on restart
3. cred needs a ref for the real credentials bc commit_creds eats one ref.
May 13: folded in fix to userns refcounting.

[...]

A message that is not in the archive (sent off-list or not yet received): [email protected]

#24 lore raw

Re: [PATCH 4/6] cr: checkpoint and restore task credentials

Quoted 9 lines · Oren Laadan

Serge -

The 'creator' makes the 'struct user' recursive because to save an object you need to first save its creator etc. However the implementation may not call checkpoint_obj() recursively, if the depth isn't bound a-priory. You probably need to convert checkpoint_write_user() to do an iterative (loop) implementation of the recursion...

It's not done recursively, though. checkpoint_write_userns() will
only be called by checkpoint_write_user(). checkpoint_write_user()
will make sure there are only 5 levels deep of unwritten creator user namespace (else bail), then start at the oldest creator, and write it. That checkpoint_write_user will cause a write of its user_ns, then write the user, then return to the original checkpoint_write_user() which will now write the next-oldest user_struct

So the max recursion depth we get is:

	checkpoint_task_struct -> checkpoint_write_cred ->
	checkpoint_write_user -> checkpoint_write_user ->
	checkpoint_write_userns (END)

-serge

A message that is not in the archive (sent off-list or not yet received): 20090520155332.GA28999-r/[email protected]

#26 lore raw

Re: [PATCH 4/6] cr: checkpoint and restore task credentials

Quoted 19 lines · Serge E. Hallyn
Quoted 8 lines · Oren Laadan

Serge -

The 'creator' makes the 'struct user' recursive because to save an object you need to first save its creator etc. However the implementation may not call checkpoint_obj() recursively, if the depth isn't bound a-priory. You probably need to convert checkpoint_write_user() to do an iterative (loop) implementation of the recursion...

It's not done recursively, though. checkpoint_write_userns() will
only be called by checkpoint_write_user(). checkpoint_write_user()
will make sure there are only 5 levels deep of unwritten creator user namespace (else bail), then start at the oldest creator, and write it. That checkpoint_write_user will cause a write of its user_ns, then write the user, then return to the original checkpoint_write_user() which will now write the next-oldest user_struct

Quoted 5 lines

So the max recursion depth we get is:

	checkpoint_task_struct -> checkpoint_write_cred ->
	checkpoint_write_user -> checkpoint_write_user ->
	checkpoint_write_userns (END)

Ok. Let's not restrict to 5 levels :)

Oren.

A message that is not in the archive (sent off-list or not yet received): [email protected]

#28 lore raw

Re: [PATCH 4/6] cr: checkpoint and restore task credentials

Quoted 22 lines · Oren Laadan
Quoted 19 lines · Serge E. Hallyn
Quoted 8 lines · Oren Laadan

Serge -

The 'creator' makes the 'struct user' recursive because to save an object you need to first save its creator etc. However the implementation may not call checkpoint_obj() recursively, if the depth isn't bound a-priory. You probably need to convert checkpoint_write_user() to do an iterative (loop) implementation of the recursion...

It's not done recursively, though. checkpoint_write_userns() will
only be called by checkpoint_write_user(). checkpoint_write_user()
will make sure there are only 5 levels deep of unwritten creator user namespace (else bail), then start at the oldest creator, and write it. That checkpoint_write_user will cause a write of its user_ns, then write the user, then return to the original checkpoint_write_user() which will now write the next-oldest user_struct

Quoted 7 lines
Quoted 5 lines

So the max recursion depth we get is:

	checkpoint_task_struct -> checkpoint_write_cred ->
	checkpoint_write_user -> checkpoint_write_user ->
	checkpoint_write_userns (END)

Ok. Let's not restrict to 5 levels :)

Will change that, and resend the set hopefully tonight.

thanks,
-serge

#29 lore raw

Re: [PATCH 4/6] cr: checkpoint and restore task credentials

In reply to a message not in the archive
Quoted 28 lines · Serge E. Hallyn

This patch adds the checkpointing and restart of credentials (uids, gids, and capabilities) to Oren's c/r patchset (on top of v14). It goes to great pains to re-use (and define when needed) common helpers, in order to make sure that as security code is modified, the cr code will be updated. Some of the helpers should still be moved (i.e. _creds() functions should be in kernel/cred.c).

When building the credentials for the restarted process, I
1. create a new struct cred as a copy of the running task's cred (using prepare_cred())
2. always authorize any changes to the new struct cred based on the permissions of current_cred() (not the current transient state of the new cred).

While this may mean that certain transient_cred1->transient_cred2 states are allowed which otherwise wouldn't be allowed, the fact remains that current_cred() is allowed to transition to transient_cred2.

The reconstructed creds are applied to the task at the very end of the sys_restart call. This ensures that any objects which need to be re-created (file, socket, etc) are re-created using the creds of the task calling sys_restart - preventing an unpriv user from creating a privileged object, and ensuring that a root task can restart a process which had started out privileged, created some privileged objects, then dropped its privilege.

Quoted 3 lines

With these patches, the root user can restart checkpoint images (created by either hallyn or root) of user hallyn's tasks, resulting in a program owned by hallyn.

In this case, it is necessary to ensure that all resources created during the restart are properly owned. You do take care of open files (next patch); can you also add a patch for IPC ?

Quoted 19 lines

Plenty of bugs to be found, no doubt.

Changelog:
May 18: fix more refcounting: if (userns 5, uid 0) had
no active tasks or child user_namespaces, then it shouldn't exist at restart or it, its namespace, and its whole chain of creators will be leaked.
May 14: fix some refcounting:
1. a new user_ns needs a ref to remain pinned by its root user
2. current_user_ns needs an extra ref bc objhash drops two on restart
3. cred needs a ref for the real credentials bc commit_creds eats one ref.
May 13: folded in fix to userns refcounting.

---

[...]

Review static struct ckpt_obj *obj_find_by_ptr(struct ckpt_ctx *ctx, void *ptr) · line 403

Quoted 9 lines
(quoted diff) +5 -0
@@ -290,6 +396,18 @@ static struct ckpt_obj *obj_find_by_ptr(struct ckpt_ctx *ctx, void *ptr)
 	return NULL;
 }
 
+/*
+ * look up an obj and return objref if in hash, else
+ * return 0.  Used during checkpoint.
+ */
+int obj_lookup_dontadd(struct ckpt_ctx *ctx, void *ptr)

Do you mind calling it simply obj_lookup() ?

Quoted 11 lines
(quoted diff) +7 -0
+{
+	struct ckpt_obj *obj = obj_find_by_ptr(ctx, ptr);
+	if (obj)
+		return obj->objref;
+	return 0;
+}
+
 static struct ckpt_obj *obj_find_by_objref(struct ckpt_ctx *ctx, int objref)
 {
 	struct hlist_head *h;

Review int ckpt_obj_lookup_add(struct ckpt_ctx *ctx, void *ptr, · line 392

Quoted 4 lines
(quoted diff) +0 -1
@@ -389,7 +507,6 @@ int ckpt_obj_lookup_add(struct ckpt_ctx *ctx, void *ptr,
 		*first = 0;
 	}
 
-	ckpt_debug("%s objref %d first %d\n", ops->obj_name, objref, *first);

Please leave the debug messages inside... In fact, a debug message above in obj_lookup() may prove useful as well.

Quoted 16 lines
(quoted diff) +0 -0
 	return objref;
 }
 
checkpoint/process.c +1 -0
index d8d346b..74b411a 100644
@@ -17,6 +17,7 @@
 #include <linux/poll.h>
 #include <linux/nsproxy.h>
 #include <linux/utsname.h>
+#include <linux/user_namespace.h>
 #include <linux/checkpoint.h>
 #include <linux/checkpoint_hdr.h>
 #include <linux/syscalls.h>

checkpoint/process.c line 32

Quoted 5 lines
checkpoint/process.c +2 -0
@@ -27,16 +28,210 @@
  * Checkpoint
  */
 
+#define CKPT_MAXGROUPS 15
+#define MAX_GROUPINFO_SIZE (sizeof(*h)+CKPT_MAXGROUPS*sizeof(gid_t))

Is this really necessary ? If you are worried about DoS by alloc'ing a lot of memory on checkpoint, you can write it out in chunks (e.g. like the pids array), or set a sysctl tunable. Likewise for restart.

Quoted 3 lines
checkpoint/process.c +3 -0
+/* move this fn into kernel/sys.c next to group functions? */
+static int checkpoint_write_groupinfo(struct ckpt_ctx *ctx,
+					struct group_info *g)

[...]

Quoted 5 lines
checkpoint/process.c +1 -0
+
 /* dump the task_struct of a given task */
 static int checkpoint_task_struct(struct ckpt_ctx *ctx, struct task_struct *t)
 {
 	struct ckpt_hdr_task *h;

checkpoint/process.c

Quoted 10 lines
checkpoint/process.c +9 -0
 	int ret;
+	int realcred_ref, ecred_ref;
+
+	realcred_ref = checkpoint_obj(ctx, t->real_cred, CKPT_OBJ_CRED);
+	if (realcred_ref < 0)
+		return realcred_ref;
+
+	ecred_ref = checkpoint_obj(ctx, t->cred, CKPT_OBJ_CRED);
+	if (ecred_ref < 0)
+		return ecred_ref;

Is this safe even if the checkpointed task's state changes ? (e.g. unfrozen - yes, I know there is a patch in the works to prevent this; but if we ever want to checkpoint STOPPED tasks... for instance).

Would incrementing the refcount on t->{cred,real_cred} help ?

[...]

Quoted 8 lines
checkpoint/process.c +8 -0
+}
+
+/* move this code into kernel/cred.c and do proper perms checking of course */
+struct cred *restore_read_cred(struct ckpt_ctx *ctx)
+{
+	struct cred *cred;
+	struct ckpt_hdr_cred *h;
+	struct user_struct *user;

checkpoint/process.c

Quoted 10 lines
checkpoint/process.c +10 -0
+	struct group_info *groupinfo;
+	int ret = -EINVAL;
+	uid_t olduid;
+	gid_t oldgid;
+	int i;
+
+	h = ckpt_read_obj_type(ctx, sizeof(*h), CKPT_HDR_CRED);
+	if (IS_ERR(h))
+		return ERR_PTR(PTR_ERR(h));
+	if (h->version != 1)
			 ^^^

This probably deserves some constant defined somewhere ... (heh, I must have missed it in the checkpoint code above).

[...]

checkpoint/process.c

Quoted 4 lines

/* read the task_struct into the current task */

checkpoint/process.c +2 -1
-static int restore_task_struct(struct ckpt_ctx *ctx)
+static int restore_task_struct(struct ckpt_ctx *ctx, struct cred **realcredp,
+				struct cred **ecredp)
				^^^^^^^^^^^^^^^^^^^^^    ^^^^^^^^^^^^^^^^^^^^^^^

This probably belongs to restore_task_shared() ?

Quoted 49 lines

{

checkpoint/process.c +33 -0
 	struct ckpt_hdr_task *h;
 	struct task_struct *t = current;
@@ -365,8 +778,21 @@ static int restore_task_struct(struct ckpt_ctx *ctx)
 
 	memset(t->comm, 0, TASK_COMM_LEN);
 	ret = _ckpt_read_string(ctx, t->comm, h->task_comm_len);
+	if (ret < 0)
+		goto out;
 
 	/* FIXME: restore remaining relevant task_struct fields */
+
+	ret = 0;
+	*realcredp = ckpt_obj_fetch(ctx, h->cred_ref, CKPT_OBJ_CRED);
+	if (IS_ERR(*realcredp)) {
+		ret = PTR_ERR(*realcredp);
+		goto out;
+	}
+	*ecredp = ckpt_obj_fetch(ctx, h->ecred_ref, CKPT_OBJ_CRED);
+	if (IS_ERR(*ecredp))
+		ret = PTR_ERR(*ecredp);
+
  out:
 	ckpt_hdr_put(ctx, h);
 	return ret;
@@ -648,12 +1074,35 @@ static int restore_task_shared(struct ckpt_ctx *ctx)
 	return ret;
 }
 
+static int restore_creds(struct ckpt_ctx *ctx, struct cred *rcred,
+			struct cred *ecred)
+{
+	int ret;
+	const struct cred *old;
+
+	/* commit_creds will take one ref for the eff creds, but
+	 * expects us to hold a ref for the obj creds, so take a
+	 * ref here */
+	get_cred(rcred);
+	ret = commit_creds(rcred);
+	if (ret)
+		return ret;
+
+	if (ecred == rcred)
+		return 0;
+
+	old =  override_creds(ecred); /* override_creds otoh takes new ref */
+	put_cred(old);
+	return 0;

checkpoint/process.c static int restore_task_shared(struct ckpt_ctx *ctx) · line 1105

Quoted 10 lines
checkpoint/process.c +4 -1
+}
+
 /* read the entire state of the current task */
 int restore_task(struct ckpt_ctx *ctx)
 {
 	int ret;
+	struct cred *realcred, *ecred;
 
-	ret = restore_task_struct(ctx);
+	ret = restore_task_struct(ctx, &realcred, &ecred);

Actually, this is one of several cases where we need to restore some resources but only apply it to a process at the end of its restart.

Another example would be restoring pending signals and the blocked signal mask in the future.

I suggest that we keep a pointer on the task_struct to a structure that will hold all that do-later work. The structure can encapsulate the pending work either explicitly - e.g. a struct with fields like realcred, ecred, signal mask, etc... - or implicitly, by reusing the deferqueue framework, per task.

Actually, that pointer can be kept on the ckpt_ctx structure, to be used by the current-restarting-task only.

checkpoint/process.c int restore_task(struct ckpt_ctx *ctx) · line 1125

Quoted 10 lines
checkpoint/process.c +3 -0
 	ckpt_debug("ret %d\n", ret);
 	if (ret < 0)
 		goto out;
@@ -671,6 +1120,10 @@ int restore_task(struct ckpt_ctx *ctx)
 		goto out;
 	ret = restore_cpu(ctx);
 	ckpt_debug("cpu: ret %d\n", ret);
+	if (ret < 0)
+		goto out;
+	ret = restore_creds(ctx, realcred, ecred);

... and this would then be called from a restore_task_finalize() function explicitly or implicitly by deferqueue_run().

checkpoint/process.c int restore_task(struct ckpt_ctx *ctx) · line 1129

Quoted 4 lines
checkpoint/process.c +1 -0
+	ckpt_debug("creds: ret %d\n", ret);
  out:
 	return ret;
 }

[...]

Oren.

A message that is not in the archive (sent off-list or not yet received): [email protected]

#31 lore raw

Re: [PATCH 4/6] cr: checkpoint and restore task credentials

Quoted 20 lines · Oren Laadan
Quoted 4 lines

/* dump the task_struct of a given task */
static int checkpoint_task_struct(struct ckpt_ctx *ctx, struct task_struct *t) {

(quoted diff) +0 -0
 	struct ckpt_hdr_task *h;

Review

Quoted 10 lines
(quoted diff) +9 -0
 	int ret;
+	int realcred_ref, ecred_ref;
+
+	realcred_ref = checkpoint_obj(ctx, t->real_cred, CKPT_OBJ_CRED);
+	if (realcred_ref < 0)
+		return realcred_ref;
+
+	ecred_ref = checkpoint_obj(ctx, t->cred, CKPT_OBJ_CRED);
+	if (ecred_ref < 0)
+		return ecred_ref;

Is this safe even if the checkpointed task's state changes ? (e.g. unfrozen - yes, I know there is a patch in the works to prevent this; but if we ever want to checkpoint STOPPED tasks... for instance).

Quoted 1 line

Would incrementing the refcount on t->{cred,real_cred} help ?

Doesn't checkpoint_obj already do that through obj_new?

-serge

A message that is not in the archive (sent off-list or not yet received): 20090520214027.GA3517-r/[email protected]

#33 lore raw

Re: [PATCH 4/6] cr: checkpoint and restore task credentials

Quoted 20 lines · Serge E. Hallyn
Quoted 19 lines · Oren Laadan
Quoted 4 lines

/* dump the task_struct of a given task */
static int checkpoint_task_struct(struct ckpt_ctx *ctx, struct task_struct *t) {

(quoted diff) +0 -0
 	struct ckpt_hdr_task *h;

Review

Quoted 10 lines
(quoted diff) +9 -0
 	int ret;
+	int realcred_ref, ecred_ref;
+
+	realcred_ref = checkpoint_obj(ctx, t->real_cred, CKPT_OBJ_CRED);
+	if (realcred_ref < 0)
+		return realcred_ref;
+
+	ecred_ref = checkpoint_obj(ctx, t->cred, CKPT_OBJ_CRED);
+	if (ecred_ref < 0)
+		return ecred_ref;

Is this safe even if the checkpointed task's state changes ? (e.g. unfrozen - yes, I know there is a patch in the works to prevent this; but if we ever want to checkpoint STOPPED tasks... for instance).

Quoted 4 lines
Quoted 1 line

Would incrementing the refcount on t->{cred,real_cred} help ?

Doesn't checkpoint_obj already do that through obj_new?

No, it does not. There is a (potentially long) window of opportunity between the callback invoked from checkpoint_obj() - where the pointer is used, and when checkpoint_obj() later takes the extra reference.

See for comparison checkpoint_mm_obj(), it safely grabs the task->mm (with a reference) around the invocation of checkpoint_obj().

Oren.

A message that is not in the archive (sent off-list or not yet received): [email protected]

#35 lore raw

Re: [PATCH 4/6] cr: checkpoint and restore task credentials

Quoted 28 lines · Oren Laadan
Quoted 20 lines · Serge E. Hallyn
Quoted 19 lines · Oren Laadan
Quoted 4 lines

/* dump the task_struct of a given task */
static int checkpoint_task_struct(struct ckpt_ctx *ctx, struct task_struct *t) {

(quoted diff) +0 -0
 	struct ckpt_hdr_task *h;

Review

Quoted 10 lines
(quoted diff) +9 -0
 	int ret;
+	int realcred_ref, ecred_ref;
+
+	realcred_ref = checkpoint_obj(ctx, t->real_cred, CKPT_OBJ_CRED);
+	if (realcred_ref < 0)
+		return realcred_ref;
+
+	ecred_ref = checkpoint_obj(ctx, t->cred, CKPT_OBJ_CRED);
+	if (ecred_ref < 0)
+		return ecred_ref;

Is this safe even if the checkpointed task's state changes ? (e.g. unfrozen - yes, I know there is a patch in the works to prevent this; but if we ever want to checkpoint STOPPED tasks... for instance).

Quoted 4 lines
Quoted 1 line

Would incrementing the refcount on t->{cred,real_cred} help ?

Doesn't checkpoint_obj already do that through obj_new?

Quoted 6 lines

No, it does not. There is a (potentially long) window of opportunity between the callback invoked from checkpoint_obj() - where the pointer is used, and when checkpoint_obj() later takes the extra reference.

See for comparison checkpoint_mm_obj(), it safely grabs the task->mm (with a reference) around the invocation of checkpoint_obj().

Hmm, ok. Will do.

-serge

#36 lore raw

Re: [PATCH 4/6] cr: checkpoint and restore task credentials

In reply to a message not in the archive
Quoted 8 lines · Oren Laadan

Review

Quoted 4 lines

/* read the task_struct into the current task */

(quoted diff) +2 -1
-static int restore_task_struct(struct ckpt_ctx *ctx)
+static int restore_task_struct(struct ckpt_ctx *ctx, struct cred **realcredp,
+				struct cred **ecredp)
				^^^^^^^^^^^^^^^^^^^^^    ^^^^^^^^^^^^^^^^^^^^^^^

This probably belongs to restore_task_shared() ?

Why? The task->cred and task->ecred are task properties, so their reference should be stored in the ckpt_hdr_task->cred_ref and ckpt_hdr_task->ecred_ref, no?

-serge

A message that is not in the archive (sent off-list or not yet received): 20090520215250.GB3517-r/[email protected]

#38 lore raw

Re: [PATCH 4/6] cr: checkpoint and restore task credentials

Quoted 7 lines · Serge E. Hallyn
Quoted 6 lines · Oren Laadan

Review

Quoted 4 lines

/* read the task_struct into the current task */

(quoted diff) +2 -1
-static int restore_task_struct(struct ckpt_ctx *ctx)
+static int restore_task_struct(struct ckpt_ctx *ctx, struct cred **realcredp,
+				struct cred **ecredp)
				^^^^^^^^^^^^^^^^^^^^^    ^^^^^^^^^^^^^^^^^^^^^^^
Quoted 6 lines
Quoted 1 line

This probably belongs to restore_task_shared() ?

Why? The task->cred and task->ecred are task properties, so their reference should be stored in the ckpt_hdr_task->cred_ref and ckpt_hdr_task->ecred_ref, no?

Because they are shared objects; task->mm is also a task property...

checkpoint,restore}_task_struct() handles c/r of task properties that are "private" to the task.

{checkpoint,restore}_task_shared() handles c/r of task properties that are shared.

This division makes it easier to see the dependencies between shared resources (and themselves, or others), by explicitly reordering if necessary. For example, ns precedes mm because sysvipc shm depends on that of ns.

In this case, for similar reasons, I'd place the user ns right there before the rest of the ns, because sysvipc of ns depends on credentials from user-ns.

Oren.

#39 lore raw

Re: [PATCH 4/6] cr: checkpoint and restore task credentials

In reply to a message not in the archive
Quoted 24 lines · Oren Laadan

Review

Quoted 8 lines

/* read the entire state of the current task */
int restore_task(struct ckpt_ctx *ctx)
{

(quoted diff) +2 -1
 	int ret;
+	struct cred *realcred, *ecred;
 
-	ret = restore_task_struct(ctx);
+	ret = restore_task_struct(ctx, &realcred, &ecred);

Actually, this is one of several cases where we need to restore some resources but only apply it to a process at the end of its restart.

Another example would be restoring pending signals and the blocked signal mask in the future.

I suggest that we keep a pointer on the task_struct to a structure that will hold all that do-later work. The structure can encapsulate the pending work either explicitly - e.g. a struct with fields like realcred, ecred, signal mask, etc... - or implicitly, by reusing the deferqueue framework, per task.

Actually, that pointer can be kept on the ckpt_ctx structure, to be used by the current-restarting-task only.

Quoted 13 lines

Review int restore_task(struct ckpt_ctx *ctx) · line 1125

Quoted 10 lines
(quoted diff) +3 -0
 	ckpt_debug("ret %d\n", ret);
 	if (ret < 0)
 		goto out;
@@ -671,6 +1120,10 @@ int restore_task(struct ckpt_ctx *ctx)
 		goto out;
 	ret = restore_cpu(ctx);
 	ckpt_debug("cpu: ret %d\n", ret);
+	if (ret < 0)
+		goto out;
+	ret = restore_creds(ctx, realcred, ecred);

... and this would then be called from a restore_task_finalize() function explicitly or implicitly by deferqueue_run().

deferqueue_run() won't do, since that's done only once for the whole container, and we (as you say above) want to reuse one set of fields in the ckpt_ctx for each task's sys_restart() run.

I'll go ahead and put fields in the ckpt_ctx this time around and use those, but won't go further right now as I'd be overgeneralizing before we have the signals and such work done. When we do that, we can move the restore_creds() fn if appropriate.

-serge

A message that is not in the archive (sent off-list or not yet received): 20090520221600.GA3925-r/[email protected]

#41 lore raw

Re: [PATCH 4/6] cr: checkpoint and restore task credentials

Quoted 37 lines · Serge E. Hallyn
Quoted 23 lines · Oren Laadan

Review

Quoted 8 lines

/* read the entire state of the current task */
int restore_task(struct ckpt_ctx *ctx)
{

(quoted diff) +2 -1
 	int ret;
+	struct cred *realcred, *ecred;
 
-	ret = restore_task_struct(ctx);
+	ret = restore_task_struct(ctx, &realcred, &ecred);

Actually, this is one of several cases where we need to restore some resources but only apply it to a process at the end of its restart.

Another example would be restoring pending signals and the blocked signal mask in the future.

I suggest that we keep a pointer on the task_struct to a structure that will hold all that do-later work. The structure can encapsulate the pending work either explicitly - e.g. a struct with fields like realcred, ecred, signal mask, etc... - or implicitly, by reusing the deferqueue framework, per task.

Actually, that pointer can be kept on the ckpt_ctx structure, to be used by the current-restarting-task only.

Quoted 12 lines

Review int restore_task(struct ckpt_ctx *ctx) · line 1125

Quoted 10 lines
(quoted diff) +3 -0
 	ckpt_debug("ret %d\n", ret);
 	if (ret < 0)
 		goto out;
@@ -671,6 +1120,10 @@ int restore_task(struct ckpt_ctx *ctx)
 		goto out;
 	ret = restore_cpu(ctx);
 	ckpt_debug("cpu: ret %d\n", ret);
+	if (ret < 0)
+		goto out;
+	ret = restore_creds(ctx, realcred, ecred);

... and this would then be called from a restore_task_finalize() function explicitly or implicitly by deferqueue_run().

Quoted 3 lines

deferqueue_run() won't do, since that's done only once for the whole container, and we (as you say above) want to reuse one set of fields in the ckpt_ctx for each task's sys_restart() run.

I meant to add another deferqueue (either per task or on the ckpt_ctx), for this specific purpose.

Oren.

Quoted 9 lines

I'll go ahead and put fields in the ckpt_ctx this time around and use those, but won't go further right now as I'd be overgeneralizing before we have the signals and such work done. When we do that, we can move the restore_creds() fn if appropriate.

-serge

#42 lore raw

Re: [PATCH 4/6] cr: checkpoint and restore task credentials

In reply to a message not in the archive

Review

Quoted 10 lines · Serge E. Hallyn
(quoted diff) +10 -0
+static struct user_namespace *restore_read_userns(struct ckpt_ctx *ctx)
+{
+	struct ckpt_hdr_user_ns *h;
+	struct user_namespace *ns;
+	struct user_struct *new_root, *creator;
+
+	h = ckpt_read_obj_type(ctx, sizeof(*h), CKPT_HDR_USER_NS);
+	if (IS_ERR(h))
+		return ERR_PTR(PTR_ERR(h));
+	if (h->flags & CKPT_USERNS_INIT) {

Perhaps make it future-safe by disallowing other flags ?

Review

Quoted 4 lines
(quoted diff) +4 -0
+		ckpt_hdr_put(ctx, h);
+		/* grab an extra ref bc objhash will drop an extra */
+		return get_user_ns(current_user_ns());
+	}

Oren.