diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-12-15 05:36:37 +0100 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-12-15 05:36:37 +0100 |
commit | 67e2c3883828b39548cee2091b36656787775d95 (patch) | |
tree | 975a0f546a604beda30d4ede34f8e9cca9a88b71 /security/integrity | |
parent | Merge tag 'char-misc-3.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/g... (diff) | |
parent | Merge branch 'next' of git://git.infradead.org/users/pcmoore/selinux into next (diff) | |
download | linux-67e2c3883828b39548cee2091b36656787775d95.tar.xz linux-67e2c3883828b39548cee2091b36656787775d95.zip |
Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security
Pull security layer updates from James Morris:
"In terms of changes, there's general maintenance to the Smack,
SELinux, and integrity code.
The IMA code adds a new kconfig option, IMA_APPRAISE_SIGNED_INIT,
which allows IMA appraisal to require signatures. Support for reading
keys from rootfs before init is call is also added"
* 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security: (23 commits)
selinux: Remove security_ops extern
security: smack: fix out-of-bounds access in smk_parse_smack()
VFS: refactor vfs_read()
ima: require signature based appraisal
integrity: provide a hook to load keys when rootfs is ready
ima: load x509 certificate from the kernel
integrity: provide a function to load x509 certificate from the kernel
integrity: define a new function integrity_read_file()
Security: smack: replace kzalloc with kmem_cache for inode_smack
Smack: Lock mode for the floor and hat labels
ima: added support for new kernel cmdline parameter ima_template_fmt
ima: allocate field pointers array on demand in template_desc_init_fields()
ima: don't allocate a copy of template_fmt in template_desc_init_fields()
ima: display template format in meas. list if template name length is zero
ima: added error messages to template-related functions
ima: use atomic bit operations to protect policy update interface
ima: ignore empty and with whitespaces policy lines
ima: no need to allocate entry for comment
ima: report policy load status
ima: use path names cache
...
Diffstat (limited to 'security/integrity')
-rw-r--r-- | security/integrity/digsig.c | 38 | ||||
-rw-r--r-- | security/integrity/evm/evm_main.c | 11 | ||||
-rw-r--r-- | security/integrity/iint.c | 88 | ||||
-rw-r--r-- | security/integrity/ima/Kconfig | 25 | ||||
-rw-r--r-- | security/integrity/ima/ima_api.c | 7 | ||||
-rw-r--r-- | security/integrity/ima/ima_crypto.c | 35 | ||||
-rw-r--r-- | security/integrity/ima/ima_fs.c | 37 | ||||
-rw-r--r-- | security/integrity/ima/ima_init.c | 17 | ||||
-rw-r--r-- | security/integrity/ima/ima_main.c | 5 | ||||
-rw-r--r-- | security/integrity/ima/ima_policy.c | 42 | ||||
-rw-r--r-- | security/integrity/ima/ima_template.c | 103 | ||||
-rw-r--r-- | security/integrity/integrity.h | 19 |
12 files changed, 308 insertions, 119 deletions
diff --git a/security/integrity/digsig.c b/security/integrity/digsig.c index 8d4fbff8b87c..5e3bd72b299a 100644 --- a/security/integrity/digsig.c +++ b/security/integrity/digsig.c @@ -14,7 +14,7 @@ #include <linux/err.h> #include <linux/sched.h> -#include <linux/rbtree.h> +#include <linux/slab.h> #include <linux/cred.h> #include <linux/key-type.h> #include <linux/digsig.h> @@ -63,7 +63,7 @@ int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen, return -EOPNOTSUPP; } -int integrity_init_keyring(const unsigned int id) +int __init integrity_init_keyring(const unsigned int id) { const struct cred *cred = current_cred(); int err = 0; @@ -84,3 +84,37 @@ int integrity_init_keyring(const unsigned int id) } return err; } + +int __init integrity_load_x509(const unsigned int id, char *path) +{ + key_ref_t key; + char *data; + int rc; + + if (!keyring[id]) + return -EINVAL; + + rc = integrity_read_file(path, &data); + if (rc < 0) + return rc; + + key = key_create_or_update(make_key_ref(keyring[id], 1), + "asymmetric", + NULL, + data, + rc, + ((KEY_POS_ALL & ~KEY_POS_SETATTR) | + KEY_USR_VIEW | KEY_USR_READ), + KEY_ALLOC_NOT_IN_QUOTA | KEY_ALLOC_TRUSTED); + if (IS_ERR(key)) { + rc = PTR_ERR(key); + pr_err("Problem loading X.509 certificate (%d): %s\n", + rc, path); + } else { + pr_notice("Loaded X.509 cert '%s': %s\n", + key_ref_to_ptr(key)->description, path); + key_ref_put(key); + } + kfree(data); + return 0; +} diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c index c5ee1a7c5e8a..f589c9a05da2 100644 --- a/security/integrity/evm/evm_main.c +++ b/security/integrity/evm/evm_main.c @@ -162,9 +162,14 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry, (const char *)xattr_data, xattr_len, calc.digest, sizeof(calc.digest)); if (!rc) { - /* we probably want to replace rsa with hmac here */ - evm_update_evmxattr(dentry, xattr_name, xattr_value, - xattr_value_len); + /* Replace RSA with HMAC if not mounted readonly and + * not immutable + */ + if (!IS_RDONLY(dentry->d_inode) && + !IS_IMMUTABLE(dentry->d_inode)) + evm_update_evmxattr(dentry, xattr_name, + xattr_value, + xattr_value_len); } break; default: diff --git a/security/integrity/iint.c b/security/integrity/iint.c index a521edf4cbd6..dbb6d141c3db 100644 --- a/security/integrity/iint.c +++ b/security/integrity/iint.c @@ -19,14 +19,14 @@ #include <linux/module.h> #include <linux/spinlock.h> #include <linux/rbtree.h> +#include <linux/file.h> +#include <linux/uaccess.h> #include "integrity.h" static struct rb_root integrity_iint_tree = RB_ROOT; static DEFINE_RWLOCK(integrity_iint_lock); static struct kmem_cache *iint_cache __read_mostly; -int iint_initialized; - /* * __integrity_iint_find - return the iint associated with an inode */ @@ -166,7 +166,89 @@ static int __init integrity_iintcache_init(void) iint_cache = kmem_cache_create("iint_cache", sizeof(struct integrity_iint_cache), 0, SLAB_PANIC, init_once); - iint_initialized = 1; return 0; } security_initcall(integrity_iintcache_init); + + +/* + * integrity_kernel_read - read data from the file + * + * This is a function for reading file content instead of kernel_read(). + * It does not perform locking checks to ensure it cannot be blocked. + * It does not perform security checks because it is irrelevant for IMA. + * + */ +int integrity_kernel_read(struct file *file, loff_t offset, + char *addr, unsigned long count) +{ + mm_segment_t old_fs; + char __user *buf = (char __user *)addr; + ssize_t ret; + + if (!(file->f_mode & FMODE_READ)) + return -EBADF; + + old_fs = get_fs(); + set_fs(get_ds()); + ret = __vfs_read(file, buf, count, &offset); + set_fs(old_fs); + + return ret; +} + +/* + * integrity_read_file - read entire file content into the buffer + * + * This is function opens a file, allocates the buffer of required + * size, read entire file content to the buffer and closes the file + * + * It is used only by init code. + * + */ +int __init integrity_read_file(const char *path, char **data) +{ + struct file *file; + loff_t size; + char *buf; + int rc = -EINVAL; + + file = filp_open(path, O_RDONLY, 0); + if (IS_ERR(file)) { + rc = PTR_ERR(file); + pr_err("Unable to open file: %s (%d)", path, rc); + return rc; + } + + size = i_size_read(file_inode(file)); + if (size <= 0) + goto out; + + buf = kmalloc(size, GFP_KERNEL); + if (!buf) { + rc = -ENOMEM; + goto out; + } + + rc = integrity_kernel_read(file, 0, buf, size); + if (rc < 0) + kfree(buf); + else if (rc != size) + rc = -EIO; + else + *data = buf; +out: + fput(file); + return rc; +} + +/* + * integrity_load_keys - load integrity keys hook + * + * Hooks is called from init/main.c:kernel_init_freeable() + * when rootfs is ready + */ +void __init integrity_load_keys(void) +{ + ima_load_x509(); +} diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig index e099875643c5..b80a93ec1ccc 100644 --- a/security/integrity/ima/Kconfig +++ b/security/integrity/ima/Kconfig @@ -131,3 +131,28 @@ config IMA_TRUSTED_KEYRING help This option requires that all keys added to the .ima keyring be signed by a key on the system trusted keyring. + +config IMA_LOAD_X509 + bool "Load X509 certificate onto the '.ima' trusted keyring" + depends on IMA_TRUSTED_KEYRING + default n + help + File signature verification is based on the public keys + loaded on the .ima trusted keyring. These public keys are + X509 certificates signed by a trusted key on the + .system keyring. This option enables X509 certificate + loading from the kernel onto the '.ima' trusted keyring. + +config IMA_X509_PATH + string "IMA X509 certificate path" + depends on IMA_LOAD_X509 + default "/etc/keys/x509_ima.der" + help + This option defines IMA X509 certificate path. + +config IMA_APPRAISE_SIGNED_INIT + bool "Require signed user-space initialization" + depends on IMA_LOAD_X509 + default n + help + This option requires user-space init to be signed. diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c index f92be1b14089..b8a27c5052d4 100644 --- a/security/integrity/ima/ima_api.c +++ b/security/integrity/ima/ima_api.c @@ -173,8 +173,7 @@ int ima_get_action(struct inode *inode, int mask, int function) { int flags = IMA_MEASURE | IMA_AUDIT | IMA_APPRAISE; - if (!ima_appraise) - flags &= ~IMA_APPRAISE; + flags &= ima_policy_flag; return ima_match_policy(inode, function, mask, flags); } @@ -325,11 +324,11 @@ const char *ima_d_path(struct path *path, char **pathbuf) { char *pathname = NULL; - *pathbuf = kmalloc(PATH_MAX, GFP_KERNEL); + *pathbuf = __getname(); if (*pathbuf) { pathname = d_absolute_path(path, *pathbuf, PATH_MAX); if (IS_ERR(pathname)) { - kfree(*pathbuf); + __putname(*pathbuf); *pathbuf = NULL; pathname = NULL; } diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c index 78d66dae15f4..686355fea7fd 100644 --- a/security/integrity/ima/ima_crypto.c +++ b/security/integrity/ima/ima_crypto.c @@ -67,36 +67,6 @@ MODULE_PARM_DESC(ahash_bufsize, "Maximum ahash buffer size"); static struct crypto_shash *ima_shash_tfm; static struct crypto_ahash *ima_ahash_tfm; -/** - * ima_kernel_read - read file content - * - * This is a function for reading file content instead of kernel_read(). - * It does not perform locking checks to ensure it cannot be blocked. - * It does not perform security checks because it is irrelevant for IMA. - * - */ -static int ima_kernel_read(struct file *file, loff_t offset, - char *addr, unsigned long count) -{ - mm_segment_t old_fs; - char __user *buf = addr; - ssize_t ret = -EINVAL; - - if (!(file->f_mode & FMODE_READ)) - return -EBADF; - - old_fs = get_fs(); - set_fs(get_ds()); - if (file->f_op->read) - ret = file->f_op->read(file, buf, count, &offset); - else if (file->f_op->aio_read) - ret = do_sync_read(file, buf, count, &offset); - else if (file->f_op->read_iter) - ret = new_sync_read(file, buf, count, &offset); - set_fs(old_fs); - return ret; -} - int __init ima_init_crypto(void) { long rc; @@ -324,7 +294,8 @@ static int ima_calc_file_hash_atfm(struct file *file, } /* read buffer */ rbuf_len = min_t(loff_t, i_size - offset, rbuf_size[active]); - rc = ima_kernel_read(file, offset, rbuf[active], rbuf_len); + rc = integrity_kernel_read(file, offset, rbuf[active], + rbuf_len); if (rc != rbuf_len) goto out3; @@ -414,7 +385,7 @@ static int ima_calc_file_hash_tfm(struct file *file, while (offset < i_size) { int rbuf_len; - rbuf_len = ima_kernel_read(file, offset, rbuf, PAGE_SIZE); + rbuf_len = integrity_kernel_read(file, offset, rbuf, PAGE_SIZE); if (rbuf_len < 0) { rc = rbuf_len; break; diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c index da92fcc08d15..461215e5fd31 100644 --- a/security/integrity/ima/ima_fs.c +++ b/security/integrity/ima/ima_fs.c @@ -118,6 +118,7 @@ static int ima_measurements_show(struct seq_file *m, void *v) /* the list never shrinks, so we don't need a lock here */ struct ima_queue_entry *qe = v; struct ima_template_entry *e; + char *template_name; int namelen; u32 pcr = CONFIG_IMA_MEASURE_PCR_IDX; bool is_ima_template = false; @@ -128,6 +129,9 @@ static int ima_measurements_show(struct seq_file *m, void *v) if (e == NULL) return -1; + template_name = (e->template_desc->name[0] != '\0') ? + e->template_desc->name : e->template_desc->fmt; + /* * 1st: PCRIndex * PCR used is always the same (config option) in @@ -139,14 +143,14 @@ static int ima_measurements_show(struct seq_file *m, void *v) ima_putc(m, e->digest, TPM_DIGEST_SIZE); /* 3rd: template name size */ - namelen = strlen(e->template_desc->name); + namelen = strlen(template_name); ima_putc(m, &namelen, sizeof(namelen)); /* 4th: template name */ - ima_putc(m, e->template_desc->name, namelen); + ima_putc(m, template_name, namelen); /* 5th: template length (except for 'ima' template) */ - if (strcmp(e->template_desc->name, IMA_TEMPLATE_IMA_NAME) == 0) + if (strcmp(template_name, IMA_TEMPLATE_IMA_NAME) == 0) is_ima_template = true; if (!is_ima_template) @@ -200,6 +204,7 @@ static int ima_ascii_measurements_show(struct seq_file *m, void *v) /* the list never shrinks, so we don't need a lock here */ struct ima_queue_entry *qe = v; struct ima_template_entry *e; + char *template_name; int i; /* get entry */ @@ -207,6 +212,9 @@ static int ima_ascii_measurements_show(struct seq_file *m, void *v) if (e == NULL) return -1; + template_name = (e->template_desc->name[0] != '\0') ? + e->template_desc->name : e->template_desc->fmt; + /* 1st: PCR used (config option) */ seq_printf(m, "%2d ", CONFIG_IMA_MEASURE_PCR_IDX); @@ -214,7 +222,7 @@ static int ima_ascii_measurements_show(struct seq_file *m, void *v) ima_print_digest(m, e->digest, TPM_DIGEST_SIZE); /* 3th: template name */ - seq_printf(m, " %s", e->template_desc->name); + seq_printf(m, " %s", template_name); /* 4th: template specific data */ for (i = 0; i < e->template_desc->num_fields; i++) { @@ -288,7 +296,12 @@ static struct dentry *runtime_measurements_count; static struct dentry *violations; static struct dentry *ima_policy; -static atomic_t policy_opencount = ATOMIC_INIT(1); +enum ima_fs_flags { + IMA_FS_BUSY, +}; + +static unsigned long ima_fs_flags; + /* * ima_open_policy: sequentialize access to the policy file */ @@ -297,9 +310,9 @@ static int ima_open_policy(struct inode *inode, struct file *filp) /* No point in being allowed to open it if you aren't going to write */ if (!(filp->f_flags & O_WRONLY)) return -EACCES; - if (atomic_dec_and_test(&policy_opencount)) - return 0; - return -EBUSY; + if (test_and_set_bit(IMA_FS_BUSY, &ima_fs_flags)) + return -EBUSY; + return 0; } /* @@ -311,10 +324,16 @@ static int ima_open_policy(struct inode *inode, struct file *filp) */ static int ima_release_policy(struct inode *inode, struct file *file) { + const char *cause = valid_policy ? "completed" : "failed"; + + pr_info("IMA: policy update %s\n", cause); + integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, NULL, + "policy_update", cause, !valid_policy, 0); + if (!valid_policy) { ima_delete_rules(); valid_policy = 1; - atomic_set(&policy_opencount, 1); + clear_bit(IMA_FS_BUSY, &ima_fs_flags); return 0; } ima_update_policy(); diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c index 9164fc8cac84..5e4c29d174ee 100644 --- a/security/integrity/ima/ima_init.c +++ b/security/integrity/ima/ima_init.c @@ -24,6 +24,12 @@ #include <crypto/hash_info.h> #include "ima.h" +#ifdef CONFIG_IMA_X509_PATH +#define IMA_X509_PATH CONFIG_IMA_X509_PATH +#else +#define IMA_X509_PATH "/etc/keys/x509_ima.der" +#endif + /* name for boot aggregate entry */ static const char *boot_aggregate_name = "boot_aggregate"; int ima_used_chip; @@ -91,6 +97,17 @@ err_out: return result; } +#ifdef CONFIG_IMA_LOAD_X509 +void __init ima_load_x509(void) +{ + int unset_flags = ima_policy_flag & IMA_APPRAISE; + + ima_policy_flag &= ~unset_flags; + integrity_load_x509(INTEGRITY_KEYRING_IMA, IMA_X509_PATH); + ima_policy_flag |= unset_flags; +} +#endif + int __init ima_init(void) { u8 pcr_i[TPM_DIGEST_SIZE]; diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index 62f59eca32d3..eeee00dce729 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -143,7 +143,7 @@ void ima_file_free(struct file *file) struct inode *inode = file_inode(file); struct integrity_iint_cache *iint; - if (!iint_initialized || !S_ISREG(inode->i_mode)) + if (!ima_policy_flag || !S_ISREG(inode->i_mode)) return; iint = integrity_iint_find(inode); @@ -246,7 +246,8 @@ out_digsig: rc = -EACCES; kfree(xattr_value); out_free: - kfree(pathbuf); + if (pathbuf) + __putname(pathbuf); out: mutex_unlock(&inode->i_mutex); if ((rc && must_appraise) && (ima_appraise & IMA_APPRAISE_ENFORCE)) diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index cdc620b2152f..d1eefb9d65fb 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c @@ -100,7 +100,13 @@ static struct ima_rule_entry default_appraise_rules[] = { {.action = DONT_APPRAISE, .fsmagic = SECURITYFS_MAGIC, .flags = IMA_FSMAGIC}, {.action = DONT_APPRAISE, .fsmagic = SELINUX_MAGIC, .flags = IMA_FSMAGIC}, {.action = DONT_APPRAISE, .fsmagic = CGROUP_SUPER_MAGIC, .flags = IMA_FSMAGIC}, +#ifndef CONFIG_IMA_APPRAISE_SIGNED_INIT {.action = APPRAISE, .fowner = GLOBAL_ROOT_UID, .flags = IMA_FOWNER}, +#else + /* force signature */ + {.action = APPRAISE, .fowner = GLOBAL_ROOT_UID, + .flags = IMA_FOWNER | IMA_DIGSIG_REQUIRED}, +#endif }; static LIST_HEAD(ima_default_rules); @@ -356,19 +362,8 @@ void __init ima_init_policy(void) */ void ima_update_policy(void) { - static const char op[] = "policy_update"; - const char *cause = "already-exists"; - int result = 1; - int audit_info = 0; - - if (ima_rules == &ima_default_rules) { - ima_rules = &ima_policy_rules; - ima_update_policy_flag(); - cause = "complete"; - result = 0; - } - integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, - NULL, op, cause, result, audit_info); + ima_rules = &ima_policy_rules; + ima_update_policy_flag(); } enum { @@ -686,13 +681,12 @@ ssize_t ima_parse_add_rule(char *rule) ssize_t result, len; int audit_info = 0; - /* Prevent installed policy from changing */ - if (ima_rules != &ima_default_rules) { - integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, - NULL, op, "already-exists", - -EACCES, audit_info); - return -EACCES; - } + p = strsep(&rule, "\n"); + len = strlen(p) + 1; + p += strspn(p, " \t"); + + if (*p == '#' || *p == '\0') + return len; entry = kzalloc(sizeof(*entry), GFP_KERNEL); if (!entry) { @@ -703,14 +697,6 @@ ssize_t ima_parse_add_rule(char *rule) INIT_LIST_HEAD(&entry->list); - p = strsep(&rule, "\n"); - len = strlen(p) + 1; - - if (*p == '#') { - kfree(entry); - return len; - } - result = ima_parse_rule(p, entry); if (result) { kfree(entry); diff --git a/security/integrity/ima/ima_template.c b/security/integrity/ima/ima_template.c index e854862c9337..0b7404ebfa80 100644 --- a/security/integrity/ima/ima_template.c +++ b/security/integrity/ima/ima_template.c @@ -24,6 +24,7 @@ static struct ima_template_desc defined_templates[] = { {.name = IMA_TEMPLATE_IMA_NAME, .fmt = IMA_TEMPLATE_IMA_FMT}, {.name = "ima-ng", .fmt = "d-ng|n-ng"}, {.name = "ima-sig", .fmt = "d-ng|n-ng|sig"}, + {.name = "", .fmt = ""}, /* placeholder for a custom format */ }; static struct ima_template_field supported_fields[] = { @@ -41,19 +42,28 @@ static struct ima_template_field supported_fields[] = { static struct ima_template_desc *ima_template; static struct ima_template_desc *lookup_template_desc(const char *name); +static int template_desc_init_fields(const char *template_fmt, + struct ima_template_field ***fields, + int *num_fields); static int __init ima_template_setup(char *str) { struct ima_template_desc *template_desc; int template_len = strlen(str); + if (ima_template) + return 1; + /* * Verify that a template with the supplied name exists. * If not, use CONFIG_IMA_DEFAULT_TEMPLATE. */ template_desc = lookup_template_desc(str); - if (!template_desc) + if (!template_desc) { + pr_err("template %s not found, using %s\n", + str, CONFIG_IMA_DEFAULT_TEMPLATE); return 1; + } /* * Verify whether the current hash algorithm is supported @@ -70,6 +80,25 @@ static int __init ima_template_setup(char *str) } __setup("ima_template=", ima_template_setup); +static int __init ima_template_fmt_setup(char *str) +{ + int num_templates = ARRAY_SIZE(defined_templates); + + if (ima_template) + return 1; + + if (template_desc_init_fields(str, NULL, NULL) < 0) { + pr_err("format string '%s' not valid, using template %s\n", + str, CONFIG_IMA_DEFAULT_TEMPLATE); + return 1; + } + + defined_templates[num_templates - 1].fmt = str; + ima_template = defined_templates + num_templates - 1; + return 1; +} +__setup("ima_template_fmt=", ima_template_fmt_setup); + static struct ima_template_desc *lookup_template_desc(const char *name) { int i; @@ -113,43 +142,46 @@ static int template_desc_init_fields(const char *template_fmt, struct ima_template_field ***fields, int *num_fields) { - char *c, *template_fmt_copy, *template_fmt_ptr; + const char *template_fmt_ptr; + struct ima_template_field *found_fields[IMA_TEMPLATE_NUM_FIELDS_MAX]; int template_num_fields = template_fmt_size(template_fmt); - int i, result = 0; + int i, len; - if (template_num_fields > IMA_TEMPLATE_NUM_FIELDS_MAX) + if (template_num_fields > IMA_TEMPLATE_NUM_FIELDS_MAX) { + pr_err("format string '%s' contains too many fields\n", + template_fmt); return -EINVAL; - - /* copying is needed as strsep() modifies the original buffer */ - template_fmt_copy = kstrdup(template_fmt, GFP_KERNEL); - if (template_fmt_copy == NULL) - return -ENOMEM; - - *fields = kzalloc(template_num_fields * sizeof(*fields), GFP_KERNEL); - if (*fields == NULL) { - result = -ENOMEM; - goto out; } - template_fmt_ptr = template_fmt_copy; - for (i = 0; (c = strsep(&template_fmt_ptr, "|")) != NULL && - i < template_num_fields; i++) { - struct ima_template_field *f = lookup_template_field(c); + for (i = 0, template_fmt_ptr = template_fmt; i < template_num_fields; + i++, template_fmt_ptr += len + 1) { + char tmp_field_id[IMA_TEMPLATE_FIELD_ID_MAX_LEN + 1]; + + len = strchrnul(template_fmt_ptr, '|') - template_fmt_ptr; + if (len == 0 || len > IMA_TEMPLATE_FIELD_ID_MAX_LEN) { + pr_err("Invalid field with length %d\n", len); + return -EINVAL; + } - if (!f) { - result = -ENOENT; - goto out; + memcpy(tmp_field_id, template_fmt_ptr, len); + tmp_field_id[len] = '\0'; + found_fields[i] = lookup_template_field(tmp_field_id); + if (!found_fields[i]) { + pr_err("field '%s' not found\n", tmp_field_id); + return -ENOENT; } - (*fields)[i] = f; } - *num_fields = i; -out: - if (result < 0) { - kfree(*fields); - *fields = NULL; + + if (fields && num_fields) { + *fields = kmalloc_array(i, sizeof(*fields), GFP_KERNEL); + if (*fields == NULL) + return -ENOMEM; + + memcpy(*fields, found_fields, i * sizeof(*fields)); + *num_fields = i; } - kfree(template_fmt_copy); - return result; + + return 0; } struct ima_template_desc *ima_template_desc_current(void) @@ -163,8 +195,15 @@ struct ima_template_desc *ima_template_desc_current(void) int __init ima_init_template(void) { struct ima_template_desc *template = ima_template_desc_current(); + int result; + + result = template_desc_init_fields(template->fmt, + &(template->fields), + &(template->num_fields)); + if (result < 0) + pr_err("template %s init failed, result: %d\n", + (strlen(template->name) ? + template->name : template->fmt), result); - return template_desc_init_fields(template->fmt, - &(template->fields), - &(template->num_fields)); + return result; } diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h index 9d1c2ebfe12a..0fc9519fefa9 100644 --- a/security/integrity/integrity.h +++ b/security/integrity/integrity.h @@ -120,6 +120,10 @@ struct integrity_iint_cache { */ struct integrity_iint_cache *integrity_iint_find(struct inode *inode); +int integrity_kernel_read(struct file *file, loff_t offset, + char *addr, unsigned long count); +int __init integrity_read_file(const char *path, char **data); + #define INTEGRITY_KEYRING_EVM 0 #define INTEGRITY_KEYRING_MODULE 1 #define INTEGRITY_KEYRING_IMA 2 @@ -130,7 +134,8 @@ struct integrity_iint_cache *integrity_iint_find(struct inode *inode); int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen, const char *digest, int digestlen); -int integrity_init_keyring(const unsigned int id); +int __init integrity_init_keyring(const unsigned int id); +int __init integrity_load_x509(const unsigned int id, char *path); #else static inline int integrity_digsig_verify(const unsigned int id, @@ -144,6 +149,7 @@ static inline int integrity_init_keyring(const unsigned int id) { return 0; } + #endif /* CONFIG_INTEGRITY_SIGNATURE */ #ifdef CONFIG_INTEGRITY_ASYMMETRIC_KEYS @@ -157,6 +163,14 @@ static inline int asymmetric_verify(struct key *keyring, const char *sig, } #endif +#ifdef CONFIG_IMA_LOAD_X509 +void __init ima_load_x509(void); +#else +static inline void ima_load_x509(void) +{ +} +#endif + #ifdef CONFIG_INTEGRITY_AUDIT /* declarations */ void integrity_audit_msg(int audit_msgno, struct inode *inode, @@ -170,6 +184,3 @@ static inline void integrity_audit_msg(int audit_msgno, struct inode *inode, { } #endif - -/* set during initialization */ -extern int iint_initialized; |