TF-M Reference Manual  1.2.0
TrustedFirmware-M
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
spm_psa_client_call.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2019-2020, Arm Limited. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  */
7 
8 #include "psa/service.h"
9 #include "spm_ipc.h"
10 #include "tfm_core_utils.h"
11 #include "tfm_internal_defines.h"
12 #include "tfm_memory_utils.h"
14 #include "utilities.h"
15 #include "tfm_wait.h"
16 #include "tfm_nspm.h"
17 
19 {
20  return PSA_FRAMEWORK_VERSION;
21 }
22 
23 uint32_t tfm_spm_client_psa_version(uint32_t sid, bool ns_caller)
24 {
25  struct tfm_spm_service_t *service;
26 
27  /*
28  * It should return PSA_VERSION_NONE if the RoT Service is not
29  * implemented.
30  */
31  service = tfm_spm_get_service_by_sid(sid);
32  if (!service) {
33  return PSA_VERSION_NONE;
34  }
35 
36  /*
37  * It should return PSA_VERSION_NONE if the caller is not authorized
38  * to access the RoT Service.
39  */
40  if (tfm_spm_check_authorization(sid, service, ns_caller) != IPC_SUCCESS) {
41  return PSA_VERSION_NONE;
42  }
43 
44  return service->service_db->version;
45 }
46 
47 psa_status_t tfm_spm_client_psa_connect(uint32_t sid, uint32_t version,
48  bool ns_caller)
49 {
50  struct tfm_spm_service_t *service;
51  struct tfm_msg_body_t *msg;
52  struct tfm_conn_handle_t *connect_handle;
53  int32_t client_id;
54  psa_handle_t handle;
55 
56  /* It is a fatal error if the RoT Service does not exist on the platform */
57  service = tfm_spm_get_service_by_sid(sid);
58  if (!service) {
60  }
61 
62  if (ns_caller) {
63  client_id = tfm_nspm_get_current_client_id();
64  } else {
66  }
67 
68  /*
69  * It is a fatal error if the caller is not authorized to access the RoT
70  * Service.
71  */
72  if (tfm_spm_check_authorization(sid, service, ns_caller) != IPC_SUCCESS) {
74  }
75 
76  /*
77  * Create connection handle here since it is possible to return the error
78  * code to client when creation fails.
79  */
80  connect_handle = tfm_spm_create_conn_handle(service, client_id);
81  if (!connect_handle) {
83  }
84 
85  /*
86  * It is a fatal error if the version of the RoT Service requested is not
87  * supported on the platform.
88  */
89  if (tfm_spm_check_client_version(service, version) != IPC_SUCCESS) {
91  }
92 
93  msg = tfm_spm_get_msg_buffer_from_conn_handle(connect_handle);
94  if (!msg) {
95  /* Have no enough resource to create message */
97  }
98 
99  handle = tfm_spm_to_user_handle(connect_handle);
100  /* No input or output needed for connect message */
101  tfm_spm_fill_msg(msg, service, handle, PSA_IPC_CONNECT,
102  client_id, NULL, 0, NULL, 0, NULL);
103 
104  /*
105  * Send message and wake up the SP who is waiting on message queue,
106  * and scheduler triggered
107  */
108  tfm_spm_send_event(service, msg);
109 
110  return PSA_SUCCESS;
111 }
112 
114  const psa_invec *inptr, size_t in_num,
115  psa_outvec *outptr, size_t out_num,
116  bool ns_caller, uint32_t privileged)
117 {
118  psa_invec invecs[PSA_MAX_IOVEC];
119  psa_outvec outvecs[PSA_MAX_IOVEC];
120  struct tfm_conn_handle_t *conn_handle;
121  struct tfm_spm_service_t *service;
122  struct tfm_msg_body_t *msg;
123  int i, j;
124  int32_t client_id;
125 
126  /* It is a fatal error if in_len + out_len > PSA_MAX_IOVEC. */
127  if ((in_num > PSA_MAX_IOVEC) ||
128  (out_num > PSA_MAX_IOVEC) ||
129  (in_num + out_num > PSA_MAX_IOVEC)) {
130  tfm_core_panic();
131  }
132 
133  if (ns_caller) {
134  client_id = tfm_nspm_get_current_client_id();
135  } else {
137  }
138 
139  conn_handle = tfm_spm_to_handle_instance(handle);
140  /* It is a fatal error if an invalid handle was passed. */
141  if (tfm_spm_validate_conn_handle(conn_handle, client_id) != IPC_SUCCESS) {
142  tfm_core_panic();
143  }
144  service = conn_handle->service;
145  if (!service) {
146  /* FixMe: Need to implement one mechanism to resolve this failure. */
147  tfm_core_panic();
148  }
149 
150  /* It is a fatal error if the connection is currently handling a request. */
151  if (conn_handle->status == TFM_HANDLE_STATUS_ACTIVE) {
152  tfm_core_panic();
153  }
154 
155  /*
156  * Return PSA_ERROR_PROGRAMMER_ERROR immediately for the connection
157  * has been terminated by the RoT Service.
158  */
159  if (conn_handle->status == TFM_HANDLE_STATUS_CONNECT_ERROR) {
161  }
162 
163  /*
164  * Read client invecs from the wrap input vector. It is a fatal error
165  * if the memory reference for the wrap input vector is invalid or not
166  * readable.
167  */
168  if (tfm_memory_check(inptr, in_num * sizeof(psa_invec), ns_caller,
169  TFM_MEMORY_ACCESS_RO, privileged) != IPC_SUCCESS) {
170  tfm_core_panic();
171  }
172 
173  /*
174  * Read client outvecs from the wrap output vector and will update the
175  * actual length later. It is a fatal error if the memory reference for
176  * the wrap output vector is invalid or not read-write.
177  */
178  if (tfm_memory_check(outptr, out_num * sizeof(psa_outvec), ns_caller,
179  TFM_MEMORY_ACCESS_RW, privileged) != IPC_SUCCESS) {
180  tfm_core_panic();
181  }
182 
183  spm_memset(invecs, 0, sizeof(invecs));
184  spm_memset(outvecs, 0, sizeof(outvecs));
185 
186  /* Copy the address out to avoid TOCTOU attacks. */
187  spm_memcpy(invecs, inptr, in_num * sizeof(psa_invec));
188  spm_memcpy(outvecs, outptr, out_num * sizeof(psa_outvec));
189 
190  /*
191  * For client input vector, it is a fatal error if the provided payload
192  * memory reference was invalid or not readable.
193  */
194  for (i = 0; i < in_num; i++) {
195  if (tfm_memory_check(invecs[i].base, invecs[i].len, ns_caller,
196  TFM_MEMORY_ACCESS_RO, privileged) != IPC_SUCCESS) {
197  tfm_core_panic();
198  }
199  }
200 
201  /*
202  * Clients must never overlap input parameters because of the risk of a
203  * double-fetch inconsistency.
204  * Overflow is checked in tfm_memory_check functions.
205  */
206  for (i = 0; i + 1 < in_num; i++) {
207  for (j = i+1; j < in_num; j++) {
208  if (!((char *) invecs[j].base + invecs[j].len <=
209  (char *) invecs[i].base ||
210  (char *) invecs[j].base >=
211  (char *) invecs[i].base + invecs[i].len)) {
212  tfm_core_panic();
213  }
214  }
215  }
216 
217  /*
218  * For client output vector, it is a fatal error if the provided payload
219  * memory reference was invalid or not read-write.
220  */
221  for (i = 0; i < out_num; i++) {
222  if (tfm_memory_check(outvecs[i].base, outvecs[i].len,
223  ns_caller, TFM_MEMORY_ACCESS_RW, privileged) != IPC_SUCCESS) {
224  tfm_core_panic();
225  }
226  }
227 
228  /*
229  * FixMe: Need to check if the message is unrecognized by the RoT
230  * Service or incorrectly formatted.
231  */
232  msg = tfm_spm_get_msg_buffer_from_conn_handle(conn_handle);
233  if (!msg) {
234  /* FixMe: Need to implement one mechanism to resolve this failure. */
235  tfm_core_panic();
236  }
237 
238  tfm_spm_fill_msg(msg, service, handle, type, client_id,
239  invecs, in_num, outvecs, out_num, outptr);
240 
241  /*
242  * Send message and wake up the SP who is waiting on message queue,
243  * and scheduler triggered
244  */
245  if (tfm_spm_send_event(service, msg) != IPC_SUCCESS) {
246  /* FixMe: Need to refine failure process here. */
247  tfm_core_panic();
248  }
249  return PSA_SUCCESS;
250 }
251 
252 void tfm_spm_client_psa_close(psa_handle_t handle, bool ns_caller)
253 {
254  struct tfm_spm_service_t *service;
255  struct tfm_msg_body_t *msg;
256  struct tfm_conn_handle_t *conn_handle;
257  int32_t client_id;
258 
259  /* It will have no effect if called with the NULL handle */
260  if (handle == PSA_NULL_HANDLE) {
261  return;
262  }
263 
264  if (ns_caller) {
265  client_id = tfm_nspm_get_current_client_id();
266  } else {
268  }
269 
270  conn_handle = tfm_spm_to_handle_instance(handle);
271  /*
272  * It is a fatal error if an invalid handle was provided that is not the
273  * null handle.
274  */
275  if (tfm_spm_validate_conn_handle(conn_handle, client_id) != IPC_SUCCESS) {
276  tfm_core_panic();
277  }
278  service = conn_handle->service;
279  if (!service) {
280  /* FixMe: Need to implement one mechanism to resolve this failure. */
281  tfm_core_panic();
282  }
283 
284  msg = tfm_spm_get_msg_buffer_from_conn_handle(conn_handle);
285  if (!msg) {
286  /* FixMe: Need to implement one mechanism to resolve this failure. */
287  tfm_core_panic();
288  }
289 
290  /* It is a fatal error if the connection is currently handling a request. */
291  if (conn_handle->status == TFM_HANDLE_STATUS_ACTIVE) {
292  tfm_core_panic();
293  }
294 
295  /* No input or output needed for close message */
296  tfm_spm_fill_msg(msg, service, handle, PSA_IPC_DISCONNECT, client_id,
297  NULL, 0, NULL, 0, NULL);
298 
299  /*
300  * Send message and wake up the SP who is waiting on message queue,
301  * and scheduler triggered
302  */
303  tfm_spm_send_event(service, msg);
304 }
#define PSA_ERROR_CONNECTION_BUSY
Definition: error.h:34
#define PSA_FRAMEWORK_VERSION
Definition: client.h:26
uint32_t tfm_spm_client_psa_framework_version(void)
handler for psa_framework_version.
#define TFM_HANDLE_STATUS_CONNECT_ERROR
Definition: spm_ipc.h:25
#define PSA_SUCCESS
Definition: crypto_values.h:35
#define TFM_HANDLE_STATUS_ACTIVE
Definition: spm_ipc.h:24
struct tfm_spm_service_t service[]
int32_t tfm_spm_check_authorization(uint32_t sid, struct tfm_spm_service_t *service, bool ns_caller)
Check the client access authorization.
Definition: spm_ipc.c:416
struct tfm_spm_service_t * service
Definition: spm_ipc.h:164
psa_status_t tfm_spm_client_psa_call(psa_handle_t handle, int32_t type, const psa_invec *inptr, size_t in_num, psa_outvec *outptr, size_t out_num, bool ns_caller, uint32_t privileged)
handler for psa_call.
int32_t tfm_spm_validate_conn_handle(const struct tfm_conn_handle_t *conn_handle, int32_t client_id)
Validate connection handle for client connect.
Definition: spm_ipc.c:161
void tfm_spm_client_psa_close(psa_handle_t handle, bool ns_caller)
handler for psa_close.
struct tfm_conn_handle_t * tfm_spm_create_conn_handle(struct tfm_spm_service_t *service, int32_t client_id)
Create connection handle for client connect.
Definition: spm_ipc.c:137
void tfm_core_panic(void)
Definition: utilities.c:11
int32_t tfm_memory_check(const void *buffer, size_t len, bool ns_caller, enum tfm_memory_access_e access, uint32_t privileged)
Check the memory reference is valid.
Definition: spm_ipc.c:596
#define PSA_MAX_IOVEC
Definition: client.h:54
psa_handle_t tfm_spm_to_user_handle(struct tfm_conn_handle_t *handle_instance)
Converts a handle instance into a corresponded user handle.
Definition: spm_ipc.c:93
#define PSA_IPC_DISCONNECT
Definition: service.h:47
int32_t tfm_nspm_get_current_client_id(void)
Get the client ID of the current NS client.
Definition: tfm_nspm_func.c:63
psa_msg_t msg
Definition: spm_ipc.h:63
void * spm_memcpy(void *dest, const void *src, size_t n)
Memory copy function for TF-M core.
void * spm_memset(void *s, int c, size_t n)
Memory set function for TF-M core.
#define PSA_ERROR_PROGRAMMER_ERROR
Definition: error.h:32
#define PSA_VERSION_NONE
Definition: client.h:32
#define PSA_NULL_HANDLE
Definition: client.h:38
struct tfm_msg_body_t * tfm_spm_get_msg_buffer_from_conn_handle(struct tfm_conn_handle_t *conn_handle)
Get message context by connect handle.
Definition: spm_ipc.c:491
int32_t tfm_spm_check_client_version(struct tfm_spm_service_t *service, uint32_t version)
Check the client version according to version policy.
Definition: spm_ipc.c:394
int32_t psa_handle_t
Definition: client.h:61
struct tfm_spm_service_t * tfm_spm_get_service_by_sid(uint32_t sid)
Get the service context by service ID.
Definition: spm_ipc.c:351
#define IPC_SUCCESS
#define PSA_IPC_CONNECT
Definition: service.h:45
uint32_t version
Definition: spm_ipc.h:132
psa_status_t tfm_spm_client_psa_connect(uint32_t sid, uint32_t version, bool ns_caller)
handler for psa_connect.
int32_t client_id
Definition: spm_ipc.h:157
uint32_t tfm_spm_client_psa_version(uint32_t sid, bool ns_caller)
handler for psa_version.
int32_t tfm_spm_send_event(struct tfm_spm_service_t *service, struct tfm_msg_body_t *msg)
Send message and wake up the SP who is waiting on message queue, block the current thread and schedul...
Definition: spm_ipc.c:556
const struct tfm_spm_service_db_t * service_db
Definition: spm_ipc.h:138
int32_t psa_status_t
Function return status.
Definition: crypto_types.h:43
struct tfm_conn_handle_t * tfm_spm_to_handle_instance(psa_handle_t user_handle)
Converts a user handle into a corresponded handle instance.
Definition: spm_ipc.c:121
uint32_t status
Definition: spm_ipc.h:150
void tfm_spm_fill_msg(struct tfm_msg_body_t *msg, struct tfm_spm_service_t *service, psa_handle_t handle, int32_t type, int32_t client_id, psa_invec *invec, size_t in_len, psa_outvec *outvec, size_t out_len, psa_outvec *caller_outvec)
Fill the message for PSA client call.
Definition: spm_ipc.c:498
uint32_t tfm_spm_partition_get_running_partition_id(void)
Get the running partition ID.
Definition: spm_ipc.c:584