Merge "Sync encryptedstorage after payload execution"
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 72926ff..14452a3 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -19,7 +19,7 @@
       "name": "compos_key_tests"
     },
     {
-      "name": "composd_verify.test"
+      "name": "compos_verify.test"
     },
     {
       "name": "initrd_bootconfig.test"
diff --git a/libs/libfdt/src/lib.rs b/libs/libfdt/src/lib.rs
index 8fd1879..29d7abe 100644
--- a/libs/libfdt/src/lib.rs
+++ b/libs/libfdt/src/lib.rs
@@ -388,6 +388,23 @@
         fdt_err_expect_zero(ret)
     }
 
+    /// Create or change a property name-value pair to the given node.
+    pub fn setprop(&mut self, name: &CStr, value: &[u8]) -> Result<()> {
+        // SAFETY - New value size is constrained to the DT totalsize
+        //          (validated by underlying libfdt).
+        let ret = unsafe {
+            libfdt_bindgen::fdt_setprop(
+                self.fdt.as_mut_ptr(),
+                self.offset,
+                name.as_ptr(),
+                value.as_ptr().cast::<c_void>(),
+                value.len().try_into().map_err(|_| FdtError::BadValue)?,
+            )
+        };
+
+        fdt_err_expect_zero(ret)
+    }
+
     /// Get reference to the containing device tree.
     pub fn fdt(&mut self) -> &mut Fdt {
         self.fdt
diff --git a/pvmfw/avb/Android.bp b/pvmfw/avb/Android.bp
index fb950b7..03670c1 100644
--- a/pvmfw/avb/Android.bp
+++ b/pvmfw/avb/Android.bp
@@ -46,7 +46,9 @@
     rustlibs: [
         "libanyhow",
         "libavb_bindgen",
+        "libhex",
         "libpvmfw_avb_nostd",
+        "libopenssl",
     ],
     enabled: false,
     arch: {
diff --git a/pvmfw/avb/src/descriptor.rs b/pvmfw/avb/src/descriptor.rs
index b0598de..c54d416 100644
--- a/pvmfw/avb/src/descriptor.rs
+++ b/pvmfw/avb/src/descriptor.rs
@@ -31,7 +31,8 @@
 };
 use tinyvec::ArrayVec;
 
-const DIGEST_SIZE: usize = AVB_SHA256_DIGEST_SIZE as usize;
+/// Digest type for kernel and initrd.
+pub type Digest = [u8; AVB_SHA256_DIGEST_SIZE as usize];
 
 /// `HashDescriptors` can have maximum one `HashDescriptor` per known partition.
 #[derive(Default)]
@@ -132,9 +133,7 @@
 #[derive(Default)]
 pub(crate) struct HashDescriptor {
     partition_name: PartitionName,
-    /// TODO(b/265897559): Pass this digest to DICE.
-    #[allow(dead_code)]
-    pub(crate) digest: [u8; DIGEST_SIZE],
+    pub(crate) digest: Digest,
 }
 
 impl HashDescriptor {
@@ -145,7 +144,7 @@
             .try_into()?;
         let partition_digest =
             data.get(desc.digest_range()?).ok_or(AvbIOError::RangeOutsidePartition)?;
-        let mut digest = [0u8; DIGEST_SIZE];
+        let mut digest = [0u8; size_of::<Digest>()];
         digest.copy_from_slice(partition_digest);
         Ok(Self { partition_name, digest })
     }
diff --git a/pvmfw/avb/src/lib.rs b/pvmfw/avb/src/lib.rs
index 065eca5..8fea162 100644
--- a/pvmfw/avb/src/lib.rs
+++ b/pvmfw/avb/src/lib.rs
@@ -25,5 +25,6 @@
 mod utils;
 mod verify;
 
+pub use descriptor::Digest;
 pub use error::AvbSlotVerifyError;
-pub use verify::{verify_payload, DebugLevel};
+pub use verify::{verify_payload, DebugLevel, VerifiedBootData};
diff --git a/pvmfw/avb/src/partition.rs b/pvmfw/avb/src/partition.rs
index 636bfd3..bc63003 100644
--- a/pvmfw/avb/src/partition.rs
+++ b/pvmfw/avb/src/partition.rs
@@ -18,7 +18,7 @@
 use crate::utils::is_not_null;
 use core::ffi::{c_char, CStr};
 
-#[derive(Clone, Debug, Default, PartialEq, Eq)]
+#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
 pub(crate) enum PartitionName {
     /// The default `PartitionName` is needed to build the default `HashDescriptor`.
     #[default]
diff --git a/pvmfw/avb/src/verify.rs b/pvmfw/avb/src/verify.rs
index 14b0e7e..1a79c83 100644
--- a/pvmfw/avb/src/verify.rs
+++ b/pvmfw/avb/src/verify.rs
@@ -14,15 +14,26 @@
 
 //! This module handles the pvmfw payload verification.
 
-use crate::descriptor::HashDescriptors;
+use crate::descriptor::{Digest, HashDescriptors};
 use crate::error::AvbSlotVerifyError;
 use crate::ops::{Ops, Payload};
 use crate::partition::PartitionName;
 use avb_bindgen::{AvbPartitionData, AvbVBMetaData};
 use core::ffi::c_char;
 
+/// Verified data returned when the payload verification succeeds.
+#[derive(Debug)]
+pub struct VerifiedBootData {
+    /// DebugLevel of the VM.
+    pub debug_level: DebugLevel,
+    /// Kernel digest.
+    pub kernel_digest: Digest,
+    /// Initrd digest if initrd exists.
+    pub initrd_digest: Option<Digest>,
+}
+
 /// This enum corresponds to the `DebugLevel` in `VirtualMachineConfig`.
-#[derive(Clone, Debug, PartialEq, Eq)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 pub enum DebugLevel {
     /// Not debuggable at all.
     None,
@@ -87,7 +98,7 @@
     kernel: &[u8],
     initrd: Option<&[u8]>,
     trusted_public_key: &[u8],
-) -> Result<DebugLevel, AvbSlotVerifyError> {
+) -> Result<VerifiedBootData, AvbSlotVerifyError> {
     let mut payload = Payload::new(kernel, initrd, trusted_public_key);
     let mut ops = Ops::from(&mut payload);
     let kernel_verify_result = ops.verify_partition(PartitionName::Kernel.as_cstr())?;
@@ -100,12 +111,15 @@
     // which is returned by `avb_slot_verify()` when the verification succeeds. It is
     // guaranteed by libavb to be non-null and to point to a valid VBMeta structure.
     let hash_descriptors = unsafe { HashDescriptors::from_vbmeta(vbmeta_image)? };
-    // TODO(b/265897559): Pass the digest in kernel descriptor to DICE.
-    let _kernel_descriptor = hash_descriptors.find(PartitionName::Kernel)?;
+    let kernel_descriptor = hash_descriptors.find(PartitionName::Kernel)?;
 
     if initrd.is_none() {
         verify_vbmeta_has_only_one_hash_descriptor(&hash_descriptors)?;
-        return Ok(DebugLevel::None);
+        return Ok(VerifiedBootData {
+            debug_level: DebugLevel::None,
+            kernel_digest: kernel_descriptor.digest,
+            initrd_digest: None,
+        });
     }
 
     let initrd = initrd.unwrap();
@@ -123,5 +137,10 @@
         initrd_partition_name,
         initrd.len(),
     )?;
-    Ok(debug_level)
+    let initrd_descriptor = hash_descriptors.find(initrd_partition_name)?;
+    Ok(VerifiedBootData {
+        debug_level,
+        kernel_digest: kernel_descriptor.digest,
+        initrd_digest: Some(initrd_descriptor.digest),
+    })
 }
diff --git a/pvmfw/avb/tests/api_test.rs b/pvmfw/avb/tests/api_test.rs
index 4f00f1e..261d8a8 100644
--- a/pvmfw/avb/tests/api_test.rs
+++ b/pvmfw/avb/tests/api_test.rs
@@ -16,9 +16,9 @@
 
 mod utils;
 
-use anyhow::Result;
+use anyhow::{anyhow, Result};
 use avb_bindgen::{AvbFooter, AvbVBMetaImageHeader};
-use pvmfw_avb::{AvbSlotVerifyError, DebugLevel};
+use pvmfw_avb::{verify_payload, AvbSlotVerifyError, DebugLevel};
 use std::{fs, mem::size_of, ptr};
 use utils::*;
 
@@ -35,121 +35,125 @@
 /// the latest payload can be verified successfully.
 #[test]
 fn latest_normal_payload_passes_verification() -> Result<()> {
-    assert_payload_verification_with_initrd_eq(
-        &load_latest_signed_kernel()?,
+    assert_latest_payload_verification_passes(
         &load_latest_initrd_normal()?,
-        &load_trusted_public_key()?,
-        Ok(DebugLevel::None),
+        b"initrd_normal",
+        DebugLevel::None,
     )
 }
 
 #[test]
 fn latest_debug_payload_passes_verification() -> Result<()> {
-    assert_payload_verification_with_initrd_eq(
-        &load_latest_signed_kernel()?,
+    assert_latest_payload_verification_passes(
         &load_latest_initrd_debug()?,
-        &load_trusted_public_key()?,
-        Ok(DebugLevel::Full),
+        b"initrd_debug",
+        DebugLevel::Full,
     )
 }
 
 #[test]
 fn payload_expecting_no_initrd_passes_verification_with_no_initrd() -> Result<()> {
-    assert_payload_verification_eq(
+    let verified_boot_data = verify_payload(
         &fs::read(TEST_IMG_WITH_ONE_HASHDESC_PATH)?,
         /*initrd=*/ None,
         &load_trusted_public_key()?,
-        Ok(DebugLevel::None),
     )
+    .map_err(|e| anyhow!("Verification failed. Error: {}", e))?;
+
+    assert_eq!(DebugLevel::None, verified_boot_data.debug_level);
+    let digest = hash(&[&hex::decode("1111")?, &fs::read(UNSIGNED_TEST_IMG_PATH)?]);
+    assert_eq!(digest, verified_boot_data.kernel_digest);
+    assert!(verified_boot_data.initrd_digest.is_none());
+    Ok(())
 }
 
 #[test]
 fn payload_with_non_initrd_descriptor_fails_verification_with_no_initrd() -> Result<()> {
-    assert_payload_verification_eq(
+    assert_payload_verification_fails(
         &fs::read(TEST_IMG_WITH_NON_INITRD_HASHDESC_PATH)?,
         /*initrd=*/ None,
         &load_trusted_public_key()?,
-        Err(AvbSlotVerifyError::InvalidMetadata),
+        AvbSlotVerifyError::InvalidMetadata,
     )
 }
 
 #[test]
 fn payload_with_non_initrd_descriptor_fails_verification_with_initrd() -> Result<()> {
-    assert_payload_verification_with_initrd_eq(
+    assert_payload_verification_with_initrd_fails(
         &fs::read(TEST_IMG_WITH_INITRD_AND_NON_INITRD_DESC_PATH)?,
         &load_latest_initrd_normal()?,
         &load_trusted_public_key()?,
-        Err(AvbSlotVerifyError::InvalidMetadata),
+        AvbSlotVerifyError::InvalidMetadata,
     )
 }
 
 #[test]
 fn payload_with_prop_descriptor_fails_verification_with_no_initrd() -> Result<()> {
-    assert_payload_verification_eq(
+    assert_payload_verification_fails(
         &fs::read(TEST_IMG_WITH_PROP_DESC_PATH)?,
         /*initrd=*/ None,
         &load_trusted_public_key()?,
-        Err(AvbSlotVerifyError::InvalidMetadata),
+        AvbSlotVerifyError::InvalidMetadata,
     )
 }
 
 #[test]
 fn payload_expecting_initrd_fails_verification_with_no_initrd() -> Result<()> {
-    assert_payload_verification_eq(
+    assert_payload_verification_fails(
         &load_latest_signed_kernel()?,
         /*initrd=*/ None,
         &load_trusted_public_key()?,
-        Err(AvbSlotVerifyError::InvalidMetadata),
+        AvbSlotVerifyError::InvalidMetadata,
     )
 }
 
 #[test]
 fn payload_with_empty_public_key_fails_verification() -> Result<()> {
-    assert_payload_verification_with_initrd_eq(
+    assert_payload_verification_with_initrd_fails(
         &load_latest_signed_kernel()?,
         &load_latest_initrd_normal()?,
         /*trusted_public_key=*/ &[0u8; 0],
-        Err(AvbSlotVerifyError::PublicKeyRejected),
+        AvbSlotVerifyError::PublicKeyRejected,
     )
 }
 
 #[test]
 fn payload_with_an_invalid_public_key_fails_verification() -> Result<()> {
-    assert_payload_verification_with_initrd_eq(
+    assert_payload_verification_with_initrd_fails(
         &load_latest_signed_kernel()?,
         &load_latest_initrd_normal()?,
         /*trusted_public_key=*/ &[0u8; 512],
-        Err(AvbSlotVerifyError::PublicKeyRejected),
+        AvbSlotVerifyError::PublicKeyRejected,
     )
 }
 
 #[test]
 fn payload_with_a_different_valid_public_key_fails_verification() -> Result<()> {
-    assert_payload_verification_with_initrd_eq(
+    assert_payload_verification_with_initrd_fails(
         &load_latest_signed_kernel()?,
         &load_latest_initrd_normal()?,
         &fs::read(PUBLIC_KEY_RSA2048_PATH)?,
-        Err(AvbSlotVerifyError::PublicKeyRejected),
+        AvbSlotVerifyError::PublicKeyRejected,
     )
 }
 
 #[test]
 fn payload_with_an_invalid_initrd_fails_verification() -> Result<()> {
-    assert_payload_verification_with_initrd_eq(
+    assert_payload_verification_with_initrd_fails(
         &load_latest_signed_kernel()?,
         /*initrd=*/ &fs::read(UNSIGNED_TEST_IMG_PATH)?,
         &load_trusted_public_key()?,
-        Err(AvbSlotVerifyError::Verification),
+        AvbSlotVerifyError::Verification,
     )
 }
 
 #[test]
 fn unsigned_kernel_fails_verification() -> Result<()> {
-    assert_payload_verification_with_initrd_eq(
+    assert_payload_verification_with_initrd_fails(
         &fs::read(UNSIGNED_TEST_IMG_PATH)?,
         &load_latest_initrd_normal()?,
         &load_trusted_public_key()?,
-        Err(AvbSlotVerifyError::Io),
+        AvbSlotVerifyError::Io,
     )
 }
 
@@ -158,11 +162,11 @@
     let mut kernel = load_latest_signed_kernel()?;
     kernel[1] = !kernel[1]; // Flip the bits
 
-    assert_payload_verification_with_initrd_eq(
+    assert_payload_verification_with_initrd_fails(
         &kernel,
         &load_latest_initrd_normal()?,
         &load_trusted_public_key()?,
-        Err(AvbSlotVerifyError::Verification),
+        AvbSlotVerifyError::Verification,
     )
 }
 
@@ -191,11 +195,11 @@
         // footer is unaligned; copy vbmeta_offset to local variable
         let vbmeta_offset = footer.vbmeta_offset;
         assert_eq!(wrong_offset, vbmeta_offset);
-        assert_payload_verification_with_initrd_eq(
+        assert_payload_verification_with_initrd_fails(
             &kernel,
             &load_latest_initrd_normal()?,
             &load_trusted_public_key()?,
-            Err(AvbSlotVerifyError::Io),
+            AvbSlotVerifyError::Io,
         )?;
     }
     Ok(())
@@ -207,11 +211,11 @@
     let avb_footer_index = kernel.len() - size_of::<AvbFooter>() + RANDOM_FOOTER_POS;
     kernel[avb_footer_index] = !kernel[avb_footer_index];
 
-    assert_payload_verification_with_initrd_eq(
+    assert_payload_verification_with_initrd_fails(
         &kernel,
         &load_latest_initrd_normal()?,
         &load_trusted_public_key()?,
-        Err(AvbSlotVerifyError::InvalidMetadata),
+        AvbSlotVerifyError::InvalidMetadata,
     )
 }
 
@@ -220,11 +224,11 @@
     let mut initrd = load_latest_initrd_normal()?;
     initrd.extend(b"androidboot.vbmeta.digest=1111");
 
-    assert_payload_verification_with_initrd_eq(
+    assert_payload_verification_with_initrd_fails(
         &load_latest_signed_kernel()?,
         &initrd,
         &load_trusted_public_key()?,
-        Err(AvbSlotVerifyError::Verification),
+        AvbSlotVerifyError::Verification,
     )
 }
 
@@ -236,11 +240,11 @@
 
     kernel[vbmeta_index] = !kernel[vbmeta_index]; // Flip the bits
 
-    assert_payload_verification_with_initrd_eq(
+    assert_payload_verification_with_initrd_fails(
         &kernel,
         &load_latest_initrd_normal()?,
         &load_trusted_public_key()?,
-        Err(AvbSlotVerifyError::InvalidMetadata),
+        AvbSlotVerifyError::InvalidMetadata,
     )
 }
 
@@ -259,17 +263,17 @@
     kernel[public_key_offset..(public_key_offset + public_key_size)]
         .copy_from_slice(&empty_public_key);
 
-    assert_payload_verification_with_initrd_eq(
+    assert_payload_verification_with_initrd_fails(
         &kernel,
         &load_latest_initrd_normal()?,
         &empty_public_key,
-        Err(AvbSlotVerifyError::Verification),
+        AvbSlotVerifyError::Verification,
     )?;
-    assert_payload_verification_with_initrd_eq(
+    assert_payload_verification_with_initrd_fails(
         &kernel,
         &load_latest_initrd_normal()?,
         &load_trusted_public_key()?,
-        Err(AvbSlotVerifyError::Verification),
+        AvbSlotVerifyError::Verification,
     )
 }
 
@@ -303,10 +307,10 @@
         AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED, vbmeta_header_flags,
         "VBMeta verification flag should be disabled now."
     );
-    assert_payload_verification_with_initrd_eq(
+    assert_payload_verification_with_initrd_fails(
         &kernel,
         &load_latest_initrd_normal()?,
         &load_trusted_public_key()?,
-        Err(AvbSlotVerifyError::Verification),
+        AvbSlotVerifyError::Verification,
     )
 }
diff --git a/pvmfw/avb/tests/utils.rs b/pvmfw/avb/tests/utils.rs
index 0a2eac6..8756d06 100644
--- a/pvmfw/avb/tests/utils.rs
+++ b/pvmfw/avb/tests/utils.rs
@@ -16,12 +16,13 @@
 
 //! Utility functions used by API tests.
 
-use anyhow::Result;
+use anyhow::{anyhow, Result};
 use avb_bindgen::{
     avb_footer_validate_and_byteswap, avb_vbmeta_image_header_to_host_byte_order, AvbFooter,
     AvbVBMetaImageHeader,
 };
-use pvmfw_avb::{verify_payload, AvbSlotVerifyError, DebugLevel};
+use openssl::sha;
+use pvmfw_avb::{verify_payload, AvbSlotVerifyError, DebugLevel, Digest};
 use std::{
     fs,
     mem::{size_of, transmute, MaybeUninit},
@@ -34,22 +35,22 @@
 
 pub const PUBLIC_KEY_RSA2048_PATH: &str = "data/testkey_rsa2048_pub.bin";
 
-pub fn assert_payload_verification_with_initrd_eq(
+pub fn assert_payload_verification_with_initrd_fails(
     kernel: &[u8],
     initrd: &[u8],
     trusted_public_key: &[u8],
-    expected_result: Result<DebugLevel, AvbSlotVerifyError>,
+    expected_error: AvbSlotVerifyError,
 ) -> Result<()> {
-    assert_payload_verification_eq(kernel, Some(initrd), trusted_public_key, expected_result)
+    assert_payload_verification_fails(kernel, Some(initrd), trusted_public_key, expected_error)
 }
 
-pub fn assert_payload_verification_eq(
+pub fn assert_payload_verification_fails(
     kernel: &[u8],
     initrd: Option<&[u8]>,
     trusted_public_key: &[u8],
-    expected_result: Result<DebugLevel, AvbSlotVerifyError>,
+    expected_error: AvbSlotVerifyError,
 ) -> Result<()> {
-    assert_eq!(expected_result, verify_payload(kernel, initrd, trusted_public_key));
+    assert_eq!(expected_error, verify_payload(kernel, initrd, trusted_public_key).unwrap_err());
     Ok(())
 }
 
@@ -95,3 +96,34 @@
     };
     Ok(vbmeta_header)
 }
+
+pub fn assert_latest_payload_verification_passes(
+    initrd: &[u8],
+    initrd_salt: &[u8],
+    expected_debug_level: DebugLevel,
+) -> Result<()> {
+    let kernel = load_latest_signed_kernel()?;
+    let verified_boot_data = verify_payload(&kernel, Some(initrd), &load_trusted_public_key()?)
+        .map_err(|e| anyhow!("Verification failed. Error: {}", e))?;
+
+    assert_eq!(expected_debug_level, verified_boot_data.debug_level);
+
+    let footer = extract_avb_footer(&kernel)?;
+    assert_eq!(
+        hash(&[&hash(&[b"bootloader"]), &kernel[..usize::try_from(footer.original_image_size)?]]),
+        verified_boot_data.kernel_digest,
+        "Kernel digest is not equal to the expected."
+    );
+    assert_eq!(
+        hash(&[&hash(&[initrd_salt]), initrd,]),
+        verified_boot_data.initrd_digest.unwrap(),
+        "initrd digest is not equal to the expected."
+    );
+    Ok(())
+}
+
+pub fn hash(inputs: &[&[u8]]) -> Digest {
+    let mut digester = sha::Sha256::new();
+    inputs.iter().for_each(|input| digester.update(input));
+    digester.finish()
+}
diff --git a/pvmfw/src/debug_policy.rs b/pvmfw/src/debug_policy.rs
new file mode 100644
index 0000000..37e2af8
--- /dev/null
+++ b/pvmfw/src/debug_policy.rs
@@ -0,0 +1,152 @@
+// Copyright 2023, 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.
+
+//! Support for the debug policy overlay in pvmfw
+
+use alloc::vec;
+use core::ffi::CStr;
+use core::fmt;
+use libfdt::FdtError;
+use log::info;
+
+#[derive(Debug, Clone)]
+pub enum DebugPolicyError {
+    /// The provided baseline FDT was invalid or malformed, so cannot access certain node/prop
+    Fdt(&'static str, FdtError),
+    /// The provided debug policy FDT was invalid or malformed.
+    DebugPolicyFdt(&'static str, FdtError),
+    /// The overlaid result FDT is invalid or malformed, and may be corrupted.
+    OverlaidFdt(&'static str, FdtError),
+}
+
+impl fmt::Display for DebugPolicyError {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match self {
+            Self::Fdt(s, e) => write!(f, "Invalid baseline FDT. {s}: {e}"),
+            Self::DebugPolicyFdt(s, e) => write!(f, "Invalid overlay FDT. {s}: {e}"),
+            Self::OverlaidFdt(s, e) => write!(f, "Invalid overlaid FDT. {s}: {e}"),
+        }
+    }
+}
+
+/// Applies the debug policy device tree overlay to the pVM DT.
+///
+/// # Safety
+///
+/// When an error is returned by this function, the input `Fdt` should be
+/// discarded as it may have have been partially corrupted during the overlay
+/// application process.
+unsafe fn apply_debug_policy(
+    fdt: &mut libfdt::Fdt,
+    debug_policy: &mut [u8],
+) -> Result<(), DebugPolicyError> {
+    let overlay = libfdt::Fdt::from_mut_slice(debug_policy)
+        .map_err(|e| DebugPolicyError::DebugPolicyFdt("Failed to load debug policy overlay", e))?;
+
+    fdt.unpack().map_err(|e| DebugPolicyError::Fdt("Failed to unpack", e))?;
+
+    let fdt = fdt
+        .apply_overlay(overlay)
+        .map_err(|e| DebugPolicyError::DebugPolicyFdt("Failed to apply overlay", e))?;
+
+    fdt.pack().map_err(|e| DebugPolicyError::OverlaidFdt("Failed to re-pack", e))
+}
+
+/// Dsiables ramdump by removing crashkernel from bootargs in /chosen.
+///
+/// # Safety
+///
+/// This may corrupt the input `Fdt` when error happens while editing prop value.
+unsafe fn disable_ramdump(fdt: &mut libfdt::Fdt) -> Result<(), DebugPolicyError> {
+    let chosen_path = CStr::from_bytes_with_nul(b"/chosen\0").unwrap();
+    let bootargs_name = CStr::from_bytes_with_nul(b"bootargs\0").unwrap();
+
+    let chosen = match fdt
+        .node(chosen_path)
+        .map_err(|e| DebugPolicyError::Fdt("Failed to find /chosen", e))?
+    {
+        Some(node) => node,
+        None => return Ok(()),
+    };
+
+    let bootargs = match chosen
+        .getprop_str(bootargs_name)
+        .map_err(|e| DebugPolicyError::Fdt("Failed to find bootargs prop", e))?
+    {
+        Some(value) if !value.to_bytes().is_empty() => value,
+        _ => return Ok(()),
+    };
+
+    // TODO: Improve add 'crashkernel=17MB' only when it's unnecessary.
+    //       Currently 'crashkernel=17MB' in virtualizationservice and passed by
+    //       chosen node, because it's not exactly a debug policy but a
+    //       configuration. However, it's actually microdroid specific
+    //       so we need a way to generalize it.
+    let mut args = vec![];
+    for arg in bootargs.to_bytes().split(|byte| byte.is_ascii_whitespace()) {
+        if arg.is_empty() || arg.starts_with(b"crashkernel=") {
+            continue;
+        }
+        args.push(arg);
+    }
+    let mut new_bootargs = args.as_slice().join(&b" "[..]);
+    new_bootargs.push(b'\0');
+
+    // We've checked existence of /chosen node at the beginning.
+    let mut chosen_mut = fdt.node_mut(chosen_path).unwrap().unwrap();
+    chosen_mut.setprop(bootargs_name, new_bootargs.as_slice()).map_err(|e| {
+        DebugPolicyError::OverlaidFdt("Failed to remove crashkernel. FDT might be corrupted", e)
+    })
+}
+
+/// Returns true only if fdt has ramdump prop in the /avf/guest/common node with value <1>
+fn is_ramdump_enabled(fdt: &libfdt::Fdt) -> Result<bool, DebugPolicyError> {
+    let common = match fdt
+        .node(CStr::from_bytes_with_nul(b"/avf/guest/common\0").unwrap())
+        .map_err(|e| DebugPolicyError::DebugPolicyFdt("Failed to find /avf/guest/common node", e))?
+    {
+        Some(node) => node,
+        None => return Ok(false),
+    };
+
+    match common
+        .getprop_u32(CStr::from_bytes_with_nul(b"ramdump\0").unwrap())
+        .map_err(|e| DebugPolicyError::DebugPolicyFdt("Failed to find ramdump prop", e))?
+    {
+        Some(1) => Ok(true),
+        _ => Ok(false),
+    }
+}
+
+/// Handles debug policies.
+///
+/// # Safety
+///
+/// This may corrupt the input `Fdt` when overlaying debug policy or applying
+/// ramdump configuration.
+pub unsafe fn handle_debug_policy(
+    fdt: &mut libfdt::Fdt,
+    debug_policy: Option<&mut [u8]>,
+) -> Result<(), DebugPolicyError> {
+    if let Some(dp) = debug_policy {
+        apply_debug_policy(fdt, dp)?;
+    }
+
+    // Handles ramdump in the debug policy
+    if is_ramdump_enabled(fdt)? {
+        info!("ramdump is enabled by debug policy");
+        return Ok(());
+    }
+    disable_ramdump(fdt)
+}
diff --git a/pvmfw/src/dice.rs b/pvmfw/src/dice.rs
index b322850..d1ea5f0 100644
--- a/pvmfw/src/dice.rs
+++ b/pvmfw/src/dice.rs
@@ -15,24 +15,40 @@
 //! Support for DICE derivation and BCC generation.
 
 use core::ffi::CStr;
-
+use core::mem::size_of;
 use dice::bcc::format_config_descriptor;
 use dice::bcc::Handover;
 use dice::hash;
 use dice::ConfigType;
 use dice::InputValues;
+use pvmfw_avb::{DebugLevel, Digest, VerifiedBootData};
+
+fn to_dice_mode(debug_level: DebugLevel) -> dice::Mode {
+    match debug_level {
+        DebugLevel::None => dice::Mode::Normal,
+        DebugLevel::Full => dice::Mode::Debug,
+    }
+}
+
+fn to_dice_hash(verified_boot_data: &VerifiedBootData) -> dice::Result<dice::Hash> {
+    let mut digests = [0u8; size_of::<Digest>() * 2];
+    digests[..size_of::<Digest>()].copy_from_slice(&verified_boot_data.kernel_digest);
+    if let Some(initrd_digest) = verified_boot_data.initrd_digest {
+        digests[size_of::<Digest>()..].copy_from_slice(&initrd_digest);
+    }
+    hash(&digests)
+}
 
 /// Derive the VM-specific secrets and certificate through DICE.
 pub fn derive_next_bcc(
     bcc: &Handover,
     next_bcc: &mut [u8],
-    code: &[u8],
-    debug_mode: bool,
+    verified_boot_data: &VerifiedBootData,
     authority: &[u8],
 ) -> dice::Result<usize> {
-    let code_hash = hash(code)?;
+    let code_hash = to_dice_hash(verified_boot_data)?;
     let auth_hash = hash(authority)?;
-    let mode = if debug_mode { dice::Mode::Debug } else { dice::Mode::Normal };
+    let mode = to_dice_mode(verified_boot_data.debug_level);
     let component_name = CStr::from_bytes_with_nul(b"vm_entry\0").unwrap();
     let mut config_descriptor_buffer = [0; 128];
     let config_descriptor_size = format_config_descriptor(
diff --git a/pvmfw/src/entry.rs b/pvmfw/src/entry.rs
index 4f30902..c7ae011 100644
--- a/pvmfw/src/entry.rs
+++ b/pvmfw/src/entry.rs
@@ -15,6 +15,7 @@
 //! Low-level entry and exit points of pvmfw.
 
 use crate::config;
+use crate::debug_policy::{handle_debug_policy, DebugPolicyError};
 use crate::fdt;
 use crate::heap;
 use crate::helpers;
@@ -52,6 +53,16 @@
     SecretDerivationError,
 }
 
+impl From<DebugPolicyError> for RebootReason {
+    fn from(error: DebugPolicyError) -> Self {
+        match error {
+            DebugPolicyError::Fdt(_, _) => RebootReason::InvalidFdt,
+            DebugPolicyError::DebugPolicyFdt(_, _) => RebootReason::InvalidConfig,
+            DebugPolicyError::OverlaidFdt(_, _) => RebootReason::InternalError,
+        }
+    }
+}
+
 main!(start);
 
 /// Entry point for pVM firmware.
@@ -178,37 +189,6 @@
     }
 }
 
-/// Applies the debug policy device tree overlay to the pVM DT.
-///
-/// # Safety
-///
-/// When an error is returned by this function, the input `Fdt` should be discarded as it may have
-/// have been partially corrupted during the overlay application process.
-unsafe fn apply_debug_policy(
-    fdt: &mut libfdt::Fdt,
-    debug_policy: &mut [u8],
-) -> Result<(), RebootReason> {
-    let overlay = libfdt::Fdt::from_mut_slice(debug_policy).map_err(|e| {
-        error!("Failed to load the debug policy overlay: {e}");
-        RebootReason::InvalidConfig
-    })?;
-
-    fdt.unpack().map_err(|e| {
-        error!("Failed to unpack DT for debug policy: {e}");
-        RebootReason::InternalError
-    })?;
-
-    let fdt = fdt.apply_overlay(overlay).map_err(|e| {
-        error!("Failed to apply the debug policy overlay: {e}");
-        RebootReason::InvalidConfig
-    })?;
-
-    fdt.pack().map_err(|e| {
-        error!("Failed to re-pack DT after debug policy: {e}");
-        RebootReason::InternalError
-    })
-}
-
 /// Sets up the environment for main() and wraps its result for start().
 ///
 /// Provide the abstractions necessary for start() to abort the pVM boot and for main() to run with
@@ -283,9 +263,12 @@
     helpers::flushed_zeroize(bcc_slice);
     helpers::flush(slices.fdt.as_slice());
 
-    if let Some(debug_policy) = appended.get_debug_policy() {
-        // SAFETY - As we `?` the result, there is no risk of re-using a bad `slices.fdt`.
-        unsafe { apply_debug_policy(slices.fdt, debug_policy) }?;
+    // SAFETY - As we `?` the result, there is no risk of using a bad `slices.fdt`.
+    unsafe {
+        handle_debug_policy(slices.fdt, appended.get_debug_policy()).map_err(|e| {
+            error!("Unexpected error when handling debug policy: {e:?}");
+            RebootReason::from(e)
+        })?;
     }
 
     info!("Expecting a bug making MMIO_GUARD_UNMAP return NOT_SUPPORTED on success");
diff --git a/pvmfw/src/main.rs b/pvmfw/src/main.rs
index eabdfe8..be5a16a 100644
--- a/pvmfw/src/main.rs
+++ b/pvmfw/src/main.rs
@@ -21,6 +21,7 @@
 extern crate alloc;
 
 mod config;
+mod debug_policy;
 mod dice;
 mod entry;
 mod exceptions;
@@ -78,28 +79,11 @@
     let mut pci_root = pci::initialise(pci_info, memory)?;
     find_virtio_devices(&mut pci_root).map_err(handle_pci_error)?;
 
-    verify_payload(signed_kernel, ramdisk, PUBLIC_KEY).map_err(|e| {
+    let verified_boot_data = verify_payload(signed_kernel, ramdisk, PUBLIC_KEY).map_err(|e| {
         error!("Failed to verify the payload: {e}");
         RebootReason::PayloadVerificationError
     })?;
 
-    let debug_mode = false; // TODO(b/256148034): Derive the DICE mode from the received initrd.
-    const HASH_SIZE: usize = 64;
-    let mut hashes = [0; HASH_SIZE * 2]; // TODO(b/256148034): Extract AvbHashDescriptor digests.
-    hashes[..HASH_SIZE].copy_from_slice(&::dice::hash(signed_kernel).map_err(|_| {
-        error!("Failed to hash the kernel");
-        RebootReason::InternalError
-    })?);
-    // Note: Using signed_kernel currently makes the DICE code input depend on its VBMeta fields.
-    let code_hash = if let Some(rd) = ramdisk {
-        hashes[HASH_SIZE..].copy_from_slice(&::dice::hash(rd).map_err(|_| {
-            error!("Failed to hash the ramdisk");
-            RebootReason::InternalError
-        })?);
-        &hashes[..]
-    } else {
-        &hashes[..HASH_SIZE]
-    };
     let next_bcc = heap::aligned_boxed_slice(NEXT_BCC_SIZE, GUEST_PAGE_SIZE).ok_or_else(|| {
         error!("Failed to allocate the next-stage BCC");
         RebootReason::InternalError
@@ -107,7 +91,7 @@
     // By leaking the slice, its content will be left behind for the next stage.
     let next_bcc = Box::leak(next_bcc);
     let next_bcc_size =
-        derive_next_bcc(bcc, next_bcc, code_hash, debug_mode, PUBLIC_KEY).map_err(|e| {
+        derive_next_bcc(bcc, next_bcc, &verified_boot_data, PUBLIC_KEY).map_err(|e| {
             error!("Failed to derive next-stage DICE secrets: {e:?}");
             RebootReason::SecretDerivationError
         })?;
diff --git a/tests/hostside/java/com/android/microdroid/test/MicrodroidHostTests.java b/tests/hostside/java/com/android/microdroid/test/MicrodroidHostTests.java
index 112041b..0623ff2 100644
--- a/tests/hostside/java/com/android/microdroid/test/MicrodroidHostTests.java
+++ b/tests/hostside/java/com/android/microdroid/test/MicrodroidHostTests.java
@@ -509,7 +509,7 @@
         assertThatEventually(
                 100000,
                 () -> getDevice().pullFileContents(CONSOLE_PATH),
-                containsString("init: [libfs_avb]Failed to verify vbmeta digest"));
+                containsString("init: [libfs_avb] Failed to verify vbmeta digest"));
         vmInfo.mProcess.destroy();
     }