* [RFC][PATCH 4/5]integrity: Linux Integrity Module(LIM)
@ 2008-05-23 15:05 Mimi Zohar
2008-05-23 23:30 ` Randy Dunlap
2008-05-28 7:46 ` Andrew Morton
0 siblings, 2 replies; 9+ messages in thread
From: Mimi Zohar @ 2008-05-23 15:05 UTC (permalink / raw)
To: linux-kernel
Cc: safford, serue, sailer, zohar, Stephen Smalley, CaseySchaufler
This is a request for comments for a redesign of the integrity patches.
The new version addresses a number of issues, including
- generalizing the measurement API beyond just inode measurements.
- separation of the measurement into distinct collection, appraisal,
and commitment phases, for greater flexibility.
- redesigning the interactions with LSM modules (Selinux and Smack)
to be acceptable to those groups.
Extended Verification Module(EVM) and the Integrity Measurement
Architecture(IMA) were originally implemented as an LSM module. Based
on discussions on the LSM mailing list, a decision was made that the
LSM hooks should only be used to enforce mandatory access control
decisions and a new set of hooks should be defined specifically for
integrity.
EVM/IMA was limited to verifying and measuring a file's (i.e. an inode)
integrity and the metadata associated with it. Current research is
looking into other types of integrity measurements. (i.e. "Linux kernel
integrity measurement using contextual inspection", by Peter A. Loscocco,
Perry W. Wilson, J. Aaron Pendergrass, C. Durward McDonell,
http://doi.acm.org/10.1145/1314354.1314362) As a result, a requirement
of the new integrity framework is support for different types of integrity
measurements.
Our work has shown that requests for integrity verification/measurement
needs to be based on knowledge of the filesystem, requiring the system
to either be labeled with integrity data or depend on the existent LSM
security labels. The previous set of integrity patches modified the LSM
modules to be integrity context aware, meaning that the LSM modules made
integrity data/metadata verification and measurement API calls based on
an understanding of the LSM security labels. Both of the LSM maintainers
felt that the changes were too intrusive and that integrity enforcement
should be made by the integrity provider, not the LSM module.
To address these concerns, Stephen Smalley suggested using the
security_audit_rule_match(), renamed to security_filter_rule_match(), to
define LSM specific integrity measurement policy rules, in lieu of
modifying the LSM modules. In the current set of patches, the integrity
API calls can be made either by the integrity provider (i.e. IMA), based
on an LSM specific integrity policy, or by an integrity context aware LSM
module.
This patch provides an integrity framework(api and hooks), placement of
the integrity hooks in the appropriate places in the fs directory, and a
dummy provider for an integrity service. Collecting, appraising, and
storing of inode and other types of integrity data is supported. Multiple
integrity templates, which implement the integrity API, may register
themselves. For now, only a single integrity provider can register itself
for the integrity hooks. (Support for multiple providers registering
themselves for the integrity hooks would require some form of stacking.)
The ten integrity hooks are:
inode_setxattr, inode_post_setxattr,
inode_alloc_integrity, inode_free_integrity, inode_init_integrity,
file_free_integrity, d_instantiate,
bprm_check_integrity, file_mmap, inode_permission
The five integrity API calls provided are:
integrity_must_measure, integrity_collect_measurement,
integrity_appraise_measurement, integrity_store_measurement,
and integrity_display_template.
The type of integrity data being collected, appraised, stored, or
displayed is template dependent.
(Details on the calls and their exact arguments are in linux/integrity.h,
included in the patch.)
Signed-off-by: Mimi Zohar <zohar@us.ibm.com>
---
Index: linux-2.6.26-rc3-git2/include/linux/integrity.h
===================================================================
--- /dev/null
+++ linux-2.6.26-rc3-git2/include/linux/integrity.h
@@ -0,0 +1,261 @@
+/*
+ * integrity.h
+ *
+ * Copyright (C) 2005,2006,2007,2008 IBM Corporation
+ * Author: Mimi Zohar <zohar@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2 of the License.
+ */
+
+#ifndef _LINUX_INTEGRITY_H
+#define _LINUX_INTEGRITY_H
+
+#include <linux/fs.h>
+#include <linux/audit.h>
+
+#ifdef CONFIG_INTEGRITY
+void integrity_audit_msg(int audit_msgno, struct inode *inode,
+ const unsigned char *fname, char *op,
+ char *cause, int result);
+
+enum lim_hooks {INODE_PERMISSION = 1, FILE_MMAP, BPRM_CHECK };
+extern int integrity_measure_policy(struct inode *inode, enum lim_hooks func,
+ int mask);
+extern int integrity_measure_rule_add(char *, char *, char *, char *);
+extern void integrity_measure_policy_init(void);
+extern void integrity_measure_policy_complete(void);
+
+/*
+ * Integrity API calls:
+ *
+ * @collect_measurement:
+ * Collect template specific measurement data.
+ * @data contains template specific data used for collecting the
+ * measurement.
+ * Return 0 if operation was successful.
+ *
+ * @appraise_measurement:
+ * Appraise the integrity of the template specific measurement data.
+ * @data contains template specific data used for appraising the
+ * measurement.
+ * Return 0 if operation was successful.
+ *
+ * @store_measurement:
+ * Store the template specific data.
+ * @data contains template specific data used for storing the
+ * measurement.
+ *
+ * @must_measure:
+ * Measurement decision based on an integrity policy.
+ * @data contains template specific data used for making policy
+ * decision.
+ * Return 0 if operation was successful.
+ *
+ * @display_template:
+ * Display template specific data.
+ *
+ */
+
+enum integrity_show_type { INTEGRITY_SHOW_BINARY, INTEGRITY_SHOW_ASCII};
+
+struct template_operations {
+ int (*collect_measurement)(void *);
+ int (*appraise_measurement)(void *);
+ void (*store_measurement)(void *);
+ int (*must_measure)(void *);
+ void (*display_template)(struct seq_file *m, void *,
+ enum integrity_show_type);
+};
+extern int register_template(char *template_name,
+ struct template_operations *ops);
+extern int unregister_template(char *template_name);
+extern int integrity_find_template(char *, struct template_operations **ops);
+
+/*
+ * Integrity hooks:
+ *
+ * @bprm_check_integrity:
+ * This hook mediates the point when a search for a binary handler will
+ * begin. At this point, the OS protects against an executable file,
+ * already open for write, from being executed; and an executable file
+ * already open for execute, from being modified. So we can be certain
+ * that any measurements(collect, appraise, store) done here are of
+ * the file being executed.
+ * @bprm contains the linux_binprm structure.
+ * Return 0 if the hook is successful and permission is granted.
+ *
+ * @inode_setxattr:
+ * Check permission before permitting an integrity extended attribute
+ * to be set.
+ * @value identified by @name for @dentry.
+ *
+ * @inode_post_setxattr:
+ * Update inode integrity xattr after successful setxattr operation.
+ * identified by @name for @dentry.
+ *
+ * @inode_alloc_integrity:
+ * Allocate and attach an integrity structure to @inode->i_integrity. The
+ * i_integrity field is initialized to NULL when the inode structure is
+ * allocated.
+ * @inode contains the inode structure.
+ * Return 0 if operation was successful.
+ *
+ * @inode_free_integrity:
+ * @inode contains the inode structure.
+ * Deallocate the inode integrity structure and set @inode->i_integrity to
+ * NULL.
+ *
+ * @inode_init_integrity:
+ * Create inode integrity xattr for a new inode based on the new security
+ * xattr information.
+ * @inode contains the inode structure of the newly created inode.
+ * @dir contains the inode structure of the parent directory.
+ * @name contains the security xattr name suffix.
+ * @value contains the security attribute value.
+ * @len contains the length of the security attribute value.
+ *
+ * @inode_permission:
+ * This hook is called by the existing Linux permission function, when
+ * a file is opened (as well as many other operations). At this point,
+ * measurements of files open for read(collect, appraise, store) can
+ * be made.
+ * @inode contains the inode structure to check.
+ * @mask contains the permission mask.
+ * @nd contains the nameidata (may be NULL).
+ *
+ * @file_free_integrity:
+ * Update the integrity xattr value as necessary.
+ * *file contains the file structure being closed.
+ *
+ * @file_mmap :
+ * Measurement(collect, appraise, store) of files mmaped for EXEC,
+ * could be measured at this point.
+ * @file contains the file structure for file to map (may be NULL).
+ * @reqprot contains the protection requested by the application.
+ * @prot contains the protection that will be applied by the kernel.
+ * @flags contains the operational flags.
+ * Return 0 if permission is granted.
+ *
+ * @d_instantiate:
+ * Initialize the integrity structure of an inode for a dentry.
+ * @dentry to complete.
+ * @inode to attach to this dentry.
+ *
+ */
+
+struct integrity_operations {
+ int (*bprm_check_integrity) (struct linux_binprm *bprm);
+ int (*inode_setxattr) (struct dentry *dentry, const char *name,
+ const void *value, size_t size, int flags);
+ void (*inode_post_setxattr) (struct dentry *dentry, const char *name);
+ int (*inode_alloc_integrity) (struct inode *inode);
+ void (*inode_free_integrity) (struct inode *inode);
+ void (*inode_init_integrity) (struct inode *inode, struct inode *dir,
+ char **name, void **value, size_t *len);
+ int (*inode_permission) (struct inode *inode, int mask,
+ struct nameidata *nd);
+ void (*file_free_integrity) (struct file *file);
+ int (*file_mmap) (struct file *file,
+ unsigned long reqprot, unsigned long prot,
+ unsigned long flags, unsigned long addr,
+ unsigned long addr_only);
+ void (*d_instantiate) (struct dentry *dentry, struct inode *inode);
+};
+extern int register_integrity(struct integrity_operations *ops);
+extern int unregister_integrity(struct integrity_operations *ops);
+
+/* global variables */
+extern struct integrity_operations *integrity_ops;
+
+
+int integrity_collect_measurement(char *template_name, void *data);
+int integrity_appraise_measurement(char *template_name, void *data);
+int integrity_must_measure(char *template_name, void *data);
+void integrity_store_measurement(char *template_name, void *data);
+
+int integrity_bprm_check(struct linux_binprm *bprm);
+int integrity_inode_setxattr(struct dentry *dentry, const char *name,
+ const void *value, size_t size, int flags);
+void integrity_inode_post_setxattr(struct dentry *dentry, const char *name);
+int integrity_inode_alloc(struct inode *inode);
+void integrity_inode_free(struct inode *inode);
+void integrity_inode_init_integrity(struct inode *inode, struct inode *dir,
+ char **name, void **value, size_t *len);
+int integrity_inode_permission(struct inode *inode, int mask,
+ struct nameidata *nd);
+void integrity_file_free(struct file *file);
+int integrity_file_mmap(struct file *file,
+ unsigned long reqprot, unsigned long prot,
+ unsigned long flags, unsigned long addr,
+ unsigned long addr_only);
+void integrity_d_instantiate(struct dentry *dentry, struct inode *inode);
+
+#else
+
+static inline int integrity_bprm_check(struct linux_binprm *bprm)
+{
+ return 0;
+}
+
+static inline int integrity_inode_setxattr(struct dentry *dentry,
+ const char *name, const void *value,
+ size_t size, int flags)
+{
+ return 0;
+}
+
+static inline void integrity_inode_post_setxattr(struct dentry *dentry,
+ const char *name)
+{ }
+
+static inline int integrity_inode_alloc(struct inode *inode)
+{
+ return 0;
+}
+
+static inline void integrity_inode_free(struct inode *inode)
+{ }
+
+static inline int integrity_inode_init_integrity(struct inode *inode,
+ struct inode *dir,
+ char **name,
+ void **value,
+ size_t *len)
+{
+ return -EOPNOTSUPP;
+}
+
+static inline int integrity_inode_permission(struct inode *inode, int mask,
+ struct nameidata *nd)
+{
+ return 0;
+}
+
+static inline int integrity_file_permission(struct file *file, int mask)
+{
+ return 0;
+}
+
+static inline void integrity_file_free(struct file *file)
+{
+ return;
+}
+
+static inline int integrity_file_mmap(struct file *file,
+ unsigned long reqprot, unsigned long prot,
+ unsigned long flags, unsigned long addr,
+ unsigned long addr_only)
+{
+ return 0;
+}
+
+static inline void integrity_d_instantiate(struct dentry *dentry,
+ struct inode *inode)
+{
+ return;
+}
+
+#endif
+#endif
Index: linux-2.6.26-rc3-git2/security/integrity/integrity.c
===================================================================
--- /dev/null
+++ linux-2.6.26-rc3-git2/security/integrity/integrity.c
@@ -0,0 +1,259 @@
+/*
+ * Copyright (C) 2006,2007,2008 IBM Corporation
+ * Author: Mimi Zohar <zohar@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2 of the License.
+ *
+ * File: integrity.c
+ * register integrity subsystem
+ * register integrity template
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/integrity.h>
+#include "integrity_dummy.h"
+
+struct integrity_operations *integrity_ops = &dummy_integrity_ops;
+EXPORT_SYMBOL(integrity_ops);
+
+#define TEMPLATE_NAME_LEN_MAX 12
+struct template_list_entry {
+ struct list_head template;
+ char template_name[TEMPLATE_NAME_LEN_MAX + 1];
+ struct template_operations *template_ops;
+};
+static int template_initialized;
+static struct list_head integrity_templates;
+static DEFINE_MUTEX(integrity_templates_mutex);
+
+/**
+ * register_integrity - registers an integrity framework with the kernel
+ * @ops: a pointer to the struct security_options that is to be registered
+ *
+ * Perhaps in the future integrity module stacking will be necessary, but
+ * for the time being, this function permits only one integrity module to
+ * register itself with the kernel integrity subsystem.
+ */
+int register_integrity(struct integrity_operations *ops)
+{
+ if (integrity_ops != &dummy_integrity_ops)
+ return -EAGAIN;
+ integrity_ops = ops;
+ integrity_fixup_ops(integrity_ops);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(register_integrity);
+
+int unregister_integrity(struct integrity_operations *ops)
+{
+ if (ops != integrity_ops)
+ return -EINVAL;
+
+ integrity_ops = &dummy_integrity_ops;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(unregister_integrity);
+
+/**
+ * register_template
+ * @template_name: a pointer to a string containing the template name.
+ * @template_ops: a pointer to the template functions
+ *
+ * Register a set of functions to collect, appraise, store, and display
+ * a template measurement, and a means to decide whether to do them.
+ * Unlike integrity modules, any number of templates may be registered.
+ */
+int register_template(char *template_name,
+ struct template_operations *template_ops)
+{
+ int template_len;
+ struct template_list_entry *entry;
+
+ if (!template_initialized++) {
+ INIT_LIST_HEAD(&integrity_templates);
+ mutex_init(&integrity_templates_mutex);
+ }
+
+ entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
+ INIT_LIST_HEAD(&entry->template);
+
+ template_len = strlen(template_name);
+ if (template_len > TEMPLATE_NAME_LEN_MAX)
+ template_len = TEMPLATE_NAME_LEN_MAX;
+ memcpy(entry->template_name, template_name, template_len);
+ entry->template_name[template_len] = '\0';
+ entry->template_ops = template_ops;
+
+ mutex_lock(&integrity_templates_mutex);
+ list_add_rcu(&entry->template, &integrity_templates);
+ mutex_unlock(&integrity_templates_mutex);
+ synchronize_rcu();
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(register_template);
+
+/**
+ * unregister_template
+ * @template_name: a pointer to a string containing the template name.
+ *
+ * Unregister the template functions
+ */
+int unregister_template(char *template_name)
+{
+ struct template_list_entry *entry;
+
+ mutex_lock(&integrity_templates_mutex);
+ list_for_each_entry(entry, &integrity_templates, template) {
+ if (strncmp(entry->template_name, template_name,
+ strlen(entry->template_name)) == 0) {
+ list_del_rcu(&entry->template);
+ mutex_unlock(&integrity_templates_mutex);
+ synchronize_rcu();
+ kfree(entry);
+ return 0;
+ }
+ }
+ mutex_unlock(&integrity_templates_mutex);
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(unregister_template);
+
+/**
+ * integrity_find_template
+ * @template_name: a pointer to a string containing the template name.
+ * @template_ops: a pointer to the template functions
+ *
+ * Find the template functions based on the template name.
+ */
+int integrity_find_template(char *template_name,
+ struct template_operations **template_ops)
+{
+ struct template_list_entry *entry;
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(entry, &integrity_templates, template) {
+ if (strncmp(entry->template_name, template_name,
+ strlen(entry->template_name)) == 0) {
+ *template_ops = entry->template_ops;
+ rcu_read_unlock();
+ return 0;
+ }
+ }
+ rcu_read_unlock();
+ return 1;
+}
+EXPORT_SYMBOL_GPL(integrity_find_template);
+
+/* Integrity template API */
+int integrity_collect_measurement(char *template_name, void *data)
+{
+ struct template_operations *template_ops;
+
+ if (integrity_find_template(template_name, &template_ops) == 0)
+ template_ops->collect_measurement(data);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(integrity_collect_measurement);
+
+int integrity_appraise_measurement(char *template_name, void *data)
+{
+ struct template_operations *template_ops;
+
+ if (integrity_find_template(template_name, &template_ops) == 0)
+ return template_ops->appraise_measurement(data);
+ return 1;
+}
+EXPORT_SYMBOL_GPL(integrity_appraise_measurement);
+
+void integrity_store_measurement(char *template_name, void *data)
+{
+ struct template_operations *template_ops;
+
+ if (integrity_find_template(template_name, &template_ops) == 0)
+ template_ops->store_measurement(data);
+ return;
+}
+EXPORT_SYMBOL_GPL(integrity_store_measurement);
+
+int integrity_must_measure(char *template_name, void *data)
+{
+ struct template_operations *template_ops;
+
+ if (integrity_find_template(template_name, &template_ops) == 0)
+ return template_ops->must_measure(data);
+ return 1;
+}
+EXPORT_SYMBOL_GPL(integrity_must_measure);
+
+/* Integrity Hooks */
+int integrity_bprm_check(struct linux_binprm *bprm)
+{
+ return integrity_ops->bprm_check_integrity(bprm);
+}
+
+int integrity_inode_setxattr(struct dentry *dentry, const char *name,
+ const void *value, size_t size, int flags)
+{
+ if (unlikely(IS_PRIVATE(dentry->d_inode)))
+ return 0;
+ return integrity_ops->inode_setxattr(dentry, name, value, size, flags);
+}
+
+void integrity_inode_post_setxattr(struct dentry *dentry, const char *name)
+{
+ if (unlikely(IS_PRIVATE(dentry->d_inode)))
+ return;
+ integrity_ops->inode_post_setxattr(dentry, name);
+}
+
+int integrity_inode_alloc(struct inode *inode)
+{
+ return integrity_ops->inode_alloc_integrity(inode);
+}
+
+void integrity_inode_free(struct inode *inode)
+{
+ integrity_ops->inode_free_integrity(inode);
+}
+
+int integrity_inode_permission(struct inode *inode, int mask,
+ struct nameidata *nd)
+{
+ return integrity_ops->inode_permission(inode, mask, nd);
+}
+
+void integrity_inode_init_integrity(struct inode *inode, struct inode *dir,
+ char **name, void **value, size_t *len)
+{
+ if (unlikely(IS_PRIVATE(inode)))
+ return;
+ integrity_ops->inode_init_integrity(inode, dir, name, value, len);
+ return;
+}
+EXPORT_SYMBOL(integrity_inode_init_integrity);
+
+void integrity_file_free(struct file *file)
+{
+ integrity_ops->file_free_integrity(file);
+}
+
+int integrity_file_mmap(struct file *file, unsigned long reqprot,
+ unsigned long prot, unsigned long flags,
+ unsigned long addr, unsigned long addr_only)
+{
+ return integrity_ops->file_mmap(file, reqprot, prot, flags, addr,
+ addr_only);
+}
+
+void integrity_d_instantiate(struct dentry *dentry, struct inode *inode)
+{
+ if (unlikely(inode && IS_PRIVATE(inode)))
+ return;
+ integrity_ops->d_instantiate(dentry, inode);
+}
Index: linux-2.6.26-rc3-git2/security/integrity/integrity_dummy.c
===================================================================
--- /dev/null
+++ linux-2.6.26-rc3-git2/security/integrity/integrity_dummy.c
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2005,2006,2007,2008 IBM Corporation
+ * Author: Mimi Zohar <zohar@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2 of the License.
+ *
+ * File: integrity_dummy.c
+ * Instantiate integrity subsystem
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/capability.h>
+#include <linux/integrity.h>
+#include <linux/xattr.h>
+#include "integrity_dummy.h"
+
+/* Integrity ops */
+static int dummy_bprm_check_integrity(struct linux_binprm *bprm)
+{
+ return 0;
+}
+
+static int dummy_inode_alloc_integrity(struct inode *inode)
+{
+ return 0;
+}
+
+static void dummy_inode_free_integrity(struct inode *inode)
+{
+ return;
+}
+
+static void dummy_inode_init_integrity(struct inode *inode, struct inode *dir,
+ char **name, void **value, size_t *len)
+{
+ return;
+}
+
+static void dummy_file_free_integrity(struct file *file)
+{
+ return;
+}
+
+static int dummy_file_mmap(struct file *file,
+ unsigned long reqprot, unsigned long prot,
+ unsigned long flags, unsigned long addr,
+ unsigned long addr_only)
+{
+ return 0;
+}
+
+static int dummy_inode_setxattr(struct dentry *dentry, const char *name,
+ const void *value, size_t size, int flags)
+{
+ return 0;
+}
+
+static void dummy_inode_post_setxattr(struct dentry *dentry, const char *name)
+{
+}
+
+static int dummy_inode_permission(struct inode *inode, int mask,
+ struct nameidata *nd)
+{
+ return 0;
+}
+
+static void dummy_d_instantiate(struct dentry *dentry, struct inode *inode)
+{
+ return;
+}
+
+struct integrity_operations dummy_integrity_ops = {
+ .bprm_check_integrity = dummy_bprm_check_integrity,
+ .inode_setxattr = dummy_inode_setxattr,
+ .inode_post_setxattr = dummy_inode_post_setxattr,
+ .inode_alloc_integrity = dummy_inode_alloc_integrity,
+ .inode_init_integrity = dummy_inode_init_integrity,
+ .inode_free_integrity = dummy_inode_free_integrity,
+ .inode_permission = dummy_inode_permission,
+ .file_free_integrity = dummy_file_free_integrity,
+ .file_mmap = dummy_file_mmap,
+ .d_instantiate = dummy_d_instantiate
+};
+
+#define set_to_dummy_if_null(ops, function) \
+ do { \
+ if (!ops->function) { \
+ ops->function = dummy_##function; \
+ printk(KERN_INFO "Had to override the " #function \
+ " integrity operation with the dummy one.\n");\
+ } \
+ } while (0)
+
+void integrity_fixup_ops(struct integrity_operations *ops)
+{
+ set_to_dummy_if_null(ops, inode_setxattr);
+ set_to_dummy_if_null(ops, inode_post_setxattr);
+ set_to_dummy_if_null(ops, inode_alloc_integrity);
+ set_to_dummy_if_null(ops, inode_init_integrity);
+ set_to_dummy_if_null(ops, inode_free_integrity);
+ set_to_dummy_if_null(ops, file_free_integrity);
+ set_to_dummy_if_null(ops, d_instantiate);
+
+ set_to_dummy_if_null(ops, bprm_check_integrity);
+ set_to_dummy_if_null(ops, file_mmap);
+ set_to_dummy_if_null(ops, inode_permission);
+}
Index: linux-2.6.26-rc3-git2/security/integrity/integrity_dummy.h
===================================================================
--- /dev/null
+++ linux-2.6.26-rc3-git2/security/integrity/integrity_dummy.h
@@ -0,0 +1,13 @@
+/*
+ * integrity_dummy.h
+ *
+ * Copyright (C) 2005,2006,2007 IBM Corporation
+ * Author: Mimi Zohar <zohar@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2 of the License.
+ */
+
+extern struct integrity_operations dummy_integrity_ops;
+extern void integrity_fixup_ops(struct integrity_operations *ops);
Index: linux-2.6.26-rc3-git2/fs/dcache.c
===================================================================
--- linux-2.6.26-rc3-git2.orig/fs/dcache.c
+++ linux-2.6.26-rc3-git2/fs/dcache.c
@@ -28,6 +28,7 @@
#include <linux/file.h>
#include <asm/uaccess.h>
#include <linux/security.h>
+#include <linux/integrity.h>
#include <linux/seqlock.h>
#include <linux/swap.h>
#include <linux/bootmem.h>
@@ -972,6 +973,7 @@ void d_instantiate(struct dentry *entry,
entry->d_inode = inode;
fsnotify_d_instantiate(entry, inode);
spin_unlock(&dcache_lock);
+ integrity_d_instantiate(entry, inode);
security_d_instantiate(entry, inode);
}
@@ -1036,6 +1038,7 @@ struct dentry *d_instantiate_unique(stru
spin_unlock(&dcache_lock);
if (!result) {
+ integrity_d_instantiate(entry, inode);
security_d_instantiate(entry, inode);
return NULL;
}
@@ -1173,6 +1176,7 @@ struct dentry *d_splice_alias(struct ino
BUG_ON(!(new->d_flags & DCACHE_DISCONNECTED));
fsnotify_d_instantiate(new, inode);
spin_unlock(&dcache_lock);
+ integrity_d_instantiate(new, inode);
security_d_instantiate(new, inode);
d_rehash(dentry);
d_move(new, dentry);
@@ -1183,6 +1187,7 @@ struct dentry *d_splice_alias(struct ino
dentry->d_inode = inode;
fsnotify_d_instantiate(dentry, inode);
spin_unlock(&dcache_lock);
+ integrity_d_instantiate(dentry, inode);
security_d_instantiate(dentry, inode);
d_rehash(dentry);
}
@@ -1733,6 +1738,7 @@ found:
spin_unlock(&dcache_lock);
out_nolock:
if (actual == dentry) {
+ integrity_d_instantiate(dentry, inode);
security_d_instantiate(dentry, inode);
return NULL;
}
Index: linux-2.6.26-rc3-git2/fs/ext3/xattr_security.c
===================================================================
--- linux-2.6.26-rc3-git2.orig/fs/ext3/xattr_security.c
+++ linux-2.6.26-rc3-git2/fs/ext3/xattr_security.c
@@ -9,6 +9,7 @@
#include <linux/ext3_jbd.h>
#include <linux/ext3_fs.h>
#include <linux/security.h>
+#include <linux/integrity.h>
#include "xattr.h"
static size_t
@@ -57,12 +58,19 @@ ext3_init_security(handle_t *handle, str
err = security_inode_init_security(inode, dir, &name, &value, &len);
if (err) {
+ /* Even if creation of the security xattr fails, must
+ * indicate this is a new inode. */
+ integrity_inode_init_integrity(inode, dir, NULL, NULL, NULL);
if (err == -EOPNOTSUPP)
return 0;
return err;
}
err = ext3_xattr_set_handle(handle, inode, EXT3_XATTR_INDEX_SECURITY,
name, value, len, 0);
+
+ integrity_inode_init_integrity(inode, dir, &name, &value, &len);
+ err = ext3_xattr_set_handle(handle, inode, EXT3_XATTR_INDEX_SECURITY,
+ name, value, len, 0);
kfree(name);
kfree(value);
return err;
Index: linux-2.6.26-rc3-git2/fs/file_table.c
===================================================================
--- linux-2.6.26-rc3-git2.orig/fs/file_table.c
+++ linux-2.6.26-rc3-git2/fs/file_table.c
@@ -13,6 +13,7 @@
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/security.h>
+#include <linux/integrity.h>
#include <linux/eventpoll.h>
#include <linux/rcupdate.h>
#include <linux/mount.h>
@@ -272,6 +273,7 @@ void __fput(struct file *file)
if (file->f_op && file->f_op->release)
file->f_op->release(inode, file);
security_file_free(file);
+ integrity_file_free(file);
if (unlikely(S_ISCHR(inode->i_mode) && inode->i_cdev != NULL))
cdev_put(inode->i_cdev);
fops_put(file->f_op);
@@ -343,6 +345,7 @@ void put_filp(struct file *file)
{
if (atomic_dec_and_test(&file->f_count)) {
security_file_free(file);
+ integrity_file_free(file);
file_kill(file);
file_free(file);
}
Index: linux-2.6.26-rc3-git2/fs/inode.c
===================================================================
--- linux-2.6.26-rc3-git2.orig/fs/inode.c
+++ linux-2.6.26-rc3-git2/fs/inode.c
@@ -17,6 +17,7 @@
#include <linux/hash.h>
#include <linux/swap.h>
#include <linux/security.h>
+#include <linux/integrity.h>
#include <linux/pagemap.h>
#include <linux/cdev.h>
#include <linux/bootmem.h>
@@ -160,6 +161,14 @@ static struct inode *alloc_inode(struct
init_rwsem(&inode->i_alloc_sem);
lockdep_set_class(&inode->i_alloc_sem, &sb->s_type->i_alloc_sem_key);
+ if (integrity_inode_alloc(inode)) {
+ if (inode->i_sb->s_op->destroy_inode)
+ inode->i_sb->s_op->destroy_inode(inode);
+ else
+ kmem_cache_free(inode_cachep, (inode));
+ return NULL;
+ }
+
mapping->a_ops = &empty_aops;
mapping->host = inode;
mapping->flags = 0;
@@ -190,6 +199,7 @@ void destroy_inode(struct inode *inode)
{
BUG_ON(inode_has_buffers(inode));
security_inode_free(inode);
+ integrity_inode_free(inode);
if (inode->i_sb->s_op->destroy_inode)
inode->i_sb->s_op->destroy_inode(inode);
else
Index: linux-2.6.26-rc3-git2/fs/xattr.c
===================================================================
--- linux-2.6.26-rc3-git2.orig/fs/xattr.c
+++ linux-2.6.26-rc3-git2/fs/xattr.c
@@ -14,6 +14,7 @@
#include <linux/mount.h>
#include <linux/namei.h>
#include <linux/security.h>
+#include <linux/integrity.h>
#include <linux/syscalls.h>
#include <linux/module.h>
#include <linux/fsnotify.h>
@@ -81,11 +82,17 @@ vfs_setxattr(struct dentry *dentry, cons
error = security_inode_setxattr(dentry, name, value, size, flags);
if (error)
goto out;
+
+ error = integrity_inode_setxattr(dentry, name, value, size, flags);
+ if (error)
+ goto out;
+
error = -EOPNOTSUPP;
if (inode->i_op->setxattr) {
error = inode->i_op->setxattr(dentry, name, value, size, flags);
if (!error) {
fsnotify_xattr(dentry);
+ integrity_inode_post_setxattr(dentry, name);
security_inode_post_setxattr(dentry, name, value,
size, flags);
}
@@ -205,6 +212,8 @@ vfs_removexattr(struct dentry *dentry, c
mutex_lock(&inode->i_mutex);
error = inode->i_op->removexattr(dentry, name);
+ if (!error)
+ integrity_inode_post_setxattr(dentry, name);
mutex_unlock(&inode->i_mutex);
if (!error)
Index: linux-2.6.26-rc3-git2/include/linux/fs.h
===================================================================
--- linux-2.6.26-rc3-git2.orig/include/linux/fs.h
+++ linux-2.6.26-rc3-git2/include/linux/fs.h
@@ -653,6 +653,9 @@ struct inode {
#ifdef CONFIG_SECURITY
void *i_security;
#endif
+#ifdef CONFIG_INTEGRITY
+ void *i_integrity;
+#endif
void *i_private; /* fs or device private pointer */
};
Index: linux-2.6.26-rc3-git2/include/linux/audit.h
===================================================================
--- linux-2.6.26-rc3-git2.orig/include/linux/audit.h
+++ linux-2.6.26-rc3-git2/include/linux/audit.h
@@ -123,6 +123,11 @@
#define AUDIT_LAST_KERN_ANOM_MSG 1799
#define AUDIT_ANOM_PROMISCUOUS 1700 /* Device changed promiscuous mode */
#define AUDIT_ANOM_ABEND 1701 /* Process ended abnormally */
+#define AUDIT_INTEGRITY_DATA 1800 /* Data integrity verification */
+#define AUDIT_INTEGRITY_METADATA 1801 /* Metadata integrity verification */
+#define AUDIT_INTEGRITY_STATUS 1802 /* Integrity enable status */
+#define AUDIT_INTEGRITY_HASH 1803 /* Integrity HASH type */
+#define AUDIT_INTEGRITY_PCR 1804 /* PCR invalidation msgs */
#define AUDIT_KERNEL 2000 /* Asynchronous audit record. NOT A REQUEST. */
@@ -441,6 +446,8 @@ extern int audit_set_loginuid(struct ta
#define audit_get_loginuid(t) ((t)->loginuid)
#define audit_get_sessionid(t) ((t)->sessionid)
extern void audit_log_task_context(struct audit_buffer *ab);
+extern void audit_log_inode_context(struct audit_buffer *ab,
+ struct inode *inode);
extern int __audit_ipc_obj(struct kern_ipc_perm *ipcp);
extern int __audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode);
extern int audit_bprm(struct linux_binprm *bprm);
@@ -521,6 +528,7 @@ extern int audit_signals;
#define audit_get_loginuid(t) (-1)
#define audit_get_sessionid(t) (-1)
#define audit_log_task_context(b) do { ; } while (0)
+#define audit_log_inode_context(b, a) do { ; } while (0)
#define audit_ipc_obj(i) ({ 0; })
#define audit_ipc_set_perm(q,u,g,m) ({ 0; })
#define audit_bprm(p) ({ 0; })
Index: linux-2.6.26-rc3-git2/security/integrity/integrity_audit.c
===================================================================
--- /dev/null
+++ linux-2.6.26-rc3-git2/security/integrity/integrity_audit.c
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2008 IBM Corporation
+ * Author: Mimi Zohar <zohar@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2 of the License.
+ *
+ * File: integrity_audit.c
+ * Audit calls for the integrity subsystem
+ */
+
+#include <linux/audit.h>
+#include <linux/fs.h>
+#include <linux/integrity.h>
+
+#ifdef CONFIG_INTEGRITY_AUDIT
+static int integrity_audit = 1;
+
+static int __init integrity_audit_setup(char *str)
+{
+ char *op;
+
+ integrity_audit = simple_strtol(str, NULL, 0);
+ op = integrity_audit ? "integrity_audit_enabled" :
+ "integrity_audit_not_enabled";
+ integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, NULL, NULL, op, 0);
+ return 1;
+}
+
+__setup("integrity_audit=", integrity_audit_setup);
+#else
+static int integrity_audit = 1;
+#endif
+
+void integrity_audit_msg(int audit_msgno, struct inode *inode,
+ const unsigned char *fname, char *op,
+ char *cause, int result)
+{
+ struct audit_buffer *ab;
+ if (!integrity_audit && result == 1)
+ return;
+
+ ab = audit_log_start(current->audit_context, GFP_ATOMIC, audit_msgno);
+ audit_log_format(ab, "integrity: pid=%d uid=%u auid=%u",
+ current->pid, current->uid,
+ audit_get_loginuid(current));
+ audit_log_task_context(ab);
+ switch (audit_msgno) {
+ case AUDIT_INTEGRITY_DATA:
+ case AUDIT_INTEGRITY_METADATA:
+ case AUDIT_INTEGRITY_PCR:
+ audit_log_format(ab, " op=%s cause=%s", op, cause);
+ break;
+ case AUDIT_INTEGRITY_HASH:
+ audit_log_format(ab, " op=%s hash=%s", op, cause);
+ break;
+ case AUDIT_INTEGRITY_STATUS:
+ default:
+ audit_log_format(ab, " op=%s", op);
+ }
+ audit_log_format(ab, " comm=");
+ audit_log_untrustedstring(ab, current->comm);
+ if (fname) {
+ audit_log_format(ab, " name=");
+ audit_log_untrustedstring(ab, fname);
+ }
+ if (inode)
+ audit_log_format(ab, " dev=%s ino=%lu",
+ inode->i_sb->s_id, inode->i_ino);
+ audit_log_format(ab, " res=%d", result);
+ audit_log_end(ab);
+}
Index: linux-2.6.26-rc3-git2/Documentation/kernel-parameters.txt
===================================================================
--- linux-2.6.26-rc3-git2.orig/Documentation/kernel-parameters.txt
+++ linux-2.6.26-rc3-git2/Documentation/kernel-parameters.txt
@@ -821,6 +821,11 @@ and is between 256 and 4096 characters.
inport.irq= [HW] Inport (ATI XL and Microsoft) busmouse driver
Format: <irq>
+ integrity_audit= [INTEGRITY]
+ Format: { "0" | "1" }
+ 0 -- disable integrity auditing messages.
+ 1 -- enable integrity auditing messages. (Default)
+
inttest= [IA64]
iommu= [x86]
Index: linux-2.6.26-rc3-git2/security/integrity/Makefile
===================================================================
--- /dev/null
+++ linux-2.6.26-rc3-git2/security/integrity/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for the kernel integrity code
+#
+
+# Object file lists
+obj-$(CONFIG_INTEGRITY) += integrity.o integrity_dummy.o \
+ integrity_audit.o integrity_policy.o
Index: linux-2.6.26-rc3-git2/security/integrity/Kconfig
===================================================================
--- /dev/null
+++ linux-2.6.26-rc3-git2/security/integrity/Kconfig
@@ -0,0 +1,24 @@
+#
+# Integrity configuration
+#
+
+menu "Integrity options"
+
+config INTEGRITY
+ bool "Enable different integrity models"
+ help
+ This allows you to choose different integrity modules to be
+ configured into your kernel.
+
+ If you are unsure how to answer this question, answer N.
+
+config INTEGRITY_AUDIT
+ bool "Integrity audit boot parameter"
+ depends on INTEGRITY
+ default y
+ help
+ This option adds a kernel parameter 'integrity_audit', which
+ allows integrity auditing to be disabled at boot. If this
+ option is selected, integrity auditing can be disabled with
+ 'integrity_audit=0' on the kernel command line.
+endmenu
Index: linux-2.6.26-rc3-git2/security/Kconfig
===================================================================
--- linux-2.6.26-rc3-git2.orig/security/Kconfig
+++ linux-2.6.26-rc3-git2/security/Kconfig
@@ -4,6 +4,8 @@
menu "Security options"
+source security/integrity/Kconfig
+
config KEYS
bool "Enable access key retention support"
help
Index: linux-2.6.26-rc3-git2/fs/exec.c
===================================================================
--- linux-2.6.26-rc3-git2.orig/fs/exec.c
+++ linux-2.6.26-rc3-git2/fs/exec.c
@@ -47,6 +47,7 @@
#include <linux/ptrace.h>
#include <linux/mount.h>
#include <linux/security.h>
+#include <linux/integrity.h>
#include <linux/syscalls.h>
#include <linux/rmap.h>
#include <linux/tsacct_kern.h>
@@ -1192,6 +1193,9 @@ int search_binary_handler(struct linux_b
retval = security_bprm_check(bprm);
if (retval)
return retval;
+ retval = integrity_bprm_check(bprm);
+ if (retval)
+ return retval;
/* kernel module loader fixup */
/* so we don't try to load run modprobe in kernel space. */
Index: linux-2.6.26-rc3-git2/fs/namei.c
===================================================================
--- linux-2.6.26-rc3-git2.orig/fs/namei.c
+++ linux-2.6.26-rc3-git2/fs/namei.c
@@ -24,6 +24,7 @@
#include <linux/fsnotify.h>
#include <linux/personality.h>
#include <linux/security.h>
+#include <linux/integrity.h>
#include <linux/syscalls.h>
#include <linux/mount.h>
#include <linux/audit.h>
@@ -286,7 +287,10 @@ int permission(struct inode *inode, int
if (retval)
return retval;
- return security_inode_permission(inode, mask, nd);
+ retval = security_inode_permission(inode, mask, nd);
+ if (retval)
+ return retval;
+ return integrity_inode_permission(inode, mask, nd);
}
/**
@@ -462,6 +466,7 @@ static struct dentry * cached_lookup(str
static int exec_permission_lite(struct inode *inode,
struct nameidata *nd)
{
+ int retval;
umode_t mode = inode->i_mode;
if (inode->i_op && inode->i_op->permission)
@@ -486,7 +491,10 @@ static int exec_permission_lite(struct i
return -EACCES;
ok:
- return security_inode_permission(inode, MAY_EXEC, nd);
+ retval = security_inode_permission(inode, MAY_EXEC, nd);
+ if (retval)
+ return retval;
+ return integrity_inode_permission(inode, MAY_EXEC, nd);
}
/*
Index: linux-2.6.26-rc3-git2/mm/mmap.c
===================================================================
--- linux-2.6.26-rc3-git2.orig/mm/mmap.c
+++ linux-2.6.26-rc3-git2/mm/mmap.c
@@ -20,6 +20,7 @@
#include <linux/fs.h>
#include <linux/personality.h>
#include <linux/security.h>
+#include <linux/integrity.h>
#include <linux/hugetlb.h>
#include <linux/profile.h>
#include <linux/module.h>
@@ -1036,6 +1037,9 @@ unsigned long do_mmap_pgoff(struct file
error = security_file_mmap(file, reqprot, prot, flags, addr, 0);
if (error)
return error;
+ error = integrity_file_mmap(file, reqprot, prot, flags, addr, 0);
+ if (error)
+ return error;
return mmap_region(file, addr, len, flags, vm_flags, pgoff,
accountable);
Index: linux-2.6.26-rc3-git2/security/integrity/integrity_policy.c
===================================================================
--- /dev/null
+++ linux-2.6.26-rc3-git2/security/integrity/integrity_policy.c
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2008 IBM Corporation
+ * Author: Mimi Zohar <zohar@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2 of the License.
+ *
+ * integrity_policy.c
+ * - initialize default measure policy rules
+ - load a policy ruleset
+ *
+ */
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/audit.h>
+#include <linux/security.h>
+#include <linux/integrity.h>
+
+#define security_filter_rule_init security_audit_rule_init
+#define security_filter_rule_match security_audit_rule_match
+
+struct integrity_measure_rule_entry {
+ struct list_head list;
+ void *lsm_obj_rule;
+ void *lsm_subj_rule;
+ enum lim_hooks func;
+ int mask;
+};
+
+
+static struct integrity_measure_rule_entry default_rules[] = {
+ {{NULL, NULL}, NULL, NULL, FILE_MMAP, MAY_EXEC},
+ {{NULL, NULL}, NULL, NULL, BPRM_CHECK, MAY_EXEC},
+ {{NULL, NULL}, NULL, NULL, INODE_PERMISSION, MAY_READ},
+};
+static struct list_head measure_default_rules;
+static struct list_head measure_policy_rules;
+static struct list_head *integrity_measure;
+
+static DEFINE_MUTEX(integrity_measure_mutex);
+
+/**
+ * integrity_measure_rules - determine whether an inode matches the given rule.
+ * @rule - a pointer to a rule
+ * @inode - a pointer to an inode
+ * @func - LIM hook identifier
+ * @mask - requested action (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC)
+ *
+ * Returns 1 on rule match, 0 on failure.
+ */
+static int integrity_measure_rules(struct integrity_measure_rule_entry *rule,
+ struct inode *inode, enum lim_hooks func,
+ int mask)
+{
+ int result = 1;
+
+ if (result && (rule->func != 0)) {
+ if (rule->func != func)
+ result = 0;
+ }
+ if (result && (rule->mask != 0)) {
+ if (rule->mask != mask)
+ result = 0;
+ }
+ if (result && rule->lsm_subj_rule) {
+ struct task_struct *tsk = current;
+ u32 sid;
+
+ security_task_getsecid(tsk, &sid);
+ result = security_filter_rule_match(sid, AUDIT_SUBJ_USER,
+ AUDIT_EQUAL,
+ rule->lsm_subj_rule, NULL);
+ }
+ if (result && rule->lsm_obj_rule) {
+ u32 osid;
+
+ security_inode_getsecid(inode, &osid);
+ result = security_filter_rule_match(osid, AUDIT_OBJ_USER,
+ AUDIT_EQUAL,
+ rule->lsm_obj_rule, NULL);
+ }
+ return result;
+}
+
+/**
+ * integrity_measure_policy - base measure decision on: subj, obj, LIM hook,
+ * and mask
+ * @inode - pointer to an inode
+ * @func - LIM hook identifier
+ * @mask - requested action (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC)
+ *
+ * Returns 1 on rule match, 0 on failure.
+ */
+int integrity_measure_policy(struct inode *inode, enum lim_hooks func, int mask)
+{
+ struct integrity_measure_rule_entry *entry;
+ int rc = 0;
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(entry, integrity_measure, list) {
+ rc = integrity_measure_rules(entry, inode, func, mask);
+ if (rc) {
+ rcu_read_unlock();
+ return rc;
+ }
+ }
+ rcu_read_unlock();
+ return rc;
+}
+
+/**
+ * integrity_measure_policy_init - initialize the default and policy rules.
+ */
+void integrity_measure_policy_init(void)
+{
+ int i;
+
+ INIT_LIST_HEAD(&measure_default_rules);
+ for (i = 0; i < ARRAY_SIZE(default_rules); i++)
+ list_add(&default_rules[i].list, &measure_default_rules);
+ integrity_measure = &measure_default_rules;
+ mutex_init(&integrity_measure_mutex);
+
+ INIT_LIST_HEAD(&measure_policy_rules);
+}
+
+/**
+ * integrity_measure_policy_complete - wait to replace default_rules with
+ * a complete policy ruleset.
+ */
+void integrity_measure_policy_complete(void)
+{
+ char *op = "policy_update";
+ char *cause = "already exists";
+ int result = 1;
+
+ if (integrity_measure == &measure_default_rules) {
+ integrity_measure = &measure_policy_rules;
+ cause = "complete";
+ result = 0;
+ }
+ integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL,
+ NULL, op, cause, result);
+}
+
+/**
+ * integrity_measure_rule_add - add integrity measure rules
+ * @subj - pointer to an LSM subject value
+ * @obj - pointer to an LSM object value
+ * @func - LIM hook identifier
+ * @mask - requested action (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC)
+ *
+ * Returns 0 on success, an error code on failure.
+ */
+int integrity_measure_rule_add(char *subj, char *obj, char *func, char *mask)
+{
+ struct integrity_measure_rule_entry *entry;
+ int result = 0;
+
+ /* Prevent installed policy from changing */
+ if (integrity_measure != &measure_default_rules) {
+ integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL,
+ NULL, "policy_update", "already exists", 1);
+ return -EACCES;
+ }
+
+ entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
+ INIT_LIST_HEAD(&entry->list);
+ if (!result && subj)
+ result = security_filter_rule_init(AUDIT_SUBJ_USER, AUDIT_EQUAL,
+ subj, &entry->lsm_subj_rule);
+ if (!result && obj)
+ result = security_filter_rule_init(AUDIT_OBJ_USER, AUDIT_EQUAL,
+ obj, &entry->lsm_obj_rule);
+ if (!result && func) {
+ if (strcmp(func, "INODE_PERMISSION") == 0)
+ entry->func = INODE_PERMISSION;
+ else if (strcmp(func, "FILE_MMAP") == 0)
+ entry->func = FILE_MMAP;
+ else if (strcmp(func, "BPRM_CHECK") == 0)
+ entry->func = BPRM_CHECK;
+ else
+ result = -EINVAL;
+ }
+ if (!result && mask) {
+ if (strcmp(mask, "MAY_EXEC") == 0)
+ entry->mask = MAY_EXEC;
+ else if (strcmp(mask, "MAY_WRITE") == 0)
+ entry->mask = MAY_WRITE;
+ else if (strcmp(mask, "MAY_READ") == 0)
+ entry->mask = MAY_READ;
+ else if (strcmp(mask, "MAY_APPEND") == 0)
+ entry->mask = MAY_APPEND;
+ else
+ result = -EINVAL;
+ }
+ if (!result) {
+ mutex_lock(&integrity_measure_mutex);
+ list_add_tail(&entry->list, &measure_policy_rules);
+ mutex_unlock(&integrity_measure_mutex);
+ }
+ return result;
+}
Index: linux-2.6.26-rc3-git2/security/Makefile
===================================================================
--- linux-2.6.26-rc3-git2.orig/security/Makefile
+++ linux-2.6.26-rc3-git2/security/Makefile
@@ -19,3 +19,7 @@ obj-$(CONFIG_SECURITY_SMACK) += commonc
obj-$(CONFIG_SECURITY_CAPABILITIES) += commoncap.o capability.o
obj-$(CONFIG_SECURITY_ROOTPLUG) += commoncap.o root_plug.o
obj-$(CONFIG_CGROUP_DEVICE) += device_cgroup.o
+
+# Object integrity file lists
+subdir-$(CONFIG_INTEGRITY) += integrity
+obj-$(CONFIG_INTEGRITY) += integrity/built-in.o
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [RFC][PATCH 4/5]integrity: Linux Integrity Module(LIM)
2008-05-23 15:05 [RFC][PATCH 4/5]integrity: Linux Integrity Module(LIM) Mimi Zohar
@ 2008-05-23 23:30 ` Randy Dunlap
2008-05-27 14:34 ` Mimi Zohar
2008-05-28 7:46 ` Andrew Morton
1 sibling, 1 reply; 9+ messages in thread
From: Randy Dunlap @ 2008-05-23 23:30 UTC (permalink / raw)
To: Mimi Zohar
Cc: linux-kernel, safford, serue, sailer, zohar, Stephen Smalley,
CaseySchaufler
On Fri, 23 May 2008 11:05:33 -0400 Mimi Zohar wrote:
> ---
> Index: linux-2.6.26-rc3-git2/security/integrity/integrity.c
> ===================================================================
> --- /dev/null
> +++ linux-2.6.26-rc3-git2/security/integrity/integrity.c
> @@ -0,0 +1,259 @@
> +/**
> + * register_template
Needs short function description.
> + * @template_name: a pointer to a string containing the template name.
> + * @template_ops: a pointer to the template functions
> + *
> + * Register a set of functions to collect, appraise, store, and display
> + * a template measurement, and a means to decide whether to do them.
> + * Unlike integrity modules, any number of templates may be registered.
> + */
> +int register_template(char *template_name,
> + struct template_operations *template_ops)
> +{
> + int template_len;
> + struct template_list_entry *entry;
> +
> + if (!template_initialized++) {
> + INIT_LIST_HEAD(&integrity_templates);
> + mutex_init(&integrity_templates_mutex);
> + }
> +
> + entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
> + INIT_LIST_HEAD(&entry->template);
> +
> + template_len = strlen(template_name);
> + if (template_len > TEMPLATE_NAME_LEN_MAX)
> + template_len = TEMPLATE_NAME_LEN_MAX;
> + memcpy(entry->template_name, template_name, template_len);
> + entry->template_name[template_len] = '\0';
> + entry->template_ops = template_ops;
> +
> + mutex_lock(&integrity_templates_mutex);
> + list_add_rcu(&entry->template, &integrity_templates);
> + mutex_unlock(&integrity_templates_mutex);
> + synchronize_rcu();
> +
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(register_template);
> +
> +/**
> + * unregister_template
ditto.
> + * @template_name: a pointer to a string containing the template name.
> + *
> + * Unregister the template functions
> + */
> +int unregister_template(char *template_name)
> +{
> + struct template_list_entry *entry;
> +
> + mutex_lock(&integrity_templates_mutex);
> + list_for_each_entry(entry, &integrity_templates, template) {
> + if (strncmp(entry->template_name, template_name,
> + strlen(entry->template_name)) == 0) {
> + list_del_rcu(&entry->template);
> + mutex_unlock(&integrity_templates_mutex);
> + synchronize_rcu();
> + kfree(entry);
> + return 0;
> + }
> + }
> + mutex_unlock(&integrity_templates_mutex);
> + return -EINVAL;
> +}
> +EXPORT_SYMBOL_GPL(unregister_template);
> +
> +/**
> + * integrity_find_template
ditto.
> + * @template_name: a pointer to a string containing the template name.
> + * @template_ops: a pointer to the template functions
> + *
> + * Find the template functions based on the template name.
> + */
> +int integrity_find_template(char *template_name,
> + struct template_operations **template_ops)
> +{
> + struct template_list_entry *entry;
> +
> + rcu_read_lock();
> + list_for_each_entry_rcu(entry, &integrity_templates, template) {
> + if (strncmp(entry->template_name, template_name,
> + strlen(entry->template_name)) == 0) {
> + *template_ops = entry->template_ops;
> + rcu_read_unlock();
> + return 0;
> + }
> + }
> + rcu_read_unlock();
> + return 1;
> +}
> +EXPORT_SYMBOL_GPL(integrity_find_template);
> +
> +/* Integrity template API */
Please add kernel-doc for exported symbols (like this one and more
below).
> +int integrity_collect_measurement(char *template_name, void *data)
> +{
> + struct template_operations *template_ops;
> +
> + if (integrity_find_template(template_name, &template_ops) == 0)
> + template_ops->collect_measurement(data);
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(integrity_collect_measurement);
> +
> +int integrity_appraise_measurement(char *template_name, void *data)
> +{
> + struct template_operations *template_ops;
> +
> + if (integrity_find_template(template_name, &template_ops) == 0)
> + return template_ops->appraise_measurement(data);
> + return 1;
> +}
> +EXPORT_SYMBOL_GPL(integrity_appraise_measurement);
> +
> +void integrity_store_measurement(char *template_name, void *data)
> +{
> + struct template_operations *template_ops;
> +
> + if (integrity_find_template(template_name, &template_ops) == 0)
> + template_ops->store_measurement(data);
> + return;
> +}
> +EXPORT_SYMBOL_GPL(integrity_store_measurement);
> +
> +int integrity_must_measure(char *template_name, void *data)
> +{
> + struct template_operations *template_ops;
> +
> + if (integrity_find_template(template_name, &template_ops) == 0)
> + return template_ops->must_measure(data);
> + return 1;
> +}
> +EXPORT_SYMBOL_GPL(integrity_must_measure);
> +
> +/* Integrity Hooks */
> +int integrity_bprm_check(struct linux_binprm *bprm)
> +{
> + return integrity_ops->bprm_check_integrity(bprm);
> +}
> +
> +int integrity_inode_setxattr(struct dentry *dentry, const char *name,
> + const void *value, size_t size, int flags)
> +{
> + if (unlikely(IS_PRIVATE(dentry->d_inode)))
> + return 0;
> + return integrity_ops->inode_setxattr(dentry, name, value, size, flags);
> +}
> +
> +void integrity_inode_post_setxattr(struct dentry *dentry, const char *name)
> +{
> + if (unlikely(IS_PRIVATE(dentry->d_inode)))
> + return;
> + integrity_ops->inode_post_setxattr(dentry, name);
> +}
> +
> +int integrity_inode_alloc(struct inode *inode)
> +{
> + return integrity_ops->inode_alloc_integrity(inode);
> +}
> +
> +void integrity_inode_free(struct inode *inode)
> +{
> + integrity_ops->inode_free_integrity(inode);
> +}
> +
> +int integrity_inode_permission(struct inode *inode, int mask,
> + struct nameidata *nd)
> +{
> + return integrity_ops->inode_permission(inode, mask, nd);
> +}
> +
> +void integrity_inode_init_integrity(struct inode *inode, struct inode *dir,
> + char **name, void **value, size_t *len)
> +{
> + if (unlikely(IS_PRIVATE(inode)))
> + return;
> + integrity_ops->inode_init_integrity(inode, dir, name, value, len);
> + return;
> +}
> +EXPORT_SYMBOL(integrity_inode_init_integrity);
> +
> +void integrity_file_free(struct file *file)
> +{
> + integrity_ops->file_free_integrity(file);
> +}
> +
> +int integrity_file_mmap(struct file *file, unsigned long reqprot,
> + unsigned long prot, unsigned long flags,
> + unsigned long addr, unsigned long addr_only)
> +{
> + return integrity_ops->file_mmap(file, reqprot, prot, flags, addr,
> + addr_only);
> +}
> +
> +void integrity_d_instantiate(struct dentry *dentry, struct inode *inode)
> +{
> + if (unlikely(inode && IS_PRIVATE(inode)))
> + return;
> + integrity_ops->d_instantiate(dentry, inode);
> +}
> Index: linux-2.6.26-rc3-git2/Documentation/kernel-parameters.txt
> ===================================================================
> --- linux-2.6.26-rc3-git2.orig/Documentation/kernel-parameters.txt
> +++ linux-2.6.26-rc3-git2/Documentation/kernel-parameters.txt
> @@ -821,6 +821,11 @@ and is between 256 and 4096 characters.
> inport.irq= [HW] Inport (ATI XL and Microsoft) busmouse driver
> Format: <irq>
>
> + integrity_audit= [INTEGRITY]
Where is the INTEGRITY tag defined?
> + Format: { "0" | "1" }
> + 0 -- disable integrity auditing messages.
> + 1 -- enable integrity auditing messages. (Default)
> +
> inttest= [IA64]
>
> iommu= [x86]
> Index: linux-2.6.26-rc3-git2/security/integrity/integrity_policy.c
> ===================================================================
> --- /dev/null
> +++ linux-2.6.26-rc3-git2/security/integrity/integrity_policy.c
> @@ -0,0 +1,204 @@
> +
> +/**
> + * integrity_measure_rules - determine whether an inode matches the given rule.
> + * @rule - a pointer to a rule
> + * @inode - a pointer to an inode
> + * @func - LIM hook identifier
> + * @mask - requested action (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC)
kernel-doc notation for parameters is (e.g.)
* @rule: a pointer to a rule
> + *
> + * Returns 1 on rule match, 0 on failure.
> + */
> +static int integrity_measure_rules(struct integrity_measure_rule_entry *rule,
> + struct inode *inode, enum lim_hooks func,
> + int mask)
> +{
> + int result = 1;
> +
> + if (result && (rule->func != 0)) {
> + if (rule->func != func)
> + result = 0;
> + }
> + if (result && (rule->mask != 0)) {
> + if (rule->mask != mask)
> + result = 0;
> + }
> + if (result && rule->lsm_subj_rule) {
> + struct task_struct *tsk = current;
> + u32 sid;
> +
> + security_task_getsecid(tsk, &sid);
> + result = security_filter_rule_match(sid, AUDIT_SUBJ_USER,
> + AUDIT_EQUAL,
> + rule->lsm_subj_rule, NULL);
> + }
> + if (result && rule->lsm_obj_rule) {
> + u32 osid;
> +
> + security_inode_getsecid(inode, &osid);
> + result = security_filter_rule_match(osid, AUDIT_OBJ_USER,
> + AUDIT_EQUAL,
> + rule->lsm_obj_rule, NULL);
> + }
> + return result;
> +}
> +
> +/**
> + * integrity_measure_policy - base measure decision on: subj, obj, LIM hook,
> + * and mask
One line for short description.
* @inode: pointer to an inode
> + * @inode - pointer to an inode
> + * @func - LIM hook identifier
> + * @mask - requested action (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC)
> + *
> + * Returns 1 on rule match, 0 on failure.
> + */
> +int integrity_measure_policy(struct inode *inode, enum lim_hooks func, int mask)
> +{
> + struct integrity_measure_rule_entry *entry;
> + int rc = 0;
> +
> + rcu_read_lock();
> + list_for_each_entry_rcu(entry, integrity_measure, list) {
> + rc = integrity_measure_rules(entry, inode, func, mask);
> + if (rc) {
> + rcu_read_unlock();
> + return rc;
> + }
> + }
> + rcu_read_unlock();
> + return rc;
> +}
> +
> +
> +
> +/**
> + * integrity_measure_rule_add - add integrity measure rules
> + * @subj - pointer to an LSM subject value
* @subj: etc etc etc
> + * @obj - pointer to an LSM object value
> + * @func - LIM hook identifier
> + * @mask - requested action (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC)
> + *
> + * Returns 0 on success, an error code on failure.
> + */
> +int integrity_measure_rule_add(char *subj, char *obj, char *func, char *mask)
> +{
> + struct integrity_measure_rule_entry *entry;
> + int result = 0;
> +
> + /* Prevent installed policy from changing */
> + if (integrity_measure != &measure_default_rules) {
> + integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL,
> + NULL, "policy_update", "already exists", 1);
> + return -EACCES;
> + }
> +
> + entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
> + INIT_LIST_HEAD(&entry->list);
> + if (!result && subj)
> + result = security_filter_rule_init(AUDIT_SUBJ_USER, AUDIT_EQUAL,
> + subj, &entry->lsm_subj_rule);
> + if (!result && obj)
> + result = security_filter_rule_init(AUDIT_OBJ_USER, AUDIT_EQUAL,
> + obj, &entry->lsm_obj_rule);
> + if (!result && func) {
> + if (strcmp(func, "INODE_PERMISSION") == 0)
> + entry->func = INODE_PERMISSION;
> + else if (strcmp(func, "FILE_MMAP") == 0)
> + entry->func = FILE_MMAP;
> + else if (strcmp(func, "BPRM_CHECK") == 0)
> + entry->func = BPRM_CHECK;
> + else
> + result = -EINVAL;
> + }
> + if (!result && mask) {
> + if (strcmp(mask, "MAY_EXEC") == 0)
> + entry->mask = MAY_EXEC;
> + else if (strcmp(mask, "MAY_WRITE") == 0)
> + entry->mask = MAY_WRITE;
> + else if (strcmp(mask, "MAY_READ") == 0)
> + entry->mask = MAY_READ;
> + else if (strcmp(mask, "MAY_APPEND") == 0)
> + entry->mask = MAY_APPEND;
> + else
> + result = -EINVAL;
> + }
> + if (!result) {
> + mutex_lock(&integrity_measure_mutex);
> + list_add_tail(&entry->list, &measure_policy_rules);
> + mutex_unlock(&integrity_measure_mutex);
> + }
> + return result;
> +}
---
~Randy
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [RFC][PATCH 4/5]integrity: Linux Integrity Module(LIM)
2008-05-23 23:30 ` Randy Dunlap
@ 2008-05-27 14:34 ` Mimi Zohar
0 siblings, 0 replies; 9+ messages in thread
From: Mimi Zohar @ 2008-05-27 14:34 UTC (permalink / raw)
To: Randy Dunlap
Cc: linux-kernel, safford, serue, sailer, zohar, Stephen Smalley,
CaseySchaufler
This is a request for comments for a redesign of the integrity patches.
The new version addresses a number of issues, including
- generalizing the measurement API beyond just inode measurements.
- separation of the measurement into distinct collection, appraisal,
and commitment phases, for greater flexibility.
- redesigning the interactions with LSM modules (Selinux and Smack)
to be acceptable to those groups.
Extended Verification Module(EVM) and the Integrity Measurement
Architecture(IMA) were originally implemented as an LSM module. Based
on discussions on the LSM mailing list, a decision was made that the
LSM hooks should only be used to enforce mandatory access control
decisions and a new set of hooks should be defined specifically for
integrity.
EVM/IMA was limited to verifying and measuring a file's (i.e. an inode)
integrity and the metadata associated with it. Current research is
looking into other types of integrity measurements. (i.e. "Linux kernel
integrity measurement using contextual inspection", by Peter A. Loscocco,
Perry W. Wilson, J. Aaron Pendergrass, C. Durward McDonell,
http://doi.acm.org/10.1145/1314354.1314362) As a result, a requirement
of the new integrity framework is support for different types of integrity
measurements.
Our work has shown that requests for integrity verification/measurement
needs to be based on knowledge of the filesystem, requiring the system
to either be labeled with integrity data or depend on the existent LSM
security labels. The previous set of integrity patches modified the LSM
modules to be integrity context aware, meaning that the LSM modules made
integrity data/metadata verification and measurement API calls based on
an understanding of the LSM security labels. Both of the LSM maintainers
felt that the changes were too intrusive and that integrity enforcement
should be made by the integrity provider, not the LSM module.
To address these concerns, Stephen Smalley suggested using the
security_audit_rule_match(), renamed to security_filter_rule_match(), to
define LSM specific integrity measurement policy rules, in lieu of
modifying the LSM modules. In the current set of patches, the integrity
API calls can be made either by the integrity provider (i.e. IMA), based
on an LSM specific integrity policy, or by an integrity context aware LSM
module.
This patch provides an integrity framework(api and hooks), placement of
the integrity hooks in the appropriate places in the fs directory, and a
dummy provider for an integrity service. Collecting, appraising, and
storing of inode and other types of integrity data is supported. Multiple
integrity templates, which implement the integrity API, may register
themselves. For now, only a single integrity provider can register itself
for the integrity hooks. (Support for multiple providers registering
themselves for the integrity hooks would require some form of stacking.)
The ten integrity hooks are:
inode_setxattr, inode_post_setxattr,
inode_alloc_integrity, inode_free_integrity, inode_init_integrity,
file_free_integrity, d_instantiate,
bprm_check_integrity, file_mmap, inode_permission
The five integrity API calls provided are:
integrity_must_measure, integrity_collect_measurement,
integrity_appraise_measurement, integrity_store_measurement,
and integrity_display_template.
The type of integrity data being collected, appraised, stored, or
displayed is template dependent.
(Details on the calls and their exact arguments are in linux/integrity.h,
included in the patch.)
Signed-off-by: Mimi Zohar <zohar@us.ibm.com>
---
Index: linux-2.6.26-rc3-git2/include/linux/integrity.h
===================================================================
--- /dev/null
+++ linux-2.6.26-rc3-git2/include/linux/integrity.h
@@ -0,0 +1,261 @@
+/*
+ * integrity.h
+ *
+ * Copyright (C) 2005,2006,2007,2008 IBM Corporation
+ * Author: Mimi Zohar <zohar@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2 of the License.
+ */
+
+#ifndef _LINUX_INTEGRITY_H
+#define _LINUX_INTEGRITY_H
+
+#include <linux/fs.h>
+#include <linux/audit.h>
+
+#ifdef CONFIG_INTEGRITY
+void integrity_audit_msg(int audit_msgno, struct inode *inode,
+ const unsigned char *fname, char *op,
+ char *cause, int result);
+
+enum lim_hooks {INODE_PERMISSION = 1, FILE_MMAP, BPRM_CHECK };
+extern int integrity_measure_policy(struct inode *inode, enum lim_hooks func,
+ int mask);
+extern int integrity_measure_rule_add(char *, char *, char *, char *);
+extern void integrity_measure_policy_init(void);
+extern void integrity_measure_policy_complete(void);
+
+/*
+ * Integrity API calls:
+ *
+ * @collect_measurement:
+ * Collect template specific measurement data.
+ * @data contains template specific data used for collecting the
+ * measurement.
+ * Return 0 if operation was successful.
+ *
+ * @appraise_measurement:
+ * Appraise the integrity of the template specific measurement data.
+ * @data contains template specific data used for appraising the
+ * measurement.
+ * Return 0 if operation was successful.
+ *
+ * @store_measurement:
+ * Store the template specific data.
+ * @data contains template specific data used for storing the
+ * measurement.
+ *
+ * @must_measure:
+ * Measurement decision based on an integrity policy.
+ * @data contains template specific data used for making policy
+ * decision.
+ * Return 0 if operation was successful.
+ *
+ * @display_template:
+ * Display template specific data.
+ *
+ */
+
+enum integrity_show_type { INTEGRITY_SHOW_BINARY, INTEGRITY_SHOW_ASCII};
+
+struct template_operations {
+ int (*collect_measurement)(void *);
+ int (*appraise_measurement)(void *);
+ void (*store_measurement)(void *);
+ int (*must_measure)(void *);
+ void (*display_template)(struct seq_file *m, void *,
+ enum integrity_show_type);
+};
+extern int register_template(char *template_name,
+ struct template_operations *ops);
+extern int unregister_template(char *template_name);
+extern int integrity_find_template(char *, struct template_operations **ops);
+
+/*
+ * Integrity hooks:
+ *
+ * @bprm_check_integrity:
+ * This hook mediates the point when a search for a binary handler will
+ * begin. At this point, the OS protects against an executable file,
+ * already open for write, from being executed; and an executable file
+ * already open for execute, from being modified. So we can be certain
+ * that any measurements(collect, appraise, store) done here are of
+ * the file being executed.
+ * @bprm contains the linux_binprm structure.
+ * Return 0 if the hook is successful and permission is granted.
+ *
+ * @inode_setxattr:
+ * Check permission before permitting an integrity extended attribute
+ * to be set.
+ * @value identified by @name for @dentry.
+ *
+ * @inode_post_setxattr:
+ * Update inode integrity xattr after successful setxattr operation.
+ * identified by @name for @dentry.
+ *
+ * @inode_alloc_integrity:
+ * Allocate and attach an integrity structure to @inode->i_integrity. The
+ * i_integrity field is initialized to NULL when the inode structure is
+ * allocated.
+ * @inode contains the inode structure.
+ * Return 0 if operation was successful.
+ *
+ * @inode_free_integrity:
+ * @inode contains the inode structure.
+ * Deallocate the inode integrity structure and set @inode->i_integrity to
+ * NULL.
+ *
+ * @inode_init_integrity:
+ * Create inode integrity xattr for a new inode based on the new security
+ * xattr information.
+ * @inode contains the inode structure of the newly created inode.
+ * @dir contains the inode structure of the parent directory.
+ * @name contains the security xattr name suffix.
+ * @value contains the security attribute value.
+ * @len contains the length of the security attribute value.
+ *
+ * @inode_permission:
+ * This hook is called by the existing Linux permission function, when
+ * a file is opened (as well as many other operations). At this point,
+ * measurements of files open for read(collect, appraise, store) can
+ * be made.
+ * @inode contains the inode structure to check.
+ * @mask contains the permission mask.
+ * @nd contains the nameidata (may be NULL).
+ *
+ * @file_free_integrity:
+ * Update the integrity xattr value as necessary.
+ * *file contains the file structure being closed.
+ *
+ * @file_mmap :
+ * Measurement(collect, appraise, store) of files mmaped for EXEC,
+ * could be measured at this point.
+ * @file contains the file structure for file to map (may be NULL).
+ * @reqprot contains the protection requested by the application.
+ * @prot contains the protection that will be applied by the kernel.
+ * @flags contains the operational flags.
+ * Return 0 if permission is granted.
+ *
+ * @d_instantiate:
+ * Initialize the integrity structure of an inode for a dentry.
+ * @dentry to complete.
+ * @inode to attach to this dentry.
+ *
+ */
+
+struct integrity_operations {
+ int (*bprm_check_integrity) (struct linux_binprm *bprm);
+ int (*inode_setxattr) (struct dentry *dentry, const char *name,
+ const void *value, size_t size, int flags);
+ void (*inode_post_setxattr) (struct dentry *dentry, const char *name);
+ int (*inode_alloc_integrity) (struct inode *inode);
+ void (*inode_free_integrity) (struct inode *inode);
+ void (*inode_init_integrity) (struct inode *inode, struct inode *dir,
+ char **name, void **value, size_t *len);
+ int (*inode_permission) (struct inode *inode, int mask,
+ struct nameidata *nd);
+ void (*file_free_integrity) (struct file *file);
+ int (*file_mmap) (struct file *file,
+ unsigned long reqprot, unsigned long prot,
+ unsigned long flags, unsigned long addr,
+ unsigned long addr_only);
+ void (*d_instantiate) (struct dentry *dentry, struct inode *inode);
+};
+extern int register_integrity(struct integrity_operations *ops);
+extern int unregister_integrity(struct integrity_operations *ops);
+
+/* global variables */
+extern struct integrity_operations *integrity_ops;
+
+
+int integrity_collect_measurement(char *template_name, void *data);
+int integrity_appraise_measurement(char *template_name, void *data);
+int integrity_must_measure(char *template_name, void *data);
+void integrity_store_measurement(char *template_name, void *data);
+
+int integrity_bprm_check(struct linux_binprm *bprm);
+int integrity_inode_setxattr(struct dentry *dentry, const char *name,
+ const void *value, size_t size, int flags);
+void integrity_inode_post_setxattr(struct dentry *dentry, const char *name);
+int integrity_inode_alloc(struct inode *inode);
+void integrity_inode_free(struct inode *inode);
+void integrity_inode_init_integrity(struct inode *inode, struct inode *dir,
+ char **name, void **value, size_t *len);
+int integrity_inode_permission(struct inode *inode, int mask,
+ struct nameidata *nd);
+void integrity_file_free(struct file *file);
+int integrity_file_mmap(struct file *file,
+ unsigned long reqprot, unsigned long prot,
+ unsigned long flags, unsigned long addr,
+ unsigned long addr_only);
+void integrity_d_instantiate(struct dentry *dentry, struct inode *inode);
+
+#else
+
+static inline int integrity_bprm_check(struct linux_binprm *bprm)
+{
+ return 0;
+}
+
+static inline int integrity_inode_setxattr(struct dentry *dentry,
+ const char *name, const void *value,
+ size_t size, int flags)
+{
+ return 0;
+}
+
+static inline void integrity_inode_post_setxattr(struct dentry *dentry,
+ const char *name)
+{ }
+
+static inline int integrity_inode_alloc(struct inode *inode)
+{
+ return 0;
+}
+
+static inline void integrity_inode_free(struct inode *inode)
+{ }
+
+static inline int integrity_inode_init_integrity(struct inode *inode,
+ struct inode *dir,
+ char **name,
+ void **value,
+ size_t *len)
+{
+ return -EOPNOTSUPP;
+}
+
+static inline int integrity_inode_permission(struct inode *inode, int mask,
+ struct nameidata *nd)
+{
+ return 0;
+}
+
+static inline int integrity_file_permission(struct file *file, int mask)
+{
+ return 0;
+}
+
+static inline void integrity_file_free(struct file *file)
+{
+ return;
+}
+
+static inline int integrity_file_mmap(struct file *file,
+ unsigned long reqprot, unsigned long prot,
+ unsigned long flags, unsigned long addr,
+ unsigned long addr_only)
+{
+ return 0;
+}
+
+static inline void integrity_d_instantiate(struct dentry *dentry,
+ struct inode *inode)
+{
+ return;
+}
+
+#endif
+#endif
Index: linux-2.6.26-rc3-git2/security/integrity/integrity.c
===================================================================
--- /dev/null
+++ linux-2.6.26-rc3-git2/security/integrity/integrity.c
@@ -0,0 +1,307 @@
+/*
+ * Copyright (C) 2006,2007,2008 IBM Corporation
+ * Author: Mimi Zohar <zohar@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2 of the License.
+ *
+ * File: integrity.c
+ * register integrity subsystem
+ * register integrity template
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/integrity.h>
+#include "integrity_dummy.h"
+
+struct integrity_operations *integrity_ops = &dummy_integrity_ops;
+EXPORT_SYMBOL(integrity_ops);
+
+#define TEMPLATE_NAME_LEN_MAX 12
+struct template_list_entry {
+ struct list_head template;
+ char template_name[TEMPLATE_NAME_LEN_MAX + 1];
+ struct template_operations *template_ops;
+};
+static int template_initialized;
+static struct list_head integrity_templates;
+static DEFINE_MUTEX(integrity_templates_mutex);
+
+/**
+ * register_integrity - registers an integrity framework with the kernel
+ * @ops: a pointer to the struct security_options that is to be registered
+ *
+ * Perhaps in the future integrity module stacking will be necessary, but
+ * for the time being, this function permits only one integrity module to
+ * register itself with the kernel integrity subsystem.
+ *
+ * If another integrity module is already registered, an error code is
+ * returned. On success 0 is returned.
+ */
+int register_integrity(struct integrity_operations *ops)
+{
+ if (integrity_ops != &dummy_integrity_ops)
+ return -EAGAIN;
+ integrity_ops = ops;
+ integrity_fixup_ops(integrity_ops);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(register_integrity);
+
+/**
+ * unregister_integrity - unregisters an integrity framework from the kernel
+ * @ops: a pointer to the struct security_options that is to be registered
+ *
+ * Returns 0 on success, -EINVAL on failure.
+ */
+int unregister_integrity(struct integrity_operations *ops)
+{
+ if (ops != integrity_ops)
+ return -EINVAL;
+
+ integrity_ops = &dummy_integrity_ops;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(unregister_integrity);
+
+/**
+ * register_template - registers an integrity template with the kernel
+ * @template_name: a pointer to a string containing the template name.
+ * @template_ops: a pointer to the template functions
+ *
+ * Register a set of functions to collect, appraise, store, and display
+ * a template measurement, and a means to decide whether to do them.
+ * Unlike integrity modules, any number of templates may be registered.
+ *
+ * Returns 0 on success, an error code on failure.
+ */
+int register_template(char *template_name,
+ struct template_operations *template_ops)
+{
+ int template_len;
+ struct template_list_entry *entry;
+
+ if (!template_initialized++) {
+ INIT_LIST_HEAD(&integrity_templates);
+ mutex_init(&integrity_templates_mutex);
+ }
+
+ entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
+ if (!entry)
+ return -ENOMEM;
+ INIT_LIST_HEAD(&entry->template);
+
+ template_len = strlen(template_name);
+ if (template_len > TEMPLATE_NAME_LEN_MAX)
+ template_len = TEMPLATE_NAME_LEN_MAX;
+ memcpy(entry->template_name, template_name, template_len);
+ entry->template_name[template_len] = '\0';
+ entry->template_ops = template_ops;
+
+ mutex_lock(&integrity_templates_mutex);
+ list_add_rcu(&entry->template, &integrity_templates);
+ mutex_unlock(&integrity_templates_mutex);
+ synchronize_rcu();
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(register_template);
+
+/**
+ * unregister_template: unregister a template
+ * @template_name: a pointer to a string containing the template name.
+ *
+ * Returns 0 on success, -EINVAL on failure.
+ */
+int unregister_template(char *template_name)
+{
+ struct template_list_entry *entry;
+
+ mutex_lock(&integrity_templates_mutex);
+ list_for_each_entry(entry, &integrity_templates, template) {
+ if (strncmp(entry->template_name, template_name,
+ strlen(entry->template_name)) == 0) {
+ list_del_rcu(&entry->template);
+ mutex_unlock(&integrity_templates_mutex);
+ synchronize_rcu();
+ kfree(entry);
+ return 0;
+ }
+ }
+ mutex_unlock(&integrity_templates_mutex);
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(unregister_template);
+
+/**
+ * integrity_find_template - search the integrity_templates list
+ * @template_name: a pointer to a string containing the template name.
+ * @template_ops: a pointer to the template functions
+ *
+ * Returns 0 on success, 1 on failure.
+ */
+int integrity_find_template(char *template_name,
+ struct template_operations **template_ops)
+{
+ struct template_list_entry *entry;
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(entry, &integrity_templates, template) {
+ if (strncmp(entry->template_name, template_name,
+ strlen(entry->template_name)) == 0) {
+ *template_ops = entry->template_ops;
+ rcu_read_unlock();
+ return 0;
+ }
+ }
+ rcu_read_unlock();
+ return 1;
+}
+EXPORT_SYMBOL_GPL(integrity_find_template);
+
+/**
+ * integrity_collect_measurement - collect template specific measurement
+ * @template_name: a pointer to a string containing the template name.
+ * @data: pointer to template specific data
+ *
+ * Returns 0 on success, an error code on failure.
+ */
+int integrity_collect_measurement(char *template_name, void *data)
+{
+ struct template_operations *template_ops;
+
+ if (integrity_find_template(template_name, &template_ops) == 0)
+ return template_ops->collect_measurement(data);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(integrity_collect_measurement);
+
+/**
+ * integrity_appraise_measurement - appraise template specific measurement
+ * @template_name: a pointer to a string containing the template name.
+ * @data: pointer to template specific data
+ *
+ * Returns 0 on success, an error code on failure
+ */
+int integrity_appraise_measurement(char *template_name, void *data)
+{
+ struct template_operations *template_ops;
+
+ if (integrity_find_template(template_name, &template_ops) == 0)
+ return template_ops->appraise_measurement(data);
+ return 1;
+}
+EXPORT_SYMBOL_GPL(integrity_appraise_measurement);
+
+/**
+ * integrity_store_measurement - store template specific measurement
+ * @template_name: a pointer to a string containing the template name.
+ * @data: pointer to template specific data
+ *
+ * Store template specific integrity measurement.
+ */
+void integrity_store_measurement(char *template_name, void *data)
+{
+ struct template_operations *template_ops;
+
+ if (integrity_find_template(template_name, &template_ops) == 0)
+ template_ops->store_measurement(data);
+ return;
+}
+EXPORT_SYMBOL_GPL(integrity_store_measurement);
+
+/**
+ * integrity_must_measure - measure decision based on template policy
+ * @template_name: a pointer to a string containing the template name.
+ * @data: pointer to template specific data
+ *
+ * Returns 0 on success, an error code on failure.
+ */
+int integrity_must_measure(char *template_name, void *data)
+{
+ struct template_operations *template_ops;
+
+ if (integrity_find_template(template_name, &template_ops) == 0)
+ return template_ops->must_measure(data);
+ return 1;
+}
+EXPORT_SYMBOL_GPL(integrity_must_measure);
+
+/* Integrity Hooks */
+int integrity_bprm_check(struct linux_binprm *bprm)
+{
+ return integrity_ops->bprm_check_integrity(bprm);
+}
+
+int integrity_inode_setxattr(struct dentry *dentry, const char *name,
+ const void *value, size_t size, int flags)
+{
+ if (unlikely(IS_PRIVATE(dentry->d_inode)))
+ return 0;
+ return integrity_ops->inode_setxattr(dentry, name, value, size, flags);
+}
+
+void integrity_inode_post_setxattr(struct dentry *dentry, const char *name)
+{
+ if (unlikely(IS_PRIVATE(dentry->d_inode)))
+ return;
+ integrity_ops->inode_post_setxattr(dentry, name);
+}
+
+int integrity_inode_alloc(struct inode *inode)
+{
+ return integrity_ops->inode_alloc_integrity(inode);
+}
+
+void integrity_inode_free(struct inode *inode)
+{
+ integrity_ops->inode_free_integrity(inode);
+}
+
+int integrity_inode_permission(struct inode *inode, int mask,
+ struct nameidata *nd)
+{
+ return integrity_ops->inode_permission(inode, mask, nd);
+}
+
+/**
+ * integrity_inode_init_integrity - create integrity xattr for a new inode
+ * @inode: pointer to the inode structure of the newly created inode.
+ * @dir: pointer to the inode structure of the parent directory.
+ * @name: pointer to the security xattr name suffix.
+ * @value: pointer to the security attribute value.
+ * @len: pointer to the length of the security attribute value.
+ */
+void integrity_inode_init_integrity(struct inode *inode, struct inode *dir,
+ char **name, void **value, size_t *len)
+{
+ if (unlikely(IS_PRIVATE(inode)))
+ return;
+ integrity_ops->inode_init_integrity(inode, dir, name, value, len);
+ return;
+}
+EXPORT_SYMBOL(integrity_inode_init_integrity);
+
+void integrity_file_free(struct file *file)
+{
+ integrity_ops->file_free_integrity(file);
+}
+
+int integrity_file_mmap(struct file *file, unsigned long reqprot,
+ unsigned long prot, unsigned long flags,
+ unsigned long addr, unsigned long addr_only)
+{
+ return integrity_ops->file_mmap(file, reqprot, prot, flags, addr,
+ addr_only);
+}
+
+void integrity_d_instantiate(struct dentry *dentry, struct inode *inode)
+{
+ if (unlikely(inode && IS_PRIVATE(inode)))
+ return;
+ integrity_ops->d_instantiate(dentry, inode);
+}
Index: linux-2.6.26-rc3-git2/security/integrity/integrity_dummy.c
===================================================================
--- /dev/null
+++ linux-2.6.26-rc3-git2/security/integrity/integrity_dummy.c
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2005,2006,2007,2008 IBM Corporation
+ * Author: Mimi Zohar <zohar@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2 of the License.
+ *
+ * File: integrity_dummy.c
+ * Instantiate integrity subsystem
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/capability.h>
+#include <linux/integrity.h>
+#include <linux/xattr.h>
+#include "integrity_dummy.h"
+
+/* Integrity ops */
+static int dummy_bprm_check_integrity(struct linux_binprm *bprm)
+{
+ return 0;
+}
+
+static int dummy_inode_alloc_integrity(struct inode *inode)
+{
+ return 0;
+}
+
+static void dummy_inode_free_integrity(struct inode *inode)
+{
+ return;
+}
+
+static void dummy_inode_init_integrity(struct inode *inode, struct inode *dir,
+ char **name, void **value, size_t *len)
+{
+ return;
+}
+
+static void dummy_file_free_integrity(struct file *file)
+{
+ return;
+}
+
+static int dummy_file_mmap(struct file *file,
+ unsigned long reqprot, unsigned long prot,
+ unsigned long flags, unsigned long addr,
+ unsigned long addr_only)
+{
+ return 0;
+}
+
+static int dummy_inode_setxattr(struct dentry *dentry, const char *name,
+ const void *value, size_t size, int flags)
+{
+ return 0;
+}
+
+static void dummy_inode_post_setxattr(struct dentry *dentry, const char *name)
+{
+}
+
+static int dummy_inode_permission(struct inode *inode, int mask,
+ struct nameidata *nd)
+{
+ return 0;
+}
+
+static void dummy_d_instantiate(struct dentry *dentry, struct inode *inode)
+{
+ return;
+}
+
+struct integrity_operations dummy_integrity_ops = {
+ .bprm_check_integrity = dummy_bprm_check_integrity,
+ .inode_setxattr = dummy_inode_setxattr,
+ .inode_post_setxattr = dummy_inode_post_setxattr,
+ .inode_alloc_integrity = dummy_inode_alloc_integrity,
+ .inode_init_integrity = dummy_inode_init_integrity,
+ .inode_free_integrity = dummy_inode_free_integrity,
+ .inode_permission = dummy_inode_permission,
+ .file_free_integrity = dummy_file_free_integrity,
+ .file_mmap = dummy_file_mmap,
+ .d_instantiate = dummy_d_instantiate
+};
+
+#define set_to_dummy_if_null(ops, function) \
+ do { \
+ if (!ops->function) { \
+ ops->function = dummy_##function; \
+ printk(KERN_INFO "Had to override the " #function \
+ " integrity operation with the dummy one.\n");\
+ } \
+ } while (0)
+
+void integrity_fixup_ops(struct integrity_operations *ops)
+{
+ set_to_dummy_if_null(ops, inode_setxattr);
+ set_to_dummy_if_null(ops, inode_post_setxattr);
+ set_to_dummy_if_null(ops, inode_alloc_integrity);
+ set_to_dummy_if_null(ops, inode_init_integrity);
+ set_to_dummy_if_null(ops, inode_free_integrity);
+ set_to_dummy_if_null(ops, file_free_integrity);
+ set_to_dummy_if_null(ops, d_instantiate);
+
+ set_to_dummy_if_null(ops, bprm_check_integrity);
+ set_to_dummy_if_null(ops, file_mmap);
+ set_to_dummy_if_null(ops, inode_permission);
+}
Index: linux-2.6.26-rc3-git2/security/integrity/integrity_dummy.h
===================================================================
--- /dev/null
+++ linux-2.6.26-rc3-git2/security/integrity/integrity_dummy.h
@@ -0,0 +1,13 @@
+/*
+ * integrity_dummy.h
+ *
+ * Copyright (C) 2005,2006,2007 IBM Corporation
+ * Author: Mimi Zohar <zohar@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2 of the License.
+ */
+
+extern struct integrity_operations dummy_integrity_ops;
+extern void integrity_fixup_ops(struct integrity_operations *ops);
Index: linux-2.6.26-rc3-git2/fs/dcache.c
===================================================================
--- linux-2.6.26-rc3-git2.orig/fs/dcache.c
+++ linux-2.6.26-rc3-git2/fs/dcache.c
@@ -28,6 +28,7 @@
#include <linux/file.h>
#include <asm/uaccess.h>
#include <linux/security.h>
+#include <linux/integrity.h>
#include <linux/seqlock.h>
#include <linux/swap.h>
#include <linux/bootmem.h>
@@ -972,6 +973,7 @@ void d_instantiate(struct dentry *entry,
entry->d_inode = inode;
fsnotify_d_instantiate(entry, inode);
spin_unlock(&dcache_lock);
+ integrity_d_instantiate(entry, inode);
security_d_instantiate(entry, inode);
}
@@ -1036,6 +1038,7 @@ struct dentry *d_instantiate_unique(stru
spin_unlock(&dcache_lock);
if (!result) {
+ integrity_d_instantiate(entry, inode);
security_d_instantiate(entry, inode);
return NULL;
}
@@ -1173,6 +1176,7 @@ struct dentry *d_splice_alias(struct ino
BUG_ON(!(new->d_flags & DCACHE_DISCONNECTED));
fsnotify_d_instantiate(new, inode);
spin_unlock(&dcache_lock);
+ integrity_d_instantiate(new, inode);
security_d_instantiate(new, inode);
d_rehash(dentry);
d_move(new, dentry);
@@ -1183,6 +1187,7 @@ struct dentry *d_splice_alias(struct ino
dentry->d_inode = inode;
fsnotify_d_instantiate(dentry, inode);
spin_unlock(&dcache_lock);
+ integrity_d_instantiate(dentry, inode);
security_d_instantiate(dentry, inode);
d_rehash(dentry);
}
@@ -1733,6 +1738,7 @@ found:
spin_unlock(&dcache_lock);
out_nolock:
if (actual == dentry) {
+ integrity_d_instantiate(dentry, inode);
security_d_instantiate(dentry, inode);
return NULL;
}
Index: linux-2.6.26-rc3-git2/fs/ext3/xattr_security.c
===================================================================
--- linux-2.6.26-rc3-git2.orig/fs/ext3/xattr_security.c
+++ linux-2.6.26-rc3-git2/fs/ext3/xattr_security.c
@@ -9,6 +9,7 @@
#include <linux/ext3_jbd.h>
#include <linux/ext3_fs.h>
#include <linux/security.h>
+#include <linux/integrity.h>
#include "xattr.h"
static size_t
@@ -57,12 +58,19 @@ ext3_init_security(handle_t *handle, str
err = security_inode_init_security(inode, dir, &name, &value, &len);
if (err) {
+ /* Even if creation of the security xattr fails, must
+ * indicate this is a new inode. */
+ integrity_inode_init_integrity(inode, dir, NULL, NULL, NULL);
if (err == -EOPNOTSUPP)
return 0;
return err;
}
err = ext3_xattr_set_handle(handle, inode, EXT3_XATTR_INDEX_SECURITY,
name, value, len, 0);
+
+ integrity_inode_init_integrity(inode, dir, &name, &value, &len);
+ err = ext3_xattr_set_handle(handle, inode, EXT3_XATTR_INDEX_SECURITY,
+ name, value, len, 0);
kfree(name);
kfree(value);
return err;
Index: linux-2.6.26-rc3-git2/fs/file_table.c
===================================================================
--- linux-2.6.26-rc3-git2.orig/fs/file_table.c
+++ linux-2.6.26-rc3-git2/fs/file_table.c
@@ -13,6 +13,7 @@
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/security.h>
+#include <linux/integrity.h>
#include <linux/eventpoll.h>
#include <linux/rcupdate.h>
#include <linux/mount.h>
@@ -272,6 +273,7 @@ void __fput(struct file *file)
if (file->f_op && file->f_op->release)
file->f_op->release(inode, file);
security_file_free(file);
+ integrity_file_free(file);
if (unlikely(S_ISCHR(inode->i_mode) && inode->i_cdev != NULL))
cdev_put(inode->i_cdev);
fops_put(file->f_op);
@@ -343,6 +345,7 @@ void put_filp(struct file *file)
{
if (atomic_dec_and_test(&file->f_count)) {
security_file_free(file);
+ integrity_file_free(file);
file_kill(file);
file_free(file);
}
Index: linux-2.6.26-rc3-git2/fs/inode.c
===================================================================
--- linux-2.6.26-rc3-git2.orig/fs/inode.c
+++ linux-2.6.26-rc3-git2/fs/inode.c
@@ -17,6 +17,7 @@
#include <linux/hash.h>
#include <linux/swap.h>
#include <linux/security.h>
+#include <linux/integrity.h>
#include <linux/pagemap.h>
#include <linux/cdev.h>
#include <linux/bootmem.h>
@@ -160,6 +161,14 @@ static struct inode *alloc_inode(struct
init_rwsem(&inode->i_alloc_sem);
lockdep_set_class(&inode->i_alloc_sem, &sb->s_type->i_alloc_sem_key);
+ if (integrity_inode_alloc(inode)) {
+ if (inode->i_sb->s_op->destroy_inode)
+ inode->i_sb->s_op->destroy_inode(inode);
+ else
+ kmem_cache_free(inode_cachep, (inode));
+ return NULL;
+ }
+
mapping->a_ops = &empty_aops;
mapping->host = inode;
mapping->flags = 0;
@@ -190,6 +199,7 @@ void destroy_inode(struct inode *inode)
{
BUG_ON(inode_has_buffers(inode));
security_inode_free(inode);
+ integrity_inode_free(inode);
if (inode->i_sb->s_op->destroy_inode)
inode->i_sb->s_op->destroy_inode(inode);
else
Index: linux-2.6.26-rc3-git2/fs/xattr.c
===================================================================
--- linux-2.6.26-rc3-git2.orig/fs/xattr.c
+++ linux-2.6.26-rc3-git2/fs/xattr.c
@@ -14,6 +14,7 @@
#include <linux/mount.h>
#include <linux/namei.h>
#include <linux/security.h>
+#include <linux/integrity.h>
#include <linux/syscalls.h>
#include <linux/module.h>
#include <linux/fsnotify.h>
@@ -81,11 +82,17 @@ vfs_setxattr(struct dentry *dentry, cons
error = security_inode_setxattr(dentry, name, value, size, flags);
if (error)
goto out;
+
+ error = integrity_inode_setxattr(dentry, name, value, size, flags);
+ if (error)
+ goto out;
+
error = -EOPNOTSUPP;
if (inode->i_op->setxattr) {
error = inode->i_op->setxattr(dentry, name, value, size, flags);
if (!error) {
fsnotify_xattr(dentry);
+ integrity_inode_post_setxattr(dentry, name);
security_inode_post_setxattr(dentry, name, value,
size, flags);
}
@@ -205,6 +212,8 @@ vfs_removexattr(struct dentry *dentry, c
mutex_lock(&inode->i_mutex);
error = inode->i_op->removexattr(dentry, name);
+ if (!error)
+ integrity_inode_post_setxattr(dentry, name);
mutex_unlock(&inode->i_mutex);
if (!error)
Index: linux-2.6.26-rc3-git2/include/linux/fs.h
===================================================================
--- linux-2.6.26-rc3-git2.orig/include/linux/fs.h
+++ linux-2.6.26-rc3-git2/include/linux/fs.h
@@ -653,6 +653,9 @@ struct inode {
#ifdef CONFIG_SECURITY
void *i_security;
#endif
+#ifdef CONFIG_INTEGRITY
+ void *i_integrity;
+#endif
void *i_private; /* fs or device private pointer */
};
Index: linux-2.6.26-rc3-git2/include/linux/audit.h
===================================================================
--- linux-2.6.26-rc3-git2.orig/include/linux/audit.h
+++ linux-2.6.26-rc3-git2/include/linux/audit.h
@@ -123,6 +123,11 @@
#define AUDIT_LAST_KERN_ANOM_MSG 1799
#define AUDIT_ANOM_PROMISCUOUS 1700 /* Device changed promiscuous mode */
#define AUDIT_ANOM_ABEND 1701 /* Process ended abnormally */
+#define AUDIT_INTEGRITY_DATA 1800 /* Data integrity verification */
+#define AUDIT_INTEGRITY_METADATA 1801 /* Metadata integrity verification */
+#define AUDIT_INTEGRITY_STATUS 1802 /* Integrity enable status */
+#define AUDIT_INTEGRITY_HASH 1803 /* Integrity HASH type */
+#define AUDIT_INTEGRITY_PCR 1804 /* PCR invalidation msgs */
#define AUDIT_KERNEL 2000 /* Asynchronous audit record. NOT A REQUEST. */
@@ -441,6 +446,8 @@ extern int audit_set_loginuid(struct ta
#define audit_get_loginuid(t) ((t)->loginuid)
#define audit_get_sessionid(t) ((t)->sessionid)
extern void audit_log_task_context(struct audit_buffer *ab);
+extern void audit_log_inode_context(struct audit_buffer *ab,
+ struct inode *inode);
extern int __audit_ipc_obj(struct kern_ipc_perm *ipcp);
extern int __audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode);
extern int audit_bprm(struct linux_binprm *bprm);
@@ -521,6 +528,7 @@ extern int audit_signals;
#define audit_get_loginuid(t) (-1)
#define audit_get_sessionid(t) (-1)
#define audit_log_task_context(b) do { ; } while (0)
+#define audit_log_inode_context(b, a) do { ; } while (0)
#define audit_ipc_obj(i) ({ 0; })
#define audit_ipc_set_perm(q,u,g,m) ({ 0; })
#define audit_bprm(p) ({ 0; })
Index: linux-2.6.26-rc3-git2/security/integrity/integrity_audit.c
===================================================================
--- /dev/null
+++ linux-2.6.26-rc3-git2/security/integrity/integrity_audit.c
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2008 IBM Corporation
+ * Author: Mimi Zohar <zohar@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2 of the License.
+ *
+ * File: integrity_audit.c
+ * Audit calls for the integrity subsystem
+ */
+
+#include <linux/audit.h>
+#include <linux/fs.h>
+#include <linux/integrity.h>
+
+#ifdef CONFIG_INTEGRITY_AUDIT
+static int integrity_audit = 1;
+
+static int __init integrity_audit_setup(char *str)
+{
+ char *op;
+
+ integrity_audit = simple_strtol(str, NULL, 0);
+ op = integrity_audit ? "integrity_audit_enabled" :
+ "integrity_audit_not_enabled";
+ integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, NULL, NULL, op, 0);
+ return 1;
+}
+
+__setup("integrity_audit=", integrity_audit_setup);
+#else
+static int integrity_audit = 1;
+#endif
+
+void integrity_audit_msg(int audit_msgno, struct inode *inode,
+ const unsigned char *fname, char *op,
+ char *cause, int result)
+{
+ struct audit_buffer *ab;
+ if (!integrity_audit && result == 1)
+ return;
+
+ ab = audit_log_start(current->audit_context, GFP_ATOMIC, audit_msgno);
+ audit_log_format(ab, "integrity: pid=%d uid=%u auid=%u",
+ current->pid, current->uid,
+ audit_get_loginuid(current));
+ audit_log_task_context(ab);
+ switch (audit_msgno) {
+ case AUDIT_INTEGRITY_DATA:
+ case AUDIT_INTEGRITY_METADATA:
+ case AUDIT_INTEGRITY_PCR:
+ audit_log_format(ab, " op=%s cause=%s", op, cause);
+ break;
+ case AUDIT_INTEGRITY_HASH:
+ audit_log_format(ab, " op=%s hash=%s", op, cause);
+ break;
+ case AUDIT_INTEGRITY_STATUS:
+ default:
+ audit_log_format(ab, " op=%s", op);
+ }
+ audit_log_format(ab, " comm=");
+ audit_log_untrustedstring(ab, current->comm);
+ if (fname) {
+ audit_log_format(ab, " name=");
+ audit_log_untrustedstring(ab, fname);
+ }
+ if (inode)
+ audit_log_format(ab, " dev=%s ino=%lu",
+ inode->i_sb->s_id, inode->i_ino);
+ audit_log_format(ab, " res=%d", result);
+ audit_log_end(ab);
+}
Index: linux-2.6.26-rc3-git2/Documentation/kernel-parameters.txt
===================================================================
--- linux-2.6.26-rc3-git2.orig/Documentation/kernel-parameters.txt
+++ linux-2.6.26-rc3-git2/Documentation/kernel-parameters.txt
@@ -44,6 +44,7 @@ parameter is applicable:
FB The frame buffer device is enabled.
HW Appropriate hardware is enabled.
IA-64 IA-64 architecture is enabled.
+ INTEGRITY Integrity support is enabled.
IOSCHED More than one I/O scheduler is enabled.
IP_PNP IP DHCP, BOOTP, or RARP is enabled.
ISAPNP ISA PnP code is enabled.
@@ -821,6 +822,11 @@ and is between 256 and 4096 characters.
inport.irq= [HW] Inport (ATI XL and Microsoft) busmouse driver
Format: <irq>
+ integrity_audit= [INTEGRITY]
+ Format: { "0" | "1" }
+ 0 -- disable integrity auditing messages.
+ 1 -- enable integrity auditing messages. (Default)
+
inttest= [IA64]
iommu= [x86]
Index: linux-2.6.26-rc3-git2/security/integrity/Makefile
===================================================================
--- /dev/null
+++ linux-2.6.26-rc3-git2/security/integrity/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for the kernel integrity code
+#
+
+# Object file lists
+obj-$(CONFIG_INTEGRITY) += integrity.o integrity_dummy.o \
+ integrity_audit.o integrity_policy.o
Index: linux-2.6.26-rc3-git2/security/integrity/Kconfig
===================================================================
--- /dev/null
+++ linux-2.6.26-rc3-git2/security/integrity/Kconfig
@@ -0,0 +1,24 @@
+#
+# Integrity configuration
+#
+
+menu "Integrity options"
+
+config INTEGRITY
+ bool "Enable different integrity models"
+ help
+ This allows you to choose different integrity modules to be
+ configured into your kernel.
+
+ If you are unsure how to answer this question, answer N.
+
+config INTEGRITY_AUDIT
+ bool "Integrity audit boot parameter"
+ depends on INTEGRITY
+ default y
+ help
+ This option adds a kernel parameter 'integrity_audit', which
+ allows integrity auditing to be disabled at boot. If this
+ option is selected, integrity auditing can be disabled with
+ 'integrity_audit=0' on the kernel command line.
+endmenu
Index: linux-2.6.26-rc3-git2/security/Kconfig
===================================================================
--- linux-2.6.26-rc3-git2.orig/security/Kconfig
+++ linux-2.6.26-rc3-git2/security/Kconfig
@@ -4,6 +4,8 @@
menu "Security options"
+source security/integrity/Kconfig
+
config KEYS
bool "Enable access key retention support"
help
Index: linux-2.6.26-rc3-git2/fs/exec.c
===================================================================
--- linux-2.6.26-rc3-git2.orig/fs/exec.c
+++ linux-2.6.26-rc3-git2/fs/exec.c
@@ -47,6 +47,7 @@
#include <linux/ptrace.h>
#include <linux/mount.h>
#include <linux/security.h>
+#include <linux/integrity.h>
#include <linux/syscalls.h>
#include <linux/rmap.h>
#include <linux/tsacct_kern.h>
@@ -1192,6 +1193,9 @@ int search_binary_handler(struct linux_b
retval = security_bprm_check(bprm);
if (retval)
return retval;
+ retval = integrity_bprm_check(bprm);
+ if (retval)
+ return retval;
/* kernel module loader fixup */
/* so we don't try to load run modprobe in kernel space. */
Index: linux-2.6.26-rc3-git2/fs/namei.c
===================================================================
--- linux-2.6.26-rc3-git2.orig/fs/namei.c
+++ linux-2.6.26-rc3-git2/fs/namei.c
@@ -24,6 +24,7 @@
#include <linux/fsnotify.h>
#include <linux/personality.h>
#include <linux/security.h>
+#include <linux/integrity.h>
#include <linux/syscalls.h>
#include <linux/mount.h>
#include <linux/audit.h>
@@ -286,7 +287,10 @@ int permission(struct inode *inode, int
if (retval)
return retval;
- return security_inode_permission(inode, mask, nd);
+ retval = security_inode_permission(inode, mask, nd);
+ if (retval)
+ return retval;
+ return integrity_inode_permission(inode, mask, nd);
}
/**
@@ -462,6 +466,7 @@ static struct dentry * cached_lookup(str
static int exec_permission_lite(struct inode *inode,
struct nameidata *nd)
{
+ int retval;
umode_t mode = inode->i_mode;
if (inode->i_op && inode->i_op->permission)
@@ -486,7 +491,10 @@ static int exec_permission_lite(struct i
return -EACCES;
ok:
- return security_inode_permission(inode, MAY_EXEC, nd);
+ retval = security_inode_permission(inode, MAY_EXEC, nd);
+ if (retval)
+ return retval;
+ return integrity_inode_permission(inode, MAY_EXEC, nd);
}
/*
Index: linux-2.6.26-rc3-git2/mm/mmap.c
===================================================================
--- linux-2.6.26-rc3-git2.orig/mm/mmap.c
+++ linux-2.6.26-rc3-git2/mm/mmap.c
@@ -20,6 +20,7 @@
#include <linux/fs.h>
#include <linux/personality.h>
#include <linux/security.h>
+#include <linux/integrity.h>
#include <linux/hugetlb.h>
#include <linux/profile.h>
#include <linux/module.h>
@@ -1036,6 +1037,9 @@ unsigned long do_mmap_pgoff(struct file
error = security_file_mmap(file, reqprot, prot, flags, addr, 0);
if (error)
return error;
+ error = integrity_file_mmap(file, reqprot, prot, flags, addr, 0);
+ if (error)
+ return error;
return mmap_region(file, addr, len, flags, vm_flags, pgoff,
accountable);
Index: linux-2.6.26-rc3-git2/security/integrity/integrity_policy.c
===================================================================
--- /dev/null
+++ linux-2.6.26-rc3-git2/security/integrity/integrity_policy.c
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2008 IBM Corporation
+ * Author: Mimi Zohar <zohar@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2 of the License.
+ *
+ * integrity_policy.c
+ * - initialize default measure policy rules
+ - load a policy ruleset
+ *
+ */
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/audit.h>
+#include <linux/security.h>
+#include <linux/integrity.h>
+
+#define security_filter_rule_init security_audit_rule_init
+#define security_filter_rule_match security_audit_rule_match
+
+struct integrity_measure_rule_entry {
+ struct list_head list;
+ void *lsm_obj_rule;
+ void *lsm_subj_rule;
+ enum lim_hooks func;
+ int mask;
+};
+
+
+static struct integrity_measure_rule_entry default_rules[] = {
+ {{NULL, NULL}, NULL, NULL, FILE_MMAP, MAY_EXEC},
+ {{NULL, NULL}, NULL, NULL, BPRM_CHECK, MAY_EXEC},
+ {{NULL, NULL}, NULL, NULL, INODE_PERMISSION, MAY_READ},
+};
+static struct list_head measure_default_rules;
+static struct list_head measure_policy_rules;
+static struct list_head *integrity_measure;
+
+static DEFINE_MUTEX(integrity_measure_mutex);
+
+/**
+ * integrity_measure_rules - determine whether an inode matches the given rule.
+ * @rule: a pointer to a rule
+ * @inode: a pointer to an inode
+ * @func: LIM hook identifier
+ * @mask: requested action (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC)
+ *
+ * Returns 1 on rule match, 0 on failure.
+ */
+static int integrity_measure_rules(struct integrity_measure_rule_entry *rule,
+ struct inode *inode, enum lim_hooks func,
+ int mask)
+{
+ int result = 1;
+
+ if (result && (rule->func != 0)) {
+ if (rule->func != func)
+ result = 0;
+ }
+ if (result && (rule->mask != 0)) {
+ if (rule->mask != mask)
+ result = 0;
+ }
+ if (result && rule->lsm_subj_rule) {
+ struct task_struct *tsk = current;
+ u32 sid;
+
+ security_task_getsecid(tsk, &sid);
+ result = security_filter_rule_match(sid, AUDIT_SUBJ_USER,
+ AUDIT_EQUAL,
+ rule->lsm_subj_rule, NULL);
+ }
+ if (result && rule->lsm_obj_rule) {
+ u32 osid;
+
+ security_inode_getsecid(inode, &osid);
+ result = security_filter_rule_match(osid, AUDIT_OBJ_USER,
+ AUDIT_EQUAL,
+ rule->lsm_obj_rule, NULL);
+ }
+ return result;
+}
+
+/**
+ * integrity_measure_policy - decision based on LSM subj/obj, func, and mask
+ * @inode: pointer to an inode
+ * @func: LIM hook identifier
+ * @mask: requested action (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC)
+ *
+ * Returns 1 on rule match, 0 on failure.
+ */
+int integrity_measure_policy(struct inode *inode, enum lim_hooks func, int mask)
+{
+ struct integrity_measure_rule_entry *entry;
+ int rc = 0;
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(entry, integrity_measure, list) {
+ rc = integrity_measure_rules(entry, inode, func, mask);
+ if (rc) {
+ rcu_read_unlock();
+ return rc;
+ }
+ }
+ rcu_read_unlock();
+ return rc;
+}
+
+/**
+ * integrity_measure_policy_init - initialize the default and policy rules.
+ */
+void integrity_measure_policy_init(void)
+{
+ int i;
+
+ INIT_LIST_HEAD(&measure_default_rules);
+ for (i = 0; i < ARRAY_SIZE(default_rules); i++)
+ list_add(&default_rules[i].list, &measure_default_rules);
+ integrity_measure = &measure_default_rules;
+ mutex_init(&integrity_measure_mutex);
+
+ INIT_LIST_HEAD(&measure_policy_rules);
+}
+
+/**
+ * integrity_measure_policy_complete - replace default_rules with new rules
+ *
+ * Wait to replace the default rules with a complete set of new rules.
+ */
+void integrity_measure_policy_complete(void)
+{
+ char *op = "policy_update";
+ char *cause = "already exists";
+ int result = 1;
+
+ if (integrity_measure == &measure_default_rules) {
+ integrity_measure = &measure_policy_rules;
+ cause = "complete";
+ result = 0;
+ }
+ integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL,
+ NULL, op, cause, result);
+}
+
+/**
+ * integrity_measure_rule_add - add integrity measure rules
+ * @subj: pointer to an LSM subject value
+ * @obj: pointer to an LSM object value
+ * @func: LIM hook identifier
+ * @mask: requested action (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC)
+ *
+ * Returns 0 on success, an error code on failure.
+ */
+int integrity_measure_rule_add(char *subj, char *obj, char *func, char *mask)
+{
+ struct integrity_measure_rule_entry *entry;
+ int result = 0;
+
+ /* Prevent installed policy from changing */
+ if (integrity_measure != &measure_default_rules) {
+ integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL,
+ NULL, "policy_update", "already exists", 1);
+ return -EACCES;
+ }
+
+ entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
+ INIT_LIST_HEAD(&entry->list);
+ if (!result && subj)
+ result = security_filter_rule_init(AUDIT_SUBJ_USER, AUDIT_EQUAL,
+ subj, &entry->lsm_subj_rule);
+ if (!result && obj)
+ result = security_filter_rule_init(AUDIT_OBJ_USER, AUDIT_EQUAL,
+ obj, &entry->lsm_obj_rule);
+ if (!result && func) {
+ if (strcmp(func, "INODE_PERMISSION") == 0)
+ entry->func = INODE_PERMISSION;
+ else if (strcmp(func, "FILE_MMAP") == 0)
+ entry->func = FILE_MMAP;
+ else if (strcmp(func, "BPRM_CHECK") == 0)
+ entry->func = BPRM_CHECK;
+ else
+ result = -EINVAL;
+ }
+ if (!result && mask) {
+ if (strcmp(mask, "MAY_EXEC") == 0)
+ entry->mask = MAY_EXEC;
+ else if (strcmp(mask, "MAY_WRITE") == 0)
+ entry->mask = MAY_WRITE;
+ else if (strcmp(mask, "MAY_READ") == 0)
+ entry->mask = MAY_READ;
+ else if (strcmp(mask, "MAY_APPEND") == 0)
+ entry->mask = MAY_APPEND;
+ else
+ result = -EINVAL;
+ }
+ if (!result) {
+ mutex_lock(&integrity_measure_mutex);
+ list_add_tail(&entry->list, &measure_policy_rules);
+ mutex_unlock(&integrity_measure_mutex);
+ }
+ return result;
+}
Index: linux-2.6.26-rc3-git2/security/Makefile
===================================================================
--- linux-2.6.26-rc3-git2.orig/security/Makefile
+++ linux-2.6.26-rc3-git2/security/Makefile
@@ -19,3 +19,7 @@ obj-$(CONFIG_SECURITY_SMACK) += commonc
obj-$(CONFIG_SECURITY_CAPABILITIES) += commoncap.o capability.o
obj-$(CONFIG_SECURITY_ROOTPLUG) += commoncap.o root_plug.o
obj-$(CONFIG_CGROUP_DEVICE) += device_cgroup.o
+
+# Object integrity file lists
+subdir-$(CONFIG_INTEGRITY) += integrity
+obj-$(CONFIG_INTEGRITY) += integrity/built-in.o
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [RFC][PATCH 4/5]integrity: Linux Integrity Module(LIM)
2008-05-23 15:05 [RFC][PATCH 4/5]integrity: Linux Integrity Module(LIM) Mimi Zohar
2008-05-23 23:30 ` Randy Dunlap
@ 2008-05-28 7:46 ` Andrew Morton
2008-05-29 2:46 ` Mimi Zohar
1 sibling, 1 reply; 9+ messages in thread
From: Andrew Morton @ 2008-05-28 7:46 UTC (permalink / raw)
To: Mimi Zohar
Cc: linux-kernel, safford, serue, sailer, zohar, Stephen Smalley,
CaseySchaufler
On Fri, 23 May 2008 11:05:33 -0400 Mimi Zohar <zohar@linux.vnet.ibm.com> wrote:
> This is a request for comments for a redesign of the integrity patches.
>
> ...
>
> +int register_template(char *template_name,
> + struct template_operations *template_ops)
> +{
> + int template_len;
> + struct template_list_entry *entry;
> +
> + if (!template_initialized++) {
> + INIT_LIST_HEAD(&integrity_templates);
> + mutex_init(&integrity_templates_mutex);
> + }
> +
> + entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
> + INIT_LIST_HEAD(&entry->template);
> +
> + template_len = strlen(template_name);
> + if (template_len > TEMPLATE_NAME_LEN_MAX)
> + template_len = TEMPLATE_NAME_LEN_MAX;
> + memcpy(entry->template_name, template_name, template_len);
> + entry->template_name[template_len] = '\0';
> + entry->template_ops = template_ops;
> +
> + mutex_lock(&integrity_templates_mutex);
> + list_add_rcu(&entry->template, &integrity_templates);
> + mutex_unlock(&integrity_templates_mutex);
> + synchronize_rcu();
> +
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(register_template);
Should be integrity_register_template()?
> +/**
> + * unregister_template
> + * @template_name: a pointer to a string containing the template name.
> + *
> + * Unregister the template functions
> + */
> +int unregister_template(char *template_name)
> +{
> + struct template_list_entry *entry;
> +
> + mutex_lock(&integrity_templates_mutex);
> + list_for_each_entry(entry, &integrity_templates, template) {
> + if (strncmp(entry->template_name, template_name,
> + strlen(entry->template_name)) == 0) {
> + list_del_rcu(&entry->template);
> + mutex_unlock(&integrity_templates_mutex);
> + synchronize_rcu();
> + kfree(entry);
> + return 0;
> + }
> + }
> + mutex_unlock(&integrity_templates_mutex);
> + return -EINVAL;
> +}
> +EXPORT_SYMBOL_GPL(unregister_template);
Similarly.
> +/**
> + * integrity_find_template
> + * @template_name: a pointer to a string containing the template name.
> + * @template_ops: a pointer to the template functions
> + *
> + * Find the template functions based on the template name.
> + */
> +int integrity_find_template(char *template_name,
> + struct template_operations **template_ops)
> +{
> + struct template_list_entry *entry;
> +
> + rcu_read_lock();
> + list_for_each_entry_rcu(entry, &integrity_templates, template) {
> + if (strncmp(entry->template_name, template_name,
> + strlen(entry->template_name)) == 0) {
> + *template_ops = entry->template_ops;
> + rcu_read_unlock();
> + return 0;
> + }
> + }
> + rcu_read_unlock();
> + return 1;
> +}
> +EXPORT_SYMBOL_GPL(integrity_find_template);
Strange locking. We take the rcu_read_lock then locate a pointer to an
object then drop the lock, returning that pointer while doing nothing
to ensure the stability of the returned object?
>
> ...
>
> +#define set_to_dummy_if_null(ops, function) \
> + do { \
> + if (!ops->function) { \
> + ops->function = dummy_##function; \
> + printk(KERN_INFO "Had to override the " #function \
> + " integrity operation with the dummy one.\n");\
> + } \
> + } while (0)
hrm.
Probably the message should identify where it came from? "integrity:
had to override ..."
>
> ...
>
> @@ -1036,6 +1038,7 @@ struct dentry *d_instantiate_unique(stru
> spin_unlock(&dcache_lock);
>
> if (!result) {
> + integrity_d_instantiate(entry, inode);
> security_d_instantiate(entry, inode);
> return NULL;
> }
> @@ -1173,6 +1176,7 @@ struct dentry *d_splice_alias(struct ino
> BUG_ON(!(new->d_flags & DCACHE_DISCONNECTED));
> fsnotify_d_instantiate(new, inode);
> spin_unlock(&dcache_lock);
> + integrity_d_instantiate(new, inode);
> security_d_instantiate(new, inode);
> d_rehash(dentry);
> d_move(new, dentry);
> @@ -1183,6 +1187,7 @@ struct dentry *d_splice_alias(struct ino
> dentry->d_inode = inode;
> fsnotify_d_instantiate(dentry, inode);
> spin_unlock(&dcache_lock);
> + integrity_d_instantiate(dentry, inode);
> security_d_instantiate(dentry, inode);
> d_rehash(dentry);
> }
> @@ -1733,6 +1738,7 @@ found:
> spin_unlock(&dcache_lock);
> out_nolock:
> if (actual == dentry) {
> + integrity_d_instantiate(dentry, inode);
> security_d_instantiate(dentry, inode);
> return NULL;
> }
I'm trying to find a non-trivial ->d_instantiate() implementation to
see how much overhead is being added to these performance-critical
codepaths, but afaict this patchset doesn't add one?
> Index: linux-2.6.26-rc3-git2/fs/ext3/xattr_security.c
> ===================================================================
> --- linux-2.6.26-rc3-git2.orig/fs/ext3/xattr_security.c
> +++ linux-2.6.26-rc3-git2/fs/ext3/xattr_security.c
> @@ -9,6 +9,7 @@
> #include <linux/ext3_jbd.h>
> #include <linux/ext3_fs.h>
> #include <linux/security.h>
> +#include <linux/integrity.h>
> #include "xattr.h"
>
> static size_t
> @@ -57,12 +58,19 @@ ext3_init_security(handle_t *handle, str
>
> err = security_inode_init_security(inode, dir, &name, &value, &len);
> if (err) {
> + /* Even if creation of the security xattr fails, must
> + * indicate this is a new inode. */
> + integrity_inode_init_integrity(inode, dir, NULL, NULL, NULL);
> if (err == -EOPNOTSUPP)
> return 0;
> return err;
> }
> err = ext3_xattr_set_handle(handle, inode, EXT3_XATTR_INDEX_SECURITY,
> name, value, len, 0);
> +
> + integrity_inode_init_integrity(inode, dir, &name, &value, &len);
> + err = ext3_xattr_set_handle(handle, inode, EXT3_XATTR_INDEX_SECURITY,
> + name, value, len, 0);
Can we put the integrity_inode_init_integrity() call into
security_inode_init_security() thus avoiding having to change lots of
filesystems?
> kfree(name);
> kfree(value);
> return err;
>
> ...
>
> @@ -17,6 +17,7 @@
> #include <linux/hash.h>
> #include <linux/swap.h>
> #include <linux/security.h>
> +#include <linux/integrity.h>
> #include <linux/pagemap.h>
> #include <linux/cdev.h>
> #include <linux/bootmem.h>
> @@ -160,6 +161,14 @@ static struct inode *alloc_inode(struct
> init_rwsem(&inode->i_alloc_sem);
> lockdep_set_class(&inode->i_alloc_sem, &sb->s_type->i_alloc_sem_key);
>
> + if (integrity_inode_alloc(inode)) {
> + if (inode->i_sb->s_op->destroy_inode)
> + inode->i_sb->s_op->destroy_inode(inode);
> + else
> + kmem_cache_free(inode_cachep, (inode));
> + return NULL;
> + }
This code is uncommented and integrity_inode_alloc() also is
uncommented. People will want to know what's going on, please.
Again, where do we go to see how much overhead is being added to these
codepaths?
> mapping->a_ops = &empty_aops;
> mapping->host = inode;
> mapping->flags = 0;
> @@ -190,6 +199,7 @@ void destroy_inode(struct inode *inode)
> {
> BUG_ON(inode_has_buffers(inode));
> security_inode_free(inode);
> + integrity_inode_free(inode);
> if (inode->i_sb->s_op->destroy_inode)
> inode->i_sb->s_op->destroy_inode(inode);
> else
>
> ...
>
> --- linux-2.6.26-rc3-git2.orig/include/linux/fs.h
> +++ linux-2.6.26-rc3-git2/include/linux/fs.h
> @@ -653,6 +653,9 @@ struct inode {
> #ifdef CONFIG_SECURITY
> void *i_security;
> #endif
> +#ifdef CONFIG_INTEGRITY
> + void *i_integrity;
> +#endif
Does this _have_ to be a void*? Something typesafe would be far
preferable.
> void *i_private; /* fs or device private pointer */
> };
>
> ...
>
> @@ -521,6 +528,7 @@ extern int audit_signals;
> #define audit_get_loginuid(t) (-1)
> #define audit_get_sessionid(t) (-1)
> #define audit_log_task_context(b) do { ; } while (0)
> +#define audit_log_inode_context(b, a) do { ; } while (0)
static inline C functions are preferable.
The ";" inside the {} is unneeded.
> #define audit_ipc_obj(i) ({ 0; })
> #define audit_ipc_set_perm(q,u,g,m) ({ 0; })
> #define audit_bprm(p) ({ 0; })
> Index: linux-2.6.26-rc3-git2/security/integrity/integrity_audit.c
> ===================================================================
> --- /dev/null
> +++ linux-2.6.26-rc3-git2/security/integrity/integrity_audit.c
> @@ -0,0 +1,73 @@
> +/*
> + * Copyright (C) 2008 IBM Corporation
> + * Author: Mimi Zohar <zohar@us.ibm.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation, version 2 of the License.
> + *
> + * File: integrity_audit.c
> + * Audit calls for the integrity subsystem
> + */
> +
> +#include <linux/audit.h>
> +#include <linux/fs.h>
> +#include <linux/integrity.h>
> +
> +#ifdef CONFIG_INTEGRITY_AUDIT
> +static int integrity_audit = 1;
> +
> +static int __init integrity_audit_setup(char *str)
> +{
> + char *op;
> +
> + integrity_audit = simple_strtol(str, NULL, 0);
This will treat "42foo" as valid input. strict_strtoul() fixes that.
> + op = integrity_audit ? "integrity_audit_enabled" :
> + "integrity_audit_not_enabled";
> + integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, NULL, NULL, op, 0);
> + return 1;
> +}
> +
> +__setup("integrity_audit=", integrity_audit_setup);
> +#else
> +static int integrity_audit = 1;
This could be outside the ifdef. If it is correct?
> +#endif
> +
> +void integrity_audit_msg(int audit_msgno, struct inode *inode,
> + const unsigned char *fname, char *op,
> + char *cause, int result)
> +{
> + struct audit_buffer *ab;
> + if (!integrity_audit && result == 1)
> + return;
A newline between end-of-declarations and start-of-code is conventional.
> + ab = audit_log_start(current->audit_context, GFP_ATOMIC, audit_msgno);
> + audit_log_format(ab, "integrity: pid=%d uid=%u auid=%u",
> + current->pid, current->uid,
> + audit_get_loginuid(current));
> + audit_log_task_context(ab);
> + switch (audit_msgno) {
> + case AUDIT_INTEGRITY_DATA:
> + case AUDIT_INTEGRITY_METADATA:
> + case AUDIT_INTEGRITY_PCR:
> + audit_log_format(ab, " op=%s cause=%s", op, cause);
> + break;
> + case AUDIT_INTEGRITY_HASH:
> + audit_log_format(ab, " op=%s hash=%s", op, cause);
> + break;
> + case AUDIT_INTEGRITY_STATUS:
> + default:
> + audit_log_format(ab, " op=%s", op);
> + }
> + audit_log_format(ab, " comm=");
> + audit_log_untrustedstring(ab, current->comm);
> + if (fname) {
> + audit_log_format(ab, " name=");
> + audit_log_untrustedstring(ab, fname);
> + }
> + if (inode)
> + audit_log_format(ab, " dev=%s ino=%lu",
> + inode->i_sb->s_id, inode->i_ino);
> + audit_log_format(ab, " res=%d", result);
> + audit_log_end(ab);
> +}
>
> ...
>
> +static struct integrity_measure_rule_entry default_rules[] = {
> + {{NULL, NULL}, NULL, NULL, FILE_MMAP, MAY_EXEC},
> + {{NULL, NULL}, NULL, NULL, BPRM_CHECK, MAY_EXEC},
> + {{NULL, NULL}, NULL, NULL, INODE_PERMISSION, MAY_READ},
> +};
Can we use the
.field = value,
format here please? That will permit the omission of all the NULLs.
> +static struct list_head measure_default_rules;
> +static struct list_head measure_policy_rules;
> +static struct list_head *integrity_measure;
> +
> +static DEFINE_MUTEX(integrity_measure_mutex);
> +
> +/**
> + * integrity_measure_rules - determine whether an inode matches the given rule.
> + * @rule - a pointer to a rule
> + * @inode - a pointer to an inode
> + * @func - LIM hook identifier
> + * @mask - requested action (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC)
> + *
> + * Returns 1 on rule match, 0 on failure.
> + */
What a strange name. integrity_match_rules()?
Could return a bool type, if you like that sort of thing.
> +static int integrity_measure_rules(struct integrity_measure_rule_entry *rule,
> + struct inode *inode, enum lim_hooks func,
> + int mask)
> +{
> + int result = 1;
> +
> + if (result && (rule->func != 0)) {
The test of the known-to-be-non-zero `result' is a bit weird, btu I
guess it makes sense in context, and the compiler should elide it OK.
> + if (rule->func != func)
> + result = 0;
> + }
> + if (result && (rule->mask != 0)) {
> + if (rule->mask != mask)
> + result = 0;
> + }
> + if (result && rule->lsm_subj_rule) {
> + struct task_struct *tsk = current;
> + u32 sid;
> +
> + security_task_getsecid(tsk, &sid);
> + result = security_filter_rule_match(sid, AUDIT_SUBJ_USER,
> + AUDIT_EQUAL,
> + rule->lsm_subj_rule, NULL);
> + }
> + if (result && rule->lsm_obj_rule) {
> + u32 osid;
> +
> + security_inode_getsecid(inode, &osid);
> + result = security_filter_rule_match(osid, AUDIT_OBJ_USER,
> + AUDIT_EQUAL,
> + rule->lsm_obj_rule, NULL);
> + }
> + return result;
> +}
However the shole function could be simplified and sped up (depending
on how smart the compiler is) via:
if (rule->func && rule->func != func)
return 0;
if (rule->mask && rule->mask != mask)
return 0;
...
return 1;
}
or similar.
> +/**
> + * integrity_measure_policy - base measure decision on: subj, obj, LIM hook,
> + * and mask
> + * @inode - pointer to an inode
> + * @func - LIM hook identifier
> + * @mask - requested action (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC)
> + *
> + * Returns 1 on rule match, 0 on failure.
> + */
> +int integrity_measure_policy(struct inode *inode, enum lim_hooks func, int mask)
> +{
> + struct integrity_measure_rule_entry *entry;
> + int rc = 0;
> +
> + rcu_read_lock();
> + list_for_each_entry_rcu(entry, integrity_measure, list) {
> + rc = integrity_measure_rules(entry, inode, func, mask);
> + if (rc) {
> + rcu_read_unlock();
> + return rc;
> + }
> + }
> + rcu_read_unlock();
> + return rc;
> +}
"measure"? Or "match"?
> +/**
> + * integrity_measure_policy_init - initialize the default and policy rules.
> + */
> +void integrity_measure_policy_init(void)
> +{
> + int i;
> +
> + INIT_LIST_HEAD(&measure_default_rules);
> + for (i = 0; i < ARRAY_SIZE(default_rules); i++)
> + list_add(&default_rules[i].list, &measure_default_rules);
> + integrity_measure = &measure_default_rules;
> + mutex_init(&integrity_measure_mutex);
The mutex_init() is unneeded.
> + INIT_LIST_HEAD(&measure_policy_rules);
> +}
> +
> +/**
> + * integrity_measure_policy_complete - wait to replace default_rules with
> + * a complete policy ruleset.
> + */
> +void integrity_measure_policy_complete(void)
> +{
> + char *op = "policy_update";
> + char *cause = "already exists";
> + int result = 1;
> +
> + if (integrity_measure == &measure_default_rules) {
> + integrity_measure = &measure_policy_rules;
> + cause = "complete";
> + result = 0;
> + }
> + integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL,
> + NULL, op, cause, result);
> +}
Does it actually "wait"?
The name again doesn't seem to match the behaviour. "foo_complete"
would mean "tell listeners that foo has completed". What you have here
is a "foo_wait".
> +/**
> + * integrity_measure_rule_add - add integrity measure rules
> + * @subj - pointer to an LSM subject value
> + * @obj - pointer to an LSM object value
> + * @func - LIM hook identifier
> + * @mask - requested action (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC)
> + *
> + * Returns 0 on success, an error code on failure.
> + */
> +int integrity_measure_rule_add(char *subj, char *obj, char *func, char *mask)
> +{
> + struct integrity_measure_rule_entry *entry;
> + int result = 0;
> +
> + /* Prevent installed policy from changing */
> + if (integrity_measure != &measure_default_rules) {
> + integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL,
> + NULL, "policy_update", "already exists", 1);
> + return -EACCES;
> + }
> +
> + entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
GFP_ATOMIC is unreliable. GFP_KERNEL is much much preferable, and I
suspect that it can be used here?
> + INIT_LIST_HEAD(&entry->list);
> + if (!result && subj)
> + result = security_filter_rule_init(AUDIT_SUBJ_USER, AUDIT_EQUAL,
> + subj, &entry->lsm_subj_rule);
> + if (!result && obj)
> + result = security_filter_rule_init(AUDIT_OBJ_USER, AUDIT_EQUAL,
> + obj, &entry->lsm_obj_rule);
> + if (!result && func) {
> + if (strcmp(func, "INODE_PERMISSION") == 0)
> + entry->func = INODE_PERMISSION;
> + else if (strcmp(func, "FILE_MMAP") == 0)
> + entry->func = FILE_MMAP;
> + else if (strcmp(func, "BPRM_CHECK") == 0)
> + entry->func = BPRM_CHECK;
> + else
> + result = -EINVAL;
> + }
> + if (!result && mask) {
> + if (strcmp(mask, "MAY_EXEC") == 0)
> + entry->mask = MAY_EXEC;
> + else if (strcmp(mask, "MAY_WRITE") == 0)
> + entry->mask = MAY_WRITE;
> + else if (strcmp(mask, "MAY_READ") == 0)
> + entry->mask = MAY_READ;
> + else if (strcmp(mask, "MAY_APPEND") == 0)
> + entry->mask = MAY_APPEND;
> + else
> + result = -EINVAL;
> + }
> + if (!result) {
> + mutex_lock(&integrity_measure_mutex);
> + list_add_tail(&entry->list, &measure_policy_rules);
> + mutex_unlock(&integrity_measure_mutex);
> + }
> + return result;
> +}
>
> ...
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [RFC][PATCH 4/5]integrity: Linux Integrity Module(LIM)
2008-05-28 7:46 ` Andrew Morton
@ 2008-05-29 2:46 ` Mimi Zohar
2008-05-29 4:46 ` James Morris
0 siblings, 1 reply; 9+ messages in thread
From: Mimi Zohar @ 2008-05-29 2:46 UTC (permalink / raw)
To: Andrew Morton
Cc: linux-kernel, safford, serue, sailer, zohar, Stephen Smalley,
CaseySchaufler
On Wed, 2008-05-28 at 00:46 -0700, Andrew Morton wrote:
> On Fri, 23 May 2008 11:05:33 -0400 Mimi Zohar <zohar@linux.vnet.ibm.com> wrote:
>
> > This is a request for comments for a redesign of the integrity patches.
> >
> > ...
> >
> > +int register_template(char *template_name,
> > + struct template_operations *template_ops)
> > +{
> > + int template_len;
> > + struct template_list_entry *entry;
> > +
> > + if (!template_initialized++) {
> > + INIT_LIST_HEAD(&integrity_templates);
> > + mutex_init(&integrity_templates_mutex);
> > + }
> > +
> > + entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
> > + INIT_LIST_HEAD(&entry->template);
> > +
> > + template_len = strlen(template_name);
> > + if (template_len > TEMPLATE_NAME_LEN_MAX)
> > + template_len = TEMPLATE_NAME_LEN_MAX;
> > + memcpy(entry->template_name, template_name, template_len);
> > + entry->template_name[template_len] = '\0';
> > + entry->template_ops = template_ops;
> > +
> > + mutex_lock(&integrity_templates_mutex);
> > + list_add_rcu(&entry->template, &integrity_templates);
> > + mutex_unlock(&integrity_templates_mutex);
> > + synchronize_rcu();
> > +
> > + return 0;
> > +}
> > +EXPORT_SYMBOL_GPL(register_template);
>
> Should be integrity_register_template()?
yes, definitely.
> > +/**
> > + * unregister_template
> > + * @template_name: a pointer to a string containing the template name.
> > + *
> > + * Unregister the template functions
> > + */
> > +int unregister_template(char *template_name)
> > +{
> > + struct template_list_entry *entry;
> > +
> > + mutex_lock(&integrity_templates_mutex);
> > + list_for_each_entry(entry, &integrity_templates, template) {
> > + if (strncmp(entry->template_name, template_name,
> > + strlen(entry->template_name)) == 0) {
> > + list_del_rcu(&entry->template);
> > + mutex_unlock(&integrity_templates_mutex);
> > + synchronize_rcu();
> > + kfree(entry);
> > + return 0;
> > + }
> > + }
> > + mutex_unlock(&integrity_templates_mutex);
> > + return -EINVAL;
> > +}
> > +EXPORT_SYMBOL_GPL(unregister_template);
>
> Similarly.
Ok
> > +/**
> > + * integrity_find_template
> > + * @template_name: a pointer to a string containing the template name.
> > + * @template_ops: a pointer to the template functions
> > + *
> > + * Find the template functions based on the template name.
> > + */
> > +int integrity_find_template(char *template_name,
> > + struct template_operations **template_ops)
> > +{
> > + struct template_list_entry *entry;
> > +
> > + rcu_read_lock();
> > + list_for_each_entry_rcu(entry, &integrity_templates, template) {
> > + if (strncmp(entry->template_name, template_name,
> > + strlen(entry->template_name)) == 0) {
> > + *template_ops = entry->template_ops;
> > + rcu_read_unlock();
> > + return 0;
> > + }
> > + }
> > + rcu_read_unlock();
> > + return 1;
> > +}
> > +EXPORT_SYMBOL_GPL(integrity_find_template);
>
> Strange locking. We take the rcu_read_lock then locate a pointer to an
> object then drop the lock, returning that pointer while doing nothing
> to ensure the stability of the returned object?
yep, I messed up the locking here. Will fix it.
> >
> > ...
> >
> > +#define set_to_dummy_if_null(ops, function) \
> > + do { \
> > + if (!ops->function) { \
> > + ops->function = dummy_##function; \
> > + printk(KERN_INFO "Had to override the " #function \
> > + " integrity operation with the dummy one.\n");\
> > + } \
> > + } while (0)
>
> hrm.
>
> Probably the message should identify where it came from? "integrity:
> had to override ..."
Ok.
> >
> > ...
> >
> > @@ -1036,6 +1038,7 @@ struct dentry *d_instantiate_unique(stru
> > spin_unlock(&dcache_lock);
> >
> > if (!result) {
> > + integrity_d_instantiate(entry, inode);
> > security_d_instantiate(entry, inode);
> > return NULL;
> > }
> > @@ -1173,6 +1176,7 @@ struct dentry *d_splice_alias(struct ino
> > BUG_ON(!(new->d_flags & DCACHE_DISCONNECTED));
> > fsnotify_d_instantiate(new, inode);
> > spin_unlock(&dcache_lock);
> > + integrity_d_instantiate(new, inode);
> > security_d_instantiate(new, inode);
> > d_rehash(dentry);
> > d_move(new, dentry);
> > @@ -1183,6 +1187,7 @@ struct dentry *d_splice_alias(struct ino
> > dentry->d_inode = inode;
> > fsnotify_d_instantiate(dentry, inode);
> > spin_unlock(&dcache_lock);
> > + integrity_d_instantiate(dentry, inode);
> > security_d_instantiate(dentry, inode);
> > d_rehash(dentry);
> > }
> > @@ -1733,6 +1738,7 @@ found:
> > spin_unlock(&dcache_lock);
> > out_nolock:
> > if (actual == dentry) {
> > + integrity_d_instantiate(dentry, inode);
> > security_d_instantiate(dentry, inode);
> > return NULL;
> > }
>
> I'm trying to find a non-trivial ->d_instantiate() implementation to
> see how much overhead is being added to these performance-critical
> codepaths, but afaict this patchset doesn't add one?
The current IMA, as a stand alone integrity provider, does not use
integrity_d_instantiate. It was used by EVM to verify the integrity
of the hash and store the results in i_integrity.
(Refer to 2.6.22-rc1-mm1-broken-out.tar.bz2)
We could defer this discussion by removing it for now, as it is not
being used by the IMA.
> > Index: linux-2.6.26-rc3-git2/fs/ext3/xattr_security.c
> > ===================================================================
> > --- linux-2.6.26-rc3-git2.orig/fs/ext3/xattr_security.c
> > +++ linux-2.6.26-rc3-git2/fs/ext3/xattr_security.c
> > @@ -9,6 +9,7 @@
> > #include <linux/ext3_jbd.h>
> > #include <linux/ext3_fs.h>
> > #include <linux/security.h>
> > +#include <linux/integrity.h>
> > #include "xattr.h"
> >
> > static size_t
> > @@ -57,12 +58,19 @@ ext3_init_security(handle_t *handle, str
> >
> > err = security_inode_init_security(inode, dir, &name, &value, &len);
> > if (err) {
> > + /* Even if creation of the security xattr fails, must
> > + * indicate this is a new inode. */
> > + integrity_inode_init_integrity(inode, dir, NULL, NULL, NULL);
> > if (err == -EOPNOTSUPP)
> > return 0;
> > return err;
> > }
> > err = ext3_xattr_set_handle(handle, inode, EXT3_XATTR_INDEX_SECURITY,
> > name, value, len, 0);
> > +
> > + integrity_inode_init_integrity(inode, dir, &name, &value, &len);
> > + err = ext3_xattr_set_handle(handle, inode, EXT3_XATTR_INDEX_SECURITY,
> > + name, value, len, 0);
>
> Can we put the integrity_inode_init_integrity() call into
> security_inode_init_security() thus avoiding having to change lots of
> filesystems?
That is fine by me, not sure how others feel.
> > kfree(name);
> > kfree(value);
> > return err;
> >
> > ...
> >
> > @@ -17,6 +17,7 @@
> > #include <linux/hash.h>
> > #include <linux/swap.h>
> > #include <linux/security.h>
> > +#include <linux/integrity.h>
> > #include <linux/pagemap.h>
> > #include <linux/cdev.h>
> > #include <linux/bootmem.h>
> > @@ -160,6 +161,14 @@ static struct inode *alloc_inode(struct
> > init_rwsem(&inode->i_alloc_sem);
> > lockdep_set_class(&inode->i_alloc_sem, &sb->s_type->i_alloc_sem_key);
> >
> > + if (integrity_inode_alloc(inode)) {
> > + if (inode->i_sb->s_op->destroy_inode)
> > + inode->i_sb->s_op->destroy_inode(inode);
> > + else
> > + kmem_cache_free(inode_cachep, (inode));
> > + return NULL;
> > + }
>
> This code is uncommented and integrity_inode_alloc() also is
> uncommented. People will want to know what's going on, please.
integrity_inode_alloc() is the wrapper which calls inode_alloc_integrity().
It is commented in integrity.h. I'll comment the code here as well.
> Again, where do we go to see how much overhead is being added to these
> codepaths?
The IMA patch(5/5) instantiates the inode_alloc_integrity hook.
.inode_alloc_integrity = ima_inode_alloc_integrity,
> > mapping->a_ops = &empty_aops;
> > mapping->host = inode;
> > mapping->flags = 0;
> > @@ -190,6 +199,7 @@ void destroy_inode(struct inode *inode)
> > {
> > BUG_ON(inode_has_buffers(inode));
> > security_inode_free(inode);
> > + integrity_inode_free(inode);
> > if (inode->i_sb->s_op->destroy_inode)
> > inode->i_sb->s_op->destroy_inode(inode);
> > else
> >
> > ...
> >
> > --- linux-2.6.26-rc3-git2.orig/include/linux/fs.h
> > +++ linux-2.6.26-rc3-git2/include/linux/fs.h
> > @@ -653,6 +653,9 @@ struct inode {
> > #ifdef CONFIG_SECURITY
> > void *i_security;
> > #endif
> > +#ifdef CONFIG_INTEGRITY
> > + void *i_integrity;
> > +#endif
>
> Does this _have_ to be a void*? Something typesafe would be far
> preferable.
Different integrity providers will define it differently, using
their specific data structure.
> > void *i_private; /* fs or device private pointer */
> > };
> >
> > ...
> >
> > @@ -521,6 +528,7 @@ extern int audit_signals;
> > #define audit_get_loginuid(t) (-1)
> > #define audit_get_sessionid(t) (-1)
> > #define audit_log_task_context(b) do { ; } while (0)
> > +#define audit_log_inode_context(b, a) do { ; } while (0)
>
> static inline C functions are preferable.
>
> The ";" inside the {} is unneeded.
Ok
> > #define audit_ipc_obj(i) ({ 0; })
> > #define audit_ipc_set_perm(q,u,g,m) ({ 0; })
> > #define audit_bprm(p) ({ 0; })
> > Index: linux-2.6.26-rc3-git2/security/integrity/integrity_audit.c
> > ===================================================================
> > --- /dev/null
> > +++ linux-2.6.26-rc3-git2/security/integrity/integrity_audit.c
> > @@ -0,0 +1,73 @@
> > +/*
> > + * Copyright (C) 2008 IBM Corporation
> > + * Author: Mimi Zohar <zohar@us.ibm.com>
> > + *
> > + * This program is free software; you can redistribute it and/or modify
> > + * it under the terms of the GNU General Public License as published by
> > + * the Free Software Foundation, version 2 of the License.
> > + *
> > + * File: integrity_audit.c
> > + * Audit calls for the integrity subsystem
> > + */
> > +
> > +#include <linux/audit.h>
> > +#include <linux/fs.h>
> > +#include <linux/integrity.h>
> > +
> > +#ifdef CONFIG_INTEGRITY_AUDIT
> > +static int integrity_audit = 1;
> > +
> > +static int __init integrity_audit_setup(char *str)
> > +{
> > + char *op;
> > +
> > + integrity_audit = simple_strtol(str, NULL, 0);
>
> This will treat "42foo" as valid input. strict_strtoul() fixes that.
Thank you for pointing this out.
> > + op = integrity_audit ? "integrity_audit_enabled" :
> > + "integrity_audit_not_enabled";
> > + integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, NULL, NULL, op, 0);
> > + return 1;
> > +}
> > +
> > +__setup("integrity_audit=", integrity_audit_setup);
> > +#else
> > +static int integrity_audit = 1;
>
> This could be outside the ifdef. If it is correct?
Yes, will fix it.
> > +#endif
> > +
> > +void integrity_audit_msg(int audit_msgno, struct inode *inode,
> > + const unsigned char *fname, char *op,
> > + char *cause, int result)
> > +{
> > + struct audit_buffer *ab;
> > + if (!integrity_audit && result == 1)
> > + return;
>
> A newline between end-of-declarations and start-of-code is conventional.
Of course, don't know how I missed it.
> > + ab = audit_log_start(current->audit_context, GFP_ATOMIC, audit_msgno);
> > + audit_log_format(ab, "integrity: pid=%d uid=%u auid=%u",
> > + current->pid, current->uid,
> > + audit_get_loginuid(current));
> > + audit_log_task_context(ab);
> > + switch (audit_msgno) {
> > + case AUDIT_INTEGRITY_DATA:
> > + case AUDIT_INTEGRITY_METADATA:
> > + case AUDIT_INTEGRITY_PCR:
> > + audit_log_format(ab, " op=%s cause=%s", op, cause);
> > + break;
> > + case AUDIT_INTEGRITY_HASH:
> > + audit_log_format(ab, " op=%s hash=%s", op, cause);
> > + break;
> > + case AUDIT_INTEGRITY_STATUS:
> > + default:
> > + audit_log_format(ab, " op=%s", op);
> > + }
> > + audit_log_format(ab, " comm=");
> > + audit_log_untrustedstring(ab, current->comm);
> > + if (fname) {
> > + audit_log_format(ab, " name=");
> > + audit_log_untrustedstring(ab, fname);
> > + }
> > + if (inode)
> > + audit_log_format(ab, " dev=%s ino=%lu",
> > + inode->i_sb->s_id, inode->i_ino);
> > + audit_log_format(ab, " res=%d", result);
> > + audit_log_end(ab);
> > +}
> >
> > ...
> >
> > +static struct integrity_measure_rule_entry default_rules[] = {
> > + {{NULL, NULL}, NULL, NULL, FILE_MMAP, MAY_EXEC},
> > + {{NULL, NULL}, NULL, NULL, BPRM_CHECK, MAY_EXEC},
> > + {{NULL, NULL}, NULL, NULL, INODE_PERMISSION, MAY_READ},
> > +};
>
> Can we use the
>
> .field = value,
>
> format here please? That will permit the omission of all the NULLs.
np
> > +static struct list_head measure_default_rules;
> > +static struct list_head measure_policy_rules;
> > +static struct list_head *integrity_measure;
> > +
> > +static DEFINE_MUTEX(integrity_measure_mutex);
> > +
> > +/**
> > + * integrity_measure_rules - determine whether an inode matches the given rule.
> > + * @rule - a pointer to a rule
> > + * @inode - a pointer to an inode
> > + * @func - LIM hook identifier
> > + * @mask - requested action (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC)
> > + *
> > + * Returns 1 on rule match, 0 on failure.
> > + */
>
> What a strange name. integrity_match_rules()
The match decision, here, is deciding whether or not to measure
a file.
The functions below are called: integrity_measure_policy_init(),
integrity_measure_policy_complete(), integrity_measure_policy_add().
To parallel the rest of the names, then the function here would be
integrity_measure_rules_match(). Or I could remove 'measure'
from all of the function names, as you're suggesting.
choice 2: integrity_policy_init, integrity_policy_add,
integrity_policy_complete/end, integrity_policy_match,
integrity_rules_match
choice 3: integrity_init_policy, integrity_add_policy,
integrity_complete/end_policy, integrity_match_policy,
integrity_match_rules
> Could return a bool type, if you like that sort of thing.
>
> > +static int integrity_measure_rules(struct integrity_measure_rule_entry *rule,
> > + struct inode *inode, enum lim_hooks func,
> > + int mask)
> > +{
> > + int result = 1;
> > +
> > + if (result && (rule->func != 0)) {
>
> The test of the known-to-be-non-zero `result' is a bit weird, btu I
> guess it makes sense in context, and the compiler should elide it OK.
>
> > + if (rule->func != func)
> > + result = 0;
> > + }
> > + if (result && (rule->mask != 0)) {
> > + if (rule->mask != mask)
> > + result = 0;
> > + }
> > + if (result && rule->lsm_subj_rule) {
> > + struct task_struct *tsk = current;
> > + u32 sid;
> > +
> > + security_task_getsecid(tsk, &sid);
> > + result = security_filter_rule_match(sid, AUDIT_SUBJ_USER,
> > + AUDIT_EQUAL,
> > + rule->lsm_subj_rule, NULL);
> > + }
> > + if (result && rule->lsm_obj_rule) {
> > + u32 osid;
> > +
> > + security_inode_getsecid(inode, &osid);
> > + result = security_filter_rule_match(osid, AUDIT_OBJ_USER,
> > + AUDIT_EQUAL,
> > + rule->lsm_obj_rule, NULL);
> > + }
> > + return result;
> > +}
>
> However the shole function could be simplified and sped up (depending
> on how smart the compiler is) via:
>
> if (rule->func && rule->func != func)
> return 0;
> if (rule->mask && rule->mask != mask)
> return 0;
> ...
> return 1;
> }
>
> or similar.
yes, of course. thanks!
> > +/**
> > + * integrity_measure_policy - base measure decision on: subj, obj, LIM hook,
> > + * and mask
> > + * @inode - pointer to an inode
> > + * @func - LIM hook identifier
> > + * @mask - requested action (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC)
> > + *
> > + * Returns 1 on rule match, 0 on failure.
> > + */
> > +int integrity_measure_policy(struct inode *inode, enum lim_hooks func, int mask)
> > +{
> > + struct integrity_measure_rule_entry *entry;
> > + int rc = 0;
> > +
> > + rcu_read_lock();
> > + list_for_each_entry_rcu(entry, integrity_measure, list) {
> > + rc = integrity_measure_rules(entry, inode, func, mask);
> > + if (rc) {
> > + rcu_read_unlock();
> > + return rc;
> > + }
> > + }
> > + rcu_read_unlock();
> > + return rc;
> > +}
>
> "measure"? Or "match"?
discussion above.
> > +/**
> > + * integrity_measure_policy_init - initialize the default and policy rules.
> > + */
> > +void integrity_measure_policy_init(void)
> > +{
> > + int i;
> > +
> > + INIT_LIST_HEAD(&measure_default_rules);
> > + for (i = 0; i < ARRAY_SIZE(default_rules); i++)
> > + list_add(&default_rules[i].list, &measure_default_rules);
> > + integrity_measure = &measure_default_rules;
> > + mutex_init(&integrity_measure_mutex);
>
> The mutex_init() is unneeded.
Ok
> > + INIT_LIST_HEAD(&measure_policy_rules);
> > +}
> > +
> > +/**
> > + * integrity_measure_policy_complete - wait to replace default_rules with
> > + * a complete policy ruleset.
> > + */
> > +void integrity_measure_policy_complete(void)
> > +{
> > + char *op = "policy_update";
> > + char *cause = "already exists";
> > + int result = 1;
> > +
> > + if (integrity_measure == &measure_default_rules) {
> > + integrity_measure = &measure_policy_rules;
> > + cause = "complete";
> > + result = 0;
> > + }
> > + integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL,
> > + NULL, op, cause, result);
> > +}
>
> Does it actually "wait"?
No, it doesn't wait. The function is called when the file closes,
meaning that all of the rules have been added. Refer to
ima_release_policy() in the IMA patch (5/5). Only after this function
is called, are the new set of rules used.
> The name again doesn't seem to match the behaviour. "foo_complete"
> would mean "tell listeners that foo has completed". What you have here
> is a "foo_wait".
Juxtaposed to the function below called integrity_measure_policy_add(),
how about integrity_measure_policy_end()?
> > +/**
> > + * integrity_measure_rule_add - add integrity measure rules
> > + * @subj - pointer to an LSM subject value
> > + * @obj - pointer to an LSM object value
> > + * @func - LIM hook identifier
> > + * @mask - requested action (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC)
> > + *
> > + * Returns 0 on success, an error code on failure.
> > + */
> > +int integrity_measure_rule_add(char *subj, char *obj, char *func, char *mask)
> > +{
> > + struct integrity_measure_rule_entry *entry;
> > + int result = 0;
> > +
> > + /* Prevent installed policy from changing */
> > + if (integrity_measure != &measure_default_rules) {
> > + integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL,
> > + NULL, "policy_update", "already exists", 1);
> > + return -EACCES;
> > + }
> > +
> > + entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
>
> GFP_ATOMIC is unreliable. GFP_KERNEL is much much preferable, and I
> suspect that it can be used here?
Probably. Will look into it.
> > + INIT_LIST_HEAD(&entry->list);
> > + if (!result && subj)
> > + result = security_filter_rule_init(AUDIT_SUBJ_USER, AUDIT_EQUAL,
> > + subj, &entry->lsm_subj_rule);
> > + if (!result && obj)
> > + result = security_filter_rule_init(AUDIT_OBJ_USER, AUDIT_EQUAL,
> > + obj, &entry->lsm_obj_rule);
> > + if (!result && func) {
> > + if (strcmp(func, "INODE_PERMISSION") == 0)
> > + entry->func = INODE_PERMISSION;
> > + else if (strcmp(func, "FILE_MMAP") == 0)
> > + entry->func = FILE_MMAP;
> > + else if (strcmp(func, "BPRM_CHECK") == 0)
> > + entry->func = BPRM_CHECK;
> > + else
> > + result = -EINVAL;
> > + }
> > + if (!result && mask) {
> > + if (strcmp(mask, "MAY_EXEC") == 0)
> > + entry->mask = MAY_EXEC;
> > + else if (strcmp(mask, "MAY_WRITE") == 0)
> > + entry->mask = MAY_WRITE;
> > + else if (strcmp(mask, "MAY_READ") == 0)
> > + entry->mask = MAY_READ;
> > + else if (strcmp(mask, "MAY_APPEND") == 0)
> > + entry->mask = MAY_APPEND;
> > + else
> > + result = -EINVAL;
> > + }
> > + if (!result) {
> > + mutex_lock(&integrity_measure_mutex);
> > + list_add_tail(&entry->list, &measure_policy_rules);
> > + mutex_unlock(&integrity_measure_mutex);
> > + }
> > + return result;
> > +}
> >
> > ...
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [RFC][PATCH 4/5]integrity: Linux Integrity Module(LIM)
2008-05-29 2:46 ` Mimi Zohar
@ 2008-05-29 4:46 ` James Morris
0 siblings, 0 replies; 9+ messages in thread
From: James Morris @ 2008-05-29 4:46 UTC (permalink / raw)
To: Mimi Zohar
Cc: Andrew Morton, linux-kernel, safford, serue, sailer, zohar,
Stephen Smalley, CaseySchaufler
On Wed, 28 May 2008, Mimi Zohar wrote:
> > Can we put the integrity_inode_init_integrity() call into
> > security_inode_init_security() thus avoiding having to change lots of
> > filesystems?
>
> That is fine by me, not sure how others feel.
I agree it makes sense to do this.
--
James Morris
<jmorris@namei.org>
^ permalink raw reply [flat|nested] 9+ messages in thread
* [RFC][PATCH 4/5] integrity: Linux Integrity Module(LIM)
[not found] <20080627131946.225566613@linux.vnet.ibm.com>
@ 2008-06-27 16:23 ` Mimi Zohar
2008-06-30 10:43 ` James Morris
0 siblings, 1 reply; 9+ messages in thread
From: Mimi Zohar @ 2008-06-27 16:23 UTC (permalink / raw)
To: linux-kernel; +Cc: David Safford, Serge Hallyn, Reiner Sailer, Mimi Zohar
This is a request for comments for a redesign of the integrity patches.
The new version addresses a number of issues, including
- generalizing the measurement API beyond just inode measurements.
- separation of the measurement into distinct collection, appraisal,
and commitment phases, for greater flexibility.
Extended Verification Module(EVM) and the Integrity Measurement
Architecture(IMA) were originally implemented as an LSM module. Based
on discussions on the LSM mailing list, a decision was made that the
LSM hooks should only be used to enforce mandatory access control
decisions and a new set of hooks should be defined specifically for
integrity.
EVM/IMA was limited to verifying and measuring a file's (i.e. an inode)
integrity and the metadata associated with it. Current research is
looking into other types of integrity measurements. (i.e. "Linux kernel
integrity measurement using contextual inspection", by Peter A. Loscocco,
Perry W. Wilson, J. Aaron Pendergrass, C. Durward McDonell,
http://doi.acm.org/10.1145/1314354.1314362). As a result, a requirement
of the new integrity framework is support for different types of integrity
measurements.
This patch provides an integrity framework(api and hooks) and placement
of the integrity hooks in the appropriate places in the fs directory.
Collecting, appraising, and storing of file and other types of integrity
data is supported. Multiple integrity templates, which implement the
integrity API, may register themselves. For now, only a single integrity
provider can register itself for the integrity hooks. (Support for multiple
providers registering themselves for the integrity hooks would require
some form of stacking.)
The six integrity hooks are:
inode_permission, inode_alloc_integrity, inode_free_integrity,
bprm_check_integrity, file_free_integrity, file_mmap
The five integrity API calls provided are:
integrity_must_measure, integrity_collect_measurement,
integrity_appraise_measurement, integrity_store_measurement,
and integrity_display_template.
The type of integrity data being collected, appraised, stored, or
displayed is template dependent.
(Details on the calls and their exact arguments are in linux/integrity.h,
included in the patch.)
Signed-off-by: Mimi Zohar <zohar@us.ibm.com>
---
Index: linux-2.6.26-rc8/include/linux/integrity.h
===================================================================
--- /dev/null
+++ linux-2.6.26-rc8/include/linux/integrity.h
@@ -0,0 +1,195 @@
+/*
+ * integrity.h
+ *
+ * Copyright (C) 2005,2006,2007,2008 IBM Corporation
+ * Author: Mimi Zohar <zohar@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2 of the License.
+ */
+
+#ifndef _LINUX_INTEGRITY_H
+#define _LINUX_INTEGRITY_H
+
+#include <linux/fs.h>
+#include <linux/audit.h>
+
+#ifdef CONFIG_INTEGRITY
+void integrity_audit_msg(int audit_msgno, struct inode *inode,
+ const unsigned char *fname, char *op,
+ char *cause, int result);
+
+/*
+ * Integrity API calls:
+ *
+ * @collect_measurement:
+ * Collect template specific measurement data.
+ * @data contains template specific data used for collecting the
+ * measurement.
+ * Return 0 if operation was successful.
+ *
+ * @appraise_measurement:
+ * Appraise the integrity of the template specific measurement data.
+ * @data contains template specific data used for appraising the
+ * measurement.
+ * Return 0 if operation was successful.
+ *
+ * @store_measurement:
+ * Store the template specific data.
+ * @data contains template specific data used for storing the
+ * measurement.
+ *
+ * @must_measure:
+ * Measurement decision based on an integrity policy.
+ * @data contains template specific data used for making policy
+ * decision.
+ * Return 0 if operation was successful.
+ *
+ * @display_template:
+ * Display template specific data.
+ *
+ */
+
+enum integrity_show_type { INTEGRITY_SHOW_BINARY, INTEGRITY_SHOW_ASCII};
+
+struct template_operations {
+ int (*collect_measurement)(void *);
+ int (*appraise_measurement)(void *);
+ void (*store_measurement)(void *);
+ int (*must_measure)(void *);
+ void (*display_template)(struct seq_file *m, void *,
+ enum integrity_show_type);
+};
+extern int integrity_register_template(const char *template_name,
+ const struct template_operations *ops);
+extern int integrity_unregister_template(const char *template_name);
+extern int integrity_find_template(const char *,
+ const struct template_operations **ops);
+
+/*
+ * Integrity hooks:
+ *
+ * @bprm_check_integrity:
+ * This hook mediates the point when a search for a binary handler will
+ * begin. At this point, the OS protects against an executable file,
+ * already open for write, from being executed; and an executable file
+ * already open for execute, from being modified. So we can be certain
+ * that any measurements(collect, appraise, store) done here are of
+ * the file being executed.
+ * @bprm contains the linux_binprm structure.
+ * Return 0 if the hook is successful and permission is granted.
+ *
+ * @inode_alloc_integrity:
+ * Allocate and attach an integrity structure to @inode->i_integrity. The
+ * i_integrity field is initialized to NULL when the inode structure is
+ * allocated.
+ * @inode contains the inode structure.
+ * Return 0 if operation was successful.
+ *
+ * @inode_free_integrity:
+ * @inode contains the inode structure.
+ * Deallocate the inode integrity structure and set @inode->i_integrity to
+ * NULL.
+ *
+ * @inode_permission:
+ * This hook is called by the existing Linux permission function, when
+ * a file is opened (as well as many other operations). At this point,
+ * measurements of files open for read(collect, appraise, store) can
+ * be made.
+ * @inode contains the inode structure to check.
+ * @mask contains the permission mask.
+ * @nd contains the nameidata (may be NULL).
+ *
+ * @file_free_integrity:
+ * Update the integrity xattr value as necessary.
+ * *file contains the file structure being closed.
+ *
+ * @file_mmap :
+ * Measurement(collect, appraise, store) of files mmaped for EXEC,
+ * could be measured at this point.
+ * @file contains the file structure for file to map (may be NULL).
+ * @reqprot contains the protection requested by the application.
+ * @prot contains the protection that will be applied by the kernel.
+ * @flags contains the operational flags.
+ * Return 0 if permission is granted.
+ */
+
+enum lim_hooks {INODE_PERMISSION = 1, FILE_MMAP, BPRM_CHECK };
+
+struct integrity_operations {
+ int (*bprm_check_integrity) (struct linux_binprm *bprm);
+ int (*inode_alloc_integrity) (struct inode *inode);
+ void (*inode_free_integrity) (struct inode *inode);
+ int (*inode_permission) (struct inode *inode, int mask,
+ struct nameidata *nd);
+ void (*file_free_integrity) (struct file *file);
+ int (*file_mmap) (struct file *file,
+ unsigned long reqprot, unsigned long prot,
+ unsigned long flags, unsigned long addr,
+ unsigned long addr_only);
+};
+extern int register_integrity(const struct integrity_operations *ops);
+extern int unregister_integrity(const struct integrity_operations *ops);
+
+/* global variables */
+extern const struct integrity_operations *integrity_ops;
+
+
+int integrity_collect_measurement(const char *template_name, void *data);
+int integrity_appraise_measurement(const char *template_name, void *data);
+int integrity_must_measure(const char *template_name, void *data);
+void integrity_store_measurement(const char *template_name, void *data);
+
+int integrity_bprm_check(struct linux_binprm *bprm);
+int integrity_inode_alloc(struct inode *inode);
+void integrity_inode_free(struct inode *inode);
+int integrity_inode_permission(struct inode *inode, int mask,
+ struct nameidata *nd);
+void integrity_file_free(struct file *file);
+int integrity_file_mmap(struct file *file,
+ unsigned long reqprot, unsigned long prot,
+ unsigned long flags, unsigned long addr,
+ unsigned long addr_only);
+#else
+
+static inline int integrity_bprm_check(struct linux_binprm *bprm)
+{
+ return 0;
+}
+
+static inline int integrity_inode_alloc(struct inode *inode)
+{
+ return 0;
+}
+
+static inline void integrity_inode_free(struct inode *inode)
+{
+ return;
+}
+
+static inline int integrity_inode_permission(struct inode *inode, int mask,
+ struct nameidata *nd)
+{
+ return 0;
+}
+
+static inline int integrity_file_permission(struct file *file, int mask)
+{
+ return 0;
+}
+
+static inline void integrity_file_free(struct file *file)
+{
+ return;
+}
+
+static inline int integrity_file_mmap(struct file *file,
+ unsigned long reqprot, unsigned long prot,
+ unsigned long flags, unsigned long addr,
+ unsigned long addr_only)
+{
+ return 0;
+}
+#endif
+#endif
Index: linux-2.6.26-rc8/security/integrity/integrity.c
===================================================================
--- /dev/null
+++ linux-2.6.26-rc8/security/integrity/integrity.c
@@ -0,0 +1,324 @@
+/*
+ * Copyright (C) 2006,2007,2008 IBM Corporation
+ * Author: Mimi Zohar <zohar@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2 of the License.
+ *
+ * File: integrity.c
+ * register integrity subsystem
+ * register integrity template
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/integrity.h>
+
+const struct integrity_operations *integrity_ops = NULL;
+EXPORT_SYMBOL(integrity_ops);
+
+#define TEMPLATE_NAME_LEN_MAX 12
+struct template_list_entry {
+ struct list_head template;
+ char template_name[TEMPLATE_NAME_LEN_MAX + 1];
+ const struct template_operations *template_ops;
+};
+static int template_initialized;
+static struct list_head integrity_templates;
+static DEFINE_MUTEX(integrity_templates_mutex);
+
+/**
+ * register_integrity - registers an integrity framework with the kernel
+ * @ops: a pointer to the struct security_options that is to be registered
+ *
+ * Perhaps in the future integrity module stacking will be necessary, but
+ * for the time being, this function permits only one integrity module to
+ * register itself with the kernel integrity subsystem.
+ *
+ * If another integrity module is already registered, an error code is
+ * returned. On success 0 is returned.
+ */
+int register_integrity(const struct integrity_operations *ops)
+{
+ if (integrity_ops != NULL)
+ return -EAGAIN;
+ integrity_ops = ops;
+ return 0;
+}
+
+EXPORT_SYMBOL_GPL(register_integrity);
+
+/**
+ * unregister_integrity - unregisters an integrity framework from the kernel
+ * @ops: a pointer to the struct security_options that is to be registered
+ *
+ * Returns 0 on success, -EINVAL on failure.
+ */
+int unregister_integrity(const struct integrity_operations *ops)
+{
+ if (ops != integrity_ops)
+ return -EINVAL;
+
+ integrity_ops = NULL;
+ return 0;
+}
+
+EXPORT_SYMBOL_GPL(unregister_integrity);
+
+/**
+ * integrity_register_template - registers an integrity template with the kernel
+ * @template_name: a pointer to a string containing the template name.
+ * @template_ops: a pointer to the template functions
+ *
+ * Register a set of functions to collect, appraise, store, and display
+ * a template measurement, and a means to decide whether to do them.
+ * Unlike integrity modules, any number of templates may be registered.
+ *
+ * Returns 0 on success, an error code on failure.
+ */
+int integrity_register_template(const char *template_name,
+ const struct template_operations *template_ops)
+{
+ int template_len;
+ struct template_list_entry *entry;
+
+ if (!template_initialized++)
+ INIT_LIST_HEAD(&integrity_templates);
+
+ entry = kmalloc(sizeof(*entry), GFP_KERNEL);
+ if (!entry)
+ return -ENOMEM;
+ INIT_LIST_HEAD(&entry->template);
+
+ template_len = strlen(template_name);
+ if (template_len > TEMPLATE_NAME_LEN_MAX)
+ template_len = TEMPLATE_NAME_LEN_MAX;
+ memcpy(entry->template_name, template_name, template_len);
+ entry->template_name[template_len] = '\0';
+ entry->template_ops = template_ops;
+
+ mutex_lock(&integrity_templates_mutex);
+ list_add_rcu(&entry->template, &integrity_templates);
+ mutex_unlock(&integrity_templates_mutex);
+ synchronize_rcu();
+
+ return 0;
+}
+
+EXPORT_SYMBOL_GPL(integrity_register_template);
+
+/**
+ * integrity_unregister_template: unregister a template
+ * @template_name: a pointer to a string containing the template name.
+ *
+ * Returns 0 on success, -EINVAL on failure.
+ */
+int integrity_unregister_template(const char *template_name)
+{
+ struct template_list_entry *entry;
+
+ mutex_lock(&integrity_templates_mutex);
+ list_for_each_entry(entry, &integrity_templates, template) {
+ if (strncmp(entry->template_name, template_name,
+ strlen(entry->template_name)) == 0) {
+ list_del_rcu(&entry->template);
+ mutex_unlock(&integrity_templates_mutex);
+ synchronize_rcu();
+ kfree(entry);
+ return 0;
+ }
+ }
+ mutex_unlock(&integrity_templates_mutex);
+ return -EINVAL;
+}
+
+EXPORT_SYMBOL_GPL(integrity_unregister_template);
+
+/**
+ * integrity_find_template - search the integrity_templates list
+ * @template_name: a pointer to a string containing the template name.
+ * @template_ops: a pointer to the template functions
+ *
+ * Called with an rcu_read_lock
+ * Returns 0 on success, 1 on failure.
+ */
+int integrity_find_template(const char *template_name,
+ const struct template_operations **template_ops)
+{
+ struct template_list_entry *entry;
+
+ list_for_each_entry_rcu(entry, &integrity_templates, template) {
+ if (strncmp(entry->template_name, template_name,
+ strlen(entry->template_name)) == 0) {
+ *template_ops = entry->template_ops;
+ return 0;
+ }
+ }
+ return 1;
+}
+
+EXPORT_SYMBOL_GPL(integrity_find_template);
+
+/* Start of the integrity API calls */
+
+/**
+ * integrity_collect_measurement - collect template specific measurement
+ * @template_name: a pointer to a string containing the template name.
+ * @data: pointer to template specific data
+ *
+ * Returns 0 on success, an error code on failure.
+ */
+int integrity_collect_measurement(const char *template_name, void *data)
+{
+ const struct template_operations *template_ops;
+ int rc;
+
+ rcu_read_lock();
+ rc = integrity_find_template(template_name, &template_ops);
+ if (rc == 0) {
+ rc = template_ops->collect_measurement(data);
+ rcu_read_unlock();
+ return rc;
+ }
+ rcu_read_unlock();
+ return -EINVAL;
+}
+
+EXPORT_SYMBOL_GPL(integrity_collect_measurement);
+
+/**
+ * integrity_appraise_measurement - appraise template specific measurement
+ * @template_name: a pointer to a string containing the template name.
+ * @data: pointer to template specific data
+ *
+ * Returns 0 on success, an error code on failure
+ */
+int integrity_appraise_measurement(const char *template_name, void *data)
+{
+ const struct template_operations *template_ops;
+ int rc;
+
+ rcu_read_lock();
+ rc = integrity_find_template(template_name, &template_ops);
+ if (rc == 0) {
+ rc = template_ops->appraise_measurement(data);
+ rcu_read_unlock();
+ return rc;
+ }
+ rcu_read_unlock();
+ return -EINVAL;
+}
+
+EXPORT_SYMBOL_GPL(integrity_appraise_measurement);
+
+/**
+ * integrity_store_measurement - store template specific measurement
+ * @template_name: a pointer to a string containing the template name.
+ * @data: pointer to template specific data
+ *
+ * Store template specific integrity measurement.
+ */
+void integrity_store_measurement(const char *template_name, void *data)
+{
+ const struct template_operations *template_ops;
+ int rc;
+
+ rcu_read_lock();
+ rc = integrity_find_template(template_name, &template_ops);
+ if (rc == 0)
+ template_ops->store_measurement(data);
+ rcu_read_unlock();
+ return;
+}
+
+EXPORT_SYMBOL_GPL(integrity_store_measurement);
+
+/**
+ * integrity_must_measure - measure decision based on template policy
+ * @template_name: a pointer to a string containing the template name.
+ * @data: pointer to template specific data
+ *
+ * Returns 0 on success, an error code on failure.
+ */
+int integrity_must_measure(const char *template_name, void *data)
+{
+ const struct template_operations *template_ops;
+ int rc;
+
+ rcu_read_lock();
+ rc = integrity_find_template(template_name, &template_ops);
+ if (rc == 0) {
+ rc = template_ops->must_measure(data);
+ rcu_read_unlock();
+ return rc;
+ }
+ rcu_read_unlock();
+ return -EINVAL;
+}
+
+EXPORT_SYMBOL_GPL(integrity_must_measure);
+
+/* Start of the integrity Hooks */
+
+/* Hook used to measure executable file integrity. */
+int integrity_bprm_check(struct linux_binprm *bprm)
+{
+ int rc = 0;
+
+ if (integrity_ops && integrity_ops->bprm_check_integrity)
+ rc = integrity_ops->bprm_check_integrity(bprm);
+ return rc;
+}
+
+/* Allocate, attach and initialize an inode's i_integrity. */
+int integrity_inode_alloc(struct inode *inode)
+{
+ int rc = 0;
+
+ if (integrity_ops && integrity_ops->inode_alloc_integrity)
+ rc = integrity_ops->inode_alloc_integrity(inode);
+ return rc;
+}
+
+/* Hook used to free an inode's i_integrity structure. */
+void integrity_inode_free(struct inode *inode)
+{
+ if (integrity_ops && integrity_ops->inode_free_integrity)
+ integrity_ops->inode_free_integrity(inode);
+}
+
+/* Hook used to measure a file's integrity. */
+int integrity_inode_permission(struct inode *inode, int mask,
+ struct nameidata *nd)
+{
+ int rc = 0;
+
+ if (integrity_ops && integrity_ops->inode_permission)
+ rc = integrity_ops->inode_permission(inode, mask, nd);
+ return rc;
+}
+
+/* Hook used to update i_integrity data and integrity xattr values
+ * as necessary.
+ */
+void integrity_file_free(struct file *file)
+{
+ if (integrity_ops && integrity_ops->file_free_integrity)
+ integrity_ops->file_free_integrity(file);
+}
+
+/* Hook used to measure integrity of an mmapped file */
+int integrity_file_mmap(struct file *file, unsigned long reqprot,
+ unsigned long prot, unsigned long flags,
+ unsigned long addr, unsigned long addr_only)
+{
+ int rc = 0;
+
+ if (integrity_ops && integrity_ops->file_mmap)
+ rc = integrity_ops->file_mmap(file, reqprot, prot,
+ flags, addr, addr_only);
+ return rc;
+}
Index: linux-2.6.26-rc8/fs/file_table.c
===================================================================
--- linux-2.6.26-rc8.orig/fs/file_table.c
+++ linux-2.6.26-rc8/fs/file_table.c
@@ -13,6 +13,7 @@
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/security.h>
+#include <linux/integrity.h>
#include <linux/eventpoll.h>
#include <linux/rcupdate.h>
#include <linux/mount.h>
@@ -272,6 +273,7 @@ void __fput(struct file *file)
if (file->f_op && file->f_op->release)
file->f_op->release(inode, file);
security_file_free(file);
+ integrity_file_free(file);
if (unlikely(S_ISCHR(inode->i_mode) && inode->i_cdev != NULL))
cdev_put(inode->i_cdev);
fops_put(file->f_op);
@@ -343,6 +345,7 @@ void put_filp(struct file *file)
{
if (atomic_dec_and_test(&file->f_count)) {
security_file_free(file);
+ integrity_file_free(file);
file_kill(file);
file_free(file);
}
Index: linux-2.6.26-rc8/fs/inode.c
===================================================================
--- linux-2.6.26-rc8.orig/fs/inode.c
+++ linux-2.6.26-rc8/fs/inode.c
@@ -17,6 +17,7 @@
#include <linux/hash.h>
#include <linux/swap.h>
#include <linux/security.h>
+#include <linux/integrity.h>
#include <linux/pagemap.h>
#include <linux/cdev.h>
#include <linux/bootmem.h>
@@ -151,6 +152,15 @@ static struct inode *alloc_inode(struct
return NULL;
}
+ /* allocate, attach and initialize an i_integrity */
+ if (integrity_inode_alloc(inode)) {
+ if (inode->i_sb->s_op->destroy_inode)
+ inode->i_sb->s_op->destroy_inode(inode);
+ else
+ kmem_cache_free(inode_cachep, (inode));
+ return NULL;
+ }
+
spin_lock_init(&inode->i_lock);
lockdep_set_class(&inode->i_lock, &sb->s_type->i_lock_key);
@@ -190,6 +200,7 @@ void destroy_inode(struct inode *inode)
{
BUG_ON(inode_has_buffers(inode));
security_inode_free(inode);
+ integrity_inode_free(inode);
if (inode->i_sb->s_op->destroy_inode)
inode->i_sb->s_op->destroy_inode(inode);
else
Index: linux-2.6.26-rc8/include/linux/fs.h
===================================================================
--- linux-2.6.26-rc8.orig/include/linux/fs.h
+++ linux-2.6.26-rc8/include/linux/fs.h
@@ -653,6 +653,9 @@ struct inode {
#ifdef CONFIG_SECURITY
void *i_security;
#endif
+#ifdef CONFIG_INTEGRITY
+ void *i_integrity;
+#endif
void *i_private; /* fs or device private pointer */
};
Index: linux-2.6.26-rc8/include/linux/audit.h
===================================================================
--- linux-2.6.26-rc8.orig/include/linux/audit.h
+++ linux-2.6.26-rc8/include/linux/audit.h
@@ -123,6 +123,11 @@
#define AUDIT_LAST_KERN_ANOM_MSG 1799
#define AUDIT_ANOM_PROMISCUOUS 1700 /* Device changed promiscuous mode */
#define AUDIT_ANOM_ABEND 1701 /* Process ended abnormally */
+#define AUDIT_INTEGRITY_DATA 1800 /* Data integrity verification */
+#define AUDIT_INTEGRITY_METADATA 1801 /* Metadata integrity verification */
+#define AUDIT_INTEGRITY_STATUS 1802 /* Integrity enable status */
+#define AUDIT_INTEGRITY_HASH 1803 /* Integrity HASH type */
+#define AUDIT_INTEGRITY_PCR 1804 /* PCR invalidation msgs */
#define AUDIT_KERNEL 2000 /* Asynchronous audit record. NOT A REQUEST. */
@@ -441,6 +446,8 @@ extern int audit_set_loginuid(struct ta
#define audit_get_loginuid(t) ((t)->loginuid)
#define audit_get_sessionid(t) ((t)->sessionid)
extern void audit_log_task_context(struct audit_buffer *ab);
+extern void audit_log_inode_context(struct audit_buffer *ab,
+ struct inode *inode);
extern int __audit_ipc_obj(struct kern_ipc_perm *ipcp);
extern int __audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode);
extern int audit_bprm(struct linux_binprm *bprm);
@@ -521,6 +528,7 @@ extern int audit_signals;
#define audit_get_loginuid(t) (-1)
#define audit_get_sessionid(t) (-1)
#define audit_log_task_context(b) do { ; } while (0)
+#define audit_log_inode_context(b, a) do { } while (0)
#define audit_ipc_obj(i) ({ 0; })
#define audit_ipc_set_perm(q,u,g,m) ({ 0; })
#define audit_bprm(p) ({ 0; })
Index: linux-2.6.26-rc8/security/integrity/integrity_audit.c
===================================================================
--- /dev/null
+++ linux-2.6.26-rc8/security/integrity/integrity_audit.c
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2008 IBM Corporation
+ * Author: Mimi Zohar <zohar@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2 of the License.
+ *
+ * File: integrity_audit.c
+ * Audit calls for the integrity subsystem
+ */
+
+#include <linux/audit.h>
+#include <linux/fs.h>
+#include <linux/integrity.h>
+
+static int integrity_audit = 1;
+
+#ifdef CONFIG_INTEGRITY_AUDIT
+static int __init integrity_audit_setup(char *str)
+{
+ ulong audit;
+ int rc;
+ char *op;
+
+ rc = strict_strtoul(str, 10, &audit);
+ if (rc < 0 || audit > 1)
+ printk(KERN_INFO "integrity: invalid integrity_audit value\n");
+ else
+ integrity_audit = audit;
+
+ op = integrity_audit ? "integrity_audit_enabled" :
+ "integrity_audit_not_enabled";
+ integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, NULL, NULL, op, 0);
+ return 1;
+}
+
+__setup("integrity_audit=", integrity_audit_setup);
+#endif
+
+void integrity_audit_msg(int audit_msgno, struct inode *inode,
+ const unsigned char *fname, char *op,
+ char *cause, int result)
+{
+ struct audit_buffer *ab;
+
+ if (!integrity_audit && result == 1)
+ return;
+
+ ab = audit_log_start(current->audit_context, GFP_KERNEL, audit_msgno);
+ audit_log_format(ab, "integrity: pid=%d uid=%u auid=%u",
+ current->pid, current->uid,
+ audit_get_loginuid(current));
+ audit_log_task_context(ab);
+ switch (audit_msgno) {
+ case AUDIT_INTEGRITY_DATA:
+ case AUDIT_INTEGRITY_METADATA:
+ case AUDIT_INTEGRITY_PCR:
+ audit_log_format(ab, " op=%s cause=%s", op, cause);
+ break;
+ case AUDIT_INTEGRITY_HASH:
+ audit_log_format(ab, " op=%s hash=%s", op, cause);
+ break;
+ case AUDIT_INTEGRITY_STATUS:
+ default:
+ audit_log_format(ab, " op=%s", op);
+ }
+ audit_log_format(ab, " comm=");
+ audit_log_untrustedstring(ab, current->comm);
+ if (fname) {
+ audit_log_format(ab, " name=");
+ audit_log_untrustedstring(ab, fname);
+ }
+ if (inode)
+ audit_log_format(ab, " dev=%s ino=%lu",
+ inode->i_sb->s_id, inode->i_ino);
+ audit_log_format(ab, " res=%d", result);
+ audit_log_end(ab);
+}
Index: linux-2.6.26-rc8/Documentation/kernel-parameters.txt
===================================================================
--- linux-2.6.26-rc8.orig/Documentation/kernel-parameters.txt
+++ linux-2.6.26-rc8/Documentation/kernel-parameters.txt
@@ -44,6 +44,7 @@ parameter is applicable:
FB The frame buffer device is enabled.
HW Appropriate hardware is enabled.
IA-64 IA-64 architecture is enabled.
+ INTEGRITY Integrity support is enabled.
IOSCHED More than one I/O scheduler is enabled.
IP_PNP IP DHCP, BOOTP, or RARP is enabled.
ISAPNP ISA PnP code is enabled.
@@ -821,6 +822,11 @@ and is between 256 and 4096 characters.
inport.irq= [HW] Inport (ATI XL and Microsoft) busmouse driver
Format: <irq>
+ integrity_audit= [INTEGRITY]
+ Format: { "0" | "1" }
+ 0 -- disable integrity auditing messages.
+ 1 -- enable integrity auditing messages. (Default)
+
inttest= [IA64]
iommu= [x86]
Index: linux-2.6.26-rc8/security/integrity/Makefile
===================================================================
--- /dev/null
+++ linux-2.6.26-rc8/security/integrity/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for the kernel integrity code
+#
+
+# Object file lists
+obj-$(CONFIG_INTEGRITY) += integrity.o integrity_audit.o
Index: linux-2.6.26-rc8/security/integrity/Kconfig
===================================================================
--- /dev/null
+++ linux-2.6.26-rc8/security/integrity/Kconfig
@@ -0,0 +1,24 @@
+#
+# Integrity configuration
+#
+
+menu "Integrity options"
+
+config INTEGRITY
+ bool "Enable different integrity models"
+ help
+ This allows you to choose different integrity modules to be
+ configured into your kernel.
+
+ If you are unsure how to answer this question, answer N.
+
+config INTEGRITY_AUDIT
+ bool "Integrity audit boot parameter"
+ depends on INTEGRITY
+ default y
+ help
+ This option adds a kernel parameter 'integrity_audit', which
+ allows integrity auditing to be disabled at boot. If this
+ option is selected, integrity auditing can be disabled with
+ 'integrity_audit=0' on the kernel command line.
+endmenu
Index: linux-2.6.26-rc8/security/Kconfig
===================================================================
--- linux-2.6.26-rc8.orig/security/Kconfig
+++ linux-2.6.26-rc8/security/Kconfig
@@ -4,6 +4,8 @@
menu "Security options"
+source security/integrity/Kconfig
+
config KEYS
bool "Enable access key retention support"
help
Index: linux-2.6.26-rc8/fs/exec.c
===================================================================
--- linux-2.6.26-rc8.orig/fs/exec.c
+++ linux-2.6.26-rc8/fs/exec.c
@@ -46,6 +46,7 @@
#include <linux/ptrace.h>
#include <linux/mount.h>
#include <linux/security.h>
+#include <linux/integrity.h>
#include <linux/syscalls.h>
#include <linux/rmap.h>
#include <linux/tsacct_kern.h>
@@ -1197,6 +1198,9 @@ int search_binary_handler(struct linux_b
retval = security_bprm_check(bprm);
if (retval)
return retval;
+ retval = integrity_bprm_check(bprm);
+ if (retval)
+ return retval;
/* kernel module loader fixup */
/* so we don't try to load run modprobe in kernel space. */
Index: linux-2.6.26-rc8/fs/namei.c
===================================================================
--- linux-2.6.26-rc8.orig/fs/namei.c
+++ linux-2.6.26-rc8/fs/namei.c
@@ -24,6 +24,7 @@
#include <linux/fsnotify.h>
#include <linux/personality.h>
#include <linux/security.h>
+#include <linux/integrity.h>
#include <linux/syscalls.h>
#include <linux/mount.h>
#include <linux/audit.h>
@@ -286,7 +287,10 @@ int permission(struct inode *inode, int
if (retval)
return retval;
- return security_inode_permission(inode, mask, nd);
+ retval = security_inode_permission(inode, mask, nd);
+ if (retval)
+ return retval;
+ return integrity_inode_permission(inode, mask, nd);
}
/**
@@ -462,6 +466,7 @@ static struct dentry * cached_lookup(str
static int exec_permission_lite(struct inode *inode,
struct nameidata *nd)
{
+ int retval;
umode_t mode = inode->i_mode;
if (inode->i_op && inode->i_op->permission)
@@ -486,7 +491,10 @@ static int exec_permission_lite(struct i
return -EACCES;
ok:
- return security_inode_permission(inode, MAY_EXEC, nd);
+ retval = security_inode_permission(inode, MAY_EXEC, nd);
+ if (retval)
+ return retval;
+ return integrity_inode_permission(inode, MAY_EXEC, nd);
}
/*
Index: linux-2.6.26-rc8/mm/mmap.c
===================================================================
--- linux-2.6.26-rc8.orig/mm/mmap.c
+++ linux-2.6.26-rc8/mm/mmap.c
@@ -20,6 +20,7 @@
#include <linux/fs.h>
#include <linux/personality.h>
#include <linux/security.h>
+#include <linux/integrity.h>
#include <linux/hugetlb.h>
#include <linux/profile.h>
#include <linux/module.h>
@@ -1042,6 +1043,9 @@ unsigned long do_mmap_pgoff(struct file
error = security_file_mmap(file, reqprot, prot, flags, addr, 0);
if (error)
return error;
+ error = integrity_file_mmap(file, reqprot, prot, flags, addr, 0);
+ if (error)
+ return error;
return mmap_region(file, addr, len, flags, vm_flags, pgoff,
accountable);
Index: linux-2.6.26-rc8/security/Makefile
===================================================================
--- linux-2.6.26-rc8.orig/security/Makefile
+++ linux-2.6.26-rc8/security/Makefile
@@ -19,3 +19,7 @@ obj-$(CONFIG_SECURITY_SMACK) += commonc
obj-$(CONFIG_SECURITY_CAPABILITIES) += commoncap.o capability.o
obj-$(CONFIG_SECURITY_ROOTPLUG) += commoncap.o root_plug.o
obj-$(CONFIG_CGROUP_DEVICE) += device_cgroup.o
+
+# Object integrity file lists
+subdir-$(CONFIG_INTEGRITY) += integrity
+obj-$(CONFIG_INTEGRITY) += integrity/built-in.o
--
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [RFC][PATCH 4/5] integrity: Linux Integrity Module(LIM)
2008-06-27 16:23 ` [RFC][PATCH 4/5] integrity: " Mimi Zohar
@ 2008-06-30 10:43 ` James Morris
2008-06-30 21:21 ` Mimi Zohar
0 siblings, 1 reply; 9+ messages in thread
From: James Morris @ 2008-06-30 10:43 UTC (permalink / raw)
To: Mimi Zohar
Cc: linux-kernel, David Safford, Serge Hallyn, Reiner Sailer,
Mimi Zohar
On Fri, 27 Jun 2008, Mimi Zohar wrote:
> +const struct integrity_operations *integrity_ops = NULL;
This will be initialized to zero anyway.
> +
> + if (!template_initialized++)
> + INIT_LIST_HEAD(&integrity_templates);
Why not just intialize this at compile time with LIST_HEAD ?
> + template_len = strlen(template_name);
> + if (template_len > TEMPLATE_NAME_LEN_MAX)
> + template_len = TEMPLATE_NAME_LEN_MAX;
> + memcpy(entry->template_name, template_name, template_len);
> + entry->template_name[template_len] = '\0';
Perhaps this would be simpler if you just bail with -EINVAL if the length
is too great. Then you can use strcpy and don't need to nul termiate the
string for the caller.
> + rc = integrity_find_template(template_name, &template_ops);
> + if (rc == 0) {
> + rc = template_ops->collect_measurement(data);
> + rcu_read_unlock();
> + return rc;
> + }
> + rcu_read_unlock();
> + return -EINVAL;
> +}
If you give integrity_find_template() a standard form of returning 0 on
success and -errno on failure, you can simplify the above quite a lot to
have one unlock and one return.
> + int rc;
> +
> + rcu_read_lock();
> + rc = integrity_find_template(template_name, &template_ops);
> + if (rc == 0) {
> + rc = template_ops->appraise_measurement(data);
> + rcu_read_unlock();
> + return rc;
> + }
> + rcu_read_unlock();
> + return -EINVAL;
> +}
Ditto.
> +
> +EXPORT_SYMBOL_GPL(integrity_appraise_measurement);
> +
> +/**
> + * integrity_store_measurement - store template specific measurement
> + * @template_name: a pointer to a string containing the template name.
> + * @data: pointer to template specific data
> + *
> + * Store template specific integrity measurement.
> + */
> +void integrity_store_measurement(const char *template_name, void *data)
> +{
> + const struct template_operations *template_ops;
> + int rc;
> +
> + rcu_read_lock();
> + rc = integrity_find_template(template_name, &template_ops);
> + if (rc == 0)
> + template_ops->store_measurement(data);
> + rcu_read_unlock();
> + return;
> +}
So, the caller does not get an error if they supply an invalid template
name? That sounds like a bug which they need to know about.
> +/**
> + * integrity_must_measure - measure decision based on template policy
> + * @template_name: a pointer to a string containing the template name.
> + * @data: pointer to template specific data
> + *
> + * Returns 0 on success, an error code on failure.
> + */
> +int integrity_must_measure(const char *template_name, void *data)
> +{
> + const struct template_operations *template_ops;
> + int rc;
> +
> + rcu_read_lock();
> + rc = integrity_find_template(template_name, &template_ops);
> + if (rc == 0) {
> + rc = template_ops->must_measure(data);
> + rcu_read_unlock();
> + return rc;
> + }
> + rcu_read_unlock();
> + return -EINVAL;
> +}
Do a single unlock and return.
> +/* Hook used to measure executable file integrity. */
> +int integrity_bprm_check(struct linux_binprm *bprm)
> +{
> + int rc = 0;
> +
> + if (integrity_ops && integrity_ops->bprm_check_integrity)
> + rc = integrity_ops->bprm_check_integrity(bprm);
> + return rc;
> +}
Have you considered using a set of dummy ops similar to LSM, so that
integrity_ops->whatever will always point to something and can be
unconditionally called? (see security_fixup_ops()).
- James
--
James Morris
<jmorris@namei.org>
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [RFC][PATCH 4/5] integrity: Linux Integrity Module(LIM)
2008-06-30 10:43 ` James Morris
@ 2008-06-30 21:21 ` Mimi Zohar
0 siblings, 0 replies; 9+ messages in thread
From: Mimi Zohar @ 2008-06-30 21:21 UTC (permalink / raw)
To: James Morris
Cc: linux-kernel, David Safford, Serge Hallyn, Reiner Sailer,
Mimi Zohar
On Mon, 2008-06-30 at 20:43 +1000, James Morris wrote:
Thank you for the suggestions. I've incorporated them into
the patch below, except for this:
> > +/* Hook used to measure executable file integrity. */
> > +int integrity_bprm_check(struct linux_binprm *bprm)
> > +{
> > + int rc = 0;
> > +
> > + if (integrity_ops && integrity_ops->bprm_check_integrity)
> > + rc = integrity_ops->bprm_check_integrity(bprm);
> > + return rc;
> > +}
>
> Have you considered using a set of dummy ops similar to LSM, so that
> integrity_ops->whatever will always point to something and can be
> unconditionally called? (see security_fixup_ops()).
>
> - James
The code up to this point did exactly that, but
On Wed, 2008-05-28 at 01:22 -0700, Andrew Morton wrote:
> - All the `static struct integrity_operations' instances could be
> made const. And lots of other foo_operations too, I expect.
>
> That will lead to a constification chase all over the place, but
> it's probably for the best. This is after all a "security" feature
> and there is perhaps some benefit in getting your eminently
> hijackable function pointers into read-only memory.
Can't use fixup_ops if integrity_ops is defined as a const.
Mimi
[RFC][PATCH 4/5]integrity: Linux Integrity Module(LIM)
This is a request for comments for a redesign of the integrity patches.
The new version addresses a number of issues, including
- generalizing the measurement API beyond just inode measurements.
- separation of the measurement into distinct collection, appraisal,
and commitment phases, for greater flexibility.
Extended Verification Module(EVM) and the Integrity Measurement
Architecture(IMA) were originally implemented as an LSM module. Based
on discussions on the LSM mailing list, a decision was made that the
LSM hooks should only be used to enforce mandatory access control
decisions and a new set of hooks should be defined specifically for
integrity.
EVM/IMA was limited to verifying and measuring a file's (i.e. an inode)
integrity and the metadata associated with it. Current research is
looking into other types of integrity measurements. (i.e. "Linux kernel
integrity measurement using contextual inspection", by Peter A. Loscocco,
Perry W. Wilson, J. Aaron Pendergrass, C. Durward McDonell,
http://doi.acm.org/10.1145/1314354.1314362). As a result, a requirement
of the new integrity framework is support for different types of integrity
measurements.
This patch provides an integrity framework(api and hooks) and placement
of the integrity hooks in the appropriate places in the fs directory.
Collecting, appraising, and storing of file and other types of integrity
data is supported. Multiple integrity templates, which implement the
integrity API, may register themselves. For now, only a single integrity
provider can register itself for the integrity hooks. (Support for multiple
providers registering themselves for the integrity hooks would require
some form of stacking.)
The six integrity hooks are:
inode_permission, inode_alloc_integrity, inode_free_integrity,
bprm_check_integrity, file_free_integrity, file_mmap
The five integrity API calls provided are:
integrity_must_measure, integrity_collect_measurement,
integrity_appraise_measurement, integrity_store_measurement,
and integrity_display_template.
The type of integrity data being collected, appraised, stored, or
displayed is template dependent.
(Details on the calls and their exact arguments are in linux/integrity.h,
included in the patch.)
Signed-off-by: Mimi Zohar <zohar@us.ibm.com>
---
Index: linux-2.6.26-rc8/include/linux/integrity.h
===================================================================
--- /dev/null
+++ linux-2.6.26-rc8/include/linux/integrity.h
@@ -0,0 +1,195 @@
+/*
+ * integrity.h
+ *
+ * Copyright (C) 2005,2006,2007,2008 IBM Corporation
+ * Author: Mimi Zohar <zohar@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2 of the License.
+ */
+
+#ifndef _LINUX_INTEGRITY_H
+#define _LINUX_INTEGRITY_H
+
+#include <linux/fs.h>
+#include <linux/audit.h>
+
+#ifdef CONFIG_INTEGRITY
+void integrity_audit_msg(int audit_msgno, struct inode *inode,
+ const unsigned char *fname, char *op,
+ char *cause, int result);
+
+/*
+ * Integrity API calls:
+ *
+ * @collect_measurement:
+ * Collect template specific measurement data.
+ * @data contains template specific data used for collecting the
+ * measurement.
+ * Return 0 if operation was successful.
+ *
+ * @appraise_measurement:
+ * Appraise the integrity of the template specific measurement data.
+ * @data contains template specific data used for appraising the
+ * measurement.
+ * Return 0 if operation was successful.
+ *
+ * @store_measurement:
+ * Store the template specific data.
+ * @data contains template specific data used for storing the
+ * measurement.
+ *
+ * @must_measure:
+ * Measurement decision based on an integrity policy.
+ * @data contains template specific data used for making policy
+ * decision.
+ * Return 0 if operation was successful.
+ *
+ * @display_template:
+ * Display template specific data.
+ *
+ */
+
+enum integrity_show_type { INTEGRITY_SHOW_BINARY, INTEGRITY_SHOW_ASCII};
+
+struct template_operations {
+ int (*collect_measurement)(void *);
+ int (*appraise_measurement)(void *);
+ void (*store_measurement)(void *);
+ int (*must_measure)(void *);
+ void (*display_template)(struct seq_file *m, void *,
+ enum integrity_show_type);
+};
+extern int integrity_register_template(const char *template_name,
+ const struct template_operations *ops);
+extern int integrity_unregister_template(const char *template_name);
+extern int integrity_find_template(const char *,
+ const struct template_operations **ops);
+
+/*
+ * Integrity hooks:
+ *
+ * @bprm_check_integrity:
+ * This hook mediates the point when a search for a binary handler will
+ * begin. At this point, the OS protects against an executable file,
+ * already open for write, from being executed; and an executable file
+ * already open for execute, from being modified. So we can be certain
+ * that any measurements(collect, appraise, store) done here are of
+ * the file being executed.
+ * @bprm contains the linux_binprm structure.
+ * Return 0 if the hook is successful and permission is granted.
+ *
+ * @inode_alloc_integrity:
+ * Allocate and attach an integrity structure to @inode->i_integrity. The
+ * i_integrity field is initialized to NULL when the inode structure is
+ * allocated.
+ * @inode contains the inode structure.
+ * Return 0 if operation was successful.
+ *
+ * @inode_free_integrity:
+ * @inode contains the inode structure.
+ * Deallocate the inode integrity structure and set @inode->i_integrity to
+ * NULL.
+ *
+ * @inode_permission:
+ * This hook is called by the existing Linux permission function, when
+ * a file is opened (as well as many other operations). At this point,
+ * measurements of files open for read(collect, appraise, store) can
+ * be made.
+ * @inode contains the inode structure to check.
+ * @mask contains the permission mask.
+ * @nd contains the nameidata (may be NULL).
+ *
+ * @file_free_integrity:
+ * Update the integrity xattr value as necessary.
+ * *file contains the file structure being closed.
+ *
+ * @file_mmap :
+ * Measurement(collect, appraise, store) of files mmaped for EXEC,
+ * could be measured at this point.
+ * @file contains the file structure for file to map (may be NULL).
+ * @reqprot contains the protection requested by the application.
+ * @prot contains the protection that will be applied by the kernel.
+ * @flags contains the operational flags.
+ * Return 0 if permission is granted.
+ */
+
+enum lim_hooks {INODE_PERMISSION = 1, FILE_MMAP, BPRM_CHECK };
+
+struct integrity_operations {
+ int (*bprm_check_integrity) (struct linux_binprm *bprm);
+ int (*inode_alloc_integrity) (struct inode *inode);
+ void (*inode_free_integrity) (struct inode *inode);
+ int (*inode_permission) (struct inode *inode, int mask,
+ struct nameidata *nd);
+ void (*file_free_integrity) (struct file *file);
+ int (*file_mmap) (struct file *file,
+ unsigned long reqprot, unsigned long prot,
+ unsigned long flags, unsigned long addr,
+ unsigned long addr_only);
+};
+extern int register_integrity(const struct integrity_operations *ops);
+extern int unregister_integrity(const struct integrity_operations *ops);
+
+/* global variables */
+extern const struct integrity_operations *integrity_ops;
+
+
+int integrity_collect_measurement(const char *template_name, void *data);
+int integrity_appraise_measurement(const char *template_name, void *data);
+int integrity_must_measure(const char *template_name, void *data);
+int integrity_store_measurement(const char *template_name, void *data);
+
+int integrity_bprm_check(struct linux_binprm *bprm);
+int integrity_inode_alloc(struct inode *inode);
+void integrity_inode_free(struct inode *inode);
+int integrity_inode_permission(struct inode *inode, int mask,
+ struct nameidata *nd);
+void integrity_file_free(struct file *file);
+int integrity_file_mmap(struct file *file,
+ unsigned long reqprot, unsigned long prot,
+ unsigned long flags, unsigned long addr,
+ unsigned long addr_only);
+#else
+
+static inline int integrity_bprm_check(struct linux_binprm *bprm)
+{
+ return 0;
+}
+
+static inline int integrity_inode_alloc(struct inode *inode)
+{
+ return 0;
+}
+
+static inline void integrity_inode_free(struct inode *inode)
+{
+ return;
+}
+
+static inline int integrity_inode_permission(struct inode *inode, int mask,
+ struct nameidata *nd)
+{
+ return 0;
+}
+
+static inline int integrity_file_permission(struct file *file, int mask)
+{
+ return 0;
+}
+
+static inline void integrity_file_free(struct file *file)
+{
+ return;
+}
+
+static inline int integrity_file_mmap(struct file *file,
+ unsigned long reqprot, unsigned long prot,
+ unsigned long flags, unsigned long addr,
+ unsigned long addr_only)
+{
+ return 0;
+}
+#endif
+#endif
Index: linux-2.6.26-rc8/security/integrity/integrity.c
===================================================================
--- /dev/null
+++ linux-2.6.26-rc8/security/integrity/integrity.c
@@ -0,0 +1,310 @@
+/*
+ * Copyright (C) 2006,2007,2008 IBM Corporation
+ * Author: Mimi Zohar <zohar@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2 of the License.
+ *
+ * File: integrity.c
+ * register integrity subsystem
+ * register integrity template
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/integrity.h>
+
+const struct integrity_operations *integrity_ops;
+EXPORT_SYMBOL(integrity_ops);
+
+#define TEMPLATE_NAME_LEN_MAX 12
+struct template_list_entry {
+ struct list_head template;
+ char template_name[TEMPLATE_NAME_LEN_MAX + 1];
+ const struct template_operations *template_ops;
+};
+static LIST_HEAD(integrity_templates);
+static DEFINE_MUTEX(integrity_templates_mutex);
+
+/**
+ * register_integrity - registers an integrity framework with the kernel
+ * @ops: a pointer to the struct security_options that is to be registered
+ *
+ * Perhaps in the future integrity module stacking will be necessary, but
+ * for the time being, this function permits only one integrity module to
+ * register itself with the kernel integrity subsystem.
+ *
+ * If another integrity module is already registered, an error code is
+ * returned. On success 0 is returned.
+ */
+int register_integrity(const struct integrity_operations *ops)
+{
+ if (integrity_ops != NULL)
+ return -EAGAIN;
+ integrity_ops = ops;
+ return 0;
+}
+
+EXPORT_SYMBOL_GPL(register_integrity);
+
+/**
+ * unregister_integrity - unregisters an integrity framework from the kernel
+ * @ops: a pointer to the struct security_options that is to be registered
+ *
+ * Returns 0 on success, -EINVAL on failure.
+ */
+int unregister_integrity(const struct integrity_operations *ops)
+{
+ if (ops != integrity_ops)
+ return -EINVAL;
+
+ integrity_ops = NULL;
+ return 0;
+}
+
+EXPORT_SYMBOL_GPL(unregister_integrity);
+
+/**
+ * integrity_register_template - registers an integrity template with the kernel
+ * @template_name: a pointer to a string containing the template name.
+ * @template_ops: a pointer to the template functions
+ *
+ * Register a set of functions to collect, appraise, store, and display
+ * a template measurement, and a means to decide whether to do them.
+ * Unlike integrity modules, any number of templates may be registered.
+ *
+ * Returns 0 on success, an error code on failure.
+ */
+int integrity_register_template(const char *template_name,
+ const struct template_operations *template_ops)
+{
+ int template_len;
+ struct template_list_entry *entry;
+
+ entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+ if (!entry)
+ return -ENOMEM;
+ INIT_LIST_HEAD(&entry->template);
+
+ template_len = strlen(template_name);
+ if (template_len > TEMPLATE_NAME_LEN_MAX)
+ return -EINVAL;
+ strcpy(entry->template_name, template_name);
+ entry->template_ops = template_ops;
+
+ mutex_lock(&integrity_templates_mutex);
+ list_add_rcu(&entry->template, &integrity_templates);
+ mutex_unlock(&integrity_templates_mutex);
+ synchronize_rcu();
+
+ return 0;
+}
+
+EXPORT_SYMBOL_GPL(integrity_register_template);
+
+/**
+ * integrity_unregister_template: unregister a template
+ * @template_name: a pointer to a string containing the template name.
+ *
+ * Returns 0 on success, -EINVAL on failure.
+ */
+int integrity_unregister_template(const char *template_name)
+{
+ struct template_list_entry *entry;
+
+ mutex_lock(&integrity_templates_mutex);
+ list_for_each_entry(entry, &integrity_templates, template) {
+ if (strncmp(entry->template_name, template_name,
+ strlen(entry->template_name)) == 0) {
+ list_del_rcu(&entry->template);
+ mutex_unlock(&integrity_templates_mutex);
+ synchronize_rcu();
+ kfree(entry);
+ return 0;
+ }
+ }
+ mutex_unlock(&integrity_templates_mutex);
+ return -EINVAL;
+}
+
+EXPORT_SYMBOL_GPL(integrity_unregister_template);
+
+/**
+ * integrity_find_template - search the integrity_templates list
+ * @template_name: a pointer to a string containing the template name.
+ * @template_ops: a pointer to the template functions
+ *
+ * Called with an rcu_read_lock
+ * Returns 0 on success, -EINVAL on failure.
+ */
+int integrity_find_template(const char *template_name,
+ const struct template_operations **template_ops)
+{
+ struct template_list_entry *entry;
+
+ list_for_each_entry_rcu(entry, &integrity_templates, template) {
+ if (strncmp(entry->template_name, template_name,
+ strlen(entry->template_name)) == 0) {
+ *template_ops = entry->template_ops;
+ return 0;
+ }
+ }
+ return -EINVAL;
+}
+
+EXPORT_SYMBOL_GPL(integrity_find_template);
+
+/* Start of the integrity API calls */
+
+/**
+ * integrity_collect_measurement - collect template specific measurement
+ * @template_name: a pointer to a string containing the template name.
+ * @data: pointer to template specific data
+ *
+ * Returns 0 on success, an error code on failure.
+ */
+int integrity_collect_measurement(const char *template_name, void *data)
+{
+ const struct template_operations *template_ops;
+ int rc;
+
+ rcu_read_lock();
+ rc = integrity_find_template(template_name, &template_ops);
+ if (rc == 0)
+ rc = template_ops->collect_measurement(data);
+ rcu_read_unlock();
+ return rc;
+}
+
+EXPORT_SYMBOL_GPL(integrity_collect_measurement);
+
+/**
+ * integrity_appraise_measurement - appraise template specific measurement
+ * @template_name: a pointer to a string containing the template name.
+ * @data: pointer to template specific data
+ *
+ * Returns 0 on success, an error code on failure
+ */
+int integrity_appraise_measurement(const char *template_name, void *data)
+{
+ const struct template_operations *template_ops;
+ int rc;
+
+ rcu_read_lock();
+ rc = integrity_find_template(template_name, &template_ops);
+ if (rc == 0)
+ rc = template_ops->appraise_measurement(data);
+ rcu_read_unlock();
+ return rc;
+}
+
+EXPORT_SYMBOL_GPL(integrity_appraise_measurement);
+
+/**
+ * integrity_store_measurement - store template specific measurement
+ * @template_name: a pointer to a string containing the template name.
+ * @data: pointer to template specific data
+ *
+ * Store template specific integrity measurement.
+ */
+int integrity_store_measurement(const char *template_name, void *data)
+{
+ const struct template_operations *template_ops;
+ int rc;
+
+ rcu_read_lock();
+ rc = integrity_find_template(template_name, &template_ops);
+ if (rc == 0)
+ template_ops->store_measurement(data);
+ rcu_read_unlock();
+ return rc;
+}
+
+EXPORT_SYMBOL_GPL(integrity_store_measurement);
+
+/**
+ * integrity_must_measure - measure decision based on template policy
+ * @template_name: a pointer to a string containing the template name.
+ * @data: pointer to template specific data
+ *
+ * Returns 0 on success, an error code on failure.
+ */
+int integrity_must_measure(const char *template_name, void *data)
+{
+ const struct template_operations *template_ops;
+ int rc;
+
+ rcu_read_lock();
+ rc = integrity_find_template(template_name, &template_ops);
+ if (rc == 0)
+ rc = template_ops->must_measure(data);
+ rcu_read_unlock();
+ return rc;
+}
+
+EXPORT_SYMBOL_GPL(integrity_must_measure);
+
+/* Start of the integrity Hooks */
+
+/* Hook used to measure executable file integrity. */
+int integrity_bprm_check(struct linux_binprm *bprm)
+{
+ int rc = 0;
+
+ if (integrity_ops && integrity_ops->bprm_check_integrity)
+ rc = integrity_ops->bprm_check_integrity(bprm);
+ return rc;
+}
+
+/* Allocate, attach and initialize an inode's i_integrity. */
+int integrity_inode_alloc(struct inode *inode)
+{
+ int rc = 0;
+
+ if (integrity_ops && integrity_ops->inode_alloc_integrity)
+ rc = integrity_ops->inode_alloc_integrity(inode);
+ return rc;
+}
+
+/* Hook used to free an inode's i_integrity structure. */
+void integrity_inode_free(struct inode *inode)
+{
+ if (integrity_ops && integrity_ops->inode_free_integrity)
+ integrity_ops->inode_free_integrity(inode);
+}
+
+/* Hook used to measure a file's integrity. */
+int integrity_inode_permission(struct inode *inode, int mask,
+ struct nameidata *nd)
+{
+ int rc = 0;
+
+ if (integrity_ops && integrity_ops->inode_permission)
+ rc = integrity_ops->inode_permission(inode, mask, nd);
+ return rc;
+}
+
+/* Hook used to update i_integrity data and integrity xattr values
+ * as necessary.
+ */
+void integrity_file_free(struct file *file)
+{
+ if (integrity_ops && integrity_ops->file_free_integrity)
+ integrity_ops->file_free_integrity(file);
+}
+
+/* Hook used to measure integrity of an mmapped file */
+int integrity_file_mmap(struct file *file, unsigned long reqprot,
+ unsigned long prot, unsigned long flags,
+ unsigned long addr, unsigned long addr_only)
+{
+ int rc = 0;
+
+ if (integrity_ops && integrity_ops->file_mmap)
+ rc = integrity_ops->file_mmap(file, reqprot, prot,
+ flags, addr, addr_only);
+ return rc;
+}
Index: linux-2.6.26-rc8/fs/file_table.c
===================================================================
--- linux-2.6.26-rc8.orig/fs/file_table.c
+++ linux-2.6.26-rc8/fs/file_table.c
@@ -13,6 +13,7 @@
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/security.h>
+#include <linux/integrity.h>
#include <linux/eventpoll.h>
#include <linux/rcupdate.h>
#include <linux/mount.h>
@@ -272,6 +273,7 @@ void __fput(struct file *file)
if (file->f_op && file->f_op->release)
file->f_op->release(inode, file);
security_file_free(file);
+ integrity_file_free(file);
if (unlikely(S_ISCHR(inode->i_mode) && inode->i_cdev != NULL))
cdev_put(inode->i_cdev);
fops_put(file->f_op);
@@ -343,6 +345,7 @@ void put_filp(struct file *file)
{
if (atomic_dec_and_test(&file->f_count)) {
security_file_free(file);
+ integrity_file_free(file);
file_kill(file);
file_free(file);
}
Index: linux-2.6.26-rc8/fs/inode.c
===================================================================
--- linux-2.6.26-rc8.orig/fs/inode.c
+++ linux-2.6.26-rc8/fs/inode.c
@@ -17,6 +17,7 @@
#include <linux/hash.h>
#include <linux/swap.h>
#include <linux/security.h>
+#include <linux/integrity.h>
#include <linux/pagemap.h>
#include <linux/cdev.h>
#include <linux/bootmem.h>
@@ -151,6 +152,15 @@ static struct inode *alloc_inode(struct
return NULL;
}
+ /* allocate, attach and initialize an i_integrity */
+ if (integrity_inode_alloc(inode)) {
+ if (inode->i_sb->s_op->destroy_inode)
+ inode->i_sb->s_op->destroy_inode(inode);
+ else
+ kmem_cache_free(inode_cachep, (inode));
+ return NULL;
+ }
+
spin_lock_init(&inode->i_lock);
lockdep_set_class(&inode->i_lock, &sb->s_type->i_lock_key);
@@ -190,6 +200,7 @@ void destroy_inode(struct inode *inode)
{
BUG_ON(inode_has_buffers(inode));
security_inode_free(inode);
+ integrity_inode_free(inode);
if (inode->i_sb->s_op->destroy_inode)
inode->i_sb->s_op->destroy_inode(inode);
else
Index: linux-2.6.26-rc8/include/linux/fs.h
===================================================================
--- linux-2.6.26-rc8.orig/include/linux/fs.h
+++ linux-2.6.26-rc8/include/linux/fs.h
@@ -653,6 +653,9 @@ struct inode {
#ifdef CONFIG_SECURITY
void *i_security;
#endif
+#ifdef CONFIG_INTEGRITY
+ void *i_integrity;
+#endif
void *i_private; /* fs or device private pointer */
};
Index: linux-2.6.26-rc8/include/linux/audit.h
===================================================================
--- linux-2.6.26-rc8.orig/include/linux/audit.h
+++ linux-2.6.26-rc8/include/linux/audit.h
@@ -123,6 +123,11 @@
#define AUDIT_LAST_KERN_ANOM_MSG 1799
#define AUDIT_ANOM_PROMISCUOUS 1700 /* Device changed promiscuous mode */
#define AUDIT_ANOM_ABEND 1701 /* Process ended abnormally */
+#define AUDIT_INTEGRITY_DATA 1800 /* Data integrity verification */
+#define AUDIT_INTEGRITY_METADATA 1801 /* Metadata integrity verification */
+#define AUDIT_INTEGRITY_STATUS 1802 /* Integrity enable status */
+#define AUDIT_INTEGRITY_HASH 1803 /* Integrity HASH type */
+#define AUDIT_INTEGRITY_PCR 1804 /* PCR invalidation msgs */
#define AUDIT_KERNEL 2000 /* Asynchronous audit record. NOT A REQUEST. */
@@ -441,6 +446,8 @@ extern int audit_set_loginuid(struct ta
#define audit_get_loginuid(t) ((t)->loginuid)
#define audit_get_sessionid(t) ((t)->sessionid)
extern void audit_log_task_context(struct audit_buffer *ab);
+extern void audit_log_inode_context(struct audit_buffer *ab,
+ struct inode *inode);
extern int __audit_ipc_obj(struct kern_ipc_perm *ipcp);
extern int __audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode);
extern int audit_bprm(struct linux_binprm *bprm);
@@ -521,6 +528,7 @@ extern int audit_signals;
#define audit_get_loginuid(t) (-1)
#define audit_get_sessionid(t) (-1)
#define audit_log_task_context(b) do { ; } while (0)
+#define audit_log_inode_context(b, a) do { } while (0)
#define audit_ipc_obj(i) ({ 0; })
#define audit_ipc_set_perm(q,u,g,m) ({ 0; })
#define audit_bprm(p) ({ 0; })
Index: linux-2.6.26-rc8/security/integrity/integrity_audit.c
===================================================================
--- /dev/null
+++ linux-2.6.26-rc8/security/integrity/integrity_audit.c
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2008 IBM Corporation
+ * Author: Mimi Zohar <zohar@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2 of the License.
+ *
+ * File: integrity_audit.c
+ * Audit calls for the integrity subsystem
+ */
+
+#include <linux/audit.h>
+#include <linux/fs.h>
+#include <linux/integrity.h>
+
+static int integrity_audit = 1;
+
+#ifdef CONFIG_INTEGRITY_AUDIT
+static int __init integrity_audit_setup(char *str)
+{
+ ulong audit;
+ int rc;
+ char *op;
+
+ rc = strict_strtoul(str, 10, &audit);
+ if (rc < 0 || audit > 1)
+ printk(KERN_INFO "integrity: invalid integrity_audit value\n");
+ else
+ integrity_audit = audit;
+
+ op = integrity_audit ? "integrity_audit_enabled" :
+ "integrity_audit_not_enabled";
+ integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, NULL, NULL, op, 0);
+ return 1;
+}
+
+__setup("integrity_audit=", integrity_audit_setup);
+#endif
+
+void integrity_audit_msg(int audit_msgno, struct inode *inode,
+ const unsigned char *fname, char *op,
+ char *cause, int result)
+{
+ struct audit_buffer *ab;
+
+ if (!integrity_audit && result == 1)
+ return;
+
+ ab = audit_log_start(current->audit_context, GFP_KERNEL, audit_msgno);
+ audit_log_format(ab, "integrity: pid=%d uid=%u auid=%u",
+ current->pid, current->uid,
+ audit_get_loginuid(current));
+ audit_log_task_context(ab);
+ switch (audit_msgno) {
+ case AUDIT_INTEGRITY_DATA:
+ case AUDIT_INTEGRITY_METADATA:
+ case AUDIT_INTEGRITY_PCR:
+ audit_log_format(ab, " op=%s cause=%s", op, cause);
+ break;
+ case AUDIT_INTEGRITY_HASH:
+ audit_log_format(ab, " op=%s hash=%s", op, cause);
+ break;
+ case AUDIT_INTEGRITY_STATUS:
+ default:
+ audit_log_format(ab, " op=%s", op);
+ }
+ audit_log_format(ab, " comm=");
+ audit_log_untrustedstring(ab, current->comm);
+ if (fname) {
+ audit_log_format(ab, " name=");
+ audit_log_untrustedstring(ab, fname);
+ }
+ if (inode)
+ audit_log_format(ab, " dev=%s ino=%lu",
+ inode->i_sb->s_id, inode->i_ino);
+ audit_log_format(ab, " res=%d", result);
+ audit_log_end(ab);
+}
Index: linux-2.6.26-rc8/Documentation/kernel-parameters.txt
===================================================================
--- linux-2.6.26-rc8.orig/Documentation/kernel-parameters.txt
+++ linux-2.6.26-rc8/Documentation/kernel-parameters.txt
@@ -44,6 +44,7 @@ parameter is applicable:
FB The frame buffer device is enabled.
HW Appropriate hardware is enabled.
IA-64 IA-64 architecture is enabled.
+ INTEGRITY Integrity support is enabled.
IOSCHED More than one I/O scheduler is enabled.
IP_PNP IP DHCP, BOOTP, or RARP is enabled.
ISAPNP ISA PnP code is enabled.
@@ -821,6 +822,11 @@ and is between 256 and 4096 characters.
inport.irq= [HW] Inport (ATI XL and Microsoft) busmouse driver
Format: <irq>
+ integrity_audit= [INTEGRITY]
+ Format: { "0" | "1" }
+ 0 -- disable integrity auditing messages.
+ 1 -- enable integrity auditing messages. (Default)
+
inttest= [IA64]
iommu= [x86]
Index: linux-2.6.26-rc8/security/integrity/Makefile
===================================================================
--- /dev/null
+++ linux-2.6.26-rc8/security/integrity/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for the kernel integrity code
+#
+
+# Object file lists
+obj-$(CONFIG_INTEGRITY) += integrity.o integrity_audit.o
Index: linux-2.6.26-rc8/security/integrity/Kconfig
===================================================================
--- /dev/null
+++ linux-2.6.26-rc8/security/integrity/Kconfig
@@ -0,0 +1,24 @@
+#
+# Integrity configuration
+#
+
+menu "Integrity options"
+
+config INTEGRITY
+ bool "Enable different integrity models"
+ help
+ This allows you to choose different integrity modules to be
+ configured into your kernel.
+
+ If you are unsure how to answer this question, answer N.
+
+config INTEGRITY_AUDIT
+ bool "Integrity audit boot parameter"
+ depends on INTEGRITY
+ default y
+ help
+ This option adds a kernel parameter 'integrity_audit', which
+ allows integrity auditing to be disabled at boot. If this
+ option is selected, integrity auditing can be disabled with
+ 'integrity_audit=0' on the kernel command line.
+endmenu
Index: linux-2.6.26-rc8/security/Kconfig
===================================================================
--- linux-2.6.26-rc8.orig/security/Kconfig
+++ linux-2.6.26-rc8/security/Kconfig
@@ -4,6 +4,8 @@
menu "Security options"
+source security/integrity/Kconfig
+
config KEYS
bool "Enable access key retention support"
help
Index: linux-2.6.26-rc8/fs/exec.c
===================================================================
--- linux-2.6.26-rc8.orig/fs/exec.c
+++ linux-2.6.26-rc8/fs/exec.c
@@ -46,6 +46,7 @@
#include <linux/ptrace.h>
#include <linux/mount.h>
#include <linux/security.h>
+#include <linux/integrity.h>
#include <linux/syscalls.h>
#include <linux/rmap.h>
#include <linux/tsacct_kern.h>
@@ -1197,6 +1198,9 @@ int search_binary_handler(struct linux_b
retval = security_bprm_check(bprm);
if (retval)
return retval;
+ retval = integrity_bprm_check(bprm);
+ if (retval)
+ return retval;
/* kernel module loader fixup */
/* so we don't try to load run modprobe in kernel space. */
Index: linux-2.6.26-rc8/fs/namei.c
===================================================================
--- linux-2.6.26-rc8.orig/fs/namei.c
+++ linux-2.6.26-rc8/fs/namei.c
@@ -24,6 +24,7 @@
#include <linux/fsnotify.h>
#include <linux/personality.h>
#include <linux/security.h>
+#include <linux/integrity.h>
#include <linux/syscalls.h>
#include <linux/mount.h>
#include <linux/audit.h>
@@ -286,7 +287,10 @@ int permission(struct inode *inode, int
if (retval)
return retval;
- return security_inode_permission(inode, mask, nd);
+ retval = security_inode_permission(inode, mask, nd);
+ if (retval)
+ return retval;
+ return integrity_inode_permission(inode, mask, nd);
}
/**
@@ -462,6 +466,7 @@ static struct dentry * cached_lookup(str
static int exec_permission_lite(struct inode *inode,
struct nameidata *nd)
{
+ int retval;
umode_t mode = inode->i_mode;
if (inode->i_op && inode->i_op->permission)
@@ -486,7 +491,10 @@ static int exec_permission_lite(struct i
return -EACCES;
ok:
- return security_inode_permission(inode, MAY_EXEC, nd);
+ retval = security_inode_permission(inode, MAY_EXEC, nd);
+ if (retval)
+ return retval;
+ return integrity_inode_permission(inode, MAY_EXEC, nd);
}
/*
Index: linux-2.6.26-rc8/mm/mmap.c
===================================================================
--- linux-2.6.26-rc8.orig/mm/mmap.c
+++ linux-2.6.26-rc8/mm/mmap.c
@@ -20,6 +20,7 @@
#include <linux/fs.h>
#include <linux/personality.h>
#include <linux/security.h>
+#include <linux/integrity.h>
#include <linux/hugetlb.h>
#include <linux/profile.h>
#include <linux/module.h>
@@ -1042,6 +1043,9 @@ unsigned long do_mmap_pgoff(struct file
error = security_file_mmap(file, reqprot, prot, flags, addr, 0);
if (error)
return error;
+ error = integrity_file_mmap(file, reqprot, prot, flags, addr, 0);
+ if (error)
+ return error;
return mmap_region(file, addr, len, flags, vm_flags, pgoff,
accountable);
Index: linux-2.6.26-rc8/security/Makefile
===================================================================
--- linux-2.6.26-rc8.orig/security/Makefile
+++ linux-2.6.26-rc8/security/Makefile
@@ -19,3 +19,7 @@ obj-$(CONFIG_SECURITY_SMACK) += commonc
obj-$(CONFIG_SECURITY_CAPABILITIES) += commoncap.o capability.o
obj-$(CONFIG_SECURITY_ROOTPLUG) += commoncap.o root_plug.o
obj-$(CONFIG_CGROUP_DEVICE) += device_cgroup.o
+
+# Object integrity file lists
+subdir-$(CONFIG_INTEGRITY) += integrity
+obj-$(CONFIG_INTEGRITY) += integrity/built-in.o
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2008-06-30 21:21 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-05-23 15:05 [RFC][PATCH 4/5]integrity: Linux Integrity Module(LIM) Mimi Zohar
2008-05-23 23:30 ` Randy Dunlap
2008-05-27 14:34 ` Mimi Zohar
2008-05-28 7:46 ` Andrew Morton
2008-05-29 2:46 ` Mimi Zohar
2008-05-29 4:46 ` James Morris
[not found] <20080627131946.225566613@linux.vnet.ibm.com>
2008-06-27 16:23 ` [RFC][PATCH 4/5] integrity: " Mimi Zohar
2008-06-30 10:43 ` James Morris
2008-06-30 21:21 ` Mimi Zohar
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox