init: Report valid verified boot for SafetyNet checks

Google's SafetyNet attestation includes checks for the integrity of the
verified boot chain, as reported by some ro.boot.* properties normally
passed by the bootloader. Reporting successful, valid values helps pass
SafetyNet checks, as long as other system state is intact.

However, the real prop values must be retained in recovery/fastbootd in
order for fastbootd to allow/deny flashing correctly based on the
bootloader lock state. This is accomplished a simple build time conditional,
to have the code bail out early when built for recovery. This is more reliable
and works across all OEMs rather than androidboot.mode

Given that CalyxOS is meant for usage with a locked bootloader, we only
need to spoof the value of verified boot state from yellow to green.
The other values are already acceptable, so we don't touch them

Co-authored-by: Chirayu Desai <chirayudesai1@gmail.com>
Co-authored-by: Michael Bestas <mkbestas@gmail.com>
Change-Id: I66d23fd91d82906b00d5eb020668f01ae83ec31f
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 0139247..a2168bf 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -1363,6 +1363,7 @@
 }
 
 constexpr auto ANDROIDBOOT_PREFIX = "androidboot."sv;
+constexpr auto ANDROIDBOOT_VERIFIEDBOOTSTATE = "androidboot.verifiedbootstate"sv;
 
 static void ProcessKernelCmdline() {
     android::fs_mgr::ImportKernelCmdline([&](const std::string& key, const std::string& value) {
@@ -1381,6 +1382,34 @@
     });
 }
 
+static void SetSafetyNetProps() {
+#ifdef RECOVERY
+    // Bail out if this is recovery, fastbootd, or anything other than a normal boot.
+    // fastbootd, in particular, needs the real values so it can allow flashing on
+    // unlocked bootloaders.
+    return;
+#endif
+
+    // Check whether verified boot state is yellow
+    auto isVerifiedBootYellow = false;
+    // This runs before keys are set as props, so we need to process them ourselves.
+    ImportKernelCmdline([&](const std::string& key, const std::string& value) {
+        if (key == ANDROIDBOOT_VERIFIEDBOOTSTATE && value == "yellow") {
+            isVerifiedBootYellow = true;
+        }
+    });
+    ImportBootconfig([&](const std::string& key, const std::string& value) {
+        if (key == ANDROIDBOOT_VERIFIEDBOOTSTATE && value == "yellow") {
+            isVerifiedBootYellow = true;
+        }
+    });
+
+    // Spoof verified boot state to green only when it's yellow
+    if (isVerifiedBootYellow) {
+        InitPropertySet("ro.boot.verifiedbootstate", "green");
+    }
+}
+
 void PropertyInit() {
     selinux_callback cb;
     cb.func_audit = PropertyAuditCallback;
@@ -1395,6 +1424,9 @@
         LOG(FATAL) << "Failed to load serialized property info file";
     }
 
+    // Report valid verified boot chain to help pass Google SafetyNet integrity checks
+    SetSafetyNetProps();
+
     // If arguments are passed both on the command line and in DT,
     // properties set in DT always have priority over the command-line ones.
     ProcessKernelDt();