update_engine: Add hardware support for firmware_max_rollforward

- Adds the methods to get and set firmware_max_rollforward
- This is for supporting the rollback feature
- A future CL will set these values based on policy

BUG=chromium:840432
TEST=unittests

Change-Id: I560f4cef9595d4a52d011fcfeb7b2675a096aefa
Reviewed-on: https://chromium-review.googlesource.com/1062766
Commit-Ready: Zentaro Kavanagh <zentaro@chromium.org>
Tested-by: Zentaro Kavanagh <zentaro@chromium.org>
Reviewed-by: Amin Hassani <ahassani@chromium.org>
diff --git a/common/fake_hardware.h b/common/fake_hardware.h
index d68b0f8..55dcc2c 100644
--- a/common/fake_hardware.h
+++ b/common/fake_hardware.h
@@ -44,7 +44,13 @@
   // default for consumer devices and effectively means "unlimited rollforward
   // is allowed", which is the same as the behavior prior to implementing
   // roll forward prevention.
-  static const int kMaxKernelRollforward = 0xfffffffe;
+  static const int kKernelMaxRollforward = 0xfffffffe;
+
+  // Default value for crossystem firmware_max_rollforward. This value is the
+  // default for consumer devices and effectively means "unlimited rollforward
+  // is allowed", which is the same as the behavior prior to implementing
+  // roll forward prevention.
+  static const int kFirmwareMaxRollforward = 0xfffffffe;
 
   FakeHardware() = default;
 
@@ -79,6 +85,18 @@
     return min_firmware_key_version_;
   }
 
+  int GetMaxFirmwareKeyRollforward() const override {
+    return firmware_max_rollforward_;
+  }
+
+  bool SetMaxFirmwareKeyRollforward(int firmware_max_rollforward) override {
+    if (GetMaxFirmwareKeyRollforward() == -1)
+      return false;
+
+    firmware_max_rollforward_ = firmware_max_rollforward;
+    return true;
+  }
+
   bool SetMaxKernelKeyRollforward(int kernel_max_rollforward) override {
     kernel_max_rollforward_ = kernel_max_rollforward;
     return true;
@@ -183,7 +201,8 @@
   std::string ec_version_{"Fake EC v1.0a"};
   int min_kernel_key_version_{kMinKernelKeyVersion};
   int min_firmware_key_version_{kMinFirmwareKeyVersion};
-  int kernel_max_rollforward_{kMaxKernelRollforward};
+  int kernel_max_rollforward_{kKernelMaxRollforward};
+  int firmware_max_rollforward_{kFirmwareMaxRollforward};
   int powerwash_count_{kPowerwashCountNotSet};
   bool powerwash_scheduled_{false};
   bool first_active_omaha_ping_sent_{false};
diff --git a/common/hardware_interface.h b/common/hardware_interface.h
index 239e7c8..dd42e05 100644
--- a/common/hardware_interface.h
+++ b/common/hardware_interface.h
@@ -78,6 +78,17 @@
   // -1 on error, or if not running on Chrome OS.
   virtual int GetMinFirmwareKeyVersion() const = 0;
 
+  // Returns the maximum firmware key version that verified boot should roll
+  // forward to. This is the value of crossystem firmware_max_rollforward.
+  // Returns -1 on error, if this board does not yet support this value, or
+  // if not running on Chrome OS.
+  virtual int GetMaxFirmwareKeyRollforward() const = 0;
+
+  // Sets the maximum firmware key version that verified boot should roll
+  // forward to. This is the value of crossystem firmware_max_rollforward.
+  // This value is not available on all Chrome OS devices.
+  virtual bool SetMaxFirmwareKeyRollforward(int firmware_max_rollforward) = 0;
+
   // Sets the maximum kernel key version that verified boot should roll
   // forward to. This is the value of crossystem kernel_max_rollforward.
   // Returns false if the value cannot be set, or if not running on Chrome OS.
diff --git a/common/mock_hardware.h b/common/mock_hardware.h
index 662ccd9..f972df2 100644
--- a/common/mock_hardware.h
+++ b/common/mock_hardware.h
@@ -60,6 +60,12 @@
     ON_CALL(*this, GetMinFirmwareKeyVersion())
         .WillByDefault(
             testing::Invoke(&fake_, &FakeHardware::GetMinFirmwareKeyVersion));
+    ON_CALL(*this, GetMaxFirmwareKeyRollforward())
+        .WillByDefault(testing::Invoke(
+            &fake_, &FakeHardware::GetMaxFirmwareKeyRollforward));
+    ON_CALL(*this, SetMaxFirmwareKeyRollforward())
+        .WillByDefault(testing::Invoke(
+            &fake_, &FakeHardware::SetMaxFirmwareKeyRollforward));
     ON_CALL(*this, SetMaxKernelKeyRollforward())
         .WillByDefault(
             testing::Invoke(&fake_, &FakeHardware::SetMaxKernelKeyRollforward));
@@ -92,6 +98,9 @@
   MOCK_CONST_METHOD0(GetECVersion, std::string());
   MOCK_CONST_METHOD0(GetMinKernelKeyVersion, int());
   MOCK_CONST_METHOD0(GetMinFirmwareKeyVersion, int());
+  MOCK_CONST_METHOD0(GetMaxFirmwareKeyRollforward, int());
+  MOCK_CONST_METHOD1(SetMaxFirmwareKeyRollforward,
+                     bool(int firmware_max_rollforward));
   MOCK_CONST_METHOD1(SetMaxKernelKeyRollforward,
                      bool(int kernel_max_rollforward));
   MOCK_CONST_METHOD0(GetPowerwashCount, int());
diff --git a/hardware_android.cc b/hardware_android.cc
index 3f0fb59..deabc5c 100644
--- a/hardware_android.cc
+++ b/hardware_android.cc
@@ -174,6 +174,17 @@
   return -1;
 }
 
+int HardwareAndroid::GetMaxFirmwareKeyRollforward() const {
+  LOG(WARNING) << "STUB: Getting firmware_max_rollforward is not supported.";
+  return -1;
+}
+
+bool HardwareAndroid::SetMaxFirmwareKeyRollforward(
+    int firmware_max_rollforward) {
+  LOG(WARNING) << "STUB: Setting firmware_max_rollforward is not supported.";
+  return false;
+}
+
 bool HardwareAndroid::SetMaxKernelKeyRollforward(int kernel_max_rollforward) {
   LOG(WARNING) << "STUB: Setting kernel_max_rollforward is not supported.";
   return false;
diff --git a/hardware_android.h b/hardware_android.h
index 981f033..b7a6f96 100644
--- a/hardware_android.h
+++ b/hardware_android.h
@@ -44,6 +44,8 @@
   std::string GetECVersion() const override;
   int GetMinKernelKeyVersion() const override;
   int GetMinFirmwareKeyVersion() const override;
+  int GetMaxFirmwareKeyRollforward() const override;
+  bool SetMaxFirmwareKeyRollforward(int firmware_max_rollforward) override;
   bool SetMaxKernelKeyRollforward(int kernel_max_rollforward) override;
   int GetPowerwashCount() const override;
   bool SchedulePowerwash() override;
diff --git a/hardware_chromeos.cc b/hardware_chromeos.cc
index 08303d0..6cfe5ef 100644
--- a/hardware_chromeos.cc
+++ b/hardware_chromeos.cc
@@ -186,6 +186,21 @@
   return VbGetSystemPropertyInt("tpm_kernver");
 }
 
+int HardwareChromeOS::GetMaxFirmwareKeyRollforward() const {
+  return VbGetSystemPropertyInt("firmware_max_rollforward");
+}
+
+bool HardwareChromeOS::SetMaxFirmwareKeyRollforward(
+    int firmware_max_rollforward) {
+  // Not all devices have this field yet. So first try to read
+  // it and if there is an error just fail.
+  if (GetMaxFirmwareKeyRollforward() == -1)
+    return false;
+
+  return VbSetSystemPropertyInt("firmware_max_rollforward",
+                                firmware_max_rollforward) == 0;
+}
+
 int HardwareChromeOS::GetMinFirmwareKeyVersion() const {
   return VbGetSystemPropertyInt("tpm_fwver");
 }
diff --git a/hardware_chromeos.h b/hardware_chromeos.h
index 6bdd37a..3aeeb0b 100644
--- a/hardware_chromeos.h
+++ b/hardware_chromeos.h
@@ -49,6 +49,8 @@
   std::string GetECVersion() const override;
   int GetMinKernelKeyVersion() const override;
   int GetMinFirmwareKeyVersion() const override;
+  int GetMaxFirmwareKeyRollforward() const override;
+  bool SetMaxFirmwareKeyRollforward(int firmware_max_rollforward) override;
   bool SetMaxKernelKeyRollforward(int kernel_max_rollforward) override;
   int GetPowerwashCount() const override;
   bool SchedulePowerwash() override;