Add functions to read and write AVB_ATX permanent attributes

Trusty's AVB service can store permanent attributes in RPMB, and will
only allow the values to be written once. This patch enables reading and
writing permanent attributes by calling into Trusty. If RPMB is used to
store permanent attributes, they MUST be verified against write-once
hardware.

avb_do_tipc is refactored and documented.

Bug: 33051168
Test: manual test on imx6ul
Change-Id: If52762dc710e1e0265d7de508c6c1daaf62b7f0d
diff --git a/interface/include/interface/avb/avb.h b/interface/include/interface/avb/avb.h
index 165f821..07aac91 100644
--- a/interface/include/interface/avb/avb.h
+++ b/interface/include/interface/avb/avb.h
@@ -28,15 +28,17 @@
 #include <trusty/sysdeps.h>
 
 #define AVB_PORT "com.android.trusty.avb"
-#define AVB_MAX_BUFFER_LENGTH 1024
+#define AVB_MAX_BUFFER_LENGTH 2048
 
 enum avb_command {
     AVB_REQ_SHIFT = 1,
     AVB_RESP_BIT  = 1,
 
-    READ_ROLLBACK_INDEX  = (0 << AVB_REQ_SHIFT),
-    WRITE_ROLLBACK_INDEX = (1 << AVB_REQ_SHIFT),
-    AVB_GET_VERSION      = (2 << AVB_REQ_SHIFT),
+    READ_ROLLBACK_INDEX        = (0 << AVB_REQ_SHIFT),
+    WRITE_ROLLBACK_INDEX       = (1 << AVB_REQ_SHIFT),
+    AVB_GET_VERSION            = (2 << AVB_REQ_SHIFT),
+    READ_PERMANENT_ATTRIBUTES  = (3 << AVB_REQ_SHIFT),
+    WRITE_PERMANENT_ATTRIBUTES = (4 << AVB_REQ_SHIFT),
 };
 
 /**
@@ -53,8 +55,8 @@
 
 /**
  * avb_message - Serial header for communicating with AVB server
- * @cmd:     the command, one of [READ|WRITE]_ROLLBACK_INDEX. Payload must
-             be a serialized buffer of the corresponding request object.
+ * @cmd:     the command. Payload must be a serialized buffer of the
+ *           corresponding request object.
  * @result:  resulting error code for message, one of avb_error.
  * @payload: start of the serialized command specific payload
  */
diff --git a/ql-tipc/avb.c b/ql-tipc/avb.c
index 659da8f..87090a0 100644
--- a/ql-tipc/avb.c
+++ b/ql-tipc/avb.c
@@ -61,11 +61,24 @@
         trusty_error("malformed response\n");
         return TRUSTY_ERR_GENERIC;
     }
-    return rc;
+    /* return payload size */
+    return rc - sizeof(*msg);
 }
 
+/*
+ * Convenience function to send a request to the AVB service and read the
+ * response.
+ *
+ * @cmd: the command
+ * @req: the request buffer
+ * @req_size: size of the request buffer
+ * @resp: the response buffer
+ * @resp_size_p: pointer to the size of the response buffer. changed to the
+                 actual size of the response read from the secure side
+ * @handle_rpmb: true if the request is expected to invoke RPMB callbacks
+ */
 static int avb_do_tipc(uint32_t cmd, void *req, uint32_t req_size, void *resp,
-                       uint32_t resp_size, bool handle_rpmb)
+                       uint32_t *resp_size_p, bool handle_rpmb)
 {
     int rc;
     struct avb_message msg = { .cmd = cmd };
@@ -91,21 +104,31 @@
         }
     }
 
+    uint32_t resp_size = resp_size_p ? *resp_size_p : 0;
     rc = avb_read_response(&msg, cmd, resp, resp_size);
     if (rc < 0) {
         trusty_error("%s: failed (%d) to read AVB response\n", __func__, rc);
         return rc;
     }
-
-    return msg.result;
+    /* change response size to actual response size */
+    if (resp_size_p && rc != *resp_size_p) {
+        *resp_size_p = rc;
+    }
+    if (msg.result != AVB_ERROR_NONE) {
+        trusty_error("%s: AVB service returned error (%d)\n", __func__,
+                     msg.result);
+        return TRUSTY_ERR_GENERIC;
+    }
+    return TRUSTY_ERR_NONE;
 }
 
 static int avb_get_version(uint32_t *version)
 {
     int rc;
     struct avb_get_version_resp resp;
+    uint32_t resp_size = sizeof(resp);
 
-    rc = avb_do_tipc(AVB_GET_VERSION, NULL, 0, &resp, sizeof(resp), false);
+    rc = avb_do_tipc(AVB_GET_VERSION, NULL, 0, &resp, &resp_size, false);
 
     *version = resp.version;
     return rc;
@@ -164,9 +187,10 @@
     int rc;
     struct avb_rollback_req req = { .slot = slot, .value = 0 };
     struct avb_rollback_resp resp;
+    uint32_t resp_size = sizeof(resp);
 
     rc = avb_do_tipc(READ_ROLLBACK_INDEX, &req, sizeof(req), &resp,
-                     sizeof(resp), true);
+                     &resp_size, true);
 
     *value = resp.value;
     return rc;
@@ -177,8 +201,32 @@
     int rc;
     struct avb_rollback_req req = { .slot = slot, .value = value };
     struct avb_rollback_resp resp;
+    uint32_t resp_size = sizeof(resp);
 
     rc = avb_do_tipc(WRITE_ROLLBACK_INDEX, &req, sizeof(req), &resp,
-                     sizeof(resp), true);
+                     &resp_size, true);
     return rc;
 }
+
+int trusty_read_permanent_attributes(uint8_t *attributes, uint32_t size)
+{
+    uint8_t resp_buf[AVB_MAX_BUFFER_LENGTH];
+    uint32_t resp_size = AVB_MAX_BUFFER_LENGTH;
+    int rc = avb_do_tipc(READ_PERMANENT_ATTRIBUTES, NULL, 0, resp_buf,
+                         &resp_size, true);
+    if (rc != 0) {
+        return rc;
+    }
+    /* ensure caller passed size matches size returned by Trusty */
+    if (size != resp_size) {
+        return TRUSTY_ERR_INVALID_ARGS;
+    }
+    trusty_memcpy(attributes, resp_buf, resp_size);
+    return rc;
+}
+
+int trusty_write_permanent_attributes(uint8_t *attributes, uint32_t size)
+{
+    return avb_do_tipc(WRITE_PERMANENT_ATTRIBUTES, attributes, size, NULL, NULL,
+                       true);
+}
diff --git a/ql-tipc/include/trusty/avb.h b/ql-tipc/include/trusty/avb.h
index a59cb57..1e5b718 100644
--- a/ql-tipc/include/trusty/avb.h
+++ b/ql-tipc/include/trusty/avb.h
@@ -57,5 +57,25 @@
  * @value:   rollback index value to write
  */
 int trusty_write_rollback_index(uint32_t slot, uint64_t value);
+/*
+ * Send request to secure side to read permanent attributes. When permanent
+ * attributes are stored in RPMB, a hash of the permanent attributes which is
+ * given to AVB during verification MUST still be backed by write-once hardware.
+ *
+ * Copies attributes received by secure side to |attributes|. If |size| does not
+ * match the size returned by the secure side, an error is returned. Returns one
+ * of trusty_err.
+ *
+ * @attributes:  caller allocated buffer
+ * @size:        size of |attributes|
+ */
+int trusty_read_permanent_attributes(uint8_t *attributes, uint32_t size);
+/*
+ * Send request to secure side to write permanent attributes. Permanent
+ * attributes can only be written to storage once.
+ *
+ * Returns one of trusty_err.
+ */
+int trusty_write_permanent_attributes(uint8_t *attributes, uint32_t size);
 
 #endif /* TRUSTY_AVB_H_ */