Handle requests to read and write permanent product attributes

This patch adds commands to store permanent product attributes in RPMB.
Permanent attributes can only be written once, but can always be read by
a non-secure client. A hash of the permanent attributes MUST be verified
against write-once hardware.

Bug: 33051168
Test: manual test on imx6ul

Change-Id: I5c8bdb2302e763a588e3574f070da4dbc4803918
diff --git a/avb_manager.cpp b/avb_manager.cpp
index 1a0a609..88ffe4e 100644
--- a/avb_manager.cpp
+++ b/avb_manager.cpp
@@ -31,6 +31,8 @@
 
 static const uint32_t kAvbVersion = 1;
 static const char* kAvbRollbackFilename = "avb.rollback";
+static const unsigned int kPermanentAttributesLengthMax = 2048;
+static const char* kPermanentAttributesFilename = "avb.ppa";
 static const unsigned int kStorageIdLengthMax = 64;
 
 static const uint32_t kTypeMask = 0xF000;
@@ -192,4 +194,62 @@
   response->set_version(kAvbVersion);
 }
 
+void AvbManager::ReadPermanentAttributes(
+    const ReadPermanentAttributesRequest& request,
+    ReadPermanentAttributesResponse* response) {
+  int rc = storage_->open(kPermanentAttributesFilename);
+  if (rc < 0) {
+    response->set_error(AvbError::kInternal);
+    TLOGE("Error: failed to open attributes file: %d\n", rc);
+    return;
+  }
+
+  // Read permanent product attributes
+  UniquePtr<uint8_t[]> attributes(new uint8_t[kPermanentAttributesLengthMax]);
+  rc = storage_->read(0, attributes.get(), kPermanentAttributesLengthMax);
+  if (rc <= 0) {
+    response->set_error(AvbError::kInternal);
+    TLOGE("Error: %s attributes file [%d]\n",
+          rc == 0 ? "missing" : "accessing",
+          rc);
+    return;
+  }
+  uint32_t attributes_size = static_cast<uint32_t>(rc);
+  response->set_attributes_buf(attributes.get(), attributes_size);
+}
+
+void AvbManager::WritePermanentAttributes(
+    const WritePermanentAttributesRequest& request,
+    WritePermanentAttributesResponse* response) {
+  int rc = storage_->open(kPermanentAttributesFilename);
+  if (rc < 0) {
+    response->set_error(AvbError::kInternal);
+    TLOGE("Error: failed to open attributes file: %d\n", rc);
+    return;
+  }
+  uint64_t size;
+  rc = storage_->get_file_size(&size);
+  if (rc < 0) {
+    response->set_error(AvbError::kInternal);
+    TLOGE("Error: failed to get size of attributes file: %d\n", rc);
+    return;
+  }
+
+  if (size) {
+    response->set_error(AvbError::kInvalid);
+    TLOGE("Error: Permanent attributes already set!\n");
+    return;
+  }
+  // New file, write serialized permanent product attributes to storage
+  uint32_t attributes_size = request.get_attributes_size();
+  uint8_t* attributes = request.get_attributes_buf();
+  rc = storage_->write(0, attributes, attributes_size);
+
+  if (rc < 0 || static_cast<size_t>(rc) < attributes_size) {
+    response->set_error(AvbError::kInternal);
+    TLOGE("Error: accessing storage object [%d]\n", rc);
+    return;
+  }
+}
+
 };  // namespace avb
diff --git a/avb_manager.h b/avb_manager.h
index 48ab5cc..fc6d869 100644
--- a/avb_manager.h
+++ b/avb_manager.h
@@ -66,6 +66,12 @@
   // be versioned.
   void GetVersion(const GetVersionRequest& request,
                   GetVersionResponse* response);
+  // The Avb service provides storage for Android Things permanent attributes
+  // structure, but these must still be verified against write-once fuses.
+  void ReadPermanentAttributes(const ReadPermanentAttributesRequest& request,
+                               ReadPermanentAttributesResponse* response);
+  void WritePermanentAttributes(const WritePermanentAttributesRequest& request,
+                                WritePermanentAttributesResponse* response);
 
  private:
   UniquePtr<SecureStorageInterface> storage_;
diff --git a/avb_messages.cpp b/avb_messages.cpp
index 4bcdeff..3d121ae 100644
--- a/avb_messages.cpp
+++ b/avb_messages.cpp
@@ -95,4 +95,28 @@
   return NO_ERROR;
 }
 
+uint32_t PermanentAttributesMessage::GetSerializedSize() const {
+  return attributes_size_;
+}
+
+uint32_t PermanentAttributesMessage::Serialize(uint8_t* payload,
+                                               const uint8_t* end) const {
+  if (static_cast<uint32_t>(end - payload) != attributes_size_)
+    return 0;
+  memcpy(payload, attributes_.get(), attributes_size_);
+  return attributes_size_;
+}
+
+int PermanentAttributesMessage::Deserialize(const uint8_t* payload,
+                                            const uint8_t* end) {
+  if (end < payload)
+    return ERR_NOT_VALID;
+  attributes_size_ = end - payload;
+  attributes_.reset(new uint8_t[attributes_size_]);
+  if (!attributes_.get())
+    return ERR_NO_MEMORY;
+  memcpy(attributes_.get(), payload, attributes_size_);
+  return NO_ERROR;
+}
+
 };  // namespace avb
diff --git a/avb_messages.h b/avb_messages.h
index ba737c8..796aeac 100644
--- a/avb_messages.h
+++ b/avb_messages.h
@@ -24,6 +24,8 @@
 
 }  // extern C
 
+#include <UniquePtr.h>
+
 // Message serialization objects for communicating with Android
 // Verified Boot app.
 namespace avb {
@@ -35,8 +37,7 @@
   kInternal = 2,  // Error occurred during an operation in Trusty
 };
 
-// Abstract base class of all message objects. Delegates specialized
-// serialization to pure virtual functions implemented by subclasses.
+// Abstract base class of all AVB messages.
 class AvbMessage {
  public:
   // Returns serialized size in bytes of the current state of the
@@ -97,9 +98,9 @@
   uint64_t value_ = 0;  // Value of requested rollback index.
 };
 
-class GetVersionRequest : public AvbMessage {
+class EmptyMessage : public AvbMessage {
  public:
-  GetVersionRequest() {}
+  EmptyMessage() {}
 
   uint32_t GetSerializedSize() const override { return 0; }
   uint32_t Serialize(uint8_t* payload, const uint8_t* end) const override {
@@ -110,6 +111,8 @@
   }
 };
 
+class GetVersionRequest : public EmptyMessage {};
+
 class GetVersionResponse : public AvbMessage {
  public:
   GetVersionResponse() {}
@@ -126,6 +129,31 @@
   uint32_t version_ = 0;
 };
 
+class PermanentAttributesMessage : public AvbMessage {
+ public:
+  PermanentAttributesMessage() {}
+
+  uint32_t GetSerializedSize() const override;
+  uint32_t Serialize(uint8_t* payload, const uint8_t* end) const override;
+  int Deserialize(const uint8_t* payload, const uint8_t* end) override;
+
+  uint32_t get_attributes_size() const { return attributes_size_; }
+  uint8_t* get_attributes_buf() const { return attributes_.get(); }
+  int set_attributes_buf(const uint8_t* buf, const uint32_t size) {
+    return Deserialize(buf, buf + size);
+  }
+
+ private:
+  UniquePtr<uint8_t[]> attributes_;
+  uint32_t attributes_size_ = 0;
+};
+
+class WritePermanentAttributesRequest : public PermanentAttributesMessage {};
+class WritePermanentAttributesResponse : public EmptyMessage {};
+
+class ReadPermanentAttributesRequest : public EmptyMessage {};
+class ReadPermanentAttributesResponse : public PermanentAttributesMessage {};
+
 }  // namespace avb
 
 #endif  // AVB_MESSAGES_H_
diff --git a/ipc/avb_ipc.cpp b/ipc/avb_ipc.cpp
index 739ccf0..600536d 100644
--- a/ipc/avb_ipc.cpp
+++ b/ipc/avb_ipc.cpp
@@ -30,7 +30,7 @@
 
 const char kAvbServiceName[] = "com.android.trusty.avb";
 const int kAvbServiceNumBufs = 1;
-const int kAvbServiceBufSize = 1024;
+const int kAvbServiceBufSize = 2048;
 const uint32_t kAvbServiceFlags = IPC_PORT_ALLOW_NS_CONNECT;
 
 avb::AvbManager* g_avb_manager;
@@ -65,6 +65,10 @@
     return ERR_TOO_BIG;
   }
 
+  if (*out_size == 0) {
+    return NO_ERROR;
+  }
+
   out_buf->reset(new uint8_t[*out_size]);
   if (out_buf->get() == nullptr) {
     *out_size = 0;
@@ -107,6 +111,20 @@
     case AVB_GET_VERSION:
       return ExecuteCommand(
           &AvbManager::GetVersion, in_buf, in_size, out_buf, out_size, error);
+    case READ_PERMANENT_ATTRIBUTES:
+      return ExecuteCommand(&AvbManager::ReadPermanentAttributes,
+                            in_buf,
+                            in_size,
+                            out_buf,
+                            out_size,
+                            error);
+    case WRITE_PERMANENT_ATTRIBUTES:
+      return ExecuteCommand(&AvbManager::WritePermanentAttributes,
+                            in_buf,
+                            in_size,
+                            out_buf,
+                            out_size,
+                            error);
     default:
       return ERR_NOT_VALID;
   }
diff --git a/ipc/avb_ipc.h b/ipc/avb_ipc.h
index eb40832..0d74bbe 100644
--- a/ipc/avb_ipc.h
+++ b/ipc/avb_ipc.h
@@ -28,6 +28,8 @@
   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),
 };
 
 // struct avb_message - Generic message format for communicating with AVB server
diff --git a/manifest.c b/manifest.c
index ddb13ed..c94b8e6 100644
--- a/manifest.c
+++ b/manifest.c
@@ -22,5 +22,8 @@
     /* UUID : {905bcb84-2dc4-419d-b951-7255027d318c} */
     { 0x905bcb84, 0x2dc4, 0x419d,
         { 0xb9, 0x51, 0x72, 0x55, 0x02, 0x7d, 0x31, 0x8c } },
-
+	{
+		TRUSTY_APP_CONFIG_MIN_HEAP_SIZE(2 * 4096),
+		TRUSTY_APP_CONFIG_MIN_STACK_SIZE(1 * 4096),
+	},
 };