All of lore.kernel.org
 help / color / mirror / Atom feed
From: Joshua Brindle <method@manicmethod.com>
To: Mimi Zohar <zohar@linux.vnet.ibm.com>
Cc: selinux@tycho.nsa.gov, zohar@us.ibm.com, safford@watson.ibm.com
Subject: Re: [RFC]integrity: SELinux patch
Date: Mon, 16 Jul 2007 14:40:27 -0400	[thread overview]
Message-ID: <469BBB9B.3040108@manicmethod.com> (raw)
In-Reply-To: <1184594240.5860.5.camel@localhost.localdomain>

Mimi Zohar wrote:
> This is a first attempt to verify and measure file integrity, by
> adding the new Linux Integrity Modules(LIM) API calls to SElinux.
> We are planning on posting the corresponding LIM and IMA patches to
> LKML, but would like comments/suggestions here first, particularly
> in regards to the policy checking code in selinux_measure() called 
> from selinux_inode_permission().
>
> SELINUX_ENFORCE_INTEGRITY can be configured to either verify and
> enforce integrity or to just log integrity failures. The default
> is to just log integrity failures.
>
>   
I haven't reviewed the patch yet but reference to the above comments. 
This should be controlled with policy I think, its tricky though and I 
haven't thought about all the ramifications yet, I'll get back to this 
after I've thought about it.

> The integrity of the SELinux metadata is verified when the xattr
> is initially retrieved.  On an integrity failure, assuming that
> integrity verification is enforced, normal error processing occurs.
>
> By default, all executables and all files that are mmap'ed executable
> are measured. This patch extends the file class with 'measure'.
> Additional files can be measured in selinux_inode_permission()
> based on a FILE__MEASURE policy. (As the policy call is causing too
> many files to be measured, it is commented out.) For example, to
> measure kernel modules add:
>   
I'd like to say that if SELinux is controlling whether measurements 
happen or not I don't think there should be a 'default' policy in the 
module. Being able to avoid the measurement overhead for domains that we 
don't care about would be a win, fine grained as well as course grained 
measurement selections can be done with SELinux.

> 	module ima 1.0;
>
> 	require {
> 		type insmod_t;
> 		type modules_object_t;
> 		class file measure;
> 	}
>
> 	#============= insmod_t ==============
> 	allow insmod_t modules_object_t:file measure;
>
> Signed-off-by: Mimi Zohar <zohar@us.ibm.com>
> ---
> Index: linux-2.6.22-rc6-mm1/security/selinux/hooks.c
> ===================================================================
> --- linux-2.6.22-rc6-mm1.orig/security/selinux/hooks.c
> +++ linux-2.6.22-rc6-mm1/security/selinux/hooks.c
> @@ -70,6 +70,7 @@
>  #include <linux/audit.h>
>  #include <linux/string.h>
>  #include <linux/selinux.h>
> +#include <linux/integrity.h>
>  #include <linux/mutex.h>
>  
>  #include "avc.h"
> @@ -109,6 +110,12 @@ __setup("selinux=", selinux_enabled_setu
>  int selinux_enabled = 1;
>  #endif
>  
> +#ifdef CONFIG_SECURITY_SELINUX_ENFORCE_INTEGRITY
> +static int integrity_enforce = 1;
> +#else
> +static int integrity_enforce;
> +#endif
> +
>  /* Original (dummy) security module. */
>  static struct security_operations *original_ops = NULL;
>  
> @@ -847,6 +854,7 @@ static int inode_doinit_with_dentry(stru
>  	char *context = NULL;
>  	unsigned len = 0;
>  	int rc = 0;
> +	int status;
>  
>  	if (isec->initialized)
>  		goto out;
> @@ -890,35 +898,12 @@ static int inode_doinit_with_dentry(stru
>  			goto out_unlock;
>  		}
>  
> -		len = INITCONTEXTLEN;
> -		context = kmalloc(len, GFP_KERNEL);
> -		if (!context) {
> -			rc = -ENOMEM;
> +		rc = integrity_verify_metadata(dentry, XATTR_NAME_SELINUX,
> +				       &context, &len, &status);
> +		if (rc == -ENOMEM) {
>  			dput(dentry);
>  			goto out_unlock;
>  		}
> -		rc = inode->i_op->getxattr(dentry, XATTR_NAME_SELINUX,
> -					   context, len);
> -		if (rc == -ERANGE) {
> -			/* Need a larger buffer.  Query for the right size. */
> -			rc = inode->i_op->getxattr(dentry, XATTR_NAME_SELINUX,
> -						   NULL, 0);
> -			if (rc < 0) {
> -				dput(dentry);
> -				goto out_unlock;
> -			}
> -			kfree(context);
> -			len = rc;
> -			context = kmalloc(len, GFP_KERNEL);
> -			if (!context) {
> -				rc = -ENOMEM;
> -				dput(dentry);
> -				goto out_unlock;
> -			}
> -			rc = inode->i_op->getxattr(dentry,
> -						   XATTR_NAME_SELINUX,
> -						   context, len);
> -		}
>  		dput(dentry);
>  		if (rc < 0) {
>  			if (rc != -ENODATA) {
> @@ -932,6 +917,19 @@ static int inode_doinit_with_dentry(stru
>  			sid = sbsec->def_sid;
>  			rc = 0;
>  		} else {
> +			/* Log integrity failures, if integrity enforced
> +			 * behave like for any other failure.
> +			 */
> +			if (status == INTEGRITY_FAIL) {
> +				printk(KERN_WARNING "%s: verify_metadata "
> +				       "failed for dev=%s ino=%ld\n",
> +					__FUNCTION__,
> +					inode->i_sb->s_id, inode->i_ino);
> +				if (integrity_enforce) {
> +					kfree(context);
> +					goto out_unlock;
> +				}
> +			}
>  			rc = security_context_to_sid_default(context, rc, &sid,
>  			                                     sbsec->def_sid);
>  			if (rc) {
> @@ -1701,9 +1699,109 @@ static int selinux_bprm_set_security(str
>  	return 0;
>  }
>  
> -static int selinux_bprm_check_security (struct linux_binprm *bprm)
> +static inline int is_kernel_thread(struct task_struct *tsk)
> +{
> +	return (!tsk->mm) ? 1 : 0;
> +}
> +
> +static int selinux_verify_metadata(struct dentry *dentry)
> +{
> +	int rc, status;
> +
> +	if (!dentry)
> +		return 0;
> +
> +	rc = integrity_verify_metadata(dentry, NULL, NULL, NULL, &status);
> +	if (rc == -EOPNOTSUPP)
> +		return 0;
> +
> +	if (rc < 0) {
> +		printk(KERN_INFO "%s: verify_metadata %s failed"
> +				"(rc: %d - status: %d)\n", __FUNCTION__,
> +				dentry->d_name.name, rc, status);
> +		if (!integrity_enforce)
> +			rc = 0;
> +		goto out;
> +	}
> +	if (status != INTEGRITY_PASS) {	/* FAIL | NO_LABEL */
> +		if (!is_kernel_thread(current)) {
> +			printk(KERN_INFO "%s: verify_metadata %s "
> +			       "(Integrity status: %s)\n", __FUNCTION__,
> +				dentry->d_name.name,
> +				status == INTEGRITY_FAIL ? "FAIL" : "NOLABEL");
> +			if (integrity_enforce) {
> +				rc = -EACCES;
> +				goto out;
> +			}
> +		}
> +	}
> +	return 0;
> +out:
> +	return rc;
> +}
> +
> +static int selinux_verify_and_measure(struct dentry *dentry,
> +					struct file *file,
> +					char *filename, int mask)
> +{
> +	int rc, status;
> +
> +	if (!dentry && !file)
> +		return 0;
> +
> +	rc = integrity_verify_data(dentry, file, &status);
> +	if (rc < 0) {
> +		printk(KERN_INFO "%s: %s verify_data failed "
> +		       "(rc: %d - status: %d)\n", __FUNCTION__,
> +			filename, rc, status);
> +		if (!integrity_enforce)
> +			rc = 0;
> +		goto out;
> +	}
> +
> +	if (status != INTEGRITY_PASS) {
> +		if (!is_kernel_thread(current)) {
> +			printk(KERN_INFO "%s: verify_data %s "
> +			       "(Integrity status: FAIL)\n",
> +				__FUNCTION__, filename);
> +			if (integrity_enforce) {
> +				rc = -EACCES;
> +				goto out;
> +			}
> +		}
> +	}
> +
> +	/* Only measure files that passed integrity verification. */
> +	integrity_measure(dentry, file, filename, mask);
> +	return 0;
> +out:
> +	/*
> +	 * Verification failed, but as integrity is not being enforced,
> +	 * we still need to measure.
> +	 */
> +	if (rc == 0)
> +		integrity_measure(dentry, file, filename, mask);
> +	return rc;
> +}
> +
> +static int selinux_bprm_check_security(struct linux_binprm *bprm)
>  {
> -	return secondary_ops->bprm_check_security(bprm);
> +	struct dentry *dentry = bprm->file->f_dentry;
> +	int rc;
> +
> +	rc = secondary_ops->bprm_check_security(bprm);
> +	if (rc != 0)
> +		return rc;
> +
> +	/* We probably want to re-verify the metadata, verify
> +	 * the data, and measure the integrity of all executables.
> +	 */
> +	rc = selinux_verify_metadata(dentry);
> +	if (rc == 0)
> +		rc = selinux_verify_and_measure(dentry,
> +				bprm->file, bprm->filename, MAY_EXEC);
> +
> +	return rc;
>  }
>  
>  
> @@ -2252,6 +2350,30 @@ static int selinux_inode_follow_link(str
>  	return dentry_has_perm(current, NULL, dentry, FILE__READ);
>  }
>  
> +/*
> + * Measure based on a policy
> + */
> +static int selinux_measure(struct inode *inode, struct dentry *dentry)
> +{
> +	int rc = 1;
> +#if 0
> +	struct inode_security_struct *isec = inode->i_security;
> +	struct task_security_struct *tsec = current->security;
> +	struct av_decision avd;
> +	struct avc_audit_data ad;
> +
> +	/* This initial attempt to base on policy measures too much. */
> +	rc = avc_has_perm_noaudit(tsec->sid, isec->sid, SECCLASS_FILE,
> +				  FILE__MEASURE, AVC_STRICT, &avd);
> +	AVC_AUDIT_DATA_INIT(&ad,FS);
> +	ad.u.fs.mnt = NULL;
> +	ad.u.fs.dentry = dentry;
> +	avc_audit(tsec->sid, isec->sid, SECCLASS_FILE, FILE__MEASURE,
> +		  &avd, rc, &ad);
> +#endif
> +	return rc;
> +}
> +
>  static int selinux_inode_permission(struct inode *inode, int mask,
>  				    struct nameidata *nd)
>  {
> @@ -2265,9 +2387,26 @@ static int selinux_inode_permission(stru
>  		/* No permission to check.  Existence test. */
>  		return 0;
>  	}
> -
> -	return inode_has_perm(current, inode,
> +	rc = inode_has_perm(current, inode,
>  			       file_mask_to_av(inode->i_mode, mask), NULL);
> +	if (rc != 0)
> +		return rc;
> +
> +	if (S_ISREG(inode->i_mode) && (mask & MAY_READ)) {
> +		struct dentry *dentry;
> +
> +		dentry = (!nd || !nd->dentry) ?
> +				d_find_alias(inode) : nd->dentry;
> +
> +		if (dentry) {
> +			if (selinux_measure(inode, dentry) == 0)
> +				integrity_measure(dentry, NULL,
> +					(char *)dentry->d_name.name, mask);
> +			if (!nd || !nd->dentry)
> +				dput(dentry);
> +		}
> +	}
> +	return rc;
>  }
>  
>  static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
> @@ -2630,8 +2769,20 @@ static int selinux_file_mprotect(struct 
>  			return rc;
>  	}
>  #endif
> +	rc = file_map_prot_check(vma->vm_file, prot, vma->vm_flags&VM_SHARED);
> +	if (rc != 0)
> +		return rc;
>  
> -	return file_map_prot_check(vma->vm_file, prot, vma->vm_flags&VM_SHARED);
> +	if (vma->vm_file && vma->vm_file->f_dentry) {
> +		rc = selinux_verify_metadata(vma->vm_file->f_dentry);
> +		if (rc == 0)
> +			rc = selinux_verify_and_measure(NULL, vma->vm_file,
> +				(char *)vma->vm_file->f_dentry->d_name.name,
> +				MAY_EXEC);
> +		if (rc != 0)
> +			return rc;
> +	}
> +	return rc;
>  }
>  
>  static int selinux_file_lock(struct file *file, unsigned int cmd)
> Index: linux-2.6.22-rc6-mm1/security/selinux/Kconfig
> ===================================================================
> --- linux-2.6.22-rc6-mm1.orig/security/selinux/Kconfig
> +++ linux-2.6.22-rc6-mm1/security/selinux/Kconfig
> @@ -161,3 +161,15 @@ config SECURITY_SELINUX_POLICYDB_VERSION
>  	  installed under /etc/selinux/$SELINUXTYPE/policy, where
>  	  SELINUXTYPE is defined in your /etc/selinux/config.
>  
> +config SECURITY_SELINUX_ENFORCE_INTEGRITY
> +	bool "SELinux integrity "
> +	depends on SECURITY_SELINUX && INTEGRITY
> +	default n
> +	help
> +	  This option enables SELinux, using the Linux Integrity
> +	  Module (LIM) API, to verify metadata stored as extended
> +	  attributes, verify the file data and extend the TPM PCR
> +	  measurements.
> +
> +	  If you are unsure how to answer this question, answer N.
> +
> Index: linux-2.6.22-rc6-mm1/security/selinux/include/av_permissions.h
> ===================================================================
> --- linux-2.6.22-rc6-mm1.orig/security/selinux/include/av_permissions.h
> +++ linux-2.6.22-rc6-mm1/security/selinux/include/av_permissions.h
> @@ -99,6 +99,7 @@
>  #define FILE__EXECUTE_NO_TRANS                    0x00020000UL
>  #define FILE__ENTRYPOINT                          0x00040000UL
>  #define FILE__EXECMOD                             0x00080000UL
> +#define FILE__MEASURE                             0x00100000UL
>  #define LNK_FILE__IOCTL                           0x00000001UL
>  #define LNK_FILE__READ                            0x00000002UL
>  #define LNK_FILE__WRITE                           0x00000004UL
> Index: linux-2.6.22-rc6-mm1/security/selinux/include/av_perm_to_string.h
> ===================================================================
> --- linux-2.6.22-rc6-mm1.orig/security/selinux/include/av_perm_to_string.h
> +++ linux-2.6.22-rc6-mm1/security/selinux/include/av_perm_to_string.h
> @@ -17,6 +17,7 @@
>     S_(SECCLASS_FILE, FILE__EXECUTE_NO_TRANS, "execute_no_trans")
>     S_(SECCLASS_FILE, FILE__ENTRYPOINT, "entrypoint")
>     S_(SECCLASS_FILE, FILE__EXECMOD, "execmod")
> +   S_(SECCLASS_FILE, FILE__MEASURE, "measure")
>     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")
>
>
> --
> 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.
>
>   



--
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:[~2007-07-16 18:40 UTC|newest]

Thread overview: 36+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2007-07-16 13:57 [RFC]integrity: SELinux patch Mimi Zohar
2007-07-16 18:40 ` Joshua Brindle [this message]
2007-07-16 23:13   ` Mimi Zohar
2007-07-16 19:23 ` Paul Moore
2007-07-17 14:30   ` Mimi Zohar
2007-07-17 14:32     ` Paul Moore
2007-07-17 14:54     ` James Morris
2007-07-18 15:05       ` Steve G
2007-09-04 20:46         ` Mimi Zohar
2007-09-04 21:08           ` Steve Grubb
     [not found]         ` <1188999967.5563.2.camel@localhost.localdomain>
2007-09-05 15:11           ` Integrity auditing Steve Grubb
2007-09-05 19:26             ` Mimi Zohar
2007-09-06 17:07               ` Steve Grubb
2007-09-10 20:16                 ` Mimi Zohar
2007-09-12 13:25                   ` Steve Grubb
2007-07-17  0:20 ` [RFC]integrity: SELinux patch James Morris
2007-07-17 13:20   ` Joshua Brindle
2007-07-17 14:44 ` James Morris
2007-07-18 21:33   ` Mimi Zohar
2007-07-17 14:52 ` Stephen Smalley
2007-07-18 21:43   ` Mimi Zohar
2007-07-19 13:08     ` Stephen Smalley
2007-07-20 18:57       ` Mimi Zohar
  -- strict thread matches above, loose matches on Subject: below --
2007-08-28 22:35 Mimi Zohar
2007-08-29  4:16 ` Joshua Brindle
2007-08-29 10:14   ` Mimi Zohar
2007-09-19 19:41     ` Mimi Zohar
2007-09-19 21:04       ` Stephen Smalley
2007-09-20  1:34         ` Mimi Zohar
2007-09-20 13:12           ` Stephen Smalley
2007-09-20 21:16             ` James Morris
2007-09-21 14:13               ` Mimi Zohar
2007-09-21 14:02             ` Mimi Zohar
2007-08-30 20:58 ` Serge E. Hallyn
2007-08-30 21:12   ` Serge E. Hallyn
2007-08-31 13:15     ` Mimi Zohar

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=469BBB9B.3040108@manicmethod.com \
    --to=method@manicmethod.com \
    --cc=safford@watson.ibm.com \
    --cc=selinux@tycho.nsa.gov \
    --cc=zohar@linux.vnet.ibm.com \
    --cc=zohar@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.