#include typedef enum { IMPL_ALIAS_INSTANCE, IMPL_ALIAS_SINGLETON, IMPL_PREPEND } patch_impl; /* Calls to Contrast modules */ /* Contrast::Agent::Patching::Policy::PatchStatus */ static VALUE patch_status; /* Contrast::Agent::Assess::PreShift */ static VALUE preshift_class; /* Symbol constants used throughout */ static VALUE rb_sym_brackets; static VALUE rb_sym_build_preshift; static VALUE rb_sym_contrast_apply_post_patch; static VALUE rb_sym_contrast_apply_pre_patch; static VALUE rb_sym_custom_patch; static VALUE rb_sym_cs_to_s; static VALUE rb_sym_in_request_context; static VALUE rb_sym_enter_method_scope; static VALUE rb_sym_exit_method_scope; static VALUE rb_sym_build_method_name; static VALUE rb_sym_info_for; static VALUE rb_sym_propagation_node; static VALUE rb_sym_set_info_for; static VALUE rb_sym_private_method; static VALUE rb_sym_method_name; static VALUE rb_sym_alias_method; static VALUE rb_sym_public; static VALUE rb_sym_private; static VALUE rb_sym_instance_method; static VALUE rb_sym_cs_singleton_class; /** * Build the preshift object - a snapshot of the object and parameters before * they're transformed by the method being patched. This is required for * proper taint creation in propagation events. * * method_policy - method_policy for the patched method; :MethodPolicy * object - the object on which the method is invoked; Object * argc - the number of params passed to the call of the patched method; C int * params - the params passed to the call of the patched method; C Array * * return - :PreShift or nil if no snapshot is required */ VALUE build_preshift(const VALUE method_policy, const VALUE object, const int argc, const VALUE *params); /** * Call the original function. Because we have to use the rb_rescue method, the * args all have to be passed in as a C array. * * args[0] - the object on which the method is invoked; Object * args[1] - the name of the method to be invoked, aliased by Contrast during * patching; cs__ format Symbol * args[2] - the number of params to be used when the method is invoked; C int * args[3] - the params to be used when the method is invoked; C Array or NULL * * return - the return value of the original function; Object, nil, or * Exception */ VALUE contrast_patch_call_original(const VALUE *args); /** * Call the contrast patching function responsible for tracking, propagating, * and triggering. * * method_policy - method policy for the patched method; :MethodPolicy * object - the object on which the method was invoked; Object * argc - the number of params used when the method was invoked; C int * params - the params used when the method was invoked; C Array or NULL * exception - any exceptions raised that this patch has to account for * return - the value with which to replace the original functions * return, allowing us to track frozen sources, or nil */ VALUE contrast_call_pre_patch(const VALUE method_policy, const VALUE method, const VALUE object, const int count, const VALUE *params, const VALUE exception); /** * Call the contrast patching function responsible for tracking, propagating, * and triggering. * * method_policy - method_policy for the patched method; :MethodPolicy * preshift - a capture of the state before the method was invoked; :PreShift * object - the object on which the method was invoked; Object * ret - the return of the method that was invoked; Object or nil * argc - the number of params used when the method was invoked; C int * params - the params used when the method was invoked; C Array or NULL * * return - the value with which to replace the original functions return, * allowing us to track frozen sources, or nil */ VALUE contrast_call_post_patch(const VALUE method_policy, const VALUE preshift, const VALUE object, const VALUE ret, const int count, const VALUE *params); /** * Call our Contrast rescue block for the original function. If the call to * the original function results in exception, we still need to do our Contrast * things. An example is triggering for a SecurityException, i.e. if a command * is poorly formatted doesn't mean it isn't still a command injection. * * args[0] - the object on which the method was invoked; Object * args[1] - the name of the method invoked; Symbol * args[2] - the number of params used when the method was invoked; C int * args[3] - the params used when the method was invoked; C Array or NULL * args[4] - method_policy for the patched method; :MethodPolicy * args[5] - a capture of the state before the method was invoked; :PreShift * */ VALUE contrast_patch_call_rescue(const VALUE *args); /** * Call super() with an rb_rescue-compatible function signature. * * args[0] - argc, as native int. * args[1] - *argv, of size argc. * * */ VALUE contrast_call_super(const VALUE *args); /* * Build the 'proc' to call in place of the original method * 1) Pull the things needed from Policy * 2) Capture state * 3) Do Contrast things * 4) Invoke the original method * 5) Do more Contrast things * * argc - the number of args used in this invocation of the method; C int * argv - the args used in this invocation of the method; C Array * impl - what patch implementation is being used * object - the object on which this invocation of the method occurs; Object * * return - the result of the original function, or as close to it as we can * get. Should be the same value, but not guaranteed to be the same * instance (specifically for frozen sources) */ VALUE contrast_patch_dispatch(const int argc, const VALUE *argv, const patch_impl impl, const VALUE object); VALUE contrast_alias_instance_patch(const int argc, const VALUE *argv, const VALUE object); VALUE contrast_alias_singleton_patch(const int argc, const VALUE *argv, const VALUE object); VALUE contrast_prepend_patch(const int argc, const VALUE *argv, const VALUE object); /* * Patches a module's method by prepend: * - creates a Contrast module under the namespace of the original module * - defines a shim method on the Contrast module * - prepends the Contrast module to the original module * After this, calling the original method results in calling our shim * method instead. Our shim method can call super() to achieve original * behavior. * * Example: * Prepending Foo#bar results in: * - creating Foo::ContrastPrepend * - defining shim method Foo::ContrastPrepend#bar * - prepending Foo with Foo::ContrastPrepend * * originalModule - Module; the actual Module being prepended * methodPolicy - :MethodPolicy; the method policy that apply to the method being redefined * * return - Boolean; if the prepend occurred or not */ VALUE contrast_patch_prepend(const VALUE self, const VALUE originalModule, const VALUE methodPolicy); /* * Call this to redefine the given function such that it can be invoked with * Contrast assess tracking. * * self - Patcher C - Ruby magic binding thing * clazz - the class that owns the method being redefined; Module or Class * method_policy - the method policy that apply to the method being redefined; * :MethodPolicy * cs_method - the name to which the method is being redefined; Symbol */ VALUE contrast_patch_define_method(const VALUE self, const VALUE clazz, const VALUE methodPolicy, const VALUE cs_method); void Init_cs__contrast_patch(void);