@dharma-ai-labs/agent-fabric 0.2.135 → 0.2.136
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/README.md +13 -2
- package/dist/containerDockerInit.test.d.ts +2 -0
- package/dist/containerDockerInit.test.d.ts.map +1 -0
- package/dist/containerDockerInit.test.js +187 -0
- package/dist/containerDockerInit.test.js.map +1 -0
- package/dist/containerRelayLifecycle.d.ts +9 -0
- package/dist/containerRelayLifecycle.d.ts.map +1 -1
- package/dist/containerRelayLifecycle.js +151 -32
- package/dist/containerRelayLifecycle.js.map +1 -1
- package/dist/containerRelayPublicCommand.test.js +3 -0
- package/dist/containerRelayPublicCommand.test.js.map +1 -1
- package/dist/containerRelaySchema.test.js +9 -0
- package/dist/containerRelaySchema.test.js.map +1 -1
- package/dist/index.js +4 -4
- package/dist/index.js.map +1 -1
- package/dist/schemas/container-relay-lifecycle.v1.schema.json +39 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -37,7 +37,18 @@ command accepts no grant, policy, provider or task arguments. Inspect the
|
|
|
37
37
|
credential-free plan with `relay container-entrypoint --dry-run` before image
|
|
38
38
|
installation; it makes no local changes. Set an explicit
|
|
39
39
|
private `DHARMA_HOME` before launch. An npm wrapper, shell that does not exec,
|
|
40
|
-
`sleep` or init shim as PID1 does not qualify.
|
|
40
|
+
`sleep` or an arbitrary init shim as PID1 does not qualify. A narrowly verified
|
|
41
|
+
Docker `--init` route also supports the canonical CLI as the non-root direct
|
|
42
|
+
child of Docker's root-owned, non-writable `/sbin/docker-init` executable. This
|
|
43
|
+
route retains the existing official Node-image command
|
|
44
|
+
`docker-entrypoint.sh sleep infinity`; an explicitly approved public entrypoint
|
|
45
|
+
migration must exec the canonical Node/CLI command as that init's main child.
|
|
46
|
+
The CLI checks the executable inode, UID, both process start times and the
|
|
47
|
+
kernel's first init-child identity, retaining zombies rather than promoting
|
|
48
|
+
adopted processes. The controller must also retain init's session and its own
|
|
49
|
+
process group. The main-child and process identities are checked again before
|
|
50
|
+
control is admitted; a foreground or orphaned `docker exec` or a fabricated
|
|
51
|
+
marker cannot claim startup.
|
|
41
52
|
|
|
42
53
|
The image/operator must provide its own protected Secret Service, private
|
|
43
54
|
session bus and durable private home. Never mount a host bus or copy another
|
|
@@ -52,7 +63,7 @@ The entrypoint owns one relay for that container OS user. It never creates a
|
|
|
52
63
|
second host service or changes an existing systemd user unit. Owned start/stop
|
|
53
64
|
controls use atomic private receipts; disable removes the registration. It
|
|
54
65
|
reaps its child on normal shutdown and retries an exited child with a bounded
|
|
55
|
-
delay. A new container boot renews only its own
|
|
66
|
+
delay. A new container boot renews only its own entrypoint lease while retaining its
|
|
56
67
|
configuration and encrypted state. Runtime-version mismatch blocks restart;
|
|
57
68
|
upgrade the reviewed image/runtime together through the normal release path.
|
|
58
69
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"containerDockerInit.test.d.ts","sourceRoot":"","sources":["../src/containerDockerInit.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import { spawn } from 'node:child_process';
|
|
3
|
+
import { mkdtemp, mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
4
|
+
import { tmpdir } from 'node:os';
|
|
5
|
+
import { join } from 'node:path';
|
|
6
|
+
import test from 'node:test';
|
|
7
|
+
import * as lifecycle from './containerRelayLifecycle.js';
|
|
8
|
+
import { enableRelayAutostart, relayAutostartStatus } from './relayAutostart.js';
|
|
9
|
+
const linux = { skip: process.platform !== 'linux' };
|
|
10
|
+
async function fixture() {
|
|
11
|
+
const root = await mkdtemp(join(tmpdir(), 'dharma-docker-init-'));
|
|
12
|
+
const home = join(root, 'device');
|
|
13
|
+
const workspace = join(root, 'checkout');
|
|
14
|
+
await mkdir(join(home, 'relay'), { recursive: true, mode: 0o700 });
|
|
15
|
+
await mkdir(join(workspace, '.dharma'), { recursive: true, mode: 0o700 });
|
|
16
|
+
const uid = process.getuid();
|
|
17
|
+
const init = { pid: 1, parentPid: 0, processGroupId: 1, sessionId: 1, uid, startTicks: '123', argv: ['/sbin/docker-init', '--', 'docker-entrypoint.sh', 'sleep', 'infinity'] };
|
|
18
|
+
const controller = { pid: 42, parentPid: 1, processGroupId: 42, sessionId: 1, uid, startTicks: '124',
|
|
19
|
+
argv: ['/usr/local/bin/node', '/fixture/cli/dist/bin.js', 'relay', 'container-entrypoint'] };
|
|
20
|
+
const marker = { schema: 'dharma.container-entrypoint/v2', home, pid: controller.pid, uid,
|
|
21
|
+
startTicks: controller.startTicks, initStartTicks: init.startTicks };
|
|
22
|
+
await writeFile(join(home, 'relay', 'container-entrypoint.json'), JSON.stringify(marker), { mode: 0o600 });
|
|
23
|
+
let verifiedInit = true;
|
|
24
|
+
let verifiedNode = true;
|
|
25
|
+
let mainChild = controller.pid;
|
|
26
|
+
const runtime = { identity: async () => init, canonicalEntrypoint: controller.argv[1], runtimeVersion: '0.2.135',
|
|
27
|
+
controllerIdentity: async (pid) => { assert.equal(pid, controller.pid); return controller; },
|
|
28
|
+
dockerInitVerified: async () => verifiedInit,
|
|
29
|
+
dockerInitMainChild: async () => mainChild,
|
|
30
|
+
controllerExecutableVerified: async () => verifiedNode,
|
|
31
|
+
childIdentity: async (pid) => ({ ...await lifecycle.readContainerChildIdentity(pid), parentPid: controller.pid }) };
|
|
32
|
+
const options = { platform: 'linux', home, uid, userHome: root, workspace,
|
|
33
|
+
launcher: join(workspace, '.dharma', 'bin', 'dharma'), policy: join(workspace, '.dharma', 'approved-policy.json'),
|
|
34
|
+
version: '0.2.135', containerRuntime: runtime,
|
|
35
|
+
run: async () => { throw new Error('must never use systemd for the owned init child'); } };
|
|
36
|
+
return { root, home, init, controller, marker, runtime, options,
|
|
37
|
+
untrustInit: () => { verifiedInit = false; }, untrustNode: () => { verifiedNode = false; },
|
|
38
|
+
setMainChild: (pid) => { mainChild = pid; } };
|
|
39
|
+
}
|
|
40
|
+
async function until(check) {
|
|
41
|
+
const deadline = Date.now() + 3000;
|
|
42
|
+
while (!check()) {
|
|
43
|
+
if (Date.now() > deadline)
|
|
44
|
+
throw new Error('fixture did not progress');
|
|
45
|
+
await new Promise(r => setTimeout(r, 10));
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
test('canonical direct child of verified Docker init can own persistent container startup', linux, async () => {
|
|
49
|
+
const f = await fixture();
|
|
50
|
+
assert.equal((await enableRelayAutostart(f.options)).backend, 'container-entrypoint');
|
|
51
|
+
assert.equal((await relayAutostartStatus(f.options)).state, 'enabled');
|
|
52
|
+
});
|
|
53
|
+
test('adopted canonical exec child cannot replace the Docker init main startup child', linux, async () => {
|
|
54
|
+
for (const kind of ['different-main-child', 'foreign-session', 'foreign-process-group', 'missing-main-child']) {
|
|
55
|
+
const f = await fixture();
|
|
56
|
+
if (kind === 'different-main-child')
|
|
57
|
+
f.setMainChild(7);
|
|
58
|
+
if (kind === 'missing-main-child')
|
|
59
|
+
f.setMainChild(0);
|
|
60
|
+
if (kind === 'foreign-session')
|
|
61
|
+
f.controller.sessionId = 99;
|
|
62
|
+
if (kind === 'foreign-process-group')
|
|
63
|
+
f.controller.processGroupId = 99;
|
|
64
|
+
await assert.rejects(enableRelayAutostart(f.options), /container_startup_unavailable/, kind);
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
test('Docker init main-child identity is checked again before control is admitted', linux, async () => {
|
|
68
|
+
const f = await fixture();
|
|
69
|
+
let reads = 0;
|
|
70
|
+
f.runtime.dockerInitMainChild = async () => ++reads === 1 ? f.controller.pid : 7;
|
|
71
|
+
await assert.rejects(enableRelayAutostart(f.options), /container_startup_unavailable/);
|
|
72
|
+
});
|
|
73
|
+
test('Docker init session and controller process group cannot change during attribution', linux, async () => {
|
|
74
|
+
for (const kind of ['init-session', 'init-group', 'controller-session', 'controller-group']) {
|
|
75
|
+
const f = await fixture();
|
|
76
|
+
let reads = 0;
|
|
77
|
+
if (kind.startsWith('init-'))
|
|
78
|
+
f.runtime.identity = async () => {
|
|
79
|
+
reads++;
|
|
80
|
+
return { ...f.init, ...(reads > 1 ? kind === 'init-session' ? { sessionId: 99 } : { processGroupId: 99 } : {}) };
|
|
81
|
+
};
|
|
82
|
+
else
|
|
83
|
+
f.runtime.controllerIdentity = async () => {
|
|
84
|
+
reads++;
|
|
85
|
+
return { ...f.controller, ...(reads > 1 ? kind === 'controller-session' ? { sessionId: 99 } : { processGroupId: 99 } : {}) };
|
|
86
|
+
};
|
|
87
|
+
await assert.rejects(enableRelayAutostart(f.options), /container_startup_unavailable/, kind);
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
test('Docker init route rejects foreign parent owner argv executable boot and controller ticks', linux, async () => {
|
|
91
|
+
for (const kind of ['parent', 'uid', 'argv', 'executable', 'node-executable', 'init-parent', 'init-argv', 'init-boot', 'controller-boot', 'extra-argument']) {
|
|
92
|
+
const f = await fixture();
|
|
93
|
+
if (kind === 'parent')
|
|
94
|
+
f.controller.parentPid = 9;
|
|
95
|
+
if (kind === 'uid')
|
|
96
|
+
f.controller.uid++;
|
|
97
|
+
if (kind === 'argv')
|
|
98
|
+
f.controller.argv[1] = '/foreign/cli/dist/bin.js';
|
|
99
|
+
if (kind === 'executable')
|
|
100
|
+
f.untrustInit();
|
|
101
|
+
if (kind === 'node-executable')
|
|
102
|
+
f.untrustNode();
|
|
103
|
+
if (kind === 'init-parent')
|
|
104
|
+
f.init.parentPid = 3;
|
|
105
|
+
if (kind === 'init-argv')
|
|
106
|
+
f.init.argv[3] = 'foreign-command';
|
|
107
|
+
if (kind === 'init-boot')
|
|
108
|
+
f.init.startTicks = '999';
|
|
109
|
+
if (kind === 'controller-boot')
|
|
110
|
+
f.controller.startTicks = '999';
|
|
111
|
+
if (kind === 'extra-argument')
|
|
112
|
+
f.controller.argv.push('--grant');
|
|
113
|
+
await assert.rejects(enableRelayAutostart(f.options), /container_startup_unavailable/, kind);
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
test('init marker cannot omit the Docker boot identity or promote an ordinary exec child to the entrypoint', linux, async () => {
|
|
117
|
+
const f = await fixture();
|
|
118
|
+
await writeFile(join(f.home, 'relay', 'container-entrypoint.json'), JSON.stringify({ ...f.marker, initStartTicks: undefined }));
|
|
119
|
+
await assert.rejects(enableRelayAutostart(f.options), /container_startup_unavailable/);
|
|
120
|
+
});
|
|
121
|
+
test('controller identity changes during executable verification are rejected before startup control', linux, async () => {
|
|
122
|
+
const f = await fixture();
|
|
123
|
+
let reads = 0;
|
|
124
|
+
f.runtime.controllerIdentity = async (pid) => {
|
|
125
|
+
assert.equal(pid, f.controller.pid);
|
|
126
|
+
reads++;
|
|
127
|
+
return { ...f.controller, startTicks: reads > 1 ? 'CANARY_REUSED_PROCESS' : f.controller.startTicks };
|
|
128
|
+
};
|
|
129
|
+
await assert.rejects(enableRelayAutostart(f.options), error => {
|
|
130
|
+
assert.match(String(error), /container_startup_unavailable/);
|
|
131
|
+
assert.doesNotMatch(String(error), /CANARY_REUSED_PROCESS/);
|
|
132
|
+
return true;
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
test('same Docker-init boot cannot take over another controller lease', linux, async () => {
|
|
136
|
+
const f = await fixture();
|
|
137
|
+
await writeFile(join(f.home, 'relay', 'container-entrypoint.lock'), JSON.stringify({ ...f.marker, pid: 77, startTicks: '99' }), { mode: 0o600 });
|
|
138
|
+
const abort = new AbortController();
|
|
139
|
+
await assert.rejects(lifecycle.runOwnedContainerEntrypoint({ home: f.home, uid: f.options.uid, signal: abort.signal,
|
|
140
|
+
containerRuntime: { ...f.runtime, currentControllerPid: f.controller.pid } }), /container_entrypoint_busy/);
|
|
141
|
+
});
|
|
142
|
+
test('different verified Docker-init boot renews only its own previous lifecycle metadata', linux, async () => {
|
|
143
|
+
const f = await fixture();
|
|
144
|
+
await writeFile(join(f.home, 'relay', 'container-entrypoint.lock'), JSON.stringify(f.marker), { mode: 0o600 });
|
|
145
|
+
f.init.startTicks = '223';
|
|
146
|
+
f.controller.startTicks = '224';
|
|
147
|
+
const abort = new AbortController();
|
|
148
|
+
const result = lifecycle.runOwnedContainerEntrypoint({ home: f.home, uid: f.options.uid, signal: abort.signal,
|
|
149
|
+
containerRuntime: { ...f.runtime, currentControllerPid: f.controller.pid }, pollMs: 10,
|
|
150
|
+
spawnRelay: () => { throw new Error('unconfigured controller cannot launch'); } });
|
|
151
|
+
try {
|
|
152
|
+
await new Promise(resolve => setTimeout(resolve, 50));
|
|
153
|
+
const marker = JSON.parse(await readFile(join(f.home, 'relay', 'container-entrypoint.json'), 'utf8'));
|
|
154
|
+
assert.equal(marker.initStartTicks, '223');
|
|
155
|
+
assert.equal(marker.startTicks, '224');
|
|
156
|
+
}
|
|
157
|
+
finally {
|
|
158
|
+
abort.abort();
|
|
159
|
+
}
|
|
160
|
+
await result;
|
|
161
|
+
});
|
|
162
|
+
test('Docker init controller fences its own supervisor and remains blocked while the consumer is locked', linux, async () => {
|
|
163
|
+
const f = await fixture();
|
|
164
|
+
await enableRelayAutostart(f.options);
|
|
165
|
+
const abort = new AbortController();
|
|
166
|
+
let ready = false;
|
|
167
|
+
const children = [];
|
|
168
|
+
const result = lifecycle.runOwnedContainerEntrypoint({ home: f.home, uid: f.options.uid, signal: abort.signal,
|
|
169
|
+
containerRuntime: { ...f.runtime, currentControllerPid: f.controller.pid }, pollMs: 10,
|
|
170
|
+
consumerStoreReady: async () => ready,
|
|
171
|
+
spawnRelay: () => { const child = spawn(process.execPath, ['-e', 'setInterval(() => {}, 1000)'], { stdio: 'ignore' }); children.push(child); return child; } });
|
|
172
|
+
try {
|
|
173
|
+
await new Promise(resolve => setTimeout(resolve, 50));
|
|
174
|
+
const heartbeat = JSON.parse(await readFile(join(f.home, 'relay', 'container-heartbeat.json'), 'utf8'));
|
|
175
|
+
assert.equal(heartbeat.lifecycle, 'blocked');
|
|
176
|
+
assert.equal(children.length, 0);
|
|
177
|
+
ready = true;
|
|
178
|
+
await until(() => children.length === 1);
|
|
179
|
+
assert.equal((await relayAutostartStatus(f.options)).lifecycle, 'running');
|
|
180
|
+
}
|
|
181
|
+
finally {
|
|
182
|
+
abort.abort();
|
|
183
|
+
}
|
|
184
|
+
await result;
|
|
185
|
+
assert.equal(children.every(child => child.exitCode !== null || child.signalCode !== null), true);
|
|
186
|
+
});
|
|
187
|
+
//# sourceMappingURL=containerDockerInit.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"containerDockerInit.test.js","sourceRoot":"","sources":["../src/containerDockerInit.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,6 +4,9 @@ export interface ContainerProcessIdentity {
|
|
|
4
4
|
uid: number;
|
|
5
5
|
startTicks: string;
|
|
6
6
|
argv: string[];
|
|
7
|
+
parentPid?: number;
|
|
8
|
+
processGroupId?: number;
|
|
9
|
+
sessionId?: number;
|
|
7
10
|
}
|
|
8
11
|
export interface ContainerChildIdentity {
|
|
9
12
|
pid: number;
|
|
@@ -16,6 +19,11 @@ export interface ContainerRuntime {
|
|
|
16
19
|
childIdentity?: (pid: number) => Promise<ContainerChildIdentity>;
|
|
17
20
|
canonicalEntrypoint?: string;
|
|
18
21
|
runtimeVersion?: string;
|
|
22
|
+
controllerIdentity?: (pid: number) => Promise<ContainerProcessIdentity>;
|
|
23
|
+
dockerInitVerified?: () => Promise<boolean>;
|
|
24
|
+
dockerInitMainChild?: () => Promise<number>;
|
|
25
|
+
controllerExecutableVerified?: (identity: ContainerProcessIdentity) => Promise<boolean>;
|
|
26
|
+
currentControllerPid?: number;
|
|
19
27
|
}
|
|
20
28
|
export interface ContainerLifecycleOptions {
|
|
21
29
|
home: string;
|
|
@@ -32,6 +40,7 @@ export interface ContainerRelayRegistration {
|
|
|
32
40
|
taskName: null;
|
|
33
41
|
}
|
|
34
42
|
export declare function readContainerPid1Identity(): Promise<ContainerProcessIdentity>;
|
|
43
|
+
export declare function readContainerProcessIdentity(pid: number): Promise<ContainerProcessIdentity>;
|
|
35
44
|
export declare function readContainerChildIdentity(pid: number): Promise<ContainerChildIdentity>;
|
|
36
45
|
export declare function containerEntrypointAvailable(options: ContainerLifecycleOptions): Promise<boolean>;
|
|
37
46
|
export declare function containerStartupControl(options: ContainerLifecycleOptions, registration: ContainerRelayRegistration, running: boolean): Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"containerRelayLifecycle.d.ts","sourceRoot":"","sources":["../src/containerRelayLifecycle.ts"],"names":[],"mappings":"AACA,OAAO,EAAmB,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAOxE,MAAM,WAAW,wBAAwB;IAAG,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE;
|
|
1
|
+
{"version":3,"file":"containerRelayLifecycle.d.ts","sourceRoot":"","sources":["../src/containerRelayLifecycle.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createHash, randomUUID } from 'node:crypto';
|
|
2
2
|
import { execFile, spawn } from 'node:child_process';
|
|
3
3
|
import { constants } from 'node:fs';
|
|
4
|
-
import { lstat, mkdir, open, readFile, realpath, rename, rm, writeFile } from 'node:fs/promises';
|
|
4
|
+
import { lstat, mkdir, open, readFile, realpath, rename, rm, stat, writeFile } from 'node:fs/promises';
|
|
5
5
|
import { dirname, isAbsolute, join, resolve } from 'node:path';
|
|
6
6
|
import { promisify } from 'node:util';
|
|
7
7
|
import { fileURLToPath } from 'node:url';
|
|
@@ -50,15 +50,78 @@ function exactObject(value, keys) {
|
|
|
50
50
|
&& Object.keys(value).length === keys.length && keys.every(key => Object.hasOwn(value, key)));
|
|
51
51
|
}
|
|
52
52
|
export async function readContainerPid1Identity() {
|
|
53
|
+
return readContainerProcessIdentity(1);
|
|
54
|
+
}
|
|
55
|
+
export async function readContainerProcessIdentity(pid) {
|
|
56
|
+
if (!Number.isSafeInteger(pid) || pid < 1)
|
|
57
|
+
throw unavailable();
|
|
53
58
|
const [stat, command, owner] = await Promise.all([
|
|
54
|
-
readFile(
|
|
59
|
+
readFile(`/proc/${pid}/stat`, 'utf8'), readFile(`/proc/${pid}/cmdline`), lstat(`/proc/${pid}`),
|
|
55
60
|
]);
|
|
56
|
-
if (stat.length > 8192 || command.length > 8192)
|
|
61
|
+
if (stat.length > 8192 || command.length > 8192 || Number(stat.slice(0, stat.indexOf(' '))) !== pid)
|
|
57
62
|
throw unavailable();
|
|
58
63
|
const fields = stat.slice(stat.lastIndexOf(')') + 2).trim().split(/\s+/);
|
|
59
|
-
|
|
64
|
+
if (fields[0] === 'Z' || fields[0] === 'X')
|
|
65
|
+
throw unavailable();
|
|
66
|
+
return { pid, uid: owner.uid, parentPid: Number(fields[1]), processGroupId: Number(fields[2]), sessionId: Number(fields[3]), startTicks: fields[19] || '',
|
|
60
67
|
argv: command.toString('utf8').split('\0').filter(Boolean) };
|
|
61
68
|
}
|
|
69
|
+
async function dockerInitMainChild() {
|
|
70
|
+
// Tini forks its main child first. Linux appends subsequently forked and
|
|
71
|
+
// adopted children to this kernel list; PPID 1 alone also admits orphans.
|
|
72
|
+
// Retain the first entry even if it is a zombie: never promote an adoptee.
|
|
73
|
+
const file = await open('/proc/1/task/1/children', constants.O_RDONLY);
|
|
74
|
+
try {
|
|
75
|
+
const bytes = Buffer.alloc(4097);
|
|
76
|
+
const { bytesRead } = await file.read(bytes, 0, bytes.length, 0);
|
|
77
|
+
if (bytesRead === 0 || bytesRead > 4096)
|
|
78
|
+
throw unavailable();
|
|
79
|
+
const text = bytes.subarray(0, bytesRead).toString('ascii').trim();
|
|
80
|
+
if (!/^[1-9]\d*(?:\s+[1-9]\d*)*$/.test(text))
|
|
81
|
+
throw unavailable();
|
|
82
|
+
const children = text.split(/\s+/).map(Number);
|
|
83
|
+
if (children.length > 256 || children.some(pid => !Number.isSafeInteger(pid) || pid <= 1)
|
|
84
|
+
|| new Set(children).size !== children.length)
|
|
85
|
+
throw unavailable();
|
|
86
|
+
return children[0];
|
|
87
|
+
}
|
|
88
|
+
finally {
|
|
89
|
+
await file.close();
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
async function verifiedDockerInit() {
|
|
93
|
+
// Docker's --init executable is supplied by the daemon, root-owned and not
|
|
94
|
+
// writable by the client UID. Names or argv alone cannot establish this.
|
|
95
|
+
try {
|
|
96
|
+
const canonical = await realpath('/sbin/docker-init');
|
|
97
|
+
if (canonical !== '/usr/sbin/docker-init' && canonical !== '/sbin/docker-init')
|
|
98
|
+
return false;
|
|
99
|
+
if (await realpath('/proc/1/exe') !== canonical)
|
|
100
|
+
return false;
|
|
101
|
+
const [file, running] = await Promise.all([lstat(canonical), stat('/proc/1/exe')]);
|
|
102
|
+
return file.isFile() && file.uid === 0 && (file.mode & 0o022) === 0
|
|
103
|
+
&& file.dev === running.dev && file.ino === running.ino;
|
|
104
|
+
}
|
|
105
|
+
catch {
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
async function verifiedControllerExecutable(identity) {
|
|
110
|
+
try {
|
|
111
|
+
const candidate = identity.argv[0];
|
|
112
|
+
if (!candidate || !isAbsolute(candidate))
|
|
113
|
+
return false;
|
|
114
|
+
const canonical = await realpath(candidate);
|
|
115
|
+
if (await realpath(`/proc/${identity.pid}/exe`) !== canonical)
|
|
116
|
+
return false;
|
|
117
|
+
const [file, running] = await Promise.all([lstat(canonical), stat(`/proc/${identity.pid}/exe`)]);
|
|
118
|
+
return file.isFile() && file.uid === 0 && (file.mode & 0o022) === 0
|
|
119
|
+
&& file.dev === running.dev && file.ino === running.ino;
|
|
120
|
+
}
|
|
121
|
+
catch {
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
62
125
|
async function publicRuntimeBytes(path, limit, executingCaller = false) {
|
|
63
126
|
const file = await open(path, constants.O_RDONLY | constants.O_NOFOLLOW | constants.O_NONBLOCK);
|
|
64
127
|
try {
|
|
@@ -103,10 +166,67 @@ async function canonicalEntrypoint(options, identity) {
|
|
|
103
166
|
}
|
|
104
167
|
}
|
|
105
168
|
function ownedIdentity(identity, uid, entrypoint) {
|
|
106
|
-
return identity.pid
|
|
169
|
+
return Number.isSafeInteger(identity.pid) && identity.pid >= 1 && identity.uid === uid && Number.isSafeInteger(uid) && uid > 0 && /^\d{1,20}$/.test(identity.startTicks)
|
|
107
170
|
&& identity.argv.length === 4 && identity.argv[2] === 'relay' && identity.argv[3] === 'container-entrypoint'
|
|
108
171
|
&& identity.argv[1] === entrypoint && isAbsolute(entrypoint);
|
|
109
172
|
}
|
|
173
|
+
function validMarker(value) {
|
|
174
|
+
const init = Boolean(value && typeof value === 'object' && value.schema === 'dharma.container-entrypoint/v2');
|
|
175
|
+
return exactObject(value, ['schema', 'home', 'pid', 'uid', 'startTicks', ...(init ? ['initStartTicks'] : [])])
|
|
176
|
+
&& (init ? value.schema === 'dharma.container-entrypoint/v2' && Number.isSafeInteger(value.pid) && Number(value.pid) > 1
|
|
177
|
+
&& typeof value.initStartTicks === 'string' && /^\d{1,20}$/.test(value.initStartTicks)
|
|
178
|
+
: value.schema === 'dharma.container-entrypoint/v1' && value.pid === 1)
|
|
179
|
+
&& typeof value.home === 'string' && Number.isSafeInteger(value.uid) && Number(value.uid) > 0
|
|
180
|
+
&& typeof value.startTicks === 'string' && /^\d{1,20}$/.test(value.startTicks);
|
|
181
|
+
}
|
|
182
|
+
async function ownedController(options, pid) {
|
|
183
|
+
const init = await (options.containerRuntime?.identity || readContainerPid1Identity)();
|
|
184
|
+
if (init.pid !== 1 || init.uid !== ownUid(options) || !/^\d{1,20}$/.test(init.startTicks))
|
|
185
|
+
throw unavailable();
|
|
186
|
+
if (init.argv[2] === 'relay' && init.argv[3] === 'container-entrypoint') {
|
|
187
|
+
if (pid !== undefined && pid !== 1 || !ownedIdentity(init, ownUid(options), await canonicalEntrypoint(options, init)))
|
|
188
|
+
throw unavailable();
|
|
189
|
+
return { identity: init, initStartTicks: undefined };
|
|
190
|
+
}
|
|
191
|
+
// Bounded migration of the existing official Node-image startup. Neither an
|
|
192
|
+
// arbitrary init/wrapper nor a foreground exec can claim this lifecycle.
|
|
193
|
+
if (init.parentPid !== 0 || init.argv.length !== 5 || init.argv[0] !== '/sbin/docker-init' || init.argv[1] !== '--'
|
|
194
|
+
|| init.argv[2] !== 'docker-entrypoint.sh' || init.argv[3] !== 'sleep' || init.argv[4] !== 'infinity'
|
|
195
|
+
|| !await (options.containerRuntime?.dockerInitVerified || verifiedDockerInit)())
|
|
196
|
+
throw unavailable();
|
|
197
|
+
const controller = await (options.containerRuntime?.controllerIdentity || readContainerProcessIdentity)(pid ?? options.containerRuntime?.currentControllerPid ?? process.pid);
|
|
198
|
+
if (controller.pid <= 1 || controller.parentPid !== 1
|
|
199
|
+
|| !Number.isSafeInteger(init.sessionId) || Number(init.sessionId) <= 0
|
|
200
|
+
|| controller.sessionId !== init.sessionId || controller.processGroupId !== controller.pid
|
|
201
|
+
|| await (options.containerRuntime?.dockerInitMainChild || dockerInitMainChild)() !== controller.pid
|
|
202
|
+
|| !ownedIdentity(controller, ownUid(options), await canonicalEntrypoint(options, controller))
|
|
203
|
+
|| !await (options.containerRuntime?.controllerExecutableVerified || verifiedControllerExecutable)(controller))
|
|
204
|
+
throw unavailable();
|
|
205
|
+
const [freshInit, freshController, freshMainChild] = await Promise.all([
|
|
206
|
+
(options.containerRuntime?.identity || readContainerPid1Identity)(),
|
|
207
|
+
(options.containerRuntime?.controllerIdentity || readContainerProcessIdentity)(controller.pid),
|
|
208
|
+
(options.containerRuntime?.dockerInitMainChild || dockerInitMainChild)(),
|
|
209
|
+
]);
|
|
210
|
+
if (freshInit.pid !== init.pid || freshInit.uid !== init.uid || freshInit.startTicks !== init.startTicks
|
|
211
|
+
|| JSON.stringify(freshInit.argv) !== JSON.stringify(init.argv)
|
|
212
|
+
|| freshInit.sessionId !== init.sessionId || freshInit.processGroupId !== init.processGroupId
|
|
213
|
+
|| freshController.pid !== controller.pid || freshController.uid !== controller.uid
|
|
214
|
+
|| freshController.parentPid !== 1 || freshController.startTicks !== controller.startTicks
|
|
215
|
+
|| freshMainChild !== controller.pid || freshController.sessionId !== init.sessionId
|
|
216
|
+
|| freshController.processGroupId !== controller.pid
|
|
217
|
+
|| JSON.stringify(freshController.argv) !== JSON.stringify(controller.argv))
|
|
218
|
+
throw unavailable();
|
|
219
|
+
return { identity: controller, initStartTicks: init.startTicks };
|
|
220
|
+
}
|
|
221
|
+
async function liveMarker(options) {
|
|
222
|
+
const marker = await privateJson(options, 'container-entrypoint.json');
|
|
223
|
+
if (!validMarker(marker) || marker.home !== options.home || marker.uid !== ownUid(options))
|
|
224
|
+
throw unavailable();
|
|
225
|
+
const live = await ownedController(options, marker.pid);
|
|
226
|
+
if (live.identity.startTicks !== marker.startTicks || live.initStartTicks !== marker.initStartTicks)
|
|
227
|
+
throw unavailable();
|
|
228
|
+
return marker;
|
|
229
|
+
}
|
|
110
230
|
export async function readContainerChildIdentity(pid) {
|
|
111
231
|
if (!Number.isSafeInteger(pid) || pid <= 1)
|
|
112
232
|
throw unavailable();
|
|
@@ -118,9 +238,15 @@ export async function readContainerChildIdentity(pid) {
|
|
|
118
238
|
throw unavailable();
|
|
119
239
|
return { pid, uid: owner.uid, parentPid: Number(fields[1]), startTicks: fields[19] };
|
|
120
240
|
}
|
|
121
|
-
async function ownedChild(options, pid, startTicks) {
|
|
241
|
+
async function ownedChild(options, pid, startTicks, controller) {
|
|
242
|
+
const parent = controller || await liveMarker(options);
|
|
243
|
+
if (controller) {
|
|
244
|
+
const live = await ownedController(options, controller.pid);
|
|
245
|
+
if (live.identity.startTicks !== controller.startTicks || live.initStartTicks !== controller.initStartTicks)
|
|
246
|
+
throw unavailable();
|
|
247
|
+
}
|
|
122
248
|
const identity = await (options.containerRuntime?.childIdentity || readContainerChildIdentity)(pid);
|
|
123
|
-
if (identity.pid !== pid || identity.uid !== ownUid(options) || identity.parentPid !==
|
|
249
|
+
if (identity.pid !== pid || identity.uid !== ownUid(options) || identity.parentPid !== parent.pid
|
|
124
250
|
|| !/^\d{1,20}$/.test(identity.startTicks) || startTicks !== undefined && identity.startTicks !== startTicks)
|
|
125
251
|
throw unavailable();
|
|
126
252
|
return identity;
|
|
@@ -129,13 +255,7 @@ export async function containerEntrypointAvailable(options) {
|
|
|
129
255
|
const value = await privateJson(options, 'container-entrypoint.json');
|
|
130
256
|
if (value === null)
|
|
131
257
|
return false;
|
|
132
|
-
|
|
133
|
-
throw unavailable();
|
|
134
|
-
const identity = await (options.containerRuntime?.identity || readContainerPid1Identity)().catch(() => { throw unavailable(); });
|
|
135
|
-
if (value.schema !== 'dharma.container-entrypoint/v1' || value.home !== options.home
|
|
136
|
-
|| value.pid !== 1 || value.uid !== ownUid(options) || value.startTicks !== identity.startTicks
|
|
137
|
-
|| !ownedIdentity(identity, ownUid(options), await canonicalEntrypoint(options, identity)))
|
|
138
|
-
throw unavailable();
|
|
258
|
+
await liveMarker(options);
|
|
139
259
|
return true;
|
|
140
260
|
}
|
|
141
261
|
function registrationHash(home, registration) {
|
|
@@ -279,11 +399,11 @@ export async function containerConsumerStoreReady() {
|
|
|
279
399
|
return false;
|
|
280
400
|
}
|
|
281
401
|
}
|
|
282
|
-
async function stopOwnedChild(child, options, identity) {
|
|
402
|
+
async function stopOwnedChild(child, options, identity, controller) {
|
|
283
403
|
if (child.exitCode !== null || child.signalCode !== null || !child.pid)
|
|
284
404
|
return;
|
|
285
405
|
// Never signal a recycled PID or a process outside this owned parent/UID.
|
|
286
|
-
if (identity && !await ownedChild(options, child.pid, identity.startTicks).catch(() => null))
|
|
406
|
+
if (identity && !await ownedChild(options, child.pid, identity.startTicks, controller).catch(() => null))
|
|
287
407
|
return;
|
|
288
408
|
// On an initial /proc failure, the freshly spawned ChildProcess handle is
|
|
289
409
|
// still ours. Drain it immediately; never leave unverified work running.
|
|
@@ -298,13 +418,14 @@ async function stopOwnedChild(child, options, identity) {
|
|
|
298
418
|
if (timer)
|
|
299
419
|
clearTimeout(timer);
|
|
300
420
|
if (child.exitCode === null && child.signalCode === null
|
|
301
|
-
&& (!identity || await ownedChild(options, child.pid, identity.startTicks).catch(() => null))) {
|
|
421
|
+
&& (!identity || await ownedChild(options, child.pid, identity.startTicks, controller).catch(() => null))) {
|
|
302
422
|
child.kill('SIGKILL');
|
|
303
423
|
await exited;
|
|
304
424
|
}
|
|
305
425
|
}
|
|
306
426
|
export async function runOwnedContainerEntrypoint(options) {
|
|
307
|
-
const
|
|
427
|
+
const live = await ownedController(options);
|
|
428
|
+
const identity = live.identity;
|
|
308
429
|
const bin = await canonicalEntrypoint(options, identity);
|
|
309
430
|
const runtimeVersion = options.containerRuntime?.runtimeVersion
|
|
310
431
|
?? JSON.parse(await readFile(new URL('../package.json', import.meta.url), 'utf8')).version;
|
|
@@ -314,21 +435,19 @@ export async function runOwnedContainerEntrypoint(options) {
|
|
|
314
435
|
throw unavailable();
|
|
315
436
|
await mkdir(join(options.home, 'relay'), { recursive: true, mode: 0o700 });
|
|
316
437
|
await privateDirectory(options);
|
|
317
|
-
const marker = { schema: 'dharma.container-entrypoint/v1', home: options.home,
|
|
318
|
-
pid:
|
|
438
|
+
const marker = { schema: live.initStartTicks === undefined ? 'dharma.container-entrypoint/v1' : 'dharma.container-entrypoint/v2', home: options.home,
|
|
439
|
+
pid: identity.pid, uid: identity.uid, startTicks: identity.startTicks,
|
|
440
|
+
...(live.initStartTicks === undefined ? {} : { initStartTicks: live.initStartTicks }) };
|
|
319
441
|
const previous = await privateJson(options, 'container-entrypoint.json');
|
|
320
|
-
if (previous !== null && (!
|
|
321
|
-
|| previous.
|
|
322
|
-
|| typeof previous.startTicks !== 'string' || !/^\d{1,20}$/.test(previous.startTicks)))
|
|
442
|
+
if (previous !== null && (!validMarker(previous) || previous.schema !== marker.schema
|
|
443
|
+
|| previous.home !== marker.home || previous.uid !== marker.uid))
|
|
323
444
|
throw unavailable();
|
|
324
445
|
const lockPath = privatePath(options.home, 'container-entrypoint.lock');
|
|
325
446
|
const oldLock = await privateJson(options, 'container-entrypoint.lock');
|
|
326
447
|
if (oldLock !== null) {
|
|
327
|
-
if (!
|
|
328
|
-
|| oldLock.schema !== marker.schema || oldLock.home !== marker.home || oldLock.uid !== marker.uid || oldLock.pid !== 1
|
|
329
|
-
|| typeof oldLock.startTicks !== 'string' || !/^\d{1,20}$/.test(oldLock.startTicks))
|
|
448
|
+
if (!validMarker(oldLock) || oldLock.schema !== marker.schema || oldLock.home !== marker.home || oldLock.uid !== marker.uid)
|
|
330
449
|
throw unavailable();
|
|
331
|
-
if (oldLock.startTicks === marker.startTicks)
|
|
450
|
+
if (marker.initStartTicks === undefined ? oldLock.startTicks === marker.startTicks : oldLock.initStartTicks === marker.initStartTicks)
|
|
332
451
|
throw new Error('container_entrypoint_busy: an owned entrypoint is already active.');
|
|
333
452
|
await rm(lockPath); // an earlier boot's private lock; actual PID1 identity was verified
|
|
334
453
|
}
|
|
@@ -370,7 +489,7 @@ export async function runOwnedContainerEntrypoint(options) {
|
|
|
370
489
|
retryAt = Date.now() + restartDelayMs;
|
|
371
490
|
}
|
|
372
491
|
if (child && (!shouldRun || hash !== childHash)) {
|
|
373
|
-
await stopOwnedChild(child, options, childIdentity);
|
|
492
|
+
await stopOwnedChild(child, options, childIdentity, marker);
|
|
374
493
|
child = null;
|
|
375
494
|
childIdentity = null;
|
|
376
495
|
childHash = null;
|
|
@@ -379,7 +498,7 @@ export async function runOwnedContainerEntrypoint(options) {
|
|
|
379
498
|
child = spawnRelay(configuration.registration);
|
|
380
499
|
childHash = hash;
|
|
381
500
|
child.on('error', () => { childFailed = true; });
|
|
382
|
-
childIdentity = child.pid ? await ownedChild(options, child.pid).catch(() => null) : null;
|
|
501
|
+
childIdentity = child.pid ? await ownedChild(options, child.pid, undefined, marker).catch(() => null) : null;
|
|
383
502
|
if (child.pid && !childIdentity && child.exitCode === null && child.signalCode === null)
|
|
384
503
|
throw unavailable();
|
|
385
504
|
}
|
|
@@ -401,14 +520,14 @@ export async function runOwnedContainerEntrypoint(options) {
|
|
|
401
520
|
}
|
|
402
521
|
finally {
|
|
403
522
|
if (child)
|
|
404
|
-
await stopOwnedChild(child, options, childIdentity);
|
|
523
|
+
await stopOwnedChild(child, options, childIdentity, marker);
|
|
405
524
|
const current = await privateJson(options, 'container-entrypoint.json').catch(() => null);
|
|
406
|
-
if (current?.startTicks === marker.startTicks && current.home === marker.home) {
|
|
525
|
+
if (current?.startTicks === marker.startTicks && current.home === marker.home && current.pid === marker.pid && current.initStartTicks === marker.initStartTicks) {
|
|
407
526
|
await rm(privatePath(options.home, 'container-entrypoint.json'), { force: true });
|
|
408
527
|
await rm(privatePath(options.home, 'container-heartbeat.json'), { force: true });
|
|
409
528
|
}
|
|
410
529
|
const lock = await privateJson(options, 'container-entrypoint.lock').catch(() => null);
|
|
411
|
-
if (lock?.startTicks === marker.startTicks && lock.home === marker.home)
|
|
530
|
+
if (lock?.startTicks === marker.startTicks && lock.home === marker.home && lock.pid === marker.pid && lock.initStartTicks === marker.initStartTicks)
|
|
412
531
|
await rm(lockPath, { force: true });
|
|
413
532
|
}
|
|
414
533
|
}
|