diff options
author | Kent Yoder <key@linux.vnet.ibm.com> | 2012-07-25 15:14:02 -0400 |
---|---|---|
committer | Kent Yoder <key@linux.vnet.ibm.com> | 2012-08-22 12:11:49 -0400 |
commit | dd7da132f7f04f34074efd134847a818ea29ddd7 (patch) | |
tree | 79448a7b8ccfb8531fbec1f241a853b2b911baa9 /drivers/char/tpm | |
parent | 578b016fdc91464c08c096f0c5952cae549fdb8f (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.c | 5 |
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 | } |
1243 | EXPORT_SYMBOL_GPL(tpm_read); | 1244 | EXPORT_SYMBOL_GPL(tpm_read); |