libfdt: Make unsafe API for DT cloning safe

The Fdt::copy_from_slice() was unsound as it allowed client code to
bypass the (safe) constructor (which validates the class invariant) and
provide arbitrary bytes that would then be available as a "safe" (but
not actually) &Fdt. Instead of marking that API unsafe (which it should
have been), rework it into a safe API taking a &Self, meaning that the
invariant has already been validated for the input.

Update callers to use the new API. In particular, note that this change
forces one of them to be marked unsafe (which is good!).

Test: m pvmfw
Test: atest liblibfdt.integration_test
Change-Id: I7d2d8ecb85c26f5644ca26330c057568a75656ce
diff --git a/libs/libfdt/src/lib.rs b/libs/libfdt/src/lib.rs
index 3248397..39749f0 100644
--- a/libs/libfdt/src/lib.rs
+++ b/libs/libfdt/src/lib.rs
@@ -24,7 +24,6 @@
     PropertyIterator, RangesIterator, Reg, RegIterator, SubnodeIterator,
 };
 
-use core::cmp::max;
 use core::ffi::{c_int, c_void, CStr};
 use core::fmt;
 use core::ops::Range;
@@ -1002,19 +1001,22 @@
         unsafe { &mut *self_mut_ptr }
     }
 
-    /// Updates this FDT from a slice containing another FDT.
-    pub fn copy_from_slice(&mut self, new_fdt: &[u8]) -> Result<()> {
-        if self.buffer.len() < new_fdt.len() {
-            Err(FdtError::NoSpace)
-        } else {
-            let totalsize = self.totalsize();
-            self.buffer[..new_fdt.len()].clone_from_slice(new_fdt);
-            // Zeroize the remaining part. We zeroize up to the size of the original DT because
-            // zeroizing the entire buffer (max 2MB) is not necessary and may increase the VM boot
-            // time.
-            self.buffer[new_fdt.len()..max(new_fdt.len(), totalsize)].fill(0_u8);
-            Ok(())
+    /// Updates this FDT from another FDT.
+    pub fn clone_from(&mut self, other: &Self) -> Result<()> {
+        let new_len = other.buffer.len();
+        if self.buffer.len() < new_len {
+            return Err(FdtError::NoSpace);
         }
+
+        let zeroed_len = self.totalsize().checked_sub(new_len);
+        let (cloned, zeroed) = self.buffer.split_at_mut(new_len);
+
+        cloned.clone_from_slice(&other.buffer);
+        if let Some(len) = zeroed_len {
+            zeroed[..len].fill(0);
+        }
+
+        Ok(())
     }
 
     /// Unpacks the DT to cover the whole slice it is contained in.