cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

iint.c (5503B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (C) 2008 IBM Corporation
      4 *
      5 * Authors:
      6 * Mimi Zohar <zohar@us.ibm.com>
      7 *
      8 * File: integrity_iint.c
      9 *	- implements the integrity hooks: integrity_inode_alloc,
     10 *	  integrity_inode_free
     11 *	- cache integrity information associated with an inode
     12 *	  using a rbtree tree.
     13 */
     14#include <linux/slab.h>
     15#include <linux/init.h>
     16#include <linux/spinlock.h>
     17#include <linux/rbtree.h>
     18#include <linux/file.h>
     19#include <linux/uaccess.h>
     20#include <linux/security.h>
     21#include <linux/lsm_hooks.h>
     22#include "integrity.h"
     23
     24static struct rb_root integrity_iint_tree = RB_ROOT;
     25static DEFINE_RWLOCK(integrity_iint_lock);
     26static struct kmem_cache *iint_cache __read_mostly;
     27
     28struct dentry *integrity_dir;
     29
     30/*
     31 * __integrity_iint_find - return the iint associated with an inode
     32 */
     33static struct integrity_iint_cache *__integrity_iint_find(struct inode *inode)
     34{
     35	struct integrity_iint_cache *iint;
     36	struct rb_node *n = integrity_iint_tree.rb_node;
     37
     38	while (n) {
     39		iint = rb_entry(n, struct integrity_iint_cache, rb_node);
     40
     41		if (inode < iint->inode)
     42			n = n->rb_left;
     43		else if (inode > iint->inode)
     44			n = n->rb_right;
     45		else
     46			break;
     47	}
     48	if (!n)
     49		return NULL;
     50
     51	return iint;
     52}
     53
     54/*
     55 * integrity_iint_find - return the iint associated with an inode
     56 */
     57struct integrity_iint_cache *integrity_iint_find(struct inode *inode)
     58{
     59	struct integrity_iint_cache *iint;
     60
     61	if (!IS_IMA(inode))
     62		return NULL;
     63
     64	read_lock(&integrity_iint_lock);
     65	iint = __integrity_iint_find(inode);
     66	read_unlock(&integrity_iint_lock);
     67
     68	return iint;
     69}
     70
     71static void iint_free(struct integrity_iint_cache *iint)
     72{
     73	kfree(iint->ima_hash);
     74	iint->ima_hash = NULL;
     75	iint->version = 0;
     76	iint->flags = 0UL;
     77	iint->atomic_flags = 0UL;
     78	iint->ima_file_status = INTEGRITY_UNKNOWN;
     79	iint->ima_mmap_status = INTEGRITY_UNKNOWN;
     80	iint->ima_bprm_status = INTEGRITY_UNKNOWN;
     81	iint->ima_read_status = INTEGRITY_UNKNOWN;
     82	iint->ima_creds_status = INTEGRITY_UNKNOWN;
     83	iint->evm_status = INTEGRITY_UNKNOWN;
     84	iint->measured_pcrs = 0;
     85	kmem_cache_free(iint_cache, iint);
     86}
     87
     88/**
     89 * integrity_inode_get - find or allocate an iint associated with an inode
     90 * @inode: pointer to the inode
     91 * @return: allocated iint
     92 *
     93 * Caller must lock i_mutex
     94 */
     95struct integrity_iint_cache *integrity_inode_get(struct inode *inode)
     96{
     97	struct rb_node **p;
     98	struct rb_node *node, *parent = NULL;
     99	struct integrity_iint_cache *iint, *test_iint;
    100
    101	/*
    102	 * The integrity's "iint_cache" is initialized at security_init(),
    103	 * unless it is not included in the ordered list of LSMs enabled
    104	 * on the boot command line.
    105	 */
    106	if (!iint_cache)
    107		panic("%s: lsm=integrity required.\n", __func__);
    108
    109	iint = integrity_iint_find(inode);
    110	if (iint)
    111		return iint;
    112
    113	iint = kmem_cache_alloc(iint_cache, GFP_NOFS);
    114	if (!iint)
    115		return NULL;
    116
    117	write_lock(&integrity_iint_lock);
    118
    119	p = &integrity_iint_tree.rb_node;
    120	while (*p) {
    121		parent = *p;
    122		test_iint = rb_entry(parent, struct integrity_iint_cache,
    123				     rb_node);
    124		if (inode < test_iint->inode)
    125			p = &(*p)->rb_left;
    126		else
    127			p = &(*p)->rb_right;
    128	}
    129
    130	iint->inode = inode;
    131	node = &iint->rb_node;
    132	inode->i_flags |= S_IMA;
    133	rb_link_node(node, parent, p);
    134	rb_insert_color(node, &integrity_iint_tree);
    135
    136	write_unlock(&integrity_iint_lock);
    137	return iint;
    138}
    139
    140/**
    141 * integrity_inode_free - called on security_inode_free
    142 * @inode: pointer to the inode
    143 *
    144 * Free the integrity information(iint) associated with an inode.
    145 */
    146void integrity_inode_free(struct inode *inode)
    147{
    148	struct integrity_iint_cache *iint;
    149
    150	if (!IS_IMA(inode))
    151		return;
    152
    153	write_lock(&integrity_iint_lock);
    154	iint = __integrity_iint_find(inode);
    155	rb_erase(&iint->rb_node, &integrity_iint_tree);
    156	write_unlock(&integrity_iint_lock);
    157
    158	iint_free(iint);
    159}
    160
    161static void init_once(void *foo)
    162{
    163	struct integrity_iint_cache *iint = (struct integrity_iint_cache *) foo;
    164
    165	memset(iint, 0, sizeof(*iint));
    166	iint->ima_file_status = INTEGRITY_UNKNOWN;
    167	iint->ima_mmap_status = INTEGRITY_UNKNOWN;
    168	iint->ima_bprm_status = INTEGRITY_UNKNOWN;
    169	iint->ima_read_status = INTEGRITY_UNKNOWN;
    170	iint->ima_creds_status = INTEGRITY_UNKNOWN;
    171	iint->evm_status = INTEGRITY_UNKNOWN;
    172	mutex_init(&iint->mutex);
    173}
    174
    175static int __init integrity_iintcache_init(void)
    176{
    177	iint_cache =
    178	    kmem_cache_create("iint_cache", sizeof(struct integrity_iint_cache),
    179			      0, SLAB_PANIC, init_once);
    180	return 0;
    181}
    182DEFINE_LSM(integrity) = {
    183	.name = "integrity",
    184	.init = integrity_iintcache_init,
    185};
    186
    187
    188/*
    189 * integrity_kernel_read - read data from the file
    190 *
    191 * This is a function for reading file content instead of kernel_read().
    192 * It does not perform locking checks to ensure it cannot be blocked.
    193 * It does not perform security checks because it is irrelevant for IMA.
    194 *
    195 */
    196int integrity_kernel_read(struct file *file, loff_t offset,
    197			  void *addr, unsigned long count)
    198{
    199	return __kernel_read(file, addr, count, &offset);
    200}
    201
    202/*
    203 * integrity_load_keys - load integrity keys hook
    204 *
    205 * Hooks is called from init/main.c:kernel_init_freeable()
    206 * when rootfs is ready
    207 */
    208void __init integrity_load_keys(void)
    209{
    210	ima_load_x509();
    211
    212	if (!IS_ENABLED(CONFIG_IMA_LOAD_X509))
    213		evm_load_x509();
    214}
    215
    216static int __init integrity_fs_init(void)
    217{
    218	integrity_dir = securityfs_create_dir("integrity", NULL);
    219	if (IS_ERR(integrity_dir)) {
    220		int ret = PTR_ERR(integrity_dir);
    221
    222		if (ret != -ENODEV)
    223			pr_err("Unable to create integrity sysfs dir: %d\n",
    224			       ret);
    225		integrity_dir = NULL;
    226		return ret;
    227	}
    228
    229	return 0;
    230}
    231
    232late_initcall(integrity_fs_init)