blob: 1a0a609fcdd463fb246f9f208f84bfb84b5a3ecd [file] [log] [blame]
/*
* Copyright 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "avb_manager.h"
extern "C" {
#include <err.h>
#include <string.h>
} // extern C
#include "secure_storage_interface.h"
#define DEBUG 0
const unsigned int kRollbackSlotMax = 32;
static const uint32_t kAvbVersion = 1;
static const char* kAvbRollbackFilename = "avb.rollback";
static const unsigned int kStorageIdLengthMax = 64;
static const uint32_t kTypeMask = 0xF000;
static const unsigned int kTypeShift = 12;
// Helper function to get |filename| and |slot| and based on type flag
// in |raw_slot|. |filename| is assumed to be allocated with
// kStorageIdLengthMax bytes.
static int GetFilenameAndSlot(uint32_t raw_slot,
char filename[kStorageIdLengthMax],
uint32_t* slot) {
// Upper 16 bits should not be set
if (raw_slot & 0xFFFF0000) {
TLOGE("Error: Slot value %u invalid\n", raw_slot);
return ERR_NOT_VALID;
}
// Mask type flag from raw slot to get index
*slot = raw_slot & ~kTypeMask;
if (*slot >= kRollbackSlotMax) {
TLOGE("Error: Slot value %u larger than supported %u\n",
*slot,
kRollbackSlotMax);
return ERR_NOT_VALID;
}
// Choose correct file for rollback index type
strcpy(filename, kAvbRollbackFilename);
int index_type = (raw_slot & kTypeMask) >> kTypeShift;
char postfix[4];
snprintf(postfix, 4, ".%01X", index_type);
strcat(filename, postfix);
return NO_ERROR;
}
namespace avb {
void AvbManager::ReadRollbackIndex(const RollbackIndexRequest& request,
RollbackIndexResponse* response) {
uint32_t slot;
char filename[kStorageIdLengthMax];
if (GetFilenameAndSlot(request.get_slot(), filename, &slot) < 0) {
response->set_error(AvbError::kInvalid);
TLOGE("Error: Invalid slot value: %u\n", request.get_slot());
return;
}
int rc = storage_->open(filename);
if (rc < 0) {
response->set_error(AvbError::kInternal);
TLOGE("Error: failed to open file %s: %d\n", filename, rc);
return;
}
uint64_t size;
rc = storage_->get_file_size(&size);
if (rc < 0) {
response->set_error(AvbError::kInternal);
TLOGE("Error: failed to get size of file %s: %d\n", filename, rc);
return;
}
// If no valid rollback counter file is found, initialize to 0
uint64_t rollback_counter;
if (size < kRollbackSlotMax * sizeof(uint64_t)) {
TLOGD("No valid rollback index file found. Initializing to 0\n");
uint64_t write_buf[kRollbackSlotMax] = {0};
rc = storage_->write(0, write_buf, sizeof(write_buf));
rollback_counter = 0;
} else {
TLOGD("Rollback index file found\n");
rc = storage_->read(sizeof(rollback_counter) * slot,
&rollback_counter,
sizeof(rollback_counter));
}
if (rc < 0) {
response->set_error(AvbError::kInternal);
TLOGE("Error: reading storage object: %d\n", rc);
return;
}
if (static_cast<size_t>(rc) < sizeof(rollback_counter)) {
response->set_error(AvbError::kInternal);
TLOGE("Error: invalid object size: %d\n", rc);
return;
}
response->set_value(rollback_counter);
}
void AvbManager::WriteRollbackIndex(const RollbackIndexRequest& request,
RollbackIndexResponse* response) {
uint32_t slot;
char filename[kStorageIdLengthMax];
if (GetFilenameAndSlot(request.get_slot(), filename, &slot) < 0) {
response->set_error(AvbError::kInvalid);
TLOGE("Error: Invalid slot value: %u\n", request.get_slot());
return;
}
int rc = storage_->open(filename);
if (rc < 0) {
response->set_error(AvbError::kInternal);
TLOGE("Error: failed to open file %s: %d\n", filename, rc);
return;
}
uint64_t size;
rc = storage_->get_file_size(&size);
if (rc < 0) {
response->set_error(AvbError::kInternal);
TLOGE("Error: failed to get size of file %s: %d\n", filename, rc);
return;
}
// If no valid rollback counter file is found, initialize to 0
uint64_t request_value = request.get_value();
if (static_cast<size_t>(size) < kRollbackSlotMax * sizeof(uint64_t)) {
TLOGD("No valid rollback index file found. Initializing to 0\n");
uint64_t write_buf[kRollbackSlotMax] = {0};
write_buf[slot] = request_value;
rc = storage_->write(0, write_buf, sizeof(write_buf));
} else {
uint64_t rollback_counter;
TLOGD("Found a rollback index file\n");
rc = storage_->read(sizeof(rollback_counter) * slot,
&rollback_counter,
sizeof(rollback_counter));
// Write value to specified slot in file
if (request_value < rollback_counter) {
response->set_error(AvbError::kInvalid);
TLOGE(
"Error: Requested write [%lu] is less than existing counter value "
"[%lu]\n",
static_cast<long unsigned>(request_value),
static_cast<long unsigned>(rollback_counter));
response->set_value(rollback_counter);
return;
}
rc = storage_->write(
sizeof(request_value) * slot, &request_value, sizeof(request_value));
}
if (rc < 0) {
response->set_error(AvbError::kInternal);
TLOGE("Error: accessing storage object [%d]\n", rc);
return;
}
if (static_cast<size_t>(rc) < sizeof(request_value)) {
response->set_error(AvbError::kInternal);
TLOGE("Error: invalid object size [%d]\n", rc);
return;
}
response->set_value(request_value);
}
void AvbManager::GetVersion(const GetVersionRequest& request,
GetVersionResponse* response) {
response->set_version(kAvbVersion);
}
}; // namespace avb