summaryrefslogtreecommitdiff
diff options
authorPeter Zhu <[email protected]>2024-06-20 13:25:30 -0400
committerPeter Zhu <[email protected]>2024-06-21 11:49:01 -0400
commit90763e04ba2200f96a485d2ef3bb56817ae1b2db (patch)
treea5b9327ee455e0ab5ff25487f348aff3e39f98a6
parentbd583ca645ea348a2894f4227fcb1af650ee8dec (diff)
Load external GC using command line argument
This commit changes the external GC to be loaded with the `--gc-library` command line argument instead of the RUBY_GC_LIBRARY_PATH environment variable because @nobu pointed out that loading binaries using environment variables can pose a security risk.
-rw-r--r--gc.c42
-rw-r--r--main.c5
-rw-r--r--ruby.c10
-rw-r--r--vm_core.h11
4 files changed, 38 insertions, 30 deletions
diff --git a/gc.c b/gc.c
index 5ee318c5af..0932693004 100644
--- a/gc.c
+++ b/gc.c
@@ -1862,31 +1862,44 @@ static void *rb_gc_impl_objspace_alloc(void);
#if USE_SHARED_GC
# include "dln.h"
-# define RUBY_GC_LIBRARY_PATH "RUBY_GC_LIBRARY_PATH"
+typedef struct gc_function_map {
+ void *(*objspace_alloc)(void);
+} rb_gc_function_map_t;
-static void
-ruby_external_gc_init(void)
+static rb_gc_function_map_t rb_gc_functions;
+
+# define RUBY_GC_LIBRARY_ARG "--gc-library="
+
+void
+ruby_load_external_gc_from_argv(int argc, char **argv)
{
- char *gc_so_path = getenv(RUBY_GC_LIBRARY_PATH);
+ char *gc_so_path = NULL;
+
+ for (int i = 0; i < argc; i++) {
+ if (strncmp(argv[i], RUBY_GC_LIBRARY_ARG, sizeof(RUBY_GC_LIBRARY_ARG) - 1) == 0) {
+ gc_so_path = argv[i] + sizeof(RUBY_GC_LIBRARY_ARG) - 1;
+ }
+ }
+
void *handle = NULL;
if (gc_so_path && dln_supported_p()) {
char error[1024];
handle = dln_open(gc_so_path, error, sizeof(error));
if (!handle) {
fprintf(stderr, "%s", error);
- rb_bug("ruby_external_gc_init: Shared library %s cannot be opened", gc_so_path);
+ rb_bug("ruby_load_external_gc_from_argv: Shared library %s cannot be opened", gc_so_path);
}
}
# define load_external_gc_func(name) do { \
if (handle) { \
- rb_gc_functions->name = dln_symbol(handle, "rb_gc_impl_" #name); \
- if (!rb_gc_functions->name) { \
- rb_bug("ruby_external_gc_init: " #name " func not exported by library %s", gc_so_path); \
+ rb_gc_functions.name = dln_symbol(handle, "rb_gc_impl_" #name); \
+ if (!rb_gc_functions.name) { \
+ rb_bug("ruby_load_external_gc_from_argv: " #name " func not exported by library %s", gc_so_path); \
} \
} \
else { \
- rb_gc_functions->name = rb_gc_impl_##name; \
+ rb_gc_functions.name = rb_gc_impl_##name; \
} \
} while (0)
@@ -1895,15 +1908,12 @@ ruby_external_gc_init(void)
# undef load_external_gc_func
}
-# define rb_gc_impl_objspace_alloc rb_gc_functions->objspace_alloc
+# define rb_gc_impl_objspace_alloc rb_gc_functions.objspace_alloc
#endif
rb_objspace_t *
rb_objspace_alloc(void)
{
-#if USE_SHARED_GC
- ruby_external_gc_init();
-#endif
return (rb_objspace_t *)rb_gc_impl_objspace_alloc();
}
@@ -13638,12 +13648,6 @@ rb_gcdebug_remove_stress_to_class(int argc, VALUE *argv, VALUE self)
void
Init_GC(void)
{
-#if USE_SHARED_GC
- if (getenv(RUBY_GC_LIBRARY_PATH) != NULL && !dln_supported_p()) {
- rb_warn(RUBY_GC_LIBRARY_PATH " is ignored because this executable file can't load extension libraries");
- }
-#endif
-
#undef rb_intern
malloc_offset = gc_compute_malloc_offset();
diff --git a/main.c b/main.c
index cbb294ba72..ddfa0569a2 100644
--- a/main.c
+++ b/main.c
@@ -32,10 +32,15 @@
# undef RUBY_DEBUG_ENV
#endif
+void ruby_load_external_gc_from_argv(int argc, char **argv);
+
static int
rb_main(int argc, char **argv)
{
RUBY_INIT_STACK;
+#if USE_SHARED_GC
+ ruby_load_external_gc_from_argv(argc, argv);
+#endif
ruby_init();
return ruby_run_node(ruby_options(argc, argv));
}
diff --git a/ruby.c b/ruby.c
index b452b0b1ef..fa64dc3caa 100644
--- a/ruby.c
+++ b/ruby.c
@@ -1436,6 +1436,16 @@ proc_long_options(ruby_cmdline_options_t *opt, const char *s, long argc, char **
set_source_encoding_once(opt, s, 0);
}
#endif
+#if defined(USE_SHARED_GC) && USE_SHARED_GC
+ else if (is_option_with_arg("gc-library", Qfalse, Qfalse)) {
+ // no-op
+ // Handled by ruby_load_external_gc_from_argv
+
+ if (!dln_supported_p()) {
+ rb_warn("--gc-library is ignored because this executable file can't load extension libraries");
+ }
+ }
+#endif
else if (strcmp("version", s) == 0) {
if (envopt) goto noenvopt_long;
opt->dump |= DUMP_BIT(version);
diff --git a/vm_core.h b/vm_core.h
index 15ca4571af..7bb779dfa0 100644
--- a/vm_core.h
+++ b/vm_core.h
@@ -106,14 +106,6 @@ extern int ruby_assert_critical_section_entered;
#include "ruby/thread_native.h"
-#if USE_SHARED_GC
-typedef struct gc_function_map {
- void *(*objspace_alloc)(void);
-} rb_gc_function_map_t;
-
-#define rb_gc_functions (&GET_VM()->gc_functions_map)
-#endif
-
/*
* implementation selector of get_insn_info algorithm
* 0: linear search
@@ -761,9 +753,6 @@ typedef struct rb_vm_struct {
int coverage_mode;
struct rb_objspace *objspace;
-#if USE_SHARED_GC
- rb_gc_function_map_t gc_functions_map;
-#endif
rb_at_exit_list *at_exit;