Skip to content

Commit

Permalink
Enforce no OS downgrade for Protected Devices
Browse files Browse the repository at this point in the history
  • Loading branch information
monkbroc committed Jun 27, 2024
1 parent 91bae8d commit a4b0100
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 20 deletions.
31 changes: 30 additions & 1 deletion src/lib/flash-helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ const ensureError = utilities.ensureError;
// Flashing an NCP firmware can take a few minutes
const FLASH_TIMEOUT = 4 * 60000;

// Minimum version of Device OS that supports protected modules
const PROTECTED_MINIMUM_VERSION = '6.0.0';
const PROTECTED_MINIMUM_SYSTEM_VERSION = 6000;
const PROTECTED_MINIMUM_BOOTLOADER_VERSION = 3000;

async function flashFiles({ device, flashSteps, resetAfterFlash = true, ui, verbose=true }) {
let progress = null;
progress = verbose ? _createFlashProgress({ flashSteps, ui, verbose }) : null;
Expand Down Expand Up @@ -358,8 +363,32 @@ function validateDFUSupport({ device, ui }) {
}
}

function validateModulesForProtection({ modules, device }) {
async function validateModulesForProtection({ modules, device }) {
try {
const s = await device.getProtectionState();

if (!s.protected && !s.overridden) {
// Device is not protected -> Don't enforce Device OS version
return;
}
} catch (error) {
// Device does not support device protection -> Don't enforce Device OS version
if (error.message === 'Not supported') {
return;
}
throw error;
}

for (const module of modules) {
const oldSystem = module.moduleFunction === ModuleInfo.FunctionType.SYSTEM_PART &&
module.moduleVersion < PROTECTED_MINIMUM_SYSTEM_VERSION;
const oldBootloader = module.moduleFunction === ModuleInfo.FunctionType.BOOTLOADER &&
module.moduleIndex === 0 && module.moduleVersion < PROTECTED_MINIMUM_BOOTLOADER_VERSION;

if (oldSystem || oldBootloader) {
throw new Error(`Cannot downgrade Device OS below version ${PROTECTED_MINIMUM_VERSION} on a Protected Device`);
}
}
}

module.exports = {
Expand Down
38 changes: 19 additions & 19 deletions src/lib/flash-helper.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -689,65 +689,65 @@ describe('flash-helper', () => {

beforeEach(() => {
device = {
getProtectedState: sinon.stub(),
getProtectionState: sinon.stub(),
};
});

describe('device is not protected', () => {
beforeEach(() => {
device.getProtectedState.returns({ protected: false, overriden: false });
device.getProtectionState.returns({ protected: false, overridden: false });
});

it('does does not reject old modules', () => {
it('does does not reject old modules', async () => {
let error;
try {
validateModulesForProtection({ device, modules: modulesOldBootloader });
await validateModulesForProtection({ device, modules: modulesOldBootloader });
} catch (_error) {
error = _error;
}
expect(error).to.be.undefined;
});

it('does does not reject new modules', () => {
it('does does not reject new modules', async () => {
let error;
try {
validateModulesForProtection({ device, modules: modulesNew });
await validateModulesForProtection({ device, modules: modulesNew });
} catch (_error) {
error = _error;
}
expect(error).to.be.undefined;
});
});

describe('device is protected', () => {
describe('device is protected', () => {
beforeEach(() => {
device.getProtectedState.returns({ protected: true, overriden: false });
device.getProtectionState.returns({ protected: true, overridden: false });
});

it('throws an exception if the bootloader is too old', () => {
it('throws an exception if the bootloader is too old', async () => {
let error;
try {
validateModulesForProtection({ device, modules: modulesOldBootloader });
await validateModulesForProtection({ device, modules: modulesOldBootloader });
} catch (_error) {
error = _error;
}
expect(error).to.have.property('message').that.eql('Cannot downgrade Device OS below version 6.0.0 on a Protected Device');
});

it('throws an exception if the system part is too old', () => {
it('throws an exception if the system part is too old', async () => {
let error;
try {
validateModulesForProtection({ device, modules: modulesOldSystem });
await validateModulesForProtection({ device, modules: modulesOldSystem });
} catch (_error) {
error = _error;
}
expect(error).to.have.property('message').that.eql('Cannot downgrade Device OS below version 6.0.0 on a Protected Device');
});

it('does does not reject new modules', () => {
it('does does not reject new modules', async () => {
let error;
try {
validateModulesForProtection({ device, modules: modulesNew });
await validateModulesForProtection({ device, modules: modulesNew });
} catch (_error) {
error = _error;
}
Expand All @@ -757,23 +757,23 @@ describe('flash-helper', () => {

describe('device does not support protection', () => {
beforeEach(() => {
device.getProtectedState.throws(new Error('Not supported'));
device.getProtectionState.throws(new Error('Not supported'));
});

it('does does not reject old modules', () => {
it('does does not reject old modules', async () => {
let error;
try {
validateModulesForProtection({ device, modules: modulesOldBootloader });
await validateModulesForProtection({ device, modules: modulesOldBootloader });
} catch (_error) {
error = _error;
}
expect(error).to.be.undefined;
});

it('does does not reject new modules', () => {
it('does does not reject new modules', async () => {
let error;
try {
validateModulesForProtection({ device, modules: modulesNew });
await validateModulesForProtection({ device, modules: modulesNew });
} catch (_error) {
error = _error;
}
Expand Down

0 comments on commit a4b0100

Please sign in to comment.