Implement roadmap items across booter, protocol, kernel bundle, coreutils, and docs.
- Hyperswarm connection caps (env + /proc + disk.os replication_operator_sketch) - Protomux operator metrics schema; warm-cache invalidation on replication - ctx.bareOsSyscall nanosleep; socket bridge getsockopt/setsockopt (keepalive/nodelay) - Extension signer pin verification before kernel.ext.d scripts; ctx/DTS updates - Structured seeder logging (BARE_OS_SEED_LOG_*); release-checklist holepunch drift - POSIX profile/matrix/conformance lists + handbook/env appendix/kernel-extensions - Coreutils printf golden tests; sync kernel ↔ seeder parity after bundle
This commit is contained in:
@@ -2433,6 +2433,149 @@ function kernelExtDependencyDepth(entries) {
|
||||
return max
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge extension signer pin maps from boot policy env mirrors (V2–V5; later JSON wins per key).
|
||||
* @param {Record<string, unknown> | null | undefined} env
|
||||
* @returns {Record<string, string | string[]>}
|
||||
*/
|
||||
function mergeExtensionSignerPinsFromEnv(env) {
|
||||
if (!env || typeof env !== 'object') return {}
|
||||
const keys = [
|
||||
'BARE_OS_BOOT_POLICY_EXTENSION_SIGNER_PINS_V2_JSON',
|
||||
'BARE_OS_BOOT_POLICY_EXTENSION_SIGNER_PINS_V3_JSON',
|
||||
'BARE_OS_BOOT_POLICY_EXTENSION_SIGNER_PINS_V4_JSON',
|
||||
'BARE_OS_BOOT_POLICY_EXTENSION_SIGNER_PINS_V5_JSON'
|
||||
]
|
||||
/** @type {Record<string, string | string[]>} */
|
||||
const out = {}
|
||||
for (const k of keys) {
|
||||
const raw = String(env[k] ?? '').trim()
|
||||
if (!raw) continue
|
||||
try {
|
||||
const o = JSON.parse(raw)
|
||||
if (o && typeof o === 'object' && !Array.isArray(o)) {
|
||||
for (const [ik, iv] of Object.entries(o)) {
|
||||
out[String(ik)] = /** @type {string | string[]} */ (iv)
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
/* ignore malformed JSON */
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
/**
|
||||
* When boot.policy pins an extension id to Ed25519 key(s), verify detached signature over script bytes.
|
||||
* @param {Record<string, unknown>} ctx
|
||||
* @param {{ extId: string, file: string, signaturePointer?: string }} ent
|
||||
* @param {string} imgPath
|
||||
* @param {Record<string, string | string[]>} pins
|
||||
* @param {boolean} strictPol
|
||||
* @returns {Promise<boolean>} true if the script may run
|
||||
*/
|
||||
async function verifyKernelExtSignerPinsForScript(
|
||||
ctx,
|
||||
ent,
|
||||
imgPath,
|
||||
pins,
|
||||
strictPol
|
||||
) {
|
||||
const id = String(ent.extId || '').trim()
|
||||
const need = pins[id]
|
||||
if (need == null) return true
|
||||
/** @type {string[]} */
|
||||
const pubHexList = Array.isArray(need)
|
||||
? need.map((x) =>
|
||||
String(x)
|
||||
.trim()
|
||||
.toLowerCase()
|
||||
.replace(/^0x/, '')
|
||||
)
|
||||
: [String(need).trim().toLowerCase().replace(/^0x/, '')]
|
||||
const validKeys = pubHexList.filter(
|
||||
(h) => h.length === 64 && /^[0-9a-f]+$/.test(h)
|
||||
)
|
||||
if (!validKeys.length) {
|
||||
bootStructuredLog(
|
||||
ctx,
|
||||
'error',
|
||||
'kernelExt.signerPinBadKey',
|
||||
`[kernel.ext.d] extensionSignerPins for "${id}" must be 64-char hex pubkey(s)`
|
||||
)
|
||||
return !strictPol
|
||||
}
|
||||
const sigPtr = ent.signaturePointer
|
||||
? String(ent.signaturePointer).trim()
|
||||
: ''
|
||||
if (!sigPtr.startsWith('/')) {
|
||||
bootStructuredLog(
|
||||
ctx,
|
||||
'error',
|
||||
'kernelExt.signerPinNoSigPath',
|
||||
`[kernel.ext.d] "${id}": signaturePointer (absolute path to signature) required when extensionSignerPins lists this id`
|
||||
)
|
||||
return !strictPol
|
||||
}
|
||||
const { drive, b4a } = ctx
|
||||
if (!drive || typeof drive.get !== 'function' || !b4a) {
|
||||
bootStructuredLog(
|
||||
ctx,
|
||||
'error',
|
||||
'kernelExt.signerPinNoDrive',
|
||||
'[kernel.ext.d] signer pin verify requires ctx.drive.get and ctx.b4a'
|
||||
)
|
||||
return !strictPol
|
||||
}
|
||||
let scriptBuf
|
||||
let sigBuf
|
||||
try {
|
||||
scriptBuf = await drive.get(imgPath)
|
||||
sigBuf = await drive.get(sigPtr)
|
||||
} catch (e) {
|
||||
bootStructuredLog(
|
||||
ctx,
|
||||
'error',
|
||||
'kernelExt.signerPinRead',
|
||||
`[kernel.ext.d] signer pin read: ${(e && e.message) || String(e)}`
|
||||
)
|
||||
return !strictPol
|
||||
}
|
||||
if (!scriptBuf || !scriptBuf.byteLength || !sigBuf || !sigBuf.byteLength) {
|
||||
bootStructuredLog(
|
||||
ctx,
|
||||
'error',
|
||||
'kernelExt.signerPinMissingBytes',
|
||||
`[kernel.ext.d] "${id}": script or signature file missing/empty for pin verify`
|
||||
)
|
||||
return !strictPol
|
||||
}
|
||||
const verifyFn = ctx.bareOsVerifyBootManifestSignature
|
||||
if (typeof verifyFn !== 'function') {
|
||||
bootStructuredLog(
|
||||
ctx,
|
||||
'error',
|
||||
'kernelExt.signerPinNoVerify',
|
||||
'[kernel.ext.d] ctx.bareOsVerifyBootManifestSignature unavailable; cannot enforce extensionSignerPins'
|
||||
)
|
||||
return !strictPol
|
||||
}
|
||||
for (const pk of validKeys) {
|
||||
try {
|
||||
if (verifyFn.call(ctx, scriptBuf, sigBuf, pk) === true) return true
|
||||
} catch {
|
||||
/* try next pubkey */
|
||||
}
|
||||
}
|
||||
bootStructuredLog(
|
||||
ctx,
|
||||
'error',
|
||||
'kernelExt.signerPinVerifyFailed',
|
||||
`[kernel.ext.d] "${id}": Ed25519 verify failed for pinned key(s)`
|
||||
)
|
||||
return !strictPol
|
||||
}
|
||||
|
||||
/**
|
||||
* Optional `/etc/bare-os/kernel.ext.d/*.json` with `{ "scripts": ["/lib/bare-os/extensions/foo.js"] }`.
|
||||
* @param {Record<string, unknown>} ctx
|
||||
@@ -2462,6 +2605,7 @@ async function runKernelExtDropins(ctx, opts = {}) {
|
||||
const strictPol =
|
||||
ctx.env?.BARE_OS_BOOT_POLICY_STRICT === '1' ||
|
||||
ctx.env?.BARE_OS_BOOT_POLICY_STRICT === 'true'
|
||||
const extSignerPins = mergeExtensionSignerPinsFromEnv(ctx.env)
|
||||
const multisigExtGate =
|
||||
ctx.env?.BARE_OS_EXTENSION_MULTISIG_VERIFY === '1' ||
|
||||
ctx.env?.BARE_OS_EXTENSION_MULTISIG_VERIFY === 'true' ||
|
||||
@@ -2775,6 +2919,22 @@ async function runKernelExtDropins(ctx, opts = {}) {
|
||||
)
|
||||
continue
|
||||
}
|
||||
if (
|
||||
!(await verifyKernelExtSignerPinsForScript(
|
||||
ctx,
|
||||
ent,
|
||||
imgPath,
|
||||
extSignerPins,
|
||||
strictPol
|
||||
))
|
||||
) {
|
||||
if (strictPol) {
|
||||
if (typeof ctx.bareOsRequestBooterExit === 'function')
|
||||
ctx.bareOsRequestBooterExit(1)
|
||||
return false
|
||||
}
|
||||
continue
|
||||
}
|
||||
try {
|
||||
await run(imgPath)
|
||||
loadedSet.add(imgPath)
|
||||
|
||||
Reference in New Issue
Block a user