cr: credentials
Subsystems (2)
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]
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
@@ -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
PATCH 2/6 cr: split core function out of some set*{u,g}id functions
In reply to a message not in the archiveWhen 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
@@ -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
PATCH 3/6 cr: capabilities: define checkpoint and restore fns
In reply to a message not in the archiveAn 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
@@ -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
PATCH 4/6 cr: checkpoint and restore task credentials
In reply to a message not in the archiveThis 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
@@ -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
@@ -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
@@ -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
PATCH 5/6 cr: restore file->f_cred
In reply to a message not in the archiveOny 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
@@ -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
@@ -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]
Oren Laadan
Acked-byRe: [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.Signed-off-by Serge E. Hallyn <serue-r/[email protected]>--- checkpoint/files.c | 16 ++++++++++++++-- include/linux/checkpoint_hdr.h | 1 + 2 files changed, 15 insertions(+), 2 deletions(-)checkpoint/files.c +14
-2@@ -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
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]
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@@ -341,6 +341,7 @@ struct ckpt_hdr_file {__u32 _padding;__u64 f_pos;__u64 f_version; +__s32 f_credref;This can replace the unused
_paddingfield 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 {Acked-by Oren Laadan <[email protected]>
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]
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@@ -341,6 +341,7 @@ struct ckpt_hdr_file {__u32 _padding;__u64 f_pos;__u64 f_version; +__s32 f_credref;This can replace the unused
_paddingfield 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 {Acked-by Oren Laadan <[email protected]>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.
PATCH 6/6 user namespaces: debug refcounts
In reply to a message not in the archiveCreate /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
@@ -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
@@ -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]
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]
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]
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]
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->securityis inherited from the current process by virtue of callingprepare_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
Re: [PATCH 4/6] cr: checkpoint and restore task credentials
In reply to a message not in the archiveSerge -
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 inkernel/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 (usingprepare_cred())
2. always authorize any changes to the new struct cred based on the permissions ofcurrent_cred()(not the current transient state of the new cred).While this may mean that certain
transient_cred1->transient_cred2states are allowed which otherwise wouldn't be allowed, the fact remains thatcurrent_cred()is allowed to transition totransient_cred2.The reconstructed creds are applied to the task at the very end of the
sys_restartcall. This ensures that any objects which need to be re-created (file, socket, etc) are re-created using the creds of the task callingsys_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 childuser_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 newuser_nsneeds a ref to remain pinned by its root user
2.current_user_nsneeds an extra ref bc objhash drops two on restart
3. cred needs a ref for the real credentials bccommit_credseats one ref.
May 13: folded in fix to userns refcounting.Signed-off-by Serge E. Hallyn <serue-r/[email protected]>
[...]
A message that is not in the archive (sent off-list or not yet received): [email protected]
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 convertcheckpoint_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]
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 convertcheckpoint_write_user()to do an iterative (loop) implementation of the recursion...It's not done recursively, though.
checkpoint_write_userns()will
only be called bycheckpoint_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. Thatcheckpoint_write_userwill cause a write of itsuser_ns, then write the user, then return to the originalcheckpoint_write_user()which will now write the next-oldestuser_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]
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 convertcheckpoint_write_user()to do an iterative (loop) implementation of the recursion...It's not done recursively, though.
checkpoint_write_userns()will
only be called bycheckpoint_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. Thatcheckpoint_write_userwill cause a write of itsuser_ns, then write the user, then return to the originalcheckpoint_write_user()which will now write the next-oldestuser_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
Re: [PATCH 4/6] cr: checkpoint and restore task credentials
In reply to a message not in the archiveQuoted 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 inkernel/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 (usingprepare_cred())
2. always authorize any changes to the new struct cred based on the permissions ofcurrent_cred()(not the current transient state of the new cred).While this may mean that certain
transient_cred1->transient_cred2states are allowed which otherwise wouldn't be allowed, the fact remains thatcurrent_cred()is allowed to transition totransient_cred2.The reconstructed creds are applied to the task at the very end of the
sys_restartcall. This ensures that any objects which need to be re-created (file, socket, etc) are re-created using the creds of the task callingsys_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 childuser_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 newuser_nsneeds a ref to remain pinned by its root user
2.current_user_nsneeds an extra ref bc objhash drops two on restart
3. cred needs a ref for the real credentials bccommit_credseats one ref.
May 13: folded in fix to userns refcounting.Signed-off-by Serge E. Hallyn <serue-r/[email protected]>---
[...]
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
-0return objref; }checkpoint/process.c +1
-0@@ -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
-0int 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_structinto 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
-0struct 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
-0ckpt_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]
Re: [PATCH 4/6] cr: checkpoint and restore task credentials
Quoted 20 lines · Oren Laadan
Quoted 4 lines
/* dump the
task_structof a given task */
static intcheckpoint_task_struct(struct ckpt_ctx *ctx, struct task_struct *t){(quoted diff) +0
-0struct ckpt_hdr_task *h;Review
Quoted 10 lines
(quoted diff) +9
-0int 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]
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_structof a given task */
static intcheckpoint_task_struct(struct ckpt_ctx *ctx, struct task_struct *t){(quoted diff) +0
-0struct ckpt_hdr_task *h;Review
Quoted 10 lines
(quoted diff) +9
-0int 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_objalready do that throughobj_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]
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_structof a given task */
static intcheckpoint_task_struct(struct ckpt_ctx *ctx, struct task_struct *t){(quoted diff) +0
-0struct ckpt_hdr_task *h;Review
Quoted 10 lines
(quoted diff) +9
-0int 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_objalready do that throughobj_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 whencheckpoint_obj()later takes the extra reference.See for comparison
checkpoint_mm_obj(), it safely grabs thetask->mm(with a reference) around the invocation ofcheckpoint_obj().
Hmm, ok. Will do.
-serge
Re: [PATCH 4/6] cr: checkpoint and restore task credentials
In reply to a message not in the archiveQuoted 8 lines · Oren Laadan
Review
Quoted 4 lines
/* read the
task_structinto 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]
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_structinto 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->credandtask->ecredare task properties, so their reference should be stored in theckpt_hdr_task->cred_refandckpt_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.
Re: [PATCH 4/6] cr: checkpoint and restore task credentials
In reply to a message not in the archiveQuoted 24 lines · Oren Laadan
Review
Quoted 8 lines
/* read the entire state of the current task */
intrestore_task(struct ckpt_ctx *ctx)
{(quoted diff) +2
-1int 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_structto 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_ctxstructure, 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
-0ckpt_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 bydeferqueue_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]
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 */
intrestore_task(struct ckpt_ctx *ctx)
{(quoted diff) +2
-1int 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_structto 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_ctxstructure, 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
-0ckpt_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 bydeferqueue_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 theckpt_ctxfor each task'ssys_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_ctxthis 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 therestore_creds()fn if appropriate.-serge
Re: [PATCH 4/6] cr: checkpoint and restore task credentials
In reply to a message not in the archiveReview
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.