Complete Android parity and security audit (#111)
This commit is contained in:
1 parent
45d78aa5b3
commit
b54636b7bc
14 files changed
+498
-75
No files matched your search
@@ -30,6 +30,33 @@ pub fn manifest(manifest: &Path, backup: &Path, extraction: &Path) -> Result<(),
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn release_manifest(path: &Path) -> Result<(), Box<dyn Error>> {
|
||||
release_manifest_text(&fs::read_to_string(path)?)?;
|
||||
println!("Verified release cannot be debugged, profiled or installed as test-only");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn release_manifest_text(source: &str) -> Result<(), Box<dyn Error>> {
|
||||
let document = Document::parse(source)?;
|
||||
let application = document
|
||||
.root_element()
|
||||
.children()
|
||||
.find(|node| node.has_tag_name("application"))
|
||||
.ok_or("application missing")?;
|
||||
for name in ["debuggable", "testOnly"] {
|
||||
if !matches!(application.attribute((ANDROID, name)), None | Some("false")) {
|
||||
return Err(format!("unsafe release application flag: {name}").into());
|
||||
}
|
||||
}
|
||||
if application
|
||||
.children()
|
||||
.any(|node| node.has_tag_name("profileable"))
|
||||
{
|
||||
return Err("profiling is restricted to benchmark/profile builds".into());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn manifest_text(source: &str) -> Result<(), Box<dyn Error>> {
|
||||
let document = Document::parse(source)?;
|
||||
let root = document.root_element();
|
||||
@@ -489,6 +516,35 @@ fn android_license<'a>(
|
||||
mod tests {
|
||||
use super::*;
|
||||
#[test]
|
||||
fn release_rejects_debug_test_and_profile_access() {
|
||||
let source = format!(r#"<manifest xmlns:android="{ANDROID}"><application/></manifest>"#);
|
||||
assert!(release_manifest_text(&source).is_ok());
|
||||
for flag in ["debuggable", "testOnly"] {
|
||||
assert!(
|
||||
release_manifest_text(&source.replace(
|
||||
"<application/>",
|
||||
&format!(r#"<application android:{flag}="false"/>"#)
|
||||
))
|
||||
.is_ok()
|
||||
);
|
||||
assert!(
|
||||
release_manifest_text(&source.replace(
|
||||
"<application/>",
|
||||
&format!(r#"<application android:{flag}="true"/>"#)
|
||||
))
|
||||
.is_err()
|
||||
);
|
||||
}
|
||||
assert!(
|
||||
release_manifest_text(&source.replace(
|
||||
"<application/>",
|
||||
r#"<application><profileable android:shell="true"/></application>"#
|
||||
))
|
||||
.is_err()
|
||||
);
|
||||
assert!(release_manifest_text("<manifest/>").is_err());
|
||||
}
|
||||
#[test]
|
||||
fn manifest_rejects_backup_permissions_and_exports() {
|
||||
let source = format!(
|
||||
r#"<manifest xmlns:android="{ANDROID}" package="de.rfc1437.ironstorage"><application android:allowBackup="false" android:usesCleartextTraffic="false" android:fullBackupContent="@xml/backup_rules" android:dataExtractionRules="@xml/data_extraction_rules"><activity android:name="de.rfc1437.ironstorage.MainActivity" android:exported="true"><intent-filter><action android:name="android.intent.action.MAIN"/><category android:name="android.intent.category.LAUNCHER"/></intent-filter></activity><provider android:name="fixture" android:exported="false"/></application></manifest>"#
|
||||
|
||||
@@ -52,6 +52,9 @@ fn main() -> Result<(), Box<dyn Error>> {
|
||||
[_, command, directory] if command == "audit-native" => {
|
||||
native::audit_directory(Path::new(directory))?
|
||||
}
|
||||
[_, command, manifest] if command == "audit-release-manifest" => {
|
||||
gates::release_manifest(Path::new(manifest))?;
|
||||
}
|
||||
[_, command, manifest, backup, extraction] if command == "audit-manifest" => {
|
||||
gates::manifest(
|
||||
Path::new(manifest),
|
||||
@@ -85,7 +88,7 @@ fn main() -> Result<(), Box<dyn Error>> {
|
||||
}
|
||||
_ => {
|
||||
return Err(
|
||||
"usage: ironstorage-android-build <fixtures output.kt | check android-dir | prepare-bindings input output | package-native input output | audit-elf path abi | audit-native jniLibs | audit-apk-split apk abi | audit-package apk-or-aab | audit-release apk symbols | audit-manifest manifest.xml backup.xml extraction.xml | sbom android.json rust.txt Cargo.lock policy.json output.json | safe-reports input-dir output.json | check-toolchain cargo rust ndk ndk-version cargo-ndk-version>".into(),
|
||||
"usage: ironstorage-android-build <fixtures output.kt | check android-dir | prepare-bindings input output | package-native input output | audit-elf path abi | audit-native jniLibs | audit-apk-split apk abi | audit-package apk-or-aab | audit-release apk symbols | audit-release-manifest manifest.xml | audit-manifest manifest.xml backup.xml extraction.xml | sbom android.json rust.txt Cargo.lock policy.json output.json | safe-reports input-dir output.json | check-toolchain cargo rust ndk ndk-version cargo-ndk-version>".into(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user