Run app payloads as non-root.

This is in preparation before moving to running multiple payload
processes in multiple UIDs.

Add a new payload user and group in the system-reserved range, only
within Microdroid, and assign them to the payload process. Fix up a
bunch of DAC permissions to make sure the payload still has access to
the things it should have.

Add a test to check we aren't running as root, and make some minor
test fixes.

This is a potentially breaking change, so for now I've disabled it via
Rust conditional compilation (and marked the new test as @Ignore). I
claim the changes that aren't protected by this are harmless.

I've run tests with and without the cfg option enabled.

Unrelated changes done in passing:
- Move a comment from reference to definition.
- Make sure encryptedstore logs any errors in full.
- Use with_context in a few more places.

Bug: 296393106
Test: atest MicrodroidTests
Change-Id: I6648580615a9fce906dd170f999e11f63e5874d9
diff --git a/encryptedstore/src/main.rs b/encryptedstore/src/main.rs
index 1a16f49..2a698ea 100644
--- a/encryptedstore/src/main.rs
+++ b/encryptedstore/src/main.rs
@@ -21,24 +21,32 @@
 use anyhow::{ensure, Context, Result};
 use clap::arg;
 use dm::{crypt::CipherType, util};
-use log::info;
+use log::{error, info};
 use std::ffi::CString;
 use std::fs::{create_dir_all, OpenOptions};
 use std::io::{Error, Read, Write};
 use std::os::unix::ffi::OsStrExt;
-use std::os::unix::fs::FileTypeExt;
+use std::os::unix::fs::{FileTypeExt, PermissionsExt};
 use std::path::{Path, PathBuf};
 use std::process::Command;
 
 const MK2FS_BIN: &str = "/system/bin/mke2fs";
 const UNFORMATTED_STORAGE_MAGIC: &str = "UNFORMATTED-STORAGE";
 
-fn main() -> Result<()> {
+fn main() {
     android_logger::init_once(
         android_logger::Config::default()
             .with_tag("encryptedstore")
             .with_min_level(log::Level::Info),
     );
+
+    if let Err(e) = try_main() {
+        error!("{:?}", e);
+        std::process::exit(1)
+    }
+}
+
+fn try_main() -> Result<()> {
     info!("Starting encryptedstore binary");
 
     let matches = clap_command().get_matches();
@@ -47,10 +55,12 @@
     let key = matches.get_one::<String>("key").unwrap();
     let mountpoint = Path::new(matches.get_one::<String>("mountpoint").unwrap());
     // Note this error context is used in MicrodroidTests.
-    encryptedstore_init(blkdevice, key, mountpoint).context(format!(
-        "Unable to initialize encryptedstore on {:?} & mount at {:?}",
-        blkdevice, mountpoint
-    ))?;
+    encryptedstore_init(blkdevice, key, mountpoint).with_context(|| {
+        format!(
+            "Unable to initialize encryptedstore on {:?} & mount at {:?}",
+            blkdevice, mountpoint
+        )
+    })?;
     Ok(())
 }
 
@@ -65,7 +75,7 @@
 fn encryptedstore_init(blkdevice: &Path, key: &str, mountpoint: &Path) -> Result<()> {
     ensure!(
         std::fs::metadata(blkdevice)
-            .context(format!("Failed to get metadata of {:?}", blkdevice))?
+            .with_context(|| format!("Failed to get metadata of {:?}", blkdevice))?
             .file_type()
             .is_block_device(),
         "The path:{:?} is not of a block device",
@@ -82,7 +92,12 @@
         info!("Freshly formatting the crypt device");
         format_ext4(&crypt_device)?;
     }
-    mount(&crypt_device, mountpoint).context(format!("Unable to mount {:?}", crypt_device))?;
+    mount(&crypt_device, mountpoint)
+        .with_context(|| format!("Unable to mount {:?}", crypt_device))?;
+    if needs_formatting {
+        std::fs::set_permissions(mountpoint, PermissionsExt::from_mode(0o770))
+            .context("Failed to chmod root directory")?;
+    }
     Ok(())
 }
 
@@ -124,6 +139,11 @@
 }
 
 fn format_ext4(device: &Path) -> Result<()> {
+    let root_dir_uid_gid = format!(
+        "root_owner={}:{}",
+        microdroid_uids::ROOT_UID,
+        microdroid_uids::MICRODROID_PAYLOAD_GID
+    );
     let mkfs_options = [
         "-j", // Create appropriate sized journal
         /* metadata_csum: enabled for filesystem integrity
@@ -131,20 +151,22 @@
          * 64bit: larger fields afforded by this feature enable full-strength checksumming.
          */
         "-O metadata_csum, extents, 64bit",
-        "-b 4096", // block size in the filesystem
+        "-b 4096", // block size in the filesystem,
+        "-E",
+        &root_dir_uid_gid,
     ];
     let mut cmd = Command::new(MK2FS_BIN);
     let status = cmd
         .args(mkfs_options)
         .arg(device)
         .status()
-        .context(format!("failed to execute {}", MK2FS_BIN))?;
+        .with_context(|| format!("failed to execute {}", MK2FS_BIN))?;
     ensure!(status.success(), "mkfs failed with {:?}", status);
     Ok(())
 }
 
 fn mount(source: &Path, mountpoint: &Path) -> Result<()> {
-    create_dir_all(mountpoint).context(format!("Failed to create {:?}", &mountpoint))?;
+    create_dir_all(mountpoint).with_context(|| format!("Failed to create {:?}", &mountpoint))?;
     let mount_options = CString::new(
         "fscontext=u:object_r:encryptedstore_fs:s0,context=u:object_r:encryptedstore_file:s0",
     )