Skip to content

Commit 32b97f2

Browse files
committed
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.
1 parent 529cb48 commit 32b97f2

File tree

5 files changed

+88
-78
lines changed

5 files changed

+88
-78
lines changed

libc/calls/mkntcmdline.c

Lines changed: 26 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,17 @@
1616
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
1717
│ PERFORMANCE OF THIS SOFTWARE. │
1818
╚─────────────────────────────────────────────────────────────────────────────*/
19+
#include "libc/calls/syscall_support-nt.internal.h"
20+
#include "libc/dce.h"
21+
#include "libc/errno.h"
22+
#include "libc/limits.h"
1923
#include "libc/mem/mem.h"
24+
#include "libc/nt/files.h"
2025
#include "libc/proc/ntspawn.h"
2126
#include "libc/str/str.h"
2227
#include "libc/str/thompike.h"
2328
#include "libc/str/utf16.h"
29+
#include "libc/sysv/consts/at.h"
2430
#include "libc/sysv/errfuns.h"
2531

2632
#define APPEND(c) \
@@ -54,6 +60,12 @@ static inline int IsAlpha(int c) {
5460
return ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z');
5561
}
5662

63+
static bool LooksLikeCosmoDrivePath(const char *s) {
64+
return s[0] == '/' && //
65+
IsAlpha(s[1]) && //
66+
s[2] == '/';
67+
}
68+
5769
// Converts System V argv to Windows-style command line.
5870
//
5971
// Escaping is performed and it's designed to round-trip with
@@ -68,20 +80,31 @@ static inline int IsAlpha(int c) {
6880
// @see libc/runtime/getdosargv.c
6981
// @asyncsignalsafe
7082
textwindows int mkntcmdline(char16_t cmdline[32767], char *const argv[]) {
83+
char *arg;
7184
int slashes, n;
7285
bool needsquote;
7386
size_t i, j, k, s;
87+
char argbuf[PATH_MAX];
7488
for (k = i = 0; argv[i]; ++i) {
7589
if (i) APPEND(u' ');
76-
if ((needsquote = NeedsQuotes(argv[i]))) APPEND(u'"');
90+
if (LooksLikeCosmoDrivePath(argv[i]) &&
91+
strlcpy(argbuf, argv[i], PATH_MAX) < PATH_MAX) {
92+
mungentpath(argbuf);
93+
arg = argbuf;
94+
} else {
95+
arg = argv[i];
96+
}
97+
if ((needsquote = NeedsQuotes(arg))) {
98+
APPEND(u'"');
99+
}
77100
for (slashes = j = 0;;) {
78-
wint_t x = argv[i][j++] & 255;
101+
wint_t x = arg[j++] & 255;
79102
if (x >= 0300) {
80103
n = ThomPikeLen(x);
81104
x = ThomPikeByte(x);
82105
while (--n) {
83106
wint_t y;
84-
if ((y = argv[i][j++] & 255)) {
107+
if ((y = arg[j++] & 255)) {
85108
x = ThomPikeMerge(x, y);
86109
} else {
87110
x = 0;
@@ -90,28 +113,6 @@ textwindows int mkntcmdline(char16_t cmdline[32767], char *const argv[]) {
90113
}
91114
}
92115
if (!x) break;
93-
if (x == '/' || x == '\\') {
94-
if (!i) {
95-
// turn / into \ for first argv[i]
96-
x = '\\';
97-
// turn \c\... into c:\ for first argv[i]
98-
if (k == 2 && IsAlpha(cmdline[1]) && cmdline[0] == '\\') {
99-
cmdline[0] = cmdline[1];
100-
cmdline[1] = ':';
101-
}
102-
} else {
103-
// turn stuff like `less /c/...`
104-
// into `less c:/...`
105-
// turn stuff like `more <"/c/..."`
106-
// into `more <"c:/..."`
107-
if (k > 3 && IsAlpha(cmdline[k - 1]) &&
108-
(cmdline[k - 2] == '/' || cmdline[k - 2] == '\\') &&
109-
(cmdline[k - 3] == '"' || cmdline[k - 3] == ' ')) {
110-
cmdline[k - 2] = cmdline[k - 1];
111-
cmdline[k - 1] = ':';
112-
}
113-
}
114-
}
115116
if (x == '\\') {
116117
++slashes;
117118
} else if (x == '"') {

libc/calls/mkntenvblock.c

Lines changed: 2 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "libc/assert.h"
2020
#include "libc/intrin/getenv.internal.h"
2121
#include "libc/mem/alloca.h"
22+
#include "libc/proc/ntspawn.h"
2223
#include "libc/runtime/runtime.h"
2324
#include "libc/runtime/stack.h"
2425
#include "libc/str/str.h"
@@ -51,38 +52,6 @@ static textwindows int Compare(const char *l, const char *r) {
5152
return a - b;
5253
}
5354

54-
static textwindows void FixPath(char *path) {
55-
char *p;
56-
57-
// turn colon into semicolon
58-
// unless it already looks like a dos path
59-
for (p = path; *p; ++p) {
60-
if (p[0] == ':' && p[1] != '\\') {
61-
p[0] = ';';
62-
}
63-
}
64-
65-
// turn /c/... into c:\...
66-
p = path;
67-
if (p[0] == '/' && IsAlpha(p[1]) && p[2] == '/') {
68-
p[0] = p[1];
69-
p[1] = ':';
70-
}
71-
for (; *p; ++p) {
72-
if (p[0] == ';' && p[1] == '/' && IsAlpha(p[2]) && p[3] == '/') {
73-
p[1] = p[2];
74-
p[2] = ':';
75-
}
76-
}
77-
78-
// turn slash into backslash
79-
for (p = path; *p; ++p) {
80-
if (*p == '/') {
81-
*p = '\\';
82-
}
83-
}
84-
}
85-
8655
static textwindows int InsertString(struct EnvBuilder *env, const char *str) {
8756
int c, i, cmp;
8857
char *var, *path = 0;
@@ -101,7 +70,7 @@ static textwindows int InsertString(struct EnvBuilder *env, const char *str) {
10170
} while (c);
10271

10372
// fixup key=/c/... → key=c:\...
104-
if (path) FixPath(path);
73+
if (path) mungentpath(path);
10574

10675
// append key=val to sorted list using insertion sort technique
10776
for (i = env->vari;; --i) {

libc/calls/mungentpath.c

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
2+
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
3+
╞══════════════════════════════════════════════════════════════════════════════╡
4+
│ Copyright 2023 Justine Alexandra Roberts Tunney │
5+
│ │
6+
│ Permission to use, copy, modify, and/or distribute this software for │
7+
│ any purpose with or without fee is hereby granted, provided that the │
8+
│ above copyright notice and this permission notice appear in all copies. │
9+
│ │
10+
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
11+
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
12+
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
13+
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
14+
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
15+
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
16+
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
17+
│ PERFORMANCE OF THIS SOFTWARE. │
18+
╚─────────────────────────────────────────────────────────────────────────────*/
19+
#include "libc/proc/ntspawn.h"
20+
21+
static inline int IsAlpha(int c) {
22+
return ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z');
23+
}
24+
25+
textwindows void mungentpath(char *path) {
26+
char *p;
27+
28+
// turn colon into semicolon
29+
// unless it already looks like a dos path
30+
for (p = path; *p; ++p) {
31+
if (p[0] == ':' && p[1] != '\\') {
32+
p[0] = ';';
33+
}
34+
}
35+
36+
// turn /c/... into c:\...
37+
p = path;
38+
if (p[0] == '/' && IsAlpha(p[1]) && p[2] == '/') {
39+
p[0] = p[1];
40+
p[1] = ':';
41+
}
42+
for (; *p; ++p) {
43+
if (p[0] == ';' && p[1] == '/' && IsAlpha(p[2]) && p[3] == '/') {
44+
p[1] = p[2];
45+
p[2] = ':';
46+
}
47+
}
48+
49+
// turn slash into backslash
50+
for (p = path; *p; ++p) {
51+
if (*p == '/') {
52+
*p = '\\';
53+
}
54+
}
55+
}

libc/proc/ntspawn.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#if !(__ASSEMBLER__ + __LINKER__ + 0)
66
COSMOPOLITAN_C_START_
77

8+
void mungentpath(char *);
89
int mkntcmdline(char16_t[32767], char *const[]);
910
int mkntenvblock(char16_t[32767], char *const[], char *const[], char[32767]);
1011
int ntspawn(int64_t, const char *, char *const[], char *const[], char *const[],

test/libc/calls/mkntcmdline_test.c

Lines changed: 4 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -74,30 +74,14 @@ TEST(mkntcmdline, testUnicode) {
7474
cmdline);
7575
}
7676

77-
TEST(mkntcmdline, fixAsBestAsWeCanForNow1) {
77+
TEST(mkntcmdline, fixit) {
7878
char *argv1[] = {
79-
"/C/WINDOWS/system32/cmd.exe",
80-
"/C",
81-
"more <\"/C/Users/jart/AppData/Local/Temp/tmplquaa_d6\"",
79+
"/C/Program Files/doom/doom.exe",
80+
"--version",
8281
NULL,
8382
};
8483
EXPECT_NE(-1, mkntcmdline(cmdline, argv1));
85-
EXPECT_STREQ(u"C:\\WINDOWS\\system32\\cmd.exe /C \"more <"
86-
u"\"\"\"C:/Users/jart/AppData/Local/Temp/tmplquaa_d6\"\"\"\"",
87-
cmdline);
88-
}
89-
90-
TEST(mkntcmdline, fixAsBestAsWeCanForNow2) {
91-
char *argv1[] = {
92-
"/C/WINDOWS/system32/cmd.exe",
93-
"/C",
94-
"less /C/Users/jart/AppData/Local/Temp/tmplquaa_d6",
95-
NULL,
96-
};
97-
EXPECT_NE(-1, mkntcmdline(cmdline, argv1));
98-
EXPECT_STREQ(u"C:\\WINDOWS\\system32\\cmd.exe /C \"less "
99-
u"C:/Users/jart/AppData/Local/Temp/tmplquaa_d6\"",
100-
cmdline);
84+
EXPECT_STREQ(u"\"C:\\Program Files\\doom\\doom.exe\" --version", cmdline);
10185
}
10286

10387
TEST(mkntcmdline, testWut) {

0 commit comments

Comments
 (0)