From b0e18db71663a1359e897c6b61fa71c46f69ff2c Mon Sep 17 00:00:00 2001 From: Tudor Date: Thu, 23 May 2024 13:55:45 +0300 Subject: [PATCH] Panics for soft error handling, some refactor and comments --- src/extension/aikido.cpp | 33 ++++++++++++++++++----------- src/lib/handle_function_executed.go | 2 +- src/lib/main.go | 14 ++++++++---- src/lib/utils.go | 8 +++---- 4 files changed, 36 insertions(+), 21 deletions(-) diff --git a/src/extension/aikido.cpp b/src/extension/aikido.cpp index a3f37dc6..4a508330 100644 --- a/src/extension/aikido.cpp +++ b/src/extension/aikido.cpp @@ -28,9 +28,21 @@ struct FUNCTION_HANDLERS { zif_handler original_handler; }; -#define AIKIDO_REGISTER_HANDLER(function_name) { std::string(#function_name), { handle_##function_name, nullptr } } +/* + Macro for registering an Aikido handler in the HOOKED_FUNCTIONS map. + It takes as parameters the PHP function name to be hooked and C++ function + that should be called when that PHP function is executed. + The nullptr part is a placeholder where the original function handler from + the Zend framework will be stored at initialization when we run the hooking. +*/ #define AIKIDO_REGISTER_HANDLER_EX(function_name, function_pointer) { std::string(#function_name), { function_pointer, nullptr } } +/* + Shorthand version of AIKIDO_REGISTER_HANDLER_EX that constructs automatically the C++ function to be called. + For example, if function name is curl_init this macro will store { "curl_init", { handle_curl_init, nullptr } }. +*/ +#define AIKIDO_REGISTER_HANDLER(function_name) { std::string(#function_name), { handle_##function_name, nullptr } } + unordered_map HOOKED_FUNCTIONS = { AIKIDO_REGISTER_HANDLER(curl_init), @@ -44,16 +56,13 @@ unordered_map HOOKED_FUNCTIONS = { AIKIDO_REGISTER_HANDLER_EX(proc_open, handle_shell_execution) }; -#define AIKIDO_HANDLER_START(function_name) php_printf("[AIKIDO-C++] Handler called for \"" #function_name "\"!\n"); -#define AIKIDO_HANDLER_END(function_name) HOOKED_FUNCTIONS[#function_name].original_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU); - #define AIKIDO_GET_FUNCTION_NAME() (ZSTR_VAL(execute_data->func->common.function_name)) -#define AIKIDO_HANDLER_START_GENERIC() php_printf("[AIKIDO-C++] Handler called for \"%s\"!\n", AIKIDO_GET_FUNCTION_NAME()); -#define AIKIDO_HANDLER_END_GENERIC() HOOKED_FUNCTIONS[AIKIDO_GET_FUNCTION_NAME()].original_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU); +#define AIKIDO_HANDLER_START() php_printf("[AIKIDO-C++] Handler called for \"%s\"!\n", AIKIDO_GET_FUNCTION_NAME()); +#define AIKIDO_HANDLER_END() HOOKED_FUNCTIONS[AIKIDO_GET_FUNCTION_NAME()].original_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU); ZEND_NAMED_FUNCTION(handle_curl_init) { - AIKIDO_HANDLER_START(curl_init); + AIKIDO_HANDLER_START(); zend_string *url = NULL; @@ -62,7 +71,7 @@ ZEND_NAMED_FUNCTION(handle_curl_init) { Z_PARAM_STR_OR_NULL(url) ZEND_PARSE_PARAMETERS_END(); - AIKIDO_HANDLER_END(curl_init); + AIKIDO_HANDLER_END(); if (Z_TYPE_P(return_value) != IS_FALSE) { // Z_OBJ_P(return_value) @@ -82,7 +91,7 @@ ZEND_NAMED_FUNCTION(handle_curl_init) { } ZEND_NAMED_FUNCTION(handle_curl_setopt) { - AIKIDO_HANDLER_START(curl_setopt); + AIKIDO_HANDLER_START(); zval *curlHandle = NULL; zend_long options = 0; @@ -115,11 +124,11 @@ ZEND_NAMED_FUNCTION(handle_curl_setopt) { zend_tmp_string_release(tmp_str); } - AIKIDO_HANDLER_END(curl_setopt); + AIKIDO_HANDLER_END(); } ZEND_NAMED_FUNCTION(handle_shell_execution) { - AIKIDO_HANDLER_START_GENERIC(); + AIKIDO_HANDLER_START(); zend_string *cmd = NULL; @@ -144,7 +153,7 @@ ZEND_NAMED_FUNCTION(handle_shell_execution) { GoOnEvent(shell_execution_event); - AIKIDO_HANDLER_END_GENERIC(); + AIKIDO_HANDLER_END(); } /* For compatibility with older PHP versions */ diff --git a/src/lib/handle_function_executed.go b/src/lib/handle_function_executed.go index 326cc6c7..1e5df3b7 100644 --- a/src/lib/handle_function_executed.go +++ b/src/lib/handle_function_executed.go @@ -18,7 +18,7 @@ func OnFunctionExecuted(data map[string]interface{}) string { functionName := MustGetFromMap[string](data, "function_name") parameters := MustGetFromMap[map[string]interface{}](data, "parameters") - ExitIfKeyDoesNotExistInMap(functionExecutedHandlers, functionName) + CheckIfKeyExists(functionExecutedHandlers, functionName) return functionExecutedHandlers[functionName](parameters) } diff --git a/src/lib/main.go b/src/lib/main.go index 44e240ae..79341b27 100644 --- a/src/lib/main.go +++ b/src/lib/main.go @@ -4,7 +4,6 @@ import "C" import ( "encoding/json" "fmt" - "log" ) type eventFunctionExecutedFn func(map[string]interface{}) string @@ -14,19 +13,26 @@ var eventHandlers = map[string]eventFunctionExecutedFn{ } //export OnEvent -func OnEvent(eventJson string) string { +func OnEvent(eventJson string) (outputJson string) { + defer func() { + if r := recover(); r != nil { + fmt.Println("[AIKIDO-GO] Recovered from panic:", r) + outputJson = "{}" + } + }() + fmt.Println("[AIKIDO-GO] OnEvent:", eventJson) var event map[string]interface{} err := json.Unmarshal([]byte(eventJson), &event) if err != nil { - log.Fatalf("Error parsing JSON: %s", err) + panic(fmt.Sprintf("Error parsing JSON: %s", err)) } eventName := MustGetFromMap[string](event, "event") data := MustGetFromMap[map[string]interface{}](event, "data") - ExitIfKeyDoesNotExistInMap(eventHandlers, eventName) + CheckIfKeyExists(eventHandlers, eventName) return eventHandlers[eventName](data) } diff --git a/src/lib/utils.go b/src/lib/utils.go index 4d303b4f..6b53ba03 100644 --- a/src/lib/utils.go +++ b/src/lib/utils.go @@ -1,13 +1,13 @@ package main import ( - "log" + "fmt" "net/url" ) -func ExitIfKeyDoesNotExistInMap[K comparable, V any](m map[K]V, key K) { +func CheckIfKeyExists[K comparable, V any](m map[K]V, key K) { if _, exists := m[key]; !exists { - log.Fatalf("Key %s does not exist in map!", key) + panic(fmt.Sprintf("Key %s does not exist in map!", key)) } } @@ -26,7 +26,7 @@ func GetFromMap[T any](m map[string]interface{}, key string) *T { func MustGetFromMap[T any](m map[string]interface{}, key string) T { value := GetFromMap[T](m, key) if value == nil { - log.Fatalf("Error parsing JSON: key %s has incorrect type", key) + panic(fmt.Sprintf("Error parsing JSON: key %s does not exist or it has an incorrect type", key)) } return *value }