mirror of
https://github.com/Droid-Deck/DroidDeck.git
synced 2026-11-10 10:01:32 -10:00
Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bb4a6d0480 | ||
|
|
0e9a43476f |
No files matched your search
@@ -18,6 +18,8 @@
|
||||
|
||||
typedef int (*spawn_fn)(pid_t *, const char *, const posix_spawn_file_actions_t *, const posix_spawnattr_t *,
|
||||
char *const[], char *const[]);
|
||||
__attribute__((visibility("hidden")))
|
||||
char *const *bl_webhelper_argv(const char *path, char *const argv[], char *const envp[]);
|
||||
|
||||
#if defined(__aarch64__) || defined(BINFMT_TEST)
|
||||
|
||||
@@ -141,21 +143,26 @@ __attribute__((visibility("hidden"))) int bl_binfmt_spawn(pid_t *pid, const char
|
||||
}
|
||||
|
||||
int execvpe(const char *file, char *const argv[], char *const envp[]) {
|
||||
char resolved[PATH_MAX];
|
||||
const char *path = lookup(file, resolved, sizeof resolved) ? resolved : file;
|
||||
char *const *adjusted = bl_webhelper_argv(path, argv, envp);
|
||||
static int (*real)(const char *, char *const[], char *const[]);
|
||||
if (!real) real = (int (*)(const char *, char *const[], char *const[]))dlsym(RTLD_NEXT, "execvpe");
|
||||
bl_binfmt_before_search(file, argv, envp);
|
||||
real(file, argv, envp);
|
||||
return bl_binfmt_after_search(file, argv, envp, errno);
|
||||
bl_binfmt_before_search(file, (char *const *)adjusted, envp);
|
||||
real(file, (char *const *)adjusted, envp);
|
||||
return bl_binfmt_after_search(file, (char *const *)adjusted, envp, errno);
|
||||
}
|
||||
|
||||
int posix_spawnp(pid_t *pid, const char *file, const posix_spawn_file_actions_t *fa, const posix_spawnattr_t *attr,
|
||||
char *const argv[], char *const envp[]) {
|
||||
char path[PATH_MAX];
|
||||
int found = lookup(file, path, sizeof path);
|
||||
char *const *adjusted = bl_webhelper_argv(found ? path : file, argv, envp);
|
||||
static spawn_fn real, spawn;
|
||||
if (!real) real = (spawn_fn)dlsym(RTLD_NEXT, "posix_spawnp");
|
||||
if (!spawn) spawn = (spawn_fn)dlsym(RTLD_NEXT, "posix_spawn");
|
||||
char path[PATH_MAX];
|
||||
if (!handing_off() || !lookup(file, path, sizeof path)) return real(pid, file, fa, attr, argv, envp);
|
||||
return bl_binfmt_spawn(pid, path, fa, attr, argv, envp, spawn);
|
||||
if (!handing_off() || !found) return real(pid, file, fa, attr, (char *const *)adjusted, envp);
|
||||
return bl_binfmt_spawn(pid, path, fa, attr, (char *const *)adjusted, envp, spawn);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
@@ -271,7 +271,8 @@ __attribute__((visibility("hidden"))) void bl_binfmt_before(const char *path, ch
|
||||
__attribute__((visibility("hidden"))) int bl_binfmt_retry(const char *path, char *const argv[], char *const envp[], int error);
|
||||
__attribute__((visibility("hidden"))) void bl_binfmt_before_search(const char *file, char *const argv[], char *const envp[]);
|
||||
__attribute__((visibility("hidden"))) int bl_binfmt_after_search(const char *file, char *const argv[], char *const envp[], int error);
|
||||
__attribute__((visibility("hidden"))) char *const *bl_webhelper_argv(const char *path, char *const argv[]);
|
||||
__attribute__((visibility("hidden")))
|
||||
char *const *bl_webhelper_argv(const char *path, char *const argv[], char *const envp[]);
|
||||
__attribute__((visibility("hidden"))) int bl_binfmt_spawn(pid_t *pid, const char *path, const posix_spawn_file_actions_t *fa,
|
||||
const posix_spawnattr_t *attr, char *const argv[], char *const envp[],
|
||||
spawn_fn real);
|
||||
@@ -341,7 +342,7 @@ static char **web_helper_redirect(const char *path, char *const argv[], const ch
|
||||
}
|
||||
|
||||
int execve(const char *path, char *const argv_in[], char *const envp[]) {
|
||||
char *const *argv = bl_webhelper_argv(path, argv_in);
|
||||
char *const *argv = bl_webhelper_argv(path, argv_in, envp);
|
||||
static int (*real)(const char *, char *const[], char *const[]);
|
||||
if (!real) real = (int (*)(const char *, char *const[], char *const[]))dlsym(RTLD_NEXT, "execve");
|
||||
maybe_answer_lsof(path, argv);
|
||||
@@ -372,7 +373,7 @@ static int answer_lsof_via_spawn(const char *path, char *const argv[], pid_t *pi
|
||||
}
|
||||
|
||||
int execvp(const char *file, char *const argv_in[]) {
|
||||
char *const *argv = bl_webhelper_argv(file, argv_in);
|
||||
char *const *argv = bl_webhelper_argv(file, argv_in, environ);
|
||||
static int (*real)(const char *, char *const[]);
|
||||
if (!real) real = (int (*)(const char *, char *const[]))dlsym(RTLD_NEXT, "execvp");
|
||||
maybe_answer_lsof(file, argv);
|
||||
@@ -382,7 +383,7 @@ int execvp(const char *file, char *const argv_in[]) {
|
||||
}
|
||||
|
||||
int execv(const char *path, char *const argv_in[]) {
|
||||
char *const *argv = bl_webhelper_argv(path, argv_in);
|
||||
char *const *argv = bl_webhelper_argv(path, argv_in, environ);
|
||||
static int (*real)(const char *, char *const[]);
|
||||
if (!real) real = (int (*)(const char *, char *const[]))dlsym(RTLD_NEXT, "execv");
|
||||
maybe_answer_lsof(path, argv);
|
||||
@@ -406,5 +407,6 @@ int posix_spawn(pid_t *pid, const char *path, const posix_spawn_file_actions_t *
|
||||
}
|
||||
static spawn_fn real;
|
||||
if (!real) real = (spawn_fn)dlsym(RTLD_NEXT, "posix_spawn");
|
||||
return bl_binfmt_spawn(pid, path, fa, attr, argv, envp, real);
|
||||
char *const *adjusted = bl_webhelper_argv(path, argv, envp);
|
||||
return bl_binfmt_spawn(pid, path, fa, attr, (char *const *)adjusted, envp, real);
|
||||
}
|
||||
@@ -26,6 +26,14 @@ static char *join_features(const char *have, const char *add) {
|
||||
return strcat(out, add);
|
||||
}
|
||||
|
||||
static int electron_node_mode(char *const envp[]) {
|
||||
static const char variable[] = "ELECTRON_RUN_AS_NODE=";
|
||||
for (int i = 0; envp && envp[i]; i++)
|
||||
if (!strncmp(envp[i], variable, sizeof variable - 1))
|
||||
return envp[i][sizeof variable - 1] != 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *const *chromium_argv(const char *path, char *const argv[]) {
|
||||
const char *slash = path ? strrchr(path, '/') : NULL;
|
||||
if (!slash || !argv || !argv[0]) return argv;
|
||||
@@ -48,7 +56,9 @@ static char *const *chromium_argv(const char *path, char *const argv[]) {
|
||||
return out;
|
||||
}
|
||||
|
||||
__attribute__((visibility("hidden"))) char *const *bl_webhelper_argv(const char *path, char *const argv[]) {
|
||||
__attribute__((visibility("hidden")))
|
||||
char *const *bl_webhelper_argv(const char *path, char *const argv[], char *const envp[]) {
|
||||
if (electron_node_mode(envp)) return argv;
|
||||
if (!is_webhelper_browser(path, argv)) return chromium_argv(path, argv);
|
||||
const char *spec = getenv("BL_WEBHELPER_ARGS");
|
||||
if (!spec || !*spec) spec = WEBHELPER_DEFAULT;
|
||||
|
||||
@@ -22,22 +22,29 @@ extern char **environ;
|
||||
int main(int argc, char **argv) {
|
||||
if (argc < 3) return 2;
|
||||
const char *how = argv[1], *file = argv[2];
|
||||
char *node_env[] = {"ELECTRON_RUN_AS_NODE=1", NULL};
|
||||
char *const *child_env = !strcmp(how, "execve-node") || !strcmp(how, "execvpe-node") ||
|
||||
!strcmp(how, "spawn-node") || !strcmp(how, "spawnp-node") ? node_env : environ;
|
||||
char **args = argv + 2;
|
||||
if (!strcmp(how, "access")) {
|
||||
int result = access(file, X_OK);
|
||||
printf("access %d %d\n", result, result ? errno : 0);
|
||||
return 0;
|
||||
}
|
||||
if (!strcmp(how, "spawn") || !strcmp(how, "spawnp")) {
|
||||
if (!strcmp(how, "spawn") || !strcmp(how, "spawnp") || !strcmp(how, "spawn-node") ||
|
||||
!strcmp(how, "spawnp-node")) {
|
||||
pid_t pid;
|
||||
int error = how[5] ? posix_spawnp(&pid, file, NULL, NULL, args, environ) : posix_spawn(&pid, file, NULL, NULL, args, environ);
|
||||
int spawnp = !strcmp(how, "spawnp") || !strcmp(how, "spawnp-node");
|
||||
int error = spawnp ? posix_spawnp(&pid, file, NULL, NULL, args, child_env)
|
||||
: posix_spawn(&pid, file, NULL, NULL, args, child_env);
|
||||
if (error) { printf("errno %d\n", error); return 3; }
|
||||
int status;
|
||||
waitpid(pid, &status, 0);
|
||||
printf("exit %d\n", WEXITSTATUS(status));
|
||||
return 0;
|
||||
}
|
||||
if (!strcmp(how, "execve")) execve(file, args, environ);
|
||||
if (!strcmp(how, "execve") || !strcmp(how, "execve-node")) execve(file, args, (char *const *)child_env);
|
||||
else if (!strcmp(how, "execvpe-node")) execvpe(file, args, (char *const *)child_env);
|
||||
else if (!strcmp(how, "execv")) execv(file, args);
|
||||
else if (!strcmp(how, "execvp")) execvp(file, args);
|
||||
else if (!strcmp(how, "execvpe")) execvpe(file, args, environ);
|
||||
@@ -88,6 +95,15 @@ class BinfmtPreloadTest(unittest.TestCase):
|
||||
path.chmod(mode)
|
||||
return path
|
||||
|
||||
def chromium_script(self):
|
||||
folder = self.dir / "vscode"
|
||||
folder.mkdir()
|
||||
executable = folder / "code"
|
||||
executable.write_text("#!/bin/sh\nprintf '%s\\n' \"$@\"\n")
|
||||
executable.chmod(0o755)
|
||||
(folder / "chrome-sandbox").touch()
|
||||
return executable
|
||||
|
||||
def environment(self, desktop=True, **extra):
|
||||
env = {"PATH": "%s:/usr/bin:/bin" % self.dir, "LD_PRELOAD": str(self.library), "HANDLER_LOG": str(self.log)}
|
||||
if desktop:
|
||||
@@ -161,6 +177,17 @@ class BinfmtPreloadTest(unittest.TestCase):
|
||||
self.file("script.sh", b"#!/bin/sh\nexit 5\n")
|
||||
self.assertEqual(self.run_program("spawnp", "script.sh"), (0, "exit 5", None))
|
||||
|
||||
def test_explicit_node_child_environment_skips_injection_for_execve_and_spawn(self):
|
||||
code = self.chromium_script()
|
||||
self.assertEqual(self.run_program("execve-node", code, "--version"), (0, "--version", None))
|
||||
self.assertEqual(self.run_program("execvpe-node", code, "--version"), (0, "--version", None))
|
||||
self.assertEqual(self.run_program("spawn-node", code, "--version"), (0, "--version\nexit 0", None))
|
||||
self.assertEqual(self.run_program("spawnp-node", code, "--version"), (0, "--version\nexit 0", None))
|
||||
|
||||
def test_chromium_gui_launch_without_node_mode_still_receives_no_sandbox(self):
|
||||
code = self.chromium_script()
|
||||
self.assertEqual(self.run_program("execve", code, "--version"), (0, "--no-sandbox\n--version", None))
|
||||
|
||||
def test_the_hand_off_switch_works_without_the_desktop(self):
|
||||
tool = self.x86()
|
||||
for how in ("execve", "execvp"):
|
||||
|
||||
@@ -9,9 +9,16 @@ PRELOAD = Path(__file__).resolve().parents[1] / "linuxfs/preload"
|
||||
|
||||
PROGRAM = r"""
|
||||
#include <stdio.h>
|
||||
char *const *bl_webhelper_argv(const char *path, char *const argv[]);
|
||||
#include <stdlib.h>
|
||||
char *const *bl_webhelper_argv(const char *path, char *const argv[], char *const envp[]);
|
||||
int main(int argc, char **argv) {
|
||||
char *const *out = bl_webhelper_argv(argv[1], argv + 1);
|
||||
const char *mode = getenv("TEST_NODE_MODE_CHILD");
|
||||
static char node[64];
|
||||
snprintf(node, sizeof node, "ELECTRON_RUN_AS_NODE=%s", mode ? mode : "");
|
||||
char *node_env[] = {node, NULL};
|
||||
char *plain_env[] = {"PATH=/usr/bin", NULL};
|
||||
char *const *envp = mode ? node_env : plain_env;
|
||||
char *const *out = bl_webhelper_argv(argv[1], argv + 1, (char *const *)envp);
|
||||
for (int i = 0; out[i]; i++) printf("%s\n", out[i]);
|
||||
return 0;
|
||||
}
|
||||
@@ -35,13 +42,28 @@ class WebhelperPreloadTest(unittest.TestCase):
|
||||
def tearDownClass(cls):
|
||||
shutil.rmtree(cls.tmp, ignore_errors=True)
|
||||
|
||||
def argv(self, *args, spec=None):
|
||||
def argv(self, *args, spec=None, node_child=False, parent_node=False):
|
||||
env = {k: v for k, v in os.environ.items() if k != "BL_WEBHELPER_ARGS"}
|
||||
env.pop("ELECTRON_RUN_AS_NODE", None)
|
||||
if spec is not None:
|
||||
env["BL_WEBHELPER_ARGS"] = spec
|
||||
if node_child is not False:
|
||||
env["TEST_NODE_MODE_CHILD"] = "1" if node_child is True else node_child
|
||||
else:
|
||||
env.pop("TEST_NODE_MODE_CHILD", None)
|
||||
if parent_node:
|
||||
env["ELECTRON_RUN_AS_NODE"] = "1"
|
||||
result = subprocess.run([str(self.program), *args], env=env, capture_output=True, text=True, check=True)
|
||||
return result.stdout.splitlines()
|
||||
|
||||
def chromium(self, directory, name):
|
||||
root = self.tmp / directory
|
||||
root.mkdir(exist_ok=True)
|
||||
executable = root / name
|
||||
executable.touch()
|
||||
(root / "chrome-sandbox").touch()
|
||||
return str(executable)
|
||||
|
||||
def test_the_browser_process_keeps_its_helpers_in_process(self):
|
||||
out = self.argv(WEBHELPER, "-lang=en_US", "--enable-features=A", "--no-sandbox", "--disable-features=B,C")
|
||||
self.assertEqual(out, [WEBHELPER, "-lang=en_US", "--no-sandbox", "--no-zygote", "--in-process-gpu",
|
||||
@@ -57,6 +79,31 @@ class WebhelperPreloadTest(unittest.TestCase):
|
||||
other = ["/usr/bin/steam", "--enable-features=A"]
|
||||
self.assertEqual(self.argv(*other), other)
|
||||
|
||||
def test_node_mode_from_the_child_environment_skips_sandbox_injection(self):
|
||||
code = self.chromium("vscode", "code")
|
||||
self.assertEqual(self.argv(code, node_child=True), [code])
|
||||
|
||||
def test_any_nonempty_node_mode_value_skips_sandbox_injection(self):
|
||||
code = self.chromium("vscode-true", "code")
|
||||
for value in ("true", "0", "yes"):
|
||||
self.assertEqual(self.argv(code, node_child=value), [code])
|
||||
|
||||
def test_empty_node_mode_value_still_gets_sandbox_flag(self):
|
||||
chrome = self.chromium("chromium-empty-mode", "chrome")
|
||||
self.assertEqual(self.argv(chrome, node_child=""), [chrome, "--no-sandbox"])
|
||||
|
||||
def test_non_browser_helper_beside_chrome_sandbox_skips_injection_in_node_mode(self):
|
||||
helper = self.chromium("vscode-helper", "remote-cli")
|
||||
self.assertEqual(self.argv(helper, node_child=True), [helper])
|
||||
|
||||
def test_chromium_gui_launch_still_gets_sandbox_flag_from_explicit_environment(self):
|
||||
chrome = self.chromium("chromium", "chrome")
|
||||
self.assertEqual(self.argv(chrome), [chrome, "--no-sandbox"])
|
||||
|
||||
def test_parent_node_mode_does_not_override_the_explicit_child_environment(self):
|
||||
chrome = self.chromium("chromium-parent-mode", "chrome")
|
||||
self.assertEqual(self.argv(chrome, parent_node=True), [chrome, "--no-sandbox"])
|
||||
|
||||
def test_stock_turns_it_off(self):
|
||||
args = [WEBHELPER, "--enable-features=A"]
|
||||
self.assertEqual(self.argv(*args, spec="stock"), args)
|
||||
|
||||
Reference in new issue
Block a user