aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/tpm
diff options
context:
space:
mode:
authorKent Yoder <key@linux.vnet.ibm.com>2012-07-25 15:14:02 -0400
committerKent Yoder <key@linux.vnet.ibm.com>2012-08-22 12:11:49 -0400
commitdd7da132f7f04f34074efd134847a818ea29ddd7 (patch)
tree79448a7b8ccfb8531fbec1f241a853b2b911baa9 /drivers/char/tpm
parent578b016fdc91464c08c096f0c5952cae549fdb8f (diff)
tpm: fix double write race and tpm_release free issue
Moved the atomic_set of the data_pending variable until after the tpm_read has completed processing. The existing code had a window of time where a second write to the driver could clobber the tpm command buffer. Also fixed an issue where if close was called on the tpm device before a read completed, the tpm command buffer would be returned to the OS, which could contain sensitive information. Signed-off-by: Kent Yoder <key@linux.vnet.ibm.com>
Diffstat (limited to 'drivers/char/tpm')
-rw-r--r--drivers/char/tpm/tpm.c5
1 files changed, 3 insertions, 2 deletions
diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c
index 36e43e50dcef..0a75638e3e56 100644
--- a/drivers/char/tpm/tpm.c
+++ b/drivers/char/tpm/tpm.c
@@ -1171,7 +1171,7 @@ int tpm_release(struct inode *inode, struct file *file)
1171 flush_work_sync(&chip->work); 1171 flush_work_sync(&chip->work);
1172 file->private_data = NULL; 1172 file->private_data = NULL;
1173 atomic_set(&chip->data_pending, 0); 1173 atomic_set(&chip->data_pending, 0);
1174 kfree(chip->data_buffer); 1174 kzfree(chip->data_buffer);
1175 clear_bit(0, &chip->is_open); 1175 clear_bit(0, &chip->is_open);
1176 put_device(chip->dev); 1176 put_device(chip->dev);
1177 return 0; 1177 return 0;
@@ -1223,7 +1223,6 @@ ssize_t tpm_read(struct file *file, char __user *buf,
1223 del_singleshot_timer_sync(&chip->user_read_timer); 1223 del_singleshot_timer_sync(&chip->user_read_timer);
1224 flush_work_sync(&chip->work); 1224 flush_work_sync(&chip->work);
1225 ret_size = atomic_read(&chip->data_pending); 1225 ret_size = atomic_read(&chip->data_pending);
1226 atomic_set(&chip->data_pending, 0);
1227 if (ret_size > 0) { /* relay data */ 1226 if (ret_size > 0) { /* relay data */
1228 ssize_t orig_ret_size = ret_size; 1227 ssize_t orig_ret_size = ret_size;
1229 if (size < ret_size) 1228 if (size < ret_size)
@@ -1238,6 +1237,8 @@ ssize_t tpm_read(struct file *file, char __user *buf,
1238 mutex_unlock(&chip->buffer_mutex); 1237 mutex_unlock(&chip->buffer_mutex);
1239 } 1238 }
1240 1239
1240 atomic_set(&chip->data_pending, 0);
1241
1241 return ret_size; 1242 return ret_size;
1242} 1243}
1243EXPORT_SYMBOL_GPL(tpm_read); 1244EXPORT_SYMBOL_GPL(tpm_read);