contrast-agent 3.8.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.clang-format +5 -0
- data/.dockerignore +10 -0
- data/.gitignore +58 -0
- data/.gitmodules +6 -0
- data/.rspec +6 -0
- data/.simplecov +4 -0
- data/Gemfile +7 -0
- data/LICENSE.txt +12 -0
- data/Rakefile +15 -0
- data/exe/contrast_service +29 -0
- data/ext/build_funchook.rb +48 -0
- data/ext/cs__assess_active_record_named/cs__active_record_named.c +47 -0
- data/ext/cs__assess_active_record_named/cs__active_record_named.h +10 -0
- data/ext/cs__assess_active_record_named/extconf.rb +2 -0
- data/ext/cs__assess_array/cs__assess_array.c +38 -0
- data/ext/cs__assess_array/cs__assess_array.h +9 -0
- data/ext/cs__assess_array/extconf.rb +2 -0
- data/ext/cs__assess_basic_object/cs__assess_basic_object.c +50 -0
- data/ext/cs__assess_basic_object/cs__assess_basic_object.h +17 -0
- data/ext/cs__assess_basic_object/extconf.rb +2 -0
- data/ext/cs__assess_fiber_track/cs__assess_fiber_track.c +86 -0
- data/ext/cs__assess_fiber_track/cs__assess_fiber_track.h +34 -0
- data/ext/cs__assess_fiber_track/extconf.rb +2 -0
- data/ext/cs__assess_hash/cs__assess_hash.c +64 -0
- data/ext/cs__assess_hash/cs__assess_hash.h +24 -0
- data/ext/cs__assess_hash/extconf.rb +2 -0
- data/ext/cs__assess_kernel/cs__assess_kernel.c +36 -0
- data/ext/cs__assess_kernel/cs__assess_kernel.h +10 -0
- data/ext/cs__assess_kernel/extconf.rb +2 -0
- data/ext/cs__assess_marshal_module/cs__assess_marshal_module.c +47 -0
- data/ext/cs__assess_marshal_module/cs__assess_marshal_module.h +18 -0
- data/ext/cs__assess_marshal_module/extconf.rb +2 -0
- data/ext/cs__assess_module/cs__assess_module.c +78 -0
- data/ext/cs__assess_module/cs__assess_module.h +25 -0
- data/ext/cs__assess_module/extconf.rb +2 -0
- data/ext/cs__assess_regexp/cs__assess_regexp.c +48 -0
- data/ext/cs__assess_regexp/cs__assess_regexp.h +22 -0
- data/ext/cs__assess_regexp/extconf.rb +2 -0
- data/ext/cs__assess_regexp_track/cs__assess_regexp_track.c +63 -0
- data/ext/cs__assess_regexp_track/cs__assess_regexp_track.h +29 -0
- data/ext/cs__assess_regexp_track/extconf.rb +2 -0
- data/ext/cs__assess_string/cs__assess_string.c +38 -0
- data/ext/cs__assess_string/cs__assess_string.h +19 -0
- data/ext/cs__assess_string/extconf.rb +2 -0
- data/ext/cs__assess_string_interpolation26/cs__assess_string_interpolation26.c +31 -0
- data/ext/cs__assess_string_interpolation26/cs__assess_string_interpolation26.h +13 -0
- data/ext/cs__assess_string_interpolation26/extconf.rb +2 -0
- data/ext/cs__common/cs__common.c +60 -0
- data/ext/cs__common/cs__common.h +28 -0
- data/ext/cs__common/extconf.rb +20 -0
- data/ext/cs__contrast_patch/cs__contrast_patch.c +445 -0
- data/ext/cs__contrast_patch/cs__contrast_patch.h +196 -0
- data/ext/cs__contrast_patch/extconf.rb +2 -0
- data/ext/cs__protect_kernel/cs__protect_kernel.c +37 -0
- data/ext/cs__protect_kernel/cs__protect_kernel.h +11 -0
- data/ext/cs__protect_kernel/extconf.rb +2 -0
- data/ext/cs__scope/cs__scope.c +96 -0
- data/ext/cs__scope/cs__scope.h +33 -0
- data/ext/cs__scope/extconf.rb +2 -0
- data/ext/extconf_common.rb +49 -0
- data/funchook/LICENSE +360 -0
- data/funchook/Makefile +29 -0
- data/funchook/Makefile.in +29 -0
- data/funchook/README.md +121 -0
- data/funchook/appveyor.yml +42 -0
- data/funchook/autogen.sh +3 -0
- data/funchook/autom4te.cache/output.0 +4976 -0
- data/funchook/autom4te.cache/requests +78 -0
- data/funchook/autom4te.cache/traces.0 +364 -0
- data/funchook/config.guess +1530 -0
- data/funchook/config.log +490 -0
- data/funchook/config.status +1016 -0
- data/funchook/config.sub +1773 -0
- data/funchook/configure +4976 -0
- data/funchook/configure.ac +59 -0
- data/funchook/distorm/COPYING +26 -0
- data/funchook/distorm/MANIFEST +25 -0
- data/funchook/distorm/MANIFEST.in +4 -0
- data/funchook/distorm/README.md +12 -0
- data/funchook/distorm/disOps/disOps.py +795 -0
- data/funchook/distorm/disOps/x86db.py +404 -0
- data/funchook/distorm/disOps/x86header.py +247 -0
- data/funchook/distorm/disOps/x86sets.py +1664 -0
- data/funchook/distorm/examples/cs/TestdiStorm/Program.cs +79 -0
- data/funchook/distorm/examples/cs/TestdiStorm/Properties/AssemblyInfo.cs +36 -0
- data/funchook/distorm/examples/cs/TestdiStorm/TestdiStorm.csproj +69 -0
- data/funchook/distorm/examples/cs/distorm-net.sln +26 -0
- data/funchook/distorm/examples/cs/distorm-net/CodeInfo.cs +23 -0
- data/funchook/distorm/examples/cs/distorm-net/DecodedInst.cs +15 -0
- data/funchook/distorm/examples/cs/distorm-net/DecodedResult.cs +14 -0
- data/funchook/distorm/examples/cs/distorm-net/DecomposedInst.cs +36 -0
- data/funchook/distorm/examples/cs/distorm-net/DecomposedResult.cs +14 -0
- data/funchook/distorm/examples/cs/distorm-net/Opcodes.cs +1268 -0
- data/funchook/distorm/examples/cs/distorm-net/Opcodes.tt +37 -0
- data/funchook/distorm/examples/cs/distorm-net/Operand.cs +25 -0
- data/funchook/distorm/examples/cs/distorm-net/Properties/AssemblyInfo.cs +36 -0
- data/funchook/distorm/examples/cs/distorm-net/diStorm3.cs +411 -0
- data/funchook/distorm/examples/cs/distorm-net/distorm-net.csproj +80 -0
- data/funchook/distorm/examples/cs/readme +3 -0
- data/funchook/distorm/examples/ddk/README +48 -0
- data/funchook/distorm/examples/ddk/distorm.ini +11 -0
- data/funchook/distorm/examples/ddk/dummy.c +15 -0
- data/funchook/distorm/examples/ddk/main.c +91 -0
- data/funchook/distorm/examples/ddk/makefile +1 -0
- data/funchook/distorm/examples/ddk/sources +10 -0
- data/funchook/distorm/examples/java/Makefile +23 -0
- data/funchook/distorm/examples/java/distorm/src/Main.java +43 -0
- data/funchook/distorm/examples/java/distorm/src/diStorm3/CodeInfo.java +27 -0
- data/funchook/distorm/examples/java/distorm/src/diStorm3/DecodedInst.java +32 -0
- data/funchook/distorm/examples/java/distorm/src/diStorm3/DecodedResult.java +11 -0
- data/funchook/distorm/examples/java/distorm/src/diStorm3/DecomposedInst.java +89 -0
- data/funchook/distorm/examples/java/distorm/src/diStorm3/DecomposedResult.java +11 -0
- data/funchook/distorm/examples/java/distorm/src/diStorm3/OpcodeEnum.java +131 -0
- data/funchook/distorm/examples/java/distorm/src/diStorm3/Opcodes.java +1123 -0
- data/funchook/distorm/examples/java/distorm/src/diStorm3/Operand.java +24 -0
- data/funchook/distorm/examples/java/distorm/src/diStorm3/distorm3.java +41 -0
- data/funchook/distorm/examples/java/jdistorm.c +405 -0
- data/funchook/distorm/examples/java/jdistorm.h +40 -0
- data/funchook/distorm/examples/java/jdistorm.sln +20 -0
- data/funchook/distorm/examples/java/jdistorm.vcproj +208 -0
- data/funchook/distorm/examples/linux/Makefile +15 -0
- data/funchook/distorm/examples/linux/main.c +181 -0
- data/funchook/distorm/examples/tests/Makefile +15 -0
- data/funchook/distorm/examples/tests/main.cpp +42 -0
- data/funchook/distorm/examples/tests/main.py +66 -0
- data/funchook/distorm/examples/tests/test_distorm3.py +1672 -0
- data/funchook/distorm/examples/tests/tests.sln +20 -0
- data/funchook/distorm/examples/tests/tests.vcxproj +82 -0
- data/funchook/distorm/examples/tests/tests.vcxproj.filters +22 -0
- data/funchook/distorm/examples/win32/disasm.sln +25 -0
- data/funchook/distorm/examples/win32/disasm.vcxproj +201 -0
- data/funchook/distorm/examples/win32/disasm.vcxproj.filters +14 -0
- data/funchook/distorm/examples/win32/main.cpp +163 -0
- data/funchook/distorm/include/distorm.h +482 -0
- data/funchook/distorm/include/mnemonics.h +301 -0
- data/funchook/distorm/make/linux/Makefile +28 -0
- data/funchook/distorm/make/mac/Makefile +24 -0
- data/funchook/distorm/make/win32/cdistorm.vcxproj +239 -0
- data/funchook/distorm/make/win32/cdistorm.vcxproj.filters +80 -0
- data/funchook/distorm/make/win32/distorm.sln +25 -0
- data/funchook/distorm/make/win32/resource.h +14 -0
- data/funchook/distorm/make/win32/resource.rc +99 -0
- data/funchook/distorm/python/distorm3/__init__.py +957 -0
- data/funchook/distorm/python/distorm3/sample.py +51 -0
- data/funchook/distorm/setup.cfg +10 -0
- data/funchook/distorm/setup.py +266 -0
- data/funchook/distorm/src/config.h +169 -0
- data/funchook/distorm/src/decoder.c +641 -0
- data/funchook/distorm/src/decoder.h +33 -0
- data/funchook/distorm/src/distorm.c +413 -0
- data/funchook/distorm/src/instructions.c +597 -0
- data/funchook/distorm/src/instructions.h +463 -0
- data/funchook/distorm/src/insts.c +7939 -0
- data/funchook/distorm/src/insts.h +64 -0
- data/funchook/distorm/src/mnemonics.c +284 -0
- data/funchook/distorm/src/operands.c +1290 -0
- data/funchook/distorm/src/operands.h +28 -0
- data/funchook/distorm/src/prefix.c +368 -0
- data/funchook/distorm/src/prefix.h +64 -0
- data/funchook/distorm/src/textdefs.c +172 -0
- data/funchook/distorm/src/textdefs.h +57 -0
- data/funchook/distorm/src/wstring.c +47 -0
- data/funchook/distorm/src/wstring.h +35 -0
- data/funchook/distorm/src/x86defs.h +82 -0
- data/funchook/include/funchook.h +123 -0
- data/funchook/install-sh +527 -0
- data/funchook/src/Makefile +70 -0
- data/funchook/src/Makefile.in +70 -0
- data/funchook/src/__strerror.h +109 -0
- data/funchook/src/config.h +101 -0
- data/funchook/src/config.h.in +100 -0
- data/funchook/src/decoder.o +0 -0
- data/funchook/src/distorm.o +0 -0
- data/funchook/src/funchook.c +440 -0
- data/funchook/src/funchook.o +0 -0
- data/funchook/src/funchook_internal.h +155 -0
- data/funchook/src/funchook_io.c +182 -0
- data/funchook/src/funchook_io.h +64 -0
- data/funchook/src/funchook_io.o +0 -0
- data/funchook/src/funchook_syscall.S +134 -0
- data/funchook/src/funchook_syscall.o +0 -0
- data/funchook/src/funchook_unix.c +480 -0
- data/funchook/src/funchook_unix.o +0 -0
- data/funchook/src/funchook_windows.c +397 -0
- data/funchook/src/funchook_x86.c +622 -0
- data/funchook/src/funchook_x86.o +0 -0
- data/funchook/src/instructions.o +0 -0
- data/funchook/src/insts.o +0 -0
- data/funchook/src/libfunchook.so +0 -0
- data/funchook/src/mnemonics.o +0 -0
- data/funchook/src/operands.o +0 -0
- data/funchook/src/os_func.c +115 -0
- data/funchook/src/os_func.h +75 -0
- data/funchook/src/os_func.o +0 -0
- data/funchook/src/os_func_unix.c +94 -0
- data/funchook/src/os_func_unix.o +0 -0
- data/funchook/src/os_func_windows.c +32 -0
- data/funchook/src/prefix.o +0 -0
- data/funchook/src/printf_base.c +1688 -0
- data/funchook/src/printf_base.h +46 -0
- data/funchook/src/printf_base.o +0 -0
- data/funchook/src/textdefs.o +0 -0
- data/funchook/src/wstring.o +0 -0
- data/funchook/test/Makefile +43 -0
- data/funchook/test/Makefile.in +43 -0
- data/funchook/test/funchook_test +0 -0
- data/funchook/test/libfunchook_test.c +25 -0
- data/funchook/test/libfunchook_test.so +0 -0
- data/funchook/test/libfunchook_test2.c +18 -0
- data/funchook/test/suffix.list +600 -0
- data/funchook/test/test_main.c +430 -0
- data/funchook/test/test_main.o +0 -0
- data/funchook/test/x86_64_test.S +10 -0
- data/funchook/test/x86_64_test.o +0 -0
- data/funchook/test/x86_test.S +339 -0
- data/funchook/win32/config.h +1 -0
- data/funchook/win32/funchook.sln +52 -0
- data/funchook/win32/funchook.vcxproj +188 -0
- data/funchook/win32/funchook.vcxproj.filters +84 -0
- data/funchook/win32/funchook_test.vcxproj +170 -0
- data/funchook/win32/funchook_test.vcxproj.filters +22 -0
- data/funchook/win32/funchook_test_dll.vcxproj +184 -0
- data/funchook/win32/funchook_test_dll.vcxproj.filters +30 -0
- data/funchook/win32/funchook_test_exe.def +3 -0
- data/lib/contrast-agent.rb +8 -0
- data/lib/contrast.rb +57 -0
- data/lib/contrast/agent.rb +80 -0
- data/lib/contrast/agent/assess.rb +45 -0
- data/lib/contrast/agent/assess/adjusted_span.rb +25 -0
- data/lib/contrast/agent/assess/class_reverter.rb +82 -0
- data/lib/contrast/agent/assess/contrast_event.rb +398 -0
- data/lib/contrast/agent/assess/frozen_properties.rb +41 -0
- data/lib/contrast/agent/assess/insulator.rb +53 -0
- data/lib/contrast/agent/assess/policy/dynamic_source_factory.rb +78 -0
- data/lib/contrast/agent/assess/policy/patcher.rb +85 -0
- data/lib/contrast/agent/assess/policy/policy.rb +116 -0
- data/lib/contrast/agent/assess/policy/policy_node.rb +289 -0
- data/lib/contrast/agent/assess/policy/policy_scanner.rb +44 -0
- data/lib/contrast/agent/assess/policy/preshift.rb +94 -0
- data/lib/contrast/agent/assess/policy/propagation_method.rb +260 -0
- data/lib/contrast/agent/assess/policy/propagation_node.rb +127 -0
- data/lib/contrast/agent/assess/policy/propagator.rb +35 -0
- data/lib/contrast/agent/assess/policy/propagator/append.rb +54 -0
- data/lib/contrast/agent/assess/policy/propagator/base.rb +37 -0
- data/lib/contrast/agent/assess/policy/propagator/center.rb +73 -0
- data/lib/contrast/agent/assess/policy/propagator/custom.rb +36 -0
- data/lib/contrast/agent/assess/policy/propagator/database_write.rb +62 -0
- data/lib/contrast/agent/assess/policy/propagator/insert.rb +55 -0
- data/lib/contrast/agent/assess/policy/propagator/keep.rb +26 -0
- data/lib/contrast/agent/assess/policy/propagator/next.rb +42 -0
- data/lib/contrast/agent/assess/policy/propagator/prepend.rb +50 -0
- data/lib/contrast/agent/assess/policy/propagator/remove.rb +76 -0
- data/lib/contrast/agent/assess/policy/propagator/replace.rb +27 -0
- data/lib/contrast/agent/assess/policy/propagator/reverse.rb +38 -0
- data/lib/contrast/agent/assess/policy/propagator/select.rb +86 -0
- data/lib/contrast/agent/assess/policy/propagator/splat.rb +60 -0
- data/lib/contrast/agent/assess/policy/propagator/split.rb +49 -0
- data/lib/contrast/agent/assess/policy/propagator/substitution.rb +169 -0
- data/lib/contrast/agent/assess/policy/propagator/trim.rb +81 -0
- data/lib/contrast/agent/assess/policy/rewriter_patch.rb +79 -0
- data/lib/contrast/agent/assess/policy/source_method.rb +209 -0
- data/lib/contrast/agent/assess/policy/source_node.rb +62 -0
- data/lib/contrast/agent/assess/policy/trigger_method.rb +209 -0
- data/lib/contrast/agent/assess/policy/trigger_node.rb +198 -0
- data/lib/contrast/agent/assess/policy/trigger_validation/ssrf_validator.rb +77 -0
- data/lib/contrast/agent/assess/policy/trigger_validation/trigger_validation.rb +31 -0
- data/lib/contrast/agent/assess/policy/trigger_validation/xss_validator.rb +40 -0
- data/lib/contrast/agent/assess/properties.rb +392 -0
- data/lib/contrast/agent/assess/rule.rb +18 -0
- data/lib/contrast/agent/assess/rule/base.rb +72 -0
- data/lib/contrast/agent/assess/rule/csrf.rb +66 -0
- data/lib/contrast/agent/assess/rule/csrf/csrf_action.rb +28 -0
- data/lib/contrast/agent/assess/rule/csrf/csrf_applicator.rb +69 -0
- data/lib/contrast/agent/assess/rule/csrf/csrf_watcher.rb +132 -0
- data/lib/contrast/agent/assess/rule/provider.rb +21 -0
- data/lib/contrast/agent/assess/rule/provider/hardcoded_key.rb +62 -0
- data/lib/contrast/agent/assess/rule/provider/hardcoded_password.rb +73 -0
- data/lib/contrast/agent/assess/rule/provider/hardcoded_value_rule.rb +121 -0
- data/lib/contrast/agent/assess/rule/redos.rb +68 -0
- data/lib/contrast/agent/assess/rule/response_scanning_rule.rb +47 -0
- data/lib/contrast/agent/assess/rule/response_watcher.rb +36 -0
- data/lib/contrast/agent/assess/rule/watcher.rb +36 -0
- data/lib/contrast/agent/assess/tag.rb +151 -0
- data/lib/contrast/agent/at_exit_hook.rb +33 -0
- data/lib/contrast/agent/class_reopener.rb +195 -0
- data/lib/contrast/agent/deadzone/policy/deadzone_node.rb +26 -0
- data/lib/contrast/agent/deadzone/policy/policy.rb +57 -0
- data/lib/contrast/agent/disable_reaction.rb +24 -0
- data/lib/contrast/agent/exclusion_matcher.rb +190 -0
- data/lib/contrast/agent/feature_state.rb +379 -0
- data/lib/contrast/agent/inventory/policy/policy.rb +32 -0
- data/lib/contrast/agent/inventory/policy/trigger_node.rb +22 -0
- data/lib/contrast/agent/logger_manager.rb +116 -0
- data/lib/contrast/agent/middleware.rb +352 -0
- data/lib/contrast/agent/module_data.rb +16 -0
- data/lib/contrast/agent/patching/policy/after_load_patch.rb +37 -0
- data/lib/contrast/agent/patching/policy/after_load_patcher.rb +58 -0
- data/lib/contrast/agent/patching/policy/method_policy.rb +94 -0
- data/lib/contrast/agent/patching/policy/module_policy.rb +116 -0
- data/lib/contrast/agent/patching/policy/patch.rb +312 -0
- data/lib/contrast/agent/patching/policy/patch_status.rb +192 -0
- data/lib/contrast/agent/patching/policy/patcher.rb +310 -0
- data/lib/contrast/agent/patching/policy/policy.rb +138 -0
- data/lib/contrast/agent/patching/policy/policy_node.rb +80 -0
- data/lib/contrast/agent/patching/policy/policy_unpatcher.rb +28 -0
- data/lib/contrast/agent/patching/policy/trigger_node.rb +81 -0
- data/lib/contrast/agent/protect/policy/policy.rb +37 -0
- data/lib/contrast/agent/protect/policy/trigger_node.rb +23 -0
- data/lib/contrast/agent/protect/rule.rb +58 -0
- data/lib/contrast/agent/protect/rule/base.rb +300 -0
- data/lib/contrast/agent/protect/rule/base_service.rb +88 -0
- data/lib/contrast/agent/protect/rule/cmd_injection.rb +156 -0
- data/lib/contrast/agent/protect/rule/csrf.rb +118 -0
- data/lib/contrast/agent/protect/rule/csrf/csrf_evaluator.rb +103 -0
- data/lib/contrast/agent/protect/rule/csrf/csrf_token_injector.rb +85 -0
- data/lib/contrast/agent/protect/rule/default_scanner.rb +300 -0
- data/lib/contrast/agent/protect/rule/deserialization.rb +193 -0
- data/lib/contrast/agent/protect/rule/http_method_tampering.rb +80 -0
- data/lib/contrast/agent/protect/rule/no_sqli.rb +101 -0
- data/lib/contrast/agent/protect/rule/no_sqli/mongo_no_sql_scanner.rb +40 -0
- data/lib/contrast/agent/protect/rule/path_traversal.rb +143 -0
- data/lib/contrast/agent/protect/rule/sqli.rb +101 -0
- data/lib/contrast/agent/protect/rule/sqli/default_sql_scanner.rb +16 -0
- data/lib/contrast/agent/protect/rule/sqli/mysql_sql_scanner.rb +38 -0
- data/lib/contrast/agent/protect/rule/sqli/postgres_sql_scanner.rb +22 -0
- data/lib/contrast/agent/protect/rule/sqli/sqlite_sql_scanner.rb +19 -0
- data/lib/contrast/agent/protect/rule/unsafe_file_upload.rb +20 -0
- data/lib/contrast/agent/protect/rule/xss.rb +24 -0
- data/lib/contrast/agent/protect/rule/xxe.rb +120 -0
- data/lib/contrast/agent/protect/rule/xxe/entity_wrapper.rb +82 -0
- data/lib/contrast/agent/railtie.rb +30 -0
- data/lib/contrast/agent/reaction_processor.rb +47 -0
- data/lib/contrast/agent/request.rb +493 -0
- data/lib/contrast/agent/request_context.rb +225 -0
- data/lib/contrast/agent/require_state.rb +61 -0
- data/lib/contrast/agent/response.rb +215 -0
- data/lib/contrast/agent/rewriter.rb +244 -0
- data/lib/contrast/agent/scope.rb +28 -0
- data/lib/contrast/agent/service_heartbeat.rb +37 -0
- data/lib/contrast/agent/settings_state.rb +148 -0
- data/lib/contrast/agent/socket_client.rb +125 -0
- data/lib/contrast/agent/thread.rb +26 -0
- data/lib/contrast/agent/tracepoint_hook.rb +51 -0
- data/lib/contrast/agent/version.rb +8 -0
- data/lib/contrast/api.rb +17 -0
- data/lib/contrast/api/.gitkeep +0 -0
- data/lib/contrast/api/connection_status.rb +49 -0
- data/lib/contrast/api/socket.rb +43 -0
- data/lib/contrast/api/speedracer.rb +206 -0
- data/lib/contrast/api/tcp_socket.rb +31 -0
- data/lib/contrast/api/unix_socket.rb +25 -0
- data/lib/contrast/common_agent_configuration.rb +86 -0
- data/lib/contrast/components/agent.rb +85 -0
- data/lib/contrast/components/app_context.rb +188 -0
- data/lib/contrast/components/assess.rb +67 -0
- data/lib/contrast/components/config.rb +135 -0
- data/lib/contrast/components/contrast_service.rb +113 -0
- data/lib/contrast/components/heap_dump.rb +34 -0
- data/lib/contrast/components/interface.rb +178 -0
- data/lib/contrast/components/inventory.rb +23 -0
- data/lib/contrast/components/logger.rb +92 -0
- data/lib/contrast/components/protect.rb +38 -0
- data/lib/contrast/components/sampling.rb +41 -0
- data/lib/contrast/components/scope.rb +106 -0
- data/lib/contrast/components/settings.rb +140 -0
- data/lib/contrast/config.rb +33 -0
- data/lib/contrast/config/agent_configuration.rb +24 -0
- data/lib/contrast/config/application_configuration.rb +27 -0
- data/lib/contrast/config/assess_configuration.rb +22 -0
- data/lib/contrast/config/assess_rules_configuration.rb +18 -0
- data/lib/contrast/config/base_configuration.rb +105 -0
- data/lib/contrast/config/default_value.rb +16 -0
- data/lib/contrast/config/exception_configuration.rb +21 -0
- data/lib/contrast/config/heap_dump_configuration.rb +23 -0
- data/lib/contrast/config/inventory_configuration.rb +20 -0
- data/lib/contrast/config/logger_configuration.rb +20 -0
- data/lib/contrast/config/protect_configuration.rb +20 -0
- data/lib/contrast/config/protect_rule_configuration.rb +37 -0
- data/lib/contrast/config/protect_rules_configuration.rb +30 -0
- data/lib/contrast/config/root_configuration.rb +26 -0
- data/lib/contrast/config/ruby_configuration.rb +39 -0
- data/lib/contrast/config/sampling_configuration.rb +22 -0
- data/lib/contrast/config/server_configuration.rb +23 -0
- data/lib/contrast/config/service_configuration.rb +22 -0
- data/lib/contrast/configuration.rb +214 -0
- data/lib/contrast/core_extensions/assess.rb +51 -0
- data/lib/contrast/core_extensions/assess/array.rb +58 -0
- data/lib/contrast/core_extensions/assess/assess_extension.rb +145 -0
- data/lib/contrast/core_extensions/assess/basic_object.rb +15 -0
- data/lib/contrast/core_extensions/assess/erb.rb +42 -0
- data/lib/contrast/core_extensions/assess/exec_trigger.rb +48 -0
- data/lib/contrast/core_extensions/assess/fiber.rb +125 -0
- data/lib/contrast/core_extensions/assess/hash.rb +22 -0
- data/lib/contrast/core_extensions/assess/kernel.rb +95 -0
- data/lib/contrast/core_extensions/assess/module.rb +14 -0
- data/lib/contrast/core_extensions/assess/regexp.rb +206 -0
- data/lib/contrast/core_extensions/assess/string.rb +75 -0
- data/lib/contrast/core_extensions/assess/tilt_template_trigger.rb +73 -0
- data/lib/contrast/core_extensions/delegator.rb +14 -0
- data/lib/contrast/core_extensions/eval_trigger.rb +52 -0
- data/lib/contrast/core_extensions/inventory.rb +22 -0
- data/lib/contrast/core_extensions/inventory/datastores.rb +37 -0
- data/lib/contrast/core_extensions/module.rb +42 -0
- data/lib/contrast/core_extensions/object.rb +27 -0
- data/lib/contrast/core_extensions/protect.rb +20 -0
- data/lib/contrast/core_extensions/protect/applies_command_injection_rule.rb +70 -0
- data/lib/contrast/core_extensions/protect/applies_deserialization_rule.rb +58 -0
- data/lib/contrast/core_extensions/protect/applies_no_sqli_rule.rb +81 -0
- data/lib/contrast/core_extensions/protect/applies_path_traversal_rule.rb +119 -0
- data/lib/contrast/core_extensions/protect/applies_sqli_rule.rb +63 -0
- data/lib/contrast/core_extensions/protect/applies_xxe_rule.rb +141 -0
- data/lib/contrast/core_extensions/protect/kernel.rb +30 -0
- data/lib/contrast/core_extensions/protect/psych.rb +7 -0
- data/lib/contrast/core_extensions/thread.rb +31 -0
- data/lib/contrast/internal_exception.rb +8 -0
- data/lib/contrast/rails_extensions/assess/action_controller_inheritance.rb +48 -0
- data/lib/contrast/rails_extensions/assess/active_record.rb +32 -0
- data/lib/contrast/rails_extensions/assess/active_record_named.rb +61 -0
- data/lib/contrast/rails_extensions/assess/configuration.rb +26 -0
- data/lib/contrast/rails_extensions/buffer.rb +30 -0
- data/lib/contrast/rails_extensions/rack.rb +45 -0
- data/lib/contrast/security_exception.rb +14 -0
- data/lib/contrast/sinatra_extensions/assess/cookie.rb +26 -0
- data/lib/contrast/sinatra_extensions/inventory/sinatra_base.rb +59 -0
- data/lib/contrast/tasks/service.rb +95 -0
- data/lib/contrast/utils/assess/sampling_util.rb +96 -0
- data/lib/contrast/utils/assess/tracking_util.rb +39 -0
- data/lib/contrast/utils/boolean_util.rb +33 -0
- data/lib/contrast/utils/cache.rb +69 -0
- data/lib/contrast/utils/class_util.rb +58 -0
- data/lib/contrast/utils/comment_range.rb +19 -0
- data/lib/contrast/utils/data_store_util.rb +23 -0
- data/lib/contrast/utils/duck_utils.rb +58 -0
- data/lib/contrast/utils/env_configuration_item.rb +52 -0
- data/lib/contrast/utils/environment_util.rb +152 -0
- data/lib/contrast/utils/freeze_util.rb +36 -0
- data/lib/contrast/utils/gemfile_reader.rb +191 -0
- data/lib/contrast/utils/hash_digest.rb +148 -0
- data/lib/contrast/utils/heap_dump_util.rb +113 -0
- data/lib/contrast/utils/invalid_configuration_util.rb +88 -0
- data/lib/contrast/utils/inventory_util.rb +126 -0
- data/lib/contrast/utils/io_util.rb +61 -0
- data/lib/contrast/utils/object_share.rb +117 -0
- data/lib/contrast/utils/operating_environment.rb +38 -0
- data/lib/contrast/utils/os.rb +49 -0
- data/lib/contrast/utils/path_util.rb +151 -0
- data/lib/contrast/utils/performs_logging.rb +152 -0
- data/lib/contrast/utils/preflight_util.rb +13 -0
- data/lib/contrast/utils/prevent_serialization.rb +52 -0
- data/lib/contrast/utils/rack_assess_session_cookie.rb +104 -0
- data/lib/contrast/utils/rails_assess_configuration.rb +95 -0
- data/lib/contrast/utils/random_util.rb +22 -0
- data/lib/contrast/utils/resource_loader.rb +23 -0
- data/lib/contrast/utils/ruby_ast_rewriter.rb +74 -0
- data/lib/contrast/utils/scope_util.rb +99 -0
- data/lib/contrast/utils/service_response_util.rb +116 -0
- data/lib/contrast/utils/service_sender_util.rb +98 -0
- data/lib/contrast/utils/sha256_builder.rb +69 -0
- data/lib/contrast/utils/sinatra_helper.rb +49 -0
- data/lib/contrast/utils/stack_trace_utils.rb +209 -0
- data/lib/contrast/utils/string_utils.rb +72 -0
- data/lib/contrast/utils/tag_util.rb +139 -0
- data/lib/contrast/utils/thread_tracker.rb +54 -0
- data/lib/contrast/utils/timer.rb +78 -0
- data/resources/assess/policy.json +1673 -0
- data/resources/csrf/inject.js +44 -0
- data/resources/deadzone/policy.json +55 -0
- data/resources/factory-bot-spec/spec_helper.rb +30 -0
- data/resources/inventory/policy.json +110 -0
- data/resources/protect/policy.json +417 -0
- data/resources/rubocops/kernel/catch_cop.rb +37 -0
- data/resources/rubocops/kernel/require_cop.rb +37 -0
- data/resources/rubocops/kernel/require_relative_cop.rb +33 -0
- data/resources/rubocops/module/autoload_cop.rb +37 -0
- data/resources/rubocops/module/const_defined_cop.rb +37 -0
- data/resources/rubocops/module/const_get_cop.rb +37 -0
- data/resources/rubocops/module/const_set_cop.rb +37 -0
- data/resources/rubocops/module/constants_cop.rb +37 -0
- data/resources/rubocops/module/name_cop.rb +37 -0
- data/resources/rubocops/object/class_cop.rb +37 -0
- data/resources/rubocops/object/freeze_cop.rb +37 -0
- data/resources/rubocops/object/frozen_cop.rb +37 -0
- data/resources/rubocops/object/is_a_cop.rb +37 -0
- data/resources/rubocops/object/method_cop.rb +37 -0
- data/resources/rubocops/object/respond_to_cop.rb +37 -0
- data/resources/rubocops/object/singleton_class_cop.rb +37 -0
- data/resources/rubocops/regexp/spelling_cop.rb +44 -0
- data/resources/rubocops/thread/new_cop.rb +39 -0
- data/resources/ruby-spec/ancestors_spec.rb +70 -0
- data/resources/ruby-spec/modulo_spec.rb +831 -0
- data/resources/ruby-spec/parameters_spec.rb +261 -0
- data/resources/ruby-spec/ruby_spec_spec_helper.rb +35 -0
- data/resources/test_marker.txt +1 -0
- data/ruby-agent.gemspec +129 -0
- data/service_executables/.gitkeep +0 -0
- data/service_executables/VERSION +1 -0
- data/service_executables/linux/contrast-service +0 -0
- data/service_executables/mac/contrast-service +0 -0
- metadata +945 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
#include <funchook.h>
|
|
2
|
+
#include <ruby.h>
|
|
3
|
+
|
|
4
|
+
static VALUE regexp_class;
|
|
5
|
+
static VALUE track_rb_n_match;
|
|
6
|
+
static VALUE track_rb_pre_match;
|
|
7
|
+
static VALUE track_rb_post_match;
|
|
8
|
+
static VALUE track_rb_reg_match_last;
|
|
9
|
+
|
|
10
|
+
VALUE rb_reg_match_pre(VALUE match);
|
|
11
|
+
static VALUE *(*rb_reg_match_pre_original)(VALUE match);
|
|
12
|
+
|
|
13
|
+
VALUE rb_reg_match_post(VALUE match);
|
|
14
|
+
static VALUE *(*rb_reg_match_post_original)(VALUE match);
|
|
15
|
+
|
|
16
|
+
VALUE rb_reg_match_last(VALUE match);
|
|
17
|
+
static VALUE *(*rb_reg_match_last_original)(VALUE match);
|
|
18
|
+
|
|
19
|
+
VALUE rb_reg_nth_match(int nth, VALUE match);
|
|
20
|
+
static VALUE *(*rb_reg_nth_match_original)(int nth, VALUE match);
|
|
21
|
+
|
|
22
|
+
static VALUE rb_reg_match_pre_hook(VALUE match);
|
|
23
|
+
static VALUE rb_reg_match_post_hook(VALUE match);
|
|
24
|
+
static VALUE rb_reg_match_last_hook(VALUE match);
|
|
25
|
+
static VALUE rb_reg_nth_match_hook(int nth, VALUE match);
|
|
26
|
+
|
|
27
|
+
static int install_regexp_hooks();
|
|
28
|
+
|
|
29
|
+
void Init_cs__assess_regexp_track(void);
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/* Copyright (c) 2020 Contrast Security, Inc. See
|
|
2
|
+
* https://www.contrastsecurity.com/enduser-terms-0317a for more details. */
|
|
3
|
+
|
|
4
|
+
#include "cs__assess_string.h"
|
|
5
|
+
#include "../cs__common/cs__common.h"
|
|
6
|
+
#include <ruby.h>
|
|
7
|
+
|
|
8
|
+
static VALUE contrast_assess_string_uminus(const VALUE obj) {
|
|
9
|
+
VALUE dup, tracked;
|
|
10
|
+
if (!OBJ_FROZEN(obj)) {
|
|
11
|
+
tracked = rb_funcall(obj, rb_sym_cs_tracked, 0);
|
|
12
|
+
if (RTEST(tracked)) {
|
|
13
|
+
/*
|
|
14
|
+
* If the object is not frozen and the object is tracked, we cheat.
|
|
15
|
+
* We dup and then freeze to replicate the behavior of str_uminus in
|
|
16
|
+
* string.c, but we ignore any other monkey patches on String#-@
|
|
17
|
+
*/
|
|
18
|
+
dup = rb_funcall(obj, rb_sym_dup, 0);
|
|
19
|
+
rb_funcall(dup, rb_sym_freeze, 0);
|
|
20
|
+
return dup;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
/* in all other cases, preserve monkey patching and c call */
|
|
24
|
+
return rb_funcall(obj, rb_sym_assess_string_uminus, 0);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
void Init_cs__assess_string(void) {
|
|
28
|
+
VALUE string_class;
|
|
29
|
+
|
|
30
|
+
rb_sym_dup = rb_intern("dup");
|
|
31
|
+
rb_sym_freeze = rb_intern("freeze");
|
|
32
|
+
rb_sym_assess_string_uminus = rb_intern("cs__patched_minus_at");
|
|
33
|
+
|
|
34
|
+
string_class = rb_define_class("String", rb_cObject);
|
|
35
|
+
/* -@ */
|
|
36
|
+
contrast_alias_method(string_class, "cs__patched_minus_at", "-@");
|
|
37
|
+
rb_define_method(string_class, "-@", contrast_assess_string_uminus, 0);
|
|
38
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
#include <ruby.h>
|
|
2
|
+
|
|
3
|
+
static VALUE rb_sym_assess_string_uminus;
|
|
4
|
+
static VALUE rb_sym_dup;
|
|
5
|
+
static VALUE rb_sym_freeze;
|
|
6
|
+
|
|
7
|
+
/*
|
|
8
|
+
* The String#-@ method calls to the str_uminus method in String.C. This method
|
|
9
|
+
* differs in behavior from String#freeze in that it removes instance variables
|
|
10
|
+
* from the object when it is frozen. Rather than implement a trace map for
|
|
11
|
+
* frozen things (to which you cannot implment weak references, resulting in
|
|
12
|
+
* a potential memory leak), we'll override the method so that, in essence, it
|
|
13
|
+
* never calls String#-@ for unfrozen and tracked objects, but instead calls
|
|
14
|
+
* String#freeze, which will leave our properties alone.
|
|
15
|
+
* -HM
|
|
16
|
+
*/
|
|
17
|
+
static VALUE contrast_assess_string_uminus(const VALUE obj);
|
|
18
|
+
|
|
19
|
+
void Init_cs__assess_string(void);
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/* Copyright (c) 2020 Contrast Security, Inc. See
|
|
2
|
+
* https://www.contrastsecurity.com/enduser-terms-0317a for more details. */
|
|
3
|
+
|
|
4
|
+
#include "cs__assess_string_interpolation26.h"
|
|
5
|
+
#include "../cs__common/cs__common.h"
|
|
6
|
+
#include <funchook.h>
|
|
7
|
+
#include <ruby.h>
|
|
8
|
+
|
|
9
|
+
static VALUE rb_str_concat_literals_hook(size_t num, VALUE *strary) {
|
|
10
|
+
VALUE result = rb_str_concat_literals_original(num, strary);
|
|
11
|
+
VALUE rb_params = rb_ary_new_from_values((int)num, strary);
|
|
12
|
+
rb_funcall(string_class, track_interpolation, 2, rb_params, result);
|
|
13
|
+
return result;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
static int install_hooks() {
|
|
17
|
+
funchook_t *funchook = funchook_create();
|
|
18
|
+
|
|
19
|
+
rb_str_concat_literals_original = rb_str_concat_literals;
|
|
20
|
+
funchook_prepare(funchook, (void **)&rb_str_concat_literals_original,
|
|
21
|
+
rb_str_concat_literals_hook);
|
|
22
|
+
|
|
23
|
+
funchook_install(funchook, 0);
|
|
24
|
+
return 0;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
void Init_cs__assess_string_interpolation26(void) {
|
|
28
|
+
string_class = rb_define_class_under(core_assess, "StringPropagator", rb_cObject);
|
|
29
|
+
track_interpolation = rb_intern("track_interpolation");
|
|
30
|
+
install_hooks();
|
|
31
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#include <ruby.h>
|
|
2
|
+
|
|
3
|
+
static VALUE string_class;
|
|
4
|
+
static VALUE track_interpolation;
|
|
5
|
+
|
|
6
|
+
void *rb_str_concat_literals(size_t num, const VALUE *strary);
|
|
7
|
+
void *(*rb_str_concat_literals_original)(size_t, const VALUE *);
|
|
8
|
+
|
|
9
|
+
static VALUE rb_str_concat_literals_hook(size_t num, VALUE *strary);
|
|
10
|
+
|
|
11
|
+
static int install_hooks();
|
|
12
|
+
|
|
13
|
+
void Init_cs__assess_string_interpolation26(void);
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/* Copyright (c) 2020 Contrast Security, Inc. See
|
|
2
|
+
* https://www.contrastsecurity.com/enduser-terms-0317a for more details. */
|
|
3
|
+
|
|
4
|
+
#include "cs__common.h"
|
|
5
|
+
#include <ruby.h>
|
|
6
|
+
|
|
7
|
+
/* Globals */
|
|
8
|
+
/* These are defined w/ `extern` in the header */
|
|
9
|
+
VALUE contrast, agent, patching, policy, assess, core_extensions, core_assess;
|
|
10
|
+
|
|
11
|
+
VALUE rb_sym_enter_scope;
|
|
12
|
+
VALUE rb_sym_exit_scope;
|
|
13
|
+
VALUE rb_sym_in_scope;
|
|
14
|
+
VALUE rb_sym_skip_contrast_analysis;
|
|
15
|
+
VALUE rb_sym_skip_assess_analysis;
|
|
16
|
+
VALUE rb_sym_method;
|
|
17
|
+
VALUE rb_sym_cs_tracked;
|
|
18
|
+
/* end globals */
|
|
19
|
+
|
|
20
|
+
void contrast_alias_method(const VALUE target, const char *to,
|
|
21
|
+
const char *from) {
|
|
22
|
+
rb_funcall(target, cs__send_method, 3, cs__alias_method_sym,
|
|
23
|
+
ID2SYM(rb_intern(to)), ID2SYM(rb_intern(from)));
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
VALUE contrast_patcher() {
|
|
27
|
+
return patcher;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
void Init_cs__common(void) {
|
|
31
|
+
cs__send_method = rb_intern("send");
|
|
32
|
+
cs__alias_method_sym = ID2SYM(rb_intern("alias_method"));
|
|
33
|
+
|
|
34
|
+
/* Define symbols */
|
|
35
|
+
rb_sym_enter_scope = rb_intern("enter_contrast_scope!");
|
|
36
|
+
rb_sym_exit_scope = rb_intern("exit_contrast_scope!");
|
|
37
|
+
rb_sym_in_scope = rb_intern("in_contrast_scope?");
|
|
38
|
+
rb_sym_skip_contrast_analysis = rb_intern("skip_contrast_analysis?");
|
|
39
|
+
rb_sym_skip_assess_analysis = rb_intern("skip_assess_analysis?");
|
|
40
|
+
rb_sym_method = rb_intern("__method__");
|
|
41
|
+
rb_sym_cs_tracked = rb_intern("cs__tracked?");
|
|
42
|
+
|
|
43
|
+
/* Ensure definition of core Contrast instrumentation modules */
|
|
44
|
+
contrast = rb_define_module("Contrast");
|
|
45
|
+
agent = rb_define_module_under(contrast, "Agent");
|
|
46
|
+
|
|
47
|
+
assess = rb_define_module_under(agent, "Assess");
|
|
48
|
+
|
|
49
|
+
patching = rb_define_module_under(agent, "Patching");
|
|
50
|
+
policy = rb_define_module_under(patching, "Policy");
|
|
51
|
+
patcher = rb_define_module_under(policy, "Patch");
|
|
52
|
+
|
|
53
|
+
core_extensions = rb_define_module_under(contrast, "CoreExtensions");
|
|
54
|
+
core_assess = rb_define_module_under(core_extensions, "Assess");
|
|
55
|
+
|
|
56
|
+
/* Ensure ScopeUtil is set on the Contrast patcher */
|
|
57
|
+
VALUE utils = rb_define_module_under(contrast, "Utils");
|
|
58
|
+
VALUE scopeUtil = rb_define_module_under(utils, "ScopeUtil");
|
|
59
|
+
rb_extend_object(patcher, scopeUtil);
|
|
60
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
#ifndef __CS_COMMON
|
|
2
|
+
#define __CS_COMMON
|
|
3
|
+
|
|
4
|
+
#include <ruby.h>
|
|
5
|
+
|
|
6
|
+
static VALUE cs__send_method;
|
|
7
|
+
static VALUE cs__alias_method_sym;
|
|
8
|
+
|
|
9
|
+
extern VALUE contrast, agent, patching, policy, assess, core_extensions, core_assess;
|
|
10
|
+
|
|
11
|
+
extern VALUE rb_sym_enter_scope;
|
|
12
|
+
extern VALUE rb_sym_exit_scope;
|
|
13
|
+
extern VALUE rb_sym_in_scope;
|
|
14
|
+
extern VALUE rb_sym_skip_contrast_analysis;
|
|
15
|
+
extern VALUE rb_sym_skip_assess_analysis;
|
|
16
|
+
extern VALUE rb_sym_method;
|
|
17
|
+
extern VALUE rb_sym_cs_tracked;
|
|
18
|
+
|
|
19
|
+
static VALUE patcher;
|
|
20
|
+
|
|
21
|
+
void contrast_alias_method(const VALUE target, const char *to,
|
|
22
|
+
const char *from);
|
|
23
|
+
|
|
24
|
+
VALUE contrast_patcher();
|
|
25
|
+
|
|
26
|
+
void Init_cs__common(void);
|
|
27
|
+
|
|
28
|
+
#endif /* __CS_COMMON */
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
require 'mkmf'
|
|
2
|
+
|
|
3
|
+
require_relative '../../lib/contrast/agent/version'
|
|
4
|
+
installed_path = __dir__
|
|
5
|
+
|
|
6
|
+
origin = if (darwin = !(/darwin/ =~ RUBY_PLATFORM).nil?)
|
|
7
|
+
"@loader_path"
|
|
8
|
+
else
|
|
9
|
+
"\\$${ORIGIN}"
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
options = " -Wl,-rpath,#{origin}/../../shared_libraries"
|
|
13
|
+
|
|
14
|
+
if try_link('int main() {return 0;}', options)
|
|
15
|
+
$LDFLAGS << options
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
$LIBPATH << installed_path
|
|
19
|
+
|
|
20
|
+
create_makefile 'cs__common/cs__common'
|
|
@@ -0,0 +1,445 @@
|
|
|
1
|
+
/* Copyright (c) 2020 Contrast Security, Inc. See
|
|
2
|
+
* https://www.contrastsecurity.com/enduser-terms-0317a for more details. */
|
|
3
|
+
|
|
4
|
+
#include "cs__contrast_patch.h"
|
|
5
|
+
#include "../cs__common/cs__common.h"
|
|
6
|
+
#include <ruby.h>
|
|
7
|
+
|
|
8
|
+
VALUE build_preshift(const VALUE method_policy, const VALUE object,
|
|
9
|
+
const int argc, const VALUE *params) {
|
|
10
|
+
if (method_policy == Qnil) {
|
|
11
|
+
return Qnil;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
VALUE propagation_node, send, ret;
|
|
15
|
+
propagation_node = rb_funcall(method_policy, rb_sym_propagation_node, 0);
|
|
16
|
+
/* if there isn't a propagation node that applies to this method
|
|
17
|
+
* we don't need to build a preshift */
|
|
18
|
+
if (propagation_node == Qnil) {
|
|
19
|
+
return Qnil;
|
|
20
|
+
}
|
|
21
|
+
send = rb_ary_new_from_values(argc, params);
|
|
22
|
+
ret = rb_funcall(preshift_class, rb_sym_build_preshift, 3, propagation_node,
|
|
23
|
+
object, send);
|
|
24
|
+
return ret;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
VALUE contrast_patch_call_original(const VALUE *args) {
|
|
28
|
+
int argc;
|
|
29
|
+
VALUE method, method_id, object;
|
|
30
|
+
VALUE *params;
|
|
31
|
+
object = args[0];
|
|
32
|
+
method = args[1];
|
|
33
|
+
method_id = SYM2ID(method);
|
|
34
|
+
argc = NUM2INT(args[2]);
|
|
35
|
+
params = (VALUE *)args[3];
|
|
36
|
+
|
|
37
|
+
/* It looks like we can find the last Ruby block given so long as we don't
|
|
38
|
+
* change Ruby method scope (always call this function from C, not Ruby),
|
|
39
|
+
* which is the point of this C call.
|
|
40
|
+
*/
|
|
41
|
+
if (rb_block_given_p()) {
|
|
42
|
+
return rb_funcall_with_block(object, method_id, argc, params,
|
|
43
|
+
rb_block_proc());
|
|
44
|
+
} else {
|
|
45
|
+
return rb_funcall2(object, method_id, argc, params);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
VALUE contrast_call_pre_patch(const VALUE method_policy, const VALUE method,
|
|
50
|
+
const VALUE object, const int count,
|
|
51
|
+
const VALUE *params, const VALUE exception) {
|
|
52
|
+
/* For simplicity's sake, this Ruby method is responsible for
|
|
53
|
+
* exiting scope if it throws a SecurityException.
|
|
54
|
+
* When we start to macro rescues, we can change this.
|
|
55
|
+
*/
|
|
56
|
+
VALUE send;
|
|
57
|
+
send = rb_ary_new_from_values(count, params);
|
|
58
|
+
return rb_funcall(contrast_patcher(), rb_sym_contrast_apply_pre_patch, 5,
|
|
59
|
+
method_policy, method, exception, object, send);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
VALUE contrast_call_post_patch(const VALUE method_policy, const VALUE preshift,
|
|
63
|
+
const VALUE object, const VALUE ret,
|
|
64
|
+
const int count, const VALUE *params) {
|
|
65
|
+
VALUE send;
|
|
66
|
+
send = rb_ary_new_from_values(count, params);
|
|
67
|
+
|
|
68
|
+
VALUE block;
|
|
69
|
+
if (rb_block_given_p()) {
|
|
70
|
+
block = rb_block_proc();
|
|
71
|
+
} else {
|
|
72
|
+
block = Qnil;
|
|
73
|
+
}
|
|
74
|
+
return rb_funcall(contrast_patcher(), rb_sym_contrast_apply_post_patch, 6,
|
|
75
|
+
method_policy, preshift, object, ret, send, block);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
VALUE contrast_patch_call_rescue(const VALUE *args) {
|
|
79
|
+
int argc;
|
|
80
|
+
VALUE exception, object, preshift, method_policy, method;
|
|
81
|
+
VALUE *argv;
|
|
82
|
+
|
|
83
|
+
/* rb_errinfo() gives the value of $!, the exception that
|
|
84
|
+
* triggered a rescue block.
|
|
85
|
+
*/
|
|
86
|
+
exception = rb_errinfo();
|
|
87
|
+
|
|
88
|
+
object = args[0];
|
|
89
|
+
method = args[1];
|
|
90
|
+
argc = NUM2INT(args[2]);
|
|
91
|
+
argv = (VALUE *)args[3];
|
|
92
|
+
method_policy = args[4];
|
|
93
|
+
preshift = args[5];
|
|
94
|
+
|
|
95
|
+
contrast_call_post_patch(method_policy, preshift, object, Qnil, argc, argv);
|
|
96
|
+
|
|
97
|
+
/* exit scope */
|
|
98
|
+
rb_funcall(contrast_patcher(), rb_sym_exit_scope, 0);
|
|
99
|
+
|
|
100
|
+
/* reraise the exception that got us here */
|
|
101
|
+
rb_exc_raise(exception);
|
|
102
|
+
|
|
103
|
+
return Qnil;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
VALUE contrast_call_super(const VALUE *args) {
|
|
107
|
+
int argc = NUM2INT(args[0]);
|
|
108
|
+
VALUE *argv = (VALUE *)args[1];
|
|
109
|
+
|
|
110
|
+
return rb_call_super(argc, argv);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
VALUE contrast_patch_dispatch(const int argc, const VALUE *argv,
|
|
114
|
+
const patch_impl impl, const VALUE object) {
|
|
115
|
+
VALUE cs__method, known, method, ret, transformed_ret, original_ret,
|
|
116
|
+
method_policy, preshift;
|
|
117
|
+
VALUE original_args[4];
|
|
118
|
+
VALUE rescue_args[7];
|
|
119
|
+
|
|
120
|
+
int do_contrast, nested_scope;
|
|
121
|
+
|
|
122
|
+
/* Do Contrast analysis, unless our subsequent checks tell us no. */
|
|
123
|
+
do_contrast = 1;
|
|
124
|
+
|
|
125
|
+
/* Before we enter scope, see if we're already in scope.
|
|
126
|
+
* We only want to Contrast methods called out of all scope.
|
|
127
|
+
* Otherwise, we do things like propagate within propagators,
|
|
128
|
+
* which is unnecessary, or run Contrast analysis on Contrast code,
|
|
129
|
+
* which will never terminate.
|
|
130
|
+
*/
|
|
131
|
+
nested_scope = RTEST(rb_funcall(contrast_patcher(), rb_sym_in_scope, 0));
|
|
132
|
+
|
|
133
|
+
/* enter scope */
|
|
134
|
+
rb_funcall(contrast_patcher(), rb_sym_enter_scope, 0);
|
|
135
|
+
|
|
136
|
+
/* Get the name of the calling method */
|
|
137
|
+
method = rb_funcall(object, rb_sym_method, 0);
|
|
138
|
+
|
|
139
|
+
/* Retrieve from Ruby Patcher class
|
|
140
|
+
* [method_policy object, Symbol representing original method]
|
|
141
|
+
*/
|
|
142
|
+
switch (impl) {
|
|
143
|
+
case IMPL_ALIAS_INSTANCE:
|
|
144
|
+
case IMPL_PREPEND:
|
|
145
|
+
known =
|
|
146
|
+
rb_funcall(patch_status, rb_sym_info_for, 3, object, method, Qtrue);
|
|
147
|
+
break;
|
|
148
|
+
case IMPL_ALIAS_SINGLETON:
|
|
149
|
+
known = rb_funcall(patch_status, rb_sym_info_for, 3, object, method,
|
|
150
|
+
Qfalse);
|
|
151
|
+
break;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/* Index into above array & retrieve contents */
|
|
155
|
+
if (RTEST(known)) {
|
|
156
|
+
method_policy = rb_funcall(known, rb_sym_brackets, 1, INT2NUM(0));
|
|
157
|
+
} else {
|
|
158
|
+
method_policy = Qnil;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (impl == IMPL_ALIAS_INSTANCE || impl == IMPL_ALIAS_SINGLETON) {
|
|
162
|
+
/* Alias patching moves the original method to "cs__#{method}" */
|
|
163
|
+
cs__method = rb_funcall(known, rb_sym_brackets, 1, INT2NUM(1));
|
|
164
|
+
|
|
165
|
+
/* We may not have built the alias yet */
|
|
166
|
+
if (!RTEST(cs__method)) {
|
|
167
|
+
cs__method =
|
|
168
|
+
rb_funcall(contrast_patcher(), rb_sym_build_method_name, 2,
|
|
169
|
+
object, method);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/* Check conditions for not doing Contrast analysis */
|
|
174
|
+
if (nested_scope) {
|
|
175
|
+
/* if we were in scope */
|
|
176
|
+
do_contrast = 0;
|
|
177
|
+
} else if (!RTEST(known)) {
|
|
178
|
+
/* nothing to be done with entirely unknown method*/
|
|
179
|
+
do_contrast = 0;
|
|
180
|
+
} else if (!RTEST(method_policy)) {
|
|
181
|
+
/* nothing to be done without a method policy */
|
|
182
|
+
do_contrast = 0;
|
|
183
|
+
} else if (!RTEST(rb_funcall(contrast_patcher(), rb_sym_in_request_context,
|
|
184
|
+
0))) {
|
|
185
|
+
/* (RUBY-290, checking for a request_context is to be deprecated)
|
|
186
|
+
* if we're not within a request context, don't analyze (by fiat)
|
|
187
|
+
* We reset scope at the end of request contexts right now, don't remove
|
|
188
|
+
* this check without also handling that code.
|
|
189
|
+
*/
|
|
190
|
+
do_contrast = 0;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
switch (impl) {
|
|
194
|
+
case IMPL_ALIAS_INSTANCE:
|
|
195
|
+
case IMPL_ALIAS_SINGLETON:
|
|
196
|
+
original_args[0] = object;
|
|
197
|
+
original_args[1] = cs__method;
|
|
198
|
+
original_args[2] = INT2NUM(argc);
|
|
199
|
+
original_args[3] = (VALUE)argv;
|
|
200
|
+
break;
|
|
201
|
+
case IMPL_PREPEND:
|
|
202
|
+
original_args[0] = INT2NUM(argc);
|
|
203
|
+
original_args[1] = (VALUE)argv;
|
|
204
|
+
break;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/* If we're not doing Contrast analysis, exit scope and treat as normal. */
|
|
208
|
+
if (!do_contrast) {
|
|
209
|
+
goto call_original;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
rescue_args[0] = object;
|
|
213
|
+
rescue_args[1] = method;
|
|
214
|
+
rescue_args[2] = INT2NUM(argc);
|
|
215
|
+
rescue_args[3] = (VALUE)argv;
|
|
216
|
+
rescue_args[4] = method_policy;
|
|
217
|
+
|
|
218
|
+
/* Tracking, triggering, and propagation here. */
|
|
219
|
+
contrast_call_pre_patch(method_policy, method, object, argc, argv, Qnil);
|
|
220
|
+
|
|
221
|
+
/* Capture pre-call state */
|
|
222
|
+
preshift = build_preshift(method_policy, object, argc, argv);
|
|
223
|
+
rescue_args[5] = preshift;
|
|
224
|
+
|
|
225
|
+
/* We wrap a call to the original method with a rescue block, and we use
|
|
226
|
+
* rb_rescue2 to capture all Exception-inheriting exceptions (and if your
|
|
227
|
+
* software is well-behaved, all exceptions should inherit from Exception.)
|
|
228
|
+
*
|
|
229
|
+
* The rescue block is responsible for doing Contrast post-call analysis
|
|
230
|
+
* in the event the original method has thrown an exception.
|
|
231
|
+
*
|
|
232
|
+
* EDGE CASES:
|
|
233
|
+
* Given how extensively we patch and instrument, this code is
|
|
234
|
+
* prone to some esoteric edge cases that are not well-documented or
|
|
235
|
+
* easy to research.
|
|
236
|
+
*
|
|
237
|
+
* There is an esoteric edge case in core Ruby, upon Thread#kill, where
|
|
238
|
+
* it raises Fixnum 8 (Qnil==8). This is an intentional choice on the
|
|
239
|
+
* part of the core Ruby devs, as blindly rescuing Thread#kill would be
|
|
240
|
+
* disastrous.
|
|
241
|
+
* A consequence of this is that Thread#kill will leak scope, if you
|
|
242
|
+
* happen to ever instrument it.
|
|
243
|
+
*
|
|
244
|
+
* If you are within a catch block, and the original function results
|
|
245
|
+
* in a throw, you will leak scope. We handle this by not instrumenting
|
|
246
|
+
* methods that do that. (Tracked in RUBY-552.)
|
|
247
|
+
*
|
|
248
|
+
* If you're thinking of cleaning this up by using rb_protect,
|
|
249
|
+
* you will catch ALL exceptions, as well as ANYTHING
|
|
250
|
+
* else that unwinds the stack. This includes fiber context switches
|
|
251
|
+
* (which are used to implement Enumerator#next) and catch/throw blocks.
|
|
252
|
+
* I spent a week debugging that so you don't have to. -ajm
|
|
253
|
+
*/
|
|
254
|
+
|
|
255
|
+
switch (impl) {
|
|
256
|
+
case IMPL_ALIAS_INSTANCE:
|
|
257
|
+
case IMPL_ALIAS_SINGLETON:
|
|
258
|
+
original_ret = rb_rescue2(
|
|
259
|
+
contrast_patch_call_original, (VALUE)original_args,
|
|
260
|
+
contrast_patch_call_rescue, (VALUE)rescue_args, rb_eException, 0);
|
|
261
|
+
break;
|
|
262
|
+
case IMPL_PREPEND:
|
|
263
|
+
original_ret = rb_rescue2(contrast_call_super, (VALUE)original_args,
|
|
264
|
+
contrast_patch_call_rescue,
|
|
265
|
+
(VALUE)rescue_args, rb_eException, 0);
|
|
266
|
+
break;
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
/* If you're here, the original method did not throw an exception
|
|
270
|
+
* (or unwind the stack otherwise).
|
|
271
|
+
* If the original method threw an exception, contrast_patch_call_rescue
|
|
272
|
+
* re-raises the original exception, which unwinds the stack back to the
|
|
273
|
+
* call site. This means the rest of this function is not executed.
|
|
274
|
+
*/
|
|
275
|
+
|
|
276
|
+
/* Invoke Contrast post-call patching.
|
|
277
|
+
* Post-call patching may transform the return value,
|
|
278
|
+
* hence the assignment.
|
|
279
|
+
*/
|
|
280
|
+
transformed_ret = contrast_call_post_patch(method_policy, preshift, object,
|
|
281
|
+
original_ret, argc, argv);
|
|
282
|
+
|
|
283
|
+
/* Special case for tracking frozen sources */
|
|
284
|
+
if (transformed_ret != Qnil) {
|
|
285
|
+
ret = transformed_ret;
|
|
286
|
+
} else {
|
|
287
|
+
ret = original_ret;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/* exit scope */
|
|
291
|
+
rb_funcall(contrast_patcher(), rb_sym_exit_scope, 0);
|
|
292
|
+
|
|
293
|
+
return ret;
|
|
294
|
+
|
|
295
|
+
call_original:
|
|
296
|
+
|
|
297
|
+
/* exit scope */
|
|
298
|
+
rb_funcall(contrast_patcher(), rb_sym_exit_scope, 0);
|
|
299
|
+
|
|
300
|
+
switch (impl) {
|
|
301
|
+
case IMPL_ALIAS_INSTANCE:
|
|
302
|
+
case IMPL_ALIAS_SINGLETON:
|
|
303
|
+
return contrast_patch_call_original(original_args);
|
|
304
|
+
case IMPL_PREPEND:
|
|
305
|
+
return contrast_call_super(original_args);
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
VALUE contrast_alias_instance_patch(const int argc, const VALUE *argv,
|
|
310
|
+
const VALUE object) {
|
|
311
|
+
return contrast_patch_dispatch(argc, argv, IMPL_ALIAS_INSTANCE, object);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
VALUE contrast_alias_singleton_patch(const int argc, const VALUE *argv,
|
|
315
|
+
const VALUE object) {
|
|
316
|
+
return contrast_patch_dispatch(argc, argv, IMPL_ALIAS_SINGLETON, object);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
VALUE contrast_prepend_patch(const int argc, const VALUE *argv,
|
|
320
|
+
const VALUE object) {
|
|
321
|
+
return contrast_patch_dispatch(argc, argv, IMPL_PREPEND, object);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
VALUE contrast_patch_define_method(const VALUE self, const VALUE clazz,
|
|
325
|
+
const VALUE method_policy,
|
|
326
|
+
const VALUE cs_method) {
|
|
327
|
+
const VALUE original_method_name =
|
|
328
|
+
rb_funcall(method_policy, rb_sym_method_name, 0);
|
|
329
|
+
const VALUE is_instance_method =
|
|
330
|
+
rb_funcall(method_policy, rb_sym_instance_method, 0);
|
|
331
|
+
char *cStr;
|
|
332
|
+
VALUE str;
|
|
333
|
+
rb_funcall(patch_status, rb_sym_set_info_for, 5, clazz, original_method_name,
|
|
334
|
+
method_policy, is_instance_method, cs_method);
|
|
335
|
+
|
|
336
|
+
/* Some methods we patch rely on a specific C level patch,
|
|
337
|
+
* in those cases we should still add the method to the info_for hash
|
|
338
|
+
* on the class, but we should skip setting up the generic Contrast
|
|
339
|
+
* monkeypatch
|
|
340
|
+
*/
|
|
341
|
+
VALUE is_custom_patch = rb_funcall(method_policy, rb_sym_custom_patch, 0);
|
|
342
|
+
if (RTEST(is_custom_patch)) {
|
|
343
|
+
return Qnil;
|
|
344
|
+
}
|
|
345
|
+
str = rb_funcall(original_method_name, rb_sym_cs_to_s, 0);
|
|
346
|
+
cStr = StringValueCStr(str);
|
|
347
|
+
|
|
348
|
+
const VALUE is_private =
|
|
349
|
+
rb_funcall(method_policy, rb_sym_private_method, 0);
|
|
350
|
+
if (RTEST(is_instance_method)) {
|
|
351
|
+
rb_funcall(clazz, rb_sym_alias_method, 2, cs_method,
|
|
352
|
+
original_method_name);
|
|
353
|
+
if (RTEST(is_private)) {
|
|
354
|
+
rb_funcall(clazz, rb_sym_public, 1, cs_method);
|
|
355
|
+
}
|
|
356
|
+
rb_define_method(clazz, cStr, contrast_alias_instance_patch, -1);
|
|
357
|
+
if (RTEST(is_private)) {
|
|
358
|
+
rb_funcall(clazz, rb_sym_private, 1, original_method_name);
|
|
359
|
+
}
|
|
360
|
+
} else {
|
|
361
|
+
/*
|
|
362
|
+
* we have to send the method call to either the singleton class or the
|
|
363
|
+
* instance depending on the method type. send_to will hold this for us.
|
|
364
|
+
* https://stackoverflow.com/questions/212407/what-exactly-is-the-singleton-class-in-ruby
|
|
365
|
+
*/
|
|
366
|
+
const VALUE singleton_class =
|
|
367
|
+
rb_funcall(clazz, rb_sym_cs_singleton_class, 0);
|
|
368
|
+
rb_funcall(singleton_class, rb_sym_alias_method, 2, cs_method,
|
|
369
|
+
original_method_name);
|
|
370
|
+
if (RTEST(is_private)) {
|
|
371
|
+
rb_funcall(singleton_class, rb_sym_public, 1, cs_method);
|
|
372
|
+
}
|
|
373
|
+
rb_define_singleton_method(clazz, cStr, contrast_alias_singleton_patch,
|
|
374
|
+
-1);
|
|
375
|
+
if (RTEST(is_private)) {
|
|
376
|
+
rb_funcall(singleton_class, rb_sym_private, 1,
|
|
377
|
+
original_method_name);
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
return Qnil;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
VALUE contrast_patch_prepend(const VALUE self, const VALUE originalModule,
|
|
384
|
+
const VALUE method_policy) {
|
|
385
|
+
|
|
386
|
+
const VALUE original_method_name =
|
|
387
|
+
rb_funcall(method_policy, rb_sym_method_name, 0);
|
|
388
|
+
const VALUE is_private =
|
|
389
|
+
rb_funcall(method_policy, rb_sym_private_method, 0);
|
|
390
|
+
const VALUE is_instance_method =
|
|
391
|
+
rb_funcall(method_policy, rb_sym_instance_method, 0);
|
|
392
|
+
rb_funcall(patch_status, rb_sym_set_info_for, 5, originalModule,
|
|
393
|
+
original_method_name, method_policy, Qtrue, Qnil);
|
|
394
|
+
VALUE module = rb_define_module_under(originalModule, "ContrastPrepend");
|
|
395
|
+
VALUE str = rb_funcall(original_method_name, rb_sym_cs_to_s, 0);
|
|
396
|
+
char *cMethodName = StringValueCStr(str);
|
|
397
|
+
if (RTEST(is_instance_method)) {
|
|
398
|
+
if (RTEST(is_private)) {
|
|
399
|
+
rb_define_private_method(module, cMethodName,
|
|
400
|
+
contrast_prepend_patch, -1);
|
|
401
|
+
} else {
|
|
402
|
+
rb_define_method(module, cMethodName, contrast_prepend_patch, -1);
|
|
403
|
+
}
|
|
404
|
+
} else {
|
|
405
|
+
rb_define_singleton_method(module, cMethodName, contrast_prepend_patch,
|
|
406
|
+
-1);
|
|
407
|
+
}
|
|
408
|
+
rb_prepend_module(originalModule, module);
|
|
409
|
+
return Qtrue;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
void Init_cs__contrast_patch(void) {
|
|
413
|
+
rb_sym_brackets = rb_intern("[]");
|
|
414
|
+
rb_sym_build_method_name = rb_intern("build_method_name");
|
|
415
|
+
rb_sym_build_preshift = rb_intern("build_preshift");
|
|
416
|
+
rb_sym_contrast_apply_post_patch = rb_intern("apply_post_patch");
|
|
417
|
+
rb_sym_contrast_apply_pre_patch = rb_intern("apply_pre_patch");
|
|
418
|
+
rb_sym_cs_to_s = rb_intern("to_s");
|
|
419
|
+
rb_sym_custom_patch = rb_intern("requires_custom_patch?");
|
|
420
|
+
rb_sym_in_request_context = rb_intern("in_request_context?");
|
|
421
|
+
rb_sym_info_for = rb_intern("info_for");
|
|
422
|
+
rb_sym_propagation_node = rb_intern("propagation_node");
|
|
423
|
+
rb_sym_set_info_for = rb_intern("set_info_for");
|
|
424
|
+
|
|
425
|
+
rb_sym_private_method = rb_intern("private_method?");
|
|
426
|
+
rb_sym_method_name = rb_intern("method_name");
|
|
427
|
+
rb_sym_alias_method = rb_intern("alias_method");
|
|
428
|
+
rb_sym_public = rb_intern("public");
|
|
429
|
+
rb_sym_private = rb_intern("private");
|
|
430
|
+
rb_sym_instance_method = rb_intern("instance_method");
|
|
431
|
+
rb_sym_cs_singleton_class = rb_intern("cs__singleton_class");
|
|
432
|
+
|
|
433
|
+
|
|
434
|
+
rb_define_module_function(contrast_patcher(), "contrast_define_method",
|
|
435
|
+
contrast_patch_define_method, 3);
|
|
436
|
+
|
|
437
|
+
rb_define_module_function(contrast_patcher(), "contrast_prepend_method",
|
|
438
|
+
contrast_patch_prepend, 2);
|
|
439
|
+
|
|
440
|
+
/* patch_status = Contrast::Agent::Patching::Policy::PatchStatus */
|
|
441
|
+
patch_status = rb_define_class_under(policy, "PatchStatus", rb_cObject);
|
|
442
|
+
|
|
443
|
+
/* preshift_class = Contrast::Agent::Assess::PreShift */
|
|
444
|
+
preshift_class = rb_define_class_under(assess, "PreShift", rb_cObject);
|
|
445
|
+
}
|