aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMattias Nissler <mnissler@google.com>2016-08-08 14:00:07 +0200
committerMattias Nissler <mnissler@google.com>2016-08-08 14:00:07 +0200
commite26b4baabffb0d06997cc49ec2e70d9fa9b4c911 (patch)
tree2192403699a6c2084d6b0a77835da6d2f65e9a0d
parent5197aa8c197ef8a9f7c8a9cadcf5f4fc59a70866 (diff)
downloadnvram-e26b4baabffb0d06997cc49ec2e70d9fa9b4c911.tar.gz
Wire up TrustyNvram with TIPC.
This adds glue code that receives NVRAM operations via Trusty IPC, passes them to TrustyNvram for execution and sends the result back via IPC. BUG: 27194378 Change-Id: I0f033a5e4745552570693589c377e7ecfb20a9cc
-rw-r--r--ipc/nvram_ipc.cpp228
-rw-r--r--ipc/rules.mk25
2 files changed, 253 insertions, 0 deletions
diff --git a/ipc/nvram_ipc.cpp b/ipc/nvram_ipc.cpp
new file mode 100644
index 0000000..7099500
--- /dev/null
+++ b/ipc/nvram_ipc.cpp
@@ -0,0 +1,228 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+extern "C" {
+#include <stdint.h>
+
+#include <err.h>
+#include <trusty_std.h>
+}
+
+#include <nvram/core/logger.h>
+#include <nvram/core/nvram_manager.h>
+#include <nvram/messages/nvram_messages.h>
+
+namespace {
+
+const char kNvramServiceName[] = "com.android.trusty.nvram";
+const int kNvramServiceNumBufs = 1;
+const int kNvramServiceBufSize = 4096;
+const uint32_t kNvramServiceFlags =
+ IPC_PORT_ALLOW_TA_CONNECT | IPC_PORT_ALLOW_NS_CONNECT;
+
+nvram::NvramManager* g_nvram_manager = nullptr;
+
+// Decodes a command from the binary |request_blob| and dispatches it. The
+// serialized response is written to |response_blob|. Returns a Trusty error
+// code in case there's a problem with decoding the request or encoding the
+// response. Note that NVRAM-specific errors are carried in the serialized
+// response and this function will return success.
+int ProcessRequest(const nvram::Blob& request_blob,
+ nvram::Blob* response_blob) {
+ nvram::Request request;
+ if (!nvram::Decode(request_blob.data(), request_blob.size(), &request)) {
+ NVRAM_LOG_INFO("Failed to decode request");
+ return ERR_INVALID_ARGS;
+ }
+
+ nvram::Response response;
+ g_nvram_manager->Dispatch(request, &response);
+
+ if (!nvram::Encode(response, response_blob)) {
+ NVRAM_LOG_INFO("Failed to encode response");
+ return ERR_GENERIC;
+ }
+
+ return NO_ERROR;
+}
+
+// Reads the message described by |msg_info| from channel and processes it.
+// Writes the response message back to |channel|. Returns a Trusty error code if
+// there is any I/O problem.
+int ProcessOneMessage(handle_t channel, const ipc_msg_info_t& msg_info) {
+ if (msg_info.len > kNvramServiceBufSize) {
+ NVRAM_LOG_ERR("Message too large on channel %x: %d", channel, msg_info.len);
+ return ERR_TOO_BIG;
+ }
+
+ nvram::Blob request_blob;
+ if (!request_blob.Resize(msg_info.len)) {
+ NVRAM_LOG_ERR("Failed to allocate buffer for message on channel %x\n",
+ channel);
+ return ERR_NO_MEMORY;
+ }
+
+ iovec_t request_iov{request_blob.data(), request_blob.size()};
+ ipc_msg_t request_msg{
+ 1, // number of iovecs
+ &request_iov, // iovecs pointer
+ 0, // number of handles
+ nullptr, // handles pointer
+ };
+ int rc = read_msg(channel, msg_info.id, 0, &request_msg);
+ if (rc < 0) {
+ NVRAM_LOG_ERR("Failed to read_msg on channel %x: %d", channel, rc);
+ return rc;
+ }
+
+ nvram::Blob response_blob;
+ rc = ProcessRequest(request_blob, &response_blob);
+ if (rc != NO_ERROR) {
+ NVRAM_LOG_ERR("Failed to process request on channel %x: %d", channel, rc);
+ return rc;
+ }
+
+ iovec_t response_iov{response_blob.data(), response_blob.size()};
+ ipc_msg_t response_msg{
+ 1, // number of iovecs
+ &response_iov, // iovecs pointer
+ 0, // number of handles
+ nullptr // handles pointer
+ };
+ rc = send_msg(channel, &response_msg);
+ if (rc < 0) {
+ NVRAM_LOG_ERR("Failed to send_msg on channel %x: %d", channel, rc);
+ return rc;
+ }
+
+ return NO_ERROR;
+}
+
+// Receives all pending messages from |channel| and processes them, producing
+// responses as appropriate. Returns a Trusty error code if there's a problem
+// with message processing or I/O.
+int ProcessMessages(handle_t channel) {
+ while (true) {
+ struct ipc_msg_info msg_info;
+ int rc = get_msg(channel, &msg_info);
+ if (rc == ERR_NO_MSG) {
+ break;
+ }
+
+ if (rc != NO_ERROR) {
+ NVRAM_LOG_ERR("Failed to get_msg on channel %x: %d", channel, rc);
+ return rc;
+ }
+
+ rc = ProcessOneMessage(channel, msg_info);
+ if (rc != NO_ERROR) {
+ put_msg(channel, msg_info.id);
+ return rc;
+ }
+
+ rc = put_msg(channel, msg_info.id);
+ if (rc != NO_ERROR) {
+ NVRAM_LOG_ERR("Failed to put_msg on channel %x: %d", channel, rc);
+ return rc;
+ }
+ }
+
+ return NO_ERROR;
+}
+
+// Handles an |event| that has occurred on a connected channel. This may either
+// be an incoming message, which is then processed, or the event indicates
+// channel teardown or errors, in which case the channel will be closed.
+void HandleChannelEvent(const uevent_t& event) {
+ if (event.event & IPC_HANDLE_POLL_ERROR) {
+ NVRAM_LOG_ERR("Error on channel %x", event.handle);
+ close(event.handle);
+ return;
+ }
+
+ if (event.event & IPC_HANDLE_POLL_HUP) {
+ close(event.handle);
+ return;
+ }
+
+ if (event.event & IPC_HANDLE_POLL_MSG) {
+ if (ProcessMessages(event.handle) != NO_ERROR) {
+ close(event.handle);
+ return;
+ }
+ } else {
+ NVRAM_LOG_ERR("Unexpected event on channel %x: 0x%x", event.handle,
+ event.event);
+ }
+}
+
+// Handles an event on the nvram IPC port. The only relevant event are incoming
+// connections, which get accepted and will then be ready to receive requests.
+void HandlePortEvent(const uevent_t& event) {
+ if (event.event & IPC_HANDLE_POLL_READY) {
+ uuid_t peer_uuid;
+ int rc = accept(event.handle, &peer_uuid);
+ if (rc < 0) {
+ NVRAM_LOG_ERR("Failed to accept connection: %d", rc);
+ } else {
+ // The channel is open now. The main loop will detect incoming messages
+ // and process them.
+ }
+ } else {
+ NVRAM_LOG_ERR("Unexpected event on port: 0x%x", event.event);
+ }
+}
+
+} // namespace
+
+int main() {
+ nvram::NvramManager nvram_manager;
+ g_nvram_manager = &nvram_manager;
+
+ // Create the IPC port. This publishes the nvram service to IPC clients (both
+ // on the trusty side and for the main OS).
+ int rc = port_create(kNvramServiceName, kNvramServiceNumBufs,
+ kNvramServiceBufSize, kNvramServiceFlags);
+ if (rc < 0) {
+ NVRAM_LOG_ERR("Failed to init ipc: %d", rc);
+ g_nvram_manager = nullptr;
+ return rc;
+ }
+
+ handle_t port = static_cast<handle_t>(rc);
+
+ // Process events on the port or any open channels.
+ while (true) {
+ uevent_t event;
+ event.handle = INVALID_IPC_HANDLE;
+ event.event = 0;
+ event.cookie = nullptr;
+ unsigned long timeout = -1;
+ rc = wait_any(&event, timeout);
+ if (rc == NO_ERROR) {
+ if (event.handle == port) {
+ HandlePortEvent(event);
+ } else {
+ HandleChannelEvent(event);
+ }
+ } else {
+ NVRAM_LOG_ERR("wait_any failed: %d", rc);
+ }
+ }
+
+ g_nvram_manager = nullptr;
+ return 0;
+}
diff --git a/ipc/rules.mk b/ipc/rules.mk
new file mode 100644
index 0000000..a240d66
--- /dev/null
+++ b/ipc/rules.mk
@@ -0,0 +1,25 @@
+#
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_DIR := $(GET_LOCAL_DIR)
+
+MODULE_SRCS += \
+ $(LOCAL_DIR)/nvram_ipc.cpp
+
+MODULE_DEPS += \
+ app/trusty \
+ lib/libc-trusty \
+ system/nvram/messages