diff --git a/userspace/ksud/Cargo.lock b/userspace/ksud/Cargo.lock index 288e0d31..b22639b7 100644 --- a/userspace/ksud/Cargo.lock +++ b/userspace/ksud/Cargo.lock @@ -1032,9 +1032,9 @@ dependencies = [ [[package]] name = "sys-mount" -version = "2.0.1" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793d38aa916d55e979587ea7cf551106f5f091e548a91e89ee4f0698bc9cf289" +checksum = "d8b080a2fff4d267282506b4d5f2efe0dfa732fb2a5715f30662eed1c4f13390" dependencies = [ "bitflags", "libc", diff --git a/userspace/ksud/Cargo.toml b/userspace/ksud/Cargo.toml index 499b7744..bc184ebd 100644 --- a/userspace/ksud/Cargo.toml +++ b/userspace/ksud/Cargo.toml @@ -22,14 +22,16 @@ encoding = "0.2.33" retry = "2.0.0" humansize = "2.0.0" libc = "0.2" -sys-mount = "2.0.1" -android-properties = { version = "0.2.2", features = ["bionic-deprecated"] } extattr = "1.0.0" jwalk = "0.8.1" is_executable = "1.0.1" nom = "7" derive-new = "0.5" +[target.'cfg(target_os = "android")'.dependencies] +sys-mount = "2.0.1" +android-properties = { version = "0.2.2", features = ["bionic-deprecated"] } + [profile.release] strip = true opt-level = "z" diff --git a/userspace/ksud/src/apk_sign.rs b/userspace/ksud/src/apk_sign.rs index 3968e27e..780ac620 100644 --- a/userspace/ksud/src/apk_sign.rs +++ b/userspace/ksud/src/apk_sign.rs @@ -23,7 +23,7 @@ pub fn get_apk_signature(apk: &str) -> Result<(u32, u32)> { if u32::from_le_bytes(size4) ^ 0xcafebabeu32 == 0xccfbf1eeu32 { if i > 0 { - println!("warning: comment length is {}", i); + println!("warning: comment length is {i}"); } break; } diff --git a/userspace/ksud/src/event.rs b/userspace/ksud/src/event.rs index 8f674b4e..a4009c24 100644 --- a/userspace/ksud/src/event.rs +++ b/userspace/ksud/src/event.rs @@ -1,22 +1,21 @@ use std::{collections::HashMap, path::Path}; use crate::{ - assets, defs, - utils::{ensure_clean_dir, ensure_dir_exists, mount_image}, + assets, defs, mount, + utils::{ensure_clean_dir, ensure_dir_exists}, }; use anyhow::{bail, Context, Result}; -use sys_mount::{FilesystemType, Mount, MountFlags}; -fn mount_partition(partition: &str, lowerdir: &mut Vec) { +fn mount_partition(partition: &str, lowerdir: &mut Vec) -> Result<()> { if lowerdir.is_empty() { println!("partition: {partition} lowerdir is empty"); - return; + return Ok(()); } // if /partition is a symlink and linked to /system/partition, then we don't need to overlay it separately if Path::new(&format!("/{}", partition)).read_link().is_ok() { println!("partition: {} is a symlink", partition); - return; + return Ok(()); } // add /partition as the lowerest dir let lowest_dir = format!("/{partition}"); @@ -25,14 +24,7 @@ fn mount_partition(partition: &str, lowerdir: &mut Vec) { let lowerdir = lowerdir.join(":"); println!("partition: {partition} lowerdir: {lowerdir}"); - if let Err(err) = Mount::builder() - .fstype(FilesystemType::from("overlay")) - .flags(MountFlags::RDONLY) - .data(&format!("lowerdir={lowerdir}")) - .mount("overlay", lowest_dir) - { - println!("mount partition: {partition} overlay failed: {err}"); - } + mount::mount_overlay(&lowerdir, &lowest_dir) } pub fn do_systemless_mount(module_dir: &str) -> Result<()> { @@ -82,11 +74,11 @@ pub fn do_systemless_mount(module_dir: &str) -> Result<()> { } // mount /system first - mount_partition("system", &mut system_lowerdir); + let _ = mount_partition("system", &mut system_lowerdir); // mount other partitions for (k, mut v) in partition_lowerdir { - mount_partition(&k, &mut v); + let _ = mount_partition(&k, &mut v); } Ok(()) @@ -127,7 +119,7 @@ pub fn on_post_data_fs() -> Result<()> { } println!("mount {} to {}", target_update_img, module_dir); - mount_image(target_update_img, module_dir)?; + mount::mount_ext4(target_update_img, module_dir)?; // load sepolicy.rule if crate::module::load_sepolicy_rule().is_err() { diff --git a/userspace/ksud/src/main.rs b/userspace/ksud/src/main.rs index ceaaaca7..5b6d8df8 100644 --- a/userspace/ksud/src/main.rs +++ b/userspace/ksud/src/main.rs @@ -9,6 +9,7 @@ mod restorecon; mod utils; mod sepolicy; mod assets; +mod mount; fn main() -> anyhow::Result<()> { cli::run() diff --git a/userspace/ksud/src/module.rs b/userspace/ksud/src/module.rs index 457b5b42..e3748775 100644 --- a/userspace/ksud/src/module.rs +++ b/userspace/ksud/src/module.rs @@ -4,6 +4,7 @@ use crate::{ sepolicy, utils::*, assets, + mount, }; use const_format::concatcp; @@ -430,7 +431,7 @@ pub fn install_module(zip: String) -> Result<()> { // mount the modules_update.img to mountpoint println!("- Mounting image"); - mount_image(tmp_module_img, module_update_tmp_dir)?; + mount::mount_ext4(tmp_module_img, module_update_tmp_dir)?; setsyscon(module_update_tmp_dir)?; @@ -457,7 +458,7 @@ pub fn install_module(zip: String) -> Result<()> { }; // umount the modules_update.img - let _ = umount_dir(module_update_tmp_dir); + let _ = mount::umount_dir(module_update_tmp_dir); // remove modules_update dir, ignore the error let _ = remove_dir_all(module_update_tmp_dir); @@ -506,13 +507,13 @@ where ensure_clean_dir(update_dir)?; // mount the modules_update img - mount_image(defs::MODULE_UPDATE_TMP_IMG, update_dir)?; + mount::mount_ext4(defs::MODULE_UPDATE_TMP_IMG, update_dir)?; // call the operation func let result = func(id, update_dir); // umount modules_update.img - let _ = umount_dir(update_dir); + let _ = mount::umount_dir(update_dir); let _ = remove_dir_all(update_dir); std::fs::rename(modules_update_tmp_img, defs::MODULE_UPDATE_IMG)?; diff --git a/userspace/ksud/src/mount.rs b/userspace/ksud/src/mount.rs new file mode 100644 index 00000000..59a8ba8f --- /dev/null +++ b/userspace/ksud/src/mount.rs @@ -0,0 +1,58 @@ +use anyhow::Result; + +#[cfg(target_os = "android")] +use anyhow::{ensure, Context, Ok}; +#[cfg(target_os = "android")] +use retry::delay::NoDelay; +#[cfg(target_os = "android")] +use sys_mount::{unmount, FilesystemType, Mount, MountFlags, UnmountFlags}; + +#[cfg(target_os = "android")] +fn do_mount_image(src: &str, target: &str) -> Result<()> { + Mount::builder() + .fstype(FilesystemType::from("ext4")) + .mount(src, target) + .with_context(|| format!("Failed to do mount: {src} -> {target}"))?; + Ok(()) +} + +#[cfg(target_os = "android")] +pub fn mount_ext4(src: &str, target: &str) -> Result<()> { + // umount target first. + let _ = umount_dir(target); + let result = retry::retry(NoDelay.take(3), || do_mount_image(src, target)); + ensure!(result.is_ok(), "Failed to mount {} -> {}", src, target); + Ok(()) +} + +#[cfg(target_os = "android")] +pub fn umount_dir(src: &str) -> Result<()> { + unmount(src, UnmountFlags::empty()).with_context(|| format!("Failed to umount {src}"))?; + Ok(()) +} + +#[cfg(target_os = "android")] +pub fn mount_overlay(lowerdir: &str, mnt: &str) -> Result<()> { + Mount::builder() + .fstype(FilesystemType::from("overlay")) + .flags(MountFlags::RDONLY) + .data(&format!("lowerdir={lowerdir}")) + .mount("overlay", mnt) + .map(|_| ()) + .map_err(|e| anyhow::anyhow!("mount partition: {mnt} overlay failed: {e}")) +} + +#[cfg(not(target_os = "android"))] +pub fn mount_ext4(src: &str, target: &str) -> Result<()> { + unimplemented!() +} + +#[cfg(not(target_os = "android"))] +pub fn umount_dir(src: &str) -> Result<()> { + unimplemented!() +} + +#[cfg(not(target_os = "android"))] +pub fn mount_overlay(lowerdir: &str, mnt: &str) -> Result<()> { + unimplemented!() +} diff --git a/userspace/ksud/src/restorecon.rs b/userspace/ksud/src/restorecon.rs index 81301b84..5adceeb0 100644 --- a/userspace/ksud/src/restorecon.rs +++ b/userspace/ksud/src/restorecon.rs @@ -1,4 +1,5 @@ use anyhow::{Context, Ok, Result}; +#[cfg(target_os = "android")] use extattr::{setxattr, Flags as XattrFlags}; use jwalk::{Parallelism::Serial, WalkDir}; @@ -6,6 +7,7 @@ const SYSTEM_CON: &str = "u:object_r:system_file:s0"; const _ADB_CON: &str = "u:object_r:adb_data_file:s0"; pub fn setcon(path: &str, con: &str) -> Result<()> { + #[cfg(target_os = "android")] setxattr(path, "security.selinux", con, XattrFlags::empty()) .with_context(|| format!("Failed to change SELinux context for {path}"))?; Ok(()) @@ -18,6 +20,7 @@ pub fn setsyscon(path: &str) -> Result<()> { pub fn restore_syscon(dir: &str) -> Result<()> { for dir_entry in WalkDir::new(dir).parallelism(Serial) { if let Some(path) = dir_entry.ok().map(|dir_entry| dir_entry.path()) { + #[cfg(target_os = "android")] setxattr(&path, "security.selinux", SYSTEM_CON, XattrFlags::empty()).with_context( || { format!( diff --git a/userspace/ksud/src/sepolicy.rs b/userspace/ksud/src/sepolicy.rs index 0130864b..88b6e190 100644 --- a/userspace/ksud/src/sepolicy.rs +++ b/userspace/ksud/src/sepolicy.rs @@ -11,7 +11,7 @@ use nom::{ sequence::Tuple, IResult, Parser, }; -use std::{vec, path::Path}; +use std::{path::Path, vec}; type SeObject<'a> = Vec<&'a str>; @@ -692,6 +692,7 @@ impl From for FfiPolicy { } } +#[cfg(target_os = "android")] fn apply_one_rule<'a>(statement: &'a PolicyStatement<'a>) -> Result<()> { let policies: Vec = statement.try_into()?; @@ -716,6 +717,11 @@ fn apply_one_rule<'a>(statement: &'a PolicyStatement<'a>) -> Result<()> { Ok(()) } +#[cfg(not(target_os = "android"))] +fn apply_one_rule<'a>(statement: &'a PolicyStatement<'a>) -> Result<()> { + unimplemented!() +} + pub fn live_patch(policy: &str) -> Result<()> { let result = parse_sepolicy(policy.trim())?; for statement in result { diff --git a/userspace/ksud/src/utils.rs b/userspace/ksud/src/utils.rs index d749557d..9b4a8766 100644 --- a/userspace/ksud/src/utils.rs +++ b/userspace/ksud/src/utils.rs @@ -1,33 +1,10 @@ -use anyhow::{bail, ensure, Context, Error, Ok, Result}; -use retry::delay::NoDelay; +use anyhow::{bail, Context, Error, Ok, Result}; use std::{ fs::{create_dir_all, set_permissions, write, File, Permissions}, io::ErrorKind::AlreadyExists, os::unix::prelude::PermissionsExt, path::Path, }; -use sys_mount::{unmount, FilesystemType, Mount, UnmountFlags}; - -fn do_mount_image(src: &str, target: &str) -> Result<()> { - Mount::builder() - .fstype(FilesystemType::from("ext4")) - .mount(src, target) - .with_context(|| format!("Failed to do mount: {src} -> {target}"))?; - Ok(()) -} - -pub fn mount_image(src: &str, target: &str) -> Result<()> { - // umount target first. - let _ = umount_dir(target); - let result = retry::retry(NoDelay.take(3), || do_mount_image(src, target)); - ensure!(result.is_ok(), "Failed to mount {} -> {}", src, target); - Ok(()) -} - -pub fn umount_dir(src: &str) -> Result<()> { - unmount(src, UnmountFlags::empty()).with_context(|| format!("Failed to umount {src}"))?; - Ok(()) -} pub fn ensure_clean_dir(dir: &str) -> Result<()> { let path = Path::new(dir); @@ -83,10 +60,16 @@ pub fn ensure_binary>(path: T, contents: &[u8]) -> Result<()> { Ok(()) } +#[cfg(target_os = "android")] pub fn getprop(prop: &str) -> Option { android_properties::getprop(prop).value() } +#[cfg(not(target_os = "android"))] +pub fn getprop(prop: &str) -> Option { + unimplemented!() +} + pub fn is_safe_mode() -> bool { getprop("persist.sys.safemode") .filter(|prop| prop == "1")