SPM: Implement version check for stateless service

Encode the service version and stateless indicator into
stateless handle, validate the stateless handle indicator,
version and index before using.

Change-Id: Id5f388f938a758803863958dfbb0c0011c2e1f04
Signed-off-by: Mingyang Sun <mingyang.sun@arm.com>
diff --git a/interface/include/psa_manifest/sid.h.template b/interface/include/psa_manifest/sid.h.template
index bc478a5..e188d62 100644
--- a/interface/include/psa_manifest/sid.h.template
+++ b/interface/include/psa_manifest/sid.h.template
@@ -29,7 +29,7 @@
                 {% endif %}
                 {% if partition.manifest.psa_framework_version > 1.0 and service.connection_based == false %}
                     {% set str = service.name + "_HANDLE" %}
-#define {{"%-58s"|format(str)}} ({{"%d"|format(service.stateless_handle)}}U)
+#define {{"%-58s"|format(str)}} ({{"%s"|format(service.stateless_handle)}}U)
                 {% endif %}
             {% endfor %}
         {% endif %}
diff --git a/secure_fw/spm/cmsis_psa/spm_ipc.c b/secure_fw/spm/cmsis_psa/spm_ipc.c
index 0a32695..3c20fed 100644
--- a/secure_fw/spm/cmsis_psa/spm_ipc.c
+++ b/secure_fw/spm/cmsis_psa/spm_ipc.c
@@ -753,14 +753,14 @@
 
         /* Populate the p_service of stateless_service_ref[] */
         if (service_db[i].connection_based == false) {
-            for (j = 0; j < STATIC_HANDLE_VALUE_LIMIT; j++) {
+            for (j = 0; j < STATIC_HANDLE_NUM_LIMIT; j++) {
                 if (stateless_service_ref[j].sid == service_db[i].sid) {
                     stateless_service_ref[j].p_service = &service[i];
                     break;
                 }
             }
             /* Stateless service not found in tracking table */
-            if (j >= STATIC_HANDLE_VALUE_LIMIT) {
+            if (j >= STATIC_HANDLE_NUM_LIMIT) {
                 tfm_core_panic();
             }
         }
diff --git a/secure_fw/spm/cmsis_psa/spm_ipc.h b/secure_fw/spm/cmsis_psa/spm_ipc.h
index dd02911..dc0fd1f 100644
--- a/secure_fw/spm/cmsis_psa/spm_ipc.h
+++ b/secure_fw/spm/cmsis_psa/spm_ipc.h
@@ -29,11 +29,34 @@
 
 #define TFM_CONN_HANDLE_MAX_NUM         16
 
-/* Set a minimum for client handle. Reserve small values for static handle. */
-#define STATIC_HANDLE_VALUE_LIMIT       32
-#define CLIENT_HANDLE_VALUE_MIN         (STATIC_HANDLE_VALUE_LIMIT + 1)
-#define IS_STATIC_HANDLE(h)             ((h) > 0 && \
-                                         (h) <= STATIC_HANDLE_VALUE_LIMIT)
+/*
+ * Set a number limit for stateless handle.
+ * Valid handle must be positive, set client handle minimum value to 1.
+ */
+#define STATIC_HANDLE_NUM_LIMIT         32
+#define CLIENT_HANDLE_VALUE_MIN         1
+
+#define STAIC_HANDLE_IDX_BIT_WIDTH      8
+#define STAIC_HANDLE_IDX_MASK \
+    (uint32_t)((1UL << STAIC_HANDLE_IDX_BIT_WIDTH) - 1)
+#define GET_INDEX_FROM_STATIC_HANDLE(handle) \
+    (uint32_t)(((handle) & STAIC_HANDLE_IDX_MASK) - 1)
+
+#define STAIC_HANDLE_VER_BIT_WIDTH      8
+#define STAIC_HANDLE_VER_OFFSET         8
+#define STAIC_HANDLE_VER_MASK \
+    (uint32_t)((1UL << STAIC_HANDLE_VER_BIT_WIDTH) - 1)
+#define GET_VERSION_FROM_STATIC_HANDLE(handle) \
+    (uint32_t)(((handle) >> STAIC_HANDLE_VER_OFFSET) & STAIC_HANDLE_VER_MASK)
+
+#define STAIC_HANDLE_INDICATOR_OFFSET   30
+/*
+ * A valid static handle must have indicator bit set, have a positive index,
+ * 1 <= index <= STATIC_HANDLE_NUM_LIMIT.
+ */
+#define IS_VALID_STATIC_HANDLE(handle)                      \
+    (((handle) & (1UL << STAIC_HANDLE_INDICATOR_OFFSET)) && \
+     (GET_INDEX_FROM_STATIC_HANDLE(handle) < STATIC_HANDLE_NUM_LIMIT))
 
 #define SPM_INVALID_PARTITION_IDX     (~0U)
 
diff --git a/secure_fw/spm/ffm/spm_psa_client_call.c b/secure_fw/spm/ffm/spm_psa_client_call.c
index 6fbc346..28f5987 100644
--- a/secure_fw/spm/ffm/spm_psa_client_call.c
+++ b/secure_fw/spm/ffm/spm_psa_client_call.c
@@ -15,6 +15,9 @@
 #include "tfm_nspm.h"
 #include "ffm/spm_error_base.h"
 
+#define GET_STATELESS_SERVICE(index)    (stateless_service_ref[index].p_service)
+#define GET_STATELESS_SID(index)        (stateless_service_ref[index].sid)
+
 extern struct stateless_service_tracking_t stateless_service_ref[];
 
 uint32_t tfm_spm_client_psa_framework_version(void)
@@ -132,7 +135,7 @@
     struct tfm_msg_body_t *msg;
     int i, j;
     int32_t client_id;
-    uint32_t sid;
+    uint32_t sid, version, index;
 
     /* It is a PROGRAMMER ERROR if in_len + out_len > PSA_MAX_IOVEC. */
     if ((in_num > PSA_MAX_IOVEC) ||
@@ -148,9 +151,11 @@
     }
 
     /* Allocate space from handle pool for static handle. */
-    if (IS_STATIC_HANDLE(handle)) {
-        service = stateless_service_ref[(uint32_t)handle-1].p_service;
-        sid = stateless_service_ref[(uint32_t)handle-1].sid;
+    if (IS_VALID_STATIC_HANDLE(handle)) {
+        index = GET_INDEX_FROM_STATIC_HANDLE(handle);
+        service = GET_STATELESS_SERVICE(index);
+        sid = GET_STATELESS_SID(index);
+
         /*
          * It is a PROGRAMMER ERROR if the caller is not authorized to access
          * the RoT Service.
@@ -160,6 +165,12 @@
             TFM_PROGRAMMER_ERROR(ns_caller, PSA_ERROR_CONNECTION_REFUSED);
         }
 
+        version = GET_VERSION_FROM_STATIC_HANDLE(handle);
+
+        if (tfm_spm_check_client_version(service, version) != SPM_SUCCESS) {
+            TFM_PROGRAMMER_ERROR(ns_caller, PSA_ERROR_PROGRAMMER_ERROR);
+        }
+
         conn_handle = tfm_spm_create_conn_handle(service, client_id);
 
         if (!conn_handle) {
@@ -301,7 +312,7 @@
     }
 
     /* It is a PROGRAMMER ERROR if called with a stateless handle. */
-    if (IS_STATIC_HANDLE(handle)) {
+    if (IS_VALID_STATIC_HANDLE(handle)) {
         TFM_PROGRAMMER_ERROR(ns_caller, PROGRAMMER_ERROR_NULL);
     }
 
diff --git a/tools/tfm_parse_manifest_list.py b/tools/tfm_parse_manifest_list.py
index d4a0d80..cfc6bfc 100644
--- a/tools/tfm_parse_manifest_list.py
+++ b/tools/tfm_parse_manifest_list.py
@@ -231,12 +231,23 @@
 
     # Auto-allocate stateless handle
     for i in range(0, static_handle_max_num):
-        if reordered_stateless_list[i] == None:
+        if reordered_stateless_list[i] == None and len(stateless_services) > 0:
             service = stateless_services.pop(0)
             service['stateless_handle'] = i + 1
             reordered_stateless_list[i] = service
-        if len(stateless_services) == 0:
-            break
+        """
+        Encode stateless flag and version into stateless handle
+        bit 30: stateless handle indicator
+        bit 15-8: stateless service version
+        bit 7-0: stateless handle index
+        """
+        if reordered_stateless_list[i] != None:
+            stateless_handle_value = reordered_stateless_list[i]['stateless_handle']
+            stateless_flag = 1 << 30
+            stateless_handle_value |= stateless_flag
+            stateless_version = (reordered_stateless_list[i]['version'] & 0xFF) << 8
+            stateless_handle_value |= stateless_version
+            reordered_stateless_list[i]['stateless_handle'] = '0x%08x' % stateless_handle_value
 
     return reordered_stateless_list