1 // Copyright 2018 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "optee-message.h"
6
7 #include <ddk/debug.h>
8 #include <endian.h>
9 #include <limits>
10 #include <string.h>
11
12 namespace optee {
13
14 namespace {
15
16 // Converts a big endian UUID from a MessageParam value to a host endian TEEC_UUID.
17 // The fields of a UUID are stored in big endian in a MessageParam by the TEE and is thus why the
18 // parameter value cannot be directly reinterpreted as a UUID.
ConvertMessageParamToUuid(const MessageParam::Value & src,TEEC_UUID * dst)19 void ConvertMessageParamToUuid(const MessageParam::Value& src, TEEC_UUID* dst) {
20 // Convert TEEC_UUID fields from big endian to host endian
21 dst->timeLow = betoh32(src.uuid_big_endian.timeLow);
22 dst->timeMid = betoh16(src.uuid_big_endian.timeMid);
23 dst->timeHiAndVersion = betoh16(src.uuid_big_endian.timeHiAndVersion);
24
25 // Because clockSeqAndNode is uint8_t, no need to convert endianness - just memcpy
26 memcpy(dst->clockSeqAndNode,
27 src.uuid_big_endian.clockSeqAndNode,
28 sizeof(src.uuid_big_endian.clockSeqAndNode));
29 }
30
IsParameterInput(fuchsia_hardware_tee_Direction direction)31 constexpr bool IsParameterInput(fuchsia_hardware_tee_Direction direction) {
32 return (direction == fuchsia_hardware_tee_Direction_INPUT) ||
33 (direction == fuchsia_hardware_tee_Direction_INOUT);
34 }
35
IsParameterOutput(fuchsia_hardware_tee_Direction direction)36 constexpr bool IsParameterOutput(fuchsia_hardware_tee_Direction direction) {
37 return (direction == fuchsia_hardware_tee_Direction_OUTPUT) ||
38 (direction == fuchsia_hardware_tee_Direction_INOUT);
39 }
40
41 }; // namespace
42
TryInitializeParameters(size_t starting_param_index,const fuchsia_hardware_tee_ParameterSet & parameter_set,SharedMemoryManager::ClientMemoryPool * temp_memory_pool)43 bool Message::TryInitializeParameters(size_t starting_param_index,
44 const fuchsia_hardware_tee_ParameterSet& parameter_set,
45 SharedMemoryManager::ClientMemoryPool* temp_memory_pool) {
46 // If we don't have any parameters to parse, then we can just skip this
47 if (parameter_set.count == 0) {
48 return true;
49 }
50
51 bool is_valid = true;
52 for (size_t i = 0; i < parameter_set.count; i++) {
53 MessageParam& optee_param = params()[starting_param_index + i];
54 const fuchsia_hardware_tee_Parameter& zx_param = parameter_set.parameters[i];
55
56 switch (zx_param.tag) {
57 case fuchsia_hardware_tee_ParameterTag_none:
58 optee_param.attribute = MessageParam::kAttributeTypeNone;
59 break;
60 case fuchsia_hardware_tee_ParameterTag_value:
61 is_valid = TryInitializeValue(zx_param.value, &optee_param);
62 break;
63 case fuchsia_hardware_tee_ParameterTag_buffer:
64 is_valid = TryInitializeBuffer(zx_param.buffer, temp_memory_pool, &optee_param);
65 break;
66 default:
67 return false;
68 }
69
70 if (!is_valid) {
71 zxlogf(ERROR, "optee: failed to initialize parameters\n");
72 return false;
73 }
74 }
75
76 return true;
77 }
78
TryInitializeValue(const fuchsia_hardware_tee_Value & value,MessageParam * out_param)79 bool Message::TryInitializeValue(const fuchsia_hardware_tee_Value& value, MessageParam* out_param) {
80 ZX_DEBUG_ASSERT(out_param != nullptr);
81
82 switch (value.direction) {
83 case fuchsia_hardware_tee_Direction_INPUT:
84 out_param->attribute = MessageParam::kAttributeTypeValueInput;
85 break;
86 case fuchsia_hardware_tee_Direction_OUTPUT:
87 out_param->attribute = MessageParam::kAttributeTypeValueOutput;
88 break;
89 case fuchsia_hardware_tee_Direction_INOUT:
90 out_param->attribute = MessageParam::kAttributeTypeValueInOut;
91 break;
92 default:
93 return false;
94 }
95 out_param->payload.value.generic.a = value.a;
96 out_param->payload.value.generic.b = value.b;
97 out_param->payload.value.generic.c = value.c;
98
99 return true;
100 }
101
TryInitializeBuffer(const fuchsia_hardware_tee_Buffer & buffer,SharedMemoryManager::ClientMemoryPool * temp_memory_pool,MessageParam * out_param)102 bool Message::TryInitializeBuffer(const fuchsia_hardware_tee_Buffer& buffer,
103 SharedMemoryManager::ClientMemoryPool* temp_memory_pool,
104 MessageParam* out_param) {
105 ZX_DEBUG_ASSERT(temp_memory_pool != nullptr);
106 ZX_DEBUG_ASSERT(out_param != nullptr);
107
108 // Take ownership of the provided VMO. If we have to return early for any reason, this will
109 // take care of closing the VMO.
110 zx::vmo vmo(buffer.vmo);
111
112 MessageParam::AttributeType attribute;
113 switch (buffer.direction) {
114 case fuchsia_hardware_tee_Direction_INPUT:
115 attribute = MessageParam::kAttributeTypeTempMemInput;
116 break;
117 case fuchsia_hardware_tee_Direction_OUTPUT:
118 attribute = MessageParam::kAttributeTypeTempMemOutput;
119 break;
120 case fuchsia_hardware_tee_Direction_INOUT:
121 attribute = MessageParam::kAttributeTypeTempMemInOut;
122 break;
123 default:
124 return false;
125 }
126
127 // If an invalid VMO was provided, but the buffer is only an output, this is just a size check.
128 if (!vmo.is_valid()) {
129 if (IsParameterInput(buffer.direction)) {
130 return false;
131 } else {
132 // No need to allocate a temporary buffer from the shared memory pool,
133 out_param->attribute = attribute;
134 out_param->payload.temporary_memory.buffer = 0;
135 out_param->payload.temporary_memory.size = buffer.size;
136 out_param->payload.temporary_memory.shared_memory_reference = 0;
137 return true;
138 }
139 }
140
141 // For most buffer types, we must allocate a temporary shared memory buffer within the physical
142 // pool to share it with the TEE. We'll attach them to the Message object so that they can be
143 // looked up upon return from TEE and to tie the lifetimes of the Message and the temporary
144 // shared memory together.
145 SharedMemoryPtr shared_mem;
146 if (temp_memory_pool->Allocate(buffer.size, &shared_mem) != ZX_OK) {
147 zxlogf(ERROR, "optee: Failed to allocate temporary shared memory (%" PRIu64 ")\n",
148 buffer.size);
149 return false;
150 }
151
152 uint64_t paddr = static_cast<uint64_t>(shared_mem->paddr());
153
154 TemporarySharedMemory temp_shared_mem{std::move(vmo), buffer.offset, buffer.size,
155 std::move(shared_mem)};
156
157 // Input buffers should be copied into the shared memory buffer. Output only buffers can skip
158 // this step.
159 if (IsParameterInput(buffer.direction)) {
160 zx_status_t status = temp_shared_mem.SyncToSharedMemory();
161 if (status != ZX_OK) {
162 zxlogf(ERROR, "optee: shared memory sync failed (%d)\n", status);
163 return false;
164 }
165 }
166
167 allocated_temp_memory_.push_back(std::move(temp_shared_mem));
168 uint64_t index = static_cast<uint64_t>(allocated_temp_memory_.size()) - 1;
169
170 out_param->attribute = attribute;
171 out_param->payload.temporary_memory.buffer = paddr;
172 out_param->payload.temporary_memory.size = buffer.size;
173 out_param->payload.temporary_memory.shared_memory_reference = index;
174 return true;
175 }
176
177 zx_status_t
CreateOutputParameterSet(size_t starting_param_index,fuchsia_hardware_tee_ParameterSet * out_parameter_set)178 Message::CreateOutputParameterSet(size_t starting_param_index,
179 fuchsia_hardware_tee_ParameterSet* out_parameter_set) {
180 ZX_DEBUG_ASSERT(out_parameter_set != nullptr);
181
182 // Use a temporary parameter set to avoid populating the output until we're sure it's valid.
183 fuchsia_hardware_tee_ParameterSet parameter_set = {};
184
185 // Below code assumes that we can fit all of the parameters from optee into the FIDL parameter
186 // set. This static assert ensures that the FIDL parameter set can always fit the number of
187 // parameters into the count.
188 static_assert(fbl::count_of(parameter_set.parameters) <=
189 std::numeric_limits<decltype(parameter_set.count)>::max(),
190 "The size of the tee parameter set has outgrown the count");
191
192 if (header()->num_params < starting_param_index) {
193 zxlogf(ERROR, "optee: Message contained fewer parameters (%" PRIu32 ") than required %zd\n",
194 header()->num_params, starting_param_index);
195 return ZX_ERR_INVALID_ARGS;
196 }
197
198 // Ensure that the number of parameters returned by the TEE does not exceed the parameter set
199 // array of parameters.
200 const size_t count = header()->num_params - starting_param_index;
201 if (count > fbl::count_of(parameter_set.parameters)) {
202 zxlogf(ERROR, "optee: Message contained more parameters (%zd) than allowed\n", count);
203 return ZX_ERR_INVALID_ARGS;
204 }
205
206 parameter_set.count = static_cast<uint16_t>(count);
207 for (size_t i = starting_param_index; i < header()->num_params; i++) {
208 const MessageParam& optee_param = params()[i];
209 fuchsia_hardware_tee_Parameter& zx_param = parameter_set.parameters[i];
210
211 switch (optee_param.attribute) {
212 case MessageParam::kAttributeTypeNone:
213 zx_param.tag = fuchsia_hardware_tee_ParameterTag_none;
214 zx_param.none = {};
215 break;
216 case MessageParam::kAttributeTypeValueInput:
217 case MessageParam::kAttributeTypeValueOutput:
218 case MessageParam::kAttributeTypeValueInOut:
219 zx_param.tag = fuchsia_hardware_tee_ParameterTag_value;
220 zx_param.value = CreateOutputValueParameter(optee_param);
221 break;
222 case MessageParam::kAttributeTypeTempMemInput:
223 case MessageParam::kAttributeTypeTempMemOutput:
224 case MessageParam::kAttributeTypeTempMemInOut:
225 zx_param.tag = fuchsia_hardware_tee_ParameterTag_buffer;
226 if (zx_status_t status = CreateOutputBufferParameter(optee_param, &zx_param.buffer);
227 status != ZX_OK) {
228 return status;
229 }
230 break;
231 case MessageParam::kAttributeTypeRegMemInput:
232 case MessageParam::kAttributeTypeRegMemOutput:
233 case MessageParam::kAttributeTypeRegMemInOut:
234 default:
235 break;
236 }
237 }
238
239 *out_parameter_set = parameter_set;
240 return ZX_OK;
241 }
242
CreateOutputValueParameter(const MessageParam & optee_param)243 fuchsia_hardware_tee_Value Message::CreateOutputValueParameter(const MessageParam& optee_param) {
244 fuchsia_hardware_tee_Value zx_value = {};
245
246 switch (optee_param.attribute) {
247 case MessageParam::kAttributeTypeValueInput:
248 zx_value.direction = fuchsia_hardware_tee_Direction_INPUT;
249 break;
250 case MessageParam::kAttributeTypeValueOutput:
251 zx_value.direction = fuchsia_hardware_tee_Direction_OUTPUT;
252 break;
253 case MessageParam::kAttributeTypeValueInOut:
254 zx_value.direction = fuchsia_hardware_tee_Direction_INOUT;
255 break;
256 default:
257 ZX_PANIC("Invalid OP-TEE attribute specified\n");
258 }
259
260 const MessageParam::Value& optee_value = optee_param.payload.value;
261
262 if (IsParameterOutput(zx_value.direction)) {
263 zx_value.a = optee_value.generic.a;
264 zx_value.b = optee_value.generic.b;
265 zx_value.c = optee_value.generic.c;
266 }
267 return zx_value;
268 }
269
CreateOutputBufferParameter(const MessageParam & optee_param,fuchsia_hardware_tee_Buffer * out_buffer)270 zx_status_t Message::CreateOutputBufferParameter(const MessageParam& optee_param,
271 fuchsia_hardware_tee_Buffer* out_buffer) {
272 ZX_DEBUG_ASSERT(out_buffer != nullptr);
273
274 // Use a temporary buffer to avoid populating the output until we're sure it's valid.
275 fuchsia_hardware_tee_Buffer zx_buffer = {};
276
277 switch (optee_param.attribute) {
278 case MessageParam::kAttributeTypeTempMemInput:
279 zx_buffer.direction = fuchsia_hardware_tee_Direction_INPUT;
280 break;
281 case MessageParam::kAttributeTypeTempMemOutput:
282 zx_buffer.direction = fuchsia_hardware_tee_Direction_OUTPUT;
283 break;
284 case MessageParam::kAttributeTypeTempMemInOut:
285 zx_buffer.direction = fuchsia_hardware_tee_Direction_INOUT;
286 break;
287 default:
288 ZX_PANIC("Invalid OP-TEE attribute specified\n");
289 }
290
291 const MessageParam::TemporaryMemory& optee_temp_mem = optee_param.payload.temporary_memory;
292
293 zx_buffer.size = optee_temp_mem.size;
294
295 if (optee_temp_mem.buffer == 0) {
296 // If there was no buffer and this was just a size check, just return the size.
297 *out_buffer = zx_buffer;
298 return ZX_OK;
299 }
300
301 if (optee_temp_mem.shared_memory_reference >= allocated_temp_memory_.size()) {
302 zxlogf(ERROR, "optee: TEE returned an invalid shared_memory_reference (%" PRIu64 ")\n",
303 optee_temp_mem.shared_memory_reference);
304 return ZX_ERR_INVALID_ARGS;
305 }
306
307 auto& temp_shared_memory = allocated_temp_memory_[optee_temp_mem.shared_memory_reference];
308
309 if (!temp_shared_memory.is_valid()) {
310 zxlogf(ERROR, "optee: Invalid TemporarySharedMemory attempted to be used\n");
311 return ZX_ERR_INVALID_ARGS;
312 }
313
314 // For output buffers, we need to sync the shared memory buffer back to the VMO. It's possible
315 // that the returned size is smaller or larger than the originally provided buffer.
316 if (IsParameterOutput(zx_buffer.direction)) {
317 if (zx_status_t status = temp_shared_memory.SyncToVmo(zx_buffer.size); status != ZX_OK) {
318 zxlogf(ERROR, "optee: SharedMemory writeback to vmo failed (%d)\n", status);
319 return status;
320 }
321 }
322
323 zx_buffer.vmo = temp_shared_memory.ReleaseVmo();
324 zx_buffer.offset = temp_shared_memory.vmo_offset();
325
326 *out_buffer = zx_buffer;
327
328 return ZX_OK;
329 }
330
TemporarySharedMemory(zx::vmo vmo,uint64_t vmo_offset,size_t size,fbl::unique_ptr<SharedMemory> shared_memory)331 Message::TemporarySharedMemory::TemporarySharedMemory(zx::vmo vmo, uint64_t vmo_offset, size_t size,
332 fbl::unique_ptr<SharedMemory> shared_memory)
333 : vmo_(std::move(vmo)), vmo_offset_(vmo_offset), size_(size),
334 shared_memory_(std::move(shared_memory)) {}
335
SyncToSharedMemory()336 zx_status_t Message::TemporarySharedMemory::SyncToSharedMemory() {
337 ZX_DEBUG_ASSERT(is_valid());
338 return vmo_.read(reinterpret_cast<void*>(shared_memory_->vaddr()), vmo_offset_, size_);
339 }
340
SyncToVmo(size_t actual_size)341 zx_status_t Message::TemporarySharedMemory::SyncToVmo(size_t actual_size) {
342 ZX_DEBUG_ASSERT(is_valid());
343 // If the actual size of the data is larger than the size of the vmo, then we should skip the
344 // actual write. This is a valid scenario and the Trusted World will be responsible for
345 // providing the short buffer error code in it's result.
346 if (actual_size > size_) {
347 return ZX_OK;
348 }
349 return vmo_.write(reinterpret_cast<void*>(shared_memory_->vaddr()), vmo_offset_, actual_size);
350 }
351
ReleaseVmo()352 zx_handle_t Message::TemporarySharedMemory::ReleaseVmo() {
353 return vmo_.release();
354 }
355
OpenSessionMessage(SharedMemoryManager::DriverMemoryPool * message_pool,SharedMemoryManager::ClientMemoryPool * temp_memory_pool,const Uuid & trusted_app,const fuchsia_hardware_tee_ParameterSet & parameter_set)356 OpenSessionMessage::OpenSessionMessage(SharedMemoryManager::DriverMemoryPool* message_pool,
357 SharedMemoryManager::ClientMemoryPool* temp_memory_pool,
358 const Uuid& trusted_app,
359 const fuchsia_hardware_tee_ParameterSet& parameter_set) {
360 ZX_DEBUG_ASSERT(message_pool != nullptr);
361
362 const size_t num_params = parameter_set.count + kNumFixedOpenSessionParams;
363 ZX_DEBUG_ASSERT(num_params <= std::numeric_limits<uint32_t>::max());
364
365 zx_status_t status = message_pool->Allocate(CalculateSize(num_params), &memory_);
366
367 if (status != ZX_OK) {
368 memory_ = nullptr;
369 return;
370 }
371
372 header()->command = Command::kOpenSession;
373 header()->cancel_id = 0;
374 header()->num_params = static_cast<uint32_t>(num_params);
375
376 MessageParam& trusted_app_param = params()[kTrustedAppParamIndex];
377 MessageParam& client_app_param = params()[kClientAppParamIndex];
378
379 trusted_app_param.attribute = MessageParam::kAttributeTypeMeta |
380 MessageParam::kAttributeTypeValueInput;
381 trusted_app.ToUint64Pair(&trusted_app_param.payload.value.generic.a,
382 &trusted_app_param.payload.value.generic.b);
383
384 client_app_param.attribute = MessageParam::kAttributeTypeMeta |
385 MessageParam::kAttributeTypeValueInput;
386 // Not really any need to provide client app uuid, so just fill in with 0s
387 client_app_param.payload.value.generic.a = 0;
388 client_app_param.payload.value.generic.b = 0;
389 client_app_param.payload.value.generic.c = TEEC_LOGIN_PUBLIC;
390
391 // If we fail to initialize the parameters, then null out the message memory.
392 if (!TryInitializeParameters(kNumFixedOpenSessionParams, parameter_set, temp_memory_pool)) {
393 memory_ = nullptr;
394 }
395 }
396
CloseSessionMessage(SharedMemoryManager::DriverMemoryPool * message_pool,uint32_t session_id)397 CloseSessionMessage::CloseSessionMessage(SharedMemoryManager::DriverMemoryPool* message_pool,
398 uint32_t session_id) {
399 ZX_DEBUG_ASSERT(message_pool != nullptr);
400
401 zx_status_t status = message_pool->Allocate(CalculateSize(kNumParams), &memory_);
402
403 if (status != ZX_OK) {
404 memory_ = nullptr;
405 return;
406 }
407
408 header()->command = Command::kCloseSession;
409 header()->num_params = static_cast<uint32_t>(kNumParams);
410 header()->session_id = session_id;
411 }
412
InvokeCommandMessage(SharedMemoryManager::DriverMemoryPool * message_pool,SharedMemoryManager::ClientMemoryPool * temp_memory_pool,uint32_t session_id,uint32_t command_id,const fuchsia_hardware_tee_ParameterSet & parameter_set)413 InvokeCommandMessage::InvokeCommandMessage(SharedMemoryManager::DriverMemoryPool* message_pool,
414 SharedMemoryManager::ClientMemoryPool* temp_memory_pool,
415 uint32_t session_id, uint32_t command_id,
416 const fuchsia_hardware_tee_ParameterSet& parameter_set) {
417 ZX_DEBUG_ASSERT(message_pool != nullptr);
418
419 zx_status_t status = message_pool->Allocate(CalculateSize(parameter_set.count), &memory_);
420
421 if (status != ZX_OK) {
422 memory_ = nullptr;
423 return;
424 }
425
426 header()->command = Command::kInvokeCommand;
427 header()->session_id = session_id;
428 header()->app_function = command_id;
429 header()->cancel_id = 0;
430 header()->num_params = parameter_set.count;
431
432 if (!TryInitializeParameters(0, parameter_set, temp_memory_pool)) {
433 memory_ = nullptr;
434 }
435 }
436
TryInitializeMembers()437 bool RpcMessage::TryInitializeMembers() {
438 size_t memory_size = memory_->size();
439 if (memory_size < sizeof(MessageHeader)) {
440 zxlogf(ERROR,
441 "optee: shared memory region passed into RPC command could not be parsed into a "
442 "valid message!\n");
443 return false;
444 }
445
446 if (memory_size < CalculateSize(header()->num_params)) {
447 zxlogf(ERROR,
448 "optee: shared memory region passed into RPC command could not be parsed into a "
449 "valid message!\n");
450 // Can at least write error code to the header since that has been checked already
451 header()->return_origin = TEEC_ORIGIN_COMMS;
452 header()->return_code = TEEC_ERROR_BAD_PARAMETERS;
453 return false;
454 }
455
456 return true;
457 }
458
TryInitializeMembers()459 bool LoadTaRpcMessage::TryInitializeMembers() {
460 if (header()->num_params != kNumParams) {
461 zxlogf(ERROR,
462 "optee: RPC command to load trusted app received unexpected number of parameters!"
463 "\n");
464 set_return_origin(TEEC_ORIGIN_COMMS);
465 set_return_code(TEEC_ERROR_BAD_PARAMETERS);
466 return false;
467 }
468
469 // Parse the UUID of the trusted application from the parameters
470 MessageParam& uuid_param = params()[kUuidParamIndex];
471 switch (uuid_param.attribute) {
472 case MessageParam::kAttributeTypeValueInput:
473 case MessageParam::kAttributeTypeValueInOut:
474 ConvertMessageParamToUuid(uuid_param.payload.value, &ta_uuid_);
475 break;
476 default:
477 zxlogf(ERROR,
478 "optee: RPC command to load trusted app received unexpected first parameter!\n");
479 set_return_origin(TEEC_ORIGIN_COMMS);
480 set_return_code(TEEC_ERROR_BAD_PARAMETERS);
481 return false;
482 }
483
484 // Parse where in memory to write the trusted application
485 MessageParam& memory_reference_param = params()[kMemoryReferenceParamIndex];
486 switch (memory_reference_param.attribute) {
487 case MessageParam::kAttributeTypeTempMemOutput:
488 case MessageParam::kAttributeTypeTempMemInOut: {
489 MessageParam::TemporaryMemory& temp_mem = memory_reference_param.payload.temporary_memory;
490 mem_id_ = temp_mem.shared_memory_reference;
491 mem_size_ = static_cast<size_t>(temp_mem.size);
492 out_ta_size_ = &temp_mem.size;
493 // Temporary Memory References are owned by the TEE/TA and used only for the duration of
494 // this operation. Thus, it is sized exactly for the operation being performed and does not
495 // have an offset.
496 mem_offset_ = 0;
497 break;
498 }
499 case MessageParam::kAttributeTypeRegMemOutput:
500 case MessageParam::kAttributeTypeRegMemInOut:
501 zxlogf(ERROR,
502 "optee: received unsupported registered memory parameter!\n");
503 set_return_origin(TEEC_ORIGIN_COMMS);
504 set_return_code(TEEC_ERROR_NOT_IMPLEMENTED);
505 return false;
506 default:
507 zxlogf(ERROR,
508 "optee: RPC command to load trusted app received unexpected second parameter!\n");
509 set_return_origin(TEEC_ORIGIN_COMMS);
510 set_return_code(TEEC_ERROR_BAD_PARAMETERS);
511 return false;
512 }
513
514 if (mem_offset_ >= mem_size_ && mem_offset_ > 0) {
515 zxlogf(ERROR, "optee: RPC command received a memory offset out of bounds!\n");
516 set_return_origin(TEEC_ORIGIN_COMMS);
517 set_return_code(TEEC_ERROR_BAD_PARAMETERS);
518 return false;
519 }
520
521 return true;
522 }
523
TryInitializeMembers()524 bool AllocateMemoryRpcMessage::TryInitializeMembers() {
525 if (header()->num_params != kNumParams) {
526 zxlogf(ERROR,
527 "optee: RPC command to allocate shared memory received unexpected number of "
528 "parameters!\n");
529 set_return_origin(TEEC_ORIGIN_COMMS);
530 set_return_code(TEEC_ERROR_BAD_PARAMETERS);
531 return false;
532 }
533
534 // Parse the memory specifications parameter
535 MessageParam& value_param = params()[kMemorySpecsParamIndex];
536 if (value_param.attribute != MessageParam::kAttributeTypeValueInput) {
537 zxlogf(ERROR,
538 "optee: RPC command to allocate shared memory received unexpected first parameter!"
539 "\n");
540 set_return_origin(TEEC_ORIGIN_COMMS);
541 set_return_code(TEEC_ERROR_BAD_PARAMETERS);
542 return false;
543 }
544
545 auto& memory_specs_param = value_param.payload.value.allocate_memory_specs;
546
547 switch (memory_specs_param.memory_type) {
548 case SharedMemoryType::kApplication:
549 case SharedMemoryType::kKernel:
550 case SharedMemoryType::kGlobal:
551 memory_type_ = static_cast<SharedMemoryType>(memory_specs_param.memory_type);
552 break;
553 default:
554 zxlogf(ERROR,
555 "optee: received unknown memory type %" PRIu64 " to allocate\n",
556 memory_specs_param.memory_type);
557 set_return_code(TEEC_ERROR_BAD_PARAMETERS);
558 return false;
559 }
560
561 memory_size_ = static_cast<size_t>(memory_specs_param.memory_size);
562
563 // Set up the memory output parameter
564 MessageParam& out_param = params()[kOutputTemporaryMemoryParamIndex];
565 out_param.attribute = MessageParam::AttributeType::kAttributeTypeTempMemOutput;
566 MessageParam::TemporaryMemory& out_temp_mem_param = out_param.payload.temporary_memory;
567 out_memory_size_ = &out_temp_mem_param.size;
568 out_memory_buffer_ = &out_temp_mem_param.buffer;
569 out_memory_id_ = &out_temp_mem_param.shared_memory_reference;
570
571 return true;
572 }
573
TryInitializeMembers()574 bool FreeMemoryRpcMessage::TryInitializeMembers() {
575 if (header()->num_params != kNumParams) {
576 zxlogf(ERROR,
577 "optee: RPC command to free shared memory received unexpected number of parameters!"
578 "\n");
579 set_return_origin(TEEC_ORIGIN_COMMS);
580 set_return_code(TEEC_ERROR_BAD_PARAMETERS);
581 return false;
582 }
583
584 // Parse the memory specifications parameter
585 MessageParam& value_param = params()[kMemorySpecsParamIndex];
586 if (value_param.attribute != MessageParam::kAttributeTypeValueInput) {
587 zxlogf(ERROR,
588 "optee: RPC command to free shared memory received unexpected first parameter!"
589 "\n");
590 set_return_origin(TEEC_ORIGIN_COMMS);
591 set_return_code(TEEC_ERROR_BAD_PARAMETERS);
592 return false;
593 }
594
595 auto& memory_specs_param = value_param.payload.value.free_memory_specs;
596
597 switch (memory_specs_param.memory_type) {
598 case SharedMemoryType::kApplication:
599 case SharedMemoryType::kKernel:
600 case SharedMemoryType::kGlobal:
601 memory_type_ = static_cast<SharedMemoryType>(memory_specs_param.memory_type);
602 break;
603 default:
604 zxlogf(ERROR,
605 "optee: received unknown memory type %" PRIu64 " to free\n",
606 memory_specs_param.memory_type);
607 set_return_code(TEEC_ERROR_BAD_PARAMETERS);
608 return false;
609 }
610
611 memory_id_ = memory_specs_param.memory_id;
612 return true;
613 }
614
TryInitializeMembers()615 bool FileSystemRpcMessage::TryInitializeMembers() {
616 if (header()->num_params < kMinNumParams) {
617 zxlogf(ERROR,
618 "optee: RPC command to access file system received unexpected number of parameters!"
619 "\n");
620 set_return_origin(TEEC_ORIGIN_COMMS);
621 set_return_code(TEEC_ERROR_BAD_PARAMETERS);
622 return false;
623 }
624
625 // Parse the file system command parameter
626 MessageParam& command_param = params()[kFileSystemCommandParamIndex];
627 switch (command_param.attribute) {
628 case MessageParam::kAttributeTypeValueInput:
629 case MessageParam::kAttributeTypeValueInOut:
630 break;
631 default:
632 zxlogf(ERROR,
633 "optee: RPC command to access file system received unexpected first parameter!\n");
634 set_return_origin(TEEC_ORIGIN_COMMS);
635 set_return_code(TEEC_ERROR_BAD_PARAMETERS);
636 return false;
637 }
638
639 uint64_t command_num = command_param.payload.value.file_system_command.command_number;
640 if (command_num >= kNumFileSystemCommands) {
641 zxlogf(ERROR, "optee: received unknown file system command %" PRIu64 "\n", command_num);
642 set_return_code(TEEC_ERROR_NOT_SUPPORTED);
643 return false;
644 }
645
646 fs_command_ = static_cast<FileSystemCommand>(command_num);
647 return true;
648 }
649
650 } // namespace optee
651