Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (C) 2008 IBM Corporation
0004  *
0005  * Authors:
0006  * Mimi Zohar <zohar@us.ibm.com>
0007  *
0008  * File: integrity_iint.c
0009  *  - implements the integrity hooks: integrity_inode_alloc,
0010  *    integrity_inode_free
0011  *  - cache integrity information associated with an inode
0012  *    using a rbtree tree.
0013  */
0014 #include <linux/slab.h>
0015 #include <linux/init.h>
0016 #include <linux/spinlock.h>
0017 #include <linux/rbtree.h>
0018 #include <linux/file.h>
0019 #include <linux/uaccess.h>
0020 #include <linux/security.h>
0021 #include <linux/lsm_hooks.h>
0022 #include "integrity.h"
0023 
0024 static struct rb_root integrity_iint_tree = RB_ROOT;
0025 static DEFINE_RWLOCK(integrity_iint_lock);
0026 static struct kmem_cache *iint_cache __read_mostly;
0027 
0028 struct dentry *integrity_dir;
0029 
0030 /*
0031  * __integrity_iint_find - return the iint associated with an inode
0032  */
0033 static struct integrity_iint_cache *__integrity_iint_find(struct inode *inode)
0034 {
0035     struct integrity_iint_cache *iint;
0036     struct rb_node *n = integrity_iint_tree.rb_node;
0037 
0038     while (n) {
0039         iint = rb_entry(n, struct integrity_iint_cache, rb_node);
0040 
0041         if (inode < iint->inode)
0042             n = n->rb_left;
0043         else if (inode > iint->inode)
0044             n = n->rb_right;
0045         else
0046             break;
0047     }
0048     if (!n)
0049         return NULL;
0050 
0051     return iint;
0052 }
0053 
0054 /*
0055  * integrity_iint_find - return the iint associated with an inode
0056  */
0057 struct integrity_iint_cache *integrity_iint_find(struct inode *inode)
0058 {
0059     struct integrity_iint_cache *iint;
0060 
0061     if (!IS_IMA(inode))
0062         return NULL;
0063 
0064     read_lock(&integrity_iint_lock);
0065     iint = __integrity_iint_find(inode);
0066     read_unlock(&integrity_iint_lock);
0067 
0068     return iint;
0069 }
0070 
0071 static void iint_free(struct integrity_iint_cache *iint)
0072 {
0073     kfree(iint->ima_hash);
0074     iint->ima_hash = NULL;
0075     iint->version = 0;
0076     iint->flags = 0UL;
0077     iint->atomic_flags = 0UL;
0078     iint->ima_file_status = INTEGRITY_UNKNOWN;
0079     iint->ima_mmap_status = INTEGRITY_UNKNOWN;
0080     iint->ima_bprm_status = INTEGRITY_UNKNOWN;
0081     iint->ima_read_status = INTEGRITY_UNKNOWN;
0082     iint->ima_creds_status = INTEGRITY_UNKNOWN;
0083     iint->evm_status = INTEGRITY_UNKNOWN;
0084     iint->measured_pcrs = 0;
0085     kmem_cache_free(iint_cache, iint);
0086 }
0087 
0088 /**
0089  * integrity_inode_get - find or allocate an iint associated with an inode
0090  * @inode: pointer to the inode
0091  * @return: allocated iint
0092  *
0093  * Caller must lock i_mutex
0094  */
0095 struct integrity_iint_cache *integrity_inode_get(struct inode *inode)
0096 {
0097     struct rb_node **p;
0098     struct rb_node *node, *parent = NULL;
0099     struct integrity_iint_cache *iint, *test_iint;
0100 
0101     /*
0102      * The integrity's "iint_cache" is initialized at security_init(),
0103      * unless it is not included in the ordered list of LSMs enabled
0104      * on the boot command line.
0105      */
0106     if (!iint_cache)
0107         panic("%s: lsm=integrity required.\n", __func__);
0108 
0109     iint = integrity_iint_find(inode);
0110     if (iint)
0111         return iint;
0112 
0113     iint = kmem_cache_alloc(iint_cache, GFP_NOFS);
0114     if (!iint)
0115         return NULL;
0116 
0117     write_lock(&integrity_iint_lock);
0118 
0119     p = &integrity_iint_tree.rb_node;
0120     while (*p) {
0121         parent = *p;
0122         test_iint = rb_entry(parent, struct integrity_iint_cache,
0123                      rb_node);
0124         if (inode < test_iint->inode)
0125             p = &(*p)->rb_left;
0126         else
0127             p = &(*p)->rb_right;
0128     }
0129 
0130     iint->inode = inode;
0131     node = &iint->rb_node;
0132     inode->i_flags |= S_IMA;
0133     rb_link_node(node, parent, p);
0134     rb_insert_color(node, &integrity_iint_tree);
0135 
0136     write_unlock(&integrity_iint_lock);
0137     return iint;
0138 }
0139 
0140 /**
0141  * integrity_inode_free - called on security_inode_free
0142  * @inode: pointer to the inode
0143  *
0144  * Free the integrity information(iint) associated with an inode.
0145  */
0146 void integrity_inode_free(struct inode *inode)
0147 {
0148     struct integrity_iint_cache *iint;
0149 
0150     if (!IS_IMA(inode))
0151         return;
0152 
0153     write_lock(&integrity_iint_lock);
0154     iint = __integrity_iint_find(inode);
0155     rb_erase(&iint->rb_node, &integrity_iint_tree);
0156     write_unlock(&integrity_iint_lock);
0157 
0158     iint_free(iint);
0159 }
0160 
0161 static void init_once(void *foo)
0162 {
0163     struct integrity_iint_cache *iint = (struct integrity_iint_cache *) foo;
0164 
0165     memset(iint, 0, sizeof(*iint));
0166     iint->ima_file_status = INTEGRITY_UNKNOWN;
0167     iint->ima_mmap_status = INTEGRITY_UNKNOWN;
0168     iint->ima_bprm_status = INTEGRITY_UNKNOWN;
0169     iint->ima_read_status = INTEGRITY_UNKNOWN;
0170     iint->ima_creds_status = INTEGRITY_UNKNOWN;
0171     iint->evm_status = INTEGRITY_UNKNOWN;
0172     mutex_init(&iint->mutex);
0173 }
0174 
0175 static int __init integrity_iintcache_init(void)
0176 {
0177     iint_cache =
0178         kmem_cache_create("iint_cache", sizeof(struct integrity_iint_cache),
0179                   0, SLAB_PANIC, init_once);
0180     return 0;
0181 }
0182 DEFINE_LSM(integrity) = {
0183     .name = "integrity",
0184     .init = integrity_iintcache_init,
0185 };
0186 
0187 
0188 /*
0189  * integrity_kernel_read - read data from the file
0190  *
0191  * This is a function for reading file content instead of kernel_read().
0192  * It does not perform locking checks to ensure it cannot be blocked.
0193  * It does not perform security checks because it is irrelevant for IMA.
0194  *
0195  */
0196 int integrity_kernel_read(struct file *file, loff_t offset,
0197               void *addr, unsigned long count)
0198 {
0199     return __kernel_read(file, addr, count, &offset);
0200 }
0201 
0202 /*
0203  * integrity_load_keys - load integrity keys hook
0204  *
0205  * Hooks is called from init/main.c:kernel_init_freeable()
0206  * when rootfs is ready
0207  */
0208 void __init integrity_load_keys(void)
0209 {
0210     ima_load_x509();
0211 
0212     if (!IS_ENABLED(CONFIG_IMA_LOAD_X509))
0213         evm_load_x509();
0214 }
0215 
0216 static int __init integrity_fs_init(void)
0217 {
0218     integrity_dir = securityfs_create_dir("integrity", NULL);
0219     if (IS_ERR(integrity_dir)) {
0220         int ret = PTR_ERR(integrity_dir);
0221 
0222         if (ret != -ENODEV)
0223             pr_err("Unable to create integrity sysfs dir: %d\n",
0224                    ret);
0225         integrity_dir = NULL;
0226         return ret;
0227     }
0228 
0229     return 0;
0230 }
0231 
0232 late_initcall(integrity_fs_init)