chainlesschain 0.162.183 → 0.162.184
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-DzAl5fGx.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-CXYdXEUI.js → ActionButton-DAHtMGeC.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-CKR5Lexn.js → Analytics-BHQaexv5.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-DATVUOXB.js → AppLayout-Phz_pD0n.js} +4 -4
- package/src/assets/web-panel/assets/{Artifacts-vb_0ZlV1.js → Artifacts-DHt47kCA.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-BI1l9GWt.js → Audit--Y_8FULl.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-BFXbaUEf.js → BackgroundAgents-N1zchH7D.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-DEYBJJ6H.js → Backup-B_BoyN30.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-COdzeO0M.js → BaseInput-Gl4uQHcT.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-oSN6sfM5.js → Chat-Cg-eIyAZ.js} +6 -6
- package/src/assets/web-panel/assets/ChatBubbleRenderer-BzeUi3JH.js +1 -0
- package/src/assets/web-panel/assets/{Checkbox-BezEa4tm.js → Checkbox-D0MGR2wA.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-CNEL0Ife.js → Codegen-BdObJEFn.js} +1 -1
- package/src/assets/web-panel/assets/{Col-Bf2Y2Bn1.js → Col--ghxXT3z.js} +1 -1
- package/src/assets/web-panel/assets/{Community-BfUlu4Hc.js → Community-BUFeXOqz.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-BN4xWP9e.js → Compact-DhQO2_Mr.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-Bt6BKmEP.js → Compliance-3HoTqKYd.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-DKLp8YxO.js → Cowork-B3zmO4VW.js} +3 -3
- package/src/assets/web-panel/assets/{Cron-o7Hhw6ky.js → Cron-CJDrZOcc.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-DaNXWJIw.js → Crosschain-SMl15obd.js} +1 -1
- package/src/assets/web-panel/assets/{DID-B-Qa2mha.js → DID-CgTrTWrl.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-CMX0Qnxw.js → Dashboard-dXFKaKol.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-BLuLyRu_.js → Dropdown-qQHEhCvI.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-CFBAeMij.js → EmailListRenderer-C_ej0MWH.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-DWzXQ67V.js → FamilyGuardDashboard-D6ajoE7I.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-DB1QSLgr.js → Federation-Cio2y49h.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-C-OKCToP.js → FormItemContext-ClJz1cYp.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-DMJFtFZf.js → GenericCardRenderer-Dr_8Maca.js} +1 -1
- package/src/assets/web-panel/assets/{Git-DsGSujOV.js → Git-CevLwp5u.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-B0iS9NEW.js → Governance-CW9YyQUY.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-CH004H7c.js → Inference-CQqeAyER.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-Q9MTQ83c.js → KnowledgeGraph-cuGVxHrw.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-B_fyjZK9.js → Logs-DIuHri5d.js} +2 -2
- package/src/assets/web-panel/assets/{MarkdownRenderer-C0o4FtpD.js → MarkdownRenderer-R91Qw5JA.js} +1 -1
- package/src/assets/web-panel/assets/{Marketplace-BIStF9d1.js → Marketplace-CY1VhFGx.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-pGfal768.js → McpTools-BBAbi1vt.js} +5 -5
- package/src/assets/web-panel/assets/{Memory-xbNqpIqB.js → Memory-BWYGHxJA.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-B5EQGrIK.js → MobileBridge-CPIFkW7A.js} +1 -1
- package/src/assets/web-panel/assets/MobileProjects-DQyWxCho.js +1 -0
- package/src/assets/web-panel/assets/{Mtc-a_rmfxJH.js → Mtc-Bo3GnQbx.js} +4 -4
- package/src/assets/web-panel/assets/{MtcAudit-BmKuofUr.js → MtcAudit-C8-c4rSW.js} +4 -4
- package/src/assets/web-panel/assets/{Multisig-BQbJ-CAN.js → Multisig-ChqMTtoq.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-JtPJKX25.js → NLProgramming-C48TyhvI.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-ZFKznTSG.js → Notes-zogUFWxp.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-B6aHRBBR.js → NotificationSettings-v-K9XpSB.js} +1 -1
- package/src/assets/web-panel/assets/OrderTableRenderer-P94JGGNz.js +1 -0
- package/src/assets/web-panel/assets/{Organization-BFDTAUgS.js → Organization-Boi1dQfR.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-0FoTfbWH.js → Overflow-DM5YWwgA.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-CWd90etw.js → P2P-C57LKpKK.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-DtCGC-W-.js → PdhVaultBrowser-BFkPqu6Q.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-CvQ7nr7T.js → Permissions-D6fB9YSp.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-rdNPcR-Z.js → PersonalDataHub-Bp7EefEo.js} +3 -3
- package/src/assets/web-panel/assets/{Pipeline-CmrfiNOs.js → Pipeline-BVln3hZf.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-D7ep1h_t.js → Privacy-Bf8P3nF6.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-C0xKINHS.js → ProjectInit-DM6wA2E2.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-AOmZFp-F.js → ProjectSettings-CGbc5Iho.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-BWHSkXZP.js → Projects-D0p9EOxm.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-Cb7JCTPL.js → Providers-B2kJcxS6.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-BDMehcXC.js → QrScannerModal-Cxu7dXYy.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-BF6_1nvx.js → QuickAsk-DTlrTPms.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-BHfT-A28.js → Recommend-Cm3X-cCj.js} +1 -1
- package/src/assets/web-panel/assets/RemoteSession-DNb2kjvt.js +5 -0
- package/src/assets/web-panel/assets/{Reputation-CsWHLEcj.js → Reputation-CZUFFjc1.js} +1 -1
- package/src/assets/web-panel/assets/{Row-D6srnWhm.js → Row-DAPgloxA.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-Xhr-KyVd.js → RssFeed-dsx9S793.js} +3 -3
- package/src/assets/web-panel/assets/{Search-vIbIJvwL.js → Search-DnnC8kz-.js} +1 -1
- package/src/assets/web-panel/assets/{Security-Bzi5Aiko.js → Security-VuZknRMK.js} +4 -4
- package/src/assets/web-panel/assets/{Services-BHtVX52P.js → Services-B3XNX8Vx.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-C0R8B2jf.js → Skeleton-Dl1nVtCj.js} +1 -1
- package/src/assets/web-panel/assets/Skills-CY09CZ_W.js +1 -0
- package/src/assets/web-panel/assets/{Sla-0B37mxVU.js → Sla-HzU56n1z.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-0V2jE1Bs.js → SpeechSettings-CRle7Jl2.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-CYedRzaj.js → SyncSettings-DWadz7Sl.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-D-R1x8vm.js → Tasks-CNVTDGg8.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-BKoHztGT.js → Templates-BBAgvrlM.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant--17nwVNZ.js → Tenant-BsbbvGN8.js} +1 -1
- package/src/assets/web-panel/assets/Terminal-uscpZI4q.js +3 -0
- package/src/assets/web-panel/assets/{TimelineRenderer-C5jx4AE3.js → TimelineRenderer-mTyjNE6r.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-DYJKYa9t.js → Tokens-Bz97oBgs.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-DChpWiQ9.js → Trigger-BTRKC140.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-DfWG52EA.js → Trust-B4A_KuyX.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-CMugYcyA.js → UkeySign-DES9TmLU.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-BOSmrHAd.js → VideoEditing-ClXs7Qxp.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-D5g3k3Sa.js → Wallet-IzZqFz-7.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-D-7u4Mkc.js → WebAuthn-BtOP04g_.js} +3 -3
- package/src/assets/web-panel/assets/{WorkflowEditor-CFzZMSUJ.js → WorkflowEditor-_0cqnopY.js} +1 -1
- package/src/assets/web-panel/assets/{chat-VbR6l6mc.js → chat-ax7193uU.js} +1 -1
- package/src/assets/web-panel/assets/{colors-BSZn8EDS.js → colors-Bu4WGJah.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-y74obMEq.js → compact-item-BX1dlTW0.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-C326bjex.js → createContext-CktA_Dj7.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-x877iKKS.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-D_INJQT_.js → hasIn-D5wd817l.js} +1 -1
- package/src/assets/web-panel/assets/{index-CsovTpx9.js → index-5PYYkr8S.js} +1 -1
- package/src/assets/web-panel/assets/{index-9PIVuXqo.js → index-A4uBPQCz.js} +1 -1
- package/src/assets/web-panel/assets/{index-BjcWKg1S.js → index-BAtBNfkr.js} +1 -1
- package/src/assets/web-panel/assets/{index-CMHqs3Jb.js → index-BLLsUNDc.js} +1 -1
- package/src/assets/web-panel/assets/{index-B7SrC-On.js → index-BQtoRyTO.js} +1 -1
- package/src/assets/web-panel/assets/{index-DUU2606o.js → index-BRfXoRuh.js} +1 -1
- package/src/assets/web-panel/assets/{index-Iw0FfqUz.js → index-Bad2CYeH.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dlxh9D8D.js → index-BcGdL3sG.js} +1 -1
- package/src/assets/web-panel/assets/{index-DuIkfnTF.js → index-C3HmzCLt.js} +1 -1
- package/src/assets/web-panel/assets/{index-E_v1ZCTP.js → index-C8DkWyNr.js} +1 -1
- package/src/assets/web-panel/assets/{index-4eyH-eC2.js → index-C8tLR2TG.js} +1 -1
- package/src/assets/web-panel/assets/{index-BnSfnSMP.js → index-CP8ELJBc.js} +1 -1
- package/src/assets/web-panel/assets/{index-DwHSZLXg.js → index-CUForzsG.js} +1 -1
- package/src/assets/web-panel/assets/{index-C2NyllnW.js → index-CYRE0NJA.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bnua8IX3.js → index-CeVZaJSC.js} +1 -1
- package/src/assets/web-panel/assets/{index-KF9Zmqln.js → index-CfzxR61U.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cr3uuz0C.js → index-Ci3y1ZAv.js} +3 -3
- package/src/assets/web-panel/assets/{index-DBkzrpiL.js → index-CjEJjl5C.js} +1 -1
- package/src/assets/web-panel/assets/{index-abmn_8Yz.js → index-Cv7bVWJ5.js} +1 -1
- package/src/assets/web-panel/assets/{index-qMA4GYdQ.js → index-D-o4Rwjk.js} +1 -1
- package/src/assets/web-panel/assets/index-D7pfPouB.js +1 -0
- package/src/assets/web-panel/assets/{index-jYaogFE8.js → index-D9op8poE.js} +1 -1
- package/src/assets/web-panel/assets/{index-GA80ir_u.js → index-DF1TysIF.js} +1 -1
- package/src/assets/web-panel/assets/{index-CzE53HiB.js → index-DYo9S5OT.js} +1 -1
- package/src/assets/web-panel/assets/{index-gINyI1rh.js → index-D_cycOET.js} +1 -1
- package/src/assets/web-panel/assets/{index-FQBsuExX.js → index-Db3CpWTr.js} +1 -1
- package/src/assets/web-panel/assets/{index-IZAWt0H8.js → index-DkD1K-fF.js} +1 -1
- package/src/assets/web-panel/assets/{index-C327pLbw.js → index-DmPJ6T6F.js} +1 -1
- package/src/assets/web-panel/assets/{index-DdyjrCAu.js → index-DmVUeWUk.js} +1 -1
- package/src/assets/web-panel/assets/{index-CfLJ42kv.js → index-Dzdr0zDf.js} +1 -1
- package/src/assets/web-panel/assets/{index-DkH1JvEt.js → index-PBLzwYnu.js} +1 -1
- package/src/assets/web-panel/assets/{index-DNMxIsDg.js → index-bFCaM7Eq.js} +1 -1
- package/src/assets/web-panel/assets/index-e4i-VLBd.js +1 -0
- package/src/assets/web-panel/assets/{index-C-ZCaUJc.js → index-h3KJZr95.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bfw2hf2s.js → index-iHcPtQ2e.js} +1 -1
- package/src/assets/web-panel/assets/{index-BJi3UqBt.js → index-jzlzm4VK.js} +1 -1
- package/src/assets/web-panel/assets/{index-BY8-nCgs.js → index-o14NNnxw.js} +1 -1
- package/src/assets/web-panel/assets/{index-nSn2-C4N.js → index-tYPSfGbd.js} +1 -1
- package/src/assets/web-panel/assets/{index-4PIeTM--.js → index-ytp2H5Zx.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-DI0Zaf8-.js → initDefaultProps-D2Iut83B.js} +1 -1
- package/src/assets/web-panel/assets/{motion-BZDKSy3Z.js → motion-BuaJVdK9.js} +1 -1
- package/src/assets/web-panel/assets/{move-DsIW01Vp.js → move-CaEuM92y.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-CohkDhsf.js → mtc-parser-wuKNBwys.js} +1 -1
- package/src/assets/web-panel/assets/{omit-DpiN5rzg.js → omit-7a3eklaq.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-qbuqni3y.js → pickAttrs-Dn4z7KvJ.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-mBky6714.js → placementArrow-DVn_qT4-.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-Bas3eQ2K.js → responsiveObserve-Dodz1OMQ.js} +1 -1
- package/src/assets/web-panel/assets/{slide-CBx_SKoK.js → slide-CxoGskbp.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-BlYguJSV.js → statusUtils-DBh_epQH.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-BCYQmRGv.js → styleChecker-RXQ4gG5P.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-Dp5dybLM.js → useFlexGapSupport-1Wxm0HEG.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-DHAMBgA2.js → useFs-CI_ySNxJ.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-W6jsSw76.js → usePersonalDataHub-C6973rZP.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-BkI6aayc.js → vnode-CalynwKr.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-C_IMGueq.js → zoom-CM1cd-Q0.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 +13 -0
- 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/collaboration-run-store.js +362 -0
- package/src/lib/hook-runner.cjs +98 -17
- package/src/lib/hook-runner.js +77 -6
- package/src/lib/hook-shell-command.cjs +148 -0
- package/src/lib/hooks-v2-runtime.js +188 -77
- package/src/lib/jsonl-session-store.js +2 -0
- package/src/lib/lsp/__tests__/lsp-client.test.js +18 -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 +1 -1
- 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 +99 -0
- package/src/lib/process-execution-broker/index.js +453 -12
- package/src/lib/process-execution-broker/linux-generic-bwrap-runtime.js +1347 -0
- package/src/lib/process-execution-broker/linux-generic-bwrap.js +1260 -0
- package/src/lib/process-execution-broker/platform-sandbox.js +580 -56
- package/src/lib/session-usage.js +202 -2
- package/src/lib/stream-retry.js +29 -0
- package/src/repl/agent-repl.js +32 -3
- package/src/runtime/agent-core.js +32 -4
- package/src/runtime/headless-runner.js +37 -0
- package/src/runtime/headless-stream.js +34 -2
- package/src/assets/web-panel/assets/ChatBubbleRenderer-CI_jT0ru.js +0 -1
- package/src/assets/web-panel/assets/MobileProjects-VTc3gT1y.js +0 -1
- package/src/assets/web-panel/assets/OrderTableRenderer-DdcsOqEz.js +0 -1
- package/src/assets/web-panel/assets/RemoteSession-B6EEf8hh.js +0 -5
- package/src/assets/web-panel/assets/Skills-DtT6rWOX.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,
|
|
@@ -2600,8 +2630,11 @@ function linuxBubblewrapProbe(
|
|
|
2600
2630
|
contentSnapshot = null,
|
|
2601
2631
|
supervisorBinding = null,
|
|
2602
2632
|
pluginTreeSnapshot = null,
|
|
2633
|
+
nativeDynamicClosure = null,
|
|
2603
2634
|
) {
|
|
2604
|
-
const native =
|
|
2635
|
+
const native =
|
|
2636
|
+
typeof targetRuntime === "string" && targetRuntime.startsWith("native-");
|
|
2637
|
+
const dynamicNative = targetRuntime === "native-dynamic-elf";
|
|
2605
2638
|
const expectedSnapshotScope = native
|
|
2606
2639
|
? LINUX_NATIVE_ENTRY_SNAPSHOT_SCOPE
|
|
2607
2640
|
: LINUX_NODE_ENTRY_SNAPSHOT_SCOPE;
|
|
@@ -2631,10 +2664,34 @@ function linuxBubblewrapProbe(
|
|
|
2631
2664
|
LINUX_NODE_PLUGIN_TREE_SNAPSHOT_CONSISTENCY &&
|
|
2632
2665
|
pluginTreeSnapshot?.contractBound === false &&
|
|
2633
2666
|
pluginTreeSnapshot?.atomic === false;
|
|
2667
|
+
const initialDynamicLoadClosureDescriptorBound =
|
|
2668
|
+
dynamicNative &&
|
|
2669
|
+
attempted &&
|
|
2670
|
+
snapshot &&
|
|
2671
|
+
runnable &&
|
|
2672
|
+
reason === null &&
|
|
2673
|
+
supervisorDescriptorBound &&
|
|
2674
|
+
nativeDynamicClosure?.mechanism ===
|
|
2675
|
+
LINUX_NATIVE_DYNAMIC_DIRECT_SYSTEM_SET_MECHANISM &&
|
|
2676
|
+
nativeDynamicClosure?.scope ===
|
|
2677
|
+
LINUX_NATIVE_DYNAMIC_DIRECT_SYSTEM_SET_SCOPE &&
|
|
2678
|
+
typeof nativeDynamicClosure?.interpreter === "string" &&
|
|
2679
|
+
path.posix.isAbsolute(nativeDynamicClosure.interpreter) &&
|
|
2680
|
+
Number.isSafeInteger(nativeDynamicClosure?.dependencies) &&
|
|
2681
|
+
nativeDynamicClosure.dependencies >= 0 &&
|
|
2682
|
+
nativeDynamicClosure.dependencies <= LINUX_ELF_MAX_NEEDED_ENTRIES &&
|
|
2683
|
+
Number.isSafeInteger(nativeDynamicClosure?.files) &&
|
|
2684
|
+
nativeDynamicClosure.files >= 1 &&
|
|
2685
|
+
typeof nativeDynamicClosure?.digest === "string" &&
|
|
2686
|
+
/^[a-f0-9]{64}$/.test(nativeDynamicClosure.digest);
|
|
2634
2687
|
return {
|
|
2635
|
-
kind:
|
|
2636
|
-
? "linux-bwrap-plugin-native-
|
|
2637
|
-
: "
|
|
2688
|
+
kind: dynamicNative
|
|
2689
|
+
? "linux-bwrap-plugin-native-dynamic-elf-policy-v1"
|
|
2690
|
+
: targetRuntime === "native-static-elf"
|
|
2691
|
+
? "linux-bwrap-plugin-native-static-elf-policy-v1"
|
|
2692
|
+
: native
|
|
2693
|
+
? "linux-bwrap-plugin-native-elf-policy-v1"
|
|
2694
|
+
: "linux-bwrap-plugin-node-policy-v1",
|
|
2638
2695
|
attempted,
|
|
2639
2696
|
runnable,
|
|
2640
2697
|
reason,
|
|
@@ -2660,6 +2717,17 @@ function linuxBubblewrapProbe(
|
|
|
2660
2717
|
pluginTreeSnapshotAtomic: pluginTreeSnapshot.atomic,
|
|
2661
2718
|
}
|
|
2662
2719
|
: {}),
|
|
2720
|
+
...(initialDynamicLoadClosureDescriptorBound
|
|
2721
|
+
? {
|
|
2722
|
+
initialDynamicLoadClosureDescriptorBound: true,
|
|
2723
|
+
initialDynamicLoadClosureScope: nativeDynamicClosure.scope,
|
|
2724
|
+
initialDynamicLoadClosureMechanism: nativeDynamicClosure.mechanism,
|
|
2725
|
+
initialDynamicInterpreter: nativeDynamicClosure.interpreter,
|
|
2726
|
+
initialDynamicDependencyCount: nativeDynamicClosure.dependencies,
|
|
2727
|
+
initialDynamicRuntimeFileCount: nativeDynamicClosure.files,
|
|
2728
|
+
initialDynamicLoadClosureDigest: nativeDynamicClosure.digest,
|
|
2729
|
+
}
|
|
2730
|
+
: {}),
|
|
2663
2731
|
supervisorDescriptorBound,
|
|
2664
2732
|
...(supervisorDescriptorBound
|
|
2665
2733
|
? {
|
|
@@ -2957,8 +3025,11 @@ function validateLinuxPluginContract(
|
|
|
2957
3025
|
{ sealedEntry = false } = {},
|
|
2958
3026
|
) {
|
|
2959
3027
|
const nodeContract = contract?.kind === "strict-plugin-node-bin";
|
|
2960
|
-
const
|
|
3028
|
+
const legacyStaticNativeContract =
|
|
2961
3029
|
contract?.kind === "strict-plugin-native-static-elf-bin";
|
|
3030
|
+
const nativeContract =
|
|
3031
|
+
legacyStaticNativeContract ||
|
|
3032
|
+
contract?.kind === "strict-plugin-native-elf-bin";
|
|
2962
3033
|
const entryIsSealed =
|
|
2963
3034
|
(nodeContract || nativeContract) && sealedEntry === true;
|
|
2964
3035
|
if (
|
|
@@ -3081,16 +3152,22 @@ function validateLinuxPluginContract(
|
|
|
3081
3152
|
let entryFormat = null;
|
|
3082
3153
|
if (nativeContract && !entryIsSealed) {
|
|
3083
3154
|
try {
|
|
3084
|
-
entryFormat =
|
|
3085
|
-
runtime,
|
|
3086
|
-
contract.entryIdentity,
|
|
3087
|
-
);
|
|
3155
|
+
entryFormat = inspectLinuxNativePath(runtime, contract.entryIdentity);
|
|
3088
3156
|
} catch (error) {
|
|
3089
3157
|
return {
|
|
3090
3158
|
ok: false,
|
|
3091
3159
|
reason: error.message || "native_entry_unattested",
|
|
3092
3160
|
};
|
|
3093
3161
|
}
|
|
3162
|
+
if (
|
|
3163
|
+
legacyStaticNativeContract &&
|
|
3164
|
+
entryFormat.runtime !== "native-static-elf"
|
|
3165
|
+
) {
|
|
3166
|
+
return {
|
|
3167
|
+
ok: false,
|
|
3168
|
+
reason: "native_entry_dynamic_contract_required",
|
|
3169
|
+
};
|
|
3170
|
+
}
|
|
3094
3171
|
}
|
|
3095
3172
|
if (
|
|
3096
3173
|
!validateLinuxPluginTree(runtime, contract.pluginRoot) ||
|
|
@@ -3101,7 +3178,12 @@ function validateLinuxPluginContract(
|
|
|
3101
3178
|
return {
|
|
3102
3179
|
ok: true,
|
|
3103
3180
|
contract,
|
|
3104
|
-
entryRuntime: nativeContract
|
|
3181
|
+
entryRuntime: nativeContract
|
|
3182
|
+
? entryFormat?.runtime ||
|
|
3183
|
+
(legacyStaticNativeContract
|
|
3184
|
+
? "native-static-elf"
|
|
3185
|
+
: "native-unclassified")
|
|
3186
|
+
: "node",
|
|
3105
3187
|
entryFormat,
|
|
3106
3188
|
};
|
|
3107
3189
|
}
|
|
@@ -3170,7 +3252,7 @@ function hashLinuxOpenFile(runtime, fd, bytes) {
|
|
|
3170
3252
|
}
|
|
3171
3253
|
|
|
3172
3254
|
function linuxEntrySnapshotContract(targetRuntime) {
|
|
3173
|
-
if (targetRuntime
|
|
3255
|
+
if (targetRuntime?.startsWith("native-")) {
|
|
3174
3256
|
return {
|
|
3175
3257
|
scope: LINUX_NATIVE_ENTRY_SNAPSHOT_SCOPE,
|
|
3176
3258
|
targetMode: LINUX_NATIVE_ENTRY_SNAPSHOT_TARGET_MODE,
|
|
@@ -3663,18 +3745,169 @@ function attestLinuxNodePluginTreeSnapshot(
|
|
|
3663
3745
|
}
|
|
3664
3746
|
}
|
|
3665
3747
|
|
|
3748
|
+
function validLinuxRuntimePageSize(value) {
|
|
3749
|
+
if (
|
|
3750
|
+
!Number.isSafeInteger(value) ||
|
|
3751
|
+
value < LINUX_MIN_RUNTIME_PAGE_BYTES ||
|
|
3752
|
+
value > LINUX_MAX_RUNTIME_PAGE_BYTES
|
|
3753
|
+
) {
|
|
3754
|
+
return false;
|
|
3755
|
+
}
|
|
3756
|
+
const size = BigInt(value);
|
|
3757
|
+
return (size & (size - 1n)) === 0n;
|
|
3758
|
+
}
|
|
3759
|
+
|
|
3760
|
+
function readLinuxPageSizeFromAuxv(runtimeFs) {
|
|
3761
|
+
// AT_PAGESZ is emitted by the kernel for this exact process and matches the
|
|
3762
|
+
// page granularity used by the ELF loader. Avoid filesystem block sizes or
|
|
3763
|
+
// an external getconf binary, neither of which is the loader contract.
|
|
3764
|
+
const raw = runtimeFs.readFileSync("/proc/self/auxv");
|
|
3765
|
+
const auxv = Buffer.isBuffer(raw) ? raw : Buffer.from(raw);
|
|
3766
|
+
if (
|
|
3767
|
+
auxv.length < LINUX_AUXV_ENTRY_BYTES ||
|
|
3768
|
+
auxv.length > LINUX_AUXV_MAX_BYTES ||
|
|
3769
|
+
auxv.length % LINUX_AUXV_ENTRY_BYTES !== 0
|
|
3770
|
+
) {
|
|
3771
|
+
throw new Error("linux_runtime_auxv_invalid");
|
|
3772
|
+
}
|
|
3773
|
+
let pageSize = null;
|
|
3774
|
+
let terminated = false;
|
|
3775
|
+
for (let offset = 0; offset < auxv.length; offset += LINUX_AUXV_ENTRY_BYTES) {
|
|
3776
|
+
const tag = auxv.readBigUInt64LE(offset);
|
|
3777
|
+
const value = auxv.readBigUInt64LE(offset + 8);
|
|
3778
|
+
if (tag === 0n) {
|
|
3779
|
+
terminated = true;
|
|
3780
|
+
break;
|
|
3781
|
+
}
|
|
3782
|
+
if (tag !== LINUX_AUXV_PAGE_SIZE) continue;
|
|
3783
|
+
if (pageSize !== null || value > BigInt(Number.MAX_SAFE_INTEGER)) {
|
|
3784
|
+
throw new Error("linux_runtime_page_size_ambiguous");
|
|
3785
|
+
}
|
|
3786
|
+
pageSize = Number(value);
|
|
3787
|
+
}
|
|
3788
|
+
if (!terminated || !validLinuxRuntimePageSize(pageSize)) {
|
|
3789
|
+
throw new Error("linux_runtime_page_size_unattested");
|
|
3790
|
+
}
|
|
3791
|
+
return pageSize;
|
|
3792
|
+
}
|
|
3793
|
+
|
|
3794
|
+
function linuxElfRuntimePageSize(runtime) {
|
|
3795
|
+
const pageSize =
|
|
3796
|
+
typeof runtime.linuxPageSize === "function"
|
|
3797
|
+
? runtime.linuxPageSize()
|
|
3798
|
+
: readLinuxPageSizeFromAuxv(runtime.fs);
|
|
3799
|
+
if (!validLinuxRuntimePageSize(pageSize)) {
|
|
3800
|
+
throw new Error("linux_runtime_page_size_unattested");
|
|
3801
|
+
}
|
|
3802
|
+
return BigInt(pageSize);
|
|
3803
|
+
}
|
|
3804
|
+
|
|
3805
|
+
function linuxElfAlignDown(value, alignment) {
|
|
3806
|
+
return value - (value % alignment);
|
|
3807
|
+
}
|
|
3808
|
+
|
|
3809
|
+
function linuxElfAlignUp(value, alignment) {
|
|
3810
|
+
const remainder = value % alignment;
|
|
3811
|
+
return remainder === 0n ? value : value + alignment - remainder;
|
|
3812
|
+
}
|
|
3813
|
+
|
|
3814
|
+
function attestLinuxElfLoadMappings(loadSegments, pageSize) {
|
|
3815
|
+
// Linux maps later PT_LOAD entries with MAP_FIXED. Even disjoint byte ranges
|
|
3816
|
+
// can therefore replace one another after the loader rounds them to pages.
|
|
3817
|
+
// A conservative no-overlap contract keeps our file-offset parser and the
|
|
3818
|
+
// in-memory dynamic-loader view identical.
|
|
3819
|
+
const ranges = [];
|
|
3820
|
+
for (const load of loadSegments) {
|
|
3821
|
+
if (
|
|
3822
|
+
load.fileOffset % pageSize !== load.virtualAddress % pageSize ||
|
|
3823
|
+
(load.alignment > 1n &&
|
|
3824
|
+
((load.alignment & (load.alignment - 1n)) !== 0n ||
|
|
3825
|
+
load.fileOffset % load.alignment !==
|
|
3826
|
+
load.virtualAddress % load.alignment))
|
|
3827
|
+
) {
|
|
3828
|
+
throw new Error("native_entry_load_segment_alignment_invalid");
|
|
3829
|
+
}
|
|
3830
|
+
if (
|
|
3831
|
+
load.virtualAddress > LINUX_ELF_MAX_UINT64 - load.memorySize ||
|
|
3832
|
+
load.virtualAddress + load.memorySize >
|
|
3833
|
+
LINUX_ELF_MAX_UINT64 - (pageSize - 1n)
|
|
3834
|
+
) {
|
|
3835
|
+
throw new Error("native_entry_load_segment_virtual_range_overflow");
|
|
3836
|
+
}
|
|
3837
|
+
if (load.memorySize === 0n) continue;
|
|
3838
|
+
ranges.push({
|
|
3839
|
+
start: linuxElfAlignDown(load.virtualAddress, pageSize),
|
|
3840
|
+
end: linuxElfAlignUp(load.virtualAddress + load.memorySize, pageSize),
|
|
3841
|
+
});
|
|
3842
|
+
}
|
|
3843
|
+
ranges.sort((left, right) =>
|
|
3844
|
+
left.start < right.start ? -1 : left.start > right.start ? 1 : 0,
|
|
3845
|
+
);
|
|
3846
|
+
for (let index = 1; index < ranges.length; index += 1) {
|
|
3847
|
+
if (ranges[index].start < ranges[index - 1].end) {
|
|
3848
|
+
throw new Error("native_entry_load_segment_page_overlap");
|
|
3849
|
+
}
|
|
3850
|
+
}
|
|
3851
|
+
}
|
|
3852
|
+
|
|
3853
|
+
function linuxElfVirtualRangeFileMappings(loadSegments, address, bytes) {
|
|
3854
|
+
return loadSegments
|
|
3855
|
+
.filter((load) => {
|
|
3856
|
+
if (address < load.virtualAddress) return false;
|
|
3857
|
+
const delta = address - load.virtualAddress;
|
|
3858
|
+
return (
|
|
3859
|
+
delta <= load.fileSize &&
|
|
3860
|
+
bytes <= load.fileSize - delta &&
|
|
3861
|
+
delta <= load.memorySize &&
|
|
3862
|
+
bytes <= load.memorySize - delta
|
|
3863
|
+
);
|
|
3864
|
+
})
|
|
3865
|
+
.map((load) => ({
|
|
3866
|
+
load,
|
|
3867
|
+
fileOffset: load.fileOffset + (address - load.virtualAddress),
|
|
3868
|
+
}));
|
|
3869
|
+
}
|
|
3870
|
+
|
|
3871
|
+
function readLinuxElfString(table, offset, label) {
|
|
3872
|
+
if (!Number.isSafeInteger(offset) || offset < 0 || offset >= table.length) {
|
|
3873
|
+
throw new Error(`native_entry_${label}_string_out_of_bounds`);
|
|
3874
|
+
}
|
|
3875
|
+
const end = table.indexOf(0, offset);
|
|
3876
|
+
if (end < 0) {
|
|
3877
|
+
throw new Error(`native_entry_${label}_string_unterminated`);
|
|
3878
|
+
}
|
|
3879
|
+
const bytes = table.subarray(offset, end);
|
|
3880
|
+
if (bytes.length < 1 || bytes.some((value) => value < 0x21 || value > 0x7e)) {
|
|
3881
|
+
throw new Error(`native_entry_${label}_string_invalid`);
|
|
3882
|
+
}
|
|
3883
|
+
return bytes.toString("ascii");
|
|
3884
|
+
}
|
|
3885
|
+
|
|
3886
|
+
function linuxSystemDynamicPath(value) {
|
|
3887
|
+
return (
|
|
3888
|
+
typeof value === "string" &&
|
|
3889
|
+
path.posix.isAbsolute(value) &&
|
|
3890
|
+
path.posix.normalize(value) === value &&
|
|
3891
|
+
!value.includes("\0") &&
|
|
3892
|
+
["/lib/", "/lib64/", "/usr/lib/", "/usr/lib64/"].some((prefix) =>
|
|
3893
|
+
value.startsWith(prefix),
|
|
3894
|
+
)
|
|
3895
|
+
);
|
|
3896
|
+
}
|
|
3897
|
+
|
|
3666
3898
|
/**
|
|
3667
|
-
* Classify one already-pinned plugin entry without invoking it or
|
|
3668
|
-
* inspection utility.
|
|
3669
|
-
*
|
|
3670
|
-
*
|
|
3671
|
-
*
|
|
3899
|
+
* Classify one already-pinned plugin entry without invoking it or passing it
|
|
3900
|
+
* to a host inspection utility. Besides conventional fully static ET_EXEC and
|
|
3901
|
+
* static-PIE-shaped ET_DYN images, the parser can describe a narrow dynamic
|
|
3902
|
+
* executable. The caller must separately prove that its PT_INTERP and every
|
|
3903
|
+
* direct DT_NEEDED member are present in a pinned, attested system-file set.
|
|
3672
3904
|
*/
|
|
3673
|
-
function
|
|
3905
|
+
function inspectLinuxNativeElf(runtime, fd, identity) {
|
|
3674
3906
|
const expectedMachine = LINUX_ELF_MACHINES[runtime.arch];
|
|
3675
3907
|
if (!expectedMachine) {
|
|
3676
3908
|
throw new Error(`unsupported_elf_architecture:${String(runtime.arch)}`);
|
|
3677
3909
|
}
|
|
3910
|
+
const runtimePageSize = linuxElfRuntimePageSize(runtime);
|
|
3678
3911
|
const before = runtime.fs.fstatSync(fd);
|
|
3679
3912
|
if (
|
|
3680
3913
|
!before.isFile() ||
|
|
@@ -3741,6 +3974,7 @@ function inspectLinuxStaticNativeElf(runtime, fd, identity) {
|
|
|
3741
3974
|
let nonExecutableStack = false;
|
|
3742
3975
|
const loadSegments = [];
|
|
3743
3976
|
const dynamicSegments = [];
|
|
3977
|
+
const interpreterSegments = [];
|
|
3744
3978
|
for (let index = 0; index < programHeaderCount; index += 1) {
|
|
3745
3979
|
const offset =
|
|
3746
3980
|
Number(programHeaderOffset) + index * LINUX_ELF64_PROGRAM_HEADER_BYTES;
|
|
@@ -3756,6 +3990,7 @@ function inspectLinuxStaticNativeElf(runtime, fd, identity) {
|
|
|
3756
3990
|
const virtualAddress = program.readBigUInt64LE(16);
|
|
3757
3991
|
const fileSize = program.readBigUInt64LE(32);
|
|
3758
3992
|
const memorySize = program.readBigUInt64LE(40);
|
|
3993
|
+
const alignment = program.readBigUInt64LE(48);
|
|
3759
3994
|
if (fileOffset > fileBytes || fileSize > fileBytes - fileOffset) {
|
|
3760
3995
|
throw new Error("native_entry_segment_out_of_bounds");
|
|
3761
3996
|
}
|
|
@@ -3763,18 +3998,21 @@ function inspectLinuxStaticNativeElf(runtime, fd, identity) {
|
|
|
3763
3998
|
throw new Error("native_entry_segment_out_of_bounds");
|
|
3764
3999
|
}
|
|
3765
4000
|
if (type === LINUX_ELF_PROGRAM_INTERP) {
|
|
3766
|
-
|
|
4001
|
+
interpreterSegments.push({
|
|
4002
|
+
flags,
|
|
4003
|
+
fileOffset,
|
|
4004
|
+
fileSize,
|
|
4005
|
+
memorySize,
|
|
4006
|
+
});
|
|
3767
4007
|
}
|
|
3768
4008
|
if (type === LINUX_ELF_PROGRAM_DYNAMIC) {
|
|
3769
|
-
if (elfType === LINUX_ELF_TYPE_EXEC) {
|
|
3770
|
-
throw new Error("native_entry_dynamic_elf_unsupported");
|
|
3771
|
-
}
|
|
3772
4009
|
dynamicSegments.push({
|
|
3773
4010
|
flags,
|
|
3774
4011
|
fileOffset,
|
|
3775
4012
|
virtualAddress,
|
|
3776
4013
|
fileSize,
|
|
3777
4014
|
memorySize,
|
|
4015
|
+
alignment,
|
|
3778
4016
|
});
|
|
3779
4017
|
}
|
|
3780
4018
|
if (type === LINUX_ELF_PROGRAM_GNU_STACK) {
|
|
@@ -3790,6 +4028,7 @@ function inspectLinuxStaticNativeElf(runtime, fd, identity) {
|
|
|
3790
4028
|
virtualAddress,
|
|
3791
4029
|
fileSize,
|
|
3792
4030
|
memorySize,
|
|
4031
|
+
alignment,
|
|
3793
4032
|
});
|
|
3794
4033
|
}
|
|
3795
4034
|
if (type === LINUX_ELF_PROGRAM_LOAD && (flags & 0x1) !== 0) {
|
|
@@ -3805,6 +4044,7 @@ function inspectLinuxStaticNativeElf(runtime, fd, identity) {
|
|
|
3805
4044
|
}
|
|
3806
4045
|
}
|
|
3807
4046
|
}
|
|
4047
|
+
attestLinuxElfLoadMappings(loadSegments, runtimePageSize);
|
|
3808
4048
|
if (!executableLoad || !entryInExecutableLoad) {
|
|
3809
4049
|
throw new Error("native_entry_has_no_executable_entry_segment");
|
|
3810
4050
|
}
|
|
@@ -3812,23 +4052,65 @@ function inspectLinuxStaticNativeElf(runtime, fd, identity) {
|
|
|
3812
4052
|
throw new Error("native_entry_nonexecutable_stack_unattested");
|
|
3813
4053
|
}
|
|
3814
4054
|
|
|
3815
|
-
if (
|
|
4055
|
+
if (interpreterSegments.length > 1) {
|
|
4056
|
+
throw new Error("native_entry_interpreter_ambiguous");
|
|
4057
|
+
}
|
|
4058
|
+
let interpreter = null;
|
|
4059
|
+
if (interpreterSegments.length === 1) {
|
|
4060
|
+
const segment = interpreterSegments[0];
|
|
4061
|
+
if (
|
|
4062
|
+
(segment.flags & 0x3) !== 0 ||
|
|
4063
|
+
segment.fileSize < 2n ||
|
|
4064
|
+
segment.fileSize > BigInt(LINUX_ELF_MAX_INTERPRETER_BYTES) ||
|
|
4065
|
+
segment.fileSize > segment.memorySize
|
|
4066
|
+
) {
|
|
4067
|
+
throw new Error("native_entry_interpreter_invalid");
|
|
4068
|
+
}
|
|
4069
|
+
const contents = readLinuxFdExactly(
|
|
4070
|
+
runtime,
|
|
4071
|
+
fd,
|
|
4072
|
+
Number(segment.fileSize),
|
|
4073
|
+
Number(segment.fileOffset),
|
|
4074
|
+
);
|
|
4075
|
+
if (
|
|
4076
|
+
contents[contents.length - 1] !== 0 ||
|
|
4077
|
+
contents.indexOf(0) !== contents.length - 1
|
|
4078
|
+
) {
|
|
4079
|
+
throw new Error("native_entry_interpreter_unterminated");
|
|
4080
|
+
}
|
|
4081
|
+
interpreter = readLinuxElfString(contents, 0, "interpreter");
|
|
4082
|
+
if (!linuxSystemDynamicPath(interpreter)) {
|
|
4083
|
+
throw new Error("native_entry_interpreter_outside_system_roots");
|
|
4084
|
+
}
|
|
4085
|
+
}
|
|
4086
|
+
|
|
4087
|
+
const staticPie = elfType === LINUX_ELF_TYPE_DYN && interpreter === null;
|
|
4088
|
+
const dynamicExecutable = interpreter !== null;
|
|
4089
|
+
let dynamicMetadata = null;
|
|
4090
|
+
if (elfType === LINUX_ELF_TYPE_EXEC && !dynamicExecutable) {
|
|
4091
|
+
if (dynamicSegments.length > 0) {
|
|
4092
|
+
throw new Error("native_entry_dynamic_elf_unsupported");
|
|
4093
|
+
}
|
|
4094
|
+
} else {
|
|
4095
|
+
const prefix = staticPie
|
|
4096
|
+
? "native_entry_static_pie"
|
|
4097
|
+
: "native_entry_dynamic";
|
|
3816
4098
|
if (dynamicSegments.length === 0) {
|
|
3817
|
-
throw new Error(
|
|
4099
|
+
throw new Error(`${prefix}_dynamic_segment_missing`);
|
|
3818
4100
|
}
|
|
3819
4101
|
if (dynamicSegments.length !== 1) {
|
|
3820
|
-
throw new Error(
|
|
4102
|
+
throw new Error(`${prefix}_dynamic_segment_ambiguous`);
|
|
3821
4103
|
}
|
|
3822
4104
|
const dynamic = dynamicSegments[0];
|
|
3823
4105
|
if ((dynamic.flags & 0x1) !== 0) {
|
|
3824
|
-
throw new Error(
|
|
4106
|
+
throw new Error(`${prefix}_dynamic_segment_executable`);
|
|
3825
4107
|
}
|
|
3826
4108
|
if (
|
|
3827
4109
|
dynamic.fileSize < BigInt(LINUX_ELF64_DYNAMIC_ENTRY_BYTES) ||
|
|
3828
4110
|
dynamic.fileSize % BigInt(LINUX_ELF64_DYNAMIC_ENTRY_BYTES) !== 0n ||
|
|
3829
4111
|
dynamic.fileSize > dynamic.memorySize
|
|
3830
4112
|
) {
|
|
3831
|
-
throw new Error(
|
|
4113
|
+
throw new Error(`${prefix}_dynamic_segment_invalid`);
|
|
3832
4114
|
}
|
|
3833
4115
|
const dynamicEntries =
|
|
3834
4116
|
dynamic.fileSize / BigInt(LINUX_ELF64_DYNAMIC_ENTRY_BYTES);
|
|
@@ -3836,9 +4118,9 @@ function inspectLinuxStaticNativeElf(runtime, fd, identity) {
|
|
|
3836
4118
|
dynamicEntries < 1n ||
|
|
3837
4119
|
dynamicEntries > BigInt(LINUX_ELF_MAX_DYNAMIC_ENTRIES)
|
|
3838
4120
|
) {
|
|
3839
|
-
throw new Error(
|
|
4121
|
+
throw new Error(`${prefix}_dynamic_table_too_large`);
|
|
3840
4122
|
}
|
|
3841
|
-
const
|
|
4123
|
+
const containingLoads = loadSegments.filter((load) => {
|
|
3842
4124
|
if (
|
|
3843
4125
|
dynamic.fileOffset < load.fileOffset ||
|
|
3844
4126
|
dynamic.virtualAddress < load.virtualAddress
|
|
@@ -3855,8 +4137,22 @@ function inspectLinuxStaticNativeElf(runtime, fd, identity) {
|
|
|
3855
4137
|
dynamic.memorySize <= load.memorySize - memoryDelta
|
|
3856
4138
|
);
|
|
3857
4139
|
});
|
|
3858
|
-
if (
|
|
3859
|
-
throw new Error(
|
|
4140
|
+
if (containingLoads.length === 0) {
|
|
4141
|
+
throw new Error(`${prefix}_dynamic_segment_unmapped`);
|
|
4142
|
+
}
|
|
4143
|
+
if (containingLoads.length !== 1) {
|
|
4144
|
+
throw new Error(`${prefix}_dynamic_segment_mapping_ambiguous`);
|
|
4145
|
+
}
|
|
4146
|
+
const dynamicLoaderMappings = linuxElfVirtualRangeFileMappings(
|
|
4147
|
+
loadSegments,
|
|
4148
|
+
dynamic.virtualAddress,
|
|
4149
|
+
dynamic.fileSize,
|
|
4150
|
+
);
|
|
4151
|
+
if (
|
|
4152
|
+
dynamicLoaderMappings.length !== 1 ||
|
|
4153
|
+
dynamicLoaderMappings[0].fileOffset !== dynamic.fileOffset
|
|
4154
|
+
) {
|
|
4155
|
+
throw new Error(`${prefix}_dynamic_segment_loader_view_mismatch`);
|
|
3860
4156
|
}
|
|
3861
4157
|
|
|
3862
4158
|
const dynamicTable = readLinuxFdExactly(
|
|
@@ -3865,8 +4161,21 @@ function inspectLinuxStaticNativeElf(runtime, fd, identity) {
|
|
|
3865
4161
|
Number(dynamic.fileSize),
|
|
3866
4162
|
Number(dynamic.fileOffset),
|
|
3867
4163
|
);
|
|
4164
|
+
const neededOffsets = [];
|
|
4165
|
+
const forbiddenDependencyTags = new Set([
|
|
4166
|
+
LINUX_ELF_DYNAMIC_RPATH,
|
|
4167
|
+
LINUX_ELF_DYNAMIC_RUNPATH,
|
|
4168
|
+
LINUX_ELF_DYNAMIC_CONFIG,
|
|
4169
|
+
LINUX_ELF_DYNAMIC_DEPAUDIT,
|
|
4170
|
+
LINUX_ELF_DYNAMIC_AUDIT,
|
|
4171
|
+
LINUX_ELF_DYNAMIC_AUXILIARY,
|
|
4172
|
+
LINUX_ELF_DYNAMIC_FILTER,
|
|
4173
|
+
]);
|
|
3868
4174
|
let terminated = false;
|
|
4175
|
+
let flags = null;
|
|
3869
4176
|
let flags1 = null;
|
|
4177
|
+
let stringTableAddress = null;
|
|
4178
|
+
let stringTableBytes = null;
|
|
3870
4179
|
for (
|
|
3871
4180
|
let offset = 0;
|
|
3872
4181
|
offset < dynamicTable.length;
|
|
@@ -3878,21 +4187,113 @@ function inspectLinuxStaticNativeElf(runtime, fd, identity) {
|
|
|
3878
4187
|
terminated = true;
|
|
3879
4188
|
break;
|
|
3880
4189
|
}
|
|
3881
|
-
if (
|
|
3882
|
-
|
|
4190
|
+
if (
|
|
4191
|
+
tag === LINUX_ELF_DYNAMIC_TEXTREL ||
|
|
4192
|
+
forbiddenDependencyTags.has(tag)
|
|
4193
|
+
) {
|
|
4194
|
+
throw new Error(`${prefix}_loader_directive_unsupported`);
|
|
3883
4195
|
}
|
|
3884
|
-
if (tag ===
|
|
4196
|
+
if (tag === LINUX_ELF_DYNAMIC_NEEDED) {
|
|
4197
|
+
neededOffsets.push(value);
|
|
4198
|
+
if (neededOffsets.length > LINUX_ELF_MAX_NEEDED_ENTRIES) {
|
|
4199
|
+
throw new Error(`${prefix}_dependency_count_exceeded`);
|
|
4200
|
+
}
|
|
4201
|
+
} else if (tag === LINUX_ELF_DYNAMIC_STRTAB) {
|
|
4202
|
+
if (stringTableAddress !== null) {
|
|
4203
|
+
throw new Error(`${prefix}_string_table_ambiguous`);
|
|
4204
|
+
}
|
|
4205
|
+
stringTableAddress = value;
|
|
4206
|
+
} else if (tag === LINUX_ELF_DYNAMIC_STRSZ) {
|
|
4207
|
+
if (stringTableBytes !== null) {
|
|
4208
|
+
throw new Error(`${prefix}_string_table_ambiguous`);
|
|
4209
|
+
}
|
|
4210
|
+
stringTableBytes = value;
|
|
4211
|
+
} else if (tag === LINUX_ELF_DYNAMIC_FLAGS) {
|
|
4212
|
+
if (flags !== null) {
|
|
4213
|
+
throw new Error(`${prefix}_flags_ambiguous`);
|
|
4214
|
+
}
|
|
4215
|
+
flags = value;
|
|
4216
|
+
} else if (tag === LINUX_ELF_DYNAMIC_FLAGS_1) {
|
|
3885
4217
|
if (flags1 !== null) {
|
|
3886
|
-
throw new Error(
|
|
4218
|
+
throw new Error(`${prefix}_flags_ambiguous`);
|
|
3887
4219
|
}
|
|
3888
4220
|
flags1 = value;
|
|
3889
4221
|
}
|
|
3890
4222
|
}
|
|
3891
4223
|
if (!terminated) {
|
|
3892
|
-
throw new Error(
|
|
4224
|
+
throw new Error(`${prefix}_dynamic_table_unterminated`);
|
|
4225
|
+
}
|
|
4226
|
+
if (flags !== null && (flags & LINUX_ELF_DYNAMIC_FLAG_TEXTREL) !== 0n) {
|
|
4227
|
+
throw new Error(`${prefix}_text_relocation_unsupported`);
|
|
4228
|
+
}
|
|
4229
|
+
if (
|
|
4230
|
+
elfType === LINUX_ELF_TYPE_DYN &&
|
|
4231
|
+
(flags1 === null || (flags1 & LINUX_ELF_DYNAMIC_FLAG_PIE) === 0n)
|
|
4232
|
+
) {
|
|
4233
|
+
throw new Error(`${prefix}_flag_missing`);
|
|
3893
4234
|
}
|
|
3894
|
-
if (
|
|
3895
|
-
throw new Error("
|
|
4235
|
+
if (staticPie && neededOffsets.length > 0) {
|
|
4236
|
+
throw new Error("native_entry_static_pie_dependency_unsupported");
|
|
4237
|
+
}
|
|
4238
|
+
|
|
4239
|
+
let needed = [];
|
|
4240
|
+
if (neededOffsets.length > 0) {
|
|
4241
|
+
if (
|
|
4242
|
+
stringTableAddress === null ||
|
|
4243
|
+
stringTableBytes === null ||
|
|
4244
|
+
stringTableBytes < 1n ||
|
|
4245
|
+
stringTableBytes > BigInt(LINUX_ELF_MAX_STRING_TABLE_BYTES)
|
|
4246
|
+
) {
|
|
4247
|
+
throw new Error(`${prefix}_string_table_invalid`);
|
|
4248
|
+
}
|
|
4249
|
+
const stringTableMappings = linuxElfVirtualRangeFileMappings(
|
|
4250
|
+
loadSegments,
|
|
4251
|
+
stringTableAddress,
|
|
4252
|
+
stringTableBytes,
|
|
4253
|
+
);
|
|
4254
|
+
if (stringTableMappings.length === 0) {
|
|
4255
|
+
throw new Error(`${prefix}_string_table_unmapped`);
|
|
4256
|
+
}
|
|
4257
|
+
if (stringTableMappings.length !== 1) {
|
|
4258
|
+
throw new Error(`${prefix}_string_table_mapping_ambiguous`);
|
|
4259
|
+
}
|
|
4260
|
+
const stringTableOffset = stringTableMappings[0].fileOffset;
|
|
4261
|
+
if (stringTableOffset > BigInt(Number.MAX_SAFE_INTEGER)) {
|
|
4262
|
+
throw new Error(`${prefix}_string_table_unmapped`);
|
|
4263
|
+
}
|
|
4264
|
+
const stringTable = readLinuxFdExactly(
|
|
4265
|
+
runtime,
|
|
4266
|
+
fd,
|
|
4267
|
+
Number(stringTableBytes),
|
|
4268
|
+
Number(stringTableOffset),
|
|
4269
|
+
);
|
|
4270
|
+
needed = neededOffsets.map((offset) => {
|
|
4271
|
+
if (offset > BigInt(Number.MAX_SAFE_INTEGER)) {
|
|
4272
|
+
throw new Error(`${prefix}_dependency_string_out_of_bounds`);
|
|
4273
|
+
}
|
|
4274
|
+
const name = readLinuxElfString(
|
|
4275
|
+
stringTable,
|
|
4276
|
+
Number(offset),
|
|
4277
|
+
"dynamic_dependency",
|
|
4278
|
+
);
|
|
4279
|
+
if (
|
|
4280
|
+
!/^[A-Za-z0-9][A-Za-z0-9._+-]{0,254}$/.test(name) ||
|
|
4281
|
+
path.posix.basename(name) !== name
|
|
4282
|
+
) {
|
|
4283
|
+
throw new Error("native_entry_dynamic_dependency_name_invalid");
|
|
4284
|
+
}
|
|
4285
|
+
return name;
|
|
4286
|
+
});
|
|
4287
|
+
if (new Set(needed).size !== needed.length) {
|
|
4288
|
+
throw new Error("native_entry_dynamic_dependency_ambiguous");
|
|
4289
|
+
}
|
|
4290
|
+
}
|
|
4291
|
+
|
|
4292
|
+
if (dynamicExecutable) {
|
|
4293
|
+
dynamicMetadata = Object.freeze({
|
|
4294
|
+
interpreter,
|
|
4295
|
+
needed: Object.freeze(needed),
|
|
4296
|
+
});
|
|
3896
4297
|
}
|
|
3897
4298
|
}
|
|
3898
4299
|
|
|
@@ -3902,17 +4303,23 @@ function inspectLinuxStaticNativeElf(runtime, fd, identity) {
|
|
|
3902
4303
|
throw new Error("native_entry_changed_during_elf_attestation");
|
|
3903
4304
|
}
|
|
3904
4305
|
return Object.freeze({
|
|
3905
|
-
|
|
3906
|
-
|
|
4306
|
+
runtime: dynamicExecutable ? "native-dynamic-elf" : "native-static-elf",
|
|
4307
|
+
format: dynamicExecutable
|
|
4308
|
+
? elfType === LINUX_ELF_TYPE_DYN
|
|
4309
|
+
? "elf64-dynamic-pie-et-dyn"
|
|
4310
|
+
: "elf64-dynamic-et-exec"
|
|
4311
|
+
: elfType === LINUX_ELF_TYPE_DYN
|
|
3907
4312
|
? "elf64-static-pie-shaped-et-dyn"
|
|
3908
4313
|
: "elf64-static-et-exec",
|
|
3909
4314
|
architecture: runtime.arch,
|
|
3910
4315
|
machine: expectedMachine,
|
|
4316
|
+
loaderPageBytes: Number(runtimePageSize),
|
|
3911
4317
|
programHeaders: programHeaderCount,
|
|
4318
|
+
...(dynamicMetadata || {}),
|
|
3912
4319
|
});
|
|
3913
4320
|
}
|
|
3914
4321
|
|
|
3915
|
-
function
|
|
4322
|
+
function inspectLinuxNativePath(runtime, identity) {
|
|
3916
4323
|
let fd;
|
|
3917
4324
|
try {
|
|
3918
4325
|
const constants = runtime.fs.constants || fs.constants;
|
|
@@ -3921,7 +4328,7 @@ function inspectLinuxStaticNativePath(runtime, identity) {
|
|
|
3921
4328
|
Number(constants.O_NOFOLLOW || 0) |
|
|
3922
4329
|
Number(constants.O_NONBLOCK || 0);
|
|
3923
4330
|
fd = runtime.fs.openSync(identity.realPath, flags);
|
|
3924
|
-
return
|
|
4331
|
+
return inspectLinuxNativeElf(runtime, fd, identity);
|
|
3925
4332
|
} finally {
|
|
3926
4333
|
if (fd !== undefined) {
|
|
3927
4334
|
try {
|
|
@@ -4656,6 +5063,87 @@ function pinLinuxRuntimeMounts(runtime, runtimeMounts, runtimeIdentity) {
|
|
|
4656
5063
|
}
|
|
4657
5064
|
}
|
|
4658
5065
|
|
|
5066
|
+
// Bind only the kernel-selected interpreter and the entry ELF's direct
|
|
5067
|
+
// DT_NEEDED names. This deliberately does not claim transitive or dlopen-time
|
|
5068
|
+
// closure; handleAtomic remains false for the wider launch chain.
|
|
5069
|
+
function bindLinuxNativeDynamicRuntime(entryFormat, pinnedRuntimeMounts) {
|
|
5070
|
+
if (entryFormat?.runtime !== "native-dynamic-elf") return null;
|
|
5071
|
+
if (
|
|
5072
|
+
!linuxSystemDynamicPath(entryFormat.interpreter) ||
|
|
5073
|
+
!Array.isArray(entryFormat.needed) ||
|
|
5074
|
+
entryFormat.needed.length > LINUX_ELF_MAX_NEEDED_ENTRIES
|
|
5075
|
+
) {
|
|
5076
|
+
throw new Error("native_dynamic_metadata_invalid");
|
|
5077
|
+
}
|
|
5078
|
+
const systemMounts = (pinnedRuntimeMounts || []).filter(
|
|
5079
|
+
(mount) =>
|
|
5080
|
+
linuxSystemDynamicPath(mount?.destination) &&
|
|
5081
|
+
Number.isInteger(mount?.fd) &&
|
|
5082
|
+
typeof mount?.fileId?.dev === "string" &&
|
|
5083
|
+
typeof mount?.fileId?.ino === "string" &&
|
|
5084
|
+
Number.isSafeInteger(mount?.bytes) &&
|
|
5085
|
+
mount.bytes > 0 &&
|
|
5086
|
+
Number.isFinite(mount?.mtimeMs),
|
|
5087
|
+
);
|
|
5088
|
+
const interpreterMount = systemMounts.find(
|
|
5089
|
+
(mount) => mount.destination === entryFormat.interpreter,
|
|
5090
|
+
);
|
|
5091
|
+
if (!interpreterMount) {
|
|
5092
|
+
throw new Error("native_dynamic_interpreter_outside_direct_system_set");
|
|
5093
|
+
}
|
|
5094
|
+
const selected = new Map([[interpreterMount.destination, interpreterMount]]);
|
|
5095
|
+
for (const dependency of entryFormat.needed) {
|
|
5096
|
+
if (
|
|
5097
|
+
typeof dependency !== "string" ||
|
|
5098
|
+
!/^[A-Za-z0-9][A-Za-z0-9._+-]{0,254}$/.test(dependency)
|
|
5099
|
+
) {
|
|
5100
|
+
throw new Error("native_dynamic_dependency_name_invalid");
|
|
5101
|
+
}
|
|
5102
|
+
const matches = systemMounts.filter(
|
|
5103
|
+
(mount) => path.posix.basename(mount.destination) === dependency,
|
|
5104
|
+
);
|
|
5105
|
+
if (matches.length === 0) {
|
|
5106
|
+
throw new Error("native_dynamic_dependency_outside_direct_system_set");
|
|
5107
|
+
}
|
|
5108
|
+
if (matches.length !== 1) {
|
|
5109
|
+
throw new Error("native_dynamic_dependency_runtime_ambiguous");
|
|
5110
|
+
}
|
|
5111
|
+
selected.set(matches[0].destination, matches[0]);
|
|
5112
|
+
}
|
|
5113
|
+
const members = [...selected.values()]
|
|
5114
|
+
.map((mount) => ({
|
|
5115
|
+
destination: mount.destination,
|
|
5116
|
+
fileId: {
|
|
5117
|
+
dev: mount.fileId.dev,
|
|
5118
|
+
ino: mount.fileId.ino,
|
|
5119
|
+
},
|
|
5120
|
+
bytes: mount.bytes,
|
|
5121
|
+
mtimeMs: mount.mtimeMs,
|
|
5122
|
+
}))
|
|
5123
|
+
.sort((left, right) => left.destination.localeCompare(right.destination));
|
|
5124
|
+
const digest = crypto
|
|
5125
|
+
.createHash("sha256")
|
|
5126
|
+
.update(
|
|
5127
|
+
JSON.stringify({
|
|
5128
|
+
version: 1,
|
|
5129
|
+
scope: LINUX_NATIVE_DYNAMIC_DIRECT_SYSTEM_SET_SCOPE,
|
|
5130
|
+
mechanism: LINUX_NATIVE_DYNAMIC_DIRECT_SYSTEM_SET_MECHANISM,
|
|
5131
|
+
interpreter: entryFormat.interpreter,
|
|
5132
|
+
needed: [...entryFormat.needed].sort(),
|
|
5133
|
+
members,
|
|
5134
|
+
}),
|
|
5135
|
+
)
|
|
5136
|
+
.digest("hex");
|
|
5137
|
+
return Object.freeze({
|
|
5138
|
+
scope: LINUX_NATIVE_DYNAMIC_DIRECT_SYSTEM_SET_SCOPE,
|
|
5139
|
+
mechanism: LINUX_NATIVE_DYNAMIC_DIRECT_SYSTEM_SET_MECHANISM,
|
|
5140
|
+
interpreter: entryFormat.interpreter,
|
|
5141
|
+
dependencies: entryFormat.needed.length,
|
|
5142
|
+
files: members.length,
|
|
5143
|
+
digest,
|
|
5144
|
+
});
|
|
5145
|
+
}
|
|
5146
|
+
|
|
4659
5147
|
function linuxSandboxEnvironment() {
|
|
4660
5148
|
return {
|
|
4661
5149
|
HOME: "/home/sandbox",
|
|
@@ -4932,11 +5420,22 @@ export function applyLinuxSandbox(
|
|
|
4932
5420
|
);
|
|
4933
5421
|
|
|
4934
5422
|
if (requiresStrongLinuxBoundary) {
|
|
5423
|
+
if (isLinuxGenericWorkspaceContract(sandboxOpts.executionContract)) {
|
|
5424
|
+
return applyLinuxGenericWorkspaceSandbox(
|
|
5425
|
+
command,
|
|
5426
|
+
args,
|
|
5427
|
+
spawnOpts,
|
|
5428
|
+
sandboxOpts,
|
|
5429
|
+
runtime,
|
|
5430
|
+
);
|
|
5431
|
+
}
|
|
4935
5432
|
const requestedEntryRuntime =
|
|
4936
5433
|
sandboxOpts.executionContract?.kind ===
|
|
4937
5434
|
"strict-plugin-native-static-elf-bin"
|
|
4938
5435
|
? "native-static-elf"
|
|
4939
|
-
: "
|
|
5436
|
+
: sandboxOpts.executionContract?.kind === "strict-plugin-native-elf-bin"
|
|
5437
|
+
? "native-unclassified"
|
|
5438
|
+
: "node";
|
|
4940
5439
|
const validation = validateLinuxPluginContract(
|
|
4941
5440
|
command,
|
|
4942
5441
|
args,
|
|
@@ -5009,6 +5508,29 @@ export function applyLinuxSandbox(
|
|
|
5009
5508
|
guarantees: [],
|
|
5010
5509
|
});
|
|
5011
5510
|
}
|
|
5511
|
+
let nativeDynamicClosure = null;
|
|
5512
|
+
try {
|
|
5513
|
+
nativeDynamicClosure = bindLinuxNativeDynamicRuntime(
|
|
5514
|
+
validation.entryFormat,
|
|
5515
|
+
pinnedRuntimeMounts,
|
|
5516
|
+
);
|
|
5517
|
+
} catch (error) {
|
|
5518
|
+
closeLinuxPinnedMounts(runtime, pinnedRuntimeMounts);
|
|
5519
|
+
return createSandboxPlan({
|
|
5520
|
+
...base,
|
|
5521
|
+
backend: null,
|
|
5522
|
+
candidateBackend: LINUX_BWRAP_BACKEND,
|
|
5523
|
+
policyAttested: false,
|
|
5524
|
+
runtimeProbe: linuxBubblewrapProbe(
|
|
5525
|
+
false,
|
|
5526
|
+
false,
|
|
5527
|
+
error.message || "native_dynamic_direct_system_set_unattested",
|
|
5528
|
+
validation.entryRuntime,
|
|
5529
|
+
),
|
|
5530
|
+
reason: "linux_bwrap_native_runtime_unattested",
|
|
5531
|
+
guarantees: [],
|
|
5532
|
+
});
|
|
5533
|
+
}
|
|
5012
5534
|
|
|
5013
5535
|
let pinnedMounts = [];
|
|
5014
5536
|
let pluginTree;
|
|
@@ -5046,8 +5568,8 @@ export function applyLinuxSandbox(
|
|
|
5046
5568
|
) {
|
|
5047
5569
|
throw new Error("plugin_entry_pin_mismatch");
|
|
5048
5570
|
}
|
|
5049
|
-
if (validation.entryRuntime
|
|
5050
|
-
entryFormat =
|
|
5571
|
+
if (validation.entryRuntime.startsWith("native-")) {
|
|
5572
|
+
entryFormat = inspectLinuxNativeElf(
|
|
5051
5573
|
runtime,
|
|
5052
5574
|
entryMount.fd,
|
|
5053
5575
|
validation.contract.entryIdentity,
|
|
@@ -5325,10 +5847,9 @@ export function applyLinuxSandbox(
|
|
|
5325
5847
|
environment,
|
|
5326
5848
|
seccompFilter,
|
|
5327
5849
|
);
|
|
5328
|
-
const targetArgs =
|
|
5329
|
-
|
|
5330
|
-
|
|
5331
|
-
: ["/opt/chainless/runtime/node", sandboxEntry, ...args.slice(1)];
|
|
5850
|
+
const targetArgs = validation.entryRuntime.startsWith("native-")
|
|
5851
|
+
? [sandboxEntry, ...args]
|
|
5852
|
+
: ["/opt/chainless/runtime/node", sandboxEntry, ...args.slice(1)];
|
|
5332
5853
|
const snapshotPolicyBinding = entrySnapshot
|
|
5333
5854
|
? {
|
|
5334
5855
|
scope: entrySnapshot.attestation.scope,
|
|
@@ -5389,6 +5910,9 @@ export function applyLinuxSandbox(
|
|
|
5389
5910
|
},
|
|
5390
5911
|
),
|
|
5391
5912
|
contentSnapshot: snapshotPolicyBinding,
|
|
5913
|
+
...(nativeDynamicClosure
|
|
5914
|
+
? { initialDynamicLoadClosure: nativeDynamicClosure }
|
|
5915
|
+
: {}),
|
|
5392
5916
|
...(validation.entryRuntime === "node"
|
|
5393
5917
|
? { pluginTreeContentSnapshot: pluginTreeSnapshot }
|
|
5394
5918
|
: {}),
|
|
@@ -5398,10 +5922,9 @@ export function applyLinuxSandbox(
|
|
|
5398
5922
|
sha256: seccompFilter.sha256,
|
|
5399
5923
|
},
|
|
5400
5924
|
policyArgs,
|
|
5401
|
-
target:
|
|
5402
|
-
|
|
5403
|
-
|
|
5404
|
-
: targetArgs.slice(0, 2),
|
|
5925
|
+
target: validation.entryRuntime.startsWith("native-")
|
|
5926
|
+
? targetArgs.slice(0, 1)
|
|
5927
|
+
: targetArgs.slice(0, 2),
|
|
5405
5928
|
}),
|
|
5406
5929
|
)
|
|
5407
5930
|
.digest("hex");
|
|
@@ -5556,6 +6079,7 @@ export function applyLinuxSandbox(
|
|
|
5556
6079
|
entrySnapshot?.attestation,
|
|
5557
6080
|
supervisorBinding,
|
|
5558
6081
|
pluginTreeSnapshot,
|
|
6082
|
+
nativeDynamicClosure,
|
|
5559
6083
|
),
|
|
5560
6084
|
);
|
|
5561
6085
|
const options = {
|