Merge "authfs: instantiate read-only files lazily"
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 7be81a8..25908ad 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -17,6 +17,9 @@
     },
     {
       "name": "compsvc_device_tests"
+    },
+    {
+      "name": "compos_key_tests"
     }
   ],
   "postsubmit": [
diff --git a/compos/apex/Android.bp b/compos/apex/Android.bp
index aec3c88..6550b4f 100644
--- a/compos/apex/Android.bp
+++ b/compos/apex/Android.bp
@@ -47,6 +47,7 @@
         "composd_cmd",
 
         // Used in VM
+        "compos_key_helper",
         "compsvc",
     ],
 
diff --git a/compos/compos_key_helper/Android.bp b/compos/compos_key_helper/Android.bp
new file mode 100644
index 0000000..c53d88d
--- /dev/null
+++ b/compos/compos_key_helper/Android.bp
@@ -0,0 +1,47 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_defaults {
+    name: "compos_key_defaults",
+    apex_available: ["com.android.compos"],
+
+    shared_libs: [
+        "libbase",
+        "libbinder_ndk",
+        "libcrypto",
+    ],
+}
+
+cc_library {
+    name: "libcompos_key",
+    defaults: ["compos_key_defaults"],
+    srcs: ["compos_key.cpp"],
+
+    shared_libs: [
+        "android.hardware.security.dice-V1-ndk",
+        "android.security.dice-ndk",
+    ],
+}
+
+cc_binary {
+    name: "compos_key_helper",
+    defaults: ["compos_key_defaults"],
+    srcs: ["compos_key_main.cpp"],
+
+    static_libs: ["libcompos_key"],
+    shared_libs: [
+        "android.security.dice-ndk",
+    ],
+}
+
+cc_test {
+    name: "compos_key_tests",
+    defaults: ["compos_key_defaults"],
+    test_suites: [
+        "general-tests",
+    ],
+
+    srcs: ["compos_key_test.cpp"],
+    static_libs: ["libcompos_key"],
+}
diff --git a/compos/compos_key_helper/compos_key.cpp b/compos/compos_key_helper/compos_key.cpp
new file mode 100644
index 0000000..84a736d
--- /dev/null
+++ b/compos/compos_key_helper/compos_key.cpp
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2022 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.
+ */
+
+#include "compos_key.h"
+
+#include <aidl/android/security/dice/IDiceNode.h>
+#include <android/binder_auto_utils.h>
+#include <android/binder_manager.h>
+#include <openssl/digest.h>
+#include <openssl/hkdf.h>
+#include <openssl/mem.h>
+#include <unistd.h>
+
+using aidl::android::hardware::security::dice::BccHandover;
+using aidl::android::hardware::security::dice::InputValues;
+using aidl::android::security::dice::IDiceNode;
+using android::base::ErrnoError;
+using android::base::Error;
+using android::base::Result;
+
+// Used to ensure the key we derive is distinct from any other.
+constexpr const char* kSigningKeyInfo = "CompOS signing key";
+
+Result<Ed25519KeyPair> deriveKeyFromSecret(const uint8_t* secret, size_t secret_size) {
+    // Ed25519 private keys are derived from a 32 byte seed:
+    // https://datatracker.ietf.org/doc/html/rfc8032#section-5.1.5
+    std::array<uint8_t, 32> seed;
+
+    // We derive the seed from the secret using HKDF - see
+    // https://datatracker.ietf.org/doc/html/rfc5869#section-2.
+    if (!HKDF(seed.data(), seed.size(), EVP_sha256(), secret, secret_size, /*salt=*/nullptr,
+              /*salt_len=*/0, reinterpret_cast<const uint8_t*>(kSigningKeyInfo),
+              strlen(kSigningKeyInfo))) {
+        return Error() << "HKDF failed";
+    }
+
+    Ed25519KeyPair result;
+    ED25519_keypair_from_seed(result.public_key.data(), result.private_key.data(), seed.data());
+    return result;
+}
+
+Result<Signature> sign(const PrivateKey& private_key, const uint8_t* data, size_t data_size) {
+    Signature result;
+    if (!ED25519_sign(result.data(), data, data_size, private_key.data())) {
+        return Error() << "Failed to sign";
+    }
+    return result;
+}
+
+bool verify(const PublicKey& public_key, const Signature& signature, const uint8_t* data,
+            size_t data_size) {
+    return ED25519_verify(data, data_size, signature.data(), public_key.data()) == 1;
+}
+
+Result<Ed25519KeyPair> deriveKeyFromDice() {
+    ndk::SpAIBinder binder{AServiceManager_getService("android.security.dice.IDiceNode")};
+    auto dice_node = IDiceNode::fromBinder(binder);
+    if (!dice_node) {
+        return Error() << "Unable to connect to IDiceNode";
+    }
+
+    const std::vector<InputValues> empty_input_values;
+    BccHandover bcc;
+    auto status = dice_node->derive(empty_input_values, &bcc);
+    if (!status.isOk()) {
+        return Error() << "Derive failed: " << status.getDescription();
+    }
+
+    // We use the sealing CDI because we want stability - the key needs to be the same
+    // for any instance of the "same" VM.
+    return deriveKeyFromSecret(bcc.cdiSeal.data(), bcc.cdiSeal.size());
+}
diff --git a/compos/compos_key_helper/compos_key.h b/compos/compos_key_helper/compos_key.h
new file mode 100644
index 0000000..520f846
--- /dev/null
+++ b/compos/compos_key_helper/compos_key.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2022 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.
+ */
+
+#pragma once
+
+#include <android-base/result.h>
+#include <openssl/curve25519.h>
+
+#include <array>
+
+using PrivateKey = std::array<uint8_t, ED25519_PRIVATE_KEY_LEN>;
+using PublicKey = std::array<uint8_t, ED25519_PUBLIC_KEY_LEN>;
+using Signature = std::array<uint8_t, ED25519_SIGNATURE_LEN>;
+
+struct Ed25519KeyPair {
+    PrivateKey private_key;
+    PublicKey public_key;
+};
+
+android::base::Result<Ed25519KeyPair> deriveKeyFromSecret(const uint8_t* secret,
+                                                          size_t secret_size);
+
+android::base::Result<Ed25519KeyPair> deriveKeyFromDice();
+
+android::base::Result<Signature> sign(const PrivateKey& private_key, const uint8_t* data,
+                                      size_t data_size);
+
+bool verify(const PublicKey& public_key, const Signature& signature, const uint8_t* data,
+            size_t data_size);
diff --git a/compos/compos_key_helper/compos_key_main.cpp b/compos/compos_key_helper/compos_key_main.cpp
new file mode 100644
index 0000000..70f7539
--- /dev/null
+++ b/compos/compos_key_helper/compos_key_main.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2022 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.
+ */
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <unistd.h>
+
+#include <iostream>
+#include <string_view>
+
+#include "compos_key.h"
+
+using android::base::ErrnoError;
+using android::base::WriteFully;
+using namespace std::literals;
+
+int main(int argc, char** argv) {
+    android::base::InitLogging(argv, android::base::LogdLogger(android::base::SYSTEM));
+
+    if (argc == 2) {
+        if (argv[1] == "public_key"sv) {
+            auto key_pair = deriveKeyFromDice();
+            if (!key_pair.ok()) {
+                LOG(ERROR) << key_pair.error();
+                return 1;
+            }
+            if (!WriteFully(STDOUT_FILENO, key_pair->public_key.data(),
+                            key_pair->public_key.size())) {
+                PLOG(ERROR) << "Write failed";
+                return 1;
+            }
+            return 0;
+        }
+    }
+
+    std::cerr << "Usage:\n"
+                 "compos_key_helper public_key   Write current public key to stdout\n";
+    return 1;
+}
diff --git a/compos/compos_key_helper/compos_key_test.cpp b/compos/compos_key_helper/compos_key_test.cpp
new file mode 100644
index 0000000..e5c4768
--- /dev/null
+++ b/compos/compos_key_helper/compos_key_test.cpp
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2022 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.
+ */
+
+#include "compos_key.h"
+
+#include <vector>
+
+#include "gtest/gtest.h"
+
+const std::vector<uint8_t> secret = {1, 2, 3};
+const std::vector<uint8_t> other_secret = {3, 2, 3};
+const std::vector<uint8_t> data = {42, 180, 65, 0};
+
+struct ComposKeyTest : public testing::Test {
+    Ed25519KeyPair key_pair;
+
+    void SetUp() override {
+        auto key_pair = deriveKeyFromSecret(secret.data(), secret.size());
+        ASSERT_TRUE(key_pair.ok()) << key_pair.error();
+        this->key_pair = *key_pair;
+    }
+};
+
+TEST_F(ComposKeyTest, SameSecretSameKey) {
+    auto other_key_pair = deriveKeyFromSecret(secret.data(), secret.size());
+    ASSERT_TRUE(other_key_pair.ok()) << other_key_pair.error();
+
+    ASSERT_EQ(key_pair.private_key, other_key_pair->private_key);
+    ASSERT_EQ(key_pair.public_key, other_key_pair->public_key);
+}
+
+TEST_F(ComposKeyTest, DifferentSecretDifferentKey) {
+    auto other_key_pair = deriveKeyFromSecret(other_secret.data(), other_secret.size());
+    ASSERT_TRUE(other_key_pair.ok()) << other_key_pair.error();
+
+    ASSERT_NE(key_pair.private_key, other_key_pair->private_key);
+    ASSERT_NE(key_pair.public_key, other_key_pair->public_key);
+}
+
+TEST_F(ComposKeyTest, CanVerifyValidSignature) {
+    auto signature = sign(key_pair.private_key, data.data(), data.size());
+    ASSERT_TRUE(signature.ok()) << signature.error();
+
+    bool verified = verify(key_pair.public_key, *signature, data.data(), data.size());
+    ASSERT_TRUE(verified);
+}
+
+TEST_F(ComposKeyTest, WrongSignatureDoesNotVerify) {
+    auto signature = sign(key_pair.private_key, data.data(), data.size());
+    ASSERT_TRUE(signature.ok()) << signature.error();
+
+    (*signature)[0] ^= 1;
+
+    bool verified = verify(key_pair.public_key, *signature, data.data(), data.size());
+    ASSERT_FALSE(verified);
+}
+
+TEST_F(ComposKeyTest, WrongDataDoesNotVerify) {
+    auto signature = sign(key_pair.private_key, data.data(), data.size());
+    ASSERT_TRUE(signature.ok()) << signature.error();
+
+    auto other_data = data;
+    other_data[0] ^= 1;
+
+    bool verified = verify(key_pair.public_key, *signature, other_data.data(), other_data.size());
+    ASSERT_FALSE(verified);
+}
+
+TEST_F(ComposKeyTest, WrongKeyDoesNotVerify) {
+    auto signature = sign(key_pair.private_key, data.data(), data.size());
+
+    auto other_key_pair = deriveKeyFromSecret(other_secret.data(), other_secret.size());
+    ASSERT_TRUE(other_key_pair.ok()) << other_key_pair.error();
+
+    bool verified = verify(other_key_pair->public_key, *signature, data.data(), data.size());
+    ASSERT_FALSE(verified);
+}
diff --git a/compos/compos_key_helper/tests/AndroidTest.xml b/compos/compos_key_helper/tests/AndroidTest.xml
new file mode 100644
index 0000000..3c1c657
--- /dev/null
+++ b/compos/compos_key_helper/tests/AndroidTest.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2022 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.
+-->
+<configuration description="Tests for compos_key">
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="module-name" value="compos_key_tests" />
+    </test>
+</configuration>
diff --git a/microdroid/init.rc b/microdroid/init.rc
index ebe2464..5f0001f 100644
--- a/microdroid/init.rc
+++ b/microdroid/init.rc
@@ -196,6 +196,3 @@
 "
     chown logd logd /dev/event-log-tags
     chmod 0644 /dev/event-log-tags
-
-on property:sys.boot_completed=1
-    start logd-auditctl
diff --git a/tests/hostside/java/android/virt/test/MicrodroidTestCase.java b/tests/hostside/java/android/virt/test/MicrodroidTestCase.java
index 25adc40..6dacf23 100644
--- a/tests/hostside/java/android/virt/test/MicrodroidTestCase.java
+++ b/tests/hostside/java/android/virt/test/MicrodroidTestCase.java
@@ -119,6 +119,9 @@
         assertThat(runOnMicrodroid("cat /proc/cpuinfo | grep processor | wc -l"),
                 is(Integer.toString(NUM_VCPUS)));
 
+        // Check that selinux is enabled
+        assertThat(runOnMicrodroid("getenforce"), is("Enforcing"));
+
         // TODO(b/176805428): adb is broken for nested VM
         if (!isCuttlefish()) {
             // Check neverallow rules on microdroid
diff --git a/tests/vsock_test.cc b/tests/vsock_test.cc
index 9550651..c478f64 100644
--- a/tests/vsock_test.cc
+++ b/tests/vsock_test.cc
@@ -49,26 +49,14 @@
 static constexpr const char kVmParams[] = "rdinit=/bin/init bin/vsock_client 2 45678 HelloWorld";
 static constexpr const char kTestMessage[] = "HelloWorld";
 
-/** Returns true if the kernel supports protected VMs. */
-bool isProtectedVmSupported() {
-    return android::sysprop::HypervisorProperties::hypervisor_protected_vm_supported().value_or(
-            false);
-}
-
 /** Returns true if the kernel supports unprotected VMs. */
 bool isUnprotectedVmSupported() {
     return android::sysprop::HypervisorProperties::hypervisor_vm_supported().value_or(false);
 }
 
-void runTest(sp<IVirtualizationService> virtualization_service, bool protected_vm) {
-    if (protected_vm) {
-        if (!isProtectedVmSupported()) {
-            GTEST_SKIP() << "Skipping as protected VMs are not supported on this device.";
-        }
-    } else {
-        if (!isUnprotectedVmSupported()) {
-            GTEST_SKIP() << "Skipping as unprotected VMs are not supported on this device.";
-        }
+TEST_F(VirtualizationTest, TestVsock) {
+    if (!isUnprotectedVmSupported()) {
+        GTEST_SKIP() << "Skipping as unprotected VMs are not supported on this device.";
     }
 
     binder::Status status;
@@ -93,11 +81,11 @@
     raw_config.kernel = ParcelFileDescriptor(unique_fd(open(kVmKernelPath, O_RDONLY | O_CLOEXEC)));
     raw_config.initrd = ParcelFileDescriptor(unique_fd(open(kVmInitrdPath, O_RDONLY | O_CLOEXEC)));
     raw_config.params = kVmParams;
-    raw_config.protectedVm = protected_vm;
+    raw_config.protectedVm = false;
 
     VirtualMachineConfig config(std::move(raw_config));
     sp<IVirtualMachine> vm;
-    status = virtualization_service->createVm(config, std::nullopt, std::nullopt, &vm);
+    status = mVirtualizationService->createVm(config, std::nullopt, std::nullopt, &vm);
     ASSERT_TRUE(status.isOk()) << "Error creating VM: " << status;
 
     int32_t cid;
@@ -124,12 +112,4 @@
     ASSERT_EQ(msg, kTestMessage);
 }
 
-TEST_F(VirtualizationTest, TestVsock) {
-    runTest(mVirtualizationService, false);
-}
-
-TEST_F(VirtualizationTest, TestVsockProtected) {
-    runTest(mVirtualizationService, true);
-}
-
 } // namespace virt
diff --git a/virtualizationservice/src/aidl.rs b/virtualizationservice/src/aidl.rs
index 7e0c634..89c6e8a 100644
--- a/virtualizationservice/src/aidl.rs
+++ b/virtualizationservice/src/aidl.rs
@@ -29,7 +29,6 @@
     IVirtualizationService::IVirtualizationService,
     Partition::Partition,
     PartitionType::PartitionType,
-    VirtualMachineAppConfig::DebugLevel::DebugLevel,
     VirtualMachineAppConfig::VirtualMachineAppConfig,
     VirtualMachineConfig::VirtualMachineConfig,
     VirtualMachineDebugInfo::VirtualMachineDebugInfo,
@@ -131,8 +130,8 @@
     ) -> binder::Result<Strong<dyn IVirtualMachine>> {
         check_manage_access()?;
         let state = &mut *self.state.lock().unwrap();
-        let mut console_fd = console_fd.map(clone_file).transpose()?;
-        let mut log_fd = log_fd.map(clone_file).transpose()?;
+        let console_fd = console_fd.map(clone_file).transpose()?;
+        let log_fd = log_fd.map(clone_file).transpose()?;
         let requester_uid = ThreadState::get_calling_uid();
         let requester_sid = get_calling_sid()?;
         let requester_debug_pid = ThreadState::get_calling_pid();
@@ -163,27 +162,7 @@
             )
         })?;
 
-        // Disable console logging if debug level != full. Note that kernel anyway doesn't use the
-        // console output when debug level != full. So, users won't be able to see the kernel
-        // output even without this overriding. This is to silence output from the bootloader which
-        // doesn't understand the bootconfig parameters.
-        if let VirtualMachineConfig::AppConfig(config) = config {
-            if config.debugLevel != DebugLevel::FULL {
-                console_fd = None;
-            }
-            if config.debugLevel == DebugLevel::NONE {
-                log_fd = None;
-            }
-        }
-
         let is_app_config = matches!(config, VirtualMachineConfig::AppConfig(_));
-        let is_debug_level_full = matches!(
-            config,
-            VirtualMachineConfig::AppConfig(VirtualMachineAppConfig {
-                debugLevel: DebugLevel::FULL,
-                ..
-            })
-        );
 
         let config = match config {
             VirtualMachineConfig::AppConfig(config) => BorrowedOrOwned::Owned(
@@ -201,14 +180,6 @@
         let config = config.as_ref();
         let protected = config.protectedVm;
 
-        // Debug level FULL is only supported for non-protected VMs.
-        if is_debug_level_full && protected {
-            return Err(new_binder_exception(
-                ExceptionCode::SERVICE_SPECIFIC,
-                "FULL debug level not supported for protected VMs.",
-            ));
-        };
-
         // Check if partition images are labeled incorrectly. This is to prevent random images
         // which are not protected by the Android Verified Boot (e.g. bits downloaded by apps) from
         // being loaded in a pVM.  Specifically, for images in the raw config, nothing is allowed
diff --git a/virtualizationservice/src/main.rs b/virtualizationservice/src/main.rs
index 69ae076..43e46a3 100644
--- a/virtualizationservice/src/main.rs
+++ b/virtualizationservice/src/main.rs
@@ -40,7 +40,7 @@
 
 fn main() {
     android_logger::init_once(
-        android_logger::Config::default().with_tag(LOG_TAG).with_min_level(Level::Trace),
+        android_logger::Config::default().with_tag(LOG_TAG).with_min_level(Level::Info),
     );
 
     clear_temporary_files().expect("Failed to delete old temporary files");