chainlesschain 0.162.183 → 0.162.185
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/assets/web-panel/.build-hash +1 -1
- package/src/assets/web-panel/assets/{AIOps-BapS7lz4.js → AIOps-Co4ipAKx.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-CXYdXEUI.js → ActionButton-BpsoDrDq.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-CKR5Lexn.js → Analytics-DMUqeBik.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-DATVUOXB.js → AppLayout-C6fD_dXr.js} +5 -5
- package/src/assets/web-panel/assets/{Artifacts-vb_0ZlV1.js → Artifacts-DW0YlQlV.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-BI1l9GWt.js → Audit-DXtHiiFK.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-BFXbaUEf.js → BackgroundAgents-BgmF62U-.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-DEYBJJ6H.js → Backup-D8vhVLQC.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-COdzeO0M.js → BaseInput-D7nCtY2X.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-oSN6sfM5.js → Chat-CBZLEV2G.js} +6 -6
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-CI_jT0ru.js → ChatBubbleRenderer-CtDb-2Qu.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-BezEa4tm.js → Checkbox-DJLkeD4M.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-CNEL0Ife.js → Codegen-Cs6xO8Fd.js} +1 -1
- package/src/assets/web-panel/assets/{Col-Bf2Y2Bn1.js → Col-Dtx9wxfT.js} +1 -1
- package/src/assets/web-panel/assets/{Community-BfUlu4Hc.js → Community-DiigJg4n.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-BN4xWP9e.js → Compact-B67oMDDL.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-Bt6BKmEP.js → Compliance-BBDl-Jos.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-DKLp8YxO.js → Cowork-Ba98hSsa.js} +3 -3
- package/src/assets/web-panel/assets/{Cron-o7Hhw6ky.js → Cron-DBWQZIz7.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-DaNXWJIw.js → Crosschain-OcrKzxAt.js} +1 -1
- package/src/assets/web-panel/assets/{DID-B-Qa2mha.js → DID-mW2eSbjM.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-CMX0Qnxw.js → Dashboard-BmsDPmKJ.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-BLuLyRu_.js → Dropdown-CVzmCyRx.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-CFBAeMij.js → EmailListRenderer-vVgqKzhh.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-DWzXQ67V.js → FamilyGuardDashboard-CWY5t_ZJ.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-DB1QSLgr.js → Federation-ZGomhjxr.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-C-OKCToP.js → FormItemContext-DyaknbLr.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-DMJFtFZf.js → GenericCardRenderer-CmIvN1qr.js} +1 -1
- package/src/assets/web-panel/assets/{Git-DsGSujOV.js → Git-DQOJIYkG.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-B0iS9NEW.js → Governance-CMiY-EEp.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-CH004H7c.js → Inference-D6IXuucf.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-Q9MTQ83c.js → KnowledgeGraph-6jkTL0hV.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-B_fyjZK9.js → Logs-N0jD-349.js} +2 -2
- package/src/assets/web-panel/assets/MarkdownRenderer-BL1IVXm-.js +1 -0
- package/src/assets/web-panel/assets/{Marketplace-BIStF9d1.js → Marketplace-WhYuhBxm.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-pGfal768.js → McpTools-DTeO28xy.js} +5 -5
- package/src/assets/web-panel/assets/{Memory-xbNqpIqB.js → Memory-MSHzPSE-.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-B5EQGrIK.js → MobileBridge-Cyqs3J3W.js} +1 -1
- package/src/assets/web-panel/assets/MobileProjects-7IN2hWHg.js +1 -0
- package/src/assets/web-panel/assets/{Mtc-a_rmfxJH.js → Mtc-MWBnezNM.js} +5 -5
- package/src/assets/web-panel/assets/{MtcAudit-BmKuofUr.js → MtcAudit-DQu35Nu-.js} +4 -4
- package/src/assets/web-panel/assets/{Multisig-BQbJ-CAN.js → Multisig-CQS_M-DP.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-JtPJKX25.js → NLProgramming-WD16vQvY.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-ZFKznTSG.js → Notes-DqsiSwOq.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-B6aHRBBR.js → NotificationSettings-D3LoxO-P.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-DdcsOqEz.js → OrderTableRenderer-C5jPoTd6.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-BFDTAUgS.js → Organization-48aMBJso.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-0FoTfbWH.js → Overflow-j-a2XkhR.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-CWd90etw.js → P2P-BYpBNYnh.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-DtCGC-W-.js → PdhVaultBrowser-CYCsrrLg.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-CvQ7nr7T.js → Permissions-ZRXGXDFb.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-rdNPcR-Z.js → PersonalDataHub-6OWUPHyL.js} +5 -5
- package/src/assets/web-panel/assets/{Pipeline-CmrfiNOs.js → Pipeline-FcjlDK9E.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-D7ep1h_t.js → Privacy-vD_6Tldp.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-C0xKINHS.js → ProjectInit-B_CHOLXp.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-AOmZFp-F.js → ProjectSettings-rEiqQ2da.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-BWHSkXZP.js → Projects-Bg8obRAM.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-Cb7JCTPL.js → Providers-Dgtt97B4.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-BDMehcXC.js → QrScannerModal-DaGVylZO.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-BF6_1nvx.js → QuickAsk-DP2_2x3u.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-BHfT-A28.js → Recommend-D29yj4ki.js} +1 -1
- package/src/assets/web-panel/assets/RemoteSession-Ue2wnBLp.js +5 -0
- package/src/assets/web-panel/assets/{Reputation-CsWHLEcj.js → Reputation-CrxIHqeC.js} +1 -1
- package/src/assets/web-panel/assets/{Row-D6srnWhm.js → Row-BgSzJPCn.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-Xhr-KyVd.js → RssFeed-AwhYOrP9.js} +3 -3
- package/src/assets/web-panel/assets/{Search-vIbIJvwL.js → Search-D2shpEcm.js} +1 -1
- package/src/assets/web-panel/assets/{Security-Bzi5Aiko.js → Security-BtKzhTbT.js} +4 -4
- package/src/assets/web-panel/assets/{Services-BHtVX52P.js → Services-BY0DsUSm.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-C0R8B2jf.js → Skeleton-B3Sb0UI9.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-DtT6rWOX.js → Skills-Ne5w0bDs.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-0B37mxVU.js → Sla-C8VkaP4T.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-0V2jE1Bs.js → SpeechSettings-BQdIEYP9.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-CYedRzaj.js → SyncSettings-CwFafrUg.js} +2 -2
- package/src/assets/web-panel/assets/Tasks-yJuKoDlR.js +1 -0
- package/src/assets/web-panel/assets/{Templates-BKoHztGT.js → Templates-DYn9qCmx.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant--17nwVNZ.js → Tenant-DkKReHvn.js} +1 -1
- package/src/assets/web-panel/assets/Terminal-r6bd-owt.js +3 -0
- package/src/assets/web-panel/assets/{TimelineRenderer-C5jx4AE3.js → TimelineRenderer-Mq2juUC3.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-DYJKYa9t.js → Tokens-BnMw7MRi.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-DChpWiQ9.js → Trigger-CTzKp4o9.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-DfWG52EA.js → Trust-BBrSZm9U.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-CMugYcyA.js → UkeySign-D9fDvEMq.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-BOSmrHAd.js → VideoEditing-DUi5ve-0.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-D5g3k3Sa.js → Wallet-C8Fi1P8_.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-D-7u4Mkc.js → WebAuthn-s1LppYi2.js} +5 -5
- package/src/assets/web-panel/assets/{WorkflowEditor-CFzZMSUJ.js → WorkflowEditor-DJL2C4lj.js} +1 -1
- package/src/assets/web-panel/assets/{chat-VbR6l6mc.js → chat-D3F2ndOB.js} +1 -1
- package/src/assets/web-panel/assets/{colors-BSZn8EDS.js → colors-B7739-e3.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-y74obMEq.js → compact-item-CcJbFTF4.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-C326bjex.js → createContext-CuP_DEFS.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-Cj_36GHq.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-D_INJQT_.js → hasIn-6YEXfIik.js} +1 -1
- package/src/assets/web-panel/assets/{index-DuIkfnTF.js → index-4h3lpWJ3.js} +1 -1
- package/src/assets/web-panel/assets/{index-DBkzrpiL.js → index-BIID4XcP.js} +1 -1
- package/src/assets/web-panel/assets/{index-B7SrC-On.js → index-BOHUo3aM.js} +1 -1
- package/src/assets/web-panel/assets/{index-BnSfnSMP.js → index-BYYSLEjn.js} +1 -1
- package/src/assets/web-panel/assets/{index-KF9Zmqln.js → index-Bh4hcNWW.js} +1 -1
- package/src/assets/web-panel/assets/{index-C327pLbw.js → index-BhIKnQAW.js} +1 -1
- package/src/assets/web-panel/assets/{index-E_v1ZCTP.js → index-Bru_kpZl.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bfw2hf2s.js → index-BsdSnHQE.js} +1 -1
- package/src/assets/web-panel/assets/{index-jYaogFE8.js → index-BxSqVMGh.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dlxh9D8D.js → index-C3ZA_h1j.js} +1 -1
- package/src/assets/web-panel/assets/{index-DdyjrCAu.js → index-C3pctdCb.js} +1 -1
- package/src/assets/web-panel/assets/{index-abmn_8Yz.js → index-CRuoRapN.js} +1 -1
- package/src/assets/web-panel/assets/{index-qMA4GYdQ.js → index-CY0zd_jc.js} +1 -1
- package/src/assets/web-panel/assets/index-CezFrAmD.js +1 -0
- package/src/assets/web-panel/assets/index-Cxgguez6.js +1 -0
- package/src/assets/web-panel/assets/{index-Cr3uuz0C.js → index-CxradkS6.js} +19 -19
- package/src/assets/web-panel/assets/{index-DwHSZLXg.js → index-D0K_rFC1.js} +1 -1
- package/src/assets/web-panel/assets/{index-CMHqs3Jb.js → index-D0zdPyTD.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bnua8IX3.js → index-D3haorUt.js} +1 -1
- package/src/assets/web-panel/assets/{index-BY8-nCgs.js → index-D6Ij_2uw.js} +1 -1
- package/src/assets/web-panel/assets/{index-FQBsuExX.js → index-DDRlBaDt.js} +1 -1
- package/src/assets/web-panel/assets/{index-C-ZCaUJc.js → index-DGsE7MQz.js} +1 -1
- package/src/assets/web-panel/assets/{index-BjcWKg1S.js → index-DHvxXXNA.js} +1 -1
- package/src/assets/web-panel/assets/{index-GA80ir_u.js → index-DV11jpeO.js} +1 -1
- package/src/assets/web-panel/assets/{index-CsovTpx9.js → index-DXdnfDVK.js} +1 -1
- package/src/assets/web-panel/assets/{index-nSn2-C4N.js → index-D_75jYWk.js} +1 -1
- package/src/assets/web-panel/assets/{index-BJi3UqBt.js → index-DjI9MkId.js} +1 -1
- package/src/assets/web-panel/assets/{index-gINyI1rh.js → index-DlSvpNMf.js} +1 -1
- package/src/assets/web-panel/assets/{index-CfLJ42kv.js → index-Dox44j29.js} +1 -1
- package/src/assets/web-panel/assets/{index-C2NyllnW.js → index-DpEKmjoa.js} +1 -1
- package/src/assets/web-panel/assets/{index-Iw0FfqUz.js → index-Dsy7_x4s.js} +1 -1
- package/src/assets/web-panel/assets/{index-4eyH-eC2.js → index-Gxw09e9R.js} +1 -1
- package/src/assets/web-panel/assets/{index-4PIeTM--.js → index-LfRlSmqe.js} +1 -1
- package/src/assets/web-panel/assets/{index-IZAWt0H8.js → index-Nz-MUHD1.js} +1 -1
- package/src/assets/web-panel/assets/{index-DUU2606o.js → index-b9cuvFEv.js} +1 -1
- package/src/assets/web-panel/assets/{index-CzE53HiB.js → index-eR6H6NR7.js} +1 -1
- package/src/assets/web-panel/assets/{index-9PIVuXqo.js → index-fWgUQZ9d.js} +1 -1
- package/src/assets/web-panel/assets/{index-DkH1JvEt.js → index-mfWQRSLn.js} +1 -1
- package/src/assets/web-panel/assets/{index-DNMxIsDg.js → index-yOZYSNmG.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-DI0Zaf8-.js → initDefaultProps-CJ1Bq2L3.js} +1 -1
- package/src/assets/web-panel/assets/{motion-BZDKSy3Z.js → motion-rYJN_vzf.js} +1 -1
- package/src/assets/web-panel/assets/{move-DsIW01Vp.js → move-DnDK2gTP.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-CohkDhsf.js → mtc-parser-CKnXy7ES.js} +1 -1
- package/src/assets/web-panel/assets/{omit-DpiN5rzg.js → omit-3nRc3hWT.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-qbuqni3y.js → pickAttrs-Ddjj3sLu.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-mBky6714.js → placementArrow-CbsbphQY.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-Bas3eQ2K.js → responsiveObserve-D9aZ4VDJ.js} +1 -1
- package/src/assets/web-panel/assets/{slide-CBx_SKoK.js → slide-D4pvdFj0.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-BlYguJSV.js → statusUtils-C2W-vY-S.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-BCYQmRGv.js → styleChecker-Cbq5150d.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-Dp5dybLM.js → useFlexGapSupport-BA2B7R82.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-DHAMBgA2.js → useFs-CLrwg3xg.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-W6jsSw76.js → usePersonalDataHub-DQeAI5qs.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-BkI6aayc.js → vnode-8BDGy-YU.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-C_IMGueq.js → zoom-B2SzFprl.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/commands/agenda.js +74 -1
- package/src/commands/background-session.js +11 -1
- package/src/commands/batch.js +160 -5
- package/src/commands/plugin.js +90 -27
- package/src/commands/session.js +31 -1
- package/src/commands/team.js +212 -6
- package/src/data/changelog.json +26 -0
- package/src/gateways/terminal/PtyManager.js +45 -15
- package/src/gateways/ws/ws-agent-handler.js +15 -1
- package/src/gateways/ws/ws-session-gateway.js +88 -0
- package/src/harness/background-task-command-runner.js +234 -0
- package/src/harness/background-task-manager.js +150 -20
- package/src/harness/background-task-worker.js +17 -11
- package/src/harness/jsonl-session-store.js +57 -6
- package/src/harness/mcp-client.js +65 -43
- package/src/lib/agent-batch.js +4 -1
- package/src/lib/agent-team/team-worktree.js +3 -0
- package/src/lib/async-hook-supervisor.cjs +82 -10
- package/src/lib/async-hook-supervisor.js +50 -4
- package/src/lib/background-agent-supervisor.js +46 -0
- package/src/lib/collaboration-run-store.js +362 -0
- package/src/lib/event-runtime-host.js +12 -10
- package/src/lib/hook-runner.cjs +105 -18
- package/src/lib/hook-runner.js +79 -6
- package/src/lib/hook-shell-command.cjs +148 -0
- package/src/lib/hooks-v2-runtime.js +280 -81
- package/src/lib/hooks-v2-workspace-context.js +258 -0
- package/src/lib/jsonl-session-store.js +2 -0
- package/src/lib/lsp/__tests__/lsp-client.test.js +15 -0
- package/src/lib/lsp/lsp-client.js +12 -1
- package/src/lib/plugin-monitor-supervisor.js +53 -16
- package/src/lib/plugin-runtime/bin.js +21 -5
- package/src/lib/plugin-runtime/install.js +249 -57
- package/src/lib/plugin-runtime/mcp.js +21 -2
- package/src/lib/plugin-runtime/monitors.js +19 -3
- package/src/lib/plugin-runtime/sandbox-policy.js +100 -4
- package/src/lib/process-execution-broker/index.js +1151 -44
- package/src/lib/process-execution-broker/linux-generic-bwrap-runtime.js +1557 -0
- package/src/lib/process-execution-broker/linux-generic-bwrap.js +1378 -0
- package/src/lib/process-execution-broker/platform-sandbox.js +586 -58
- package/src/lib/session-usage.js +202 -2
- package/src/lib/stream-retry.js +29 -0
- package/src/repl/agent-repl.js +40 -3
- package/src/runtime/agent-core.js +304 -42
- package/src/runtime/headless-runner.js +48 -1
- package/src/runtime/headless-stream.js +42 -2
- package/src/workers/background-agent-worker.js +5 -11
- package/src/assets/web-panel/assets/MarkdownRenderer-C0o4FtpD.js +0 -1
- package/src/assets/web-panel/assets/MobileProjects-VTc3gT1y.js +0 -1
- package/src/assets/web-panel/assets/RemoteSession-B6EEf8hh.js +0 -5
- package/src/assets/web-panel/assets/Tasks-D-R1x8vm.js +0 -1
- package/src/assets/web-panel/assets/Terminal-Dnkos7vW.js +0 -3
- package/src/assets/web-panel/assets/devWarning-D3Bho_6u.js +0 -1
- package/src/assets/web-panel/assets/index-5iAFwYx1.js +0 -1
- package/src/assets/web-panel/assets/index-BfnB7LPx.js +0 -1
|
@@ -4,10 +4,11 @@
|
|
|
4
4
|
* Platform enforcement currently available:
|
|
5
5
|
* - macOS: Seatbelt sandbox-exec profiles
|
|
6
6
|
* - Linux: prlimit resource-limit wrapper, plus a narrow bubblewrap backend
|
|
7
|
-
* for an attested direct strict Plugin Node bin or
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
7
|
+
* for an attested direct strict Plugin Node bin or a narrow static/dynamic
|
|
8
|
+
* ELF native bin. Dynamic acceptance binds PT_INTERP plus the entry's direct
|
|
9
|
+
* DT_NEEDED names to an attested system-file set; broader loader surfaces,
|
|
10
|
+
* shells, broader working directories, host-writable paths, inherited
|
|
11
|
+
* descriptors, and network egress remain fail-closed.
|
|
11
12
|
* - Windows: Win32 Job Object + restricted-token wrapper, with an attested
|
|
12
13
|
* zero-capability AppContainer for explicit filesystem/network boundaries
|
|
13
14
|
*
|
|
@@ -25,6 +26,10 @@ import * as fs from "node:fs";
|
|
|
25
26
|
import crypto from "node:crypto";
|
|
26
27
|
import { spawnSync as nativeSpawnSync } from "node:child_process";
|
|
27
28
|
import { fileURLToPath } from "node:url";
|
|
29
|
+
import {
|
|
30
|
+
applyLinuxGenericWorkspaceSandbox,
|
|
31
|
+
isLinuxGenericWorkspaceContract,
|
|
32
|
+
} from "./linux-generic-bwrap-runtime.js";
|
|
28
33
|
|
|
29
34
|
/**
|
|
30
35
|
* Stable boundary identifiers shared by broker policies, platform plans, and
|
|
@@ -169,6 +174,15 @@ const LINUX_ELF64_PROGRAM_HEADER_BYTES = 56;
|
|
|
169
174
|
const LINUX_ELF64_DYNAMIC_ENTRY_BYTES = 16;
|
|
170
175
|
const LINUX_ELF_MAX_PROGRAM_HEADERS = 128;
|
|
171
176
|
const LINUX_ELF_MAX_DYNAMIC_ENTRIES = 4096;
|
|
177
|
+
const LINUX_ELF_MAX_NEEDED_ENTRIES = 128;
|
|
178
|
+
const LINUX_ELF_MAX_INTERPRETER_BYTES = 4096;
|
|
179
|
+
const LINUX_ELF_MAX_STRING_TABLE_BYTES = 1024 * 1024;
|
|
180
|
+
const LINUX_AUXV_ENTRY_BYTES = 16;
|
|
181
|
+
const LINUX_AUXV_MAX_BYTES = 64 * 1024;
|
|
182
|
+
const LINUX_AUXV_PAGE_SIZE = 6n;
|
|
183
|
+
const LINUX_MIN_RUNTIME_PAGE_BYTES = 4096;
|
|
184
|
+
const LINUX_MAX_RUNTIME_PAGE_BYTES = 1024 * 1024;
|
|
185
|
+
const LINUX_ELF_MAX_UINT64 = (1n << 64n) - 1n;
|
|
172
186
|
const LINUX_ELF_TYPE_EXEC = 2;
|
|
173
187
|
const LINUX_ELF_TYPE_DYN = 3;
|
|
174
188
|
const LINUX_ELF_PROGRAM_LOAD = 1;
|
|
@@ -177,8 +191,24 @@ const LINUX_ELF_PROGRAM_INTERP = 3;
|
|
|
177
191
|
const LINUX_ELF_PROGRAM_GNU_STACK = 0x6474e551;
|
|
178
192
|
const LINUX_ELF_DYNAMIC_NULL = 0n;
|
|
179
193
|
const LINUX_ELF_DYNAMIC_NEEDED = 1n;
|
|
194
|
+
const LINUX_ELF_DYNAMIC_STRTAB = 5n;
|
|
195
|
+
const LINUX_ELF_DYNAMIC_STRSZ = 10n;
|
|
196
|
+
const LINUX_ELF_DYNAMIC_RPATH = 15n;
|
|
197
|
+
const LINUX_ELF_DYNAMIC_TEXTREL = 22n;
|
|
198
|
+
const LINUX_ELF_DYNAMIC_FLAGS = 30n;
|
|
199
|
+
const LINUX_ELF_DYNAMIC_RUNPATH = 29n;
|
|
200
|
+
const LINUX_ELF_DYNAMIC_CONFIG = 0x6ffffefan;
|
|
201
|
+
const LINUX_ELF_DYNAMIC_DEPAUDIT = 0x6ffffefbn;
|
|
202
|
+
const LINUX_ELF_DYNAMIC_AUDIT = 0x6ffffefcn;
|
|
180
203
|
const LINUX_ELF_DYNAMIC_FLAGS_1 = 0x6ffffffbn;
|
|
204
|
+
const LINUX_ELF_DYNAMIC_AUXILIARY = 0x7ffffffdn;
|
|
205
|
+
const LINUX_ELF_DYNAMIC_FILTER = 0x7fffffffn;
|
|
206
|
+
const LINUX_ELF_DYNAMIC_FLAG_TEXTREL = 0x4n;
|
|
181
207
|
const LINUX_ELF_DYNAMIC_FLAG_PIE = 0x08000000n;
|
|
208
|
+
const LINUX_NATIVE_DYNAMIC_DIRECT_SYSTEM_SET_SCOPE =
|
|
209
|
+
"initial-pt_interp-and-direct-dt_needed-attested-system-set";
|
|
210
|
+
const LINUX_NATIVE_DYNAMIC_DIRECT_SYSTEM_SET_MECHANISM =
|
|
211
|
+
"parsed-elf-direct-system-set-to-attested-node-runtime-fds-v1";
|
|
182
212
|
const LINUX_ELF_MACHINES = Object.freeze({
|
|
183
213
|
x64: 62,
|
|
184
214
|
arm64: 183,
|
|
@@ -291,6 +321,7 @@ function normalizeSandboxRequest(profileOrRequest, explicitRequest) {
|
|
|
291
321
|
profile,
|
|
292
322
|
requiredBoundaries,
|
|
293
323
|
sync: request.sync === true,
|
|
324
|
+
pty: request.pty === true,
|
|
294
325
|
executionContract:
|
|
295
326
|
request.executionContract &&
|
|
296
327
|
typeof request.executionContract === "object" &&
|
|
@@ -2600,8 +2631,11 @@ function linuxBubblewrapProbe(
|
|
|
2600
2631
|
contentSnapshot = null,
|
|
2601
2632
|
supervisorBinding = null,
|
|
2602
2633
|
pluginTreeSnapshot = null,
|
|
2634
|
+
nativeDynamicClosure = null,
|
|
2603
2635
|
) {
|
|
2604
|
-
const native =
|
|
2636
|
+
const native =
|
|
2637
|
+
typeof targetRuntime === "string" && targetRuntime.startsWith("native-");
|
|
2638
|
+
const dynamicNative = targetRuntime === "native-dynamic-elf";
|
|
2605
2639
|
const expectedSnapshotScope = native
|
|
2606
2640
|
? LINUX_NATIVE_ENTRY_SNAPSHOT_SCOPE
|
|
2607
2641
|
: LINUX_NODE_ENTRY_SNAPSHOT_SCOPE;
|
|
@@ -2631,10 +2665,34 @@ function linuxBubblewrapProbe(
|
|
|
2631
2665
|
LINUX_NODE_PLUGIN_TREE_SNAPSHOT_CONSISTENCY &&
|
|
2632
2666
|
pluginTreeSnapshot?.contractBound === false &&
|
|
2633
2667
|
pluginTreeSnapshot?.atomic === false;
|
|
2668
|
+
const initialDynamicLoadClosureDescriptorBound =
|
|
2669
|
+
dynamicNative &&
|
|
2670
|
+
attempted &&
|
|
2671
|
+
snapshot &&
|
|
2672
|
+
runnable &&
|
|
2673
|
+
reason === null &&
|
|
2674
|
+
supervisorDescriptorBound &&
|
|
2675
|
+
nativeDynamicClosure?.mechanism ===
|
|
2676
|
+
LINUX_NATIVE_DYNAMIC_DIRECT_SYSTEM_SET_MECHANISM &&
|
|
2677
|
+
nativeDynamicClosure?.scope ===
|
|
2678
|
+
LINUX_NATIVE_DYNAMIC_DIRECT_SYSTEM_SET_SCOPE &&
|
|
2679
|
+
typeof nativeDynamicClosure?.interpreter === "string" &&
|
|
2680
|
+
path.posix.isAbsolute(nativeDynamicClosure.interpreter) &&
|
|
2681
|
+
Number.isSafeInteger(nativeDynamicClosure?.dependencies) &&
|
|
2682
|
+
nativeDynamicClosure.dependencies >= 0 &&
|
|
2683
|
+
nativeDynamicClosure.dependencies <= LINUX_ELF_MAX_NEEDED_ENTRIES &&
|
|
2684
|
+
Number.isSafeInteger(nativeDynamicClosure?.files) &&
|
|
2685
|
+
nativeDynamicClosure.files >= 1 &&
|
|
2686
|
+
typeof nativeDynamicClosure?.digest === "string" &&
|
|
2687
|
+
/^[a-f0-9]{64}$/.test(nativeDynamicClosure.digest);
|
|
2634
2688
|
return {
|
|
2635
|
-
kind:
|
|
2636
|
-
? "linux-bwrap-plugin-native-
|
|
2637
|
-
: "
|
|
2689
|
+
kind: dynamicNative
|
|
2690
|
+
? "linux-bwrap-plugin-native-dynamic-elf-policy-v1"
|
|
2691
|
+
: targetRuntime === "native-static-elf"
|
|
2692
|
+
? "linux-bwrap-plugin-native-static-elf-policy-v1"
|
|
2693
|
+
: native
|
|
2694
|
+
? "linux-bwrap-plugin-native-elf-policy-v1"
|
|
2695
|
+
: "linux-bwrap-plugin-node-policy-v1",
|
|
2638
2696
|
attempted,
|
|
2639
2697
|
runnable,
|
|
2640
2698
|
reason,
|
|
@@ -2660,6 +2718,17 @@ function linuxBubblewrapProbe(
|
|
|
2660
2718
|
pluginTreeSnapshotAtomic: pluginTreeSnapshot.atomic,
|
|
2661
2719
|
}
|
|
2662
2720
|
: {}),
|
|
2721
|
+
...(initialDynamicLoadClosureDescriptorBound
|
|
2722
|
+
? {
|
|
2723
|
+
initialDynamicLoadClosureDescriptorBound: true,
|
|
2724
|
+
initialDynamicLoadClosureScope: nativeDynamicClosure.scope,
|
|
2725
|
+
initialDynamicLoadClosureMechanism: nativeDynamicClosure.mechanism,
|
|
2726
|
+
initialDynamicInterpreter: nativeDynamicClosure.interpreter,
|
|
2727
|
+
initialDynamicDependencyCount: nativeDynamicClosure.dependencies,
|
|
2728
|
+
initialDynamicRuntimeFileCount: nativeDynamicClosure.files,
|
|
2729
|
+
initialDynamicLoadClosureDigest: nativeDynamicClosure.digest,
|
|
2730
|
+
}
|
|
2731
|
+
: {}),
|
|
2663
2732
|
supervisorDescriptorBound,
|
|
2664
2733
|
...(supervisorDescriptorBound
|
|
2665
2734
|
? {
|
|
@@ -2957,8 +3026,11 @@ function validateLinuxPluginContract(
|
|
|
2957
3026
|
{ sealedEntry = false } = {},
|
|
2958
3027
|
) {
|
|
2959
3028
|
const nodeContract = contract?.kind === "strict-plugin-node-bin";
|
|
2960
|
-
const
|
|
3029
|
+
const legacyStaticNativeContract =
|
|
2961
3030
|
contract?.kind === "strict-plugin-native-static-elf-bin";
|
|
3031
|
+
const nativeContract =
|
|
3032
|
+
legacyStaticNativeContract ||
|
|
3033
|
+
contract?.kind === "strict-plugin-native-elf-bin";
|
|
2962
3034
|
const entryIsSealed =
|
|
2963
3035
|
(nodeContract || nativeContract) && sealedEntry === true;
|
|
2964
3036
|
if (
|
|
@@ -2969,7 +3041,7 @@ function validateLinuxPluginContract(
|
|
|
2969
3041
|
return { ok: false, reason: "execution_contract_missing" };
|
|
2970
3042
|
}
|
|
2971
3043
|
if (
|
|
2972
|
-
sync !== true ||
|
|
3044
|
+
(sync !== true && sync !== false) ||
|
|
2973
3045
|
spawnOpts?.shell !== false ||
|
|
2974
3046
|
spawnOpts?.detached === true ||
|
|
2975
3047
|
!linuxStdioIsNarrow(spawnOpts?.stdio) ||
|
|
@@ -3081,16 +3153,22 @@ function validateLinuxPluginContract(
|
|
|
3081
3153
|
let entryFormat = null;
|
|
3082
3154
|
if (nativeContract && !entryIsSealed) {
|
|
3083
3155
|
try {
|
|
3084
|
-
entryFormat =
|
|
3085
|
-
runtime,
|
|
3086
|
-
contract.entryIdentity,
|
|
3087
|
-
);
|
|
3156
|
+
entryFormat = inspectLinuxNativePath(runtime, contract.entryIdentity);
|
|
3088
3157
|
} catch (error) {
|
|
3089
3158
|
return {
|
|
3090
3159
|
ok: false,
|
|
3091
3160
|
reason: error.message || "native_entry_unattested",
|
|
3092
3161
|
};
|
|
3093
3162
|
}
|
|
3163
|
+
if (
|
|
3164
|
+
legacyStaticNativeContract &&
|
|
3165
|
+
entryFormat.runtime !== "native-static-elf"
|
|
3166
|
+
) {
|
|
3167
|
+
return {
|
|
3168
|
+
ok: false,
|
|
3169
|
+
reason: "native_entry_dynamic_contract_required",
|
|
3170
|
+
};
|
|
3171
|
+
}
|
|
3094
3172
|
}
|
|
3095
3173
|
if (
|
|
3096
3174
|
!validateLinuxPluginTree(runtime, contract.pluginRoot) ||
|
|
@@ -3101,7 +3179,12 @@ function validateLinuxPluginContract(
|
|
|
3101
3179
|
return {
|
|
3102
3180
|
ok: true,
|
|
3103
3181
|
contract,
|
|
3104
|
-
entryRuntime: nativeContract
|
|
3182
|
+
entryRuntime: nativeContract
|
|
3183
|
+
? entryFormat?.runtime ||
|
|
3184
|
+
(legacyStaticNativeContract
|
|
3185
|
+
? "native-static-elf"
|
|
3186
|
+
: "native-unclassified")
|
|
3187
|
+
: "node",
|
|
3105
3188
|
entryFormat,
|
|
3106
3189
|
};
|
|
3107
3190
|
}
|
|
@@ -3170,7 +3253,7 @@ function hashLinuxOpenFile(runtime, fd, bytes) {
|
|
|
3170
3253
|
}
|
|
3171
3254
|
|
|
3172
3255
|
function linuxEntrySnapshotContract(targetRuntime) {
|
|
3173
|
-
if (targetRuntime
|
|
3256
|
+
if (targetRuntime?.startsWith("native-")) {
|
|
3174
3257
|
return {
|
|
3175
3258
|
scope: LINUX_NATIVE_ENTRY_SNAPSHOT_SCOPE,
|
|
3176
3259
|
targetMode: LINUX_NATIVE_ENTRY_SNAPSHOT_TARGET_MODE,
|
|
@@ -3663,18 +3746,169 @@ function attestLinuxNodePluginTreeSnapshot(
|
|
|
3663
3746
|
}
|
|
3664
3747
|
}
|
|
3665
3748
|
|
|
3749
|
+
function validLinuxRuntimePageSize(value) {
|
|
3750
|
+
if (
|
|
3751
|
+
!Number.isSafeInteger(value) ||
|
|
3752
|
+
value < LINUX_MIN_RUNTIME_PAGE_BYTES ||
|
|
3753
|
+
value > LINUX_MAX_RUNTIME_PAGE_BYTES
|
|
3754
|
+
) {
|
|
3755
|
+
return false;
|
|
3756
|
+
}
|
|
3757
|
+
const size = BigInt(value);
|
|
3758
|
+
return (size & (size - 1n)) === 0n;
|
|
3759
|
+
}
|
|
3760
|
+
|
|
3761
|
+
function readLinuxPageSizeFromAuxv(runtimeFs) {
|
|
3762
|
+
// AT_PAGESZ is emitted by the kernel for this exact process and matches the
|
|
3763
|
+
// page granularity used by the ELF loader. Avoid filesystem block sizes or
|
|
3764
|
+
// an external getconf binary, neither of which is the loader contract.
|
|
3765
|
+
const raw = runtimeFs.readFileSync("/proc/self/auxv");
|
|
3766
|
+
const auxv = Buffer.isBuffer(raw) ? raw : Buffer.from(raw);
|
|
3767
|
+
if (
|
|
3768
|
+
auxv.length < LINUX_AUXV_ENTRY_BYTES ||
|
|
3769
|
+
auxv.length > LINUX_AUXV_MAX_BYTES ||
|
|
3770
|
+
auxv.length % LINUX_AUXV_ENTRY_BYTES !== 0
|
|
3771
|
+
) {
|
|
3772
|
+
throw new Error("linux_runtime_auxv_invalid");
|
|
3773
|
+
}
|
|
3774
|
+
let pageSize = null;
|
|
3775
|
+
let terminated = false;
|
|
3776
|
+
for (let offset = 0; offset < auxv.length; offset += LINUX_AUXV_ENTRY_BYTES) {
|
|
3777
|
+
const tag = auxv.readBigUInt64LE(offset);
|
|
3778
|
+
const value = auxv.readBigUInt64LE(offset + 8);
|
|
3779
|
+
if (tag === 0n) {
|
|
3780
|
+
terminated = true;
|
|
3781
|
+
break;
|
|
3782
|
+
}
|
|
3783
|
+
if (tag !== LINUX_AUXV_PAGE_SIZE) continue;
|
|
3784
|
+
if (pageSize !== null || value > BigInt(Number.MAX_SAFE_INTEGER)) {
|
|
3785
|
+
throw new Error("linux_runtime_page_size_ambiguous");
|
|
3786
|
+
}
|
|
3787
|
+
pageSize = Number(value);
|
|
3788
|
+
}
|
|
3789
|
+
if (!terminated || !validLinuxRuntimePageSize(pageSize)) {
|
|
3790
|
+
throw new Error("linux_runtime_page_size_unattested");
|
|
3791
|
+
}
|
|
3792
|
+
return pageSize;
|
|
3793
|
+
}
|
|
3794
|
+
|
|
3795
|
+
function linuxElfRuntimePageSize(runtime) {
|
|
3796
|
+
const pageSize =
|
|
3797
|
+
typeof runtime.linuxPageSize === "function"
|
|
3798
|
+
? runtime.linuxPageSize()
|
|
3799
|
+
: readLinuxPageSizeFromAuxv(runtime.fs);
|
|
3800
|
+
if (!validLinuxRuntimePageSize(pageSize)) {
|
|
3801
|
+
throw new Error("linux_runtime_page_size_unattested");
|
|
3802
|
+
}
|
|
3803
|
+
return BigInt(pageSize);
|
|
3804
|
+
}
|
|
3805
|
+
|
|
3806
|
+
function linuxElfAlignDown(value, alignment) {
|
|
3807
|
+
return value - (value % alignment);
|
|
3808
|
+
}
|
|
3809
|
+
|
|
3810
|
+
function linuxElfAlignUp(value, alignment) {
|
|
3811
|
+
const remainder = value % alignment;
|
|
3812
|
+
return remainder === 0n ? value : value + alignment - remainder;
|
|
3813
|
+
}
|
|
3814
|
+
|
|
3815
|
+
function attestLinuxElfLoadMappings(loadSegments, pageSize) {
|
|
3816
|
+
// Linux maps later PT_LOAD entries with MAP_FIXED. Even disjoint byte ranges
|
|
3817
|
+
// can therefore replace one another after the loader rounds them to pages.
|
|
3818
|
+
// A conservative no-overlap contract keeps our file-offset parser and the
|
|
3819
|
+
// in-memory dynamic-loader view identical.
|
|
3820
|
+
const ranges = [];
|
|
3821
|
+
for (const load of loadSegments) {
|
|
3822
|
+
if (
|
|
3823
|
+
load.fileOffset % pageSize !== load.virtualAddress % pageSize ||
|
|
3824
|
+
(load.alignment > 1n &&
|
|
3825
|
+
((load.alignment & (load.alignment - 1n)) !== 0n ||
|
|
3826
|
+
load.fileOffset % load.alignment !==
|
|
3827
|
+
load.virtualAddress % load.alignment))
|
|
3828
|
+
) {
|
|
3829
|
+
throw new Error("native_entry_load_segment_alignment_invalid");
|
|
3830
|
+
}
|
|
3831
|
+
if (
|
|
3832
|
+
load.virtualAddress > LINUX_ELF_MAX_UINT64 - load.memorySize ||
|
|
3833
|
+
load.virtualAddress + load.memorySize >
|
|
3834
|
+
LINUX_ELF_MAX_UINT64 - (pageSize - 1n)
|
|
3835
|
+
) {
|
|
3836
|
+
throw new Error("native_entry_load_segment_virtual_range_overflow");
|
|
3837
|
+
}
|
|
3838
|
+
if (load.memorySize === 0n) continue;
|
|
3839
|
+
ranges.push({
|
|
3840
|
+
start: linuxElfAlignDown(load.virtualAddress, pageSize),
|
|
3841
|
+
end: linuxElfAlignUp(load.virtualAddress + load.memorySize, pageSize),
|
|
3842
|
+
});
|
|
3843
|
+
}
|
|
3844
|
+
ranges.sort((left, right) =>
|
|
3845
|
+
left.start < right.start ? -1 : left.start > right.start ? 1 : 0,
|
|
3846
|
+
);
|
|
3847
|
+
for (let index = 1; index < ranges.length; index += 1) {
|
|
3848
|
+
if (ranges[index].start < ranges[index - 1].end) {
|
|
3849
|
+
throw new Error("native_entry_load_segment_page_overlap");
|
|
3850
|
+
}
|
|
3851
|
+
}
|
|
3852
|
+
}
|
|
3853
|
+
|
|
3854
|
+
function linuxElfVirtualRangeFileMappings(loadSegments, address, bytes) {
|
|
3855
|
+
return loadSegments
|
|
3856
|
+
.filter((load) => {
|
|
3857
|
+
if (address < load.virtualAddress) return false;
|
|
3858
|
+
const delta = address - load.virtualAddress;
|
|
3859
|
+
return (
|
|
3860
|
+
delta <= load.fileSize &&
|
|
3861
|
+
bytes <= load.fileSize - delta &&
|
|
3862
|
+
delta <= load.memorySize &&
|
|
3863
|
+
bytes <= load.memorySize - delta
|
|
3864
|
+
);
|
|
3865
|
+
})
|
|
3866
|
+
.map((load) => ({
|
|
3867
|
+
load,
|
|
3868
|
+
fileOffset: load.fileOffset + (address - load.virtualAddress),
|
|
3869
|
+
}));
|
|
3870
|
+
}
|
|
3871
|
+
|
|
3872
|
+
function readLinuxElfString(table, offset, label) {
|
|
3873
|
+
if (!Number.isSafeInteger(offset) || offset < 0 || offset >= table.length) {
|
|
3874
|
+
throw new Error(`native_entry_${label}_string_out_of_bounds`);
|
|
3875
|
+
}
|
|
3876
|
+
const end = table.indexOf(0, offset);
|
|
3877
|
+
if (end < 0) {
|
|
3878
|
+
throw new Error(`native_entry_${label}_string_unterminated`);
|
|
3879
|
+
}
|
|
3880
|
+
const bytes = table.subarray(offset, end);
|
|
3881
|
+
if (bytes.length < 1 || bytes.some((value) => value < 0x21 || value > 0x7e)) {
|
|
3882
|
+
throw new Error(`native_entry_${label}_string_invalid`);
|
|
3883
|
+
}
|
|
3884
|
+
return bytes.toString("ascii");
|
|
3885
|
+
}
|
|
3886
|
+
|
|
3887
|
+
function linuxSystemDynamicPath(value) {
|
|
3888
|
+
return (
|
|
3889
|
+
typeof value === "string" &&
|
|
3890
|
+
path.posix.isAbsolute(value) &&
|
|
3891
|
+
path.posix.normalize(value) === value &&
|
|
3892
|
+
!value.includes("\0") &&
|
|
3893
|
+
["/lib/", "/lib64/", "/usr/lib/", "/usr/lib64/"].some((prefix) =>
|
|
3894
|
+
value.startsWith(prefix),
|
|
3895
|
+
)
|
|
3896
|
+
);
|
|
3897
|
+
}
|
|
3898
|
+
|
|
3666
3899
|
/**
|
|
3667
|
-
* Classify one already-pinned plugin entry without invoking it or
|
|
3668
|
-
* inspection utility.
|
|
3669
|
-
*
|
|
3670
|
-
*
|
|
3671
|
-
*
|
|
3900
|
+
* Classify one already-pinned plugin entry without invoking it or passing it
|
|
3901
|
+
* to a host inspection utility. Besides conventional fully static ET_EXEC and
|
|
3902
|
+
* static-PIE-shaped ET_DYN images, the parser can describe a narrow dynamic
|
|
3903
|
+
* executable. The caller must separately prove that its PT_INTERP and every
|
|
3904
|
+
* direct DT_NEEDED member are present in a pinned, attested system-file set.
|
|
3672
3905
|
*/
|
|
3673
|
-
function
|
|
3906
|
+
function inspectLinuxNativeElf(runtime, fd, identity) {
|
|
3674
3907
|
const expectedMachine = LINUX_ELF_MACHINES[runtime.arch];
|
|
3675
3908
|
if (!expectedMachine) {
|
|
3676
3909
|
throw new Error(`unsupported_elf_architecture:${String(runtime.arch)}`);
|
|
3677
3910
|
}
|
|
3911
|
+
const runtimePageSize = linuxElfRuntimePageSize(runtime);
|
|
3678
3912
|
const before = runtime.fs.fstatSync(fd);
|
|
3679
3913
|
if (
|
|
3680
3914
|
!before.isFile() ||
|
|
@@ -3741,6 +3975,7 @@ function inspectLinuxStaticNativeElf(runtime, fd, identity) {
|
|
|
3741
3975
|
let nonExecutableStack = false;
|
|
3742
3976
|
const loadSegments = [];
|
|
3743
3977
|
const dynamicSegments = [];
|
|
3978
|
+
const interpreterSegments = [];
|
|
3744
3979
|
for (let index = 0; index < programHeaderCount; index += 1) {
|
|
3745
3980
|
const offset =
|
|
3746
3981
|
Number(programHeaderOffset) + index * LINUX_ELF64_PROGRAM_HEADER_BYTES;
|
|
@@ -3756,6 +3991,7 @@ function inspectLinuxStaticNativeElf(runtime, fd, identity) {
|
|
|
3756
3991
|
const virtualAddress = program.readBigUInt64LE(16);
|
|
3757
3992
|
const fileSize = program.readBigUInt64LE(32);
|
|
3758
3993
|
const memorySize = program.readBigUInt64LE(40);
|
|
3994
|
+
const alignment = program.readBigUInt64LE(48);
|
|
3759
3995
|
if (fileOffset > fileBytes || fileSize > fileBytes - fileOffset) {
|
|
3760
3996
|
throw new Error("native_entry_segment_out_of_bounds");
|
|
3761
3997
|
}
|
|
@@ -3763,18 +3999,21 @@ function inspectLinuxStaticNativeElf(runtime, fd, identity) {
|
|
|
3763
3999
|
throw new Error("native_entry_segment_out_of_bounds");
|
|
3764
4000
|
}
|
|
3765
4001
|
if (type === LINUX_ELF_PROGRAM_INTERP) {
|
|
3766
|
-
|
|
4002
|
+
interpreterSegments.push({
|
|
4003
|
+
flags,
|
|
4004
|
+
fileOffset,
|
|
4005
|
+
fileSize,
|
|
4006
|
+
memorySize,
|
|
4007
|
+
});
|
|
3767
4008
|
}
|
|
3768
4009
|
if (type === LINUX_ELF_PROGRAM_DYNAMIC) {
|
|
3769
|
-
if (elfType === LINUX_ELF_TYPE_EXEC) {
|
|
3770
|
-
throw new Error("native_entry_dynamic_elf_unsupported");
|
|
3771
|
-
}
|
|
3772
4010
|
dynamicSegments.push({
|
|
3773
4011
|
flags,
|
|
3774
4012
|
fileOffset,
|
|
3775
4013
|
virtualAddress,
|
|
3776
4014
|
fileSize,
|
|
3777
4015
|
memorySize,
|
|
4016
|
+
alignment,
|
|
3778
4017
|
});
|
|
3779
4018
|
}
|
|
3780
4019
|
if (type === LINUX_ELF_PROGRAM_GNU_STACK) {
|
|
@@ -3790,6 +4029,7 @@ function inspectLinuxStaticNativeElf(runtime, fd, identity) {
|
|
|
3790
4029
|
virtualAddress,
|
|
3791
4030
|
fileSize,
|
|
3792
4031
|
memorySize,
|
|
4032
|
+
alignment,
|
|
3793
4033
|
});
|
|
3794
4034
|
}
|
|
3795
4035
|
if (type === LINUX_ELF_PROGRAM_LOAD && (flags & 0x1) !== 0) {
|
|
@@ -3805,6 +4045,7 @@ function inspectLinuxStaticNativeElf(runtime, fd, identity) {
|
|
|
3805
4045
|
}
|
|
3806
4046
|
}
|
|
3807
4047
|
}
|
|
4048
|
+
attestLinuxElfLoadMappings(loadSegments, runtimePageSize);
|
|
3808
4049
|
if (!executableLoad || !entryInExecutableLoad) {
|
|
3809
4050
|
throw new Error("native_entry_has_no_executable_entry_segment");
|
|
3810
4051
|
}
|
|
@@ -3812,23 +4053,65 @@ function inspectLinuxStaticNativeElf(runtime, fd, identity) {
|
|
|
3812
4053
|
throw new Error("native_entry_nonexecutable_stack_unattested");
|
|
3813
4054
|
}
|
|
3814
4055
|
|
|
3815
|
-
if (
|
|
4056
|
+
if (interpreterSegments.length > 1) {
|
|
4057
|
+
throw new Error("native_entry_interpreter_ambiguous");
|
|
4058
|
+
}
|
|
4059
|
+
let interpreter = null;
|
|
4060
|
+
if (interpreterSegments.length === 1) {
|
|
4061
|
+
const segment = interpreterSegments[0];
|
|
4062
|
+
if (
|
|
4063
|
+
(segment.flags & 0x3) !== 0 ||
|
|
4064
|
+
segment.fileSize < 2n ||
|
|
4065
|
+
segment.fileSize > BigInt(LINUX_ELF_MAX_INTERPRETER_BYTES) ||
|
|
4066
|
+
segment.fileSize > segment.memorySize
|
|
4067
|
+
) {
|
|
4068
|
+
throw new Error("native_entry_interpreter_invalid");
|
|
4069
|
+
}
|
|
4070
|
+
const contents = readLinuxFdExactly(
|
|
4071
|
+
runtime,
|
|
4072
|
+
fd,
|
|
4073
|
+
Number(segment.fileSize),
|
|
4074
|
+
Number(segment.fileOffset),
|
|
4075
|
+
);
|
|
4076
|
+
if (
|
|
4077
|
+
contents[contents.length - 1] !== 0 ||
|
|
4078
|
+
contents.indexOf(0) !== contents.length - 1
|
|
4079
|
+
) {
|
|
4080
|
+
throw new Error("native_entry_interpreter_unterminated");
|
|
4081
|
+
}
|
|
4082
|
+
interpreter = readLinuxElfString(contents, 0, "interpreter");
|
|
4083
|
+
if (!linuxSystemDynamicPath(interpreter)) {
|
|
4084
|
+
throw new Error("native_entry_interpreter_outside_system_roots");
|
|
4085
|
+
}
|
|
4086
|
+
}
|
|
4087
|
+
|
|
4088
|
+
const staticPie = elfType === LINUX_ELF_TYPE_DYN && interpreter === null;
|
|
4089
|
+
const dynamicExecutable = interpreter !== null;
|
|
4090
|
+
let dynamicMetadata = null;
|
|
4091
|
+
if (elfType === LINUX_ELF_TYPE_EXEC && !dynamicExecutable) {
|
|
4092
|
+
if (dynamicSegments.length > 0) {
|
|
4093
|
+
throw new Error("native_entry_dynamic_elf_unsupported");
|
|
4094
|
+
}
|
|
4095
|
+
} else {
|
|
4096
|
+
const prefix = staticPie
|
|
4097
|
+
? "native_entry_static_pie"
|
|
4098
|
+
: "native_entry_dynamic";
|
|
3816
4099
|
if (dynamicSegments.length === 0) {
|
|
3817
|
-
throw new Error(
|
|
4100
|
+
throw new Error(`${prefix}_dynamic_segment_missing`);
|
|
3818
4101
|
}
|
|
3819
4102
|
if (dynamicSegments.length !== 1) {
|
|
3820
|
-
throw new Error(
|
|
4103
|
+
throw new Error(`${prefix}_dynamic_segment_ambiguous`);
|
|
3821
4104
|
}
|
|
3822
4105
|
const dynamic = dynamicSegments[0];
|
|
3823
4106
|
if ((dynamic.flags & 0x1) !== 0) {
|
|
3824
|
-
throw new Error(
|
|
4107
|
+
throw new Error(`${prefix}_dynamic_segment_executable`);
|
|
3825
4108
|
}
|
|
3826
4109
|
if (
|
|
3827
4110
|
dynamic.fileSize < BigInt(LINUX_ELF64_DYNAMIC_ENTRY_BYTES) ||
|
|
3828
4111
|
dynamic.fileSize % BigInt(LINUX_ELF64_DYNAMIC_ENTRY_BYTES) !== 0n ||
|
|
3829
4112
|
dynamic.fileSize > dynamic.memorySize
|
|
3830
4113
|
) {
|
|
3831
|
-
throw new Error(
|
|
4114
|
+
throw new Error(`${prefix}_dynamic_segment_invalid`);
|
|
3832
4115
|
}
|
|
3833
4116
|
const dynamicEntries =
|
|
3834
4117
|
dynamic.fileSize / BigInt(LINUX_ELF64_DYNAMIC_ENTRY_BYTES);
|
|
@@ -3836,9 +4119,9 @@ function inspectLinuxStaticNativeElf(runtime, fd, identity) {
|
|
|
3836
4119
|
dynamicEntries < 1n ||
|
|
3837
4120
|
dynamicEntries > BigInt(LINUX_ELF_MAX_DYNAMIC_ENTRIES)
|
|
3838
4121
|
) {
|
|
3839
|
-
throw new Error(
|
|
4122
|
+
throw new Error(`${prefix}_dynamic_table_too_large`);
|
|
3840
4123
|
}
|
|
3841
|
-
const
|
|
4124
|
+
const containingLoads = loadSegments.filter((load) => {
|
|
3842
4125
|
if (
|
|
3843
4126
|
dynamic.fileOffset < load.fileOffset ||
|
|
3844
4127
|
dynamic.virtualAddress < load.virtualAddress
|
|
@@ -3855,8 +4138,22 @@ function inspectLinuxStaticNativeElf(runtime, fd, identity) {
|
|
|
3855
4138
|
dynamic.memorySize <= load.memorySize - memoryDelta
|
|
3856
4139
|
);
|
|
3857
4140
|
});
|
|
3858
|
-
if (
|
|
3859
|
-
throw new Error(
|
|
4141
|
+
if (containingLoads.length === 0) {
|
|
4142
|
+
throw new Error(`${prefix}_dynamic_segment_unmapped`);
|
|
4143
|
+
}
|
|
4144
|
+
if (containingLoads.length !== 1) {
|
|
4145
|
+
throw new Error(`${prefix}_dynamic_segment_mapping_ambiguous`);
|
|
4146
|
+
}
|
|
4147
|
+
const dynamicLoaderMappings = linuxElfVirtualRangeFileMappings(
|
|
4148
|
+
loadSegments,
|
|
4149
|
+
dynamic.virtualAddress,
|
|
4150
|
+
dynamic.fileSize,
|
|
4151
|
+
);
|
|
4152
|
+
if (
|
|
4153
|
+
dynamicLoaderMappings.length !== 1 ||
|
|
4154
|
+
dynamicLoaderMappings[0].fileOffset !== dynamic.fileOffset
|
|
4155
|
+
) {
|
|
4156
|
+
throw new Error(`${prefix}_dynamic_segment_loader_view_mismatch`);
|
|
3860
4157
|
}
|
|
3861
4158
|
|
|
3862
4159
|
const dynamicTable = readLinuxFdExactly(
|
|
@@ -3865,8 +4162,21 @@ function inspectLinuxStaticNativeElf(runtime, fd, identity) {
|
|
|
3865
4162
|
Number(dynamic.fileSize),
|
|
3866
4163
|
Number(dynamic.fileOffset),
|
|
3867
4164
|
);
|
|
4165
|
+
const neededOffsets = [];
|
|
4166
|
+
const forbiddenDependencyTags = new Set([
|
|
4167
|
+
LINUX_ELF_DYNAMIC_RPATH,
|
|
4168
|
+
LINUX_ELF_DYNAMIC_RUNPATH,
|
|
4169
|
+
LINUX_ELF_DYNAMIC_CONFIG,
|
|
4170
|
+
LINUX_ELF_DYNAMIC_DEPAUDIT,
|
|
4171
|
+
LINUX_ELF_DYNAMIC_AUDIT,
|
|
4172
|
+
LINUX_ELF_DYNAMIC_AUXILIARY,
|
|
4173
|
+
LINUX_ELF_DYNAMIC_FILTER,
|
|
4174
|
+
]);
|
|
3868
4175
|
let terminated = false;
|
|
4176
|
+
let flags = null;
|
|
3869
4177
|
let flags1 = null;
|
|
4178
|
+
let stringTableAddress = null;
|
|
4179
|
+
let stringTableBytes = null;
|
|
3870
4180
|
for (
|
|
3871
4181
|
let offset = 0;
|
|
3872
4182
|
offset < dynamicTable.length;
|
|
@@ -3878,21 +4188,113 @@ function inspectLinuxStaticNativeElf(runtime, fd, identity) {
|
|
|
3878
4188
|
terminated = true;
|
|
3879
4189
|
break;
|
|
3880
4190
|
}
|
|
3881
|
-
if (
|
|
3882
|
-
|
|
4191
|
+
if (
|
|
4192
|
+
tag === LINUX_ELF_DYNAMIC_TEXTREL ||
|
|
4193
|
+
forbiddenDependencyTags.has(tag)
|
|
4194
|
+
) {
|
|
4195
|
+
throw new Error(`${prefix}_loader_directive_unsupported`);
|
|
3883
4196
|
}
|
|
3884
|
-
if (tag ===
|
|
4197
|
+
if (tag === LINUX_ELF_DYNAMIC_NEEDED) {
|
|
4198
|
+
neededOffsets.push(value);
|
|
4199
|
+
if (neededOffsets.length > LINUX_ELF_MAX_NEEDED_ENTRIES) {
|
|
4200
|
+
throw new Error(`${prefix}_dependency_count_exceeded`);
|
|
4201
|
+
}
|
|
4202
|
+
} else if (tag === LINUX_ELF_DYNAMIC_STRTAB) {
|
|
4203
|
+
if (stringTableAddress !== null) {
|
|
4204
|
+
throw new Error(`${prefix}_string_table_ambiguous`);
|
|
4205
|
+
}
|
|
4206
|
+
stringTableAddress = value;
|
|
4207
|
+
} else if (tag === LINUX_ELF_DYNAMIC_STRSZ) {
|
|
4208
|
+
if (stringTableBytes !== null) {
|
|
4209
|
+
throw new Error(`${prefix}_string_table_ambiguous`);
|
|
4210
|
+
}
|
|
4211
|
+
stringTableBytes = value;
|
|
4212
|
+
} else if (tag === LINUX_ELF_DYNAMIC_FLAGS) {
|
|
4213
|
+
if (flags !== null) {
|
|
4214
|
+
throw new Error(`${prefix}_flags_ambiguous`);
|
|
4215
|
+
}
|
|
4216
|
+
flags = value;
|
|
4217
|
+
} else if (tag === LINUX_ELF_DYNAMIC_FLAGS_1) {
|
|
3885
4218
|
if (flags1 !== null) {
|
|
3886
|
-
throw new Error(
|
|
4219
|
+
throw new Error(`${prefix}_flags_ambiguous`);
|
|
3887
4220
|
}
|
|
3888
4221
|
flags1 = value;
|
|
3889
4222
|
}
|
|
3890
4223
|
}
|
|
3891
4224
|
if (!terminated) {
|
|
3892
|
-
throw new Error(
|
|
4225
|
+
throw new Error(`${prefix}_dynamic_table_unterminated`);
|
|
4226
|
+
}
|
|
4227
|
+
if (flags !== null && (flags & LINUX_ELF_DYNAMIC_FLAG_TEXTREL) !== 0n) {
|
|
4228
|
+
throw new Error(`${prefix}_text_relocation_unsupported`);
|
|
4229
|
+
}
|
|
4230
|
+
if (
|
|
4231
|
+
elfType === LINUX_ELF_TYPE_DYN &&
|
|
4232
|
+
(flags1 === null || (flags1 & LINUX_ELF_DYNAMIC_FLAG_PIE) === 0n)
|
|
4233
|
+
) {
|
|
4234
|
+
throw new Error(`${prefix}_flag_missing`);
|
|
3893
4235
|
}
|
|
3894
|
-
if (
|
|
3895
|
-
throw new Error("
|
|
4236
|
+
if (staticPie && neededOffsets.length > 0) {
|
|
4237
|
+
throw new Error("native_entry_static_pie_dependency_unsupported");
|
|
4238
|
+
}
|
|
4239
|
+
|
|
4240
|
+
let needed = [];
|
|
4241
|
+
if (neededOffsets.length > 0) {
|
|
4242
|
+
if (
|
|
4243
|
+
stringTableAddress === null ||
|
|
4244
|
+
stringTableBytes === null ||
|
|
4245
|
+
stringTableBytes < 1n ||
|
|
4246
|
+
stringTableBytes > BigInt(LINUX_ELF_MAX_STRING_TABLE_BYTES)
|
|
4247
|
+
) {
|
|
4248
|
+
throw new Error(`${prefix}_string_table_invalid`);
|
|
4249
|
+
}
|
|
4250
|
+
const stringTableMappings = linuxElfVirtualRangeFileMappings(
|
|
4251
|
+
loadSegments,
|
|
4252
|
+
stringTableAddress,
|
|
4253
|
+
stringTableBytes,
|
|
4254
|
+
);
|
|
4255
|
+
if (stringTableMappings.length === 0) {
|
|
4256
|
+
throw new Error(`${prefix}_string_table_unmapped`);
|
|
4257
|
+
}
|
|
4258
|
+
if (stringTableMappings.length !== 1) {
|
|
4259
|
+
throw new Error(`${prefix}_string_table_mapping_ambiguous`);
|
|
4260
|
+
}
|
|
4261
|
+
const stringTableOffset = stringTableMappings[0].fileOffset;
|
|
4262
|
+
if (stringTableOffset > BigInt(Number.MAX_SAFE_INTEGER)) {
|
|
4263
|
+
throw new Error(`${prefix}_string_table_unmapped`);
|
|
4264
|
+
}
|
|
4265
|
+
const stringTable = readLinuxFdExactly(
|
|
4266
|
+
runtime,
|
|
4267
|
+
fd,
|
|
4268
|
+
Number(stringTableBytes),
|
|
4269
|
+
Number(stringTableOffset),
|
|
4270
|
+
);
|
|
4271
|
+
needed = neededOffsets.map((offset) => {
|
|
4272
|
+
if (offset > BigInt(Number.MAX_SAFE_INTEGER)) {
|
|
4273
|
+
throw new Error(`${prefix}_dependency_string_out_of_bounds`);
|
|
4274
|
+
}
|
|
4275
|
+
const name = readLinuxElfString(
|
|
4276
|
+
stringTable,
|
|
4277
|
+
Number(offset),
|
|
4278
|
+
"dynamic_dependency",
|
|
4279
|
+
);
|
|
4280
|
+
if (
|
|
4281
|
+
!/^[A-Za-z0-9][A-Za-z0-9._+-]{0,254}$/.test(name) ||
|
|
4282
|
+
path.posix.basename(name) !== name
|
|
4283
|
+
) {
|
|
4284
|
+
throw new Error("native_entry_dynamic_dependency_name_invalid");
|
|
4285
|
+
}
|
|
4286
|
+
return name;
|
|
4287
|
+
});
|
|
4288
|
+
if (new Set(needed).size !== needed.length) {
|
|
4289
|
+
throw new Error("native_entry_dynamic_dependency_ambiguous");
|
|
4290
|
+
}
|
|
4291
|
+
}
|
|
4292
|
+
|
|
4293
|
+
if (dynamicExecutable) {
|
|
4294
|
+
dynamicMetadata = Object.freeze({
|
|
4295
|
+
interpreter,
|
|
4296
|
+
needed: Object.freeze(needed),
|
|
4297
|
+
});
|
|
3896
4298
|
}
|
|
3897
4299
|
}
|
|
3898
4300
|
|
|
@@ -3902,17 +4304,23 @@ function inspectLinuxStaticNativeElf(runtime, fd, identity) {
|
|
|
3902
4304
|
throw new Error("native_entry_changed_during_elf_attestation");
|
|
3903
4305
|
}
|
|
3904
4306
|
return Object.freeze({
|
|
3905
|
-
|
|
3906
|
-
|
|
4307
|
+
runtime: dynamicExecutable ? "native-dynamic-elf" : "native-static-elf",
|
|
4308
|
+
format: dynamicExecutable
|
|
4309
|
+
? elfType === LINUX_ELF_TYPE_DYN
|
|
4310
|
+
? "elf64-dynamic-pie-et-dyn"
|
|
4311
|
+
: "elf64-dynamic-et-exec"
|
|
4312
|
+
: elfType === LINUX_ELF_TYPE_DYN
|
|
3907
4313
|
? "elf64-static-pie-shaped-et-dyn"
|
|
3908
4314
|
: "elf64-static-et-exec",
|
|
3909
4315
|
architecture: runtime.arch,
|
|
3910
4316
|
machine: expectedMachine,
|
|
4317
|
+
loaderPageBytes: Number(runtimePageSize),
|
|
3911
4318
|
programHeaders: programHeaderCount,
|
|
4319
|
+
...(dynamicMetadata || {}),
|
|
3912
4320
|
});
|
|
3913
4321
|
}
|
|
3914
4322
|
|
|
3915
|
-
function
|
|
4323
|
+
function inspectLinuxNativePath(runtime, identity) {
|
|
3916
4324
|
let fd;
|
|
3917
4325
|
try {
|
|
3918
4326
|
const constants = runtime.fs.constants || fs.constants;
|
|
@@ -3921,7 +4329,7 @@ function inspectLinuxStaticNativePath(runtime, identity) {
|
|
|
3921
4329
|
Number(constants.O_NOFOLLOW || 0) |
|
|
3922
4330
|
Number(constants.O_NONBLOCK || 0);
|
|
3923
4331
|
fd = runtime.fs.openSync(identity.realPath, flags);
|
|
3924
|
-
return
|
|
4332
|
+
return inspectLinuxNativeElf(runtime, fd, identity);
|
|
3925
4333
|
} finally {
|
|
3926
4334
|
if (fd !== undefined) {
|
|
3927
4335
|
try {
|
|
@@ -4146,7 +4554,8 @@ function buildLinuxNetworkSeccompFilter(arch) {
|
|
|
4146
4554
|
instructions.push([0x54, 0, 0, ~architecture.x32SyscallBit]);
|
|
4147
4555
|
}
|
|
4148
4556
|
instructions.push(
|
|
4149
|
-
// No socket family is needed by this direct
|
|
4557
|
+
// No socket family is needed by this direct one-shot Plugin bin route,
|
|
4558
|
+
// whether the Broker call is synchronous or asynchronously supervised.
|
|
4150
4559
|
// Blocking creation rather than relying only on CLONE_NEWNET also closes
|
|
4151
4560
|
// non-network-namespaced transports such as AF_VSOCK.
|
|
4152
4561
|
[0x15, 0, 1, architecture.socketSyscall],
|
|
@@ -4656,6 +5065,87 @@ function pinLinuxRuntimeMounts(runtime, runtimeMounts, runtimeIdentity) {
|
|
|
4656
5065
|
}
|
|
4657
5066
|
}
|
|
4658
5067
|
|
|
5068
|
+
// Bind only the kernel-selected interpreter and the entry ELF's direct
|
|
5069
|
+
// DT_NEEDED names. This deliberately does not claim transitive or dlopen-time
|
|
5070
|
+
// closure; handleAtomic remains false for the wider launch chain.
|
|
5071
|
+
function bindLinuxNativeDynamicRuntime(entryFormat, pinnedRuntimeMounts) {
|
|
5072
|
+
if (entryFormat?.runtime !== "native-dynamic-elf") return null;
|
|
5073
|
+
if (
|
|
5074
|
+
!linuxSystemDynamicPath(entryFormat.interpreter) ||
|
|
5075
|
+
!Array.isArray(entryFormat.needed) ||
|
|
5076
|
+
entryFormat.needed.length > LINUX_ELF_MAX_NEEDED_ENTRIES
|
|
5077
|
+
) {
|
|
5078
|
+
throw new Error("native_dynamic_metadata_invalid");
|
|
5079
|
+
}
|
|
5080
|
+
const systemMounts = (pinnedRuntimeMounts || []).filter(
|
|
5081
|
+
(mount) =>
|
|
5082
|
+
linuxSystemDynamicPath(mount?.destination) &&
|
|
5083
|
+
Number.isInteger(mount?.fd) &&
|
|
5084
|
+
typeof mount?.fileId?.dev === "string" &&
|
|
5085
|
+
typeof mount?.fileId?.ino === "string" &&
|
|
5086
|
+
Number.isSafeInteger(mount?.bytes) &&
|
|
5087
|
+
mount.bytes > 0 &&
|
|
5088
|
+
Number.isFinite(mount?.mtimeMs),
|
|
5089
|
+
);
|
|
5090
|
+
const interpreterMount = systemMounts.find(
|
|
5091
|
+
(mount) => mount.destination === entryFormat.interpreter,
|
|
5092
|
+
);
|
|
5093
|
+
if (!interpreterMount) {
|
|
5094
|
+
throw new Error("native_dynamic_interpreter_outside_direct_system_set");
|
|
5095
|
+
}
|
|
5096
|
+
const selected = new Map([[interpreterMount.destination, interpreterMount]]);
|
|
5097
|
+
for (const dependency of entryFormat.needed) {
|
|
5098
|
+
if (
|
|
5099
|
+
typeof dependency !== "string" ||
|
|
5100
|
+
!/^[A-Za-z0-9][A-Za-z0-9._+-]{0,254}$/.test(dependency)
|
|
5101
|
+
) {
|
|
5102
|
+
throw new Error("native_dynamic_dependency_name_invalid");
|
|
5103
|
+
}
|
|
5104
|
+
const matches = systemMounts.filter(
|
|
5105
|
+
(mount) => path.posix.basename(mount.destination) === dependency,
|
|
5106
|
+
);
|
|
5107
|
+
if (matches.length === 0) {
|
|
5108
|
+
throw new Error("native_dynamic_dependency_outside_direct_system_set");
|
|
5109
|
+
}
|
|
5110
|
+
if (matches.length !== 1) {
|
|
5111
|
+
throw new Error("native_dynamic_dependency_runtime_ambiguous");
|
|
5112
|
+
}
|
|
5113
|
+
selected.set(matches[0].destination, matches[0]);
|
|
5114
|
+
}
|
|
5115
|
+
const members = [...selected.values()]
|
|
5116
|
+
.map((mount) => ({
|
|
5117
|
+
destination: mount.destination,
|
|
5118
|
+
fileId: {
|
|
5119
|
+
dev: mount.fileId.dev,
|
|
5120
|
+
ino: mount.fileId.ino,
|
|
5121
|
+
},
|
|
5122
|
+
bytes: mount.bytes,
|
|
5123
|
+
mtimeMs: mount.mtimeMs,
|
|
5124
|
+
}))
|
|
5125
|
+
.sort((left, right) => left.destination.localeCompare(right.destination));
|
|
5126
|
+
const digest = crypto
|
|
5127
|
+
.createHash("sha256")
|
|
5128
|
+
.update(
|
|
5129
|
+
JSON.stringify({
|
|
5130
|
+
version: 1,
|
|
5131
|
+
scope: LINUX_NATIVE_DYNAMIC_DIRECT_SYSTEM_SET_SCOPE,
|
|
5132
|
+
mechanism: LINUX_NATIVE_DYNAMIC_DIRECT_SYSTEM_SET_MECHANISM,
|
|
5133
|
+
interpreter: entryFormat.interpreter,
|
|
5134
|
+
needed: [...entryFormat.needed].sort(),
|
|
5135
|
+
members,
|
|
5136
|
+
}),
|
|
5137
|
+
)
|
|
5138
|
+
.digest("hex");
|
|
5139
|
+
return Object.freeze({
|
|
5140
|
+
scope: LINUX_NATIVE_DYNAMIC_DIRECT_SYSTEM_SET_SCOPE,
|
|
5141
|
+
mechanism: LINUX_NATIVE_DYNAMIC_DIRECT_SYSTEM_SET_MECHANISM,
|
|
5142
|
+
interpreter: entryFormat.interpreter,
|
|
5143
|
+
dependencies: entryFormat.needed.length,
|
|
5144
|
+
files: members.length,
|
|
5145
|
+
digest,
|
|
5146
|
+
});
|
|
5147
|
+
}
|
|
5148
|
+
|
|
4659
5149
|
function linuxSandboxEnvironment() {
|
|
4660
5150
|
return {
|
|
4661
5151
|
HOME: "/home/sandbox",
|
|
@@ -4932,11 +5422,22 @@ export function applyLinuxSandbox(
|
|
|
4932
5422
|
);
|
|
4933
5423
|
|
|
4934
5424
|
if (requiresStrongLinuxBoundary) {
|
|
5425
|
+
if (isLinuxGenericWorkspaceContract(sandboxOpts.executionContract)) {
|
|
5426
|
+
return applyLinuxGenericWorkspaceSandbox(
|
|
5427
|
+
command,
|
|
5428
|
+
args,
|
|
5429
|
+
spawnOpts,
|
|
5430
|
+
sandboxOpts,
|
|
5431
|
+
runtime,
|
|
5432
|
+
);
|
|
5433
|
+
}
|
|
4935
5434
|
const requestedEntryRuntime =
|
|
4936
5435
|
sandboxOpts.executionContract?.kind ===
|
|
4937
5436
|
"strict-plugin-native-static-elf-bin"
|
|
4938
5437
|
? "native-static-elf"
|
|
4939
|
-
: "
|
|
5438
|
+
: sandboxOpts.executionContract?.kind === "strict-plugin-native-elf-bin"
|
|
5439
|
+
? "native-unclassified"
|
|
5440
|
+
: "node";
|
|
4940
5441
|
const validation = validateLinuxPluginContract(
|
|
4941
5442
|
command,
|
|
4942
5443
|
args,
|
|
@@ -5009,6 +5510,29 @@ export function applyLinuxSandbox(
|
|
|
5009
5510
|
guarantees: [],
|
|
5010
5511
|
});
|
|
5011
5512
|
}
|
|
5513
|
+
let nativeDynamicClosure = null;
|
|
5514
|
+
try {
|
|
5515
|
+
nativeDynamicClosure = bindLinuxNativeDynamicRuntime(
|
|
5516
|
+
validation.entryFormat,
|
|
5517
|
+
pinnedRuntimeMounts,
|
|
5518
|
+
);
|
|
5519
|
+
} catch (error) {
|
|
5520
|
+
closeLinuxPinnedMounts(runtime, pinnedRuntimeMounts);
|
|
5521
|
+
return createSandboxPlan({
|
|
5522
|
+
...base,
|
|
5523
|
+
backend: null,
|
|
5524
|
+
candidateBackend: LINUX_BWRAP_BACKEND,
|
|
5525
|
+
policyAttested: false,
|
|
5526
|
+
runtimeProbe: linuxBubblewrapProbe(
|
|
5527
|
+
false,
|
|
5528
|
+
false,
|
|
5529
|
+
error.message || "native_dynamic_direct_system_set_unattested",
|
|
5530
|
+
validation.entryRuntime,
|
|
5531
|
+
),
|
|
5532
|
+
reason: "linux_bwrap_native_runtime_unattested",
|
|
5533
|
+
guarantees: [],
|
|
5534
|
+
});
|
|
5535
|
+
}
|
|
5012
5536
|
|
|
5013
5537
|
let pinnedMounts = [];
|
|
5014
5538
|
let pluginTree;
|
|
@@ -5046,8 +5570,8 @@ export function applyLinuxSandbox(
|
|
|
5046
5570
|
) {
|
|
5047
5571
|
throw new Error("plugin_entry_pin_mismatch");
|
|
5048
5572
|
}
|
|
5049
|
-
if (validation.entryRuntime
|
|
5050
|
-
entryFormat =
|
|
5573
|
+
if (validation.entryRuntime.startsWith("native-")) {
|
|
5574
|
+
entryFormat = inspectLinuxNativeElf(
|
|
5051
5575
|
runtime,
|
|
5052
5576
|
entryMount.fd,
|
|
5053
5577
|
validation.contract.entryIdentity,
|
|
@@ -5325,10 +5849,9 @@ export function applyLinuxSandbox(
|
|
|
5325
5849
|
environment,
|
|
5326
5850
|
seccompFilter,
|
|
5327
5851
|
);
|
|
5328
|
-
const targetArgs =
|
|
5329
|
-
|
|
5330
|
-
|
|
5331
|
-
: ["/opt/chainless/runtime/node", sandboxEntry, ...args.slice(1)];
|
|
5852
|
+
const targetArgs = validation.entryRuntime.startsWith("native-")
|
|
5853
|
+
? [sandboxEntry, ...args]
|
|
5854
|
+
: ["/opt/chainless/runtime/node", sandboxEntry, ...args.slice(1)];
|
|
5332
5855
|
const snapshotPolicyBinding = entrySnapshot
|
|
5333
5856
|
? {
|
|
5334
5857
|
scope: entrySnapshot.attestation.scope,
|
|
@@ -5389,6 +5912,9 @@ export function applyLinuxSandbox(
|
|
|
5389
5912
|
},
|
|
5390
5913
|
),
|
|
5391
5914
|
contentSnapshot: snapshotPolicyBinding,
|
|
5915
|
+
...(nativeDynamicClosure
|
|
5916
|
+
? { initialDynamicLoadClosure: nativeDynamicClosure }
|
|
5917
|
+
: {}),
|
|
5392
5918
|
...(validation.entryRuntime === "node"
|
|
5393
5919
|
? { pluginTreeContentSnapshot: pluginTreeSnapshot }
|
|
5394
5920
|
: {}),
|
|
@@ -5398,10 +5924,9 @@ export function applyLinuxSandbox(
|
|
|
5398
5924
|
sha256: seccompFilter.sha256,
|
|
5399
5925
|
},
|
|
5400
5926
|
policyArgs,
|
|
5401
|
-
target:
|
|
5402
|
-
|
|
5403
|
-
|
|
5404
|
-
: targetArgs.slice(0, 2),
|
|
5927
|
+
target: validation.entryRuntime.startsWith("native-")
|
|
5928
|
+
? targetArgs.slice(0, 1)
|
|
5929
|
+
: targetArgs.slice(0, 2),
|
|
5405
5930
|
}),
|
|
5406
5931
|
)
|
|
5407
5932
|
.digest("hex");
|
|
@@ -5556,6 +6081,7 @@ export function applyLinuxSandbox(
|
|
|
5556
6081
|
entrySnapshot?.attestation,
|
|
5557
6082
|
supervisorBinding,
|
|
5558
6083
|
pluginTreeSnapshot,
|
|
6084
|
+
nativeDynamicClosure,
|
|
5559
6085
|
),
|
|
5560
6086
|
);
|
|
5561
6087
|
const options = {
|
|
@@ -5655,6 +6181,7 @@ export function applyLinuxSandbox(
|
|
|
5655
6181
|
* profile?: string,
|
|
5656
6182
|
* requiredBoundaries?: string[],
|
|
5657
6183
|
* sync?: boolean,
|
|
6184
|
+
* pty?: boolean,
|
|
5658
6185
|
* executionContract?: Readonly<Object>|null
|
|
5659
6186
|
* }|null} explicitRequest
|
|
5660
6187
|
* @returns {ReturnType<typeof createSandboxPlan>}
|
|
@@ -5715,6 +6242,7 @@ export function applySandbox(
|
|
|
5715
6242
|
profileName: profiles[profileName] ? profileName : "default",
|
|
5716
6243
|
requiredBoundaries: sandboxRequest.requiredBoundaries,
|
|
5717
6244
|
sync: sandboxRequest.sync,
|
|
6245
|
+
pty: sandboxRequest.pty,
|
|
5718
6246
|
executionContract: sandboxRequest.executionContract,
|
|
5719
6247
|
};
|
|
5720
6248
|
|