mirror of
https://github.com/amadvance/snapraid.git
synced 2026-10-26 02:49:02 -04:00
Harden PowerShell execution with safe SearchPathW and os_spawn
This commit is contained in:
parent
c1fa9e23b6
commit
87977f28f4
2 changed files with 69 additions and 25 deletions
|
|
@ -203,7 +203,7 @@ static int base64_encode(const unsigned char* in, size_t in_len, char* out, size
|
|||
/*
|
||||
* PowerShell helper
|
||||
*
|
||||
* Runs a PowerShell one-liner via _popen() and captures the first line
|
||||
* Runs a PowerShell one-liner via os_spawn() and captures the first line
|
||||
* of stdout into `out` as UTF-8.
|
||||
* `out` may be NULL when output is not needed.
|
||||
*
|
||||
|
|
@ -214,13 +214,34 @@ static int base64_encode(const unsigned char* in, size_t in_len, char* out, size
|
|||
*/
|
||||
static int windows_ps(const char* ps_command, char* out, size_t out_size)
|
||||
{
|
||||
char cmd[PS_CMD_MAX];
|
||||
WCHAR wps_path[PATH_MAX];
|
||||
char ps_path[PATH_MAX * 3];
|
||||
WCHAR wcmd[PS_CMD_MAX / 4];
|
||||
char b64cmd[PS_CMD_MAX];
|
||||
FILE* fp;
|
||||
int ret;
|
||||
DWORD plen;
|
||||
int stdout_fd = -1;
|
||||
pid_t pid;
|
||||
int status;
|
||||
int wlen;
|
||||
|
||||
/*
|
||||
* Resolve powershell.exe to an absolute path.
|
||||
* Safe search mode enabled in os_init() via SetSearchPathMode() ensures
|
||||
* system directories and PATH are searched before the current working directory.
|
||||
*/
|
||||
plen = SearchPathW(NULL, L"powershell.exe", NULL, PATH_MAX, wps_path, NULL);
|
||||
if (plen == 0 || plen >= PATH_MAX) {
|
||||
windows_errno(GetLastError());
|
||||
log_error(errno, "Failed to locate powershell.exe for command '%s'.\n", ps_command);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (WideCharToMultiByte(CP_UTF8, 0, wps_path, -1, ps_path, sizeof(ps_path), 0, 0) == 0) {
|
||||
errno = E2BIG;
|
||||
log_error(errno, "Failed to convert powershell.exe path for command '%s'.\n", ps_command);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* convert UTF-8 command to UTF-16LE WCHARs */
|
||||
wlen = MultiByteToWideChar(CP_UTF8, 0, ps_command, -1, wcmd, PS_CMD_MAX / 4);
|
||||
if (wlen <= 0) {
|
||||
|
|
@ -236,38 +257,50 @@ static int windows_ps(const char* ps_command, char* out, size_t out_size)
|
|||
return -1;
|
||||
}
|
||||
|
||||
ret = snprintf(cmd, sizeof(cmd), "powershell.exe -NoProfile -NonInteractive -EncodedCommand \"%s\" 2>nul", b64cmd);
|
||||
if (ret < 0 || ret >= (int)sizeof(cmd)) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
char* argv[] = {
|
||||
ps_path,
|
||||
"-NoProfile",
|
||||
"-NonInteractive",
|
||||
"-EncodedCommand",
|
||||
b64cmd,
|
||||
0
|
||||
};
|
||||
|
||||
fp = _popen(cmd, "r");
|
||||
if (!fp) {
|
||||
windows_errno(GetLastError());
|
||||
log_error(errno, "Failed to run PowerShell command '%s' (from popen).\n", ps_command);
|
||||
pid = os_spawn(argv, &stdout_fd, 0, 0);
|
||||
if (pid < 0) {
|
||||
log_error(errno, "Failed to run PowerShell command '%s' (from os_spawn).\n", ps_command);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (out && out_size > 0) {
|
||||
/* get the first line */
|
||||
if (!fgets(out, (int)out_size, fp)) {
|
||||
out[0] = 0;
|
||||
} else {
|
||||
/* trim spaces and newlines */
|
||||
strtrim(out);
|
||||
size_t pos = 0;
|
||||
while (pos + 1 < out_size) {
|
||||
ssize_t ret = read(stdout_fd, out + pos, out_size - 1 - pos);
|
||||
if (ret <= 0)
|
||||
break;
|
||||
pos += ret;
|
||||
if (memchr(out, '\n', pos))
|
||||
break;
|
||||
}
|
||||
out[pos] = 0;
|
||||
|
||||
/* truncate at first newline and trim */
|
||||
char* eol = strpbrk(out, "\r\n");
|
||||
if (eol)
|
||||
*eol = 0;
|
||||
strtrim(out);
|
||||
}
|
||||
|
||||
ret = _pclose(fp);
|
||||
if (ret == -1) {
|
||||
errno = EINVAL;
|
||||
log_error(errno, "Failed to run PowerShell command '%s' (from pclose).\n", ps_command);
|
||||
close(stdout_fd);
|
||||
|
||||
status = 0;
|
||||
if (os_wait(pid, &status) < 0) {
|
||||
log_error(errno, "Failed to wait for PowerShell command '%s' (from os_wait).\n", ps_command);
|
||||
return -1;
|
||||
}
|
||||
if (ret != 0) {
|
||||
if (status != 0) {
|
||||
errno = EINVAL;
|
||||
log_error(errno, "PowerShell command '%s' failed with '%d' (from pclose).\n", ps_command, ret);
|
||||
log_error(errno, "PowerShell command '%s' failed with '%d'.\n", ps_command, status);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
|
|||
11
os/mingw.c
11
os/mingw.c
|
|
@ -33,6 +33,14 @@
|
|||
#define WIN32_ES_CONTINUOUS 0x80000000L
|
||||
#endif
|
||||
|
||||
/* For SetSearchPathMode */
|
||||
#ifndef BASE_SEARCH_PATH_ENABLE_SAFE_SEARCHMODE
|
||||
#define BASE_SEARCH_PATH_ENABLE_SAFE_SEARCHMODE 0x00000001
|
||||
#endif
|
||||
#ifndef BASE_SEARCH_PATH_PERMANENT
|
||||
#define BASE_SEARCH_PATH_PERMANENT 0x00008000
|
||||
#endif
|
||||
|
||||
/* File Index */
|
||||
#undef FILE_INVALID_FILE_ID
|
||||
#define FILE_INVALID_FILE_ID ((ULONGLONG)-1LL)
|
||||
|
|
@ -3611,6 +3619,9 @@ void os_init(unsigned opt)
|
|||
os_exit();
|
||||
}
|
||||
|
||||
/* enable safe search path mode permanently to prevent binary hijacking from CWD */
|
||||
SetSearchPathMode(BASE_SEARCH_PATH_ENABLE_SAFE_SEARCHMODE | BASE_SEARCH_PATH_PERMANENT);
|
||||
|
||||
dll_advapi32 = LoadLibrary("ADVAPI32.DLL");
|
||||
if (!dll_advapi32) {
|
||||
os_syslog(OS_LVL_CRITICAL, "error loading the ADVAPI32 module");
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue