Move cursor to start after truncating the file
File::set_len(0), while reducing the file to size 0, does not move the
cursor, which will then be past the end with undefined behavior. Fix
this by explicitly using File::seek(_, start).
Bug: 322794510
Test: #test_create_or_update_idsig_on_non_empty_file
Change-Id: I1ad648ae3bcf1552921430b8dd95d36ad8a3e1bf
diff --git a/virtualizationmanager/src/aidl.rs b/virtualizationmanager/src/aidl.rs
index 2603e77..34994f8 100644
--- a/virtualizationmanager/src/aidl.rs
+++ b/virtualizationmanager/src/aidl.rs
@@ -82,7 +82,7 @@
use std::convert::TryInto;
use std::ffi::{CStr, CString};
use std::fs::{canonicalize, read_dir, remove_file, File, OpenOptions};
-use std::io::{BufRead, BufReader, Error, ErrorKind, Write};
+use std::io::{BufRead, BufReader, Error, ErrorKind, Seek, SeekFrom, Write};
use std::iter;
use std::num::{NonZeroU16, NonZeroU32};
use std::os::unix::io::{FromRawFd, IntoRawFd};
@@ -159,6 +159,9 @@
// We will anyway overwrite the file to the v4signature generated from input_fd.
}
+ output
+ .seek(SeekFrom::Start(0))
+ .context("failed to move cursor to start on the idsig output")?;
output.set_len(0).context("failed to set_len on the idsig output")?;
sig.write_into(&mut output).context("failed to write idsig")?;
Ok(())
@@ -243,9 +246,14 @@
.with_context(|| format!("Invalid size: {}", size_bytes))
.or_binder_exception(ExceptionCode::ILLEGAL_ARGUMENT)?;
let size_bytes = round_up(size_bytes, PARTITION_GRANULARITY_BYTES);
- let image = clone_file(image_fd)?;
+ let mut image = clone_file(image_fd)?;
// initialize the file. Any data in the file will be erased.
+ image
+ .seek(SeekFrom::Start(0))
+ .context("failed to move cursor to start")
+ .or_service_specific_exception(-1)?;
image.set_len(0).context("Failed to reset a file").or_service_specific_exception(-1)?;
+
let mut part = QcowFile::new(image, size_bytes)
.context("Failed to create QCOW2 image")
.or_service_specific_exception(-1)?;
@@ -1545,6 +1553,40 @@
}
#[test]
+ fn test_create_or_update_idsig_on_non_empty_file() -> Result<()> {
+ use std::io::Read;
+
+ // Pick any APK
+ let mut apk = File::open("/system/priv-app/Shell/Shell.apk").unwrap();
+ let idsig_empty = tempfile::tempfile().unwrap();
+ let mut idsig_invalid = tempfile::tempfile().unwrap();
+ idsig_invalid.write_all(b"Oops")?;
+
+ // Create new idsig
+ create_or_update_idsig_file(
+ &ParcelFileDescriptor::new(apk.try_clone()?),
+ &ParcelFileDescriptor::new(idsig_empty.try_clone()?),
+ )?;
+ apk.rewind()?;
+
+ // Update idsig_invalid
+ create_or_update_idsig_file(
+ &ParcelFileDescriptor::new(apk.try_clone()?),
+ &ParcelFileDescriptor::new(idsig_invalid.try_clone()?),
+ )?;
+
+ // Ensure the 2 idsig files have same size!
+ assert!(
+ idsig_empty.metadata()?.len() == idsig_invalid.metadata()?.len(),
+ "idsig files differ in size"
+ );
+ // Ensure the 2 idsig files have same content!
+ for (b1, b2) in idsig_empty.bytes().zip(idsig_invalid.bytes()) {
+ assert!(b1.unwrap() == b2.unwrap(), "idsig files differ")
+ }
+ Ok(())
+ }
+ #[test]
fn test_append_kernel_param_first_param() {
let mut vm_config = VirtualMachineRawConfig { ..Default::default() };
append_kernel_param("foo=1", &mut vm_config);