Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
build:
strategy:
matrix:
os: [ ubuntu-latest, macos-latest ]
os: [ ubuntu-latest, macos-latest, windows-latest ]

runs-on: ${{ matrix.os }}

Expand Down Expand Up @@ -41,11 +41,13 @@ jobs:

# Run js/ts scripts
- name: Set Bun.js
if: runner.os != 'Windows'
uses: oven-sh/setup-bun@v2
with:
bun-version: latest

- name: Install multiplatform JDKs
if: runner.os != 'Windows'
run: |
bun scripts/setupMultiplatformJdks.ts
printf "Exports:\n$(cat ~/java-home-vars-github.sh)"
Expand All @@ -54,6 +56,7 @@ jobs:
- uses: gradle/actions/setup-gradle@v5

- name: Grant execute permission for scripts
if: runner.os != 'Windows'
run: |
chmod +x gradlew
chmod +x quickjs/native/cmake/zig-ar.sh
Expand Down
25 changes: 6 additions & 19 deletions quickjs/native/common/stack_chk.c
Original file line number Diff line number Diff line change
@@ -1,31 +1,18 @@
#include <stdlib.h>
#include <stdint.h>
#include <windows.h>

#if defined(_WIN32)

// Default stack guard value
// Stack guard value for stack-protector support on Windows/MinGW.
// A static value is used instead of runtime randomization because this code
// is compiled into a static library linked by Kotlin/Native. Using
// __attribute__((constructor)) to call LoadLibraryA/GetProcAddress for
// RtlGenRandom caused crashes (exit code 3) since the constructor runs
// before the Windows runtime is fully initialized in that context.
uintptr_t __stack_chk_guard = 0x595e9fbd94fda766;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Static stack canary weakens stack-smashing protection.

The hardcoded guard value is visible in the source and the compiled binary, which means an attacker who can trigger a buffer overflow can also craft a payload that preserves the canary, effectively bypassing the protection. The rationale for avoiding runtime initialization is well-documented and understandable.

A couple of alternatives worth considering if you want some degree of variation without runtime Windows API calls:

  1. Compile-time pseudo-randomness — derive the value from build-specific macros (e.g., __TIME__, __COUNTER__) so each build gets a different canary. It's not cryptographically strong but at least varies per build.
  2. Linker-time randomization — some toolchains support randomizing this at link time.

If the threat model for this project doesn't prioritize stack canary strength (embedded JS engine context), the current approach is an acceptable pragmatic tradeoff — just want to flag the security implication explicitly.

🤖 Prompt for AI Agents
In `@quickjs/native/common/stack_chk.c` around lines 4 - 12, The hardcoded
__stack_chk_guard weakens protection because it is static and predictable;
replace the fixed literal with a compile-time pseudo-random value derived from
build-specific macros (e.g., combine/hash __TIME__, __DATE__, __COUNTER__,
and/or __FILE__ into a uintptr_t) and assign that computed value to
__stack_chk_guard in stack_chk.c so each build produces a different canary; if
compile-time derivation isn’t feasible for some targets, add a clearly
documented fallback (keeping the existing literal) and mention the linker-time
randomization option as an alternative.


void __stack_chk_fail(void) {
abort();
}

typedef BOOLEAN (WINAPI *RtlGenRandomFunc)(PVOID, ULONG);

// Initialize the stack guard with a random value
__attribute__((constructor))
static void __stack_chk_init(void) {
HMODULE hAdvApi32 = LoadLibraryA("advapi32.dll");
if (hAdvApi32) {
RtlGenRandomFunc RtlGenRandom = (RtlGenRandomFunc)GetProcAddress(hAdvApi32, "SystemFunction036");
if (RtlGenRandom) {
uintptr_t random_guard;
if (RtlGenRandom(&random_guard, sizeof(random_guard))) {
__stack_chk_guard = random_guard;
}
}
FreeLibrary(hAdvApi32);
}
}
#endif
Loading