From: Mimi Zohar <zohar@linux.vnet.ibm.com>
To: selinux@tycho.nsa.gov
Cc: zohar@us.ibm.com, safford@watson.ibm.com
Subject: [RFC]integrity: SELinux patch
Date: Mon, 16 Jul 2007 09:57:20 -0400 [thread overview]
Message-ID: <1184594240.5860.5.camel@localhost.localdomain> (raw)
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.
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:
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.
next reply other threads:[~2007-07-16 16:04 UTC|newest]
Thread overview: 36+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-07-16 13:57 Mimi Zohar [this message]
2007-07-16 18:40 ` [RFC]integrity: SELinux patch Joshua Brindle
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=1184594240.5860.5.camel@localhost.localdomain \
--to=zohar@linux.vnet.ibm.com \
--cc=safford@watson.ibm.com \
--cc=selinux@tycho.nsa.gov \
--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.