diff options
| author | Mimi Zohar <zohar@linux.vnet.ibm.com> | 2009-02-04 09:06:59 -0500 |
|---|---|---|
| committer | James Morris <jmorris@namei.org> | 2009-02-05 17:05:31 -0500 |
| commit | bab739378758a1e2b2d7ddcee7bc06cf4c591c3c (patch) | |
| tree | 5465ab3ccaf20ab8fb4f649aad8d1b08bfe49232 /security/integrity | |
| parent | 3323eec921efd815178a23107ab63588c605c0b2 (diff) | |
integrity: IMA display
Make the measurement lists available through securityfs.
- removed test for NULL return code from securityfs_create_file/dir
Signed-off-by: Mimi Zohar <zohar@us.ibm.com>
Acked-by: Serge Hallyn <serue@us.ibm.com>
Signed-off-by: James Morris <jmorris@namei.org>
Diffstat (limited to 'security/integrity')
| -rw-r--r-- | security/integrity/ima/Makefile | 2 | ||||
| -rw-r--r-- | security/integrity/ima/ima.h | 5 | ||||
| -rw-r--r-- | security/integrity/ima/ima_fs.c | 296 | ||||
| -rw-r--r-- | security/integrity/ima/ima_init.c | 8 | ||||
| -rw-r--r-- | security/integrity/ima/ima_main.c | 5 |
5 files changed, 314 insertions, 2 deletions
diff --git a/security/integrity/ima/Makefile b/security/integrity/ima/Makefile index 9d6bf973b9be..787c4cb916cd 100644 --- a/security/integrity/ima/Makefile +++ b/security/integrity/ima/Makefile | |||
| @@ -5,5 +5,5 @@ | |||
| 5 | 5 | ||
| 6 | obj-$(CONFIG_IMA) += ima.o | 6 | obj-$(CONFIG_IMA) += ima.o |
| 7 | 7 | ||
| 8 | ima-y := ima_queue.o ima_init.o ima_main.o ima_crypto.o ima_api.o \ | 8 | ima-y := ima_fs.o ima_queue.o ima_init.o ima_main.o ima_crypto.o ima_api.o \ |
| 9 | ima_policy.o ima_iint.o ima_audit.o | 9 | ima_policy.o ima_iint.o ima_audit.o |
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index bfa72ed41b9b..9c280cc73004 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h | |||
| @@ -67,6 +67,9 @@ void integrity_audit_msg(int audit_msgno, struct inode *inode, | |||
| 67 | /* Internal IMA function definitions */ | 67 | /* Internal IMA function definitions */ |
| 68 | void ima_iintcache_init(void); | 68 | void ima_iintcache_init(void); |
| 69 | int ima_init(void); | 69 | int ima_init(void); |
| 70 | void ima_cleanup(void); | ||
| 71 | int ima_fs_init(void); | ||
| 72 | void ima_fs_cleanup(void); | ||
| 70 | int ima_add_template_entry(struct ima_template_entry *entry, int violation, | 73 | int ima_add_template_entry(struct ima_template_entry *entry, int violation, |
| 71 | const char *op, struct inode *inode); | 74 | const char *op, struct inode *inode); |
| 72 | int ima_calc_hash(struct file *file, char *digest); | 75 | int ima_calc_hash(struct file *file, char *digest); |
| @@ -115,6 +118,8 @@ void ima_store_measurement(struct ima_iint_cache *iint, struct file *file, | |||
| 115 | const unsigned char *filename); | 118 | const unsigned char *filename); |
| 116 | int ima_store_template(struct ima_template_entry *entry, int violation, | 119 | int ima_store_template(struct ima_template_entry *entry, int violation, |
| 117 | struct inode *inode); | 120 | struct inode *inode); |
| 121 | void ima_template_show(struct seq_file *m, void *e, | ||
| 122 | enum ima_show_type show); | ||
| 118 | 123 | ||
| 119 | /* radix tree calls to lookup, insert, delete | 124 | /* radix tree calls to lookup, insert, delete |
| 120 | * integrity data associated with an inode. | 125 | * integrity data associated with an inode. |
diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c new file mode 100644 index 000000000000..4f25be768b50 --- /dev/null +++ b/security/integrity/ima/ima_fs.c | |||
| @@ -0,0 +1,296 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2005,2006,2007,2008 IBM Corporation | ||
| 3 | * | ||
| 4 | * Authors: | ||
| 5 | * Kylene Hall <kjhall@us.ibm.com> | ||
| 6 | * Reiner Sailer <sailer@us.ibm.com> | ||
| 7 | * Mimi Zohar <zohar@us.ibm.com> | ||
| 8 | * | ||
| 9 | * This program is free software; you can redistribute it and/or | ||
| 10 | * modify it under the terms of the GNU General Public License as | ||
| 11 | * published by the Free Software Foundation, version 2 of the | ||
| 12 | * License. | ||
| 13 | * | ||
| 14 | * File: ima_fs.c | ||
| 15 | * implemenents security file system for reporting | ||
| 16 | * current measurement list and IMA statistics | ||
| 17 | */ | ||
| 18 | #include <linux/module.h> | ||
| 19 | #include <linux/seq_file.h> | ||
| 20 | #include <linux/rculist.h> | ||
| 21 | #include <linux/rcupdate.h> | ||
| 22 | |||
| 23 | #include "ima.h" | ||
| 24 | |||
| 25 | #define TMPBUFLEN 12 | ||
| 26 | static ssize_t ima_show_htable_value(char __user *buf, size_t count, | ||
| 27 | loff_t *ppos, atomic_long_t *val) | ||
| 28 | { | ||
| 29 | char tmpbuf[TMPBUFLEN]; | ||
| 30 | ssize_t len; | ||
| 31 | |||
| 32 | len = scnprintf(tmpbuf, TMPBUFLEN, "%li\n", atomic_long_read(val)); | ||
| 33 | return simple_read_from_buffer(buf, count, ppos, tmpbuf, len); | ||
| 34 | } | ||
| 35 | |||
| 36 | static ssize_t ima_show_htable_violations(struct file *filp, | ||
| 37 | char __user *buf, | ||
| 38 | size_t count, loff_t *ppos) | ||
| 39 | { | ||
| 40 | return ima_show_htable_value(buf, count, ppos, &ima_htable.violations); | ||
| 41 | } | ||
| 42 | |||
| 43 | static struct file_operations ima_htable_violations_ops = { | ||
| 44 | .read = ima_show_htable_violations | ||
| 45 | }; | ||
| 46 | |||
| 47 | static ssize_t ima_show_measurements_count(struct file *filp, | ||
| 48 | char __user *buf, | ||
| 49 | size_t count, loff_t *ppos) | ||
| 50 | { | ||
| 51 | return ima_show_htable_value(buf, count, ppos, &ima_htable.len); | ||
| 52 | |||
| 53 | } | ||
| 54 | |||
| 55 | static struct file_operations ima_measurements_count_ops = { | ||
| 56 | .read = ima_show_measurements_count | ||
| 57 | }; | ||
| 58 | |||
| 59 | /* returns pointer to hlist_node */ | ||
| 60 | static void *ima_measurements_start(struct seq_file *m, loff_t *pos) | ||
| 61 | { | ||
| 62 | loff_t l = *pos; | ||
| 63 | struct ima_queue_entry *qe; | ||
| 64 | |||
| 65 | /* we need a lock since pos could point beyond last element */ | ||
| 66 | rcu_read_lock(); | ||
| 67 | list_for_each_entry_rcu(qe, &ima_measurements, later) { | ||
| 68 | if (!l--) { | ||
| 69 | rcu_read_unlock(); | ||
| 70 | return qe; | ||
| 71 | } | ||
| 72 | } | ||
| 73 | rcu_read_unlock(); | ||
| 74 | return NULL; | ||
| 75 | } | ||
| 76 | |||
| 77 | static void *ima_measurements_next(struct seq_file *m, void *v, loff_t *pos) | ||
| 78 | { | ||
| 79 | struct ima_queue_entry *qe = v; | ||
| 80 | |||
| 81 | /* lock protects when reading beyond last element | ||
| 82 | * against concurrent list-extension | ||
| 83 | */ | ||
| 84 | rcu_read_lock(); | ||
| 85 | qe = list_entry(rcu_dereference(qe->later.next), | ||
| 86 | struct ima_queue_entry, later); | ||
| 87 | rcu_read_unlock(); | ||
| 88 | (*pos)++; | ||
| 89 | |||
| 90 | return (&qe->later == &ima_measurements) ? NULL : qe; | ||
| 91 | } | ||
| 92 | |||
| 93 | static void ima_measurements_stop(struct seq_file *m, void *v) | ||
| 94 | { | ||
| 95 | } | ||
| 96 | |||
| 97 | static void ima_putc(struct seq_file *m, void *data, int datalen) | ||
| 98 | { | ||
| 99 | while (datalen--) | ||
| 100 | seq_putc(m, *(char *)data++); | ||
| 101 | } | ||
| 102 | |||
| 103 | /* print format: | ||
| 104 | * 32bit-le=pcr# | ||
| 105 | * char[20]=template digest | ||
| 106 | * 32bit-le=template name size | ||
| 107 | * char[n]=template name | ||
| 108 | * eventdata[n]=template specific data | ||
| 109 | */ | ||
| 110 | static int ima_measurements_show(struct seq_file *m, void *v) | ||
| 111 | { | ||
| 112 | /* the list never shrinks, so we don't need a lock here */ | ||
| 113 | struct ima_queue_entry *qe = v; | ||
| 114 | struct ima_template_entry *e; | ||
| 115 | int namelen; | ||
| 116 | u32 pcr = CONFIG_IMA_MEASURE_PCR_IDX; | ||
| 117 | |||
| 118 | /* get entry */ | ||
| 119 | e = qe->entry; | ||
| 120 | if (e == NULL) | ||
| 121 | return -1; | ||
| 122 | |||
| 123 | /* | ||
| 124 | * 1st: PCRIndex | ||
| 125 | * PCR used is always the same (config option) in | ||
| 126 | * little-endian format | ||
| 127 | */ | ||
| 128 | ima_putc(m, &pcr, sizeof pcr); | ||
| 129 | |||
| 130 | /* 2nd: template digest */ | ||
| 131 | ima_putc(m, e->digest, IMA_DIGEST_SIZE); | ||
| 132 | |||
| 133 | /* 3rd: template name size */ | ||
| 134 | namelen = strlen(e->template_name); | ||
| 135 | ima_putc(m, &namelen, sizeof namelen); | ||
| 136 | |||
| 137 | /* 4th: template name */ | ||
| 138 | ima_putc(m, e->template_name, namelen); | ||
| 139 | |||
| 140 | /* 5th: template specific data */ | ||
| 141 | ima_template_show(m, (struct ima_template_data *)&e->template, | ||
| 142 | IMA_SHOW_BINARY); | ||
| 143 | return 0; | ||
| 144 | } | ||
| 145 | |||
| 146 | static struct seq_operations ima_measurments_seqops = { | ||
| 147 | .start = ima_measurements_start, | ||
| 148 | .next = ima_measurements_next, | ||
| 149 | .stop = ima_measurements_stop, | ||
| 150 | .show = ima_measurements_show | ||
| 151 | }; | ||
| 152 | |||
| 153 | static int ima_measurements_open(struct inode *inode, struct file *file) | ||
| 154 | { | ||
| 155 | return seq_open(file, &ima_measurments_seqops); | ||
| 156 | } | ||
| 157 | |||
| 158 | static struct file_operations ima_measurements_ops = { | ||
| 159 | .open = ima_measurements_open, | ||
| 160 | .read = seq_read, | ||
| 161 | .llseek = seq_lseek, | ||
| 162 | .release = seq_release, | ||
| 163 | }; | ||
| 164 | |||
| 165 | static void ima_print_digest(struct seq_file *m, u8 *digest) | ||
| 166 | { | ||
| 167 | int i; | ||
| 168 | |||
| 169 | for (i = 0; i < IMA_DIGEST_SIZE; i++) | ||
| 170 | seq_printf(m, "%02x", *(digest + i)); | ||
| 171 | } | ||
| 172 | |||
| 173 | void ima_template_show(struct seq_file *m, void *e, enum ima_show_type show) | ||
| 174 | { | ||
| 175 | struct ima_template_data *entry = e; | ||
| 176 | int namelen; | ||
| 177 | |||
| 178 | switch (show) { | ||
| 179 | case IMA_SHOW_ASCII: | ||
| 180 | ima_print_digest(m, entry->digest); | ||
| 181 | seq_printf(m, " %s\n", entry->file_name); | ||
| 182 | break; | ||
| 183 | case IMA_SHOW_BINARY: | ||
| 184 | ima_putc(m, entry->digest, IMA_DIGEST_SIZE); | ||
| 185 | |||
| 186 | namelen = strlen(entry->file_name); | ||
| 187 | ima_putc(m, &namelen, sizeof namelen); | ||
| 188 | ima_putc(m, entry->file_name, namelen); | ||
| 189 | default: | ||
| 190 | break; | ||
| 191 | } | ||
| 192 | } | ||
| 193 | |||
| 194 | /* print in ascii */ | ||
| 195 | static int ima_ascii_measurements_show(struct seq_file *m, void *v) | ||
| 196 | { | ||
| 197 | /* the list never shrinks, so we don't need a lock here */ | ||
| 198 | struct ima_queue_entry *qe = v; | ||
| 199 | struct ima_template_entry *e; | ||
| 200 | |||
| 201 | /* get entry */ | ||
| 202 | e = qe->entry; | ||
| 203 | if (e == NULL) | ||
| 204 | return -1; | ||
| 205 | |||
| 206 | /* 1st: PCR used (config option) */ | ||
| 207 | seq_printf(m, "%2d ", CONFIG_IMA_MEASURE_PCR_IDX); | ||
| 208 | |||
| 209 | /* 2nd: SHA1 template hash */ | ||
| 210 | ima_print_digest(m, e->digest); | ||
| 211 | |||
| 212 | /* 3th: template name */ | ||
| 213 | seq_printf(m, " %s ", e->template_name); | ||
| 214 | |||
| 215 | /* 4th: template specific data */ | ||
| 216 | ima_template_show(m, (struct ima_template_data *)&e->template, | ||
| 217 | IMA_SHOW_ASCII); | ||
| 218 | return 0; | ||
| 219 | } | ||
| 220 | |||
| 221 | static struct seq_operations ima_ascii_measurements_seqops = { | ||
| 222 | .start = ima_measurements_start, | ||
| 223 | .next = ima_measurements_next, | ||
| 224 | .stop = ima_measurements_stop, | ||
| 225 | .show = ima_ascii_measurements_show | ||
| 226 | }; | ||
| 227 | |||
| 228 | static int ima_ascii_measurements_open(struct inode *inode, struct file *file) | ||
| 229 | { | ||
| 230 | return seq_open(file, &ima_ascii_measurements_seqops); | ||
| 231 | } | ||
| 232 | |||
| 233 | static struct file_operations ima_ascii_measurements_ops = { | ||
| 234 | .open = ima_ascii_measurements_open, | ||
| 235 | .read = seq_read, | ||
| 236 | .llseek = seq_lseek, | ||
| 237 | .release = seq_release, | ||
| 238 | }; | ||
| 239 | |||
| 240 | static struct dentry *ima_dir; | ||
| 241 | static struct dentry *binary_runtime_measurements; | ||
| 242 | static struct dentry *ascii_runtime_measurements; | ||
| 243 | static struct dentry *runtime_measurements_count; | ||
| 244 | static struct dentry *violations; | ||
| 245 | |||
| 246 | int ima_fs_init(void) | ||
| 247 | { | ||
| 248 | ima_dir = securityfs_create_dir("ima", NULL); | ||
| 249 | if (IS_ERR(ima_dir)) | ||
| 250 | return -1; | ||
| 251 | |||
| 252 | binary_runtime_measurements = | ||
| 253 | securityfs_create_file("binary_runtime_measurements", | ||
| 254 | S_IRUSR | S_IRGRP, ima_dir, NULL, | ||
| 255 | &ima_measurements_ops); | ||
| 256 | if (IS_ERR(binary_runtime_measurements)) | ||
| 257 | goto out; | ||
| 258 | |||
| 259 | ascii_runtime_measurements = | ||
| 260 | securityfs_create_file("ascii_runtime_measurements", | ||
| 261 | S_IRUSR | S_IRGRP, ima_dir, NULL, | ||
| 262 | &ima_ascii_measurements_ops); | ||
| 263 | if (IS_ERR(ascii_runtime_measurements)) | ||
| 264 | goto out; | ||
| 265 | |||
| 266 | runtime_measurements_count = | ||
| 267 | securityfs_create_file("runtime_measurements_count", | ||
| 268 | S_IRUSR | S_IRGRP, ima_dir, NULL, | ||
| 269 | &ima_measurements_count_ops); | ||
| 270 | if (IS_ERR(runtime_measurements_count)) | ||
| 271 | goto out; | ||
| 272 | |||
| 273 | violations = | ||
| 274 | securityfs_create_file("violations", S_IRUSR | S_IRGRP, | ||
| 275 | ima_dir, NULL, &ima_htable_violations_ops); | ||
| 276 | if (IS_ERR(violations)) | ||
| 277 | goto out; | ||
| 278 | |||
| 279 | return 0; | ||
| 280 | |||
| 281 | out: | ||
| 282 | securityfs_remove(runtime_measurements_count); | ||
| 283 | securityfs_remove(ascii_runtime_measurements); | ||
| 284 | securityfs_remove(binary_runtime_measurements); | ||
| 285 | securityfs_remove(ima_dir); | ||
| 286 | return -1; | ||
| 287 | } | ||
| 288 | |||
| 289 | void __exit ima_fs_cleanup(void) | ||
| 290 | { | ||
| 291 | securityfs_remove(violations); | ||
| 292 | securityfs_remove(runtime_measurements_count); | ||
| 293 | securityfs_remove(ascii_runtime_measurements); | ||
| 294 | securityfs_remove(binary_runtime_measurements); | ||
| 295 | securityfs_remove(ima_dir); | ||
| 296 | } | ||
diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c index e0f02e328d77..cf227dbfac2c 100644 --- a/security/integrity/ima/ima_init.c +++ b/security/integrity/ima/ima_init.c | |||
| @@ -86,5 +86,11 @@ int ima_init(void) | |||
| 86 | 86 | ||
| 87 | ima_add_boot_aggregate(); /* boot aggregate must be first entry */ | 87 | ima_add_boot_aggregate(); /* boot aggregate must be first entry */ |
| 88 | ima_init_policy(); | 88 | ima_init_policy(); |
| 89 | return 0; | 89 | |
| 90 | return ima_fs_init(); | ||
| 91 | } | ||
| 92 | |||
| 93 | void __exit ima_cleanup(void) | ||
| 94 | { | ||
| 95 | ima_fs_cleanup(); | ||
| 90 | } | 96 | } |
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index 53cee4c512ce..871e356e8d6c 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c | |||
| @@ -274,6 +274,11 @@ static int __init init_ima(void) | |||
| 274 | return error; | 274 | return error; |
| 275 | } | 275 | } |
| 276 | 276 | ||
| 277 | static void __exit cleanup_ima(void) | ||
| 278 | { | ||
| 279 | ima_cleanup(); | ||
| 280 | } | ||
| 281 | |||
| 277 | late_initcall(init_ima); /* Start IMA after the TPM is available */ | 282 | late_initcall(init_ima); /* Start IMA after the TPM is available */ |
| 278 | 283 | ||
| 279 | MODULE_DESCRIPTION("Integrity Measurement Architecture"); | 284 | MODULE_DESCRIPTION("Integrity Measurement Architecture"); |
