diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-03-26 14:03:39 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-03-26 14:03:39 -0400 |
| commit | 8d80ce80e1d58ba9cd3e3972b112cccd6b4008f4 (patch) | |
| tree | 16d3cca8d260c731d02a4e5e1ea5b9817c9c3626 /security/integrity/ima/ima_api.c | |
| parent | 1646df40bb111715a90ce0b86448dabbcc5b3f3d (diff) | |
| parent | 703a3cd72817e99201cef84a8a7aecc60b2b3581 (diff) | |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/security-testing-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/security-testing-2.6: (71 commits)
SELinux: inode_doinit_with_dentry drop no dentry printk
SELinux: new permission between tty audit and audit socket
SELinux: open perm for sock files
smack: fixes for unlabeled host support
keys: make procfiles per-user-namespace
keys: skip keys from another user namespace
keys: consider user namespace in key_permission
keys: distinguish per-uid keys in different namespaces
integrity: ima iint radix_tree_lookup locking fix
TOMOYO: Do not call tomoyo_realpath_init unless registered.
integrity: ima scatterlist bug fix
smack: fix lots of kernel-doc notation
TOMOYO: Don't create securityfs entries unless registered.
TOMOYO: Fix exception policy read failure.
SELinux: convert the avc cache hash list to an hlist
SELinux: code readability with avc_cache
SELinux: remove unused av.decided field
SELinux: more careful use of avd in avc_has_perm_noaudit
SELinux: remove the unused ae.used
SELinux: check seqno when updating an avc_node
...
Diffstat (limited to 'security/integrity/ima/ima_api.c')
| -rw-r--r-- | security/integrity/ima/ima_api.c | 190 |
1 files changed, 190 insertions, 0 deletions
diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c new file mode 100644 index 000000000000..3cd58b60afd2 --- /dev/null +++ b/security/integrity/ima/ima_api.c | |||
| @@ -0,0 +1,190 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2008 IBM Corporation | ||
| 3 | * | ||
| 4 | * Author: Mimi Zohar <zohar@us.ibm.com> | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU General Public License as | ||
| 8 | * published by the Free Software Foundation, version 2 of the | ||
| 9 | * License. | ||
| 10 | * | ||
| 11 | * File: ima_api.c | ||
| 12 | * Implements must_measure, collect_measurement, store_measurement, | ||
| 13 | * and store_template. | ||
| 14 | */ | ||
| 15 | #include <linux/module.h> | ||
| 16 | |||
| 17 | #include "ima.h" | ||
| 18 | static const char *IMA_TEMPLATE_NAME = "ima"; | ||
| 19 | |||
| 20 | /* | ||
| 21 | * ima_store_template - store ima template measurements | ||
| 22 | * | ||
| 23 | * Calculate the hash of a template entry, add the template entry | ||
| 24 | * to an ordered list of measurement entries maintained inside the kernel, | ||
| 25 | * and also update the aggregate integrity value (maintained inside the | ||
| 26 | * configured TPM PCR) over the hashes of the current list of measurement | ||
| 27 | * entries. | ||
| 28 | * | ||
| 29 | * Applications retrieve the current kernel-held measurement list through | ||
| 30 | * the securityfs entries in /sys/kernel/security/ima. The signed aggregate | ||
| 31 | * TPM PCR (called quote) can be retrieved using a TPM user space library | ||
| 32 | * and is used to validate the measurement list. | ||
| 33 | * | ||
| 34 | * Returns 0 on success, error code otherwise | ||
| 35 | */ | ||
| 36 | int ima_store_template(struct ima_template_entry *entry, | ||
| 37 | int violation, struct inode *inode) | ||
| 38 | { | ||
| 39 | const char *op = "add_template_measure"; | ||
| 40 | const char *audit_cause = "hashing_error"; | ||
| 41 | int result; | ||
| 42 | |||
| 43 | memset(entry->digest, 0, sizeof(entry->digest)); | ||
| 44 | entry->template_name = IMA_TEMPLATE_NAME; | ||
| 45 | entry->template_len = sizeof(entry->template); | ||
| 46 | |||
| 47 | if (!violation) { | ||
| 48 | result = ima_calc_template_hash(entry->template_len, | ||
| 49 | &entry->template, | ||
| 50 | entry->digest); | ||
| 51 | if (result < 0) { | ||
| 52 | integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, | ||
| 53 | entry->template_name, op, | ||
| 54 | audit_cause, result, 0); | ||
| 55 | return result; | ||
| 56 | } | ||
| 57 | } | ||
| 58 | result = ima_add_template_entry(entry, violation, op, inode); | ||
| 59 | return result; | ||
| 60 | } | ||
| 61 | |||
| 62 | /* | ||
| 63 | * ima_add_violation - add violation to measurement list. | ||
| 64 | * | ||
| 65 | * Violations are flagged in the measurement list with zero hash values. | ||
| 66 | * By extending the PCR with 0xFF's instead of with zeroes, the PCR | ||
| 67 | * value is invalidated. | ||
| 68 | */ | ||
| 69 | void ima_add_violation(struct inode *inode, const unsigned char *filename, | ||
| 70 | const char *op, const char *cause) | ||
| 71 | { | ||
| 72 | struct ima_template_entry *entry; | ||
| 73 | int violation = 1; | ||
| 74 | int result; | ||
| 75 | |||
| 76 | /* can overflow, only indicator */ | ||
| 77 | atomic_long_inc(&ima_htable.violations); | ||
| 78 | |||
| 79 | entry = kmalloc(sizeof(*entry), GFP_KERNEL); | ||
| 80 | if (!entry) { | ||
| 81 | result = -ENOMEM; | ||
| 82 | goto err_out; | ||
| 83 | } | ||
| 84 | memset(&entry->template, 0, sizeof(entry->template)); | ||
| 85 | strncpy(entry->template.file_name, filename, IMA_EVENT_NAME_LEN_MAX); | ||
| 86 | result = ima_store_template(entry, violation, inode); | ||
| 87 | if (result < 0) | ||
| 88 | kfree(entry); | ||
| 89 | err_out: | ||
| 90 | integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, filename, | ||
| 91 | op, cause, result, 0); | ||
| 92 | } | ||
| 93 | |||
| 94 | /** | ||
| 95 | * ima_must_measure - measure decision based on policy. | ||
| 96 | * @inode: pointer to inode to measure | ||
| 97 | * @mask: contains the permission mask (MAY_READ, MAY_WRITE, MAY_EXECUTE) | ||
| 98 | * @function: calling function (PATH_CHECK, BPRM_CHECK, FILE_MMAP) | ||
| 99 | * | ||
| 100 | * The policy is defined in terms of keypairs: | ||
| 101 | * subj=, obj=, type=, func=, mask=, fsmagic= | ||
| 102 | * subj,obj, and type: are LSM specific. | ||
| 103 | * func: PATH_CHECK | BPRM_CHECK | FILE_MMAP | ||
| 104 | * mask: contains the permission mask | ||
| 105 | * fsmagic: hex value | ||
| 106 | * | ||
| 107 | * Must be called with iint->mutex held. | ||
| 108 | * | ||
| 109 | * Return 0 to measure. Return 1 if already measured. | ||
| 110 | * For matching a DONT_MEASURE policy, no policy, or other | ||
| 111 | * error, return an error code. | ||
| 112 | */ | ||
| 113 | int ima_must_measure(struct ima_iint_cache *iint, struct inode *inode, | ||
| 114 | int mask, int function) | ||
| 115 | { | ||
| 116 | int must_measure; | ||
| 117 | |||
| 118 | if (iint->flags & IMA_MEASURED) | ||
| 119 | return 1; | ||
| 120 | |||
| 121 | must_measure = ima_match_policy(inode, function, mask); | ||
| 122 | return must_measure ? 0 : -EACCES; | ||
| 123 | } | ||
| 124 | |||
| 125 | /* | ||
| 126 | * ima_collect_measurement - collect file measurement | ||
| 127 | * | ||
| 128 | * Calculate the file hash, if it doesn't already exist, | ||
| 129 | * storing the measurement and i_version in the iint. | ||
| 130 | * | ||
| 131 | * Must be called with iint->mutex held. | ||
| 132 | * | ||
| 133 | * Return 0 on success, error code otherwise | ||
| 134 | */ | ||
| 135 | int ima_collect_measurement(struct ima_iint_cache *iint, struct file *file) | ||
| 136 | { | ||
| 137 | int result = -EEXIST; | ||
| 138 | |||
| 139 | if (!(iint->flags & IMA_MEASURED)) { | ||
| 140 | u64 i_version = file->f_dentry->d_inode->i_version; | ||
| 141 | |||
| 142 | memset(iint->digest, 0, IMA_DIGEST_SIZE); | ||
| 143 | result = ima_calc_hash(file, iint->digest); | ||
| 144 | if (!result) | ||
| 145 | iint->version = i_version; | ||
| 146 | } | ||
| 147 | return result; | ||
| 148 | } | ||
| 149 | |||
| 150 | /* | ||
| 151 | * ima_store_measurement - store file measurement | ||
| 152 | * | ||
| 153 | * Create an "ima" template and then store the template by calling | ||
| 154 | * ima_store_template. | ||
| 155 | * | ||
| 156 | * We only get here if the inode has not already been measured, | ||
| 157 | * but the measurement could already exist: | ||
| 158 | * - multiple copies of the same file on either the same or | ||
| 159 | * different filesystems. | ||
| 160 | * - the inode was previously flushed as well as the iint info, | ||
| 161 | * containing the hashing info. | ||
| 162 | * | ||
| 163 | * Must be called with iint->mutex held. | ||
| 164 | */ | ||
| 165 | void ima_store_measurement(struct ima_iint_cache *iint, struct file *file, | ||
| 166 | const unsigned char *filename) | ||
| 167 | { | ||
| 168 | const char *op = "add_template_measure"; | ||
| 169 | const char *audit_cause = "ENOMEM"; | ||
| 170 | int result = -ENOMEM; | ||
| 171 | struct inode *inode = file->f_dentry->d_inode; | ||
| 172 | struct ima_template_entry *entry; | ||
| 173 | int violation = 0; | ||
| 174 | |||
| 175 | entry = kmalloc(sizeof(*entry), GFP_KERNEL); | ||
| 176 | if (!entry) { | ||
| 177 | integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, filename, | ||
| 178 | op, audit_cause, result, 0); | ||
| 179 | return; | ||
| 180 | } | ||
| 181 | memset(&entry->template, 0, sizeof(entry->template)); | ||
| 182 | memcpy(entry->template.digest, iint->digest, IMA_DIGEST_SIZE); | ||
| 183 | strncpy(entry->template.file_name, filename, IMA_EVENT_NAME_LEN_MAX); | ||
| 184 | |||
| 185 | result = ima_store_template(entry, violation, inode); | ||
| 186 | if (!result) | ||
| 187 | iint->flags |= IMA_MEASURED; | ||
| 188 | else | ||
| 189 | kfree(entry); | ||
| 190 | } | ||
