Skip to content

Commit 8ed5e99

Browse files
fuleinistclaude
andcommitted
fix(gateway-lock): verify lock owner identity via startTime + reject non-integer ports
- Guard applyGatewayRuntimePortEnvOverride against PID reuse: when a lock carries startTime, compare it against the current process start time read from /proc/{pid}/stat before trusting the runtime-port override. If the times differ the lock is stale (PID recycled) and is ignored. - Add Number.isInteger check in readLockPayload so malformed locks with fractional ports (e.g. 18789.5) are treated as missing, preventing ERR_SOCKET_BAD_PORT from net.createConnection during owner probes. - Export readLinuxStartTime so it can be used by paths.ts for the startTime verification above. Addresses chatgpt-codex-connector[bot] P2 comments on #42496. Co-Authored-By: Claude Opus 4.6 <[email protected]>
1 parent ea8d038 commit 8ed5e99

2 files changed

Lines changed: 13 additions & 3 deletions

File tree

src/config/paths.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -306,13 +306,22 @@ export async function applyGatewayRuntimePortEnvOverride(
306306
}
307307

308308
// Dynamic import to avoid circular dependency
309-
const { readGatewayLockPayload } = await import("../infra/gateway-lock.js");
309+
const { readGatewayLockPayload, readLinuxStartTime } = await import("../infra/gateway-lock.js");
310310
const { isPidAlive } = await import("../shared/pid-alive.js");
311311
const payload = await readGatewayLockPayload(env);
312312

313-
// Verify the PID is still alive before using the port
313+
// Verify the PID is still alive and the lock startTime matches (to guard
314+
// against PID reuse by an unrelated process) before using the port.
314315
if (payload?.pid && payload.port && Number.isFinite(payload.port) && payload.port > 0) {
315316
if (isPidAlive(payload.pid)) {
317+
// If the lock carries a startTime, verify it matches the current process
318+
// start time to confirm this lock is still owned by the same process.
319+
if (payload.startTime !== undefined) {
320+
const currentStartTime = readLinuxStartTime(payload.pid);
321+
if (currentStartTime !== payload.startTime) {
322+
return; // Stale lock — PID was recycled
323+
}
324+
}
316325
env.OPENCLAW_GATEWAY_PORT = String(payload.port);
317326
}
318327
}

src/infra/gateway-lock.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ function readLinuxCmdline(pid: number): string[] | null {
5757
}
5858
}
5959

60-
function readLinuxStartTime(pid: number): number | null {
60+
export function readLinuxStartTime(pid: number): number | null {
6161
try {
6262
const raw = fsSync.readFileSync(`/proc/${pid}/stat`, "utf8").trim();
6363
const closeParen = raw.lastIndexOf(")");
@@ -157,6 +157,7 @@ async function readLockPayload(lockPath: string): Promise<LockPayload | null> {
157157
const port =
158158
typeof parsed.port === "number" &&
159159
Number.isFinite(parsed.port) &&
160+
Number.isInteger(parsed.port) &&
160161
parsed.port > 0 &&
161162
parsed.port <= 65535
162163
? parsed.port

0 commit comments

Comments
 (0)