mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-05-23 13:52:28 +00:00
Improve execve() path argument munging
Munging of paths passed inside the system() interpreter command is no longer supported. You have to pass your paths to posix_spawn() or the execve() family of functions if you want them to be munged. The first three characters must match `^/[a-z]/` in which case, it'll be turned into a DOS-style drive path with backslashes.
This commit is contained in:
parent
529cb4817c
commit
32b97f2d25
5 changed files with 88 additions and 78 deletions
|
@ -16,11 +16,17 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "libc/calls/syscall_support-nt.internal.h"
|
||||||
|
#include "libc/dce.h"
|
||||||
|
#include "libc/errno.h"
|
||||||
|
#include "libc/limits.h"
|
||||||
#include "libc/mem/mem.h"
|
#include "libc/mem/mem.h"
|
||||||
|
#include "libc/nt/files.h"
|
||||||
#include "libc/proc/ntspawn.h"
|
#include "libc/proc/ntspawn.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
#include "libc/str/thompike.h"
|
#include "libc/str/thompike.h"
|
||||||
#include "libc/str/utf16.h"
|
#include "libc/str/utf16.h"
|
||||||
|
#include "libc/sysv/consts/at.h"
|
||||||
#include "libc/sysv/errfuns.h"
|
#include "libc/sysv/errfuns.h"
|
||||||
|
|
||||||
#define APPEND(c) \
|
#define APPEND(c) \
|
||||||
|
@ -54,6 +60,12 @@ static inline int IsAlpha(int c) {
|
||||||
return ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z');
|
return ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool LooksLikeCosmoDrivePath(const char *s) {
|
||||||
|
return s[0] == '/' && //
|
||||||
|
IsAlpha(s[1]) && //
|
||||||
|
s[2] == '/';
|
||||||
|
}
|
||||||
|
|
||||||
// Converts System V argv to Windows-style command line.
|
// Converts System V argv to Windows-style command line.
|
||||||
//
|
//
|
||||||
// Escaping is performed and it's designed to round-trip with
|
// Escaping is performed and it's designed to round-trip with
|
||||||
|
@ -68,20 +80,31 @@ static inline int IsAlpha(int c) {
|
||||||
// @see libc/runtime/getdosargv.c
|
// @see libc/runtime/getdosargv.c
|
||||||
// @asyncsignalsafe
|
// @asyncsignalsafe
|
||||||
textwindows int mkntcmdline(char16_t cmdline[32767], char *const argv[]) {
|
textwindows int mkntcmdline(char16_t cmdline[32767], char *const argv[]) {
|
||||||
|
char *arg;
|
||||||
int slashes, n;
|
int slashes, n;
|
||||||
bool needsquote;
|
bool needsquote;
|
||||||
size_t i, j, k, s;
|
size_t i, j, k, s;
|
||||||
|
char argbuf[PATH_MAX];
|
||||||
for (k = i = 0; argv[i]; ++i) {
|
for (k = i = 0; argv[i]; ++i) {
|
||||||
if (i) APPEND(u' ');
|
if (i) APPEND(u' ');
|
||||||
if ((needsquote = NeedsQuotes(argv[i]))) APPEND(u'"');
|
if (LooksLikeCosmoDrivePath(argv[i]) &&
|
||||||
|
strlcpy(argbuf, argv[i], PATH_MAX) < PATH_MAX) {
|
||||||
|
mungentpath(argbuf);
|
||||||
|
arg = argbuf;
|
||||||
|
} else {
|
||||||
|
arg = argv[i];
|
||||||
|
}
|
||||||
|
if ((needsquote = NeedsQuotes(arg))) {
|
||||||
|
APPEND(u'"');
|
||||||
|
}
|
||||||
for (slashes = j = 0;;) {
|
for (slashes = j = 0;;) {
|
||||||
wint_t x = argv[i][j++] & 255;
|
wint_t x = arg[j++] & 255;
|
||||||
if (x >= 0300) {
|
if (x >= 0300) {
|
||||||
n = ThomPikeLen(x);
|
n = ThomPikeLen(x);
|
||||||
x = ThomPikeByte(x);
|
x = ThomPikeByte(x);
|
||||||
while (--n) {
|
while (--n) {
|
||||||
wint_t y;
|
wint_t y;
|
||||||
if ((y = argv[i][j++] & 255)) {
|
if ((y = arg[j++] & 255)) {
|
||||||
x = ThomPikeMerge(x, y);
|
x = ThomPikeMerge(x, y);
|
||||||
} else {
|
} else {
|
||||||
x = 0;
|
x = 0;
|
||||||
|
@ -90,28 +113,6 @@ textwindows int mkntcmdline(char16_t cmdline[32767], char *const argv[]) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!x) break;
|
if (!x) break;
|
||||||
if (x == '/' || x == '\\') {
|
|
||||||
if (!i) {
|
|
||||||
// turn / into \ for first argv[i]
|
|
||||||
x = '\\';
|
|
||||||
// turn \c\... into c:\ for first argv[i]
|
|
||||||
if (k == 2 && IsAlpha(cmdline[1]) && cmdline[0] == '\\') {
|
|
||||||
cmdline[0] = cmdline[1];
|
|
||||||
cmdline[1] = ':';
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// turn stuff like `less /c/...`
|
|
||||||
// into `less c:/...`
|
|
||||||
// turn stuff like `more <"/c/..."`
|
|
||||||
// into `more <"c:/..."`
|
|
||||||
if (k > 3 && IsAlpha(cmdline[k - 1]) &&
|
|
||||||
(cmdline[k - 2] == '/' || cmdline[k - 2] == '\\') &&
|
|
||||||
(cmdline[k - 3] == '"' || cmdline[k - 3] == ' ')) {
|
|
||||||
cmdline[k - 2] = cmdline[k - 1];
|
|
||||||
cmdline[k - 1] = ':';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (x == '\\') {
|
if (x == '\\') {
|
||||||
++slashes;
|
++slashes;
|
||||||
} else if (x == '"') {
|
} else if (x == '"') {
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include "libc/assert.h"
|
#include "libc/assert.h"
|
||||||
#include "libc/intrin/getenv.internal.h"
|
#include "libc/intrin/getenv.internal.h"
|
||||||
#include "libc/mem/alloca.h"
|
#include "libc/mem/alloca.h"
|
||||||
|
#include "libc/proc/ntspawn.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
#include "libc/runtime/stack.h"
|
#include "libc/runtime/stack.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
|
@ -51,38 +52,6 @@ static textwindows int Compare(const char *l, const char *r) {
|
||||||
return a - b;
|
return a - b;
|
||||||
}
|
}
|
||||||
|
|
||||||
static textwindows void FixPath(char *path) {
|
|
||||||
char *p;
|
|
||||||
|
|
||||||
// turn colon into semicolon
|
|
||||||
// unless it already looks like a dos path
|
|
||||||
for (p = path; *p; ++p) {
|
|
||||||
if (p[0] == ':' && p[1] != '\\') {
|
|
||||||
p[0] = ';';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// turn /c/... into c:\...
|
|
||||||
p = path;
|
|
||||||
if (p[0] == '/' && IsAlpha(p[1]) && p[2] == '/') {
|
|
||||||
p[0] = p[1];
|
|
||||||
p[1] = ':';
|
|
||||||
}
|
|
||||||
for (; *p; ++p) {
|
|
||||||
if (p[0] == ';' && p[1] == '/' && IsAlpha(p[2]) && p[3] == '/') {
|
|
||||||
p[1] = p[2];
|
|
||||||
p[2] = ':';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// turn slash into backslash
|
|
||||||
for (p = path; *p; ++p) {
|
|
||||||
if (*p == '/') {
|
|
||||||
*p = '\\';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static textwindows int InsertString(struct EnvBuilder *env, const char *str) {
|
static textwindows int InsertString(struct EnvBuilder *env, const char *str) {
|
||||||
int c, i, cmp;
|
int c, i, cmp;
|
||||||
char *var, *path = 0;
|
char *var, *path = 0;
|
||||||
|
@ -101,7 +70,7 @@ static textwindows int InsertString(struct EnvBuilder *env, const char *str) {
|
||||||
} while (c);
|
} while (c);
|
||||||
|
|
||||||
// fixup key=/c/... → key=c:\...
|
// fixup key=/c/... → key=c:\...
|
||||||
if (path) FixPath(path);
|
if (path) mungentpath(path);
|
||||||
|
|
||||||
// append key=val to sorted list using insertion sort technique
|
// append key=val to sorted list using insertion sort technique
|
||||||
for (i = env->vari;; --i) {
|
for (i = env->vari;; --i) {
|
||||||
|
|
55
libc/calls/mungentpath.c
Normal file
55
libc/calls/mungentpath.c
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||||
|
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||||
|
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||||
|
│ Copyright 2023 Justine Alexandra Roberts Tunney │
|
||||||
|
│ │
|
||||||
|
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||||
|
│ any purpose with or without fee is hereby granted, provided that the │
|
||||||
|
│ above copyright notice and this permission notice appear in all copies. │
|
||||||
|
│ │
|
||||||
|
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||||
|
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||||
|
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||||
|
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||||
|
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||||
|
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||||
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "libc/proc/ntspawn.h"
|
||||||
|
|
||||||
|
static inline int IsAlpha(int c) {
|
||||||
|
return ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z');
|
||||||
|
}
|
||||||
|
|
||||||
|
textwindows void mungentpath(char *path) {
|
||||||
|
char *p;
|
||||||
|
|
||||||
|
// turn colon into semicolon
|
||||||
|
// unless it already looks like a dos path
|
||||||
|
for (p = path; *p; ++p) {
|
||||||
|
if (p[0] == ':' && p[1] != '\\') {
|
||||||
|
p[0] = ';';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// turn /c/... into c:\...
|
||||||
|
p = path;
|
||||||
|
if (p[0] == '/' && IsAlpha(p[1]) && p[2] == '/') {
|
||||||
|
p[0] = p[1];
|
||||||
|
p[1] = ':';
|
||||||
|
}
|
||||||
|
for (; *p; ++p) {
|
||||||
|
if (p[0] == ';' && p[1] == '/' && IsAlpha(p[2]) && p[3] == '/') {
|
||||||
|
p[1] = p[2];
|
||||||
|
p[2] = ':';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// turn slash into backslash
|
||||||
|
for (p = path; *p; ++p) {
|
||||||
|
if (*p == '/') {
|
||||||
|
*p = '\\';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,6 +5,7 @@
|
||||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||||
COSMOPOLITAN_C_START_
|
COSMOPOLITAN_C_START_
|
||||||
|
|
||||||
|
void mungentpath(char *);
|
||||||
int mkntcmdline(char16_t[32767], char *const[]);
|
int mkntcmdline(char16_t[32767], char *const[]);
|
||||||
int mkntenvblock(char16_t[32767], char *const[], char *const[], char[32767]);
|
int mkntenvblock(char16_t[32767], char *const[], char *const[], char[32767]);
|
||||||
int ntspawn(int64_t, const char *, char *const[], char *const[], char *const[],
|
int ntspawn(int64_t, const char *, char *const[], char *const[], char *const[],
|
||||||
|
|
|
@ -74,30 +74,14 @@ TEST(mkntcmdline, testUnicode) {
|
||||||
cmdline);
|
cmdline);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(mkntcmdline, fixAsBestAsWeCanForNow1) {
|
TEST(mkntcmdline, fixit) {
|
||||||
char *argv1[] = {
|
char *argv1[] = {
|
||||||
"/C/WINDOWS/system32/cmd.exe",
|
"/C/Program Files/doom/doom.exe",
|
||||||
"/C",
|
"--version",
|
||||||
"more <\"/C/Users/jart/AppData/Local/Temp/tmplquaa_d6\"",
|
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
EXPECT_NE(-1, mkntcmdline(cmdline, argv1));
|
EXPECT_NE(-1, mkntcmdline(cmdline, argv1));
|
||||||
EXPECT_STREQ(u"C:\\WINDOWS\\system32\\cmd.exe /C \"more <"
|
EXPECT_STREQ(u"\"C:\\Program Files\\doom\\doom.exe\" --version", cmdline);
|
||||||
u"\"\"\"C:/Users/jart/AppData/Local/Temp/tmplquaa_d6\"\"\"\"",
|
|
||||||
cmdline);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(mkntcmdline, fixAsBestAsWeCanForNow2) {
|
|
||||||
char *argv1[] = {
|
|
||||||
"/C/WINDOWS/system32/cmd.exe",
|
|
||||||
"/C",
|
|
||||||
"less /C/Users/jart/AppData/Local/Temp/tmplquaa_d6",
|
|
||||||
NULL,
|
|
||||||
};
|
|
||||||
EXPECT_NE(-1, mkntcmdline(cmdline, argv1));
|
|
||||||
EXPECT_STREQ(u"C:\\WINDOWS\\system32\\cmd.exe /C \"less "
|
|
||||||
u"C:/Users/jart/AppData/Local/Temp/tmplquaa_d6\"",
|
|
||||||
cmdline);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(mkntcmdline, testWut) {
|
TEST(mkntcmdline, testWut) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue