selinux September 2007 archive
Main Archive Page > Month Archives  > selinux archives
selinux: [RFC] [Patch 4/4] integrity: SELinux LIM calls

[RFC] [Patch 4/4] integrity: SELinux LIM calls

From: Mimi Zohar <zohar_at_nospam>
Date: Fri Sep 21 2007 - 14:05:22 GMT
To: selinux@tycho.nsa.gov


[RFC]integrity: SELinux patch

This patch verifies and measures file integrity, by adding the new Linux Integrity Modules(LIM) API calls to SElinux.

This patch defines a new 'integrity' class with the permission 'measure'. Measurement calls are made in selinux_file_mmap(), selinux_bprm_check_security, and selinux_inode_permission(), based on policy. (Additional calls might be required.)

Signed-off-by: Mimi Zohar <zohar@us.ibm.com> --- Index: linux-2.6.23-rc6-mm1/security/selinux/hooks.c =================================================================== --- linux-2.6.23-rc6-mm1.orig/security/selinux/hooks.c +++ linux-2.6.23-rc6-mm1/security/selinux/hooks.c
@@ -69,6 +69,7 @@
#include <linux/audit.h> #include <linux/string.h> #include <linux/selinux.h> +#include <linux/integrity.h> #include <linux/mutex.h> #include "avc.h"
@@ -844,6 +845,7 @@ static int inode_doinit_with_dentry(stru
char *context = NULL; unsigned len = 0; int rc = 0; + int status; if (isec->initialized) goto out;
@@ -888,34 +890,12 @@ static int inode_doinit_with_dentry(stru
} 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) {
@@ -929,6 +909,14 @@ static int inode_doinit_with_dentry(stru
sid = sbsec->def_sid; rc = 0; } else { + 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); + kfree(context); + goto out_unlock; + } rc = security_context_to_sid_default(context, rc, &sid, sbsec->def_sid); if (rc) {
@@ -1698,9 +1686,87 @@ static int selinux_bprm_set_security(str
return 0; } -static int selinux_bprm_check_security (struct linux_binprm *bprm) +static int selinux_verify_metadata(struct dentry *dentry) { - return secondary_ops->bprm_check_security(bprm); + int rc, status; + + if (!dentry) + return 0; + + rc = integrity_verify_metadata(dentry, NULL, NULL, NULL, &status); + if (rc == -EOPNOTSUPP) + return 0; + if (rc < 0) + goto out; + + if (status != INTEGRITY_PASS) /* FAIL | NO_LABEL */ + rc = -EACCES; +out: + return rc; +} + +static int selinux_verify_data(struct dentry *dentry, struct file *file) +{ + int rc, status; + + if (!dentry && !file) + return 0; + + rc = integrity_verify_data(dentry, file, &status); + if (rc < 0) + return 0; + + if (status != INTEGRITY_PASS) + rc = -EACCES; + + return rc; +} + +/* + * Measure based on new 'integrity' class policy + */ +static void selinux_measure(struct inode *inode, struct dentry *dentry, + struct file *file, char *filename, + int mask) +{ + int rc = 1; + struct inode_security_struct *isec = inode->i_security; + struct task_security_struct *tsec = current->security; + struct av_decision avd; + + if (!S_ISREG(inode->i_mode)) + return; + + rc = avc_has_perm_noaudit(tsec->sid, isec->sid, SECCLASS_INTEGRITY, + INTEGRITY__MEASURE, AVC_STRICT, &avd); + if (rc == 0) + integrity_measure(inode, dentry, file, filename, mask); + return; +} + +/* The OS protects against an executable file, already open for write, + * from being executed in deny_write_access() and an executable file + * already open for execute, from being modified in get_write_access(). + * So we can be certain that what we verify and measure here is actually + * what is being executed. + */ +static int selinux_bprm_check_security(struct linux_binprm *bprm) +{ + struct dentry *dentry = bprm->file->f_dentry; + int rc; + + rc = secondary_ops->bprm_check_security(bprm); + if (rc != 0) + return rc; + + rc = selinux_verify_metadata(dentry); + if (rc == 0) { + rc = selinux_verify_data(dentry, bprm->file); + if (rc == 0) + selinux_measure(dentry->d_inode, dentry, bprm->file, + bprm->filename, MAY_EXEC); + } + return rc; }
@@ -2252,6 +2318,30 @@ static int selinux_inode_follow_link(str
return dentry_has_perm(current, NULL, dentry, FILE__READ); } +static char *get_fname(struct dentry *dentry, struct vfsmount *mnt, + char **buf) +{ + char *fname = NULL; + char *path = NULL; + + path = (char *)__get_free_page(GFP_KERNEL); + if (path) { + fname = d_path(dentry, mnt, path, PAGE_SIZE); + *buf = path; + } + + if (!fname) /* no choice, use short name */ + fname = (!dentry->d_name.name) ? + (char *)dentry->d_iname : (char *)dentry->d_name.name; + return fname; +} + +static void free_fname(char *path) +{ + if (path) + free_page((unsigned long)path); +} + static int selinux_inode_permission(struct inode *inode, int mask, struct nameidata *nd) {
@@ -2266,8 +2356,29 @@ static int selinux_inode_permission(stru
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 (mask & ~MAY_EXEC) { /* measure executables later */ + struct dentry *dentry = NULL; + char *path = NULL; + char *fname = NULL; + + /* The file name is not required, but only a hint. + * When possible, supply a fully qualified path name. + */ + if (nd) { + dentry = nd->dentry; + fname = get_fname(nd->dentry, nd->mnt, &path); + } + + selinux_measure(inode, dentry, NULL, fname, mask); + if (path) + free_fname(path); + } + return rc; } static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
@@ -2588,8 +2699,18 @@ static int selinux_file_mmap(struct file
if (selinux_checkreqprot) prot = reqprot; - return file_map_prot_check(file, prot, - (flags & MAP_TYPE) == MAP_SHARED); + rc = file_map_prot_check(file, prot, (flags & MAP_TYPE) == MAP_SHARED); + if (file && file->f_dentry && rc == 0) { + rc = selinux_verify_metadata(file->f_dentry); + if (rc == 0) { + rc = selinux_verify_data(NULL, file); + if (rc == 0) + selinux_measure(file->f_dentry->d_inode, + file->f_dentry, file, + NULL, MAY_EXEC); + } + } + return rc; } static int selinux_file_mprotect(struct vm_area_struct *vma,
@@ -2631,7 +2752,6 @@ static int selinux_file_mprotect(struct
return rc; } #endif - return file_map_prot_check(vma->vm_file, prot, vma->vm_flags&VM_SHARED); } Index: linux-2.6.23-rc6-mm1/security/selinux/include/av_permissions.h =================================================================== --- linux-2.6.23-rc6-mm1.orig/security/selinux/include/av_permissions.h +++ linux-2.6.23-rc6-mm1/security/selinux/include/av_permissions.h
@@ -824,3 +824,4 @@
#define DCCP_SOCKET__NODE_BIND 0x00400000UL #define DCCP_SOCKET__NAME_CONNECT 0x00800000UL #define MEMPROTECT__MMAP_ZERO 0x00000001UL +#define INTEGRITY__MEASURE 0x00000001UL Index: linux-2.6.23-rc6-mm1/security/selinux/include/av_perm_to_string.h =================================================================== --- linux-2.6.23-rc6-mm1.orig/security/selinux/include/av_perm_to_string.h +++ linux-2.6.23-rc6-mm1/security/selinux/include/av_perm_to_string.h
@@ -159,3 +159,4 @@
S_(SECCLASS_DCCP_SOCKET, DCCP_SOCKET__NODE_BIND, "node_bind") S_(SECCLASS_DCCP_SOCKET, DCCP_SOCKET__NAME_CONNECT, "name_connect") S_(SECCLASS_MEMPROTECT, MEMPROTECT__MMAP_ZERO, "mmap_zero") + S_(SECCLASS_INTEGRITY, INTEGRITY__MEASURE, "measure") Index: linux-2.6.23-rc6-mm1/security/selinux/include/flask.h =================================================================== --- linux-2.6.23-rc6-mm1.orig/security/selinux/include/flask.h +++ linux-2.6.23-rc6-mm1/security/selinux/include/flask.h
@@ -50,6 +50,7 @@
#define SECCLASS_KEY 58 #define SECCLASS_DCCP_SOCKET 60 #define SECCLASS_MEMPROTECT 61 +#define SECCLASS_INTEGRITY 62 /* * Security identifier indices for initial entities Index: linux-2.6.23-rc6-mm1/security/selinux/include/class_to_string.h =================================================================== --- linux-2.6.23-rc6-mm1.orig/security/selinux/include/class_to_string.h +++ linux-2.6.23-rc6-mm1/security/selinux/include/class_to_string.h
@@ -64,3 +64,4 @@
S_(NULL) S_("dccp_socket") S_("memprotect") + S_("integrity") -- 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.