Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 20 additions & 14 deletions skills/chrome-control/native-host/host.js
Original file line number Diff line number Diff line change
Expand Up @@ -301,20 +301,26 @@ function lstatIfExists(file) {
}
}
function listenUnix() {
server.listen(socketPath, () => {
try {
const bound = node_fs.default.lstatSync(socketPath);
boundSocket = {
dev: bound.dev,
ino: bound.ino
};
ownsSocket = true;
node_fs.default.chmodSync(socketPath, 384);
releaseStartupLock();
} catch {
refuseEndpoint();
}
});
const previousUmask = node_process.default.umask(127);
try {
server.listen(socketPath, onUnixListening);
} finally {
node_process.default.umask(previousUmask);
}
}
function onUnixListening() {
try {
const bound = node_fs.default.lstatSync(socketPath);
boundSocket = {
dev: bound.dev,
ino: bound.ino
};
ownsSocket = true;
node_fs.default.chmodSync(socketPath, 384);
releaseStartupLock();
} catch {
refuseEndpoint();
}
}
function removeOwnSocket() {
try {
Expand Down
28 changes: 17 additions & 11 deletions src/native-host/host.ts
Original file line number Diff line number Diff line change
Expand Up @@ -243,17 +243,23 @@ function lstatIfExists(file: string) {
// A bind never replaces an existing file, so a racing host fails with
// EADDRINUSE instead of taking over this endpoint.
function listenUnix() {
server.listen(socketPath, () => {
try {
const bound = fs.lstatSync(socketPath);
boundSocket = { dev: bound.dev, ino: bound.ino };
ownsSocket = true;
fs.chmodSync(socketPath, 0o600);
releaseStartupLock();
} catch {
refuseEndpoint();
}
});
// The bind inside listen is synchronous, so this umask makes the socket
// 0600 from the moment it exists instead of after the chmod below.
const previousUmask = process.umask(0o177);
try { server.listen(socketPath, onUnixListening); }
finally { process.umask(previousUmask); }
}

function onUnixListening() {
try {
const bound = fs.lstatSync(socketPath);
boundSocket = { dev: bound.dev, ino: bound.ino };
ownsSocket = true;
fs.chmodSync(socketPath, 0o600);
releaseStartupLock();
} catch {
refuseEndpoint();
}
}

// Another host may have replaced this endpoint after a stale-socket recovery,
Expand Down
2 changes: 2 additions & 0 deletions tests/security/host.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ async function host(env: NodeJS.ProcessEnv = {}, protocolVersion = 2) {
const child = spawn(process.execPath, ["dist/native-host/host.js"], {
env: { ...process.env, OPZERO_CHROME_HOST_SOCKET: endpoint, ...env }, stdio: ["pipe", "pipe", "pipe"]
});
child.stdin.on("error", () => undefined);
cleanup.push(() => { child.kill(); fs.rmSync(directory, { recursive: true, force: true }); });
const native: any[] = [];
let buffer = Buffer.alloc(0);
Expand Down Expand Up @@ -185,6 +186,7 @@ function spawnHost(endpoint: string) {
const child = spawn(process.execPath, ["dist/native-host/host.js"], {
env: { ...process.env, OPZERO_CHROME_HOST_SOCKET: endpoint }, stdio: ["pipe", "ignore", "pipe"]
});
child.stdin.on("error", () => undefined);
cleanup.push(() => child.kill());
const exited = new Promise<number | null>(resolve => child.once("exit", resolve));
return { child, exited };
Expand Down
Loading