From 7fc3285272183fa845b60eddb50422e9fcafe303 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 19 Aug 2021 13:34:44 +0200 Subject: [PATCH] added functions to handle writeprotection --- bsp_q7s/core/CoreController.cpp | 250 ++++++++++++++++++++++++++++++-- bsp_q7s/core/CoreController.h | 88 +++++++---- 2 files changed, 300 insertions(+), 38 deletions(-) diff --git a/bsp_q7s/core/CoreController.cpp b/bsp_q7s/core/CoreController.cpp index bf1a1b1a..b5e1fce3 100644 --- a/bsp_q7s/core/CoreController.cpp +++ b/bsp_q7s/core/CoreController.cpp @@ -21,12 +21,11 @@ #include -CoreController::Chip CoreController::currentChip = Chip::NO_CHIP; -CoreController::Copy CoreController::currentCopy = Copy::NO_COPY; +CoreController::Chip CoreController::CURRENT_CHIP = Chip::NO_CHIP; +CoreController::Copy CoreController::CURRENT_COPY = Copy::NO_COPY; CoreController::CoreController(object_id_t objectId): - ExtendedControllerBase(objectId, objects::NO_OBJECT, 5), - opDivider(5) { + ExtendedControllerBase(objectId, objects::NO_OBJECT, 5), opDivider(5) { ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; try { result = initWatchdogFifo(); @@ -552,6 +551,12 @@ ReturnValue_t CoreController::initializeAfterTaskCreation() { if(result != HasReturnvaluesIF::RETURN_OK) { sif::warning << "CoreController::initialize: Version initialization failed" << std::endl; } + // Add script folder to path + char* currentEnvPath = getenv("PATH"); + sif::info << currentEnvPath << std::endl; + std::string updatedEnvPath = std::string(currentEnvPath) + ":/home/root/scripts"; + setenv("PATH", updatedEnvPath.c_str(), true); + updateProtInfo(); initPrint(); return result; } @@ -614,7 +619,7 @@ ReturnValue_t CoreController::initVersionFile() { std::to_string(FSFW_SUBVERSION) + "." + std::to_string(FSFW_REVISION); std::string systemString = "System: " + unameLine; std::string mountPrefix = SdCardManager::instance()->getCurrentMountPrefix(); - std::string versionFilePath = mountPrefix + "/conf/version.txt"; + std::string versionFilePath = mountPrefix + VERSION_FILE; std::fstream versionFile; if(not std::filesystem::exists(versionFilePath)) { @@ -731,32 +736,31 @@ ReturnValue_t CoreController::actionListDirectoryIntoFile(ActionId_t actionId, } ReturnValue_t CoreController::initBootCopy() { - std::string fileName = "/tmp/curr_copy.txt"; - if(not std::filesystem::exists(fileName)) { + if(not std::filesystem::exists(CURR_COPY_FILE)) { // Thils file is created by the systemd service eive-early-config so this should // not happen normally - std::string cmd = "xsc_boot_copy > " + fileName; + std::string cmd = "xsc_boot_copy > " + std::string(CURR_COPY_FILE); int result = std::system(cmd.c_str()); if(result != 0) { utility::handleSystemError(result, "CoreController::initBootCopy"); } } - std::ifstream file(fileName); + std::ifstream file(CURR_COPY_FILE); std::string line; std::getline(file, line); std::istringstream iss(line); int value = 0; iss >> value; - currentChip = static_cast(value); + CURRENT_CHIP = static_cast(value); iss >> value; - currentCopy = static_cast(value); + CURRENT_COPY = static_cast(value); return HasReturnvaluesIF::RETURN_OK; } void CoreController::getCurrentBootCopy(Chip &chip, Copy ©) { // Not really thread-safe but it does not need to be - chip = currentChip; - copy = currentCopy; + chip = CURRENT_CHIP; + copy = CURRENT_COPY; } ReturnValue_t CoreController::initWatchdogFifo() { @@ -795,6 +799,7 @@ ReturnValue_t CoreController::actionPerformReboot(const uint8_t *data, size_t si return HasActionsIF::INVALID_PARAMETERS; } bool rebootSameBootCopy = data[0]; + bool protOpPerformed; if(rebootSameBootCopy) { #if OBSW_VERBOSE_LEVEL >= 1 sif::info << "CoreController::actionPerformReboot: Rebooting on current image" << std::endl; @@ -802,6 +807,12 @@ ReturnValue_t CoreController::actionPerformReboot(const uint8_t *data, size_t si // Attempt graceful shutdown by unmounting and switching off SD cards SdCardManager::instance()->switchOffSdCard(sd::SdCard::SLOT_0); SdCardManager::instance()->switchOffSdCard(sd::SdCard::SLOT_1); + // If any boot copies are unprotected + ReturnValue_t retval = checkAndSetBootCopyProtection(Chip::SELF_CHIP, Copy::SELF_COPY, + true, protOpPerformed, false); + if(retval == HasReturnvaluesIF::RETURN_OK and protOpPerformed) { + sif::info << "Running slot was writeprotected before reboot" << std::endl; + } int result = std::system("xsc_boot_copy -r"); if(result != 0) { utility::handleSystemError(result, "CoreController::executeAction"); @@ -816,6 +827,16 @@ ReturnValue_t CoreController::actionPerformReboot(const uint8_t *data, size_t si sif::info << "CoreController::actionPerformReboot: Rebooting on " << static_cast(data[1]) << " " << static_cast(data[2]) << std::endl; #endif + + // Check that the target chip and copy is writeprotected first + generateChipStateFile(); + // If any boot copies are unprotected, protect them here + ReturnValue_t retval = checkAndSetBootCopyProtection(static_cast(data[1]), + static_cast(data[2]), true, protOpPerformed, false); + if(retval == HasReturnvaluesIF::RETURN_OK and protOpPerformed) { + sif::info << "Target slot was writeprotected before reboot" << std::endl; + } + // The second byte in data is the target chip, the third byte is the target copy std::string cmdString = "xsc_boot_copy " + std::to_string(data[1]) + " " + std::to_string(data[2]); @@ -873,6 +894,209 @@ bool CoreController::sdInitFinished() const { return sdInfo.initFinished; } +ReturnValue_t CoreController::generateChipStateFile() { + int result = std::system(CHIP_PROT_SCRIPT); + if(result != 0) { + utility::handleSystemError(result, "CoreController::generateChipStateFile"); + return HasReturnvaluesIF::RETURN_FAILED; + } + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t CoreController::checkAndSetBootCopyProtection(Chip targetChip, Copy targetCopy, + bool protect, bool& protOperationPerformed, bool updateProtFile) { + bool allChips = false; + bool allCopies = false; + bool selfChip = false; + bool selfCopy = false; + switch(targetChip) { + case(Chip::ALL_CHIP): { + allChips = true; + break; + } + case(Chip::NO_CHIP): { + return HasReturnvaluesIF::RETURN_OK; + } + case(Chip::SELF_CHIP): { + selfChip = true; + break; + } + default: { + break; + } + } + switch(targetCopy) { + case(Copy::ALL_COPY): { + allCopies = true; + break; + } + case(Copy::NO_COPY): { + return HasReturnvaluesIF::RETURN_OK; + } + case(Copy::SELF_COPY): { + selfCopy = true; + break; + } + default: { + break; + } + } + + for(uint8_t arrIdx = 0; arrIdx < 4; arrIdx++) { + bool currentProt = protArray[arrIdx]; + std::ostringstream oss; + if(protect == currentProt) { + continue; + } + Chip currentChip; + Copy currentCopy; + oss << "writeprotect "; + if(arrIdx == 0 or arrIdx == 1) { + oss << "0 "; + currentChip = Chip::CHIP_0; + } + else { + oss << "1 "; + currentChip = Chip::CHIP_1; + } + if(arrIdx == 0 or arrIdx == 2) { + oss << "0 "; + currentCopy = Copy::COPY_0; + } + else { + oss << "1 "; + currentCopy = Copy::COPY_1; + } + if(protect) { + oss << "1"; + } + else { + oss << "0"; + } + + int result = 0; + if(allChips and allCopies) { + protOperationPerformed = true; + result = std::system(oss.str().c_str()); + } + else if(allChips) { + if((selfCopy and CURRENT_COPY == targetCopy) or + (currentCopy == targetCopy)) { + protOperationPerformed = true; + result = std::system(oss.str().c_str()); + } + } + else if(allCopies) { + if((selfChip and CURRENT_COPY == targetCopy) or + (currentChip == targetChip)) { + protOperationPerformed = true; + result = std::system(oss.str().c_str()); + } + } + else if(selfChip and (CURRENT_CHIP == targetChip)) { + protOperationPerformed = true; + result = std::system(oss.str().c_str()); + } + else if(selfCopy and (CURRENT_COPY == targetCopy)) { + protOperationPerformed = true; + result = std::system(oss.str().c_str()); + } + if(result != 0) { + utility::handleSystemError(result, "CoreController::checkAndSetBootCopyProtection"); + } + } + if(protOperationPerformed and updateProtFile) { + updateProtInfo(); + } + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t CoreController::updateProtInfo(bool regenerateChipStateFile) { + using namespace std; + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + if(regenerateChipStateFile) { + result = generateChipStateFile(); + if(result != HasReturnvaluesIF::RETURN_OK) { + sif::warning << "CoreController::updateProtInfo: Generating chip state file failed" << + std::endl; + return result; + } + } + if(not filesystem::exists(CHIP_STATE_FILE)) { + return HasReturnvaluesIF::RETURN_FAILED; + } + ifstream chipStateFile(CHIP_STATE_FILE); + if(not chipStateFile.good()) { + return HasReturnvaluesIF::RETURN_FAILED; + } + string nextLine; + uint8_t lineCounter = 0; + string word; + while(getline(chipStateFile, nextLine)) { + ReturnValue_t result = handleProtInfoUpdateLine(nextLine); + if(result != HasReturnvaluesIF::RETURN_OK) { + sif::warning << "CoreController::updateProtInfo: Protection info update failed!" << + std::endl; + return result; + } + ++lineCounter; + if(lineCounter > 4) { + sif::warning << "CoreController::checkAndProtectBootCopy: " + "Line counter larger than 4" << std::endl; + } + } + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t CoreController::handleProtInfoUpdateLine(std::string nextLine) { + using namespace std; + string word; + uint8_t wordIdx = 0; + istringstream iss(nextLine); + Chip currentChip; + Copy currentCopy; + while(iss >> word) { + if(wordIdx == 1) { + currentChip = static_cast(stoi(word)); + } + if(wordIdx == 3) { + currentCopy = static_cast(stoi(word)); + } + + uint8_t arrayIdx = 0; + if(currentChip == Chip::CHIP_0) { + if(currentCopy == Copy::COPY_1) { + arrayIdx = 1; + } + else if(currentCopy != Copy::COPY_0) { + return HasReturnvaluesIF::RETURN_FAILED; + } + } + + else if(currentChip == Chip::CHIP_1) { + if(currentCopy == Copy::COPY_0) { + arrayIdx = 2; + } + else if(currentCopy == Copy::COPY_1) { + arrayIdx = 3; + } + else { + return HasReturnvaluesIF::RETURN_FAILED; + } + } + + if(wordIdx == 5) { + if(word == "unlocked.") { + protArray[arrayIdx] = false; + } + else { + protArray[arrayIdx] = true; + } + } + } + return HasReturnvaluesIF::RETURN_OK; +} + void CoreController::performWatchdogControlOperation() { // Only perform each fifth iteration if(watchdogFifoFd != 0 and opDivider.checkAndIncrement()) { diff --git a/bsp_q7s/core/CoreController.h b/bsp_q7s/core/CoreController.h index b26c99c5..10cda0df 100644 --- a/bsp_q7s/core/CoreController.h +++ b/bsp_q7s/core/CoreController.h @@ -16,17 +16,28 @@ public: enum Chip: uint8_t { CHIP_0, CHIP_1, - NO_CHIP + NO_CHIP, + SELF_CHIP, + ALL_CHIP }; enum Copy: uint8_t { COPY_0, COPY_1, - NO_COPY + NO_COPY, + SELF_COPY, + ALL_COPY }; + static constexpr char CHIP_PROT_SCRIPT[] = "/home/root/scripts/get-chip-prot-status.sh"; + static constexpr char CHIP_STATE_FILE[] = "/tmp/chip_prot_status.txt"; + static constexpr char CURR_COPY_FILE[] = "/tmp/curr_copy.txt"; + static constexpr char VERSION_FILE[] = "/conf/sd_status"; + static constexpr ActionId_t LIST_DIRECTORY_INTO_FILE = 0; static constexpr ActionId_t REBOOT_OBC = 32; + static constexpr ActionId_t MOUNT_OTHER_COPY = 33; + static constexpr uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::CORE; @@ -46,19 +57,39 @@ public: ReturnValue_t handleCommandMessage(CommandMessage *message) override; void performControlOperation() override; + /** + * Generate a file containing the chip lock/unlock states inside /tmp/chip_status.txt + * @return + */ + static ReturnValue_t generateChipStateFile(); static ReturnValue_t incrementAllocationFailureCount(); static void getCurrentBootCopy(Chip& chip, Copy& copy); + + ReturnValue_t updateProtInfo(bool regenerateChipStateFile = true); + + /** + * Checks whether the target chip and copy are writeprotected and protect them if they are + * not + * @param targetChip + * @param targetCopy + * @param protect + * @param protOperationPerformed [out] Can be used to determine whether any operation + * was performed + * @param updateProtFile Specify whether the protection info file is updated + * @return + */ + ReturnValue_t checkAndSetBootCopyProtection(Chip targetChip, Copy targetCopy, + bool protect, bool& protOperationPerformed, bool updateProtFile = true); + bool sdInitFinished() const; private: - static Chip currentChip; - static Copy currentCopy; + static Chip CURRENT_CHIP; + static Copy CURRENT_COPY; - ReturnValue_t initializeLocalDataPool(localpool::DataPool& localDataPoolMap, - LocalDataPoolManager& poolManager) override; - LocalPoolDataSetBase* getDataSetHandle(sid_t sid) override; - ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode, - uint32_t *msToReachTheMode); + // Designated value for rechecking FIFO open + static constexpr int RETRY_FIFO_OPEN = -2; + int watchdogFifoFd = 0; // States for SD state machine, which is used in non-blocking mode enum class SdStates { @@ -85,9 +116,6 @@ private: SdCardManager* sdcMan = nullptr; - ReturnValue_t initSdCardBlocking(); - ReturnValue_t sdStateMachine(); - struct SdInfo { sd::SdCard pref = sd::SdCard::NONE; sd::SdState prefState = sd::SdState::OFF; @@ -108,9 +136,29 @@ private: sd::SdCard commandedCard = sd::SdCard::NONE; sd::SdState commandedState = sd::SdState::OFF; }; - SdInfo sdInfo; + /** + * Index 0: Chip 0 Copy 0 + * Index 1: Chip 0 Copy 1 + * Index 2: Chip 1 Copy 0 + * Index 3: Chip 1 Copy 1 + */ + std::array protArray; + + ReturnValue_t initializeLocalDataPool(localpool::DataPool& localDataPoolMap, + LocalDataPoolManager& poolManager) override; + LocalPoolDataSetBase* getDataSetHandle(sid_t sid) override; + ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode, + uint32_t *msToReachTheMode); + + ReturnValue_t initVersionFile(); + ReturnValue_t initBootCopy(); + ReturnValue_t initWatchdogFifo(); + ReturnValue_t initSdCardBlocking(); + void initPrint(); + + ReturnValue_t sdStateMachine(); void updateSdInfoOther(); ReturnValue_t sdCardSetup(sd::SdCard sdCard, sd::SdState targetState, std::string sdChar, bool printOutput = true); @@ -120,24 +168,14 @@ private: void executeNextExternalSdCommand(); void checkExternalSdCommandStatus(); - ReturnValue_t initVersionFile(); - ReturnValue_t initBootCopy(); - ReturnValue_t initWatchdogFifo(); - ReturnValue_t actionListDirectoryIntoFile(ActionId_t actionId, MessageQueueId_t commandedBy, const uint8_t *data, size_t size); ReturnValue_t actionPerformReboot(const uint8_t *data, size_t size); - void initPrint(); - - // Designated value for rechecking FIFO open - static constexpr int RETRY_FIFO_OPEN = -2; - int watchdogFifoFd = 0; - PeriodicOperationDivider opDivider; void performWatchdogControlOperation(); + + ReturnValue_t handleProtInfoUpdateLine(std::string nextLine); }; - - #endif /* BSP_Q7S_CORE_CORECONTROLLER_H_ */