Address offline playback with rollbacked time
Merge from http://go/wvgerrit/47640 Test: unit/integration tests Bug: b/62058202 The usage table keeps track of license duration by using the current system time. However, if a user were to rollback the time, they can effectively continue offline playback indefinitely. This changes the way we compute time by computing offsets by which the user rollbacked the time and adding it to the current time. This change also includes a test to verify protection against rollback for usage entries that is only run when the user is root. Change-Id: I97c430e1443747b0f9759ae5390b8f5d06bdebf1
This commit is contained in:
@@ -5617,6 +5617,86 @@ TEST_F(UsageTableTest, VerifyUsageTimes) {
|
||||
s.TestDecryptCTR(false, OEMCrypto_ERROR_UNKNOWN_FAILURE));
|
||||
}
|
||||
|
||||
// NOTE: This test needs root access since clock_settime messes with the system
|
||||
// time in order to verify that OEMCrypto protects against rollbacks in usage
|
||||
// entries. Therefore, this test is filtered if not run as root.
|
||||
// We don't test roll-forward protection or instances where the user rolls back
|
||||
// the time to the last decrypt call since this requires hardware-secure clocks
|
||||
// to guarantee.
|
||||
TEST_F(UsageTableTest, TimeRollbackPrevention) {
|
||||
std::string pst = "my_pst";
|
||||
Session s1;
|
||||
cout << "This test temporarily rolls back the system time in order to verify "
|
||||
<< "that the usage report accounts for the change. It then rolls "
|
||||
<< "the time back forward to the absolute time." << endl;
|
||||
// We use clock_gettime(CLOCK_REALTIME, ...) over time(...) so we can easily
|
||||
// set the time using clock_settime.
|
||||
timespec current_time;
|
||||
ASSERT_EQ(0, clock_gettime(CLOCK_REALTIME, ¤t_time));
|
||||
time_t loaded = current_time.tv_sec;
|
||||
ASSERT_NO_FATAL_FAILURE(LoadOfflineLicense(s1, pst));
|
||||
|
||||
ASSERT_NO_FATAL_FAILURE(s1.open());
|
||||
ASSERT_NO_FATAL_FAILURE(s1.ReloadUsageEntry());
|
||||
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s1));
|
||||
ASSERT_NO_FATAL_FAILURE(s1.LoadTestKeys(pst, new_mac_keys_));
|
||||
ASSERT_EQ(0, clock_gettime(CLOCK_REALTIME, ¤t_time));
|
||||
time_t first_decrypt = current_time.tv_sec;
|
||||
// Monotonic clock can't be changed. We use this since system clock will be
|
||||
// unreliable.
|
||||
ASSERT_EQ(0, clock_gettime(CLOCK_MONOTONIC, ¤t_time));
|
||||
time_t first_decrypt_monotonic = current_time.tv_sec;
|
||||
ASSERT_NO_FATAL_FAILURE(s1.TestDecryptCTR());
|
||||
ASSERT_NO_FATAL_FAILURE(s1.UpdateUsageEntry(&encrypted_usage_header_));
|
||||
ASSERT_NO_FATAL_FAILURE(s1.close());
|
||||
|
||||
// Imitate playback.
|
||||
sleep(kLongDuration * 2);
|
||||
|
||||
ASSERT_NO_FATAL_FAILURE(s1.open());
|
||||
ASSERT_NO_FATAL_FAILURE(s1.ReloadUsageEntry());
|
||||
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s1));
|
||||
ASSERT_NO_FATAL_FAILURE(s1.LoadTestKeys(pst, new_mac_keys_));
|
||||
ASSERT_NO_FATAL_FAILURE(s1.TestDecryptCTR());
|
||||
ASSERT_NO_FATAL_FAILURE(s1.UpdateUsageEntry(&encrypted_usage_header_));
|
||||
ASSERT_NO_FATAL_FAILURE(s1.close());
|
||||
|
||||
ASSERT_EQ(0, clock_gettime(CLOCK_REALTIME, ¤t_time));
|
||||
// Rollback the wall clock time.
|
||||
current_time.tv_sec -= kLongDuration * 10;
|
||||
cout << "Rolling the system time back..." << endl;
|
||||
ASSERT_EQ(0, clock_settime(CLOCK_REALTIME, ¤t_time));
|
||||
|
||||
// Try to playback again.
|
||||
ASSERT_NO_FATAL_FAILURE(s1.open());
|
||||
ASSERT_NO_FATAL_FAILURE(s1.ReloadUsageEntry());
|
||||
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s1));
|
||||
ASSERT_NO_FATAL_FAILURE(s1.LoadTestKeys(pst, new_mac_keys_));
|
||||
ASSERT_EQ(0, clock_gettime(CLOCK_MONOTONIC, ¤t_time));
|
||||
time_t third_decrypt = current_time.tv_sec;
|
||||
ASSERT_NO_FATAL_FAILURE(s1.TestDecryptCTR());
|
||||
ASSERT_NO_FATAL_FAILURE(s1.UpdateUsageEntry(&encrypted_usage_header_));
|
||||
ASSERT_NO_FATAL_FAILURE(s1.GenerateReport(pst));
|
||||
Test_PST_Report expected(pst, kActive);
|
||||
|
||||
// Restore wall clock to its original position to verify that OEMCrypto does
|
||||
// not report negative times.
|
||||
ASSERT_EQ(0, clock_gettime(CLOCK_MONOTONIC, ¤t_time));
|
||||
current_time.tv_sec =
|
||||
first_decrypt + current_time.tv_sec - first_decrypt_monotonic;
|
||||
cout << "Rolling the system time forward to the absolute time..." << endl;
|
||||
ASSERT_EQ(0, clock_settime(CLOCK_REALTIME, ¤t_time));
|
||||
|
||||
// Need to update time created since the verification checks the time of PST
|
||||
// report creation.
|
||||
expected.time_created = current_time.tv_sec;
|
||||
|
||||
ASSERT_NO_FATAL_FAILURE(
|
||||
s1.VerifyReport(expected, loaded, first_decrypt,
|
||||
first_decrypt + third_decrypt - first_decrypt_monotonic));
|
||||
ASSERT_NO_FATAL_FAILURE(s1.close());
|
||||
}
|
||||
|
||||
// This is a special case where a group of assets can be licensed with a master
|
||||
// key. In order for this to work, a single session must first load a device
|
||||
// specific license, and then a shared content license. This shared license is
|
||||
|
||||
Reference in New Issue
Block a user