libfdt: Make Libfdt::string() actually safe

Instead of blindly trusting that the C code has returned a properly
NULL-terminated C string[*], limit the CStr constructor to whatever
bytes are available between the returned pointer and the end of the DT
slice, which hardens the function by:

 - Avoiding UB if CStr::from_ptr wasn't passed a valid C string;
 - Avoiding OOB in CStr::from_bytes_until_nul by passing a DT sub-slice.

Test: m pvmfw
Test: atest liblibfdt.integration_test
Change-Id: I56daa3360c8556e7e210d2c53fcea1a332268828
diff --git a/libs/libfdt/src/libfdt.rs b/libs/libfdt/src/libfdt.rs
index bb26e53..a89738f 100644
--- a/libs/libfdt/src/libfdt.rs
+++ b/libs/libfdt/src/libfdt.rs
@@ -215,12 +215,10 @@
         let fdt = self.as_fdt_slice().as_ptr().cast();
         // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
         let ptr = unsafe { libfdt_bindgen::fdt_string(fdt, offset) };
-        if ptr.is_null() {
-            return Err(FdtError::Internal);
-        }
+        let bytes =
+            get_slice_from_ptr(self.as_fdt_slice(), ptr.cast()).ok_or(FdtError::Internal)?;
 
-        // SAFETY: Non-null return from fdt_string() is valid null-terminating string within FDT.
-        Ok(unsafe { CStr::from_ptr(ptr) })
+        CStr::from_bytes_until_nul(bytes).map_err(|_| FdtError::Internal)
     }
 }
 
@@ -271,6 +269,10 @@
     s.get(offset..offset.checked_add(len)?)
 }
 
+fn get_slice_from_ptr(s: &[u8], p: *const u8) -> Option<&[u8]> {
+    s.get(get_slice_ptr_offset(s, p)?..)
+}
+
 fn get_slice_ptr_offset(s: &[u8], p: *const u8) -> Option<usize> {
     s.as_ptr_range().contains(&p).then(|| {
         // SAFETY: Both pointers are in bounds, derive from the same object, and size_of::<T>()=1.