Skip to content

Commit

Permalink
Improve execve() path argument munging
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
jart committed Nov 17, 2023
1 parent 529cb48 commit 32b97f2
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 78 deletions.
51 changes: 26 additions & 25 deletions libc/calls/mkntcmdline.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,17 @@
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ 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/nt/files.h"
#include "libc/proc/ntspawn.h"
#include "libc/str/str.h"
#include "libc/str/thompike.h"
#include "libc/str/utf16.h"
#include "libc/sysv/consts/at.h"
#include "libc/sysv/errfuns.h"

#define APPEND(c) \
Expand Down Expand Up @@ -54,6 +60,12 @@ static inline int IsAlpha(int c) {
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.
//
// Escaping is performed and it's designed to round-trip with
Expand All @@ -68,20 +80,31 @@ static inline int IsAlpha(int c) {
// @see libc/runtime/getdosargv.c
// @asyncsignalsafe
textwindows int mkntcmdline(char16_t cmdline[32767], char *const argv[]) {
char *arg;
int slashes, n;
bool needsquote;
size_t i, j, k, s;
char argbuf[PATH_MAX];
for (k = i = 0; argv[i]; ++i) {
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;;) {
wint_t x = argv[i][j++] & 255;
wint_t x = arg[j++] & 255;
if (x >= 0300) {
n = ThomPikeLen(x);
x = ThomPikeByte(x);
while (--n) {
wint_t y;
if ((y = argv[i][j++] & 255)) {
if ((y = arg[j++] & 255)) {
x = ThomPikeMerge(x, y);
} else {
x = 0;
Expand All @@ -90,28 +113,6 @@ textwindows int mkntcmdline(char16_t cmdline[32767], char *const argv[]) {
}
}
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 == '\\') {
++slashes;
} else if (x == '"') {
Expand Down
35 changes: 2 additions & 33 deletions libc/calls/mkntenvblock.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "libc/assert.h"
#include "libc/intrin/getenv.internal.h"
#include "libc/mem/alloca.h"
#include "libc/proc/ntspawn.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/stack.h"
#include "libc/str/str.h"
Expand Down Expand Up @@ -51,38 +52,6 @@ static textwindows int Compare(const char *l, const char *r) {
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) {
int c, i, cmp;
char *var, *path = 0;
Expand All @@ -101,7 +70,7 @@ static textwindows int InsertString(struct EnvBuilder *env, const char *str) {
} while (c);

// fixup key=/c/... → key=c:\...
if (path) FixPath(path);
if (path) mungentpath(path);

// append key=val to sorted list using insertion sort technique
for (i = env->vari;; --i) {
Expand Down
55 changes: 55 additions & 0 deletions libc/calls/mungentpath.c
Original file line number Diff line number Diff line change
@@ -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 = '\\';
}
}
}
1 change: 1 addition & 0 deletions libc/proc/ntspawn.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_

void mungentpath(char *);
int mkntcmdline(char16_t[32767], char *const[]);
int mkntenvblock(char16_t[32767], char *const[], char *const[], char[32767]);
int ntspawn(int64_t, const char *, char *const[], char *const[], char *const[],
Expand Down
24 changes: 4 additions & 20 deletions test/libc/calls/mkntcmdline_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,30 +74,14 @@ TEST(mkntcmdline, testUnicode) {
cmdline);
}

TEST(mkntcmdline, fixAsBestAsWeCanForNow1) {
TEST(mkntcmdline, fixit) {
char *argv1[] = {
"/C/WINDOWS/system32/cmd.exe",
"/C",
"more <\"/C/Users/jart/AppData/Local/Temp/tmplquaa_d6\"",
"/C/Program Files/doom/doom.exe",
"--version",
NULL,
};
EXPECT_NE(-1, mkntcmdline(cmdline, argv1));
EXPECT_STREQ(u"C:\\WINDOWS\\system32\\cmd.exe /C \"more <"
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);
EXPECT_STREQ(u"\"C:\\Program Files\\doom\\doom.exe\" --version", cmdline);
}

TEST(mkntcmdline, testWut) {
Expand Down

0 comments on commit 32b97f2

Please sign in to comment.