cr: restore credentials: first real stab
Subsystems (2)
PATCH 1/1 cr: restore credentials: first real stab
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.
Several functions like kernel/sys.c:setresuid() had their core function moved into a common fn, like cred_setresuid(), which operates on a passed-in credential. set_user() now allocates the uid in the new->user_user_ns instead of current_user_ns(). For legacy callers, new was copied from current->cred using prepare_cred(), so this should be fine (right?).
With these patches, users root and hallyn can each checkpoint and restart their own programs, and root can restart a checkpoint created by hallyn, resulting in a restart program owned by and constrained as user hallyn. (When root creates a checkpoint of hallyn's program, restarting from that checkpoint appears to succeed (return 0), but the program immediately terminates - don't know why yet).
NOTE - this patch is for task credentials only. It doesn't address credentials on open file descriptors.
Plenty of bugs to be found, no doubt.
--- checkpoint/objhash.c | 119 ++++++++++- checkpoint/process.c | 455 +++++++++++++++++++++++++++++++++++++- include/linux/capability.h | 5 + include/linux/checkpoint.h | 11 + include/linux/checkpoint_hdr.h | 56 +++++ include/linux/checkpoint_types.h | 1 + include/linux/cred.h | 9 + include/linux/user_namespace.h | 8 + kernel/capability.c | 94 +++++++- kernel/cred.c | 143 ++++++++++++ kernel/sys.c | 163 ++------------ kernel/user_namespace.c | 53 +++-- 12 files changed, 946 insertions(+), 171 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 +453 -2
509 lines not on this page · raw message
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
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 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 +56 -0
78 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__
include/linux/cred.h +9 -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,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 */
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/capability.c +81 -13
116 lines not on this page · raw message
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
kernel/user_namespace.c +37 -16
80 lines not on this page · raw message
Signature · 1 line
1.6.1