diff options
Diffstat (limited to 'security/integrity/ima/ima_main.c')
-rw-r--r-- | security/integrity/ima/ima_main.c | 104 |
1 files changed, 4 insertions, 100 deletions
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index 69b4856af4da..2df902151193 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c | |||
@@ -36,55 +36,6 @@ static int __init hash_setup(char *str) | |||
36 | } | 36 | } |
37 | __setup("ima_hash=", hash_setup); | 37 | __setup("ima_hash=", hash_setup); |
38 | 38 | ||
39 | struct ima_imbalance { | ||
40 | struct hlist_node node; | ||
41 | unsigned long fsmagic; | ||
42 | }; | ||
43 | |||
44 | /* | ||
45 | * ima_limit_imbalance - emit one imbalance message per filesystem type | ||
46 | * | ||
47 | * Maintain list of filesystem types that do not measure files properly. | ||
48 | * Return false if unknown, true if known. | ||
49 | */ | ||
50 | static bool ima_limit_imbalance(struct file *file) | ||
51 | { | ||
52 | static DEFINE_SPINLOCK(ima_imbalance_lock); | ||
53 | static HLIST_HEAD(ima_imbalance_list); | ||
54 | |||
55 | struct super_block *sb = file->f_dentry->d_sb; | ||
56 | struct ima_imbalance *entry; | ||
57 | struct hlist_node *node; | ||
58 | bool found = false; | ||
59 | |||
60 | rcu_read_lock(); | ||
61 | hlist_for_each_entry_rcu(entry, node, &ima_imbalance_list, node) { | ||
62 | if (entry->fsmagic == sb->s_magic) { | ||
63 | found = true; | ||
64 | break; | ||
65 | } | ||
66 | } | ||
67 | rcu_read_unlock(); | ||
68 | if (found) | ||
69 | goto out; | ||
70 | |||
71 | entry = kmalloc(sizeof(*entry), GFP_NOFS); | ||
72 | if (!entry) | ||
73 | goto out; | ||
74 | entry->fsmagic = sb->s_magic; | ||
75 | spin_lock(&ima_imbalance_lock); | ||
76 | /* | ||
77 | * we could have raced and something else might have added this fs | ||
78 | * to the list, but we don't really care | ||
79 | */ | ||
80 | hlist_add_head_rcu(&entry->node, &ima_imbalance_list); | ||
81 | spin_unlock(&ima_imbalance_lock); | ||
82 | printk(KERN_INFO "IMA: unmeasured files on fsmagic: %lX\n", | ||
83 | entry->fsmagic); | ||
84 | out: | ||
85 | return found; | ||
86 | } | ||
87 | |||
88 | /* | 39 | /* |
89 | * ima_rdwr_violation_check | 40 | * ima_rdwr_violation_check |
90 | * | 41 | * |
@@ -131,65 +82,20 @@ out: | |||
131 | "open_writers"); | 82 | "open_writers"); |
132 | } | 83 | } |
133 | 84 | ||
134 | /* | ||
135 | * Decrement ima counts | ||
136 | */ | ||
137 | static void ima_dec_counts(struct inode *inode, struct file *file) | ||
138 | { | ||
139 | mode_t mode = file->f_mode; | ||
140 | |||
141 | assert_spin_locked(&inode->i_lock); | ||
142 | |||
143 | if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) { | ||
144 | if (unlikely(atomic_read(&inode->i_readcount) == 0)) { | ||
145 | if (!ima_limit_imbalance(file)) { | ||
146 | printk(KERN_INFO "%s: open/free imbalance (r:%u)\n", | ||
147 | __func__, | ||
148 | atomic_read(&inode->i_readcount)); | ||
149 | dump_stack(); | ||
150 | } | ||
151 | return; | ||
152 | } | ||
153 | } | ||
154 | } | ||
155 | |||
156 | static void ima_check_last_writer(struct ima_iint_cache *iint, | 85 | static void ima_check_last_writer(struct ima_iint_cache *iint, |
157 | struct inode *inode, | 86 | struct inode *inode, |
158 | struct file *file) | 87 | struct file *file) |
159 | { | 88 | { |
160 | mode_t mode = file->f_mode; | 89 | mode_t mode = file->f_mode; |
161 | 90 | ||
162 | BUG_ON(!mutex_is_locked(&iint->mutex)); | 91 | mutex_lock(&iint->mutex); |
163 | assert_spin_locked(&inode->i_lock); | ||
164 | |||
165 | if (mode & FMODE_WRITE && | 92 | if (mode & FMODE_WRITE && |
166 | atomic_read(&inode->i_writecount) == 1 && | 93 | atomic_read(&inode->i_writecount) == 1 && |
167 | iint->version != inode->i_version) | 94 | iint->version != inode->i_version) |
168 | iint->flags &= ~IMA_MEASURED; | 95 | iint->flags &= ~IMA_MEASURED; |
169 | } | ||
170 | |||
171 | static void ima_file_free_iint(struct ima_iint_cache *iint, struct inode *inode, | ||
172 | struct file *file) | ||
173 | { | ||
174 | mutex_lock(&iint->mutex); | ||
175 | spin_lock(&inode->i_lock); | ||
176 | |||
177 | ima_dec_counts(inode, file); | ||
178 | ima_check_last_writer(iint, inode, file); | ||
179 | |||
180 | spin_unlock(&inode->i_lock); | ||
181 | mutex_unlock(&iint->mutex); | 96 | mutex_unlock(&iint->mutex); |
182 | } | 97 | } |
183 | 98 | ||
184 | static void ima_file_free_noiint(struct inode *inode, struct file *file) | ||
185 | { | ||
186 | spin_lock(&inode->i_lock); | ||
187 | |||
188 | ima_dec_counts(inode, file); | ||
189 | |||
190 | spin_unlock(&inode->i_lock); | ||
191 | } | ||
192 | |||
193 | /** | 99 | /** |
194 | * ima_file_free - called on __fput() | 100 | * ima_file_free - called on __fput() |
195 | * @file: pointer to file structure being freed | 101 | * @file: pointer to file structure being freed |
@@ -205,12 +111,10 @@ void ima_file_free(struct file *file) | |||
205 | return; | 111 | return; |
206 | 112 | ||
207 | iint = ima_iint_find(inode); | 113 | iint = ima_iint_find(inode); |
114 | if (!iint) | ||
115 | return; | ||
208 | 116 | ||
209 | if (iint) | 117 | ima_check_last_writer(iint, inode, file); |
210 | ima_file_free_iint(iint, inode, file); | ||
211 | else | ||
212 | ima_file_free_noiint(inode, file); | ||
213 | |||
214 | } | 118 | } |
215 | 119 | ||
216 | static int process_measurement(struct file *file, const unsigned char *filename, | 120 | static int process_measurement(struct file *file, const unsigned char *filename, |