Fix a bunch of Windows bugs reported on Discord

This change addresses everything from stack smashing to %SYSTEMROOT%
breaking socket(). Issues relating to compile.com not reporting text
printed to stderr has been resolved for Windows builds.
This commit is contained in:
Justine Tunney 2023-07-28 06:17:34 -07:00
parent b0e3258709
commit 5018171fa5
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
10 changed files with 104 additions and 46 deletions

View file

@ -18,11 +18,13 @@
*/ */
#include "libc/calls/ntspawn.h" #include "libc/calls/ntspawn.h"
#include "libc/fmt/conv.h" #include "libc/fmt/conv.h"
#include "libc/intrin/_getenv.internal.h"
#include "libc/intrin/bits.h" #include "libc/intrin/bits.h"
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
#include "libc/mem/alloca.h" #include "libc/mem/alloca.h"
#include "libc/mem/arraylist2.internal.h" #include "libc/mem/arraylist2.internal.h"
#include "libc/mem/mem.h" #include "libc/mem/mem.h"
#include "libc/runtime/runtime.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"
@ -91,12 +93,15 @@ static textwindows void FixPath(char *path) {
} }
static textwindows void InsertString(char **a, size_t i, char *s, static textwindows void InsertString(char **a, size_t i, char *s,
char buf[ARG_MAX], size_t *bufi) { char buf[ARG_MAX], size_t *bufi,
bool *have_systemroot) {
char *v; char *v;
size_t j, k; size_t j, k;
v = StrChr(s, '=');
// apply fixups to var=/c/... // apply fixups to var=/c/...
if ((v = StrChr(s, '=')) && v[1] == '/' && IsAlpha(v[2]) && v[3] == '/') { if (v && v[1] == '/' && IsAlpha(v[2]) && v[3] == '/') {
v = buf + *bufi; v = buf + *bufi;
for (k = 0; s[k]; ++k) { for (k = 0; s[k]; ++k) {
if (*bufi + 1 < ARG_MAX) { if (*bufi + 1 < ARG_MAX) {
@ -136,11 +141,25 @@ textwindows int mkntenvblock(char16_t envvars[ARG_MAX / 2], char *const envp[],
uint64_t w; uint64_t w;
char **vars; char **vars;
wint_t x, y; wint_t x, y;
bool have_systemroot = false;
size_t i, j, k, n, m, bufi = 0; size_t i, j, k, n, m, bufi = 0;
for (n = 0; envp[n];) n++; for (n = 0; envp[n];) n++;
vars = alloca((n + 1) * sizeof(char *)); vars = alloca((n + 1) * sizeof(char *));
for (i = 0; i < n; ++i) InsertString(vars, i, envp[i], buf, &bufi); for (i = 0; i < n; ++i) {
if (extravar) InsertString(vars, n++, extravar, buf, &bufi); InsertString(vars, i, envp[i], buf, &bufi, &have_systemroot);
}
if (extravar) {
InsertString(vars, n++, extravar, buf, &bufi, &have_systemroot);
}
if (!have_systemroot && environ) {
// https://jpassing.com/2009/12/28/the-hidden-danger-of-forgetting-to-specify-systemroot-in-a-custom-environment-block/
struct Env systemroot;
systemroot = _getenv(environ, "SYSTEMROOT");
if (systemroot.s) {
InsertString(vars, n++, environ[systemroot.i], buf, &bufi,
&have_systemroot);
}
}
for (k = i = 0; i < n; ++i) { for (k = i = 0; i < n; ++i) {
j = 0; j = 0;
v = false; v = false;

View file

@ -31,17 +31,15 @@
* @param shdr is from GetElfSectionHeaderAddress(), or null * @param shdr is from GetElfSectionHeaderAddress(), or null
* @return pointer to section data within image, or null if * @return pointer to section data within image, or null if
* 1. `shdr` was null, or * 1. `shdr` was null, or
* 2. `sh_size` was zero, or * 2. content wasn't contained within `[elf,elf+mapsize)`, or
* 3, `sh_type` was `SHT_NOBITS`, or * 3. an arithmetic overflow occurred
* 4. content wasn't contained within `[elf,elf+mapsize)`, or
* 5. an arithmetic overflow occurred
*/ */
void *GetElfSectionAddress(const Elf64_Ehdr *elf, // validated void *GetElfSectionAddress(const Elf64_Ehdr *elf, // validated
size_t mapsize, // validated size_t mapsize, // validated
const Elf64_Shdr *shdr) { // foreign const Elf64_Shdr *shdr) { // foreign
Elf64_Off last; Elf64_Off last;
if (!shdr) return 0; if (!shdr) return 0;
if (shdr->sh_size <= 0) return 0; if (!shdr->sh_size) return elf;
if (shdr->sh_type == SHT_NOBITS) return 0; if (shdr->sh_type == SHT_NOBITS) return 0;
if (ckd_add(&last, shdr->sh_offset, shdr->sh_size)) return 0; if (ckd_add(&last, shdr->sh_offset, shdr->sh_size)) return 0;
if (last > mapsize) return 0; if (last > mapsize) return 0;

View file

@ -18,16 +18,24 @@
*/ */
#include "libc/intrin/describeflags.internal.h" #include "libc/intrin/describeflags.internal.h"
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
#include "libc/nt/enum/accessmask.h"
#include "libc/nt/enum/fileflagandattributes.h"
#include "libc/nt/enum/filemapflags.h" #include "libc/nt/enum/filemapflags.h"
#include "libc/nt/ipc.h" #include "libc/nt/ipc.h"
static const struct DescribeFlags kPipeOpenFlags[] = { static const struct DescribeFlags kPipeOpenFlags[] = {
{kNtPipeAccessDuplex, "Duplex"}, // 0x00000003 {kNtPipeAccessDuplex, "kNtPipeAccessDuplex"},
{kNtPipeAccessOutbound, "Outbound"}, // 0x00000002 {kNtPipeAccessOutbound, "kNtPipeAccessOutbound"},
{kNtPipeAccessInbound, "Inbound"}, // 0x00000001 {kNtPipeAccessInbound, "kNtPipeAccessInbound"},
{kNtFileFlagOverlapped, "kNtFileFlagOverlapped"},
{kNtFileFlagFirstPipeInstance, "kNtFileFlagFirstPipeInstance"},
{kNtFileFlagWriteThrough, "kNtFileFlagWriteThrough"},
{kNtWriteDac, "kNtWriteDac"},
{kNtWriteOwner, "kNtWriteOwner"},
{kNtAccessSystemSecurity, "kNtAccessSystemSecurity"},
}; };
const char *(DescribeNtPipeOpenFlags)(char buf[64], uint32_t x) { const char *(DescribeNtPipeOpenFlags)(char buf[64], uint32_t x) {
return DescribeFlags(buf, 64, kPipeOpenFlags, ARRAYLEN(kPipeOpenFlags), return DescribeFlags(buf, 64, kPipeOpenFlags, ARRAYLEN(kPipeOpenFlags), "",
"kNtPipeAccess", x); x);
} }

View file

@ -17,10 +17,13 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/calls/state.internal.h" #include "libc/calls/state.internal.h"
#include "libc/fmt/itoa.h"
#include "libc/intrin/describeflags.internal.h" #include "libc/intrin/describeflags.internal.h"
#include "libc/nt/struct/securityattributes.h" #include "libc/nt/struct/securityattributes.h"
const char *DescribeNtSecurityAttributes(struct NtSecurityAttributes *p) { const char *(DescribeNtSecurityAttributes)(char buf[32],
struct NtSecurityAttributes *p) {
if (p == &kNtIsInheritable) return "&kNtIsInheritable"; if (p == &kNtIsInheritable) return "&kNtIsInheritable";
return "0"; FormatInt64(buf, (uintptr_t)p);
return buf;
} }

View file

@ -1,5 +1,6 @@
#ifndef COSMOPOLITAN_LIBC_NT_STRUCT_SECURITYATTRIBUTES_H_ #ifndef COSMOPOLITAN_LIBC_NT_STRUCT_SECURITYATTRIBUTES_H_
#define COSMOPOLITAN_LIBC_NT_STRUCT_SECURITYATTRIBUTES_H_ #define COSMOPOLITAN_LIBC_NT_STRUCT_SECURITYATTRIBUTES_H_
#include "libc/mem/alloca.h"
#include "libc/nt/struct/securitydescriptor.h" #include "libc/nt/struct/securitydescriptor.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0) #if !(__ASSEMBLER__ + __LINKER__ + 0)
@ -9,7 +10,10 @@ struct NtSecurityAttributes {
bool32 bInheritHandle; bool32 bInheritHandle;
}; };
const char *DescribeNtSecurityAttributes(struct NtSecurityAttributes *); const char *DescribeNtSecurityAttributes(char[32],
struct NtSecurityAttributes *);
#define DescribeNtSecurityAttributes(x) \
DescribeNtSecurityAttributes(alloca(32), x)
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_NT_STRUCT_SECURITYATTRIBUTES_H_ */ #endif /* COSMOPOLITAN_LIBC_NT_STRUCT_SECURITYATTRIBUTES_H_ */

View file

@ -24,6 +24,7 @@
#include "libc/log/log.h" #include "libc/log/log.h"
#include "libc/mem/gc.internal.h" #include "libc/mem/gc.internal.h"
#include "libc/mem/mem.h" #include "libc/mem/mem.h"
#include "libc/runtime/runtime.h"
#include "libc/sock/sock.h" #include "libc/sock/sock.h"
#include "libc/sock/struct/ifconf.h" #include "libc/sock/struct/ifconf.h"
#include "libc/sock/struct/ifreq.h" #include "libc/sock/struct/ifreq.h"
@ -32,6 +33,7 @@
#include "libc/sysv/consts/ipproto.h" #include "libc/sysv/consts/ipproto.h"
#include "libc/sysv/consts/sio.h" #include "libc/sysv/consts/sio.h"
#include "libc/sysv/consts/sock.h" #include "libc/sysv/consts/sock.h"
#include "libc/testlib/subprocess.h"
#include "libc/testlib/testlib.h" #include "libc/testlib/testlib.h"
TEST(siocgifconf, test) { TEST(siocgifconf, test) {
@ -70,3 +72,12 @@ TEST(siocgifconf, test) {
EXPECT_TRUE(foundloopback); EXPECT_TRUE(foundloopback);
ASSERT_NE(-1, close(socketfd)); ASSERT_NE(-1, close(socketfd));
} }
TEST(siocgifconf, mkntenvblock_systemroot) {
if (__argc != 1) return;
SPAWN(fork);
execve(GetProgramExecutableName(),
(char *[]){GetProgramExecutableName(), "hi", NULL}, (char *[]){NULL});
abort();
EXITS(0);
}

View file

@ -201,17 +201,18 @@ char buf[PAGESIZE];
char tmpout[PATH_MAX]; char tmpout[PATH_MAX];
const char *const kSafeEnv[] = { const char *const kSafeEnv[] = {
"ADDR2LINE", // needed by GetAddr2linePath "ADDR2LINE", // needed by GetAddr2linePath
"HOME", // needed by ~/.runit.psk "HOME", // needed by ~/.runit.psk
"HOMEDRIVE", // needed by ~/.runit.psk "HOMEDRIVE", // needed by ~/.runit.psk
"HOMEPATH", // needed by ~/.runit.psk "HOMEPATH", // needed by ~/.runit.psk
"MAKEFLAGS", // needed by IsRunningUnderMake "MAKEFLAGS", // needed by IsRunningUnderMake
"MODE", // needed by test scripts "MODE", // needed by test scripts
"PATH", // needed by clang "PATH", // needed by clang
"PWD", // just seems plain needed "PWD", // just seems plain needed
"STRACE", // useful for troubleshooting "STRACE", // useful for troubleshooting
"TERM", // needed to detect colors "TERM", // needed to detect colors
"TMPDIR", // needed by compiler "TMPDIR", // needed by compiler
"SYSTEMROOT", // needed by socket()
}; };
const char *const kGccOnlyFlags[] = { const char *const kGccOnlyFlags[] = {
@ -373,7 +374,11 @@ bool IsSafeEnv(const char *s) {
r = ARRAYLEN(kSafeEnv) - 1; r = ARRAYLEN(kSafeEnv) - 1;
while (l <= r) { while (l <= r) {
m = (l & r) + ((l ^ r) >> 1); // floor((a+b)/2) m = (l & r) + ((l ^ r) >> 1); // floor((a+b)/2)
x = strncmp(s, kSafeEnv[m], n); if (IsWindows()) {
x = strncasecmp(s, kSafeEnv[m], n);
} else {
x = strncmp(s, kSafeEnv[m], n);
}
if (x < 0) { if (x < 0) {
r = m - 1; r = m - 1;
} else if (x > 0) { } else if (x > 0) {
@ -643,10 +648,6 @@ int Launch(void) {
close(pipefds[1]); close(pipefds[1]);
for (;;) { for (;;) {
if (gotchld) {
rc = 0;
break;
}
if (gotalrm) { if (gotalrm) {
PrintRed(); PrintRed();
appends(&output, "\n\n`"); appends(&output, "\n\n`");

View file

@ -176,13 +176,13 @@ static void RewriteTlsCode(void) {
uint32_t *p, *pe; uint32_t *p, *pe;
for (i = 0; i < elf->e_shnum; ++i) { for (i = 0; i < elf->e_shnum; ++i) {
if (!(shdr = GetElfSectionHeaderAddress(elf, esize, i))) { if (!(shdr = GetElfSectionHeaderAddress(elf, esize, i))) {
Die("elf header overflow"); Die("elf header overflow #1");
} }
if (shdr->sh_type == SHT_PROGBITS && // if (shdr->sh_type == SHT_PROGBITS && //
(shdr->sh_flags & SHF_ALLOC) && // (shdr->sh_flags & SHF_ALLOC) && //
(shdr->sh_flags & SHF_EXECINSTR)) { (shdr->sh_flags & SHF_EXECINSTR)) {
if (!(p = GetElfSectionAddress(elf, esize, shdr))) { if (!(p = GetElfSectionAddress(elf, esize, shdr))) {
Die("elf header overflow"); Die("elf header overflow #2");
} }
for (pe = p + shdr->sh_size / 4; p <= pe; ++p) { for (pe = p + shdr->sh_size / 4; p <= pe; ++p) {
if ((*p & -32) == MRS_TPIDR_EL0) { if ((*p & -32) == MRS_TPIDR_EL0) {
@ -213,11 +213,11 @@ static void OptimizePatchableFunctionEntries(void) {
if (!syms[i].st_size) continue; if (!syms[i].st_size) continue;
if (ELF64_ST_TYPE(syms[i].st_info) != STT_FUNC) continue; if (ELF64_ST_TYPE(syms[i].st_info) != STT_FUNC) continue;
if (!(shdr = GetElfSectionHeaderAddress(elf, esize, syms[i].st_shndx))) { if (!(shdr = GetElfSectionHeaderAddress(elf, esize, syms[i].st_shndx))) {
Die("elf header overflow"); Die("elf header overflow #3");
} }
if (shdr->sh_type != SHT_PROGBITS) continue; if (shdr->sh_type != SHT_PROGBITS) continue;
if (!(p = GetElfSectionAddress(elf, esize, shdr))) { if (!(p = GetElfSectionAddress(elf, esize, shdr))) {
Die("elf header overflow"); Die("elf header overflow #4");
} }
if (syms[i].st_value < shdr->sh_addr) { if (syms[i].st_value < shdr->sh_addr) {
Die("elf symbol beneath section"); Die("elf symbol beneath section");

View file

@ -651,9 +651,9 @@ int main(int argc, char *argv[]) {
if (argc == 2 && !strcmp(argv[1], "-n")) { if (argc == 2 && !strcmp(argv[1], "-n")) {
exit(0); exit(0);
} }
if (!IsOptimized()) { #ifndef NDEBUG
ShowCrashReports(); ShowCrashReports();
} #endif
bzero(&pkg, sizeof(pkg)); bzero(&pkg, sizeof(pkg));
bzero(&deps, sizeof(deps)); bzero(&deps, sizeof(deps));
Package(argc, argv, &pkg, &deps); Package(argc, argv, &pkg, &deps);

View file

@ -16,6 +16,7 @@
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/assert.h"
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/struct/stat.h" #include "libc/calls/struct/stat.h"
#include "libc/elf/def.h" #include "libc/elf/def.h"
@ -139,16 +140,27 @@ void ProcessFile(struct ElfWriter *elf, const char *path) {
size_t pathlen; size_t pathlen;
struct stat st; struct stat st;
const char *name; const char *name;
CHECK_NE(-1, (fd = open(path, O_RDONLY))); if (stat(path, &st)) {
CHECK_NE(-1, fstat(fd, &st)); perror(path);
exit(1);
}
if (S_ISDIR(st.st_mode)) { if (S_ISDIR(st.st_mode)) {
if ((fd = open(path, O_RDONLY | O_DIRECTORY)) == -1) {
perror(path);
exit(1);
}
map = ""; map = "";
st.st_size = 0; st.st_size = 0;
} else if (st.st_size) { } else if (st.st_size) {
CHECK_NE(MAP_FAILED, if ((fd = open(path, O_RDONLY)) == -1 ||
(map = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0))); (map = mmap(0, st.st_size, PROT_READ, MAP_SHARED, fd, 0)) ==
MAP_FAILED) {
perror(path);
exit(1);
}
} else { } else {
map = NULL; fd = -1;
map = 0;
} }
if (name_) { if (name_) {
name = name_; name = name_;
@ -166,7 +178,9 @@ void ProcessFile(struct ElfWriter *elf, const char *path) {
} }
elfwriter_zip(elf, name, name, strlen(name), map, st.st_size, st.st_mode, elfwriter_zip(elf, name, name, strlen(name), map, st.st_size, st.st_mode,
timestamp, timestamp, timestamp, nocompress_); timestamp, timestamp, timestamp, nocompress_);
if (st.st_size) CHECK_NE(-1, munmap(map, st.st_size)); if (st.st_size) {
unassert(!munmap(map, st.st_size));
}
close(fd); close(fd);
} }