Skip to main content

verifyos_cli/rules/
bitcode.rs

1use crate::rules::core::{
2    AppStoreRule, ArtifactContext, RuleCategory, RuleError, RuleReport, RuleStatus, Severity,
3};
4
5pub struct BitcodeRule;
6
7impl AppStoreRule for BitcodeRule {
8    fn id(&self) -> &'static str {
9        "RULE_BITCODE_ENABLED"
10    }
11
12    fn name(&self) -> &'static str {
13        "Bitcode Disabled Requirement"
14    }
15
16    fn category(&self) -> RuleCategory {
17        RuleCategory::Signing
18    }
19
20    fn severity(&self) -> Severity {
21        Severity::Error
22    }
23
24    fn recommendation(&self) -> &'static str {
25        "Apple no longer accepts apps with Bitcode. Disable Bitcode in Build Settings."
26    }
27
28    fn evaluate(&self, artifact: &ArtifactContext) -> Result<RuleReport, RuleError> {
29        let executable_path = match artifact.executable_path_for_bundle(artifact.app_bundle_path) {
30            Some(path) => path,
31            None => {
32                return Ok(RuleReport {
33                    status: RuleStatus::Skip,
34                    message: Some("No executable found in bundle".to_string()),
35                    evidence: None,
36                })
37            }
38        };
39
40        if !executable_path.exists() {
41            return Ok(RuleReport {
42                status: RuleStatus::Skip,
43                message: Some("Executable file not found".to_string()),
44                evidence: None,
45            });
46        }
47
48        let bytes = std::fs::read(&executable_path).map_err(|e| {
49            RuleError::MachO(crate::parsers::macho_parser::MachOError::ParseError(
50                Box::new(apple_codesign::AppleCodesignError::Io(e)),
51            ))
52        })?;
53
54        // We search for the __LLVM segment name in the Mach-O binary.
55        // Apple's bitcode is embedded in a segment exactly named "__LLVM" with null padding.
56        let target = b"__LLVM\0\0\0\0\0\0\0\0\0\0";
57        let found = bytes.windows(target.len()).any(|window| window == target);
58
59        if found {
60            return Ok(RuleReport {
61                status: RuleStatus::Fail,
62                message: Some("Bitcode segment (__LLVM) found in Mach-O binary.".to_string()),
63                evidence: Some("Mach-O contains __LLVM segment".to_string()),
64            });
65        }
66
67        Ok(RuleReport {
68            status: RuleStatus::Pass,
69            message: None,
70            evidence: None,
71        })
72    }
73}