From 09e511809011c10892ac8d0e3f821c0db0e8f762 Mon Sep 17 00:00:00 2001 From: keeramis Date: Thu, 27 Jun 2024 15:48:36 -0700 Subject: [PATCH] Protect bootloader before flashing with the correct requirements --- src/cmd/flash.js | 6 +-- src/cmd/update.js | 4 +- src/lib/flash-helper.js | 14 ++++-- src/lib/flash-helper.test.js | 85 +++++++++++++++++++++++------------- 4 files changed, 71 insertions(+), 38 deletions(-) diff --git a/src/cmd/flash.js b/src/cmd/flash.js index 08d1f5cea..a9b914c06 100644 --- a/src/cmd/flash.js +++ b/src/cmd/flash.js @@ -19,7 +19,7 @@ const { createFlashSteps, filterModulesToFlash, parseModulesToFlash, - validateModulesForProtection, + maintainDeviceProtection, flashFiles, validateDFUSupport, getFileFlashInfo @@ -88,7 +88,7 @@ module.exports = class FlashCommand extends CLICommandBase { platformId: device.platformId, platformName }); - await validateModulesForProtection({ modules: modulesToFlash, device }); + await maintainDeviceProtection({ modules: modulesToFlash, device }); const flashSteps = await createFlashSteps({ modules: modulesToFlash, isInDfuMode: device.isInDfuMode, @@ -158,7 +158,7 @@ module.exports = class FlashCommand extends CLICommandBase { let modulesToFlash = [...fileModules, ...deviceOsModules]; modulesToFlash = filterModulesToFlash({ modules: modulesToFlash, platformId }); - await validateModulesForProtection({ modules: modulesToFlash, device }); + await maintainDeviceProtection({ modules: modulesToFlash, device }); const flashSteps = await createFlashSteps({ modules: modulesToFlash, isInDfuMode: device.isInDfuMode, diff --git a/src/cmd/update.js b/src/cmd/update.js index 6e4d2e9cb..2aa3c817d 100644 --- a/src/cmd/update.js +++ b/src/cmd/update.js @@ -6,7 +6,7 @@ const semver = require('semver'); const usbUtils = require('./usb-util'); const deviceOsUtils = require('../lib/device-os-version-util'); const CLICommandBase = require('./base'); -const { parseModulesToFlash, filterModulesToFlash, validateModulesForProtection, createFlashSteps, flashFiles, validateDFUSupport } = require('../lib/flash-helper'); +const { parseModulesToFlash, filterModulesToFlash, maintainDeviceProtection, createFlashSteps, flashFiles, validateDFUSupport } = require('../lib/flash-helper'); const createApiCache = require('../lib/api-cache'); module.exports = class UpdateCommand extends CLICommandBase { @@ -41,7 +41,7 @@ module.exports = class UpdateCommand extends CLICommandBase { }); const deviceOsModules = await parseModulesToFlash({ files: deviceOsBinaries }); const modulesToFlash = filterModulesToFlash({ modules: deviceOsModules, platformId: device.platformId, allowAll: true }); - await validateModulesForProtection({ modules: modulesToFlash, device }); + await maintainDeviceProtection({ modules: modulesToFlash, device }); const flashSteps = await createFlashSteps({ modules: modulesToFlash, isInDfuMode: device.isInDfuMode , platformId: device.platformId }); await flashFiles({ device, flashSteps, ui: this.ui }); this.ui.write('Update success!'); diff --git a/src/lib/flash-helper.js b/src/lib/flash-helper.js index 2ea58c0bc..d5e4e69bc 100644 --- a/src/lib/flash-helper.js +++ b/src/lib/flash-helper.js @@ -4,7 +4,7 @@ const { delay } = require('./utilities'); const VError = require('verror'); const { PLATFORMS, platformForId } =require('./platform'); const { moduleTypeFromNumber, sortBinariesByDependency } = require('./dependency-walker'); -const { HalModuleParser: ModuleParser, ModuleInfo } = require('binary-version-reader'); +const { HalModuleParser: ModuleParser, ModuleInfo, createProtectedModule } = require('binary-version-reader'); const path = require('path'); const fs = require('fs-extra'); const os = require('os'); @@ -363,7 +363,7 @@ function validateDFUSupport({ device, ui }) { } } -async function validateModulesForProtection({ modules, device }) { +async function maintainDeviceProtection({ modules, device }) { try { const s = await device.getProtectionState(); @@ -389,6 +389,14 @@ async function validateModulesForProtection({ modules, device }) { if (oldSystem || oldBootloader) { throw new Error(`Cannot downgrade Device OS below version ${PROTECTED_MINIMUM_VERSION} on a Protected Device`); } + + // Enable Device Protection on the bootloader when flashing a Protected Device + if (moduleFunction === ModuleInfo.FunctionType.BOOTLOADER && moduleIndex === 0) { + const protectedBuffer = await createProtectedModule(module.fileBuffer); + const parser = new ModuleParser(); + const protectedModule = await parser.parseBuffer({ fileBuffer: protectedBuffer }); + Object.assign(module, protectedModule); + } } } @@ -399,7 +407,7 @@ module.exports = { createFlashSteps, prepareDeviceForFlash, validateDFUSupport, - validateModulesForProtection, + maintainDeviceProtection, getFileFlashInfo, _get256Hash, _skipAsset diff --git a/src/lib/flash-helper.test.js b/src/lib/flash-helper.test.js index d4cc644de..0348f7047 100644 --- a/src/lib/flash-helper.test.js +++ b/src/lib/flash-helper.test.js @@ -7,7 +7,7 @@ const { filterModulesToFlash, prepareDeviceForFlash, validateDFUSupport, - validateModulesForProtection, + maintainDeviceProtection, getFileFlashInfo, _get256Hash, _skipAsset @@ -661,44 +661,55 @@ describe('flash-helper', () => { }); }); - describe('validateModulesForProtection', () => { + describe.only('maintainDeviceProtection', () => { let device; - const modulesOldBootloader = [{ - prefixInfo: { + + + + let modulesOldBootloader; + let modulesOldSystem; + let modulesNew; + let newBootloader; + let newSystemPart; + + beforeEach(async () => { + device = { + getProtectionState: sinon.stub(), + }; + + const oldBootloaderBuffer = await firmwareTestHelper.createFirmwareBinary({ moduleFunction: ModuleInfo.FunctionType.BOOTLOADER, platformId: 12, moduleIndex: 0, moduleVersion: 1200 - } - }]; - const modulesOldSystem = [{ - prefixInfo: { + }); + const oldBootloader = await new HalModuleParser().parseBuffer({ fileBuffer: oldBootloaderBuffer }); + modulesOldBootloader = [oldBootloader]; + + const oldSystemBuffer = await firmwareTestHelper.createFirmwareBinary({ moduleFunction: ModuleInfo.FunctionType.SYSTEM_PART, platformId: 12, moduleIndex: 0, moduleVersion: 5800 - } - }]; - const modulesNew = [{ - prefixInfo: { + }); + const oldSystem = await new HalModuleParser().parseBuffer({ fileBuffer: oldSystemBuffer }); + modulesOldSystem = [oldSystem]; + + const newBootloaderBuffer = await firmwareTestHelper.createFirmwareBinary({ moduleFunction: ModuleInfo.FunctionType.BOOTLOADER, platformId: 12, moduleIndex: 0, moduleVersion: 3000 - } - }, { - prefixInfo: { + }); + const newSystemPartBuffer = await firmwareTestHelper.createFirmwareBinary({ moduleFunction: ModuleInfo.FunctionType.SYSTEM_PART, platformId: 12, moduleIndex: 0, moduleVersion: 6000 - } - }]; - - beforeEach(() => { - device = { - getProtectionState: sinon.stub(), - }; + }); + newBootloader = await new HalModuleParser().parseBuffer({ fileBuffer: newBootloaderBuffer }); + newSystemPart = await new HalModuleParser().parseBuffer({ fileBuffer: newSystemPartBuffer }); + modulesNew = [newBootloader, newSystemPart]; }); describe('device is not protected', () => { @@ -709,7 +720,7 @@ describe('flash-helper', () => { it('does does not reject old modules', async () => { let error; try { - await validateModulesForProtection({ device, modules: modulesOldBootloader }); + await maintainDeviceProtection({ device, modules: modulesOldBootloader }); } catch (_error) { error = _error; } @@ -719,15 +730,22 @@ describe('flash-helper', () => { it('does does not reject new modules', async () => { let error; try { - await validateModulesForProtection({ device, modules: modulesNew }); + await maintainDeviceProtection({ device, modules: modulesNew }); } catch (_error) { error = _error; } expect(error).to.be.undefined; }); + + it('does not protect the bootloader', async () => { + await maintainDeviceProtection({ device, modules: modulesNew }); + + expect(newBootloader).not.to.have.property('security'); + expect(newSystemPart).not.to.have.property('security'); + }); }); - describe('device is protected', () => { + describe('device is protected', () => { beforeEach(() => { device.getProtectionState.returns({ protected: true, overridden: false }); }); @@ -735,7 +753,7 @@ describe('flash-helper', () => { it('throws an exception if the bootloader is too old', async () => { let error; try { - await validateModulesForProtection({ device, modules: modulesOldBootloader }); + await maintainDeviceProtection({ device, modules: modulesOldBootloader }); } catch (_error) { error = _error; } @@ -745,7 +763,7 @@ describe('flash-helper', () => { it('throws an exception if the system part is too old', async () => { let error; try { - await validateModulesForProtection({ device, modules: modulesOldSystem }); + await maintainDeviceProtection({ device, modules: modulesOldSystem }); } catch (_error) { error = _error; } @@ -755,12 +773,19 @@ describe('flash-helper', () => { it('does does not reject new modules', async () => { let error; try { - await validateModulesForProtection({ device, modules: modulesNew }); + await maintainDeviceProtection({ device, modules: modulesNew }); } catch (_error) { error = _error; } expect(error).to.be.undefined; }); + + it('protects the bootloader', async () => { + await maintainDeviceProtection({ device, modules: modulesNew }); + + expect(newBootloader).to.have.property('security'); + expect(newSystemPart).not.to.have.property('security'); + }); }); describe('device does not support protection', () => { @@ -771,7 +796,7 @@ describe('flash-helper', () => { it('does does not reject old modules', async () => { let error; try { - await validateModulesForProtection({ device, modules: modulesOldBootloader }); + await maintainDeviceProtection({ device, modules: modulesOldBootloader }); } catch (_error) { error = _error; } @@ -781,7 +806,7 @@ describe('flash-helper', () => { it('does does not reject new modules', async () => { let error; try { - await validateModulesForProtection({ device, modules: modulesNew }); + await maintainDeviceProtection({ device, modules: modulesNew }); } catch (_error) { error = _error; }