Path: blob/master/security/integrity/ima/ima_iint.c
10818 views
/*1* Copyright (C) 2008 IBM Corporation2*3* Authors:4* Mimi Zohar <[email protected]>5*6* This program is free software; you can redistribute it and/or7* modify it under the terms of the GNU General Public License as8* published by the Free Software Foundation, version 2 of the9* License.10*11* File: ima_iint.c12* - implements the IMA hooks: ima_inode_alloc, ima_inode_free13* - cache integrity information associated with an inode14* using a rbtree tree.15*/16#include <linux/slab.h>17#include <linux/module.h>18#include <linux/spinlock.h>19#include <linux/rbtree.h>20#include "ima.h"2122static struct rb_root ima_iint_tree = RB_ROOT;23static DEFINE_SPINLOCK(ima_iint_lock);24static struct kmem_cache *iint_cache __read_mostly;2526int iint_initialized = 0;2728/*29* __ima_iint_find - return the iint associated with an inode30*/31static struct ima_iint_cache *__ima_iint_find(struct inode *inode)32{33struct ima_iint_cache *iint;34struct rb_node *n = ima_iint_tree.rb_node;3536assert_spin_locked(&ima_iint_lock);3738while (n) {39iint = rb_entry(n, struct ima_iint_cache, rb_node);4041if (inode < iint->inode)42n = n->rb_left;43else if (inode > iint->inode)44n = n->rb_right;45else46break;47}48if (!n)49return NULL;5051return iint;52}5354/*55* ima_iint_find - return the iint associated with an inode56*/57struct ima_iint_cache *ima_iint_find(struct inode *inode)58{59struct ima_iint_cache *iint;6061if (!IS_IMA(inode))62return NULL;6364spin_lock(&ima_iint_lock);65iint = __ima_iint_find(inode);66spin_unlock(&ima_iint_lock);6768return iint;69}7071static void iint_free(struct ima_iint_cache *iint)72{73iint->version = 0;74iint->flags = 0UL;75kmem_cache_free(iint_cache, iint);76}7778/**79* ima_inode_alloc - allocate an iint associated with an inode80* @inode: pointer to the inode81*/82int ima_inode_alloc(struct inode *inode)83{84struct rb_node **p;85struct rb_node *new_node, *parent = NULL;86struct ima_iint_cache *new_iint, *test_iint;87int rc;8889new_iint = kmem_cache_alloc(iint_cache, GFP_NOFS);90if (!new_iint)91return -ENOMEM;9293new_iint->inode = inode;94new_node = &new_iint->rb_node;9596mutex_lock(&inode->i_mutex); /* i_flags */97spin_lock(&ima_iint_lock);9899p = &ima_iint_tree.rb_node;100while (*p) {101parent = *p;102test_iint = rb_entry(parent, struct ima_iint_cache, rb_node);103104rc = -EEXIST;105if (inode < test_iint->inode)106p = &(*p)->rb_left;107else if (inode > test_iint->inode)108p = &(*p)->rb_right;109else110goto out_err;111}112113inode->i_flags |= S_IMA;114rb_link_node(new_node, parent, p);115rb_insert_color(new_node, &ima_iint_tree);116117spin_unlock(&ima_iint_lock);118mutex_unlock(&inode->i_mutex); /* i_flags */119120return 0;121out_err:122spin_unlock(&ima_iint_lock);123mutex_unlock(&inode->i_mutex); /* i_flags */124iint_free(new_iint);125126return rc;127}128129/**130* ima_inode_free - called on security_inode_free131* @inode: pointer to the inode132*133* Free the integrity information(iint) associated with an inode.134*/135void ima_inode_free(struct inode *inode)136{137struct ima_iint_cache *iint;138139if (!IS_IMA(inode))140return;141142spin_lock(&ima_iint_lock);143iint = __ima_iint_find(inode);144rb_erase(&iint->rb_node, &ima_iint_tree);145spin_unlock(&ima_iint_lock);146147iint_free(iint);148}149150static void init_once(void *foo)151{152struct ima_iint_cache *iint = foo;153154memset(iint, 0, sizeof *iint);155iint->version = 0;156iint->flags = 0UL;157mutex_init(&iint->mutex);158}159160static int __init ima_iintcache_init(void)161{162iint_cache =163kmem_cache_create("iint_cache", sizeof(struct ima_iint_cache), 0,164SLAB_PANIC, init_once);165iint_initialized = 1;166return 0;167}168security_initcall(ima_iintcache_init);169170171