diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-26 14:37:48 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-26 14:37:48 -0400 |
| commit | f9ba5375a8aae4aeea6be15df77e24707a429812 (patch) | |
| tree | c6388d7e40f0f6a70d7ba6a4d4aeaa0d1f5591f6 /security | |
| parent | 45352bbf48e95078b4acd20774f49e72676e1e0f (diff) | |
| parent | bade72d607c4eb1b1d6c7852c493b75f065a56b5 (diff) | |
Merge branch 'ima-memory-use-fixes'
* ima-memory-use-fixes:
IMA: fix the ToMToU logic
IMA: explicit IMA i_flag to remove global lock on inode_delete
IMA: drop refcnt from ima_iint_cache since it isn't needed
IMA: only allocate iint when needed
IMA: move read counter into struct inode
IMA: use i_writecount rather than a private counter
IMA: use inode->i_lock to protect read and write counters
IMA: convert internal flags from long to char
IMA: use unsigned int instead of long for counters
IMA: drop the inode opencount since it isn't needed for operation
IMA: use rbtree instead of radix tree for inode information cache
Diffstat (limited to 'security')
| -rw-r--r-- | security/integrity/ima/ima.h | 18 | ||||
| -rw-r--r-- | security/integrity/ima/ima_api.c | 2 | ||||
| -rw-r--r-- | security/integrity/ima/ima_iint.c | 158 | ||||
| -rw-r--r-- | security/integrity/ima/ima_main.c | 184 | ||||
| -rw-r--r-- | security/security.c | 10 |
5 files changed, 195 insertions, 177 deletions
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index 3fbcd1dda0ef..ac79032bdf23 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h | |||
| @@ -70,6 +70,7 @@ int ima_init(void); | |||
| 70 | void ima_cleanup(void); | 70 | void ima_cleanup(void); |
| 71 | int ima_fs_init(void); | 71 | int ima_fs_init(void); |
| 72 | void ima_fs_cleanup(void); | 72 | void ima_fs_cleanup(void); |
| 73 | int ima_inode_alloc(struct inode *inode); | ||
| 73 | int ima_add_template_entry(struct ima_template_entry *entry, int violation, | 74 | int ima_add_template_entry(struct ima_template_entry *entry, int violation, |
| 74 | const char *op, struct inode *inode); | 75 | const char *op, struct inode *inode); |
| 75 | int ima_calc_hash(struct file *file, char *digest); | 76 | int ima_calc_hash(struct file *file, char *digest); |
| @@ -96,19 +97,16 @@ static inline unsigned long ima_hash_key(u8 *digest) | |||
| 96 | } | 97 | } |
| 97 | 98 | ||
| 98 | /* iint cache flags */ | 99 | /* iint cache flags */ |
| 99 | #define IMA_MEASURED 1 | 100 | #define IMA_MEASURED 0x01 |
| 100 | 101 | ||
| 101 | /* integrity data associated with an inode */ | 102 | /* integrity data associated with an inode */ |
| 102 | struct ima_iint_cache { | 103 | struct ima_iint_cache { |
| 104 | struct rb_node rb_node; /* rooted in ima_iint_tree */ | ||
| 105 | struct inode *inode; /* back pointer to inode in question */ | ||
| 103 | u64 version; /* track inode changes */ | 106 | u64 version; /* track inode changes */ |
| 104 | unsigned long flags; | 107 | unsigned char flags; |
| 105 | u8 digest[IMA_DIGEST_SIZE]; | 108 | u8 digest[IMA_DIGEST_SIZE]; |
| 106 | struct mutex mutex; /* protects: version, flags, digest */ | 109 | struct mutex mutex; /* protects: version, flags, digest */ |
| 107 | long readcount; /* measured files readcount */ | ||
| 108 | long writecount; /* measured files writecount */ | ||
| 109 | long opencount; /* opens reference count */ | ||
| 110 | struct kref refcount; /* ima_iint_cache reference count */ | ||
| 111 | struct rcu_head rcu; | ||
| 112 | }; | 110 | }; |
| 113 | 111 | ||
| 114 | /* LIM API function definitions */ | 112 | /* LIM API function definitions */ |
| @@ -122,13 +120,11 @@ int ima_store_template(struct ima_template_entry *entry, int violation, | |||
| 122 | void ima_template_show(struct seq_file *m, void *e, | 120 | void ima_template_show(struct seq_file *m, void *e, |
| 123 | enum ima_show_type show); | 121 | enum ima_show_type show); |
| 124 | 122 | ||
| 125 | /* radix tree calls to lookup, insert, delete | 123 | /* rbtree tree calls to lookup, insert, delete |
| 126 | * integrity data associated with an inode. | 124 | * integrity data associated with an inode. |
| 127 | */ | 125 | */ |
| 128 | struct ima_iint_cache *ima_iint_insert(struct inode *inode); | 126 | struct ima_iint_cache *ima_iint_insert(struct inode *inode); |
| 129 | struct ima_iint_cache *ima_iint_find_get(struct inode *inode); | 127 | struct ima_iint_cache *ima_iint_find(struct inode *inode); |
| 130 | void iint_free(struct kref *kref); | ||
| 131 | void iint_rcu_free(struct rcu_head *rcu); | ||
| 132 | 128 | ||
| 133 | /* IMA policy related functions */ | 129 | /* IMA policy related functions */ |
| 134 | enum ima_hooks { FILE_CHECK = 1, FILE_MMAP, BPRM_CHECK }; | 130 | enum ima_hooks { FILE_CHECK = 1, FILE_MMAP, BPRM_CHECK }; |
diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c index 52015d098fdf..d3963de6003d 100644 --- a/security/integrity/ima/ima_api.c +++ b/security/integrity/ima/ima_api.c | |||
| @@ -116,7 +116,7 @@ int ima_must_measure(struct ima_iint_cache *iint, struct inode *inode, | |||
| 116 | { | 116 | { |
| 117 | int must_measure; | 117 | int must_measure; |
| 118 | 118 | ||
| 119 | if (iint->flags & IMA_MEASURED) | 119 | if (iint && iint->flags & IMA_MEASURED) |
| 120 | return 1; | 120 | return 1; |
| 121 | 121 | ||
| 122 | must_measure = ima_match_policy(inode, function, mask); | 122 | must_measure = ima_match_policy(inode, function, mask); |
diff --git a/security/integrity/ima/ima_iint.c b/security/integrity/ima/ima_iint.c index afba4aef812f..c442e47b6785 100644 --- a/security/integrity/ima/ima_iint.c +++ b/security/integrity/ima/ima_iint.c | |||
| @@ -12,98 +12,119 @@ | |||
| 12 | * File: ima_iint.c | 12 | * File: ima_iint.c |
| 13 | * - implements the IMA hooks: ima_inode_alloc, ima_inode_free | 13 | * - implements the IMA hooks: ima_inode_alloc, ima_inode_free |
| 14 | * - cache integrity information associated with an inode | 14 | * - cache integrity information associated with an inode |
| 15 | * using a radix tree. | 15 | * using a rbtree tree. |
| 16 | */ | 16 | */ |
| 17 | #include <linux/slab.h> | 17 | #include <linux/slab.h> |
| 18 | #include <linux/module.h> | 18 | #include <linux/module.h> |
| 19 | #include <linux/spinlock.h> | 19 | #include <linux/spinlock.h> |
| 20 | #include <linux/radix-tree.h> | 20 | #include <linux/rbtree.h> |
| 21 | #include "ima.h" | 21 | #include "ima.h" |
| 22 | 22 | ||
| 23 | RADIX_TREE(ima_iint_store, GFP_ATOMIC); | 23 | static struct rb_root ima_iint_tree = RB_ROOT; |
| 24 | DEFINE_SPINLOCK(ima_iint_lock); | 24 | static DEFINE_SPINLOCK(ima_iint_lock); |
| 25 | static struct kmem_cache *iint_cache __read_mostly; | 25 | static struct kmem_cache *iint_cache __read_mostly; |
| 26 | 26 | ||
| 27 | int iint_initialized = 0; | 27 | int iint_initialized = 0; |
| 28 | 28 | ||
| 29 | /* ima_iint_find_get - return the iint associated with an inode | 29 | /* |
| 30 | * | 30 | * __ima_iint_find - return the iint associated with an inode |
| 31 | * ima_iint_find_get gets a reference to the iint. Caller must | ||
| 32 | * remember to put the iint reference. | ||
| 33 | */ | 31 | */ |
| 34 | struct ima_iint_cache *ima_iint_find_get(struct inode *inode) | 32 | static struct ima_iint_cache *__ima_iint_find(struct inode *inode) |
| 35 | { | 33 | { |
| 36 | struct ima_iint_cache *iint; | 34 | struct ima_iint_cache *iint; |
| 35 | struct rb_node *n = ima_iint_tree.rb_node; | ||
| 36 | |||
| 37 | assert_spin_locked(&ima_iint_lock); | ||
| 38 | |||
| 39 | while (n) { | ||
| 40 | iint = rb_entry(n, struct ima_iint_cache, rb_node); | ||
| 41 | |||
| 42 | if (inode < iint->inode) | ||
| 43 | n = n->rb_left; | ||
| 44 | else if (inode > iint->inode) | ||
| 45 | n = n->rb_right; | ||
| 46 | else | ||
| 47 | break; | ||
| 48 | } | ||
| 49 | if (!n) | ||
| 50 | return NULL; | ||
| 37 | 51 | ||
| 38 | rcu_read_lock(); | ||
| 39 | iint = radix_tree_lookup(&ima_iint_store, (unsigned long)inode); | ||
| 40 | if (!iint) | ||
| 41 | goto out; | ||
| 42 | kref_get(&iint->refcount); | ||
| 43 | out: | ||
| 44 | rcu_read_unlock(); | ||
| 45 | return iint; | 52 | return iint; |
| 46 | } | 53 | } |
| 47 | 54 | ||
| 48 | /** | 55 | /* |
| 49 | * ima_inode_alloc - allocate an iint associated with an inode | 56 | * ima_iint_find - return the iint associated with an inode |
| 50 | * @inode: pointer to the inode | ||
| 51 | */ | 57 | */ |
| 52 | int ima_inode_alloc(struct inode *inode) | 58 | struct ima_iint_cache *ima_iint_find(struct inode *inode) |
| 53 | { | 59 | { |
| 54 | struct ima_iint_cache *iint = NULL; | 60 | struct ima_iint_cache *iint; |
| 55 | int rc = 0; | ||
| 56 | |||
| 57 | iint = kmem_cache_alloc(iint_cache, GFP_NOFS); | ||
| 58 | if (!iint) | ||
| 59 | return -ENOMEM; | ||
| 60 | 61 | ||
| 61 | rc = radix_tree_preload(GFP_NOFS); | 62 | if (!IS_IMA(inode)) |
| 62 | if (rc < 0) | 63 | return NULL; |
| 63 | goto out; | ||
| 64 | 64 | ||
| 65 | spin_lock(&ima_iint_lock); | 65 | spin_lock(&ima_iint_lock); |
| 66 | rc = radix_tree_insert(&ima_iint_store, (unsigned long)inode, iint); | 66 | iint = __ima_iint_find(inode); |
| 67 | spin_unlock(&ima_iint_lock); | 67 | spin_unlock(&ima_iint_lock); |
| 68 | radix_tree_preload_end(); | ||
| 69 | out: | ||
| 70 | if (rc < 0) | ||
| 71 | kmem_cache_free(iint_cache, iint); | ||
| 72 | 68 | ||
| 73 | return rc; | 69 | return iint; |
| 74 | } | 70 | } |
| 75 | 71 | ||
| 76 | /* iint_free - called when the iint refcount goes to zero */ | 72 | static void iint_free(struct ima_iint_cache *iint) |
| 77 | void iint_free(struct kref *kref) | ||
| 78 | { | 73 | { |
| 79 | struct ima_iint_cache *iint = container_of(kref, struct ima_iint_cache, | ||
| 80 | refcount); | ||
| 81 | iint->version = 0; | 74 | iint->version = 0; |
| 82 | iint->flags = 0UL; | 75 | iint->flags = 0UL; |
| 83 | if (iint->readcount != 0) { | ||
| 84 | printk(KERN_INFO "%s: readcount: %ld\n", __func__, | ||
| 85 | iint->readcount); | ||
| 86 | iint->readcount = 0; | ||
| 87 | } | ||
| 88 | if (iint->writecount != 0) { | ||
| 89 | printk(KERN_INFO "%s: writecount: %ld\n", __func__, | ||
| 90 | iint->writecount); | ||
| 91 | iint->writecount = 0; | ||
| 92 | } | ||
| 93 | if (iint->opencount != 0) { | ||
| 94 | printk(KERN_INFO "%s: opencount: %ld\n", __func__, | ||
| 95 | iint->opencount); | ||
| 96 | iint->opencount = 0; | ||
| 97 | } | ||
| 98 | kref_init(&iint->refcount); | ||
| 99 | kmem_cache_free(iint_cache, iint); | 76 | kmem_cache_free(iint_cache, iint); |
| 100 | } | 77 | } |
| 101 | 78 | ||
| 102 | void iint_rcu_free(struct rcu_head *rcu_head) | 79 | /** |
| 80 | * ima_inode_alloc - allocate an iint associated with an inode | ||
| 81 | * @inode: pointer to the inode | ||
| 82 | */ | ||
| 83 | int ima_inode_alloc(struct inode *inode) | ||
| 103 | { | 84 | { |
| 104 | struct ima_iint_cache *iint = container_of(rcu_head, | 85 | struct rb_node **p; |
| 105 | struct ima_iint_cache, rcu); | 86 | struct rb_node *new_node, *parent = NULL; |
| 106 | kref_put(&iint->refcount, iint_free); | 87 | struct ima_iint_cache *new_iint, *test_iint; |
| 88 | int rc; | ||
| 89 | |||
| 90 | new_iint = kmem_cache_alloc(iint_cache, GFP_NOFS); | ||
| 91 | if (!new_iint) | ||
| 92 | return -ENOMEM; | ||
| 93 | |||
| 94 | new_iint->inode = inode; | ||
| 95 | new_node = &new_iint->rb_node; | ||
| 96 | |||
| 97 | mutex_lock(&inode->i_mutex); /* i_flags */ | ||
| 98 | spin_lock(&ima_iint_lock); | ||
| 99 | |||
| 100 | p = &ima_iint_tree.rb_node; | ||
| 101 | while (*p) { | ||
| 102 | parent = *p; | ||
| 103 | test_iint = rb_entry(parent, struct ima_iint_cache, rb_node); | ||
| 104 | |||
| 105 | rc = -EEXIST; | ||
| 106 | if (inode < test_iint->inode) | ||
| 107 | p = &(*p)->rb_left; | ||
| 108 | else if (inode > test_iint->inode) | ||
| 109 | p = &(*p)->rb_right; | ||
| 110 | else | ||
| 111 | goto out_err; | ||
| 112 | } | ||
| 113 | |||
| 114 | inode->i_flags |= S_IMA; | ||
| 115 | rb_link_node(new_node, parent, p); | ||
| 116 | rb_insert_color(new_node, &ima_iint_tree); | ||
| 117 | |||
| 118 | spin_unlock(&ima_iint_lock); | ||
| 119 | mutex_unlock(&inode->i_mutex); /* i_flags */ | ||
| 120 | |||
| 121 | return 0; | ||
| 122 | out_err: | ||
| 123 | spin_unlock(&ima_iint_lock); | ||
| 124 | mutex_unlock(&inode->i_mutex); /* i_flags */ | ||
| 125 | iint_free(new_iint); | ||
| 126 | |||
| 127 | return rc; | ||
| 107 | } | 128 | } |
| 108 | 129 | ||
| 109 | /** | 130 | /** |
| @@ -116,11 +137,20 @@ void ima_inode_free(struct inode *inode) | |||
| 116 | { | 137 | { |
| 117 | struct ima_iint_cache *iint; | 138 | struct ima_iint_cache *iint; |
| 118 | 139 | ||
| 140 | if (inode->i_readcount) | ||
| 141 | printk(KERN_INFO "%s: readcount: %u\n", __func__, inode->i_readcount); | ||
| 142 | |||
| 143 | inode->i_readcount = 0; | ||
| 144 | |||
| 145 | if (!IS_IMA(inode)) | ||
| 146 | return; | ||
| 147 | |||
| 119 | spin_lock(&ima_iint_lock); | 148 | spin_lock(&ima_iint_lock); |
| 120 | iint = radix_tree_delete(&ima_iint_store, (unsigned long)inode); | 149 | iint = __ima_iint_find(inode); |
| 150 | rb_erase(&iint->rb_node, &ima_iint_tree); | ||
| 121 | spin_unlock(&ima_iint_lock); | 151 | spin_unlock(&ima_iint_lock); |
| 122 | if (iint) | 152 | |
| 123 | call_rcu(&iint->rcu, iint_rcu_free); | 153 | iint_free(iint); |
| 124 | } | 154 | } |
| 125 | 155 | ||
| 126 | static void init_once(void *foo) | 156 | static void init_once(void *foo) |
| @@ -131,10 +161,6 @@ static void init_once(void *foo) | |||
| 131 | iint->version = 0; | 161 | iint->version = 0; |
| 132 | iint->flags = 0UL; | 162 | iint->flags = 0UL; |
| 133 | mutex_init(&iint->mutex); | 163 | mutex_init(&iint->mutex); |
| 134 | iint->readcount = 0; | ||
| 135 | iint->writecount = 0; | ||
| 136 | iint->opencount = 0; | ||
| 137 | kref_init(&iint->refcount); | ||
| 138 | } | 164 | } |
| 139 | 165 | ||
| 140 | static int __init ima_iintcache_init(void) | 166 | static int __init ima_iintcache_init(void) |
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index e662b89d4079..203de979d305 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c | |||
| @@ -85,50 +85,6 @@ out: | |||
| 85 | return found; | 85 | return found; |
| 86 | } | 86 | } |
| 87 | 87 | ||
| 88 | /* ima_read_write_check - reflect possible reading/writing errors in the PCR. | ||
| 89 | * | ||
| 90 | * When opening a file for read, if the file is already open for write, | ||
| 91 | * the file could change, resulting in a file measurement error. | ||
| 92 | * | ||
| 93 | * Opening a file for write, if the file is already open for read, results | ||
| 94 | * in a time of measure, time of use (ToMToU) error. | ||
| 95 | * | ||
| 96 | * In either case invalidate the PCR. | ||
| 97 | */ | ||
| 98 | enum iint_pcr_error { TOMTOU, OPEN_WRITERS }; | ||
| 99 | static void ima_read_write_check(enum iint_pcr_error error, | ||
| 100 | struct ima_iint_cache *iint, | ||
| 101 | struct inode *inode, | ||
| 102 | const unsigned char *filename) | ||
| 103 | { | ||
| 104 | switch (error) { | ||
| 105 | case TOMTOU: | ||
| 106 | if (iint->readcount > 0) | ||
| 107 | ima_add_violation(inode, filename, "invalid_pcr", | ||
| 108 | "ToMToU"); | ||
| 109 | break; | ||
| 110 | case OPEN_WRITERS: | ||
| 111 | if (iint->writecount > 0) | ||
| 112 | ima_add_violation(inode, filename, "invalid_pcr", | ||
| 113 | "open_writers"); | ||
| 114 | break; | ||
| 115 | } | ||
| 116 | } | ||
| 117 | |||
| 118 | /* | ||
| 119 | * Update the counts given an fmode_t | ||
| 120 | */ | ||
| 121 | static void ima_inc_counts(struct ima_iint_cache *iint, fmode_t mode) | ||
| 122 | { | ||
| 123 | BUG_ON(!mutex_is_locked(&iint->mutex)); | ||
| 124 | |||
| 125 | iint->opencount++; | ||
| 126 | if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) | ||
| 127 | iint->readcount++; | ||
| 128 | if (mode & FMODE_WRITE) | ||
| 129 | iint->writecount++; | ||
| 130 | } | ||
| 131 | |||
| 132 | /* | 88 | /* |
| 133 | * ima_counts_get - increment file counts | 89 | * ima_counts_get - increment file counts |
| 134 | * | 90 | * |
| @@ -145,62 +101,101 @@ void ima_counts_get(struct file *file) | |||
| 145 | struct dentry *dentry = file->f_path.dentry; | 101 | struct dentry *dentry = file->f_path.dentry; |
| 146 | struct inode *inode = dentry->d_inode; | 102 | struct inode *inode = dentry->d_inode; |
| 147 | fmode_t mode = file->f_mode; | 103 | fmode_t mode = file->f_mode; |
| 148 | struct ima_iint_cache *iint; | ||
| 149 | int rc; | 104 | int rc; |
| 105 | bool send_tomtou = false, send_writers = false; | ||
| 150 | 106 | ||
| 151 | if (!iint_initialized || !S_ISREG(inode->i_mode)) | 107 | if (!S_ISREG(inode->i_mode)) |
| 152 | return; | 108 | return; |
| 153 | iint = ima_iint_find_get(inode); | 109 | |
| 154 | if (!iint) | 110 | spin_lock(&inode->i_lock); |
| 155 | return; | 111 | |
| 156 | mutex_lock(&iint->mutex); | ||
| 157 | if (!ima_initialized) | 112 | if (!ima_initialized) |
| 158 | goto out; | 113 | goto out; |
| 159 | rc = ima_must_measure(iint, inode, MAY_READ, FILE_CHECK); | ||
| 160 | if (rc < 0) | ||
| 161 | goto out; | ||
| 162 | 114 | ||
| 163 | if (mode & FMODE_WRITE) { | 115 | if (mode & FMODE_WRITE) { |
| 164 | ima_read_write_check(TOMTOU, iint, inode, dentry->d_name.name); | 116 | if (inode->i_readcount && IS_IMA(inode)) |
| 117 | send_tomtou = true; | ||
| 165 | goto out; | 118 | goto out; |
| 166 | } | 119 | } |
| 167 | ima_read_write_check(OPEN_WRITERS, iint, inode, dentry->d_name.name); | 120 | |
| 121 | rc = ima_must_measure(NULL, inode, MAY_READ, FILE_CHECK); | ||
| 122 | if (rc < 0) | ||
| 123 | goto out; | ||
| 124 | |||
| 125 | if (atomic_read(&inode->i_writecount) > 0) | ||
| 126 | send_writers = true; | ||
| 168 | out: | 127 | out: |
| 169 | ima_inc_counts(iint, file->f_mode); | 128 | /* remember the vfs deals with i_writecount */ |
| 170 | mutex_unlock(&iint->mutex); | 129 | if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) |
| 130 | inode->i_readcount++; | ||
| 171 | 131 | ||
| 172 | kref_put(&iint->refcount, iint_free); | 132 | spin_unlock(&inode->i_lock); |
| 133 | |||
| 134 | if (send_tomtou) | ||
| 135 | ima_add_violation(inode, dentry->d_name.name, "invalid_pcr", | ||
| 136 | "ToMToU"); | ||
| 137 | if (send_writers) | ||
| 138 | ima_add_violation(inode, dentry->d_name.name, "invalid_pcr", | ||
| 139 | "open_writers"); | ||
| 173 | } | 140 | } |
| 174 | 141 | ||
| 175 | /* | 142 | /* |
| 176 | * Decrement ima counts | 143 | * Decrement ima counts |
| 177 | */ | 144 | */ |
| 178 | static void ima_dec_counts(struct ima_iint_cache *iint, struct inode *inode, | 145 | static void ima_dec_counts(struct inode *inode, struct file *file) |
| 179 | struct file *file) | ||
| 180 | { | 146 | { |
| 181 | mode_t mode = file->f_mode; | 147 | mode_t mode = file->f_mode; |
| 182 | BUG_ON(!mutex_is_locked(&iint->mutex)); | ||
| 183 | 148 | ||
| 184 | iint->opencount--; | 149 | assert_spin_locked(&inode->i_lock); |
| 185 | if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) | 150 | |
| 186 | iint->readcount--; | 151 | if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) { |
| 187 | if (mode & FMODE_WRITE) { | 152 | if (unlikely(inode->i_readcount == 0)) { |
| 188 | iint->writecount--; | 153 | if (!ima_limit_imbalance(file)) { |
| 189 | if (iint->writecount == 0) { | 154 | printk(KERN_INFO "%s: open/free imbalance (r:%u)\n", |
| 190 | if (iint->version != inode->i_version) | 155 | __func__, inode->i_readcount); |
| 191 | iint->flags &= ~IMA_MEASURED; | 156 | dump_stack(); |
| 157 | } | ||
| 158 | return; | ||
| 192 | } | 159 | } |
| 160 | inode->i_readcount--; | ||
| 193 | } | 161 | } |
| 162 | } | ||
| 194 | 163 | ||
| 195 | if (((iint->opencount < 0) || | 164 | static void ima_check_last_writer(struct ima_iint_cache *iint, |
| 196 | (iint->readcount < 0) || | 165 | struct inode *inode, |
| 197 | (iint->writecount < 0)) && | 166 | struct file *file) |
| 198 | !ima_limit_imbalance(file)) { | 167 | { |
| 199 | printk(KERN_INFO "%s: open/free imbalance (r:%ld w:%ld o:%ld)\n", | 168 | mode_t mode = file->f_mode; |
| 200 | __func__, iint->readcount, iint->writecount, | 169 | |
| 201 | iint->opencount); | 170 | BUG_ON(!mutex_is_locked(&iint->mutex)); |
| 202 | dump_stack(); | 171 | assert_spin_locked(&inode->i_lock); |
| 203 | } | 172 | |
| 173 | if (mode & FMODE_WRITE && | ||
| 174 | atomic_read(&inode->i_writecount) == 1 && | ||
| 175 | iint->version != inode->i_version) | ||
| 176 | iint->flags &= ~IMA_MEASURED; | ||
| 177 | } | ||
| 178 | |||
| 179 | static void ima_file_free_iint(struct ima_iint_cache *iint, struct inode *inode, | ||
| 180 | struct file *file) | ||
| 181 | { | ||
| 182 | mutex_lock(&iint->mutex); | ||
| 183 | spin_lock(&inode->i_lock); | ||
| 184 | |||
| 185 | ima_dec_counts(inode, file); | ||
| 186 | ima_check_last_writer(iint, inode, file); | ||
| 187 | |||
| 188 | spin_unlock(&inode->i_lock); | ||
| 189 | mutex_unlock(&iint->mutex); | ||
| 190 | } | ||
| 191 | |||
| 192 | static void ima_file_free_noiint(struct inode *inode, struct file *file) | ||
| 193 | { | ||
| 194 | spin_lock(&inode->i_lock); | ||
| 195 | |||
| 196 | ima_dec_counts(inode, file); | ||
| 197 | |||
| 198 | spin_unlock(&inode->i_lock); | ||
| 204 | } | 199 | } |
| 205 | 200 | ||
| 206 | /** | 201 | /** |
| @@ -208,7 +203,7 @@ static void ima_dec_counts(struct ima_iint_cache *iint, struct inode *inode, | |||
| 208 | * @file: pointer to file structure being freed | 203 | * @file: pointer to file structure being freed |
| 209 | * | 204 | * |
| 210 | * Flag files that changed, based on i_version; | 205 | * Flag files that changed, based on i_version; |
| 211 | * and decrement the iint readcount/writecount. | 206 | * and decrement the i_readcount. |
| 212 | */ | 207 | */ |
| 213 | void ima_file_free(struct file *file) | 208 | void ima_file_free(struct file *file) |
| 214 | { | 209 | { |
| @@ -217,14 +212,14 @@ void ima_file_free(struct file *file) | |||
| 217 | 212 | ||
| 218 | if (!iint_initialized || !S_ISREG(inode->i_mode)) | 213 | if (!iint_initialized || !S_ISREG(inode->i_mode)) |
| 219 | return; | 214 | return; |
| 220 | iint = ima_iint_find_get(inode); | ||
| 221 | if (!iint) | ||
| 222 | return; | ||
| 223 | 215 | ||
| 224 | mutex_lock(&iint->mutex); | 216 | iint = ima_iint_find(inode); |
| 225 | ima_dec_counts(iint, inode, file); | 217 | |
| 226 | mutex_unlock(&iint->mutex); | 218 | if (iint) |
| 227 | kref_put(&iint->refcount, iint_free); | 219 | ima_file_free_iint(iint, inode, file); |
| 220 | else | ||
| 221 | ima_file_free_noiint(inode, file); | ||
| 222 | |||
| 228 | } | 223 | } |
| 229 | 224 | ||
| 230 | static int process_measurement(struct file *file, const unsigned char *filename, | 225 | static int process_measurement(struct file *file, const unsigned char *filename, |
| @@ -236,11 +231,21 @@ static int process_measurement(struct file *file, const unsigned char *filename, | |||
| 236 | 231 | ||
| 237 | if (!ima_initialized || !S_ISREG(inode->i_mode)) | 232 | if (!ima_initialized || !S_ISREG(inode->i_mode)) |
| 238 | return 0; | 233 | return 0; |
| 239 | iint = ima_iint_find_get(inode); | 234 | |
| 240 | if (!iint) | 235 | rc = ima_must_measure(NULL, inode, mask, function); |
| 241 | return -ENOMEM; | 236 | if (rc != 0) |
| 237 | return rc; | ||
| 238 | retry: | ||
| 239 | iint = ima_iint_find(inode); | ||
| 240 | if (!iint) { | ||
| 241 | rc = ima_inode_alloc(inode); | ||
| 242 | if (!rc || rc == -EEXIST) | ||
| 243 | goto retry; | ||
| 244 | return rc; | ||
| 245 | } | ||
| 242 | 246 | ||
| 243 | mutex_lock(&iint->mutex); | 247 | mutex_lock(&iint->mutex); |
| 248 | |||
| 244 | rc = ima_must_measure(iint, inode, mask, function); | 249 | rc = ima_must_measure(iint, inode, mask, function); |
| 245 | if (rc != 0) | 250 | if (rc != 0) |
| 246 | goto out; | 251 | goto out; |
| @@ -250,7 +255,6 @@ static int process_measurement(struct file *file, const unsigned char *filename, | |||
| 250 | ima_store_measurement(iint, file, filename); | 255 | ima_store_measurement(iint, file, filename); |
| 251 | out: | 256 | out: |
| 252 | mutex_unlock(&iint->mutex); | 257 | mutex_unlock(&iint->mutex); |
| 253 | kref_put(&iint->refcount, iint_free); | ||
| 254 | return rc; | 258 | return rc; |
| 255 | } | 259 | } |
| 256 | 260 | ||
diff --git a/security/security.c b/security/security.c index b50f472061a4..3ef5e2a7a741 100644 --- a/security/security.c +++ b/security/security.c | |||
| @@ -325,16 +325,8 @@ EXPORT_SYMBOL(security_sb_parse_opts_str); | |||
| 325 | 325 | ||
| 326 | int security_inode_alloc(struct inode *inode) | 326 | int security_inode_alloc(struct inode *inode) |
| 327 | { | 327 | { |
| 328 | int ret; | ||
| 329 | |||
| 330 | inode->i_security = NULL; | 328 | inode->i_security = NULL; |
| 331 | ret = security_ops->inode_alloc_security(inode); | 329 | return security_ops->inode_alloc_security(inode); |
| 332 | if (ret) | ||
| 333 | return ret; | ||
| 334 | ret = ima_inode_alloc(inode); | ||
| 335 | if (ret) | ||
| 336 | security_inode_free(inode); | ||
| 337 | return ret; | ||
| 338 | } | 330 | } |
| 339 | 331 | ||
| 340 | void security_inode_free(struct inode *inode) | 332 | void security_inode_free(struct inode *inode) |
