Skip to contentSkip to conversation

cr: attempt at task userid restoration

PATCH In review Serge E. Hallyn 3 participants 13 messages May 11, 2009 – May 14, 2009 6 messages not in the archive

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

cover cr: attempt at task userid restoration

Here is a broken-out patchset representing a first stab at checkpoint and restoring task userids. As I note somewhere, I have more thinking to do about refcounting and I'm sure there are plenty of bugs. I'm sending this out to see if there are major objections to this general approach.

thanks,
-serge

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

#2 lore raw

PATCH 1/5 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/5 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 |    9 +++
 kernel/cred.c        |  143 +++++++++++++++++++++++++++++++++++++++++++
 kernel/sys.c         |  163 +++++++------------------------------------------
 3 files changed, 176 insertions(+), 139 deletions(-)
include/linux/cred.h +9 -0
index 3282ee4..4d83bdb 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,10 @@ 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);
+int cred_setuid(struct cred *new, uid_t uid);
+
 #endif /* _LINUX_CRED_H */
kernel/cred.c +143 -0

146 lines not on this page · raw message

kernel/sys.c +24 -139

251 lines not on this page · raw message

Signature · 1 line
1.6.1
#4 lore raw

PATCH 3/5 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/5 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.

TODO:
I'm pretty sure I've got some refcounting wrong. If a userns is created with refcount 1, then obj_new() incs the refcount, then ref is dropped at end of restart... that's good for an empty user_ns (creator of an active child user_ns). Does it mean that any non-empty user_ns will never drop to refcount 0? (restore_read_cred adds ref for the cred)

---
 checkpoint/objhash.c             |  119 ++++++++++-
 checkpoint/process.c             |  459 +++++++++++++++++++++++++++++++++++++-
 include/linux/checkpoint.h       |   11 +
 include/linux/checkpoint_hdr.h   |   57 +++++
 include/linux/checkpoint_types.h |    1 +
 5 files changed, 644 insertions(+), 3 deletions(-)
checkpoint/objhash.c +118 -1
index 87bc5e8..9206957 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 +457 -2

513 lines not on this page · raw message

include/linux/checkpoint.h +11 -0
index 2a09244..f41e581 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 void ckpt_obj_users_inc(struct ckpt_ctx *ctx, void *ptr, int increment);
 extern int ckpt_obj_insert(struct ckpt_ctx *ctx, void *ptr, int objref,
 			   enum obj_type type);
@@ -91,6 +92,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

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

#7 lore raw

PATCH 1/1 cr: child user namespace must grab ref to creator

This applies on top of yesterday's patchset.

thanks,
-serge

From f70a08dc6abdba372e1b3e1f25aadb919d07b171 Mon Sep 17 00:00:00 2001
From: Serge E. Hallyn <serue-r/[email protected]>
Date: Tue, 12 May 2009 08:17:34 -0400
Subject: [PATCH 1/1] cr: child user namespace must grab ref to creator

With this change plus Oren's proposed fix to obj_put() after obj_new() during restore_obj(), refcounting on user_ns and user_struct should be completely correct.

---
 checkpoint/process.c |   24 +++---------------------
 1 files changed, 3 insertions(+), 21 deletions(-)
checkpoint/process.c +3 -21
index a469f46..a8cd674 100644
@@ -569,27 +569,9 @@ static struct user_namespace *restore_read_userns(struct ckpt_ctx *ctx)
 	if (IS_ERR(ns))
 		return ns;
 
-	/* we need a way to keep track of the new_root just
-	 * until we alloc the  uid inthe userns which we
-	 * actually want.  Then we can do:
-	 *   if (uid == 0)
-	 *      new_user = new_root;
-	 *   else
-	 *      new_user = alloc_uid(ns, uid);
-	 *      free_uid(new_root);
-	 *      cred->user = new_user;
-	 * This is because new_root is right now the only
-	 * thing pinning the user_ns.
-	 * BUT I don't think I can just add it to the
-	 * objhash, bc then we use up an objref which we'll
-	 * need for the next real objhash object, right?
-	 * I suppose I could just add them to the top of
-	 * the objref space :)  (MAX_INT-1)
-	 *
-	 * For now, this code is just plain wrong bc it will
-	 * leak the user_ns and its root_user when the task
-	 * exits.  But, a leak is better than an OOPS...
-	 */
+	/* new_user_ns() doesn't bump creator's refcount */
+	get_uid(creator);
+
 	return ns;
 }
 
Signature · 1 line
1.6.1
#8 lore raw

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

In reply to a message not in the archive
Quoted 6 lines · Serge E. Hallyn
checkpoint/objhash.c +4 -0
+#define CKPT_MAXGROUPS 15
+#define MAX_GROUPINFO_SIZE (sizeof(*h)+CKPT_MAXGROUPS*sizeof(gid_t))
+/* move this fn into kernel/sys.c next to group functions? */
+static int checkpoint_write_groupinfo(struct ckpt_ctx *ctx,

checkpoint/objhash.c

Quoted 10 lines
checkpoint/objhash.c +10 -0
+					struct group_info *g)
+{
+	int ret, i, size;
+	struct ckpt_hdr_groupinfo *h;
+
+	if (g->ngroups > CKPT_MAXGROUPS) {
+		ckpt_debug("Too many groups: %d  (max is %d)\n",
+			g->ngroups, CKPT_MAXGROUPS);
+		return -E2BIG;
+	}

Ooh, a hack :-)

Quoted 10 lines
checkpoint/objhash.c +10 -0
+	size = sizeof(*h) + g->ngroups * sizeof(__u32);
+	h = ckpt_hdr_get_type(ctx, size, CKPT_HDR_GROUPINFO);
+	if (!h)
+		return -ENOMEM;
+
+	h->ngroups = g->ngroups;
+	for (i = 0; i < g->ngroups; i++)
+		h->groups[i] = GROUP_AT(g, i);
+
+	ret = ckpt_write_obj(ctx, (struct ckpt_hdr *) h);

checkpoint/objhash.c

Quoted 10 lines
checkpoint/objhash.c +9 -0
+	ckpt_hdr_put(ctx, h);
+
+	return ret;
+}
 
+/*
+ * write the user struct
+ * TODO keyring will need to be dumped
+ */
+#define UNSAVED_NS_MAX 5

Another hack :-)

This is an invitation to discuss what to do with references to future, especially given that object image can be variable-size _and_ streamability on dump.

In case of user->user_ns->creator, we can avoid the issue and dump creator first.

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

#10 lore raw

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

Quoted 43 lines · Alexey Dobriyan
Quoted 6 lines · Serge E. Hallyn
checkpoint/objhash.c +4 -0
+#define CKPT_MAXGROUPS 15
+#define MAX_GROUPINFO_SIZE (sizeof(*h)+CKPT_MAXGROUPS*sizeof(gid_t))
+/* move this fn into kernel/sys.c next to group functions? */
+static int checkpoint_write_groupinfo(struct ckpt_ctx *ctx,

checkpoint/objhash.c

Quoted 10 lines
checkpoint/objhash.c +10 -0
+					struct group_info *g)
+{
+	int ret, i, size;
+	struct ckpt_hdr_groupinfo *h;
+
+	if (g->ngroups > CKPT_MAXGROUPS) {
+		ckpt_debug("Too many groups: %d  (max is %d)\n",
+			g->ngroups, CKPT_MAXGROUPS);
+		return -E2BIG;
+	}

Ooh, a hack :-)

Quoted 10 lines
checkpoint/objhash.c +10 -0
+	size = sizeof(*h) + g->ngroups * sizeof(__u32);
+	h = ckpt_hdr_get_type(ctx, size, CKPT_HDR_GROUPINFO);
+	if (!h)
+		return -ENOMEM;
+
+	h->ngroups = g->ngroups;
+	for (i = 0; i < g->ngroups; i++)
+		h->groups[i] = GROUP_AT(g, i);
+
+	ret = ckpt_write_obj(ctx, (struct ckpt_hdr *) h);

checkpoint/objhash.c

Quoted 10 lines
checkpoint/objhash.c +9 -0
+	ckpt_hdr_put(ctx, h);
+
+	return ret;
+}
 
+/*
+ * write the user struct
+ * TODO keyring will need to be dumped
+ */
+#define UNSAVED_NS_MAX 5

Another hack :-)

Quoted 6 lines

This is an invitation to discuss what to do with references to future, especially given that object image can be variable-size _and_ streamability on dump.

In case of user->user_ns->creator, we can avoid the issue and dump creator first.

Aieee, user_ns are also hierarchical and ->creator points to outside of hierarchy.

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

#12 lore raw

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

Quoted 48 lines · Alexey Dobriyan
Quoted 47 lines · Alexey Dobriyan
Quoted 6 lines · Serge E. Hallyn
checkpoint/objhash.c +4 -0
+#define CKPT_MAXGROUPS 15
+#define MAX_GROUPINFO_SIZE (sizeof(*h)+CKPT_MAXGROUPS*sizeof(gid_t))
+/* move this fn into kernel/sys.c next to group functions? */
+static int checkpoint_write_groupinfo(struct ckpt_ctx *ctx,

checkpoint/objhash.c

Quoted 10 lines
checkpoint/objhash.c +10 -0
+					struct group_info *g)
+{
+	int ret, i, size;
+	struct ckpt_hdr_groupinfo *h;
+
+	if (g->ngroups > CKPT_MAXGROUPS) {
+		ckpt_debug("Too many groups: %d  (max is %d)\n",
+			g->ngroups, CKPT_MAXGROUPS);
+		return -E2BIG;
+	}

Ooh, a hack :-)

Quoted 10 lines
checkpoint/objhash.c +10 -0
+	size = sizeof(*h) + g->ngroups * sizeof(__u32);
+	h = ckpt_hdr_get_type(ctx, size, CKPT_HDR_GROUPINFO);
+	if (!h)
+		return -ENOMEM;
+
+	h->ngroups = g->ngroups;
+	for (i = 0; i < g->ngroups; i++)
+		h->groups[i] = GROUP_AT(g, i);
+
+	ret = ckpt_write_obj(ctx, (struct ckpt_hdr *) h);

checkpoint/objhash.c

Quoted 10 lines
checkpoint/objhash.c +9 -0
+	ckpt_hdr_put(ctx, h);
+
+	return ret;
+}
 
+/*
+ * write the user struct
+ * TODO keyring will need to be dumped
+ */
+#define UNSAVED_NS_MAX 5

Another hack :-)

This is an invitation to discuss what to do with references to future, especially given that object image can be variable-size _and_ streamability on dump.

Quoted 5 lines
Quoted 2 lines

In case of user->user_ns->creator, we can avoid the issue and dump creator first.

Aieee, user_ns are also hierarchical and ->creator points to outside of hierarchy.

We don't checkpoint the final, top-most creator, the one which created the user namespace in which the top checkpointed task belongs. Instead we mark the user_ns as 'CKPT_USERNS_INIT'. So every user_struct and user_ns which we checkpoint will be in or under that namespace.

-serge

#13 lore raw

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

In reply to a message not in the archive
Quoted 11 lines · Alexey Dobriyan
Quoted 10 lines · Serge E. Hallyn
checkpoint/objhash.c +8 -0
+#define CKPT_MAXGROUPS 15
+#define MAX_GROUPINFO_SIZE (sizeof(*h)+CKPT_MAXGROUPS*sizeof(gid_t))
+/* move this fn into kernel/sys.c next to group functions? */
+static int checkpoint_write_groupinfo(struct ckpt_ctx *ctx,
+					struct group_info *g)
+{
+	int ret, i, size;
+	struct ckpt_hdr_groupinfo *h;
Quoted 8 lines

checkpoint/objhash.c

Quoted 6 lines
checkpoint/objhash.c +6 -0
+
+	if (g->ngroups > CKPT_MAXGROUPS) {
+		ckpt_debug("Too many groups: %d  (max is %d)\n",
+			g->ngroups, CKPT_MAXGROUPS);
+		return -E2BIG;
+	}

Ooh, a hack :-)

Yup - actually I originally only had this at restart, and we must have it there to protect from malicious checkpoint images.

I copied it into the restart code during a cleanup phase, and I probably shouldn't have.

Quoted 23 lines
Quoted 10 lines
checkpoint/objhash.c +10 -0
+	size = sizeof(*h) + g->ngroups * sizeof(__u32);
+	h = ckpt_hdr_get_type(ctx, size, CKPT_HDR_GROUPINFO);
+	if (!h)
+		return -ENOMEM;
+
+	h->ngroups = g->ngroups;
+	for (i = 0; i < g->ngroups; i++)
+		h->groups[i] = GROUP_AT(g, i);
+
+	ret = ckpt_write_obj(ctx, (struct ckpt_hdr *) h);

checkpoint/objhash.c

Quoted 10 lines
checkpoint/objhash.c +9 -0
+	ckpt_hdr_put(ctx, h);
+
+	return ret;
+}
 
+/*
+ * write the user struct
+ * TODO keyring will need to be dumped
+ */
+#define UNSAVED_NS_MAX 5

Another hack :-)

Quoted 6 lines

This is an invitation to discuss what to do with references to future, especially given that object image can be variable-size _and_ streamability on dump.

In case of user->user_ns->creator, we can avoid the issue and dump creator first.

In fact I do dump the creator first. Note first that this '5' is not just for 5 levels of (user->user_ns)->(creator->user_ns)->..., but for 5 such levels where there are no tasks in any of the intermediate user namespaces. So a task did a

1.  T1: T2=clone(CLONE_NEWNS)
2.  T1: exit T2: T3=clone(CLONE_NEWNS)
3.  T2: exit T3: T4=clone(CLONE_NEWNS)
4.  T3: exit T4: t5=clone(CLONE_NEWNS)

As with groups, I think I agree with you that we don't need such a limit at checkpoint time. But we need some kind of sanity check at restart time. How about 5000?

thanks,
-serge

#14 lore raw

PATCH 5/5 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 c6a946b..22c8bb9 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 475186a..5aa214f 100644
@@ -336,6 +336,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): 20090511160512.GB12286-r/[email protected]

#16 lore raw

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

Is cred_setuid() necessary given that cred_setresgid() exists?

David

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

#18 lore raw

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

Quoted 4 lines · David Howells

Is cred_setuid() necessary given that cred_setresgid() exists?

David

Uh... yikes. Not only *should* it be unnecessary, but in the set I sent out I don't actually use cred_setuid() anymore.

Will pull that out of the set, thanks.

-serge