diff --git a/adb_cli/src/models/adb_cli_error.rs b/adb_cli/src/models/adb_cli_error.rs index beb4ca79..e2f137cb 100644 --- a/adb_cli/src/models/adb_cli_error.rs +++ b/adb_cli/src/models/adb_cli_error.rs @@ -37,7 +37,6 @@ impl From for ADBCliError { let value = Box::new(value); match value.as_ref() { - // List of [`RustADBError`] that may need an issue as abnormal RustADBError::RegexParsingError | RustADBError::WrongResponseReceived(_, _) | RustADBError::FramebufferImageError(_) @@ -68,8 +67,8 @@ impl From for ADBCliError { | RustADBError::MDNSError(_) | RustADBError::SendError | RustADBError::UnknownFileMode(_) - | RustADBError::UnknownTransport(_) => Self::MayNeedAnIssue(value), - // List of [`RustADBError`] that may occur in standard contexts and therefore do not require for issues + | RustADBError::UnknownTransport(_) + | RustADBError::RemountError(_) => Self::MayNeedAnIssue(value), RustADBError::ADBDeviceNotPaired | RustADBError::UnknownResponseType(_) | RustADBError::DeviceNotFound(_) diff --git a/adb_client/src/adb_device_ext.rs b/adb_client/src/adb_device_ext.rs index 0515be32..1c8f57bd 100644 --- a/adb_client/src/adb_device_ext.rs +++ b/adb_client/src/adb_device_ext.rs @@ -3,7 +3,7 @@ use std::path::Path; use image::{ImageBuffer, ImageFormat, Rgba}; -use crate::models::{ADBListItemType, AdbStatResponse}; +use crate::models::{ADBListItemType, AdbStatResponse, RemountInfo}; use crate::{RebootType, Result}; /// Trait representing all features available on ADB devices. @@ -30,6 +30,9 @@ pub trait ADBDeviceExt { /// Reboot the device using given reboot type fn reboot(&mut self, reboot_type: RebootType) -> Result<()>; + /// Remount the device partitions as read-write + fn remount(&mut self) -> Result>; + /// Run `activity` from `package` on device. Return the command output. fn run_activity( &mut self, @@ -60,6 +63,12 @@ pub trait ADBDeviceExt { /// Uninstall the package `package` from device. fn uninstall(&mut self, package: &dyn AsRef) -> Result<()>; + /// Enable dm-verity on the device + fn enable_verity(&mut self) -> Result<()>; + + /// Disable dm-verity on the device + fn disable_verity(&mut self) -> Result<()>; + /// Inner method requesting framebuffer from an Android device fn framebuffer_inner(&mut self) -> Result, Vec>>; diff --git a/adb_client/src/error.rs b/adb_client/src/error.rs index 837ac053..39e76da3 100644 --- a/adb_client/src/error.rs +++ b/adb_client/src/error.rs @@ -54,6 +54,9 @@ pub enum RustADBError { /// Indicates that the device must be paired before attempting a connection over WI-FI #[error("Device not paired before attempting to connect")] ADBDeviceNotPaired, + /// Indicates that remount operation failed + #[error("Cannot remount filesystem: {0}")] + RemountError(String), /// An error occurred when getting device's framebuffer image #[error(transparent)] FramebufferImageError(#[from] image::error::ImageError), diff --git a/adb_client/src/message_devices/adb_message_device_commands.rs b/adb_client/src/message_devices/adb_message_device_commands.rs index 0a9065dd..679fd137 100644 --- a/adb_client/src/message_devices/adb_message_device_commands.rs +++ b/adb_client/src/message_devices/adb_message_device_commands.rs @@ -3,7 +3,7 @@ use crate::{ message_devices::{ adb_message_device::ADBMessageDevice, adb_message_transport::ADBMessageTransport, }, - models::AdbStatResponse, + models::{AdbStatResponse, RemountInfo}, }; use std::{ io::{Read, Write}, @@ -41,6 +41,11 @@ impl ADBDeviceExt for ADBMessageDevice { self.reboot(reboot_type) } + #[inline] + fn remount(&mut self) -> Result> { + self.remount() + } + #[inline] fn install(&mut self, apk_path: &dyn AsRef) -> Result<()> { self.install(apk_path) @@ -51,6 +56,16 @@ impl ADBDeviceExt for ADBMessageDevice { self.uninstall(package) } + #[inline] + fn enable_verity(&mut self) -> Result<()> { + self.enable_verity() + } + + #[inline] + fn disable_verity(&mut self) -> Result<()> { + self.disable_verity() + } + #[inline] fn framebuffer_inner(&mut self) -> Result, Vec>> { self.framebuffer_inner() diff --git a/adb_client/src/message_devices/commands/mod.rs b/adb_client/src/message_devices/commands/mod.rs index 24de463e..9d0cf1d0 100644 --- a/adb_client/src/message_devices/commands/mod.rs +++ b/adb_client/src/message_devices/commands/mod.rs @@ -4,7 +4,9 @@ mod list; mod pull; mod push; mod reboot; +mod remount; mod shell; mod stat; mod uninstall; mod utils; +mod verity; diff --git a/adb_client/src/message_devices/commands/remount.rs b/adb_client/src/message_devices/commands/remount.rs new file mode 100644 index 00000000..c8b46191 --- /dev/null +++ b/adb_client/src/message_devices/commands/remount.rs @@ -0,0 +1,34 @@ +use crate::{ + Result, + message_devices::{ + adb_message_device::ADBMessageDevice, adb_message_transport::ADBMessageTransport, + message_commands::MessageCommand, + }, + models::RemountInfo, +}; + +impl ADBMessageDevice { + pub(crate) fn remount(&mut self) -> Result> { + self.open_session(b"remount:\0")?; + + let response = self.get_transport_mut().read_message()?; + + response.assert_command(MessageCommand::Okay)?; + + let mut response_str: Vec = Vec::new(); + loop { + let response = self.get_transport_mut().read_message()?; + + if response.header().command() != MessageCommand::Write { + break; + } + + let payload_str = String::from_utf8_lossy(response.payload()); + let payload_str = payload_str.trim(); + + response_str.push(payload_str.to_string()); + } + + RemountInfo::from_str_response(&response_str.join("\n")) + } +} diff --git a/adb_client/src/message_devices/commands/verity.rs b/adb_client/src/message_devices/commands/verity.rs new file mode 100644 index 00000000..7132d5eb --- /dev/null +++ b/adb_client/src/message_devices/commands/verity.rs @@ -0,0 +1,25 @@ +use crate::{ + Result, + message_devices::{ + adb_message_device::ADBMessageDevice, adb_message_transport::ADBMessageTransport, + message_commands::MessageCommand, + }, +}; + +impl ADBMessageDevice { + pub(crate) fn enable_verity(&mut self) -> Result<()> { + self.open_session(b"enable-verity:\0")?; + + self.get_transport_mut() + .read_message() + .and_then(|message| message.assert_command(MessageCommand::Okay)) + } + + pub(crate) fn disable_verity(&mut self) -> Result<()> { + self.open_session(b"disable-verity:\0")?; + + self.get_transport_mut() + .read_message() + .and_then(|message| message.assert_command(MessageCommand::Okay)) + } +} diff --git a/adb_client/src/message_devices/tcp/adb_tcp_device.rs b/adb_client/src/message_devices/tcp/adb_tcp_device.rs index 04edba7b..05cd93f6 100644 --- a/adb_client/src/message_devices/tcp/adb_tcp_device.rs +++ b/adb_client/src/message_devices/tcp/adb_tcp_device.rs @@ -7,6 +7,7 @@ use crate::message_devices::adb_message_transport::ADBMessageTransport; use crate::message_devices::adb_transport_message::ADBTransportMessage; use crate::message_devices::message_commands::MessageCommand; use crate::message_devices::models::{ADBRsaKey, read_adb_private_key}; +use crate::models::RemountInfo; use crate::tcp::tcp_transport::TcpTransport; use crate::utils::get_default_adb_key_path; use crate::{ADBDeviceExt, ADBListItemType, ADBTransport, Result}; @@ -130,6 +131,11 @@ impl ADBDeviceExt for ADBTcpDevice { self.inner.reboot(reboot_type) } + #[inline] + fn remount(&mut self) -> Result> { + self.inner.remount() + } + #[inline] fn install(&mut self, apk_path: &dyn AsRef) -> Result<()> { self.inner.install(apk_path) @@ -140,6 +146,16 @@ impl ADBDeviceExt for ADBTcpDevice { self.inner.uninstall(package) } + #[inline] + fn enable_verity(&mut self) -> Result<()> { + self.inner.enable_verity() + } + + #[inline] + fn disable_verity(&mut self) -> Result<()> { + self.inner.disable_verity() + } + #[inline] fn framebuffer_inner(&mut self) -> Result, Vec>> { self.inner.framebuffer_inner() diff --git a/adb_client/src/message_devices/usb/adb_usb_device.rs b/adb_client/src/message_devices/usb/adb_usb_device.rs index fb5ee227..37b7bfe1 100644 --- a/adb_client/src/message_devices/usb/adb_usb_device.rs +++ b/adb_client/src/message_devices/usb/adb_usb_device.rs @@ -18,6 +18,7 @@ use crate::message_devices::adb_transport_message::ADBTransportMessage; use crate::message_devices::message_commands::MessageCommand; use crate::message_devices::models::ADBRsaKey; use crate::message_devices::models::read_adb_private_key; +use crate::models::RemountInfo; use crate::usb::usb_transport::USBTransport; use crate::utils::get_default_adb_key_path; @@ -264,6 +265,11 @@ impl ADBDeviceExt for ADBUSBDevice { self.inner.reboot(reboot_type) } + #[inline] + fn remount(&mut self) -> Result> { + self.inner.remount() + } + #[inline] fn install(&mut self, apk_path: &dyn AsRef) -> Result<()> { self.inner.install(apk_path) @@ -274,6 +280,16 @@ impl ADBDeviceExt for ADBUSBDevice { self.inner.uninstall(package) } + #[inline] + fn enable_verity(&mut self) -> Result<()> { + self.inner.enable_verity() + } + + #[inline] + fn disable_verity(&mut self) -> Result<()> { + self.inner.disable_verity() + } + #[inline] fn framebuffer_inner(&mut self) -> Result, Vec>> { self.inner.framebuffer_inner() diff --git a/adb_client/src/models/mod.rs b/adb_client/src/models/mod.rs index a4fbeec3..29aa5d48 100644 --- a/adb_client/src/models/mod.rs +++ b/adb_client/src/models/mod.rs @@ -4,6 +4,7 @@ mod framebuffer_info; mod host_features; mod list_info; mod reboot_type; +mod remount_info; mod sync_command; pub(crate) use adb_request_status::AdbRequestStatus; @@ -12,4 +13,5 @@ pub(crate) use framebuffer_info::{FrameBufferInfoV1, FrameBufferInfoV2}; pub use host_features::HostFeatures; pub use list_info::{ADBListItem, ADBListItemType}; pub use reboot_type::RebootType; -pub(crate) use sync_command::SyncCommand; +pub use remount_info::RemountInfo; +pub use sync_command::SyncCommand; diff --git a/adb_client/src/models/remount_info.rs b/adb_client/src/models/remount_info.rs new file mode 100644 index 00000000..562016b8 --- /dev/null +++ b/adb_client/src/models/remount_info.rs @@ -0,0 +1,54 @@ +use std::{str::FromStr, sync::LazyLock}; + +use regex::Regex; + +use crate::{Result, RustADBError}; + +static REMOUNT_REGEX: LazyLock = LazyLock::new(|| { + Regex::new(r"^Using\s+(?P\S+)\s+for\s+(?P\S+)$").expect("Invalid remount regex") +}); + +#[derive(Debug)] +/// Information about remount operation +pub struct RemountInfo { + /// Path that was remounted + pub path: String, + /// Mode that was used for remounting + pub mode: String, +} + +impl FromStr for RemountInfo { + type Err = RustADBError; + + fn from_str(s: &str) -> std::result::Result { + let caps = REMOUNT_REGEX + .captures(s) + .ok_or_else(|| RustADBError::RemountError(s.to_string()))?; + + let (Some(path), Some(mode)) = (caps.name("path"), caps.name("mode")) else { + return Err(RustADBError::RemountError(s.to_string())); + }; + + Ok(RemountInfo { + path: path.as_str().to_string(), + mode: mode.as_str().to_string(), + }) + } +} + +impl RemountInfo { + pub(crate) fn from_str_response(s: &str) -> Result> { + if !s.ends_with("remount succeeded") { + return Err(RustADBError::RemountError(s.to_string())); + } + + let mut infos = Vec::new(); + for line in s.lines() { + if line.starts_with("Using") { + infos.push(Self::from_str(line)?); + } + } + + Ok(infos) + } +} diff --git a/adb_client/src/server/adb_server_command.rs b/adb_client/src/server/adb_server_command.rs index 3779d584..ff71b86f 100644 --- a/adb_client/src/server/adb_server_command.rs +++ b/adb_client/src/server/adb_server_command.rs @@ -38,6 +38,9 @@ pub(crate) enum AdbServerCommand { Reverse(String, String), ReverseRemoveAll, Reconnect, + Remount, + DisableVerity, + EnableVerity, TcpIp(u16), Usb, } @@ -88,6 +91,9 @@ impl Display for AdbServerCommand { AdbServerCommand::ServerStatus => write!(f, "host:server-status"), AdbServerCommand::Reconnect => write!(f, "reconnect"), AdbServerCommand::ReconnectOffline => write!(f, "host:reconnect-offline"), + AdbServerCommand::Remount => write!(f, "remount:"), + AdbServerCommand::DisableVerity => write!(f, "disable-verity:"), + AdbServerCommand::EnableVerity => write!(f, "enable-verity:"), AdbServerCommand::TcpIp(port) => { write!(f, "tcpip:{port}") } diff --git a/adb_client/src/server_device/adb_server_device_commands.rs b/adb_client/src/server_device/adb_server_device_commands.rs index 286ef659..317dd5c3 100644 --- a/adb_client/src/server_device/adb_server_device_commands.rs +++ b/adb_client/src/server_device/adb_server_device_commands.rs @@ -5,7 +5,7 @@ use std::{ use crate::{ ADBDeviceExt, ADBListItemType, Result, RustADBError, - models::{AdbStatResponse, HostFeatures}, + models::{AdbStatResponse, HostFeatures, RemountInfo}, server::AdbServerCommand, }; @@ -125,6 +125,21 @@ impl ADBDeviceExt for ADBServerDevice { self.reboot(reboot_type) } + #[inline] + fn remount(&mut self) -> Result> { + self.remount() + } + + #[inline] + fn enable_verity(&mut self) -> Result<()> { + self.enable_verity() + } + + #[inline] + fn disable_verity(&mut self) -> Result<()> { + self.disable_verity() + } + #[inline] fn push(&mut self, stream: &mut dyn Read, path: &dyn AsRef) -> Result<()> { self.push(stream, path) diff --git a/adb_client/src/server_device/commands/mod.rs b/adb_client/src/server_device/commands/mod.rs index 5714bfa4..6f3397c0 100644 --- a/adb_client/src/server_device/commands/mod.rs +++ b/adb_client/src/server_device/commands/mod.rs @@ -7,6 +7,7 @@ mod logcat; mod reboot; mod reconnect; mod recv; +mod remount; mod reverse; mod send; mod stat; @@ -14,3 +15,4 @@ mod tcpip; mod transport; mod uninstall; mod usb; +mod verity; diff --git a/adb_client/src/server_device/commands/remount.rs b/adb_client/src/server_device/commands/remount.rs new file mode 100644 index 00000000..53302ad4 --- /dev/null +++ b/adb_client/src/server_device/commands/remount.rs @@ -0,0 +1,20 @@ +use crate::{ + Result, models::RemountInfo, server::AdbServerCommand, server_device::ADBServerDevice, +}; +use std::io::Read; + +impl ADBServerDevice { + /// Remounts the device filesystem as read-write + pub fn remount(&mut self) -> Result> { + self.set_serial_transport()?; + + self.transport + .send_adb_request(&AdbServerCommand::Remount)?; + + let mut data = [0; 1024]; + let read_amount = self.transport.get_raw_connection()?.read(&mut data)?; + + let response = String::from_utf8_lossy(&data[0..read_amount]); + RemountInfo::from_str_response(&response) + } +} diff --git a/adb_client/src/server_device/commands/verity.rs b/adb_client/src/server_device/commands/verity.rs new file mode 100644 index 00000000..cdc5c1ab --- /dev/null +++ b/adb_client/src/server_device/commands/verity.rs @@ -0,0 +1,19 @@ +use crate::{Result, server::AdbServerCommand, server_device::ADBServerDevice}; + +impl ADBServerDevice { + /// Disable verity on the device + pub fn disable_verity(&mut self) -> Result<()> { + self.set_serial_transport()?; + + self.transport + .send_adb_request(&AdbServerCommand::DisableVerity) + } + + /// Enable verity on the device + pub fn enable_verity(&mut self) -> Result<()> { + self.set_serial_transport()?; + + self.transport + .send_adb_request(&AdbServerCommand::EnableVerity) + } +}