aboutsummaryrefslogtreecommitdiffstats
path: root/security/integrity
diff options
context:
space:
mode:
authorRoberto Sassu <roberto.sassu@polito.it>2014-09-12 13:35:55 -0400
committerMimi Zohar <zohar@linux.vnet.ibm.com>2014-09-18 10:03:55 -0400
commitf7a859ff7395c0ffe60f9563df5354473e5f9244 (patch)
tree76e56090f72f9c7a26ae337da4e6ac09e9a34fea /security/integrity
parenta756024efea259282e65f3a00f512b094e805d76 (diff)
ima: fix race condition on ima_rdwr_violation_check and process_measurement
This patch fixes a race condition between two functions that try to access the same inode. Since the i_mutex lock is held and released separately in the two functions, there may be the possibility that a violation is not correctly detected. Suppose there are two processes, A (reader) and B (writer), if the following sequence happens: A: ima_rdwr_violation_check() B: ima_rdwr_violation_check() B: process_measurement() B: starts writing the inode A: process_measurement() the ToMToU violation (a reader may be accessing a content different from that measured, due to a concurrent modification by a writer) will not be detected. To avoid this issue, the violation check and the measurement must be done atomically. This patch fixes the problem by moving the violation check inside process_measurement() when the i_mutex lock is held. Differently from the old code, the violation check is executed also for the MMAP_CHECK hook (other than for FILE_CHECK). This allows to detect ToMToU violations that are possible because shared libraries can be opened for writing while they are in use (according to the output of 'man mmap', the mmap() flag MAP_DENYWRITE is ignored). Changes in v5 (Roberto Sassu): * get iint if action is not zero * exit process_measurement() after the violation check if action is zero * reverse order process_measurement() exit cleanup (Mimi) Changes in v4 (Dmitry Kasatkin): * iint allocation is done before calling ima_rdrw_violation_check() (Suggested-by Mimi) * do not check for violations if the policy does not contain 'measure' rules (done by Roberto Sassu) Changes in v3 (Dmitry Kasatkin): * no violation checking for MMAP_CHECK function in this patch * remove use of filename from violation * removes checking if ima is enabled from ima_rdrw_violation_check * slight style change Suggested-by: Dmitry Kasatkin <d.kasatkin@samsung.com> Signed-off-by: Roberto Sassu <roberto.sassu@polito.it> Signed-off-by: Dmitry Kasatkin <d.kasatkin@samsung.com> Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
Diffstat (limited to 'security/integrity')
-rw-r--r--security/integrity/ima/ima_main.c54
1 files changed, 33 insertions, 21 deletions
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index 2191b36ad1da..03bb52ecf490 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -77,21 +77,19 @@ __setup("ima_hash=", hash_setup);
77 * could result in a file measurement error. 77 * could result in a file measurement error.
78 * 78 *
79 */ 79 */
80static void ima_rdwr_violation_check(struct file *file) 80static void ima_rdwr_violation_check(struct file *file,
81 struct integrity_iint_cache *iint,
82 char **pathbuf,
83 const char **pathname)
81{ 84{
82 struct inode *inode = file_inode(file); 85 struct inode *inode = file_inode(file);
83 fmode_t mode = file->f_mode; 86 fmode_t mode = file->f_mode;
84 bool send_tomtou = false, send_writers = false; 87 bool send_tomtou = false, send_writers = false;
85 char *pathbuf = NULL;
86 const char *pathname;
87
88 if (!S_ISREG(inode->i_mode) || !(ima_policy_flag & IMA_MEASURE))
89 return;
90 88
91 if (mode & FMODE_WRITE) { 89 if (mode & FMODE_WRITE) {
92 if (atomic_read(&inode->i_readcount) && IS_IMA(inode)) { 90 if (atomic_read(&inode->i_readcount) && IS_IMA(inode)) {
93 struct integrity_iint_cache *iint; 91 if (!iint)
94 iint = integrity_iint_find(inode); 92 iint = integrity_iint_find(inode);
95 /* IMA_MEASURE is set from reader side */ 93 /* IMA_MEASURE is set from reader side */
96 if (iint && (iint->flags & IMA_MEASURE)) 94 if (iint && (iint->flags & IMA_MEASURE))
97 send_tomtou = true; 95 send_tomtou = true;
@@ -105,14 +103,13 @@ static void ima_rdwr_violation_check(struct file *file)
105 if (!send_tomtou && !send_writers) 103 if (!send_tomtou && !send_writers)
106 return; 104 return;
107 105
108 pathname = ima_d_path(&file->f_path, &pathbuf); 106 *pathname = ima_d_path(&file->f_path, pathbuf);
109 107
110 if (send_tomtou) 108 if (send_tomtou)
111 ima_add_violation(file, pathname, "invalid_pcr", "ToMToU"); 109 ima_add_violation(file, *pathname, "invalid_pcr", "ToMToU");
112 if (send_writers) 110 if (send_writers)
113 ima_add_violation(file, pathname, 111 ima_add_violation(file, *pathname,
114 "invalid_pcr", "open_writers"); 112 "invalid_pcr", "open_writers");
115 kfree(pathbuf);
116} 113}
117 114
118static void ima_check_last_writer(struct integrity_iint_cache *iint, 115static void ima_check_last_writer(struct integrity_iint_cache *iint,
@@ -160,13 +157,14 @@ static int process_measurement(struct file *file, int mask, int function,
160 int opened) 157 int opened)
161{ 158{
162 struct inode *inode = file_inode(file); 159 struct inode *inode = file_inode(file);
163 struct integrity_iint_cache *iint; 160 struct integrity_iint_cache *iint = NULL;
164 struct ima_template_desc *template_desc; 161 struct ima_template_desc *template_desc;
165 char *pathbuf = NULL; 162 char *pathbuf = NULL;
166 const char *pathname = NULL; 163 const char *pathname = NULL;
167 int rc = -ENOMEM, action, must_appraise; 164 int rc = -ENOMEM, action, must_appraise;
168 struct evm_ima_xattr_data *xattr_value = NULL, **xattr_ptr = NULL; 165 struct evm_ima_xattr_data *xattr_value = NULL, **xattr_ptr = NULL;
169 int xattr_len = 0; 166 int xattr_len = 0;
167 bool violation_check;
170 168
171 if (!ima_policy_flag || !S_ISREG(inode->i_mode)) 169 if (!ima_policy_flag || !S_ISREG(inode->i_mode))
172 return 0; 170 return 0;
@@ -176,7 +174,9 @@ static int process_measurement(struct file *file, int mask, int function,
176 * Included is the appraise submask. 174 * Included is the appraise submask.
177 */ 175 */
178 action = ima_get_action(inode, mask, function); 176 action = ima_get_action(inode, mask, function);
179 if (!action) 177 violation_check = (function == FILE_CHECK &&
178 (ima_policy_flag & IMA_MEASURE));
179 if (!action && !violation_check)
180 return 0; 180 return 0;
181 181
182 must_appraise = action & IMA_APPRAISE; 182 must_appraise = action & IMA_APPRAISE;
@@ -187,9 +187,19 @@ static int process_measurement(struct file *file, int mask, int function,
187 187
188 mutex_lock(&inode->i_mutex); 188 mutex_lock(&inode->i_mutex);
189 189
190 iint = integrity_inode_get(inode); 190 if (action) {
191 if (!iint) 191 iint = integrity_inode_get(inode);
192 goto out; 192 if (!iint)
193 goto out;
194 }
195
196 if (violation_check) {
197 ima_rdwr_violation_check(file, iint, &pathbuf, &pathname);
198 if (!action) {
199 rc = 0;
200 goto out_free;
201 }
202 }
193 203
194 /* Determine if already appraised/measured based on bitmask 204 /* Determine if already appraised/measured based on bitmask
195 * (IMA_MEASURE, IMA_MEASURED, IMA_XXXX_APPRAISE, IMA_XXXX_APPRAISED, 205 * (IMA_MEASURE, IMA_MEASURED, IMA_XXXX_APPRAISE, IMA_XXXX_APPRAISED,
@@ -218,7 +228,8 @@ static int process_measurement(struct file *file, int mask, int function,
218 goto out_digsig; 228 goto out_digsig;
219 } 229 }
220 230
221 pathname = ima_d_path(&file->f_path, &pathbuf); 231 if (!pathname) /* ima_rdwr_violation possibly pre-fetched */
232 pathname = ima_d_path(&file->f_path, &pathbuf);
222 233
223 if (action & IMA_MEASURE) 234 if (action & IMA_MEASURE)
224 ima_store_measurement(iint, file, pathname, 235 ima_store_measurement(iint, file, pathname,
@@ -228,13 +239,15 @@ static int process_measurement(struct file *file, int mask, int function,
228 xattr_value, xattr_len, opened); 239 xattr_value, xattr_len, opened);
229 if (action & IMA_AUDIT) 240 if (action & IMA_AUDIT)
230 ima_audit_measurement(iint, pathname); 241 ima_audit_measurement(iint, pathname);
231 kfree(pathbuf); 242
232out_digsig: 243out_digsig:
233 if ((mask & MAY_WRITE) && (iint->flags & IMA_DIGSIG)) 244 if ((mask & MAY_WRITE) && (iint->flags & IMA_DIGSIG))
234 rc = -EACCES; 245 rc = -EACCES;
246 kfree(xattr_value);
247out_free:
248 kfree(pathbuf);
235out: 249out:
236 mutex_unlock(&inode->i_mutex); 250 mutex_unlock(&inode->i_mutex);
237 kfree(xattr_value);
238 if ((rc && must_appraise) && (ima_appraise & IMA_APPRAISE_ENFORCE)) 251 if ((rc && must_appraise) && (ima_appraise & IMA_APPRAISE_ENFORCE))
239 return -EACCES; 252 return -EACCES;
240 return 0; 253 return 0;
@@ -288,7 +301,6 @@ int ima_bprm_check(struct linux_binprm *bprm)
288 */ 301 */
289int ima_file_check(struct file *file, int mask, int opened) 302int ima_file_check(struct file *file, int mask, int opened)
290{ 303{
291 ima_rdwr_violation_check(file);
292 return process_measurement(file, 304 return process_measurement(file,
293 mask & (MAY_READ | MAY_WRITE | MAY_EXEC), 305 mask & (MAY_READ | MAY_WRITE | MAY_EXEC),
294 FILE_CHECK, opened); 306 FILE_CHECK, opened);