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