Looks ok to my near-zero-SELinux-knowledge eyes.
Will add to v19-rc3.

Oren.


Serge E. Hallyn wrote:
> 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.
> 
> There are some tests under cr_tests/selinux at
> git://git.sr71.net/~hallyn/cr_tests.git.
> 
> A corresponding simple refpolicy (and /usr/share/selinux/devel/include)
> patch is needed.
> 
> The programs to checkpoint and restart (called 'checkpoint' and
> 'restart') come 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:
>       Dec 09: update to use common_audit_data.
>       oct 09: fix memory overrun in selinux_cred_checkpoint.
>       oct 02: (Stephen Smalley suggestions):
>               1. s/__u32/u32/
>               2. enable the fown sid restoration
>               3. use process_restore to authorize resetting osid
>               4. don't make new hooks inline.
>       oct 01: Remove some debugging that is redundant with
>               avc log data.
>       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.
> 
> Signed-off-by: Serge E. Hallyn <[email protected]>
> ---
>  checkpoint/restart.c                         |    1 +
>  security/selinux/hooks.c                     |  366 
> ++++++++++++++++++++++++++
>  security/selinux/include/av_perm_to_string.h |    5 +
>  security/selinux/include/av_permissions.h    |    5 +
>  4 files changed, 377 insertions(+), 0 deletions(-)
> 
> diff --git a/checkpoint/restart.c b/checkpoint/restart.c
> index 88d791b..cc8e68d 100644
> --- a/checkpoint/restart.c
> +++ b/checkpoint/restart.c
> @@ -665,6 +665,7 @@ static int restore_lsm(struct ckpt_ctx *ctx)
>  
>       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) {
>               ckpt_debug("c/r: RESTART_KEEP_LSM unsupported for %s\n",
>                               ctx->lsm_name);
> diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
> index bb230d5..cbcdea1 100644
> --- a/security/selinux/hooks.c
> +++ b/security/selinux/hooks.c
> @@ -76,6 +76,7 @@
>  #include <linux/selinux.h>
>  #include <linux/mutex.h>
>  #include <linux/posix-timers.h>
> +#include <linux/checkpoint.h>
>  
>  #include "avc.h"
>  #include "objsec.h"
> @@ -2979,6 +2980,104 @@ static int selinux_file_permission(struct file *file, 
> int mask)
>       return selinux_revalidate_file_permission(file, mask);
>  }
>  
> +/*
> + * for file context, we print both the fsec->sid and fsec->fown_sid
> + * as string representations, separated by ':::'
> + * We don't touch isid - if you wanted that set you shoulda set up the
> + * fs correctly.
> + */
> +static char *selinux_file_checkpoint(void *security)
> +{
> +     struct file_security_struct *fsec = security;
> +     char *s1 = NULL, *s2 = NULL, *sfull;
> +     u32 len1, len2, lenfull;
> +     int ret;
> +
> +     if (fsec->sid == 0 || fsec->fown_sid == 0)
> +             return ERR_PTR(-EINVAL);
> +
> +     ret = security_sid_to_context(fsec->sid, &s1, &len1);
> +     if (ret)
> +             return ERR_PTR(ret);
> +     len1--;
> +     ret = security_sid_to_context(fsec->fown_sid, &s2, &len2);
> +     if (ret) {
> +             kfree(s1);
> +             return ERR_PTR(ret);
> +     }
> +     len2--;
> +     lenfull = len1 + len2 + 3;
> +     sfull = kmalloc(lenfull + 1, GFP_KERNEL);
> +     if (!sfull) {
> +             sfull = ERR_PTR(-ENOMEM);
> +             goto out;
> +     }
> +     sfull[lenfull] = '\0';
> +     sprintf(sfull, "%s:::%s", s1, s2);
> +
> +out:
> +     kfree(s1);
> +     kfree(s2);
> +     return sfull;
> +}
> +
> +static int selinux_file_restore(struct file *file, char *ctx)
> +{
> +     char *s1, *s2;
> +     u32 sid1 = 0, sid2 = 0;
> +     int ret = -EINVAL;
> +     struct file_security_struct *fsec = file->f_security;
> +
> +     /*
> +      * Objhash made sure the string is null-terminated.
> +      * We make a copy so we can mangle it.
> +      */
> +     s1 = kstrdup(ctx, GFP_KERNEL);
> +     if (!s1)
> +             return -ENOMEM;
> +     s2 = strstr(s1, ":::");
> +     if (!s2)
> +             goto out;
> +
> +     *s2 = '\0';
> +     s2 += 3;
> +     if (*s2 == '\0')
> +             goto out;
> +
> +     /* SECSID_NULL is not valid for file sids */
> +     if (strlen(s1) == 0 || strlen(s2) == 0)
> +             goto out;
> +
> +     ret = security_context_to_sid(s1, strlen(s1), &sid1);
> +     if (ret)
> +             goto out;
> +     ret = security_context_to_sid(s2, strlen(s2), &sid2);
> +     if (ret)
> +             goto out;
> +
> +     if (sid1 && fsec->sid != sid1) {
> +             ret = avc_has_perm(current_sid(), sid1, SECCLASS_FILE,
> +                                     FILE__RESTORE, NULL);
> +             if (ret)
> +                     goto out;
> +             fsec->sid = sid1;
> +     }
> +
> +     if (sid2 && fsec->fown_sid != sid2) {
> +             ret = avc_has_perm(current_sid(), sid2, SECCLASS_FILE,
> +                             FILE__FOWN_RESTORE, NULL);
> +             if (ret)
> +                     goto out;
> +            fsec->fown_sid = sid2;
> +     }
> +
> +     ret = 0;
> +
> +out:
> +     kfree(s1);
> +     return ret;
> +}
> +
>  static int selinux_file_alloc_security(struct file *file)
>  {
>       return file_alloc_security(file);
> @@ -3237,6 +3336,186 @@ static int selinux_task_create(unsigned long 
> clone_flags)
>       return current_has_perm(current, PROCESS__FORK);
>  }
>  
> +#define NUMTASKSIDS 6
> +/*
> + * for cred context, we print:
> + *   osid, sid, exec_sid, create_sid, keycreate_sid, sockcreate_sid;
> + * as string representations, separated by ':::'
> + */
> +static char *selinux_cred_checkpoint(void *security)
> +{
> +     struct task_security_struct *tsec = security;
> +     char *stmp, *sfull = NULL;
> +     u32 slen, runlen;
> +     int i, ret;
> +     u32 sids[NUMTASKSIDS] = { tsec->osid, tsec->sid, tsec->exec_sid,
> +             tsec->create_sid, tsec->keycreate_sid, tsec->sockcreate_sid };
> +
> +     if (sids[0] == 0 || sids[1] == 0)
> +             /* SECSID_NULL is not valid for osid or sid */
> +             return ERR_PTR(-EINVAL);
> +
> +     ret = security_sid_to_context(sids[0], &sfull, &runlen);
> +     if (ret)
> +             return ERR_PTR(ret);
> +     runlen--;
> +
> +     for (i = 1; i < NUMTASKSIDS; i++) {
> +             if (sids[i] == 0) {
> +                     stmp = NULL;
> +                     slen = 0;
> +             } else {
> +                     ret = security_sid_to_context(sids[i], &stmp, &slen);
> +                     if (ret) {
> +                             kfree(sfull);
> +                             return ERR_PTR(ret);
> +                     }
> +                     slen--;
> +             }
> +             /* slen + runlen + ':::' + \0 */
> +             sfull = krealloc(sfull, slen + runlen + 3 + 1,
> +                              GFP_KERNEL);
> +             if (!sfull) {
> +                     kfree(stmp);
> +                     return ERR_PTR(-ENOMEM);
> +             }
> +             sprintf(sfull+runlen, ":::%s", stmp ? stmp : "");
> +             runlen += slen + 3;
> +             kfree(stmp);
> +     }
> +
> +     return sfull;
> +}
> +
> +static inline int credrestore_nullvalid(int which)
> +{
> +     int valid_array[NUMTASKSIDS] = {
> +             0, /* task osid */
> +             0, /* task sid */
> +             1, /* exec sid */
> +             1, /* create sid */
> +             1, /* keycreate_sid */
> +             1, /* sockcreate_sid */
> +     };
> +
> +     return valid_array[which];
> +}
> +
> +static int selinux_cred_restore(struct file *file, struct cred *cred,
> +                                     char *ctx)
> +{
> +     char *s, *s1, *s2 = NULL;
> +     int ret = -EINVAL;
> +     struct task_security_struct *tsec = cred->security;
> +     int i;
> +     u32 sids[NUMTASKSIDS];
> +     struct inode *ctx_inode = file->f_dentry->d_inode;
> +     struct common_audit_data ad;
> +
> +     /*
> +      * objhash made sure the string is null-terminated
> +      * now we want our own copy so we can chop it up with \0's
> +      */
> +     s = kstrdup(ctx, GFP_KERNEL);
> +     if (!s)
> +             return -ENOMEM;
> +
> +     s1 = s;
> +     for (i = 0; i < NUMTASKSIDS; i++) {
> +             if (i < NUMTASKSIDS-1) {
> +                     ret = -EINVAL;
> +                     s2 = strstr(s1, ":::");
> +                     if (!s2)
> +                             goto out;
> +                     *s2 = '\0';
> +                     s2 += 3;
> +             }
> +             if (strlen(s1) == 0) {
> +                     ret = -EINVAL;
> +                     if (credrestore_nullvalid(i))
> +                             sids[i] = 0;
> +                     else
> +                             goto out;
> +             } else {
> +                     ret = security_context_to_sid(s1, strlen(s1), &sids[i]);
> +                     if (ret)
> +                             goto out;
> +             }
> +             s1 = s2;
> +     }
> +
> +     /*
> +      * Check that these transitions are allowed, and effect them.
> +      * XXX: Do these checks suffice?
> +      */
> +     if (tsec->osid != sids[0]) {
> +             ret = avc_has_perm(current_sid(), sids[0], SECCLASS_PROCESS,
> +                                     PROCESS__RESTORE, NULL);
> +             if (ret)
> +                     goto out;
> +              tsec->osid = sids[0];
> +     }
> +
> +     if (tsec->sid != sids[1]) {
> +             struct inode_security_struct *isec;
> +             ret = avc_has_perm(current_sid(), sids[1], SECCLASS_PROCESS,
> +                                     PROCESS__RESTORE, NULL);
> +             if (ret)
> +                     goto out;
> +
> +             /* check whether checkpoint file type is a valid entry
> +              * point to the new domain:  we may want a specific
> +              * 'restore_entrypoint' permission for this, but let's
> +              * see if just entrypoint is deemed sufficient
> +              */
> +
> +             COMMON_AUDIT_DATA_INIT(&ad, FS);
> +             ad.u.fs.path = file->f_path;
> +
> +             isec = ctx_inode->i_security;
> +             ret = avc_has_perm(sids[1], isec->sid, SECCLASS_FILE,
> +                             FILE__ENTRYPOINT, &ad);
> +             if (ret)
> +                     goto out;
> +             /* TODO: do we need to check for shared state? */
> +             tsec->sid = sids[1];
> +     }
> +
> +     ret = -EPERM;
> +     if (sids[2] != tsec->exec_sid) {
> +             if (!current_has_perm(current, PROCESS__SETEXEC))
> +                     goto out;
> +             tsec->exec_sid = sids[2];
> +     }
> +
> +     if (sids[3] != tsec->create_sid) {
> +             if (!current_has_perm(current, PROCESS__SETFSCREATE))
> +                     goto out;
> +             tsec->create_sid = sids[3];
> +     }
> +
> +     if (tsec->keycreate_sid != sids[4]) {
> +             if (!current_has_perm(current, PROCESS__SETKEYCREATE))
> +                     goto out;
> +             if (!may_create_key(sids[4], current))
> +                     goto out;
> +             tsec->keycreate_sid = sids[4];
> +     }
> +
> +     if (tsec->sockcreate_sid != sids[5]) {
> +             if (!current_has_perm(current, PROCESS__SETSOCKCREATE))
> +                     goto out;
> +             tsec->sockcreate_sid = sids[5];
> +     }
> +
> +     ret = 0;
> +
> +out:
> +     kfree(s);
> +     return ret;
> +}
> +
> +
>  /*
>   * allocate the SELinux part of blank credentials
>   */
> @@ -4762,6 +5041,44 @@ static void ipc_free_security(struct kern_ipc_perm 
> *perm)
>       kfree(isec);
>  }
>  
> +static char *selinux_msg_msg_checkpoint(void *security)
> +{
> +     struct msg_security_struct *msec = security;
> +     char *s;
> +     u32 len;
> +     int ret;
> +
> +     if (msec->sid == 0)
> +             return ERR_PTR(-EINVAL);
> +
> +     ret = security_sid_to_context(msec->sid, &s, &len);
> +     if (ret)
> +             return ERR_PTR(ret);
> +     return s;
> +}
> +
> +static int selinux_msg_msg_restore(struct msg_msg *msg, char *ctx)
> +{
> +     struct msg_security_struct *msec = msg->security;
> +     int ret;
> +     u32 sid = 0;
> +
> +     ret = security_context_to_sid(ctx, strlen(ctx), &sid);
> +     if (ret)
> +             return ret;
> +
> +     if (msec->sid == sid)
> +             return 0;
> +
> +     ret = avc_has_perm(current_sid(), sid, SECCLASS_MSG,
> +                             MSG__RESTORE, NULL);
> +     if (ret)
> +             return ret;
> +
> +     msec->sid = sid;
> +     return 0;
> +}
> +
>  static int msg_msg_alloc_security(struct msg_msg *msg)
>  {
>       struct msg_security_struct *msec;
> @@ -5165,6 +5482,47 @@ static void selinux_ipc_getsecid(struct kern_ipc_perm 
> *ipcp, u32 *secid)
>       *secid = isec->sid;
>  }
>  
> +static char *selinux_ipc_checkpoint(void *security)
> +{
> +     struct ipc_security_struct *isec = security;
> +     char *s;
> +     u32 len;
> +     int ret;
> +
> +     if (isec->sid == 0)
> +             return ERR_PTR(-EINVAL);
> +
> +     ret = security_sid_to_context(isec->sid, &s, &len);
> +     if (ret)
> +             return ERR_PTR(ret);
> +     return s;
> +}
> +
> +static int selinux_ipc_restore(struct kern_ipc_perm *ipcp, char *ctx)
> +{
> +     struct ipc_security_struct *isec = ipcp->security;
> +     int ret;
> +     u32 sid = 0;
> +     struct common_audit_data ad;
> +
> +     ret = security_context_to_sid(ctx, strlen(ctx), &sid);
> +     if (ret)
> +             return ret;
> +
> +     if (isec->sid == sid)
> +             return 0;
> +
> +     COMMON_AUDIT_DATA_INIT(&ad, IPC);
> +     ad.u.ipc_id = ipcp->key;
> +     ret = avc_has_perm(current_sid(), sid, SECCLASS_IPC,
> +                             IPC__RESTORE, &ad);
> +     if (ret)
> +             return ret;
> +
> +     isec->sid = sid;
> +     return 0;
> +}
> +
>  static void selinux_d_instantiate(struct dentry *dentry, struct inode *inode)
>  {
>       if (inode)
> @@ -5512,6 +5870,8 @@ static struct security_operations selinux_ops = {
>       .inode_getsecid =               selinux_inode_getsecid,
>  
>       .file_permission =              selinux_file_permission,
> +     .file_checkpoint =              selinux_file_checkpoint,
> +     .file_restore =                 selinux_file_restore,
>       .file_alloc_security =          selinux_file_alloc_security,
>       .file_free_security =           selinux_file_free_security,
>       .file_ioctl =                   selinux_file_ioctl,
> @@ -5527,6 +5887,8 @@ static struct security_operations selinux_ops = {
>  
>       .task_create =                  selinux_task_create,
>       .cred_alloc_blank =             selinux_cred_alloc_blank,
> +     .cred_checkpoint =              selinux_cred_checkpoint,
> +     .cred_restore =                 selinux_cred_restore,
>       .cred_free =                    selinux_cred_free,
>       .cred_prepare =                 selinux_cred_prepare,
>       .cred_transfer =                selinux_cred_transfer,
> @@ -5550,8 +5912,12 @@ static struct security_operations selinux_ops = {
>  
>       .ipc_permission =               selinux_ipc_permission,
>       .ipc_getsecid =                 selinux_ipc_getsecid,
> +     .ipc_checkpoint =               selinux_ipc_checkpoint,
> +     .ipc_restore =                  selinux_ipc_restore,
>  
>       .msg_msg_alloc_security =       selinux_msg_msg_alloc_security,
> +     .msg_msg_checkpoint =           selinux_msg_msg_checkpoint,
> +     .msg_msg_restore =              selinux_msg_msg_restore,
>       .msg_msg_free_security =        selinux_msg_msg_free_security,
>  
>       .msg_queue_alloc_security =     selinux_msg_queue_alloc_security,
> diff --git a/security/selinux/include/av_perm_to_string.h 
> b/security/selinux/include/av_perm_to_string.h
> index 2b683ad..c5a1838 100644
> --- a/security/selinux/include/av_perm_to_string.h
> +++ b/security/selinux/include/av_perm_to_string.h
> @@ -19,6 +19,8 @@
>     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_FILE, FILE__FOWN_RESTORE, "fown_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 +90,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")
> @@ -108,6 +112,7 @@
>     S_(SECCLASS_SYSTEM, SYSTEM__SYSLOG_MOD, "syslog_mod")
>     S_(SECCLASS_SYSTEM, SYSTEM__SYSLOG_CONSOLE, "syslog_console")
>     S_(SECCLASS_SYSTEM, SYSTEM__MODULE_REQUEST, "module_request")
> +   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")
> diff --git a/security/selinux/include/av_permissions.h 
> b/security/selinux/include/av_permissions.h
> index 0546d61..77ad07b 100644
> --- a/security/selinux/include/av_permissions.h
> +++ b/security/selinux/include/av_permissions.h
> @@ -101,6 +101,8 @@
>  #define FILE__ENTRYPOINT                          0x00040000UL
>  #define FILE__EXECMOD                             0x00080000UL
>  #define FILE__OPEN                                0x00100000UL
> +#define FILE__RESTORE                             0x00200000UL
> +#define FILE__FOWN_RESTORE                        0x00400000UL
>  #define LNK_FILE__IOCTL                           0x00000001UL
>  #define LNK_FILE__READ                            0x00000002UL
>  #define LNK_FILE__WRITE                           0x00000004UL
> @@ -475,6 +477,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
> @@ -484,6 +487,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
> @@ -505,6 +509,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
_______________________________________________
Containers mailing list
[email protected]
https://lists.linux-foundation.org/mailman/listinfo/containers

_______________________________________________
Devel mailing list
[email protected]
https://openvz.org/mailman/listinfo/devel

Reply via email to