LSM checkpoint/restart: introduction
Subsystems (5)
cover LSM checkpoint/restart: introduction
Following is a respin of the LSM checkpoint/restart patchset, hopefully addressing most of the feedback I've gotten.
The patchset includes one (1/4) patch which is not directly LSM-related, one (2/4) which implements the generic LSM c/r support, one (3/4) implementing support for Smack, one (4/4) implementing support for SELinux, and one (1/1) updating the userspace program which initiates restart.
At this point I'm hoping to get some acks and get them pushed to the c/r kernel tree, which is branch ckpt-v17-dev ingit://git.ncl.cs.columbia.edu/pub/git/linux-cr.git/. Comments are of course appreciated. Once they sit in the tree for a bit, I'll tackle the socket related LSM c/r.
thanks,
-serge
PATCH 1/4 cr: define ckpt_debug if CONFIG_CHECKPOINT=n
So not all c/r code has to be ifdefed...
--- include/linux/checkpoint.h | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-)
include/linux/checkpoint.h +3 -0
@@ -337,6 +337,9 @@ extern unsigned long ckpt_debug_level;#endif /* CONFIG_CHECKPOINT_DEBUG */ +#else /* CONFIG_CHECKPOINT */ +#define _ckpt_debug(level, fmt, args...) do { } while (0) +#define ckpt_debug(fmt, args...) do { } while (0)#endif /* CONFIG_CHECKPOINT */ #endif /* __KERNEL__ */
Signature · 1 line
1.6.1
PATCH 2/4 cr: add generic LSM c/r support
In reply to Serge E. Hallyn[ This patch is against branch ckpt-v17-dev of the checkpoint/restart kernel tree at git://git.ncl.cs.columbia.edu/pub/git/linux-cr.git/ ]
Documentation/checkpoint/readme.txt begins:
"""
Application checkpoint/restart is the ability to save the state of a running application so that it can later resume its execution from the time at which it was checkpointed.
"""
This patch adds generic support for c/r of LSM credentials. Support for Smack and SELinux (and TOMOYO if appropriate) will be added later. Capabilities is already supported through generic creds code.
This patch supports ipc_perm, msg_msg, cred (task) and file ->security fields. Inodes, superblocks, netif, and xfrm currently are restored not through sys_restart() but through container creation, and so the security fields should be done then as well. Network should be added when network c/r is added.
Briefly, all security fields must be exported by the LSM as a simple null-terminated string. They are checkpointed through the security_checkpoint_obj() helper, because we must pass it an extra sectype field. Splitting SECURITY_OBJ_SEC into one type per object type would not work because, in Smack, one void* security is used for all object types. But we must pass the sectype field because in SELinux a different type of structure is stashed in each object type.
The RESTART_KEEP_LSM flag indicates that the LSM should attempt to reuse checkpointed security labels. It is always invalid when the LSM at restart differs from that at checkpoint. It is currently only usable for capabilities.
(For capabilities, restart without RESTART_KEEP_LSM is technically not implemented. There actually might be a use case for that, but the safety of it is dubious so for now we always re-create checkpointed capability sets whether RESTART_KEEP_LSM is specified or not)
Changelog:
sep 3: fix memory leak on LSM restore error path
Sep 3: provide 2 hooks, may_restart and checkpoint_header, to facilitate
an LSM tracking policy changes.
sep 10: merge RESTART_KEEP_LSM patch with basic LSM c/r
support patches.
sep 10: rename security_xyz_get_ctx() to security_xyz_checkpoint(),
in order to avoid confusing with the various other 'context' helpers in the security_ namespace, relating to secids and sysfs xattrs.
sep 10: pass context file to security_cred_restore. SELinux will
want the file's security context to authorize it as an entrypoint for the new process context.
--- Documentation/checkpoint/readme.txt | 25 +++++ checkpoint/checkpoint.c | 11 ++ checkpoint/files.c | 30 ++++++ checkpoint/objhash.c | 93 +++++++++++++++++ checkpoint/restart.c | 25 +++++ checkpoint/sys.c | 22 ++++ include/linux/checkpoint.h | 9 ++- include/linux/checkpoint_hdr.h | 24 +++++- include/linux/checkpoint_types.h | 9 ++ include/linux/security.h | 188 +++++++++++++++++++++++++++++++++++ ipc/checkpoint.c | 34 +++++-- ipc/checkpoint_msg.c | 26 +++++- ipc/checkpoint_sem.c | 4 +- ipc/checkpoint_shm.c | 4 +- ipc/util.h | 6 +- kernel/cred.c | 20 ++++- security/capability.c | 74 ++++++++++++++ security/security.c | 124 +++++++++++++++++++++++ 18 files changed, 705 insertions(+), 23 deletions(-)
Documentation/checkpoint/readme.txt +25 -0
@@ -328,6 +328,31 @@ So that's why we don't want CAP_SYS_ADMIN required up-front. That way we will be forced to more carefully review each of those features. However, this can be controlled with a sysctl-variable. +LSM +=== + +Security modules use custom labels on subjects and objects to +further mediate access decisions beyond DAC controls. When +checkpoint applications, these labels are [ work in progress ] +checkpointed along with the objects. At restart, the +RESTART_KEEP_LSM flag tells the kernel whether re-created objects +whould keep their checkpointed labels, or get automatically +recalculated labels. Since checkpointed labels will only make +sense to the same LSM which was active at checkpoint time, +sys_restart() with the RESTART_KEEP_LSM flag will fail with +-EINVAL if the LSM active at restart is not the same as that +active at checkpoint. If RESTART_KEEP_LSM is not specified, +then objects will be given whatever default labels the LSM and +their optional policy decide. Of course, when RESTART_KEEP_LSM +is specified, the LSM may choose a different label than the +checkpointed one, or fail the entire restart if the caller +does not have permission to create objects with the checkpointed +label. + +It should always be safe to take a checkpoint of an application +under LSM_1, and restart it without the RESTART_KEEP_LSM flag +under LSM_2. + Kernel interfaces =================
checkpoint/checkpoint.c +11 -0
@@ -24,6 +24,7 @@#include <linux/utsname.h> #include <linux/magic.h> #include <linux/hrtimer.h> +#include <linux/security.h> #include <linux/checkpoint.h> #include <linux/checkpoint_hdr.h>
@@ -250,6 +251,16 @@ static int checkpoint_write_header(struct ckpt_ctx *ctx)if (ret <0 )return ret; +memset (ctx->lsm_name,0 ,SECURITY_NAME_MAX +1 ); +strlcpy (ctx->lsm_name,security_get_lsm_name (),SECURITY_NAME_MAX +1 ); + ret =ckpt_write_buffer (ctx, ctx->lsm_name,SECURITY_NAME_MAX +1 ); +if (ret <0 ) +return ret; + + ret =security_checkpoint_header (ctx); +if (ret <0 ) +return ret; +return checkpoint_write_header_arch (ctx); }
checkpoint/files.c +30 -0
@@ -143,6 +143,19 @@ static int scan_fds(struct files_struct *files, int **fdtable)return n; } +#ifdef CONFIG_SECURITY +int checkpoint_file_security (struct ckpt_ctx *ctx,struct file *file) +{ +return security_checkpoint_obj (ctx, file->f_security, +CKPT_SECURITY_FILE ); +} +#else +int checkpoint_file_security (struct ckpt_ctx *ctx,struct file *file) +{ +return -EOPNOTSUPP ; +} +#endif +int checkpoint_file_common (struct ckpt_ctx *ctx,struct file *file,struct ckpt_hdr_file *h) {
@@ -155,6 +168,12 @@ int checkpoint_file_common(struct ckpt_ctx *ctx, struct file *file,if (h->f_credref <0 )return h->f_credref; + h->f_secref =checkpoint_file_security (ctx, file); +if (h->f_secref == -EOPNOTSUPP ) + h->f_secref =-1 ; +else if (h->f_secref <0 ) +return h->f_secref; +/* FIX: need also file->f_owner, etc */ return 0 ;
@@ -481,6 +500,17 @@ int restore_file_common(struct ckpt_ctx *ctx, struct file *file,put_cred (file->f_cred); file->f_cred =get_cred (cred); +if ((ctx->uflags &RESTART_KEEP_LSM ) && (h->f_secref !=-1 )) { +struct ckpt_stored_lsm *l =ckpt_obj_fetch (ctx, h->f_secref, +CKPT_OBJ_SEC ); +if (IS_ERR (l)) +return PTR_ERR (l); + + ret =security_file_restore (file, l->string); +if (ret) +return ret; + } +/* 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);if (ret <0 )
checkpoint/objhash.c +93 -0
111 lines not on this page · raw message
checkpoint/restart.c +25 -0
@@ -423,6 +423,31 @@ static int restore_read_header(struct ckpt_ctx *ctx)if (ret <0 ) goto out; + ret =_ckpt_read_buffer (ctx, ctx->lsm_name,SECURITY_NAME_MAX +1 ); +if (ret <0 ) + goto out; +if (ctx->uflags &RESTART_KEEP_LSM ) { +char *cur =security_get_lsm_name (); +if (strncmp (cur, ctx->lsm_name,SECURITY_NAME_MAX +1 ) !=0 ) { +pr_warning ("c/r: checkpointed LSM %s, current is %s.\n" , + ctx->lsm_name, cur); + ret = -EINVAL ; + goto out; + } +/* to be implemented later, per-lsm */ +if (strcmp (ctx->lsm_name,"lsm_none" ) !=0 && +strcmp (ctx->lsm_name,"default" ) !=0 ) { +pr_warning ("c/r: RESTART_KEEP_LSM unsupported for %s\n" , + ctx->lsm_name); + ret = -ENOSYS ; + goto out; + } + } + + ret =security_may_restart (ctx); +if (ret <0 ) + goto out; + ret =restore_read_header_arch (ctx); out:kfree (uts);
checkpoint/sys.c +22 -0
@@ -169,6 +169,28 @@ void *ckpt_hdr_get_type(struct ckpt_ctx *ctx, int len, int type)return h; } +#define DUMMY_LSM_INFO "dummy" + +int ckpt_write_dummy_lsm_info (struct ckpt_ctx *ctx) +{ +return ckpt_write_obj_type (ctx,DUMMY_LSM_INFO , +strlen (DUMMY_LSM_INFO ),CKPT_HDR_LSM_INFO ); +} + +/* +* ckpt_snarf_lsm_info +* If there is a CKPT_HDR_LSM_INFO field, toss it. +* Used when the current LSM doesn't care about this field. +*/ +void ckpt_snarf_lsm_info (struct ckpt_ctx *ctx) +{ +struct ckpt_hdr *h; + + h =ckpt_read_buf_type (ctx,CKPT_LSM_INFO_LEN ,CKPT_HDR_LSM_INFO ); +if (!IS_ERR (h)) +ckpt_hdr_put (ctx, h); +} +/* * Helpers to manage c/r contexts: allocated for each checkpoint and/or
include/linux/checkpoint.h +7 -2
@@ -10,7 +10,7 @@* distribution for more details. */ -#define CHECKPOINT_VERSION 1 +#define CHECKPOINT_VERSION 2/* checkpoint user flags */ #define CHECKPOINT_SUBTREE 0x1
@@ -18,6 +18,7 @@/* restart user flags */ #define RESTART_TASKSELF 0x1#define RESTART_FROZEN 0x2 +#define RESTART_KEEP_LSM 0x4#ifdef __KERNEL__#ifdef CONFIG_CHECKPOINT
@@ -44,7 +45,9 @@/* ckpt_ctx: uflags */ #define CHECKPOINT_USER_FLAGS CHECKPOINT_SUBTREE -#define RESTART_USER_FLAGS (RESTART_TASKSELF | RESTART_FROZEN) +#define RESTART_USER_FLAGS (RESTART_TASKSELF | RESTART_FROZEN | \ + RESTART_KEEP_LSM) +#define CKPT_LSM_INFO_LEN 200extern void exit_checkpoint (struct task_struct *tsk);
@@ -55,6 +58,8 @@ extern void _ckpt_hdr_put(struct ckpt_ctx *ctx, void *ptr, int n);extern void ckpt_hdr_put (struct ckpt_ctx *ctx,void *ptr);extern void *ckpt_hdr_get (struct ckpt_ctx *ctx,int n);extern void *ckpt_hdr_get_type (struct ckpt_ctx *ctx,int n,int type); +extern int ckpt_write_dummy_lsm_info (struct ckpt_ctx *ctx); +extern void ckpt_snarf_lsm_info (struct ckpt_ctx *ctx);extern int ckpt_write_obj (struct ckpt_ctx *ctx,struct ckpt_hdr *h); extern int ckpt_write_obj_type(struct ckpt_ctx *ctx,
include/linux/checkpoint_hdr.h +23 -1
@@ -53,6 +53,8 @@ enum {CKPT_HDR_BUFFER ,CKPT_HDR_STRING ,CKPT_HDR_OBJREF , +CKPT_HDR_SEC , +CKPT_HDR_LSM_INFO ,CKPT_HDR_TREE =101 , CKPT_HDR_TASK,
@@ -136,6 +138,7 @@ enum obj_type {CKPT_OBJ_USER ,CKPT_OBJ_GROUPINFO ,CKPT_OBJ_SOCK , +CKPT_OBJ_SEC , CKPT_OBJ_MAX };
@@ -176,10 +179,11 @@ struct ckpt_hdr_header {__u64 uflags;/* uflags from checkpoint */ /* -* the header is followed by three strings: +* the header is followed by four strings: * char release[const.uts_release_len]; * char version[const.uts_version_len]; * char machine[const.uts_machine_len]; +* char lsm_name[SECURITY_NAME_MAX + 1] */ } __attribute__((aligned(8)));
@@ -249,6 +253,8 @@ struct ckpt_hdr_cred {__u32 gid, sgid, egid, fsgid;__s32 user_ref;__s32 groupinfo_ref; +__s32 sec_ref; +__u32 padding;struct ckpt_capabilities cap_s; } __attribute__((aligned(8)));
@@ -261,6 +267,16 @@ struct ckpt_hdr_groupinfo {__u32 groups[0 ]; } __attribute__((aligned(8))); +struct ckpt_hdr_lsm { +struct ckpt_hdr h; +__u8 sectype; +__u16 len; +/* +* This is followed by a string of size len+1, +* null-terminated +*/ +__u8 string[0 ]; +} __attribute__((aligned (8 )));/* * todo - keyrings and LSM * These may be better done with userspace help though
@@ -356,6 +372,8 @@ struct ckpt_hdr_file {__s32 f_credref;__u64 f_pos;__u64 f_version; +__s32 f_secref; +__u32 f_padding; } __attribute__((aligned(8)));struct ckpt_hdr_file_generic {
@@ -594,6 +612,8 @@ struct ckpt_hdr_ipc_perms {__u32 mode;__u32 _padding;__u64 seq; +__s32 sec_ref; +__u32 padding; } __attribute__((aligned(8)));struct ckpt_hdr_ipc_shm {
@@ -627,6 +647,8 @@ struct ckpt_hdr_ipc_msg_msg {struct ckpt_hdr h;__s32 m_type;__u32 m_ts; +__s32 sec_ref; +__u32 padding; } __attribute__((aligned(8)));struct ckpt_hdr_ipc_sem {
include/linux/checkpoint_types.h +9 -0
@@ -19,6 +19,7 @@#include <linux/fs.h> #include <linux/ktime.h> #include <linux/wait.h> +#include <linux/security.h> struct ckpt_stats {int uts_ns;
@@ -36,6 +37,7 @@ struct ckpt_ctx {struct task_struct *root_task;/* [container] root task */ struct nsproxy *root_nsproxy;/* [container] root nsproxy */ struct task_struct *root_freezer;/* [container] root task */ +char lsm_name[SECURITY_NAME_MAX +1 ];/* security module at ckpt */ unsigned long kflags;/* kerenl flags */ unsigned long uflags;/* user flags */
@@ -71,6 +73,13 @@ struct ckpt_ctx {struct ckpt_stats stats;/* statistics */ }; +/* stored on hashtable */ +struct ckpt_stored_lsm { +struct kref kref; +int sectype; +char *string; +}; +#endif /* __KERNEL__ */ #endif /* _LINUX_CHECKPOINT_TYPES_H_ */
include/linux/security.h +188 -0
315 lines not on this page · raw message
ipc/checkpoint.c +24 -10
@@ -31,7 +31,8 @@ static char *ipc_ind_to_str[] = { "sem", "msg", "shm" };* Checkpoint */ -int checkpoint_fill_ipc_perms (struct ckpt_hdr_ipc_perms *h, +int checkpoint_fill_ipc_perms (struct ckpt_ctx *ctx, +struct ckpt_hdr_ipc_perms *h,struct kern_ipc_perm *perm) {if (ipcperms (perm,S_IROTH ))
@@ -45,6 +46,15 @@ int checkpoint_fill_ipc_perms(struct ckpt_hdr_ipc_perms *h, h->cgid = perm->cgid; h->mode = perm->mode &S_IRWXUGO ; h->seq = perm->seq; +if (perm->security) { + h->sec_ref =security_checkpoint_obj (ctx, perm->security, +CKPT_SECURITY_IPC ); +if (h->sec_ref == -EOPNOTSUPP ) + h->sec_ref =-1 ; +else if (h->sec_ref <0 ) +return h->sec_ref; + }else + h->sec_ref =-1 ;return 0 ; }
@@ -176,7 +186,8 @@ static int validate_created_perms(struct ckpt_hdr_ipc_perms *h)return 1 ; } -int restore_load_ipc_perms (struct ckpt_hdr_ipc_perms *h, +int restore_load_ipc_perms (struct ckpt_ctx *ctx, +struct ckpt_hdr_ipc_perms *h,struct kern_ipc_perm *perm) {if (h->id <0 )
@@ -205,14 +216,17 @@ int restore_load_ipc_perms(struct ckpt_hdr_ipc_perms *h, perm->cgid = h->cgid; perm->mode = h->mode; perm->seq = h->seq; -/* -* Todo: restore perm->security. -* At the moment it gets set by security_x_alloc() called through -* ipcget()->ipcget_public()->ops-.getnew (->nequeue for instance) -* We will want to ask the LSM to consider resetting the -* checkpointed ->security, based on current_security(), -* the checkpointed ->security, and the checkpoint file context. -*/ + +if ((ctx->uflags &RESTART_KEEP_LSM ) && (h->sec_ref !=-1 )) { +int ret; +struct ckpt_stored_lsm *l =ckpt_obj_fetch (ctx, h->sec_ref, +CKPT_OBJ_SEC ); +if (IS_ERR (l)) +return PTR_ERR (l); + ret =security_ipc_restore (perm, l->string); +if (ret) +return ret; + }return 0 ; }
ipc/checkpoint_msg.c +23 -3
@@ -37,7 +37,7 @@ static int fill_ipc_msg_hdr(struct ckpt_ctx *ctx,ipc_lock_by_ptr (&msq->q_perm); - ret =checkpoint_fill_ipc_perms (&h->perms, &msq->q_perm); + ret =checkpoint_fill_ipc_perms (ctx, &h->perms, &msq->q_perm);if (ret <0 ) goto unlock;
@@ -64,13 +64,23 @@ static int checkpoint_msg_contents(struct ckpt_ctx *ctx, struct msg_msg *msg)struct msg_msgseg *seg;int total, len;int ret; - +int sec_ref =-1 ; + +if (msg->security) { + sec_ref =security_checkpoint_obj (ctx, msg->security, +CKPT_SECURITY_MSG_MSG ); +if (sec_ref == -EOPNOTSUPP ) + sec_ref =-1 ; +else if (sec_ref <0 ) +return sec_ref; + } h =ckpt_hdr_get_type (ctx,sizeof (*h),CKPT_HDR_IPC_MSG_MSG );if (!h)return -ENOMEM ; h->m_type = msg->m_type; h->m_ts = msg->m_ts; + h->sec_ref = sec_ref; ret =ckpt_write_obj (ctx, &h->h);ckpt_hdr_put (ctx, h);
@@ -177,7 +187,7 @@ static int load_ipc_msg_hdr(struct ckpt_ctx *ctx, {int ret =0 ; - ret =restore_load_ipc_perms (&h->perms, &msq->q_perm); + ret =restore_load_ipc_perms (ctx, &h->perms, &msq->q_perm);if (ret <0 )return ret;
@@ -224,6 +234,16 @@ static struct msg_msg *restore_msg_contents_one(struct ckpt_ctx *ctx, int *clen) msg->next =NULL ; pseg = &msg->next; +if ((ctx->uflags &RESTART_KEEP_LSM ) && (h->sec_ref !=-1 )) { +struct ckpt_stored_lsm *l =ckpt_obj_fetch (ctx, h->sec_ref, +CKPT_OBJ_SEC ); +if (IS_ERR (l)) +return (struct msg_msg *)l; + ret =security_msg_msg_restore (msg, l->string); +if (ret) +return ERR_PTR (ret); + } + ret =_ckpt_read_buffer (ctx, (msg +1 ), len);if (ret <0 ) goto out;
ipc/checkpoint_sem.c +2 -2
@@ -37,7 +37,7 @@ static int fill_ipc_sem_hdr(struct ckpt_ctx *ctx,ipc_lock_by_ptr (&sem->sem_perm); - ret =checkpoint_fill_ipc_perms (&h->perms, &sem->sem_perm); + ret =checkpoint_fill_ipc_perms (ctx, &h->perms, &sem->sem_perm);if (ret <0 ) goto unlock;
@@ -113,7 +113,7 @@ static int load_ipc_sem_hdr(struct ckpt_ctx *ctx, {int ret =0 ; - ret =restore_load_ipc_perms (&h->perms, &sem->sem_perm); + ret =restore_load_ipc_perms (ctx, &h->perms, &sem->sem_perm);if (ret <0 )return ret;
ipc/checkpoint_shm.c +2 -2
@@ -41,7 +41,7 @@ static int fill_ipc_shm_hdr(struct ckpt_ctx *ctx,ipc_lock_by_ptr (&shp->shm_perm); - ret =checkpoint_fill_ipc_perms (&h->perms, &shp->shm_perm); + ret =checkpoint_fill_ipc_perms (ctx, &h->perms, &shp->shm_perm);if (ret <0 ) goto unlock;
@@ -166,7 +166,7 @@ static int load_ipc_shm_hdr(struct ckpt_ctx *ctx, {int ret; - ret =restore_load_ipc_perms (&h->perms, &shp->shm_perm); + ret =restore_load_ipc_perms (ctx, &h->perms, &shp->shm_perm);if (ret <0 )return ret;
ipc/util.h +4 -2
@@ -199,9 +199,11 @@ void freeary(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp);#ifdef CONFIG_CHECKPOINT -extern int checkpoint_fill_ipc_perms (struct ckpt_hdr_ipc_perms *h, +extern int checkpoint_fill_ipc_perms (struct ckpt_ctx *ctx, +struct ckpt_hdr_ipc_perms *h,struct kern_ipc_perm *perm); -extern int restore_load_ipc_perms (struct ckpt_hdr_ipc_perms *h, +extern int restore_load_ipc_perms (struct ckpt_ctx *ctx, +struct ckpt_hdr_ipc_perms *h,struct kern_ipc_perm *perm);extern int checkpoint_ipc_shm (int id,void *p,void *data);
kernel/cred.c +19 -1
@@ -709,7 +709,7 @@ int cred_setfsgid(struct cred *new, gid_t gid, gid_t *old_fsgid)static int do_checkpoint_cred (struct ckpt_ctx *ctx,const struct cred *cred) {int ret; -int groupinfo_ref, user_ref; +int groupinfo_ref, user_ref, sec_ref =-1 ;struct ckpt_hdr_cred *h; groupinfo_ref = checkpoint_obj(ctx, cred->group_info,
@@ -719,6 +719,14 @@ static int do_checkpoint_cred(struct ckpt_ctx *ctx, const struct cred *cred) user_ref =checkpoint_obj (ctx, cred->user,CKPT_OBJ_USER );if (user_ref <0 )return user_ref; +#ifdef CONFIG_SECURITY + sec_ref =security_checkpoint_obj (ctx, cred->security, +CKPT_SECURITY_CRED ); +if (sec_ref == -EOPNOTSUPP ) + sec_ref =-1 ; +else if (sec_ref <0 ) +return sec_ref; +#endif /* else cred->security doesn't exist and sec_ref = -1 */ h =ckpt_hdr_get_type (ctx,sizeof (*h),CKPT_HDR_CRED );if (!h)
@@ -733,6 +741,7 @@ static int do_checkpoint_cred(struct ckpt_ctx *ctx, const struct cred *cred) h->sgid = cred->sgid; h->egid = cred->egid; h->fsgid = cred->fsgid; + h->sec_ref = sec_ref;checkpoint_capabilities (&h->cap_s, cred);
@@ -806,6 +815,15 @@ static struct cred *do_restore_cred(struct ckpt_ctx *ctx) ret =cred_setfsgid (cred, h->fsgid, &oldgid);if (oldgid != h->fsgid && ret <0 ) goto err_putcred; +if ((ctx->uflags &RESTART_KEEP_LSM ) && (h->sec_ref !=-1 )) { +struct ckpt_stored_lsm *l =ckpt_obj_fetch (ctx, h->sec_ref, +CKPT_OBJ_SEC ); +if (IS_ERR (l)) +return (struct cred *)l; + ret =security_cred_restore (ctx->file, cred, l->string); +if (ret) + goto err_putcred; + } ret =restore_capabilities (&h->cap_s, cred);if (ret) goto err_putcred;
security/capability.c +74 -0
128 lines not on this page · raw message
security/security.c +124 -0
162 lines not on this page · raw message
Signature · 1 line
1.6.1
PATCH 3/4 cr: add smack support to lsm c/r
In reply to Serge E. Hallyn[ This patch is against branch ckpt-v17-dev of the checkpoint/restart kernel tree at git://git.ncl.cs.columbia.edu/pub/git/linux-cr.git/ ]
Documentation/checkpoint/readme.txt begins:
"""
Application checkpoint/restart is the ability to save the state of a running application so that it can later resume its execution from the time at which it was checkpointed.
"""
[ Note - switching to not having to kmalloc/kfree for smack labels is not yet addressed. I want to first handle the socket LSM label c/r, after which I'll be able to better judge what makes sense and what doesn't. ]
This patch implements checkpoint and restore of Smack security labels. The rules are the same as in previous versions:
1. when objects are created during restore() they are automatically labeled with current_security().
2. if there was a label checkpointed with the object, and that label != current_security() (which is the same as obj->security), then the object is relabeled if the sys_restart() caller has CAP_MAC_ADMIN. Otherwise we return -EPERM.
This has been tested by checkpointing tasks under labels _, vs1, and vs2, and restarting from tasks under _, vs1, and vs2, with and without CAP_MAC_ADMIN in the bounding set, and with and without the '-k' (keep_lsm) flag to mktree. Expected results:
#shell 1:
echo vs1 > /proc/self/attr/current
ckpt > out
echo vs2 > /proc/self/attr/current
mktree -F /cgroup/2 < out
(frozen)
# shell 2:
cat /proc/pidof ckpt/attr/current
vs2
echo THAWED > /cgroup/2/freezer.state
# shell 1:
mktree -k -F /cgroup/2 < out
(frozen)
# shell 2:
cat /proc/pidof ckpt/attr/current
vs1
echo THAWED > /cgroup/2/freezer.state
# shell 1:
capsh --drop=cap_mac_admin --
mktree -k -F /cgroup/2 < out
(permission denied)
There are testcases in git://git.sr71.net/~hallyn/cr_tests.git
under cr_tests/smack, which automate the above (and pass).
Changelog:
sep 3: add a version to smack lsm, accessible through
/smack/version (Casey and Serge)
sep 10: rename xyz_get_ctx() to xyz_checkpoint()
--- checkpoint/restart.c | 1 + security/security.c | 8 +++ security/smack/smack.h | 1 + security/smack/smack_lsm.c | 141 ++++++++++++++++++++++++++++++++++++++++++++ security/smack/smackfs.c | 83 ++++++++++++++++++++++++++ 5 files changed, 234 insertions(+), 0 deletions(-)
checkpoint/restart.c +1 -0
@@ -436,6 +436,7 @@ static int restore_read_header(struct ckpt_ctx *ctx) }/* to be implemented later, per-lsm */ if (strcmp (ctx->lsm_name,"lsm_none" ) !=0 && +strcmp (ctx->lsm_name,"smack" ) !=0 &&strcmp (ctx->lsm_name,"default" ) !=0 ) {pr_warning ("c/r: RESTART_KEEP_LSM unsupported for %s\n" , ctx->lsm_name);
security/security.c +8 -0
@@ -1330,6 +1330,14 @@ int security_checkpoint_obj(struct ckpt_ctx *ctx, void *security,char *str;int len; +/* +* to simplify the LSM code, short-cut a null security +* here - hopefully not actually needed; test without +* this one day. +*/ +if (!security) +return -EOPNOTSUPP ; +switch (sectype) {case CKPT_SECURITY_MSG_MSG : str =security_msg_msg_checkpoint (security);
security/smack/smack.h +1 -0
@@ -216,6 +216,7 @@ u32 smack_to_secid(const char *);extern int smack_cipso_direct;extern char *smack_net_ambient;extern char *smack_onlycap; +extern char *smack_version;extern const char *smack_cipso_option;extern struct smack_known smack_known_floor;
security/smack/smack_lsm.c +141 -0
203 lines not on this page · raw message
security/smack/smackfs.c +83 -0
113 lines not on this page · raw message
Signature · 1 line
1.6.1
PATCH 4/4 cr: add selinux support
In reply to Serge E. Hallyn[ This patch is against branch ckpt-v17-dev of the checkpoint/restart kernel tree at git://git.ncl.cs.columbia.edu/pub/git/linux-cr.git/ ]
Documentation/checkpoint/readme.txt begins:
"""
Application checkpoint/restart is the ability to save the state of a running application so that it can later resume its execution from the time at which it was checkpointed.
"""
This patch adds the ability to checkpoint and restore selinux contexts for tasks, open files, and sysvipc objects. Contexts are checkpointed as strings. For tasks and files, where a security struct actually points to several contexts, all contexts are written out in one string, separated by ':::'.
The default behaviors are to checkpoint contexts, but not to restore them. To attempt to restore them, sys_restart() must be given the RESTART_KEEP_LSM flag. If this is given then the caller of sys_restart() must have the new 'restore' permission to the target objclass, or for instance PROCESS__SETFSCREATE to itself to specify a create_sid.
A corresponding simple refpolicy patch is needed. I'm also working on a little testsuite to add to git://git.sr71.net/~hallyn/cr_tests.git,
which should test the restoration with and without permission of the various sids. (more general rhel5.4 refpolicy problems are standing
in the way) For now I've tested simply by creating checkpoint
images using cr_tests/simple/ckpt > out from both staff_t and sysyadm_t, and doing
shell 1:
mktree -F /freezer/1 < out
shell 2:
cat /proc/pidof ckpt/attr/current
(same as context of shell 1)
echo THAWED > /freezer/1/freezer.state
shell 1:
mktree -k -F /freezer/1 < out
(fails if enforcing and not permitted to restore the original labels)
shell 2:
cat /proc/pidof ckpt/attr/current
(same as context of the shell which had done the original ckpt)
echo THAWED > /freezer/1/freezer.state
Mktree comes from git://git.ncl.cs.columbia.edu/pub/git/user-cr.git,
This patch applies against the checkpoint/restart-enabled kernel tree at git://git.ncl.cs.columbia.edu/pub/git/linux-cr.git/.
Changelog:
sep 10: (Most addressing suggestions by Stephen Smalley)
1. change xyz_get_ctx() to xyz_checkpoint().
2. check entrypoint permission on cred_restore
3. always dec context length by 1
4. don't allow SECSID_NULL when that's not valid
5. when SECSID_NULL is valid, restore it
6. c/r task->osid
7. Just print nothing instead of 'null' for SECSID_NULL
8. sids are __u32, as are lenghts passed to sid_to_context.
--- checkpoint/restart.c | 1 + security/selinux/hooks.c | 383 ++++++++++++++++++++++++++ security/selinux/include/av_perm_to_string.h | 4 + security/selinux/include/av_permissions.h | 4 + 4 files changed, 392 insertions(+), 0 deletions(-)
checkpoint/restart.c +1 -0
@@ -437,6 +437,7 @@ static int restore_read_header(struct ckpt_ctx *ctx)/* to be implemented later, per-lsm */ if (strcmp (ctx->lsm_name,"lsm_none" ) !=0 &&strcmp (ctx->lsm_name,"smack" ) !=0 && +strcmp (ctx->lsm_name,"selinux" ) !=0 &&strcmp (ctx->lsm_name,"default" ) !=0 ) {pr_warning ("c/r: RESTART_KEEP_LSM unsupported for %s\n" , ctx->lsm_name);
security/selinux/hooks.c +383 -0
433 lines not on this page · raw message
security/selinux/include/av_perm_to_string.h +4 -0
@@ -19,6 +19,7 @@ S_(SECCLASS_FILE, FILE__ENTRYPOINT, "entrypoint") S_(SECCLASS_FILE, FILE__EXECMOD, "execmod") S_(SECCLASS_FILE, FILE__OPEN, "open") + S_(SECCLASS_FILE, FILE__RESTORE, "restore") S_(SECCLASS_CHR_FILE, CHR_FILE__EXECUTE_NO_TRANS, "execute_no_trans") S_(SECCLASS_CHR_FILE, CHR_FILE__ENTRYPOINT, "entrypoint")S_ (SECCLASS_CHR_FILE ,CHR_FILE__EXECMOD ,"execmod" )
@@ -88,9 +89,11 @@ S_(SECCLASS_PROCESS, PROCESS__EXECHEAP, "execheap") S_(SECCLASS_PROCESS, PROCESS__SETKEYCREATE, "setkeycreate") S_(SECCLASS_PROCESS, PROCESS__SETSOCKCREATE, "setsockcreate") + S_(SECCLASS_PROCESS, PROCESS__RESTORE, "restore") S_(SECCLASS_MSGQ, MSGQ__ENQUEUE, "enqueue") S_(SECCLASS_MSG, MSG__SEND, "send") S_(SECCLASS_MSG, MSG__RECEIVE, "receive") + S_(SECCLASS_MSG, MSG__RESTORE, "restore") S_(SECCLASS_SHM, SHM__LOCK, "lock") S_(SECCLASS_SECURITY, SECURITY__COMPUTE_AV, "compute_av")S_ (SECCLASS_SECURITY ,SECURITY__COMPUTE_CREATE ,"compute_create" )
@@ -107,6 +110,7 @@ S_(SECCLASS_SYSTEM, SYSTEM__SYSLOG_READ, "syslog_read") S_(SECCLASS_SYSTEM, SYSTEM__SYSLOG_MOD, "syslog_mod") S_(SECCLASS_SYSTEM, SYSTEM__SYSLOG_CONSOLE, "syslog_console") + S_(SECCLASS_IPC, IPC__RESTORE, "restore") S_(SECCLASS_CAPABILITY, CAPABILITY__CHOWN, "chown") S_(SECCLASS_CAPABILITY, CAPABILITY__DAC_OVERRIDE, "dac_override")S_ (SECCLASS_CAPABILITY ,CAPABILITY__DAC_READ_SEARCH ,"dac_read_search" )
security/selinux/include/av_permissions.h +4 -0
@@ -101,6 +101,7 @@#define FILE__ENTRYPOINT 0x00040000UL#define FILE__EXECMOD 0x00080000UL#define FILE__OPEN 0x00100000UL +#define FILE__RESTORE 0x00200000UL#define LNK_FILE__IOCTL 0x00000001UL#define LNK_FILE__READ 0x00000002UL#define LNK_FILE__WRITE 0x00000004UL
@@ -453,6 +454,7 @@#define PROCESS__EXECHEAP 0x08000000UL#define PROCESS__SETKEYCREATE 0x10000000UL#define PROCESS__SETSOCKCREATE 0x20000000UL +#define PROCESS__RESTORE 0x40000000UL#define IPC__CREATE 0x00000001UL#define IPC__DESTROY 0x00000002UL#define IPC__GETATTR 0x00000004UL
@@ -462,6 +464,7 @@#define IPC__ASSOCIATE 0x00000040UL#define IPC__UNIX_READ 0x00000080UL#define IPC__UNIX_WRITE 0x00000100UL +#define IPC__RESTORE 0x00000200UL#define SEM__CREATE 0x00000001UL#define SEM__DESTROY 0x00000002UL#define SEM__GETATTR 0x00000004UL
@@ -483,6 +486,7 @@#define MSGQ__ENQUEUE 0x00000200UL#define MSG__SEND 0x00000001UL#define MSG__RECEIVE 0x00000002UL +#define MSG__RESTORE 0x00000004UL#define SHM__CREATE 0x00000001UL#define SHM__DESTROY 0x00000002UL#define SHM__GETATTR 0x00000004UL
Signature · 1 line
1.6.1
PATCH 1/1 mktree: accept the lsm_name field in header and add -k flag
In reply to Serge E. Hallyn[ This patch is against the userspace checkpoint/restart code, available at git://git.ncl.cs.columbia.edu/pub/git/user-cr.git ]
The checkpoint file header now has an 11-character string containing the name of the active LSM, following the uts info, and a variable length buffer type conaining LSM-specific version information (for instance a sha1sum of policy). Handle these.
Also add a -k (--keeplsm) flag to tell mktree to set the RESTART_KEEP_LSM flag to sys_restart().
--- mktree.c | 32 ++++++++++++++++++++++++++++++-- 1 files changed, 30 insertions(+), 2 deletions(-)
mktree.c +30 -2
@@ -45,6 +45,7 @@ static char usage_str[] ="\t -P,--no-pidns do not create a new pid namspace (default)\n" "\t --pids restore original pids (default with --pidns)\n" "\t -w,--wait wait for (root) task to termiate (default)\n" +"\t -k,--keeplsm Try to recreate original LSM labels on all objects\n" "\t --show-status show exit status of (root) task (implies -w)\n" "\t --copy-status imitate exit status of (root) task (implies -w)\n" "\t -W,--no-wait do not wait for (root) task to terminate\n"
@@ -259,6 +260,8 @@ struct args {char *freezer; }; +int keep_lsm; +static void usage (char *str) {fprintf (stderr,"%s" , str);
@@ -273,6 +276,7 @@ static void parse_args(struct args *args, int argc, char *argv[]) { "pidns-signal", required_argument, NULL, '4' }, { "no-pidns", no_argument, NULL, 'P' }, { "pids", no_argument, NULL, 3 }, + { "keeplsm", no_argument, NULL, 'k' }, { "wait", no_argument, NULL, 'w' }, { "show-status", no_argument, NULL, 1 }, { "copy-status", no_argument, NULL, 2 },
@@ -282,7 +286,7 @@ static void parse_args(struct args *args, int argc, char *argv[]) { "debug", no_argument, NULL, 'd' }, { NULL, 0, NULL, 0 } }; -static char optc[] ="hdvpPwWF:" ; +static char optc[] ="hdvpPkwWF:" ;int sig;
@@ -320,6 +324,9 @@ static void parse_args(struct args *args, int argc, char *argv[]) args->pids =1 ; args->pidns =1 ;/* implied */ break ; +case 'k' : + keep_lsm =RESTART_KEEP_LSM ; +break ;case 'w' : args->wait =1 ;break ;
@@ -750,6 +757,7 @@ static int ckpt_coordinator(struct ckpt_ctx *ctx)if (ctx->args->freezer) flags |=RESTART_FROZEN ; + flags |= keep_lsm; ret =restart (root_pid,STDIN_FILENO , flags);if (ret <0 ) {
@@ -1309,7 +1317,7 @@ static int ckpt_make_tree(struct ckpt_ctx *ctx, struct task *task)/* on success this doesn't return */ ckpt_dbg ("about to call sys_restart()\n" ); - ret =restart (0 ,STDIN_FILENO ,0 ); + ret =restart (0 ,STDIN_FILENO , keep_lsm);if (ret <0 )perror ("task restore failed" );return ret;
@@ -1704,6 +1712,7 @@ static int ckpt_read_obj_buffer(struct ckpt_ctx *ctx, void *buf, int n)* read/write the checkpoint image: similar to in-kernel code */ +#define SECURITY_NAME_MAX 10static int ckpt_read_header (struct ckpt_ctx *ctx) {struct ckpt_hdr_header *h;
@@ -1737,6 +1746,16 @@ static int ckpt_read_header(struct ckpt_ctx *ctx)if (ret <0 )return ret; + ptr += ((struct ckpt_hdr *) ptr)->len; + ret =ckpt_read_obj_buffer (ctx, ptr,SECURITY_NAME_MAX +1 ); +if (ret <0 ) +return ret; + + ptr += ((struct ckpt_hdr *) ptr)->len; + ret =ckpt_read_obj_type (ctx, ptr,200 ,CKPT_HDR_LSM_INFO ); +if (ret <0 ) +return ret; +/* FIXME: skip version validation for now */ return 0 ;
@@ -1815,6 +1834,15 @@ static int ckpt_write_header(struct ckpt_ctx *ctx)return ret; ptr += ((struct ckpt_hdr *) ptr)->len; ret =ckpt_write_obj (ctx, (struct ckpt_hdr *) ptr); +if (ret <0 ) +return ret; + ptr += ((struct ckpt_hdr *) ptr)->len; + ret =ckpt_write_obj (ctx, (struct ckpt_hdr *) ptr); +if (ret <0 ) +return ret; + + ptr += ((struct ckpt_hdr *) ptr)->len; + ret =ckpt_write_obj (ctx, (struct ckpt_hdr *) ptr);return ret; }
Signature · 1 line
1.6.1.1