Skip to content

Commit c36b6ec

Browse files
authored
Merge pull request #2987 from Chia-Network/fix-windows-daemon-spawn
Fix Windows daemon spawn during electron startup on from CLI on Windows
1 parent c2ccd42 commit c36b6ec

1 file changed

Lines changed: 38 additions & 25 deletions

File tree

packages/gui/src/electron/utils/chiaEnvironment.js

Lines changed: 38 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ const CHIA_START_ARGS = Object.freeze(['start', 'daemon', '--skip-keyring']);
1313
let pyProc = null;
1414

1515
let IS_PACKAGED = null;
16-
const EXEC_PATH_CACHE = {}; // {[execName]: execPath}
16+
const LAUNCH_CACHE = {}; // {[execName]: { command, prefixArgs }}
1717

1818
const guessPackaged = () => {
1919
// This is very important. This means guessing whether it's packaged is checked only once in a process lifetime.
@@ -32,11 +32,16 @@ const getVirtualEnvExecDir = () => {
3232
return null;
3333
};
3434

35-
const getExecutablePath = (execName) => {
36-
// This also means getting exec path is done only once
37-
// to prevent to run a different executable with the same name in a process lifetime.
38-
if (Object.prototype.hasOwnProperty.call(EXEC_PATH_CACHE, execName)) {
39-
return EXEC_PATH_CACHE[execName];
35+
/**
36+
* Resolve a spawnable chia launch without using shell:true.
37+
* On Windows venvs that only ship chia.cmd, spawn python.exe + the chia script
38+
* (same as chia.cmd) to avoid EINVAL under CVE-2024-27980.
39+
*/
40+
const getChiaLaunch = (execName = PY_CHIA_EXEC) => {
41+
// Getting launch config is done only once to prevent running a different
42+
// executable with the same name in a process lifetime.
43+
if (Object.prototype.hasOwnProperty.call(LAUNCH_CACHE, execName)) {
44+
return LAUNCH_CACHE[execName];
4045
}
4146

4247
const execDir = guessPackaged() ? PY_DIST_FOLDER : getVirtualEnvExecDir();
@@ -45,38 +50,45 @@ const getExecutablePath = (execName) => {
4550
}
4651

4752
if (process.platform === 'win32') {
48-
let execPath = path.join(execDir, `${execName}.exe`);
49-
if (fs.existsSync(execPath)) {
50-
EXEC_PATH_CACHE[execName] = execPath;
51-
return execPath;
53+
const exePath = path.join(execDir, `${execName}.exe`);
54+
if (fs.existsSync(exePath)) {
55+
LAUNCH_CACHE[execName] = { command: exePath, prefixArgs: [] };
56+
return LAUNCH_CACHE[execName];
5257
}
53-
execPath = path.join(execDir, `${execName}.cmd`).replace(new RegExp(path.posix.sep, 'g'), path.win32.sep);
54-
if (fs.existsSync(execPath)) {
55-
EXEC_PATH_CACHE[execName] = execPath;
56-
return execPath;
58+
59+
const pythonPath = path.join(execDir, 'python.exe');
60+
const scriptPath = path.join(execDir, execName);
61+
if (!fs.existsSync(pythonPath)) {
62+
throw new Error(`python.exe could not be found in: ${execDir}`);
63+
}
64+
if (!fs.existsSync(scriptPath)) {
65+
throw new Error(`chia script could not be found in: ${execDir}`);
5766
}
58-
throw new Error(`chia executable could not be found in: ${execDir}`);
67+
68+
LAUNCH_CACHE[execName] = { command: pythonPath, prefixArgs: [scriptPath] };
69+
return LAUNCH_CACHE[execName];
5970
}
6071

61-
EXEC_PATH_CACHE[execName] = path.join(execDir, execName);
62-
return EXEC_PATH_CACHE[execName];
72+
LAUNCH_CACHE[execName] = { command: path.join(execDir, execName), prefixArgs: [] };
73+
return LAUNCH_CACHE[execName];
6374
};
6475

6576
const getChiaVersion = () => {
66-
const chiaExecPath = getExecutablePath(PY_CHIA_EXEC);
77+
const { command, prefixArgs } = getChiaLaunch();
6778
return childProcess
68-
.execFileSync(chiaExecPath, ['version'], {
79+
.execFileSync(command, [...prefixArgs, 'version'], {
6980
encoding: 'UTF-8',
7081
})
7182
.trim();
7283
};
7384

7485
const chiaInit = () => {
75-
const chiaExecPath = getExecutablePath(PY_CHIA_EXEC);
76-
console.info(`Executing: ${chiaExecPath} init`);
86+
const { command, prefixArgs } = getChiaLaunch();
87+
const args = [...prefixArgs, 'init'];
88+
console.info(`Executing: ${command} ${args.join(' ')}`);
7789

7890
try {
79-
const output = childProcess.execFileSync(chiaExecPath, ['init']);
91+
const output = childProcess.execFileSync(command, args);
8092
console.info(output.toString());
8193
return true;
8294
} catch (e) {
@@ -97,12 +109,13 @@ const startChiaDaemon = () => {
97109
};
98110
}
99111

100-
const chiaExec = getExecutablePath(PY_CHIA_EXEC);
112+
const { command, prefixArgs } = getChiaLaunch();
113+
const args = [...prefixArgs, ...CHIA_START_ARGS];
101114
console.info('Running python executable: ');
102-
console.info(`Script: ${chiaExec} ${CHIA_START_ARGS.join(' ')}`);
115+
console.info(`Script: ${command} ${args.join(' ')}`);
103116

104117
try {
105-
pyProc = childProcess.spawn(chiaExec, CHIA_START_ARGS, procOption);
118+
pyProc = childProcess.spawn(command, args, procOption);
106119
} catch (e) {
107120
console.error('Running python executable: Error: ');
108121
console.error(e);

0 commit comments

Comments
 (0)