]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blame - drivers/char/tpm/tpm-dev-common.c
tpm: access command header through struct in tpm_try_transmit()
[mirror_ubuntu-jammy-kernel.git] / drivers / char / tpm / tpm-dev-common.c
CommitLineData
ecb38e2f
JB
1/*
2 * Copyright (C) 2004 IBM Corporation
3 * Authors:
4 * Leendert van Doorn <leendert@watson.ibm.com>
5 * Dave Safford <safford@watson.ibm.com>
6 * Reiner Sailer <sailer@watson.ibm.com>
7 * Kylene Hall <kjhall@us.ibm.com>
8 *
9 * Copyright (C) 2013 Obsidian Research Corp
10 * Jason Gunthorpe <jgunthorpe@obsidianresearch.com>
11 *
12 * Device file system interface to the TPM
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License as
16 * published by the Free Software Foundation, version 2 of the
17 * License.
18 *
19 */
9e1b74a6 20#include <linux/poll.h>
ecb38e2f
JB
21#include <linux/slab.h>
22#include <linux/uaccess.h>
9e1b74a6 23#include <linux/workqueue.h>
ecb38e2f
JB
24#include "tpm.h"
25#include "tpm-dev.h"
26
9e1b74a6
TS
27static struct workqueue_struct *tpm_dev_wq;
28static DEFINE_MUTEX(tpm_dev_wq_lock);
29
30static void tpm_async_work(struct work_struct *work)
31{
32 struct file_priv *priv =
33 container_of(work, struct file_priv, async_work);
34 ssize_t ret;
35
36 mutex_lock(&priv->buffer_mutex);
37 priv->command_enqueued = false;
38 ret = tpm_transmit(priv->chip, priv->space, priv->data_buffer,
39 sizeof(priv->data_buffer), 0);
40
41 tpm_put_ops(priv->chip);
42 if (ret > 0) {
9488585b 43 priv->response_length = ret;
9e1b74a6
TS
44 mod_timer(&priv->user_read_timer, jiffies + (120 * HZ));
45 }
46 mutex_unlock(&priv->buffer_mutex);
47 wake_up_interruptible(&priv->async_wait);
48}
49
e99e88a9 50static void user_reader_timeout(struct timer_list *t)
ecb38e2f 51{
e99e88a9 52 struct file_priv *priv = from_timer(priv, t, user_read_timer);
ecb38e2f
JB
53
54 pr_warn("TPM user space timeout is deprecated (pid=%d)\n",
55 task_tgid_nr(current));
56
9e1b74a6 57 schedule_work(&priv->timeout_work);
ecb38e2f
JB
58}
59
9e1b74a6 60static void tpm_timeout_work(struct work_struct *work)
ecb38e2f 61{
9e1b74a6
TS
62 struct file_priv *priv = container_of(work, struct file_priv,
63 timeout_work);
ecb38e2f
JB
64
65 mutex_lock(&priv->buffer_mutex);
9488585b
TS
66 priv->response_read = true;
67 priv->response_length = 0;
ecb38e2f
JB
68 memset(priv->data_buffer, 0, sizeof(priv->data_buffer));
69 mutex_unlock(&priv->buffer_mutex);
9e1b74a6 70 wake_up_interruptible(&priv->async_wait);
ecb38e2f
JB
71}
72
73void tpm_common_open(struct file *file, struct tpm_chip *chip,
c3d477a7 74 struct file_priv *priv, struct tpm_space *space)
ecb38e2f
JB
75{
76 priv->chip = chip;
c3d477a7 77 priv->space = space;
9488585b 78 priv->response_read = true;
c3d477a7 79
ecb38e2f 80 mutex_init(&priv->buffer_mutex);
e99e88a9 81 timer_setup(&priv->user_read_timer, user_reader_timeout, 0);
9e1b74a6
TS
82 INIT_WORK(&priv->timeout_work, tpm_timeout_work);
83 INIT_WORK(&priv->async_work, tpm_async_work);
84 init_waitqueue_head(&priv->async_wait);
ecb38e2f
JB
85 file->private_data = priv;
86}
87
88ssize_t tpm_common_read(struct file *file, char __user *buf,
89 size_t size, loff_t *off)
90{
91 struct file_priv *priv = file->private_data;
3ab2011e 92 ssize_t ret_size = 0;
ecb38e2f
JB
93 int rc;
94
3ab2011e 95 mutex_lock(&priv->buffer_mutex);
ecb38e2f 96
9488585b
TS
97 if (priv->response_length) {
98 priv->response_read = true;
99
100 ret_size = min_t(ssize_t, size, priv->response_length);
101 if (!ret_size) {
102 priv->response_length = 0;
103 goto out;
9e1b74a6 104 }
ecb38e2f 105
9488585b
TS
106 rc = copy_to_user(buf, priv->data_buffer + *off, ret_size);
107 if (rc) {
108 memset(priv->data_buffer, 0, TPM_BUFSIZE);
109 priv->response_length = 0;
110 ret_size = -EFAULT;
111 } else {
112 memset(priv->data_buffer + *off, 0, ret_size);
113 priv->response_length -= ret_size;
114 *off += ret_size;
115 }
ecb38e2f
JB
116 }
117
9488585b
TS
118out:
119 if (!priv->response_length) {
120 *off = 0;
121 del_singleshot_timer_sync(&priv->user_read_timer);
122 flush_work(&priv->timeout_work);
123 }
3ab2011e 124 mutex_unlock(&priv->buffer_mutex);
ecb38e2f
JB
125 return ret_size;
126}
127
128ssize_t tpm_common_write(struct file *file, const char __user *buf,
c3d477a7 129 size_t size, loff_t *off)
ecb38e2f
JB
130{
131 struct file_priv *priv = file->private_data;
9e1b74a6 132 int ret = 0;
ecb38e2f 133
9e1b74a6 134 if (size > TPM_BUFSIZE)
3ab2011e
TS
135 return -E2BIG;
136
137 mutex_lock(&priv->buffer_mutex);
138
ecb38e2f
JB
139 /* Cannot perform a write until the read has cleared either via
140 * tpm_read or a user_read_timer timeout. This also prevents split
141 * buffered writes from blocking here.
142 */
9488585b
TS
143 if ((!priv->response_read && priv->response_length) ||
144 priv->command_enqueued) {
9e1b74a6
TS
145 ret = -EBUSY;
146 goto out;
3ab2011e 147 }
ecb38e2f 148
9e1b74a6
TS
149 if (copy_from_user(priv->data_buffer, buf, size)) {
150 ret = -EFAULT;
151 goto out;
ecb38e2f
JB
152 }
153
9e1b74a6
TS
154 if (size < 6 ||
155 size < be32_to_cpu(*((__be32 *)(priv->data_buffer + 2)))) {
156 ret = -EINVAL;
157 goto out;
ee70bc1e
AS
158 }
159
ecb38e2f
JB
160 /* atomic tpm command send and result receive. We only hold the ops
161 * lock during this period so that the tpm can be unregistered even if
162 * the char dev is held open.
163 */
164 if (tpm_try_get_ops(priv->chip)) {
9e1b74a6
TS
165 ret = -EPIPE;
166 goto out;
ecb38e2f 167 }
ecb38e2f 168
9488585b
TS
169 priv->response_length = 0;
170 priv->response_read = false;
171 *off = 0;
172
9e1b74a6
TS
173 /*
174 * If in nonblocking mode schedule an async job to send
175 * the command return the size.
176 * In case of error the err code will be returned in
177 * the subsequent read call.
178 */
179 if (file->f_flags & O_NONBLOCK) {
180 priv->command_enqueued = true;
181 queue_work(tpm_dev_wq, &priv->async_work);
ecb38e2f 182 mutex_unlock(&priv->buffer_mutex);
9e1b74a6 183 return size;
ecb38e2f
JB
184 }
185
9e1b74a6
TS
186 ret = tpm_transmit(priv->chip, priv->space, priv->data_buffer,
187 sizeof(priv->data_buffer), 0);
188 tpm_put_ops(priv->chip);
189
190 if (ret > 0) {
9488585b 191 priv->response_length = ret;
9e1b74a6
TS
192 mod_timer(&priv->user_read_timer, jiffies + (120 * HZ));
193 ret = size;
194 }
195out:
ecb38e2f 196 mutex_unlock(&priv->buffer_mutex);
9e1b74a6
TS
197 return ret;
198}
199
200__poll_t tpm_common_poll(struct file *file, poll_table *wait)
201{
202 struct file_priv *priv = file->private_data;
203 __poll_t mask = 0;
204
205 poll_wait(file, &priv->async_wait, wait);
ecb38e2f 206
9488585b 207 if (!priv->response_read || priv->response_length)
9e1b74a6
TS
208 mask = EPOLLIN | EPOLLRDNORM;
209 else
210 mask = EPOLLOUT | EPOLLWRNORM;
ecb38e2f 211
9e1b74a6 212 return mask;
ecb38e2f
JB
213}
214
215/*
216 * Called on file close
217 */
218void tpm_common_release(struct file *file, struct file_priv *priv)
219{
9e1b74a6 220 flush_work(&priv->async_work);
ecb38e2f 221 del_singleshot_timer_sync(&priv->user_read_timer);
9e1b74a6 222 flush_work(&priv->timeout_work);
ecb38e2f 223 file->private_data = NULL;
9488585b 224 priv->response_length = 0;
ecb38e2f 225}
9e1b74a6
TS
226
227int __init tpm_dev_common_init(void)
228{
229 tpm_dev_wq = alloc_workqueue("tpm_dev_wq", WQ_MEM_RECLAIM, 0);
230
231 return !tpm_dev_wq ? -ENOMEM : 0;
232}
233
234void __exit tpm_dev_common_exit(void)
235{
236 if (tpm_dev_wq) {
237 destroy_workqueue(tpm_dev_wq);
238 tpm_dev_wq = NULL;
239 }
240}