All of lore.kernel.org
 help / color / mirror / Atom feed
From: Casey Schaufler <casey@schaufler-ca.com>
To: "Serge E. Hallyn" <serue@us.ibm.com>
Cc: Oren Laadan <orenl@cs.columbia.edu>,
	Linux Containers <containers@lists.osdl.org>,
	linux-security-module@vger.kernel.org,
	SELinux <selinux@tycho.nsa.gov>,
	Casey Schaufler <casey@schaufler-ca.com>
Subject: Re: [RFC PATCH 2/2] cr: debug security_checkpoint_header and	security_may_restart
Date: Thu, 03 Sep 2009 22:20:46 -0700	[thread overview]
Message-ID: <4AA0A3AE.9040106@schaufler-ca.com> (raw)
In-Reply-To: <20090903222853.GA27556@us.ibm.com>

Serge E. Hallyn wrote:
> This patch, for debugging only, introduces a silly admin-controlled
> 'policy version' for smack.  By default the version is 1.  An
> admin (with CAP_MAC_ADMIN) can change it by echoing a new value
> into /smack/version.
>   

The scheme you have suggested is just one step off of completely
acceptable for real. More detail below, but if you make the "version"
a string instead of a number I'm happy with it. In particular, a
string that would itself be a valid Smack label makes everything
really simple.

It would take me a few days, but if you're not in a real hurry or
you're lazier than I am (yeah, right) I could provide a patch that
does it. Or, if I haven't been completely incomprehensible, you
could do a revision.


> It then defines security_checkpoint_header() to add this 'policy
> version' into the checkpoint header, and defines security_may_restart()
> to refuse restart if both:
> 	1. the caller asked for RESTART_KEEP_LSM
> and
> 	2. the checkpointed version was different from the current.
>
> This of course is easy enough to test by doing
>
> 	echo 1 > /smack/version
> 	ckpt > out
> 	mktree < out
> 		succeed
> 	mktree -k < out
> 		succeed
> 	echo 2 > /smack/version
> 	mktree < out
> 		succeed
> 	mktree -k < out
> 		fail
>
> Signed-off-by: Serge E. Hallyn <serue@us.ibm.com>
> ---
>  security/smack/smack_lsm.c |   46 +++++++++++++++++++++++++++
>  security/smack/smackfs.c   |   75 ++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 121 insertions(+), 0 deletions(-)
>
> diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
> index 279fdce..f0d4a08 100644
> --- a/security/smack/smack_lsm.c
> +++ b/security/smack/smack_lsm.c
> @@ -27,6 +27,7 @@
>  #include <linux/udp.h>
>  #include <linux/mutex.h>
>  #include <linux/pipe_fs_i.h>
> +#include <linux/checkpoint.h>
>  #include <net/netlabel.h>
>  #include <net/cipso_ipv4.h>
>  #include <linux/audit.h>
> @@ -3111,6 +3112,47 @@ static void smack_release_secctx(char *secdata, u32 seclen)
>  {
>  }
>  
> +#ifdef CONFIG_CHECKPOINT
> +extern int smack_version;
>   

Make this a char * instead of an int and set it to
smack_known_floor.smk_known (which will be "_").


> +
> +static int smack_may_restart(struct ckpt_ctx *ctx)
>   

So as to reduce confusion between ctx's and checkpoint thingies,

   static int smack_may_restart(struct ckpt_ctx *ckptx)
> +{
> +	struct ckpt_hdr *h;
>   

How about:
          struct ckpt_hdr *chp;

instead for a little more consistency with Smack code.

> +	char *smackv;
> +	int v = 0, slen, ret;
> +
> +	h = ckpt_read_buf_type(ctx, CKPT_LSM_INFO_LEN, CKPT_HDR_LSM_INFO);
> +	if (IS_ERR(h))
> +		return PTR_ERR(h);
> +
> +	if (strcmp(ctx->lsm_name, "smack") != 0)
> +		return 0;
> +
> +	smackv = (char *) (h + 1);
>   

And delete from here ...

> +	slen = h->len - sizeof(*h);
> +	if (smackv[slen-1] != '\0')
> +		smackv[slen-1] = '\0';
> +	ret = sscanf(smackv, "%d", &v);
>   

... to here. How about we say that the version name meet the same
requirements as a label? A call to smk_import() can verify that and
take care of all the memory allocation business.

> +	ckpt_hdr_put(ctx, h);
> +	if (!(ctx->uflags & RESTART_KEEP_LSM))
> +		return 0;
> +	if (ret != 1 || v != smack_version) {
>   

Make this a strcmp()

> +		ckpt_debug("Smack version at checkpoint was %d, now is %d\n",
>   

%s instead of %d all around.

> +			v, smack_version);
> +		return -EINVAL;
> +	}
> +	return 0;
> +}
> +
> +static int smack_checkpoint_header(struct cpt_ctx *ctx)
> +{
> +	char smackv[10];
> +	sprintf(smackv, "%d", smack_version);
>   

You can drop this ...

> +	return ckpt_write_obj_type(ctx, smackv, strlen(smackv)+1,
> +				  CKPT_HDR_LSM_INFO);
>   

And pass back smack_version, which is a string.

> +}
> +#endif
> +
>  struct security_operations smack_ops = {
>  	.name =				"smack",
>  
> @@ -3245,6 +3287,10 @@ struct security_operations smack_ops = {
>  	.secid_to_secctx = 		smack_secid_to_secctx,
>  	.secctx_to_secid = 		smack_secctx_to_secid,
>  	.release_secctx = 		smack_release_secctx,
> +#ifdef CONFIG_CHECKPOINT
> +	.may_restart =			smack_may_restart,
> +	.checkpoint_header =		smack_checkpoint_header,
> +#endif
>  };
>  
>  
> diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
> index f83a809..7b20ad9 100644
> --- a/security/smack/smackfs.c
> +++ b/security/smack/smackfs.c
> @@ -42,6 +42,7 @@ enum smk_inos {
>  	SMK_NETLBLADDR	= 8,	/* single label hosts */
>  	SMK_ONLYCAP	= 9,	/* the only "capable" label */
>  	SMK_LOGGING	= 10,	/* logging */
> +	SMK_VERSION	= 11,	/* logging */
>  };
>  
>  /*
> @@ -51,6 +52,7 @@ static DEFINE_MUTEX(smack_list_lock);
>  static DEFINE_MUTEX(smack_cipso_lock);
>  static DEFINE_MUTEX(smack_ambient_lock);
>  static DEFINE_MUTEX(smk_netlbladdr_lock);
> +static DEFINE_MUTEX(smack_version_lock);
>  
>  /*
>   * This is the "ambient" label for network traffic.
> @@ -60,6 +62,11 @@ static DEFINE_MUTEX(smk_netlbladdr_lock);
>  char *smack_net_ambient = smack_known_floor.smk_known;
>  
>  /*
> + * this is the policy version, a simple integer
> + */
> +int smack_version = 1;
> +
>   

Make this a char * instead of an int and set it to
smack_known_floor.smk_known (which will be "_"). As above.


> +/*
>   * This is the level in a CIPSO header that indicates a
>   * smack label is contained directly in the category set.
>   * It can be reset via smackfs/direct
> @@ -1255,6 +1262,72 @@ static const struct file_operations smk_logging_ops = {
>  	.read		= smk_read_logging,
>  	.write		= smk_write_logging,
>  };
> +
> +#define SMK_VERSIONLEN 12
>   

    #define SMK_VERSIONLEN SMK_LABELLEN

> +/**
> + * smk_read_version - read() for /smack/version
> + * @filp: file pointer, not actually used
> + * @buf: where to put the result
> + * @cn: maximum to send along
> + * @ppos: where to start
> + *
> + * Returns number of bytes read or error code, as appropriate
> + */
> +static ssize_t smk_read_version(struct file *filp, char __user *buf,
> +				size_t count, loff_t *ppos)
> +{
> +	char temp[SMK_VERSIONLEN];
> +
> +	if (*ppos != 0)
> +		return 0;
> +
> +	mutex_lock(&smack_version_lock);
> +	sprintf(temp, "%d\n", smack_version);
>   

In the scheme I'm suggesting, no need for the sprintf.

> +	mutex_unlock(&smack_version_lock);
> +
> +	return simple_read_from_buffer(buf, count, ppos, temp, strlen(temp));
> +}
> +
> +/**
> + * smk_write_version - write() for /smack/version
> + * @file: file pointer, not actually used
> + * @buf: where to get the data from
> + * @count: bytes sent
> + * @ppos: where to start
> + *
> + * Returns number of bytes written or error code, as appropriate
> + */
> +static ssize_t smk_write_version(struct file *file, const char __user *buf,
> +				 size_t count, loff_t *ppos)
> +{
> +	char in[SMK_VERSIONLEN];
> +	int tmp, ret;
> +
> +	if (!capable(CAP_MAC_ADMIN))
> +		return -EPERM;
> +
> +	if (count >= SMK_VERSIONLEN)
> +		return -EINVAL;
> +
> +	if (copy_from_user(in, buf, count) != 0)
> +		return -EFAULT;
>   

This would become smk_import(), replacing ....

> +
> +	in[count-1] = '\0';
> +	ret = sscanf(in, "%d", &tmp);
> +	if (ret != 1)
> +		return -EINVAL;
>   

... this

> +	mutex_lock(&smack_version_lock);
> +	smack_version = tmp;
>   

and smack_version gets the return from smk_import unless it is NULL.

> +	mutex_unlock(&smack_version_lock);
> +
> +	return count;
> +}
> +
> +static const struct file_operations smk_version_ops = {
> +	.read		= smk_read_version,
> +	.write		= smk_write_version,
> +};
> +
>  /**
>   * smk_fill_super - fill the /smackfs superblock
>   * @sb: the empty superblock
> @@ -1287,6 +1360,8 @@ static int smk_fill_super(struct super_block *sb, void *data, int silent)
>  			{"onlycap", &smk_onlycap_ops, S_IRUGO|S_IWUSR},
>  		[SMK_LOGGING]	=
>  			{"logging", &smk_logging_ops, S_IRUGO|S_IWUSR},
> +		[SMK_VERSION]	=
> +			{"version", &smk_version_ops, S_IRUGO|S_IWUSR},
>  		/* last one */ {""}
>  	};
>  
>   


WARNING: multiple messages have this Message-ID (diff)
From: Casey Schaufler <casey@schaufler-ca.com>
To: "Serge E. Hallyn" <serue@us.ibm.com>
Cc: Oren Laadan <orenl@cs.columbia.edu>,
	Linux Containers <containers@lists.osdl.org>,
	linux-security-module@vger.kernel.org,
	SELinux <selinux@tycho.nsa.gov>,
	Casey Schaufler <casey@schaufler-ca.com>
Subject: Re: [RFC PATCH 2/2] cr: debug security_checkpoint_header and	security_may_restart
Date: Thu, 03 Sep 2009 22:20:46 -0700	[thread overview]
Message-ID: <4AA0A3AE.9040106@schaufler-ca.com> (raw)
In-Reply-To: <20090903222853.GA27556@us.ibm.com>

Serge E. Hallyn wrote:
> This patch, for debugging only, introduces a silly admin-controlled
> 'policy version' for smack.  By default the version is 1.  An
> admin (with CAP_MAC_ADMIN) can change it by echoing a new value
> into /smack/version.
>   

The scheme you have suggested is just one step off of completely
acceptable for real. More detail below, but if you make the "version"
a string instead of a number I'm happy with it. In particular, a
string that would itself be a valid Smack label makes everything
really simple.

It would take me a few days, but if you're not in a real hurry or
you're lazier than I am (yeah, right) I could provide a patch that
does it. Or, if I haven't been completely incomprehensible, you
could do a revision.


> It then defines security_checkpoint_header() to add this 'policy
> version' into the checkpoint header, and defines security_may_restart()
> to refuse restart if both:
> 	1. the caller asked for RESTART_KEEP_LSM
> and
> 	2. the checkpointed version was different from the current.
>
> This of course is easy enough to test by doing
>
> 	echo 1 > /smack/version
> 	ckpt > out
> 	mktree < out
> 		succeed
> 	mktree -k < out
> 		succeed
> 	echo 2 > /smack/version
> 	mktree < out
> 		succeed
> 	mktree -k < out
> 		fail
>
> Signed-off-by: Serge E. Hallyn <serue@us.ibm.com>
> ---
>  security/smack/smack_lsm.c |   46 +++++++++++++++++++++++++++
>  security/smack/smackfs.c   |   75 ++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 121 insertions(+), 0 deletions(-)
>
> diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
> index 279fdce..f0d4a08 100644
> --- a/security/smack/smack_lsm.c
> +++ b/security/smack/smack_lsm.c
> @@ -27,6 +27,7 @@
>  #include <linux/udp.h>
>  #include <linux/mutex.h>
>  #include <linux/pipe_fs_i.h>
> +#include <linux/checkpoint.h>
>  #include <net/netlabel.h>
>  #include <net/cipso_ipv4.h>
>  #include <linux/audit.h>
> @@ -3111,6 +3112,47 @@ static void smack_release_secctx(char *secdata, u32 seclen)
>  {
>  }
>  
> +#ifdef CONFIG_CHECKPOINT
> +extern int smack_version;
>   

Make this a char * instead of an int and set it to
smack_known_floor.smk_known (which will be "_").


> +
> +static int smack_may_restart(struct ckpt_ctx *ctx)
>   

So as to reduce confusion between ctx's and checkpoint thingies,

   static int smack_may_restart(struct ckpt_ctx *ckptx)
> +{
> +	struct ckpt_hdr *h;
>   

How about:
          struct ckpt_hdr *chp;

instead for a little more consistency with Smack code.

> +	char *smackv;
> +	int v = 0, slen, ret;
> +
> +	h = ckpt_read_buf_type(ctx, CKPT_LSM_INFO_LEN, CKPT_HDR_LSM_INFO);
> +	if (IS_ERR(h))
> +		return PTR_ERR(h);
> +
> +	if (strcmp(ctx->lsm_name, "smack") != 0)
> +		return 0;
> +
> +	smackv = (char *) (h + 1);
>   

And delete from here ...

> +	slen = h->len - sizeof(*h);
> +	if (smackv[slen-1] != '\0')
> +		smackv[slen-1] = '\0';
> +	ret = sscanf(smackv, "%d", &v);
>   

... to here. How about we say that the version name meet the same
requirements as a label? A call to smk_import() can verify that and
take care of all the memory allocation business.

> +	ckpt_hdr_put(ctx, h);
> +	if (!(ctx->uflags & RESTART_KEEP_LSM))
> +		return 0;
> +	if (ret != 1 || v != smack_version) {
>   

Make this a strcmp()

> +		ckpt_debug("Smack version at checkpoint was %d, now is %d\n",
>   

%s instead of %d all around.

> +			v, smack_version);
> +		return -EINVAL;
> +	}
> +	return 0;
> +}
> +
> +static int smack_checkpoint_header(struct cpt_ctx *ctx)
> +{
> +	char smackv[10];
> +	sprintf(smackv, "%d", smack_version);
>   

You can drop this ...

> +	return ckpt_write_obj_type(ctx, smackv, strlen(smackv)+1,
> +				  CKPT_HDR_LSM_INFO);
>   

And pass back smack_version, which is a string.

> +}
> +#endif
> +
>  struct security_operations smack_ops = {
>  	.name =				"smack",
>  
> @@ -3245,6 +3287,10 @@ struct security_operations smack_ops = {
>  	.secid_to_secctx = 		smack_secid_to_secctx,
>  	.secctx_to_secid = 		smack_secctx_to_secid,
>  	.release_secctx = 		smack_release_secctx,
> +#ifdef CONFIG_CHECKPOINT
> +	.may_restart =			smack_may_restart,
> +	.checkpoint_header =		smack_checkpoint_header,
> +#endif
>  };
>  
>  
> diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
> index f83a809..7b20ad9 100644
> --- a/security/smack/smackfs.c
> +++ b/security/smack/smackfs.c
> @@ -42,6 +42,7 @@ enum smk_inos {
>  	SMK_NETLBLADDR	= 8,	/* single label hosts */
>  	SMK_ONLYCAP	= 9,	/* the only "capable" label */
>  	SMK_LOGGING	= 10,	/* logging */
> +	SMK_VERSION	= 11,	/* logging */
>  };
>  
>  /*
> @@ -51,6 +52,7 @@ static DEFINE_MUTEX(smack_list_lock);
>  static DEFINE_MUTEX(smack_cipso_lock);
>  static DEFINE_MUTEX(smack_ambient_lock);
>  static DEFINE_MUTEX(smk_netlbladdr_lock);
> +static DEFINE_MUTEX(smack_version_lock);
>  
>  /*
>   * This is the "ambient" label for network traffic.
> @@ -60,6 +62,11 @@ static DEFINE_MUTEX(smk_netlbladdr_lock);
>  char *smack_net_ambient = smack_known_floor.smk_known;
>  
>  /*
> + * this is the policy version, a simple integer
> + */
> +int smack_version = 1;
> +
>   

Make this a char * instead of an int and set it to
smack_known_floor.smk_known (which will be "_"). As above.


> +/*
>   * This is the level in a CIPSO header that indicates a
>   * smack label is contained directly in the category set.
>   * It can be reset via smackfs/direct
> @@ -1255,6 +1262,72 @@ static const struct file_operations smk_logging_ops = {
>  	.read		= smk_read_logging,
>  	.write		= smk_write_logging,
>  };
> +
> +#define SMK_VERSIONLEN 12
>   

    #define SMK_VERSIONLEN SMK_LABELLEN

> +/**
> + * smk_read_version - read() for /smack/version
> + * @filp: file pointer, not actually used
> + * @buf: where to put the result
> + * @cn: maximum to send along
> + * @ppos: where to start
> + *
> + * Returns number of bytes read or error code, as appropriate
> + */
> +static ssize_t smk_read_version(struct file *filp, char __user *buf,
> +				size_t count, loff_t *ppos)
> +{
> +	char temp[SMK_VERSIONLEN];
> +
> +	if (*ppos != 0)
> +		return 0;
> +
> +	mutex_lock(&smack_version_lock);
> +	sprintf(temp, "%d\n", smack_version);
>   

In the scheme I'm suggesting, no need for the sprintf.

> +	mutex_unlock(&smack_version_lock);
> +
> +	return simple_read_from_buffer(buf, count, ppos, temp, strlen(temp));
> +}
> +
> +/**
> + * smk_write_version - write() for /smack/version
> + * @file: file pointer, not actually used
> + * @buf: where to get the data from
> + * @count: bytes sent
> + * @ppos: where to start
> + *
> + * Returns number of bytes written or error code, as appropriate
> + */
> +static ssize_t smk_write_version(struct file *file, const char __user *buf,
> +				 size_t count, loff_t *ppos)
> +{
> +	char in[SMK_VERSIONLEN];
> +	int tmp, ret;
> +
> +	if (!capable(CAP_MAC_ADMIN))
> +		return -EPERM;
> +
> +	if (count >= SMK_VERSIONLEN)
> +		return -EINVAL;
> +
> +	if (copy_from_user(in, buf, count) != 0)
> +		return -EFAULT;
>   

This would become smk_import(), replacing ....

> +
> +	in[count-1] = '\0';
> +	ret = sscanf(in, "%d", &tmp);
> +	if (ret != 1)
> +		return -EINVAL;
>   

... this

> +	mutex_lock(&smack_version_lock);
> +	smack_version = tmp;
>   

and smack_version gets the return from smk_import unless it is NULL.

> +	mutex_unlock(&smack_version_lock);
> +
> +	return count;
> +}
> +
> +static const struct file_operations smk_version_ops = {
> +	.read		= smk_read_version,
> +	.write		= smk_write_version,
> +};
> +
>  /**
>   * smk_fill_super - fill the /smackfs superblock
>   * @sb: the empty superblock
> @@ -1287,6 +1360,8 @@ static int smk_fill_super(struct super_block *sb, void *data, int silent)
>  			{"onlycap", &smk_onlycap_ops, S_IRUGO|S_IWUSR},
>  		[SMK_LOGGING]	=
>  			{"logging", &smk_logging_ops, S_IRUGO|S_IWUSR},
> +		[SMK_VERSION]	=
> +			{"version", &smk_version_ops, S_IRUGO|S_IWUSR},
>  		/* last one */ {""}
>  	};
>  
>   


--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.

  reply	other threads:[~2009-09-04  5:20 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-09-03 22:28 [RFC PATCH 1/2] cr: lsm: provide hooks for an LSM to track policy changes Serge E. Hallyn
2009-09-03 22:28 ` Serge E. Hallyn
2009-09-03 22:28 ` [RFC PATCH 2/2] cr: debug security_checkpoint_header and security_may_restart Serge E. Hallyn
2009-09-03 22:28   ` Serge E. Hallyn
2009-09-04  5:20   ` Casey Schaufler [this message]
2009-09-04  5:20     ` Casey Schaufler
2009-09-04 13:46     ` Serge E. Hallyn
2009-09-04 13:46       ` Serge E. Hallyn
2009-09-07 18:31       ` Casey Schaufler
2009-09-07 18:31         ` Casey Schaufler
2009-09-08  4:12         ` Serge E. Hallyn
2009-09-08  4:12           ` Serge E. Hallyn
2009-09-09  4:43           ` Casey Schaufler
2009-09-09  4:43             ` Casey Schaufler
2009-09-09 14:35             ` Serge E. Hallyn
2009-09-09 14:35               ` Serge E. Hallyn
2009-09-09 14:52               ` Casey Schaufler
2009-09-09 14:52                 ` Casey Schaufler
2009-09-09 19:46                 ` Serge E. Hallyn
2009-09-09 19:46                   ` Serge E. Hallyn

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4AA0A3AE.9040106@schaufler-ca.com \
    --to=casey@schaufler-ca.com \
    --cc=containers@lists.osdl.org \
    --cc=linux-security-module@vger.kernel.org \
    --cc=orenl@cs.columbia.edu \
    --cc=selinux@tycho.nsa.gov \
    --cc=serue@us.ibm.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.