Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/powerpc/platforms/pseries/papr-phy-attest.c
26481 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
3
#define pr_fmt(fmt) "papr-phy-attest: " fmt
4
5
#include <linux/build_bug.h>
6
#include <linux/file.h>
7
#include <linux/fs.h>
8
#include <linux/init.h>
9
#include <linux/lockdep.h>
10
#include <linux/kernel.h>
11
#include <linux/miscdevice.h>
12
#include <linux/signal.h>
13
#include <linux/slab.h>
14
#include <linux/string.h>
15
#include <linux/string_helpers.h>
16
#include <linux/uaccess.h>
17
#include <asm/machdep.h>
18
#include <asm/rtas-work-area.h>
19
#include <asm/rtas.h>
20
#include <uapi/asm/papr-physical-attestation.h>
21
#include "papr-rtas-common.h"
22
23
/**
24
* struct rtas_phy_attest_params - Parameters (in and out) for
25
* ibm,physical-attestation.
26
*
27
* @cmd: In: Caller-provided attestation command buffer. Must be
28
* RTAS-addressable.
29
* @work_area: In: Caller-provided work area buffer for attestation
30
* command structure
31
* Out: Caller-provided work area buffer for the response
32
* @cmd_len: In: Caller-provided attestation command structure
33
* length
34
* @sequence: In: Sequence number. Out: Next sequence number.
35
* @written: Out: Bytes written by ibm,physical-attestation to
36
* @work_area.
37
* @status: Out: RTAS call status.
38
*/
39
struct rtas_phy_attest_params {
40
struct papr_phy_attest_io_block cmd;
41
struct rtas_work_area *work_area;
42
u32 cmd_len;
43
u32 sequence;
44
u32 written;
45
s32 status;
46
};
47
48
/**
49
* rtas_physical_attestation() - Call ibm,physical-attestation to
50
* fill a work area buffer.
51
* @params: See &struct rtas_phy_attest_params.
52
*
53
* Calls ibm,physical-attestation until it errors or successfully
54
* deposits data into the supplied work area. Handles RTAS retry
55
* statuses. Maps RTAS error statuses to reasonable errno values.
56
*
57
* The caller is expected to invoke rtas_physical_attestation()
58
* multiple times to retrieve all the data for the provided
59
* attestation command. Only one sequence should be in progress at
60
* any time; starting a new sequence will disrupt any sequence
61
* already in progress. Serialization of attestation retrieval
62
* sequences is the responsibility of the caller.
63
*
64
* The caller should inspect @params.status to determine whether more
65
* calls are needed to complete the sequence.
66
*
67
* Context: May sleep.
68
* Return: -ve on error, 0 otherwise.
69
*/
70
static int rtas_physical_attestation(struct rtas_phy_attest_params *params)
71
{
72
struct rtas_work_area *work_area;
73
s32 fwrc, token;
74
u32 rets[2];
75
int ret;
76
77
work_area = params->work_area;
78
token = rtas_function_token(RTAS_FN_IBM_PHYSICAL_ATTESTATION);
79
if (token == RTAS_UNKNOWN_SERVICE)
80
return -ENOENT;
81
82
lockdep_assert_held(&rtas_ibm_physical_attestation_lock);
83
84
do {
85
fwrc = rtas_call(token, 3, 3, rets,
86
rtas_work_area_phys(work_area),
87
params->cmd_len,
88
params->sequence);
89
} while (rtas_busy_delay(fwrc));
90
91
switch (fwrc) {
92
case RTAS_HARDWARE_ERROR:
93
ret = -EIO;
94
break;
95
case RTAS_INVALID_PARAMETER:
96
ret = -EINVAL;
97
break;
98
case RTAS_SEQ_MORE_DATA:
99
params->sequence = rets[0];
100
fallthrough;
101
case RTAS_SEQ_COMPLETE:
102
params->written = rets[1];
103
/*
104
* Kernel or firmware bug, do not continue.
105
*/
106
if (WARN(params->written > rtas_work_area_size(work_area),
107
"possible write beyond end of work area"))
108
ret = -EFAULT;
109
else
110
ret = 0;
111
break;
112
default:
113
ret = -EIO;
114
pr_err_ratelimited("unexpected ibm,get-phy_attest status %d\n", fwrc);
115
break;
116
}
117
118
params->status = fwrc;
119
return ret;
120
}
121
122
/*
123
* Internal physical-attestation sequence APIs. A physical-attestation
124
* sequence is a series of calls to get ibm,physical-attestation
125
* for a given attestation command. The sequence ends when an error
126
* is encountered or all data for the attestation command has been
127
* returned.
128
*/
129
130
/**
131
* phy_attest_sequence_begin() - Begin a response data for attestation
132
* command retrieval sequence.
133
* @seq: user specified parameters for RTAS call from seq struct.
134
*
135
* Context: May sleep.
136
*/
137
static void phy_attest_sequence_begin(struct papr_rtas_sequence *seq)
138
{
139
struct rtas_phy_attest_params *param;
140
141
/*
142
* We could allocate the work area before acquiring the
143
* function lock, but that would allow concurrent requests to
144
* exhaust the limited work area pool for no benefit. So
145
* allocate the work area under the lock.
146
*/
147
mutex_lock(&rtas_ibm_physical_attestation_lock);
148
param = (struct rtas_phy_attest_params *)seq->params;
149
param->work_area = rtas_work_area_alloc(SZ_4K);
150
memcpy(rtas_work_area_raw_buf(param->work_area), &param->cmd,
151
param->cmd_len);
152
param->sequence = 1;
153
param->status = 0;
154
}
155
156
/**
157
* phy_attest_sequence_end() - Finalize a attestation command
158
* response retrieval sequence.
159
* @seq: Sequence state.
160
*
161
* Releases resources obtained by phy_attest_sequence_begin().
162
*/
163
static void phy_attest_sequence_end(struct papr_rtas_sequence *seq)
164
{
165
struct rtas_phy_attest_params *param;
166
167
param = (struct rtas_phy_attest_params *)seq->params;
168
rtas_work_area_free(param->work_area);
169
mutex_unlock(&rtas_ibm_physical_attestation_lock);
170
kfree(param);
171
}
172
173
/*
174
* Generator function to be passed to papr_rtas_blob_generate().
175
*/
176
static const char *phy_attest_sequence_fill_work_area(struct papr_rtas_sequence *seq,
177
size_t *len)
178
{
179
struct rtas_phy_attest_params *p;
180
bool init_state;
181
182
p = (struct rtas_phy_attest_params *)seq->params;
183
init_state = (p->written == 0) ? true : false;
184
185
if (papr_rtas_sequence_should_stop(seq, p->status, init_state))
186
return NULL;
187
if (papr_rtas_sequence_set_err(seq, rtas_physical_attestation(p)))
188
return NULL;
189
*len = p->written;
190
return rtas_work_area_raw_buf(p->work_area);
191
}
192
193
static const struct file_operations papr_phy_attest_handle_ops = {
194
.read = papr_rtas_common_handle_read,
195
.llseek = papr_rtas_common_handle_seek,
196
.release = papr_rtas_common_handle_release,
197
};
198
199
/**
200
* papr_phy_attest_create_handle() - Create a fd-based handle for
201
* reading the response for the given attestation command.
202
* @ulc: Attestation command in user memory; defines the scope of
203
* data for the attestation command to retrieve.
204
*
205
* Handler for PAPR_PHYSICAL_ATTESTATION_IOC_CREATE_HANDLE ioctl
206
* command. Validates @ulc and instantiates an immutable response
207
* "blob" for attestation command. The blob is attached to a file
208
* descriptor for reading by user space. The memory backing the blob
209
* is freed when the file is released.
210
*
211
* The entire requested response buffer for the attestation command
212
* retrieved by this call and all necessary RTAS interactions are
213
* performed before returning the fd to user space. This keeps the
214
* read handler simple and ensures that kernel can prevent
215
* interleaving ibm,physical-attestation call sequences.
216
*
217
* Return: The installed fd number if successful, -ve errno otherwise.
218
*/
219
static long papr_phy_attest_create_handle(struct papr_phy_attest_io_block __user *ulc)
220
{
221
struct rtas_phy_attest_params *params;
222
struct papr_rtas_sequence seq = {};
223
int fd;
224
225
/*
226
* Freed in phy_attest_sequence_end().
227
*/
228
params = kzalloc(sizeof(*params), GFP_KERNEL_ACCOUNT);
229
if (!params)
230
return -ENOMEM;
231
232
if (copy_from_user(&params->cmd, ulc,
233
sizeof(struct papr_phy_attest_io_block)))
234
return -EFAULT;
235
236
params->cmd_len = be32_to_cpu(params->cmd.length);
237
seq = (struct papr_rtas_sequence) {
238
.begin = phy_attest_sequence_begin,
239
.end = phy_attest_sequence_end,
240
.work = phy_attest_sequence_fill_work_area,
241
};
242
243
seq.params = (void *)params;
244
245
fd = papr_rtas_setup_file_interface(&seq,
246
&papr_phy_attest_handle_ops,
247
"[papr-physical-attestation]");
248
249
return fd;
250
}
251
252
/*
253
* Top-level ioctl handler for /dev/papr-physical-attestation.
254
*/
255
static long papr_phy_attest_dev_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg)
256
{
257
void __user *argp = (__force void __user *)arg;
258
long ret;
259
260
switch (ioctl) {
261
case PAPR_PHY_ATTEST_IOC_HANDLE:
262
ret = papr_phy_attest_create_handle(argp);
263
break;
264
default:
265
ret = -ENOIOCTLCMD;
266
break;
267
}
268
return ret;
269
}
270
271
static const struct file_operations papr_phy_attest_ops = {
272
.unlocked_ioctl = papr_phy_attest_dev_ioctl,
273
};
274
275
static struct miscdevice papr_phy_attest_dev = {
276
.minor = MISC_DYNAMIC_MINOR,
277
.name = "papr-physical-attestation",
278
.fops = &papr_phy_attest_ops,
279
};
280
281
static __init int papr_phy_attest_init(void)
282
{
283
if (!rtas_function_implemented(RTAS_FN_IBM_PHYSICAL_ATTESTATION))
284
return -ENODEV;
285
286
return misc_register(&papr_phy_attest_dev);
287
}
288
machine_device_initcall(pseries, papr_phy_attest_init);
289
290