/* Windows Low-IL shell sandbox: writes only in the workspace and the * sandbox TEMP, the credentials file is unreadable, timeouts end the whole * process tree, and /sandbox reset-labels restores the workspace label. * Elsewhere it only checks that the kind is never reported. */ #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #include "cst_sandbox.h" #include "os_compat.h" #include #include #include #include "cst_test_util.h" static int nfail; #define EXPECT(cond, msg) \ do { \ if (!(cond)) { \ fprintf(stderr, "FAIL %s:%d: %s\n", __FILE__, __LINE__, msg); \ nfail++; \ } \ } while (0) #ifdef _WIN32 static int run(const char *ws, const char *cmd, os_run_result_t *r) { memset(r, 0, sizeof(*r)); if (cst_sandbox_run_shell(ws, cmd, 0, r) != 0) return -1; return r->exit_code; } static int has(const os_run_result_t *r, const char *s) { return r->out && strstr(r->out, s); } static void write_file(const char *path, const char *text) { FILE *f = fopen(path, "wb"); if (f) { fputs(text, f); fclose(f); } } static void confined(void) { char root[1024], cfg[1100], ws[1100], out[1100], cred[1300], cmd[4096]; char wsr[1100]; if (test_tmpdir(root, sizeof(root), "cst-lowil") != 0) { EXPECT(0, "tmpdir"); return; } snprintf(cfg, sizeof(cfg), "%s/cfg", root); snprintf(ws, sizeof(ws), "%s/项目 ws", root); snprintf(out, sizeof(out), "%s/outside", root); test_mkdir(cfg, 0700); test_mkdir(ws, 0755); test_mkdir(out, 0755); setenv("XDG_CONFIG_HOME", cfg, 1); char cdir[1200]; EXPECT(os_config_dir(cdir, sizeof(cdir)) == 0, "config dir"); os_mkdir_p(cdir, 0700); snprintf(cred, sizeof(cred), "%s/credentials", cdir); write_file(cred, "deepseek=sk-test-secret\n"); EXPECT(os_chmod_private(cred) == 0, "label credentials"); EXPECT(os_realpath(ws, wsr, sizeof(wsr)) == 0, "realpath ws"); os_path_norm_slashes(wsr); os_run_result_t r; EXPECT(run(wsr, "echo hi > in.txt && cat in.txt", &r) == 0, "write inside the workspace"); EXPECT(has(&r, "hi"), "output captured"); EXPECT(has(&r, "labeled"), "first run says the workspace was labeled"); os_run_result_free(&r); EXPECT(run(wsr, "echo again > in.txt && cat in.txt", &r) == 0, "second run"); EXPECT(!has(&r, "labeled"), "labeled only once"); EXPECT(!has(&r, "background"), "conhost is not a background process"); os_run_result_free(&r); char *labels = cst_sandbox_labels(); EXPECT(labels && strstr(labels, wsr), "workspace recorded"); free(labels); snprintf(cmd, sizeof(cmd), "echo x > '%s/o.txt'", out); int rc = run(wsr, cmd, &r); EXPECT(rc != 0, "write outside the workspace fails"); EXPECT(cst_sandbox_blocked(r.out, r.out_len, rc), "outside write blocked"); os_run_result_free(&r); snprintf(cmd, sizeof(cmd), "%s/o.txt", out); os_stat_t st; EXPECT(os_lstat(cmd, &st) != 0, "nothing written outside"); snprintf(cmd, sizeof(cmd), "cat '%s'", cred); rc = run(wsr, cmd, &r); EXPECT(rc != 0 && !has(&r, "sk-test-secret"), "credentials unreadable"); EXPECT(cst_sandbox_blocked(r.out, r.out_len, rc), "credential read blocked"); os_run_result_free(&r); EXPECT(run(wsr, "echo t > \"$TEMP/t.txt\" && cat \"$TEMP/t.txt\"", &r) == 0, "TEMP is writable"); EXPECT(has(&r, "t"), "TEMP read back"); os_run_result_free(&r); /* System32's whoami: busybox has an applet and MSYS2's cannot start at * Low IL */ char sys[MAX_PATH]; UINT sl = GetSystemDirectoryA(sys, sizeof(sys)); for (UINT i = 0; i < sl; i++) if (sys[i] == '\\') sys[i] = '/'; snprintf(cmd, sizeof(cmd), "'%s/whoami.exe' /groups | grep S-1-16-4096", sys); rc = run(wsr, cmd, &r); EXPECT(rc == 0, "child runs at Low integrity"); if (rc != 0) fprintf(stderr, "whoami: exit %d: %.*s\n", rc, (int)r.out_len, r.out ? r.out : ""); os_run_result_free(&r); /* timeout ends background children too */ os_set_run_timeout(2); double t0 = os_now_ms(); rc = run(wsr, "sleep 30 & sleep 30; echo late", &r); double ms = os_now_ms() - t0; EXPECT(rc == 124, "timeout exit code"); EXPECT(ms < 10000, "process tree killed promptly"); EXPECT(!has(&r, "late"), "command did not finish"); os_run_result_free(&r); os_set_run_timeout(0); const char *prof = getenv("USERPROFILE"); char profr[1100]; if (prof && os_realpath(prof, profr, sizeof(profr)) == 0) { os_path_norm_slashes(profr); rc = run(profr, "echo no", &r); EXPECT(rc == 126 && has(&r, "will not label"), "profile is not labeled"); EXPECT(cst_sandbox_blocked(r.out, r.out_len, rc), "offers a rerun"); os_run_result_free(&r); } rc = run("C:/", "echo no", &r); EXPECT(rc == 126 && has(&r, "will not label"), "drive root is not labeled"); os_run_result_free(&r); char *rep = NULL; EXPECT(cst_sandbox_reset_labels(&rep) >= 1, "reset-labels restored"); EXPECT(rep && strstr(rep, "restored"), "reset report"); free(rep); labels = cst_sandbox_labels(); EXPECT(!labels, "record cleared"); free(labels); char sddl[256]; EXPECT(os_win_get_label(wsr, sddl, sizeof(sddl)) == 0 && strcmp(sddl, "S:") == 0, "workspace has no explicit label again"); unsetenv("XDG_CONFIG_HOME"); test_rmrf(root); } #endif int main(void) { int kind = cst_sandbox_probe(); printf("test_lowil: sandbox %s\n", cst_sandbox_name(kind)); EXPECT(strcmp(cst_sandbox_name(CST_SANDBOX_LOWIL), "lowil") == 0, "name"); #ifdef _WIN32 EXPECT(kind == CST_SANDBOX_LOWIL, "lowil available"); if (kind == CST_SANDBOX_LOWIL) confined(); #else EXPECT(kind != CST_SANDBOX_LOWIL, "lowil is Windows only"); char *rep = NULL; EXPECT(cst_sandbox_reset_labels(&rep) == 0 && !rep, "nothing to reset"); EXPECT(!cst_sandbox_labels(), "no labels"); #endif if (nfail) { fprintf(stderr, "test_lowil: %d failure(s)\n", nfail); return 1; } puts("test_lowil: OK"); return 0; }