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:
+2
-2
@@ -166,10 +166,10 @@ const CONF = {
|
||||
_PC_2_SYMLINKS: '1',
|
||||
/** Comma-separated `ctx.bareOsSyscall` op names implemented in stock booter. */
|
||||
BARE_OS_SYSCALL_OPS:
|
||||
'accept,access,bind,chdir,chmod,connect,exists,fcntl,fdatasync,fsync,ftruncate,getcwd,getsockopt,kill,link,listen,lstat,mkdir,mount,mq_open,mq_receive,mq_send,pathconf,posixPoll,readFile,readdir,readlink,readv,recv,recvfrom,recvmsg,rename,rmdir,select,send,sendmsg,setsockopt,shutdown,socket,stat,symlink,truncate,umask,umount,unlink,utimes,writeFile,writev',
|
||||
'accept,access,bind,chdir,chmod,connect,exists,fcntl,fdatasync,fsync,ftruncate,getcwd,getsockopt,kill,link,listen,lstat,mkdir,mount,mq_open,mq_receive,mq_send,nanosleep,pathconf,posixPoll,readFile,readdir,readlink,readv,recv,recvfrom,recvmsg,rename,rmdir,select,send,sendmsg,setsockopt,shutdown,socket,stat,symlink,truncate,umask,umount,unlink,utimes,writeFile,writev',
|
||||
/** POSIX.1 XSH-style names documented in `/proc/bare_os/syscalls.json` opsDetail (socket family are syscall probes returning ENOSYS-shaped results). */
|
||||
BARE_OS_POSIX_XSH_OPS:
|
||||
'open,close,read,write,lseek,pipe,dup,dup2,fcntl,poll,select,umask,socket,bind,listen,accept,connect,send,recv,recvfrom,sendmsg,recvmsg,shutdown',
|
||||
'open,close,read,write,lseek,nanosleep,pipe,dup,dup2,fcntl,poll,select,umask,socket,bind,listen,accept,connect,send,recv,recvfrom,sendmsg,recvmsg,shutdown',
|
||||
/** Encodings accepted by `/bin/iconv` (subset; case-insensitive names). */
|
||||
BARE_OS_ICONV_ENCODINGS: 'UTF-8,ISO-8859-1,UTF-16LE,UTF-16BE',
|
||||
/** Synthetic process table JSON path (logical VFS). */
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"schemaVersion": 8,
|
||||
"ctxApiVersion": "1.46.0",
|
||||
"ctxApiVersion": "1.47.0",
|
||||
"posixProfile": {
|
||||
"id": "bare-os-posix-like",
|
||||
"version": "1.0.10"
|
||||
"version": "1.0.11"
|
||||
},
|
||||
"ops": ["readFile", "writeFile", "socket"],
|
||||
"opsDetail": [
|
||||
@@ -29,7 +29,7 @@
|
||||
"posixXsh": {
|
||||
"schema": 2,
|
||||
"note": "POSIX.1 XSH-style names; socket bridge may implement SOCK_DGRAM sendmsg/recvmsg when BARE_OS_POSIX_SOCKET_FD_BRIDGE.",
|
||||
"namesCsv": "open,close,read,write,readv,writev,getsockopt,setsockopt,lseek,pipe,dup,dup2,fcntl,poll,select,umask,socket,bind,listen,accept,connect,send,recv,recvfrom,sendmsg,recvmsg,shutdown"
|
||||
"namesCsv": "open,close,read,write,readv,writev,getsockopt,setsockopt,lseek,nanosleep,pipe,dup,dup2,fcntl,poll,select,umask,socket,bind,listen,accept,connect,send,recv,recvfrom,sendmsg,recvmsg,shutdown"
|
||||
},
|
||||
"socketMsgSurface": {
|
||||
"schema": 3,
|
||||
|
||||
+160
@@ -2484,6 +2484,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
|
||||
@@ -2513,6 +2656,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' ||
|
||||
@@ -2826,6 +2970,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)
|
||||
|
||||
+178
-178
@@ -1,6 +1,12 @@
|
||||
{
|
||||
"version": 1,
|
||||
"bundles": [
|
||||
{
|
||||
"path": "/lib/bare/bundles/b4a.js",
|
||||
"keys": [
|
||||
"b4a"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/safetyCatch.js",
|
||||
"keys": [
|
||||
@@ -13,12 +19,6 @@
|
||||
"hypercoreIdEncoding"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/b4a.js",
|
||||
"keys": [
|
||||
"b4a"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/compactEncoding.js",
|
||||
"keys": [
|
||||
@@ -37,12 +37,6 @@
|
||||
"protomux"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/barePath.js",
|
||||
"keys": [
|
||||
"barePath"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareEncoding.js",
|
||||
"keys": [
|
||||
@@ -55,6 +49,12 @@
|
||||
"bareEvents"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/barePath.js",
|
||||
"keys": [
|
||||
"barePath"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareAbort.js",
|
||||
"keys": [
|
||||
@@ -73,18 +73,18 @@
|
||||
"bareAnsiEscapes"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareAddonResolve.js",
|
||||
"keys": [
|
||||
"bareAddonResolve"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareReadline.js",
|
||||
"keys": [
|
||||
"bareReadline"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareAddonResolve.js",
|
||||
"keys": [
|
||||
"bareAddonResolve"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareCrypto.js",
|
||||
"keys": [
|
||||
@@ -98,9 +98,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareAssert.js",
|
||||
"path": "/lib/bare/bundles/bareAsyncHooks.js",
|
||||
"keys": [
|
||||
"bareAssert"
|
||||
"bareAsyncHooks"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -115,18 +115,18 @@
|
||||
"fetch"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareAsyncHooks.js",
|
||||
"keys": [
|
||||
"bareAsyncHooks"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareAtomics.js",
|
||||
"keys": [
|
||||
"bareAtomics"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareAssert.js",
|
||||
"keys": [
|
||||
"bareAssert"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareBmp.js",
|
||||
"keys": [
|
||||
@@ -139,18 +139,24 @@
|
||||
"bareBundleCompile"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareBuffer.js",
|
||||
"keys": [
|
||||
"bareBuffer"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareBundle.js",
|
||||
"keys": [
|
||||
"bareBundle"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareBluetoothApple.js",
|
||||
"keys": [
|
||||
"bareBluetoothApple"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareBuffer.js",
|
||||
"keys": [
|
||||
"bareBuffer"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareBundleEvaluate.js",
|
||||
"keys": [
|
||||
@@ -158,9 +164,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareBluetoothApple.js",
|
||||
"path": "/lib/bare/bundles/bareBundleId.js",
|
||||
"keys": [
|
||||
"bareBluetoothApple"
|
||||
"bareBundleId"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -175,24 +181,18 @@
|
||||
"bareConsole"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareDaemon.js",
|
||||
"keys": [
|
||||
"bareDaemon"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareBundleId.js",
|
||||
"keys": [
|
||||
"bareBundleId"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareChannel.js",
|
||||
"keys": [
|
||||
"bareChannel"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareDaemon.js",
|
||||
"keys": [
|
||||
"bareDaemon"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareDebugLog.js",
|
||||
"keys": [
|
||||
@@ -223,6 +223,12 @@
|
||||
"bareEnv"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareCov.js",
|
||||
"keys": [
|
||||
"bareCov"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareExif.js",
|
||||
"keys": [
|
||||
@@ -235,12 +241,6 @@
|
||||
"bareDgram"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareFfmpeg.js",
|
||||
"keys": [
|
||||
"bareFfmpeg"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareFfmpegEncodings.js",
|
||||
"keys": [
|
||||
@@ -248,9 +248,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareCov.js",
|
||||
"path": "/lib/bare/bundles/bareFfmpeg.js",
|
||||
"keys": [
|
||||
"bareCov"
|
||||
"bareFfmpeg"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -259,6 +259,12 @@
|
||||
"bareFormat"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareFileLogger.js",
|
||||
"keys": [
|
||||
"bareFileLogger"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareGif.js",
|
||||
"keys": [
|
||||
@@ -272,9 +278,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareFileLogger.js",
|
||||
"path": "/lib/bare/bundles/bareHrtime.js",
|
||||
"keys": [
|
||||
"bareFileLogger"
|
||||
"bareHrtime"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -284,15 +290,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareHrtime.js",
|
||||
"path": "/lib/bare/bundles/bareGtk.js",
|
||||
"keys": [
|
||||
"bareHrtime"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareFs.js",
|
||||
"keys": [
|
||||
"bareFs"
|
||||
"bareGtk"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -302,15 +302,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareGtk.js",
|
||||
"path": "/lib/bare/bundles/bareFs.js",
|
||||
"keys": [
|
||||
"bareGtk"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareIco.js",
|
||||
"keys": [
|
||||
"bareIco"
|
||||
"bareFs"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -325,6 +319,12 @@
|
||||
"bareInspect"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareIco.js",
|
||||
"keys": [
|
||||
"bareIco"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareHttp1.js",
|
||||
"keys": [
|
||||
@@ -337,12 +337,6 @@
|
||||
"bareHttps"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareJpeg.js",
|
||||
"keys": [
|
||||
"bareJpeg"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareIpc.js",
|
||||
"keys": [
|
||||
@@ -350,9 +344,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareLief.js",
|
||||
"path": "/lib/bare/bundles/bareJpeg.js",
|
||||
"keys": [
|
||||
"bareLief"
|
||||
"bareJpeg"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -361,12 +355,6 @@
|
||||
"bareIntl"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareLogger.js",
|
||||
"keys": [
|
||||
"bareLogger"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareInspector.js",
|
||||
"keys": [
|
||||
@@ -374,9 +362,15 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareMake.js",
|
||||
"path": "/lib/bare/bundles/bareLogger.js",
|
||||
"keys": [
|
||||
"bareMake"
|
||||
"bareLogger"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareLief.js",
|
||||
"keys": [
|
||||
"bareLief"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -386,15 +380,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareModule.js",
|
||||
"path": "/lib/bare/bundles/bareMake.js",
|
||||
"keys": [
|
||||
"bareModule"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareModuleLexer.js",
|
||||
"keys": [
|
||||
"bareModuleLexer"
|
||||
"bareMake"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -404,9 +392,15 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareMedia.js",
|
||||
"path": "/lib/bare/bundles/bareModuleLexer.js",
|
||||
"keys": [
|
||||
"bareMedia"
|
||||
"bareModuleLexer"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareModule.js",
|
||||
"keys": [
|
||||
"bareModule"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -428,15 +422,15 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareNative.js",
|
||||
"path": "/lib/bare/bundles/bareMedia.js",
|
||||
"keys": [
|
||||
"bareNative"
|
||||
"bareMedia"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareNet.js",
|
||||
"path": "/lib/bare/bundles/bareNative.js",
|
||||
"keys": [
|
||||
"bareNet"
|
||||
"bareNative"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -446,15 +440,15 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareOs.js",
|
||||
"path": "/lib/bare/bundles/bareNet.js",
|
||||
"keys": [
|
||||
"bareOs"
|
||||
"bareNet"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/barePack.js",
|
||||
"path": "/lib/bare/bundles/bareOs.js",
|
||||
"keys": [
|
||||
"barePack"
|
||||
"bareOs"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -464,9 +458,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/barePackDrive.js",
|
||||
"path": "/lib/bare/bundles/barePack.js",
|
||||
"keys": [
|
||||
"barePackDrive"
|
||||
"barePack"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -475,12 +469,6 @@
|
||||
"barePng"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/barePrebuild.js",
|
||||
"keys": [
|
||||
"barePrebuild"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/barePipe.js",
|
||||
"keys": [
|
||||
@@ -488,9 +476,15 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareQuerystring.js",
|
||||
"path": "/lib/bare/bundles/barePackDrive.js",
|
||||
"keys": [
|
||||
"bareQuerystring"
|
||||
"barePackDrive"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/barePrebuild.js",
|
||||
"keys": [
|
||||
"barePrebuild"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -500,9 +494,15 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareProcess.js",
|
||||
"path": "/lib/bare/bundles/bareDev.js",
|
||||
"keys": [
|
||||
"bareProcess"
|
||||
"bareDev"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareQuerystring.js",
|
||||
"keys": [
|
||||
"bareQuerystring"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -511,12 +511,6 @@
|
||||
"bareQueueMicrotask"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareRealm.js",
|
||||
"keys": [
|
||||
"bareRealm"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareNodeRuntime.js",
|
||||
"keys": [
|
||||
@@ -524,15 +518,15 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareDev.js",
|
||||
"path": "/lib/bare/bundles/bareProcess.js",
|
||||
"keys": [
|
||||
"bareDev"
|
||||
"bareProcess"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareRuntime.js",
|
||||
"path": "/lib/bare/bundles/bareRealm.js",
|
||||
"keys": [
|
||||
"bareRuntime"
|
||||
"bareRealm"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -542,9 +536,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareRpc.js",
|
||||
"path": "/lib/bare/bundles/bareRuntime.js",
|
||||
"keys": [
|
||||
"bareRpc"
|
||||
"bareRuntime"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -554,9 +548,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareRepl.js",
|
||||
"path": "/lib/bare/bundles/bareRpc.js",
|
||||
"keys": [
|
||||
"bareRepl"
|
||||
"bareRpc"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -565,6 +559,12 @@
|
||||
"bareSemver"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareRepl.js",
|
||||
"keys": [
|
||||
"bareRepl"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareRun.js",
|
||||
"keys": [
|
||||
@@ -589,6 +589,12 @@
|
||||
"bareStringDecoder"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareStorage.js",
|
||||
"keys": [
|
||||
"bareStorage"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareStream.js",
|
||||
"keys": [
|
||||
@@ -596,9 +602,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareStorage.js",
|
||||
"path": "/lib/bare/bundles/bareStdio.js",
|
||||
"keys": [
|
||||
"bareStorage"
|
||||
"bareStdio"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -608,9 +614,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareStdio.js",
|
||||
"path": "/lib/bare/bundles/bareTap.js",
|
||||
"keys": [
|
||||
"bareStdio"
|
||||
"bareTap"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -625,18 +631,6 @@
|
||||
"bareSystemLogger"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareTiff.js",
|
||||
"keys": [
|
||||
"bareTiff"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareTap.js",
|
||||
"keys": [
|
||||
"bareTap"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareSubprocess.js",
|
||||
"keys": [
|
||||
@@ -644,9 +638,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareThread.js",
|
||||
"path": "/lib/bare/bundles/bareTiff.js",
|
||||
"keys": [
|
||||
"bareThread"
|
||||
"bareTiff"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -655,18 +649,24 @@
|
||||
"bareTcp"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareTpl.js",
|
||||
"keys": [
|
||||
"bareTpl"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareTimers.js",
|
||||
"keys": [
|
||||
"bareTimers"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareThread.js",
|
||||
"keys": [
|
||||
"bareThread"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareTpl.js",
|
||||
"keys": [
|
||||
"bareTpl"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareType.js",
|
||||
"keys": [
|
||||
@@ -697,6 +697,12 @@
|
||||
"bareUnpack"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareUnionBundle.js",
|
||||
"keys": [
|
||||
"bareUnionBundle"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareV8.js",
|
||||
"keys": [
|
||||
@@ -715,18 +721,18 @@
|
||||
"bareWalkHandles"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareUnionBundle.js",
|
||||
"keys": [
|
||||
"bareUnionBundle"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareWebKit.js",
|
||||
"keys": [
|
||||
"bareWebKit"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareUtils.js",
|
||||
"keys": [
|
||||
"bareUtils"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareV8ToIstanbul.js",
|
||||
"keys": [
|
||||
@@ -739,12 +745,6 @@
|
||||
"bareWebKitGtk"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareUtils.js",
|
||||
"keys": [
|
||||
"bareUtils"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareWebp.js",
|
||||
"keys": [
|
||||
@@ -757,12 +757,6 @@
|
||||
"bareWhich"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareXdiff.js",
|
||||
"keys": [
|
||||
"bareXdiff"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareWinUi.js",
|
||||
"keys": [
|
||||
@@ -770,9 +764,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareZlib.js",
|
||||
"path": "/lib/bare/bundles/bareXdiff.js",
|
||||
"keys": [
|
||||
"bareZlib"
|
||||
"bareXdiff"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -787,6 +781,12 @@
|
||||
"bareWorker"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareZlib.js",
|
||||
"keys": [
|
||||
"bareZlib"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareZmq.js",
|
||||
"keys": [
|
||||
@@ -1595,8 +1595,8 @@
|
||||
],
|
||||
"bundleProvenance": {
|
||||
"schemaVersion": 1,
|
||||
"generatedAt": "2026-04-05T06:20:46.518Z",
|
||||
"gitCommit": "7f4279d315b4c6f13ddab76bedf5d24b7ca3fe40",
|
||||
"generatedAt": "2026-04-05T06:36:54.183Z",
|
||||
"gitCommit": "ae6f1cf8ac19cb9442f22f7c6709c71fce23be3b",
|
||||
"nodeVersion": "v22.22.0",
|
||||
"bundleTier": "all",
|
||||
"normativeManifest": "packages/bare-os-booter/lib/bare-module-manifest.json",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"schema": 1,
|
||||
"atMs": 1775370045811,
|
||||
"atMs": 1775371013414,
|
||||
"commands": [
|
||||
"arch",
|
||||
"awk",
|
||||
|
||||
@@ -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)
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user