diff options
| -rw-r--r-- | fs/inode.c | 1 | ||||
| -rw-r--r-- | include/linux/fs.h | 4 | ||||
| -rw-r--r-- | security/integrity/ima/ima.h | 3 | ||||
| -rw-r--r-- | security/integrity/ima/ima_api.c | 2 | ||||
| -rw-r--r-- | security/integrity/ima/ima_iint.c | 11 | ||||
| -rw-r--r-- | security/integrity/ima/ima_main.c | 35 | 
6 files changed, 22 insertions, 34 deletions
| diff --git a/fs/inode.c b/fs/inode.c index 86464332e590..56d909d69bc8 100644 --- a/fs/inode.c +++ b/fs/inode.c | |||
| @@ -24,6 +24,7 @@ | |||
| 24 | #include <linux/mount.h> | 24 | #include <linux/mount.h> | 
| 25 | #include <linux/async.h> | 25 | #include <linux/async.h> | 
| 26 | #include <linux/posix_acl.h> | 26 | #include <linux/posix_acl.h> | 
| 27 | #include <linux/ima.h> | ||
| 27 | 28 | ||
| 28 | /* | 29 | /* | 
| 29 | * This is needed for the following functions: | 30 | * This is needed for the following functions: | 
| diff --git a/include/linux/fs.h b/include/linux/fs.h index 63d069bd80b7..01e3a0047fed 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
| @@ -776,6 +776,10 @@ struct inode { | |||
| 776 | 776 | ||
| 777 | unsigned int i_flags; | 777 | unsigned int i_flags; | 
| 778 | 778 | ||
| 779 | #ifdef CONFIG_IMA | ||
| 780 | /* protected by i_lock */ | ||
| 781 | unsigned int i_readcount; /* struct files open RO */ | ||
| 782 | #endif | ||
| 779 | atomic_t i_writecount; | 783 | atomic_t i_writecount; | 
| 780 | #ifdef CONFIG_SECURITY | 784 | #ifdef CONFIG_SECURITY | 
| 781 | void *i_security; | 785 | void *i_security; | 
| diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index b546b90f5fa8..27849e1656dc 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); | 
| @@ -106,8 +107,6 @@ struct ima_iint_cache { | |||
| 106 | unsigned char flags; | 107 | unsigned char flags; | 
| 107 | u8 digest[IMA_DIGEST_SIZE]; | 108 | u8 digest[IMA_DIGEST_SIZE]; | 
| 108 | struct mutex mutex; /* protects: version, flags, digest */ | 109 | struct mutex mutex; /* protects: version, flags, digest */ | 
| 109 | /* protected by inode->i_lock */ | ||
| 110 | unsigned int readcount; /* measured files readcount */ | ||
| 111 | struct kref refcount; /* ima_iint_cache reference count */ | 110 | struct kref refcount; /* ima_iint_cache reference count */ | 
| 112 | }; | 111 | }; | 
| 113 | 112 | ||
| 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 e68891f8d55a..0936a7197e47 100644 --- a/security/integrity/ima/ima_iint.c +++ b/security/integrity/ima/ima_iint.c | |||
| @@ -124,11 +124,6 @@ void iint_free(struct kref *kref) | |||
| 124 | refcount); | 124 | refcount); | 
| 125 | iint->version = 0; | 125 | iint->version = 0; | 
| 126 | iint->flags = 0UL; | 126 | iint->flags = 0UL; | 
| 127 | if (iint->readcount != 0) { | ||
| 128 | printk(KERN_INFO "%s: readcount: %u\n", __func__, | ||
| 129 | iint->readcount); | ||
| 130 | iint->readcount = 0; | ||
| 131 | } | ||
| 132 | kref_init(&iint->refcount); | 127 | kref_init(&iint->refcount); | 
| 133 | kmem_cache_free(iint_cache, iint); | 128 | kmem_cache_free(iint_cache, iint); | 
| 134 | } | 129 | } | 
| @@ -143,6 +138,11 @@ void ima_inode_free(struct inode *inode) | |||
| 143 | { | 138 | { | 
| 144 | struct ima_iint_cache *iint; | 139 | struct ima_iint_cache *iint; | 
| 145 | 140 | ||
| 141 | if (inode->i_readcount) | ||
| 142 | printk(KERN_INFO "%s: readcount: %u\n", __func__, inode->i_readcount); | ||
| 143 | |||
| 144 | inode->i_readcount = 0; | ||
| 145 | |||
| 146 | spin_lock(&ima_iint_lock); | 146 | spin_lock(&ima_iint_lock); | 
| 147 | iint = __ima_iint_find(inode); | 147 | iint = __ima_iint_find(inode); | 
| 148 | if (iint) | 148 | if (iint) | 
| @@ -160,7 +160,6 @@ static void init_once(void *foo) | |||
| 160 | iint->version = 0; | 160 | iint->version = 0; | 
| 161 | iint->flags = 0UL; | 161 | iint->flags = 0UL; | 
| 162 | mutex_init(&iint->mutex); | 162 | mutex_init(&iint->mutex); | 
| 163 | iint->readcount = 0; | ||
| 164 | kref_init(&iint->refcount); | 163 | kref_init(&iint->refcount); | 
| 165 | } | 164 | } | 
| 166 | 165 | ||
| diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index 24660bf3f82a..2a77b14fee27 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c | |||
| @@ -86,17 +86,6 @@ out: | |||
| 86 | } | 86 | } | 
| 87 | 87 | ||
| 88 | /* | 88 | /* | 
| 89 | * Update the counts given an fmode_t | ||
| 90 | */ | ||
| 91 | static void ima_inc_counts(struct ima_iint_cache *iint, fmode_t mode) | ||
| 92 | { | ||
| 93 | assert_spin_locked(&iint->inode->i_lock); | ||
| 94 | |||
| 95 | if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) | ||
| 96 | iint->readcount++; | ||
| 97 | } | ||
| 98 | |||
| 99 | /* | ||
| 100 | * ima_counts_get - increment file counts | 89 | * ima_counts_get - increment file counts | 
| 101 | * | 90 | * | 
| 102 | * Maintain read/write counters for all files, but only | 91 | * Maintain read/write counters for all files, but only | 
| @@ -112,27 +101,23 @@ void ima_counts_get(struct file *file) | |||
| 112 | struct dentry *dentry = file->f_path.dentry; | 101 | struct dentry *dentry = file->f_path.dentry; | 
| 113 | struct inode *inode = dentry->d_inode; | 102 | struct inode *inode = dentry->d_inode; | 
| 114 | fmode_t mode = file->f_mode; | 103 | fmode_t mode = file->f_mode; | 
| 115 | struct ima_iint_cache *iint; | ||
| 116 | int rc; | 104 | int rc; | 
| 117 | bool send_tomtou = false, send_writers = false; | 105 | bool send_tomtou = false, send_writers = false; | 
| 118 | 106 | ||
| 119 | if (!iint_initialized || !S_ISREG(inode->i_mode)) | 107 | if (!S_ISREG(inode->i_mode)) | 
| 120 | return; | 108 | return; | 
| 121 | iint = ima_iint_find_get(inode); | 109 | |
| 122 | if (!iint) | ||
| 123 | return; | ||
| 124 | mutex_lock(&iint->mutex); | ||
| 125 | spin_lock(&inode->i_lock); | 110 | spin_lock(&inode->i_lock); | 
| 126 | 111 | ||
| 127 | if (!ima_initialized) | 112 | if (!ima_initialized) | 
| 128 | goto out; | 113 | goto out; | 
| 129 | 114 | ||
| 130 | rc = ima_must_measure(iint, inode, MAY_READ, FILE_CHECK); | 115 | rc = ima_must_measure(NULL, inode, MAY_READ, FILE_CHECK); | 
| 131 | if (rc < 0) | 116 | if (rc < 0) | 
| 132 | goto out; | 117 | goto out; | 
| 133 | 118 | ||
| 134 | if (mode & FMODE_WRITE) { | 119 | if (mode & FMODE_WRITE) { | 
| 135 | if (iint->readcount) | 120 | if (inode->i_readcount) | 
| 136 | send_tomtou = true; | 121 | send_tomtou = true; | 
| 137 | goto out; | 122 | goto out; | 
| 138 | } | 123 | } | 
| @@ -140,10 +125,10 @@ void ima_counts_get(struct file *file) | |||
| 140 | if (atomic_read(&inode->i_writecount) > 0) | 125 | if (atomic_read(&inode->i_writecount) > 0) | 
| 141 | send_writers = true; | 126 | send_writers = true; | 
| 142 | out: | 127 | out: | 
| 143 | ima_inc_counts(iint, file->f_mode); | 128 | /* remember the vfs deals with i_writecount */ | 
| 129 | if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) | ||
| 130 | inode->i_readcount++; | ||
| 144 | spin_unlock(&inode->i_lock); | 131 | spin_unlock(&inode->i_lock); | 
| 145 | mutex_unlock(&iint->mutex); | ||
| 146 | kref_put(&iint->refcount, iint_free); | ||
| 147 | 132 | ||
| 148 | if (send_tomtou) | 133 | if (send_tomtou) | 
| 149 | ima_add_violation(inode, dentry->d_name.name, "invalid_pcr", | 134 | ima_add_violation(inode, dentry->d_name.name, "invalid_pcr", | 
| @@ -166,9 +151,9 @@ static void ima_dec_counts(struct ima_iint_cache *iint, struct inode *inode, | |||
| 166 | assert_spin_locked(&inode->i_lock); | 151 | assert_spin_locked(&inode->i_lock); | 
| 167 | 152 | ||
| 168 | if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) { | 153 | if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) { | 
| 169 | if (unlikely(iint->readcount == 0)) | 154 | if (unlikely(inode->i_readcount == 0)) | 
| 170 | dump = true; | 155 | dump = true; | 
| 171 | iint->readcount--; | 156 | inode->i_readcount--; | 
| 172 | } | 157 | } | 
| 173 | if (mode & FMODE_WRITE) { | 158 | if (mode & FMODE_WRITE) { | 
| 174 | if (atomic_read(&inode->i_writecount) <= 0) | 159 | if (atomic_read(&inode->i_writecount) <= 0) | 
| @@ -180,7 +165,7 @@ static void ima_dec_counts(struct ima_iint_cache *iint, struct inode *inode, | |||
| 180 | 165 | ||
| 181 | if (dump && !ima_limit_imbalance(file)) { | 166 | if (dump && !ima_limit_imbalance(file)) { | 
| 182 | printk(KERN_INFO "%s: open/free imbalance (r:%u)\n", | 167 | printk(KERN_INFO "%s: open/free imbalance (r:%u)\n", | 
| 183 | __func__, iint->readcount); | 168 | __func__, inode->i_readcount); | 
| 184 | dump_stack(); | 169 | dump_stack(); | 
| 185 | } | 170 | } | 
| 186 | } | 171 | } | 
