From a637b5ce3d17437cb45787e53cd4e496e63d6390 Mon Sep 17 00:00:00 2001 From: Rockrid3r Date: Thu, 21 Mar 2024 14:39:12 +0300 Subject: [PATCH] Added tests for vmlinux version & config --- librz/core/cconfig.c | 3 +-- librz/core/vmlinux.c | 49 ++++++++++++++++++++++++++++------------ librz/include/vmlinux.h | 13 ++++++----- librz/util/str.c | 7 +++++- test/unit/test_vmlinux.c | 32 ++++++++++++++++++++++++-- 5 files changed, 78 insertions(+), 26 deletions(-) diff --git a/librz/core/cconfig.c b/librz/core/cconfig.c index c509a5c5ebe..c6831be1771 100644 --- a/librz/core/cconfig.c +++ b/librz/core/cconfig.c @@ -87,7 +87,6 @@ static bool cb_vmlinux(void *_core, void *_node) { } core->analysis->vmlinux_config = rz_vmlinux_config_new(); - core->analysis->vmlinux_config->config_tbl = rz_vmlinux_config_table_new(); const char *vmlinux_config = rz_config_get(core->config, "bin.elf.vmlinux.config"); const char *vmlinux_version = rz_config_get(core->config, "bin.elf.vmlinux.version"); @@ -100,7 +99,7 @@ static bool cb_vmlinux(void *_core, void *_node) { const char *apply_config_file = rz_config_get(core->config, "bin.elf.vmlinux.apply_config"); if (RZ_STR_ISNOTEMPTY(apply_config_file)) { - RZ_LOG_INFO("Parsingconfig file '%s'\n", apply_config_file); + RZ_LOG_INFO("Parsing config file '%s'...\n", apply_config_file); vmlinux_parse_apply_config_file(apply_config_file, core->analysis->vmlinux_config->config_tbl); } diff --git a/librz/core/vmlinux.c b/librz/core/vmlinux.c index 32216acaf91..53fe5c9098e 100644 --- a/librz/core/vmlinux.c +++ b/librz/core/vmlinux.c @@ -1,11 +1,14 @@ #include #include +#include #include "vmlinux.h" #include static void add_config(RzVmlinuxConfigTable* config_tbl, char* config_name, char* config_value); -RZ_IPI bool vmlinux_parse_apply_config_file(const char* config_filepath, RzVmlinuxConfigTable* config_tbl) { +RZ_API bool vmlinux_parse_apply_config_file(const char* config_filepath, RzVmlinuxConfigTable* config_tbl) { + rz_return_val_if_fail(config_filepath && config_tbl, false); + FILE* f = fopen(config_filepath, "r"); if (!f) { return false; @@ -13,6 +16,10 @@ RZ_IPI bool vmlinux_parse_apply_config_file(const char* config_filepath, RzVmlin size_t line_size = 256; char* line = malloc(line_size); + if (!line) { + return false; + } + int err = 0; while (true) { ssize_t read_sz = getline(&line, &line_size, f); // reallocs if not enough @@ -23,16 +30,8 @@ RZ_IPI bool vmlinux_parse_apply_config_file(const char* config_filepath, RzVmlin rz_str_trim(line); - char* config_name; - char* config_value; - - if (line[0] == '#' || !line[0]) { - continue; - } else if (rz_str_split_by_first_dupstr(line, "=", true, &config_name, &config_value)) { - add_config(config_tbl, config_name, config_value); - } else { + if (!vmlinux_parse_apply_config_string(line, config_tbl)) { RZ_LOG_WARN("Skipping line '%s'", line); - continue; } } out: @@ -41,10 +40,27 @@ RZ_IPI bool vmlinux_parse_apply_config_file(const char* config_filepath, RzVmlin return !err; } +RZ_API bool vmlinux_parse_apply_config_string(const char *config_str, RzVmlinuxConfigTable *config_tbl) { + rz_return_val_if_fail(config_str && config_tbl, false); + + char* config_name; + char* config_value; + + if (config_str[0] == '#' || !config_str[0]) { + return true; + } else if (rz_str_split_by_first_dupstr(config_str, "=", true, &config_name, &config_value)) { + add_config(config_tbl, config_name, config_value); + free(config_name); + free(config_value); + return true; + } + return false; +} + /** * Numeric 90+ */ -RZ_IPI bool vmlinux_parse_version(const char* version_string, unsigned long version[3]) { +RZ_API bool vmlinux_parse_version(const char* version_string, unsigned long version[3]) { RzList* version_list = rz_str_split_duplist_n(version_string, ".", 3, true); RzListIter* it; char* str; @@ -65,11 +81,13 @@ RZ_IPI bool vmlinux_parse_version(const char* version_string, unsigned long vers unsigned long numbr = strtoul(str, NULL, 10); version[v] = numbr; } else { + rz_list_free(version_list); return false; } ++v; } + rz_list_free(version_list); return true; } @@ -97,7 +115,7 @@ static void add_config(RzVmlinuxConfigTable* config_tbl, char* config_name, char } -RZ_IPI RzVmlinuxConfigTable* rz_vmlinux_config_table_new() { +RZ_API RzVmlinuxConfigTable* rz_vmlinux_config_table_new() { RzVmlinuxConfigTable* config_tbl = malloc(sizeof(RzVmlinuxConfigTable)); config_tbl->config_slab_freelist_random = VMLINUX_CONFIG_VALUE_N; config_tbl->config_slab_freelist_hardened = VMLINUX_CONFIG_VALUE_N; @@ -106,8 +124,9 @@ RZ_IPI RzVmlinuxConfigTable* rz_vmlinux_config_table_new() { return config_tbl; } -RZ_IPI RzVmlinuxConfig* rz_vmlinux_config_new() { +RZ_API RzVmlinuxConfig* rz_vmlinux_config_new() { RzVmlinuxConfig* config = malloc(sizeof(RzVmlinuxConfig)); + config->config_tbl = rz_vmlinux_config_table_new(); return config; } @@ -135,11 +154,11 @@ RZ_API int vmlinux_vercmp_with_str(unsigned long v1[3], const char* v2_str) { } -RZ_IPI void rz_vmlinux_config_free(RzVmlinuxConfig* vmlinux_config) { +RZ_API void rz_vmlinux_config_free(RzVmlinuxConfig* vmlinux_config) { rz_vmlinux_config_table_free(vmlinux_config->config_tbl); free(vmlinux_config); } -RZ_IPI void rz_vmlinux_config_table_free(RzVmlinuxConfigTable* config_tbl) { +RZ_API void rz_vmlinux_config_table_free(RzVmlinuxConfigTable* config_tbl) { free(config_tbl); } \ No newline at end of file diff --git a/librz/include/vmlinux.h b/librz/include/vmlinux.h index 21572ef212a..27862fade37 100644 --- a/librz/include/vmlinux.h +++ b/librz/include/vmlinux.h @@ -18,11 +18,12 @@ typedef struct vmlinux_config { unsigned long version[3]; } RzVmlinuxConfig; -RZ_IPI RzVmlinuxConfigTable* rz_vmlinux_config_table_new(); -RZ_IPI RzVmlinuxConfig* rz_vmlinux_config_new(); -RZ_IPI void rz_vmlinux_config_free(RzVmlinuxConfig* vmlinux_config); -RZ_IPI void rz_vmlinux_config_table_free(RzVmlinuxConfigTable* config_tbl); -RZ_IPI bool vmlinux_parse_apply_config_file(const char* config_filepath, RzVmlinuxConfigTable* config_tbl); -RZ_IPI bool vmlinux_parse_version(const char* version_string, unsigned long version[3]); +RZ_API RzVmlinuxConfigTable* rz_vmlinux_config_table_new(); +RZ_API RzVmlinuxConfig* rz_vmlinux_config_new(); +RZ_API void rz_vmlinux_config_free(RzVmlinuxConfig* vmlinux_config); +RZ_API void rz_vmlinux_config_table_free(RzVmlinuxConfigTable* config_tbl); +RZ_API bool vmlinux_parse_apply_config_file(const char* config_filepath, RzVmlinuxConfigTable* config_tbl); +RZ_API bool vmlinux_parse_apply_config_string(const char *config_str, RzVmlinuxConfigTable *config_tbl); +RZ_API bool vmlinux_parse_version(const char* version_string, unsigned long version[3]); RZ_API int vmlinux_vercmp(unsigned long v1[3], unsigned long v2[3]); RZ_API int vmlinux_vercmp_with_str(unsigned long v1[3], const char* v2_str); \ No newline at end of file diff --git a/librz/util/str.c b/librz/util/str.c index 5243001f02c..d5f78c6ecf6 100644 --- a/librz/util/str.c +++ b/librz/util/str.c @@ -3535,14 +3535,19 @@ RZ_API RZ_OWN RzList /**/ *rz_str_split_list_regex(RZ_NONNULL char *str, } /** - * \brief Split the string \p str on 2 parts according to the substring \p r . Result is stored in the \p first_half , \p second_half . + * \brief Split the string \p str on 2 parts according to the first occurence of the substring \p r . Result is stored in the \p first_half , \p second_half . * * \param str Input string to split * \param c Delimiter string used to split \p str * \param trim If true each half is trimmed after split + * \return true on success */ RZ_API RZ_OWN bool rz_str_split_by_first_dupstr(RZ_NONNULL const char *_str, RZ_NONNULL const char *r, bool trim, char** first_half, char** second_half) { char *str = strdup(_str); + if (!str) { + return false; + } + char* e = strstr(str, r); if (!e) { diff --git a/test/unit/test_vmlinux.c b/test/unit/test_vmlinux.c index 63171b6fb62..8b89dad0655 100644 --- a/test/unit/test_vmlinux.c +++ b/test/unit/test_vmlinux.c @@ -5,17 +5,45 @@ #include #include -int test_vmlinux_vercmp(void) { +static bool test_vmlinux_vercmp(void) { unsigned long v1[3] = {6, 7, 1}; unsigned long v2[3] = {5, 17, 0}; - mu_assert("v1 > v2", vmlinux_vercmp(v1, v2) > 0); + mu_assert("v1 > v2", vmlinux_vercmp(v1, v2) > 0); mu_assert("v1 > v2_str", vmlinux_vercmp_with_str(v1, "5.17") > 0); + + mu_end; +} + +static bool test_vmlinux_config(void) { + RzVmlinuxConfig *vmlinux_config = rz_vmlinux_config_new(); + RzVmlinuxConfigTable *config_tbl = vmlinux_config->config_tbl; + const char *config_lines[] = { + "CONFIG_SLAB_FREELIST_RANDOM=y", + "CONFIG_SLAB_FREELIST_HARDENED=n", + "# CONFIG_SLAB_FREELIST_HARDENED=y", + "CONFIG_STATIC_USERMODEHELPER=y", + "CONFIG_UNKNOWN=y", + }; + + size_t config_size = sizeof(config_lines) / sizeof(config_lines[0]); + for (size_t i = 0; i < config_size; ++i) { + // eprintf("%p, %p\n", config_lines[i], config_tbl); + vmlinux_parse_apply_config_string(config_lines[i], config_tbl); + } + + mu_assert("Expected CONFIG_SLAB_FREELIST_RANDOM=y", config_tbl->config_slab_freelist_random); + mu_assert("Expected CONFIG_SLAB_FREELIST_HARDENED=n", !config_tbl->config_slab_freelist_hardened); + + rz_vmlinux_config_free(vmlinux_config); + mu_end; } + int all_tests(void) { mu_run_test(test_vmlinux_vercmp); + mu_run_test(test_vmlinux_config); return tests_passed != tests_run; }