diff options
Diffstat (limited to 'src/analysis/scan/rule.c')
-rw-r--r-- | src/analysis/scan/rule.c | 1084 |
1 files changed, 1084 insertions, 0 deletions
diff --git a/src/analysis/scan/rule.c b/src/analysis/scan/rule.c new file mode 100644 index 0000000..d3acbc2 --- /dev/null +++ b/src/analysis/scan/rule.c @@ -0,0 +1,1084 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * rule.c - parcours de contenus à la recherche de motifs + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "rule.h" + + +#include <assert.h> +#include <regex.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <sys/mman.h> +#include <sys/stat.h> + + +#include "rule-int.h" +#include "matches/bytes.h" +#include "patterns/token.h" +#include "../../common/extstr.h" +#include "../../core/logs.h" + + + +/* Initialise la classe des règles de détection statique. */ +static void g_scan_rule_class_init(GScanRuleClass *); + +/* Initialise une instance de règle de détection statique. */ +static void g_scan_rule_init(GScanRule *); + +/* Supprime toutes les références externes. */ +static void g_scan_rule_dispose(GScanRule *); + +/* Procède à la libération totale de la mémoire. */ +static void g_scan_rule_finalize(GScanRule *); + + + +/* Indique le type défini pour une règle de détection par motifs. */ +G_DEFINE_TYPE(GScanRule, g_scan_rule, G_TYPE_OBJECT); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des règles de détection statique. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_rule_class_init(GScanRuleClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_rule_dispose; + object->finalize = (GObjectFinalizeFunc)g_scan_rule_finalize; + +} + + +/****************************************************************************** +* * +* Paramètres : rule = instance à initialiser. * +* * +* Description : Initialise une instance de règle de détection statique. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_rule_init(GScanRule *rule) +{ + rule->flags = SRF_NONE; + + rule->name = NULL; + rule->name_hash = 0; + + rule->tags = NULL; + rule->tags_count = 0; + + rule->bytes_locals = NULL; + rule->bytes_allocated = 0; + rule->bytes_used = 0; + + rule->condition = NULL; + +} + + +/****************************************************************************** +* * +* Paramètres : rule = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_rule_dispose(GScanRule *rule) +{ + size_t i; /* Boucle de parcours */ + + for (i = 0; i < rule->bytes_used; i++) + g_clear_object(&rule->bytes_locals[i]); + + g_clear_object(&rule->condition); + + G_OBJECT_CLASS(g_scan_rule_parent_class)->dispose(G_OBJECT(rule)); + +} + + +/****************************************************************************** +* * +* Paramètres : rule = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_rule_finalize(GScanRule *rule) +{ + size_t i; /* Boucle de parcours */ + + if (rule->name != NULL) + free(rule->name); + + for (i = 0; i < rule->tags_count; i++) + free(rule->tags[i]); + + if (rule->tags != NULL) + free(rule->tags); + + if (rule->bytes_locals != NULL) + free(rule->bytes_locals); + + G_OBJECT_CLASS(g_scan_rule_parent_class)->finalize(G_OBJECT(rule)); + +} + + +/****************************************************************************** +* * +* Paramètres : flags = propriétés particulières à conférer à la règle. * +* name = désignation à associer à la future règle. * +* * +* Description : Crée une règle de détection statique à l'aide de motifs. * +* * +* Retour : Règle de détection mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanRule *g_scan_rule_new(ScanRuleFlags flags, const char *name) +{ + GScanRule *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_SCAN_RULE, NULL); + + result->flags = flags; + + result->name = strdup(name); + result->name_hash = fnv_64a_hash(name); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : rule = règle de détection à initialiser pleinement. * +* flags = propriétés particulières à conférer à la règle. * +* name = désignation à associer à la future règle. * +* * +* Description : Met en place une règle de détection statique avec motifs. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_scan_rule_create(GScanRule *rule, ScanRuleFlags flags, const char *name) +{ + GScanRule *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_SCAN_RULE, NULL); + + result->flags = flags; + + result->name = strdup(name); + result->name_hash = fnv_64a_hash(name); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : rule = règle de détection à consulter. * +* * +* Description : Indique les particularités liées à une règle de détection. * +* * +* Retour : Propriétés particulières attachées à la règle. * +* * +* Remarques : - * +* * +******************************************************************************/ + +ScanRuleFlags g_scan_rule_get_flags(const GScanRule *rule) +{ + ScanRuleFlags result; /* Fanions à retourner */ + + result = rule->flags; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : rule = règle de détection à consulter. * +* hash = empreinte précalculée associée au nom. [OUT] * +* * +* Description : Indique le nom associé à une règle de détection. * +* * +* Retour : Désignation humaine associée à la règle. * +* * +* Remarques : - * +* * +******************************************************************************/ + +const char *g_scan_rule_get_name(const GScanRule *rule, fnv64_t *hash) +{ + const char *result; /* Désignation à retourner */ + + result = rule->name; + + if (hash != NULL) + *hash = rule->name_hash; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : rule = règle de détection à compléter. * +* tag = étiquette à associer à la règle. * +* * +* Description : Lie une règle à une nouvelle étiquette. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_scan_rule_add_tag(GScanRule *rule, const char *tag) +{ + rule->tags = realloc(rule->tags, ++rule->tags_count * sizeof(char *)); + + rule->tags[rule->tags_count - 1] = strdup(tag); + +} + + +/****************************************************************************** +* * +* Paramètres : rule = règle de détection à consulter. * +* count = quantité d'éléments retournés. [OUT] * +* * +* Description : Indique les éventuelles étiquettes associées à une règle. * +* * +* Retour : Liste d'étiquettes associées à la règle consultée. * +* * +* Remarques : - * +* * +******************************************************************************/ + +const char * const *g_scan_rule_list_tags(const GScanRule *rule, size_t *count) +{ + const char * const *result; /* Liste à retourner */ + + result = rule->tags; + + *count = rule->tags_count; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : rule = règle de détection à compléter. * +* pattern = nouveau motif de détection. * +* * +* Description : Intègre une nouvelle variable locale à une règle. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_scan_rule_add_local_variable(GScanRule *rule, GSearchPattern *pattern) +{ + if (G_IS_BYTES_TOKEN(pattern)) + { + if (rule->bytes_used == rule->bytes_allocated) + { + rule->bytes_allocated += PATTERN_ALLOC_SIZE; + rule->bytes_locals = realloc(rule->bytes_locals, rule->bytes_allocated * sizeof(GSearchPattern *)); + } + + rule->bytes_locals[rule->bytes_used++] = pattern; + g_object_ref(G_OBJECT(pattern)); + + } + +} + + +/****************************************************************************** +* * +* Paramètres : rule = règle de détection à consulter. * +* target = nom d'une variable locale à retrouver. * +* * +* Description : Fournit une variable locale à une règle selon un nom. * +* * +* Retour : Motif de détection retrouvé ou NULL en cas d'échec. * +* * +* Remarques : La propriétée de l'instance renvoyée est partagée ! * +* * +******************************************************************************/ + +const GSearchPattern *g_scan_rule_get_local_variable(GScanRule *rule, const char *target) +{ + const GSearchPattern *result; /* Variable à retourner */ + size_t i; /* Boucle de parcours */ + const char *name; /* Désignation d'un motif */ + + result = NULL; + + for (i = 0; i < rule->bytes_used; i++) + { + name = g_search_pattern_get_name(rule->bytes_locals[i]); + + if (strcmp(name, target) == 0) + { + result = rule->bytes_locals[i]; + break; + } + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : rule = règle de détection à consulter. * +* target = nom d'une variable locale à retrouver. * +* count = quantité de motifs renvoyés. [OUT] * +* * +* Description : Fournit une liste de variables locales à partir d'un nom. * +* * +* Retour : Motifs de détection retrouvés ou NULL en cas d'échec. * +* * +* Remarques : La propriétée des instances renvoyées est partagée ! * +* * +******************************************************************************/ + +const GSearchPattern **g_scan_rule_get_local_variables(GScanRule *rule, const char *target, size_t *count) +{ + const GSearchPattern **result; /* Variables à retourner */ + size_t target_len; /* Nbre de caractères à évaluer*/ + size_t len_without_star; /* Taille sans masque */ + bool need_regex; /* Traitement complexe requis */ + size_t i; /* Boucle de parcours */ + char *regex; /* Définition complète */ + regex_t preg; /* Expression compilée */ + int ret; /* Bilan d'un appel */ + const char *name; /* Désignation d'un motif */ + + result = NULL; + + *count = 0; + + /* Premier cas de figure : la liste complète est attendue */ + + if (target == NULL) + { + need_all_of_them: + + *count = rule->bytes_used; + result = malloc(*count * sizeof(GSearchPattern *)); + + memcpy(result, rule->bytes_locals, *count); + + } + + /* Second cas de figure : identification au cas par cas */ + + else + { + target_len = strlen(target); + + len_without_star = 0; + + need_regex = false; + + for (i = 0; i < target_len; i++) + if (target[i] == '*') + break; + else + len_without_star++; + + for (i++; i < target_len; i++) + if (target[i] != '*') + { + need_regex = true; + goto try_harder; + } + + if (len_without_star == 0) + goto need_all_of_them; + + result = malloc(rule->bytes_used * sizeof(GSearchPattern *)); + + for (i = 0; i < rule->bytes_used; i++) + { + name = g_search_pattern_get_name(rule->bytes_locals[i]); + + if (strncmp(name, target, len_without_star) == 0) + { + result[*count] = rule->bytes_locals[i]; + (*count)++; + } + + } + + if (*count == 0) + { + free(result); + result = NULL; + } + + } + + try_harder: + + /* Dernier cas de figure : une expression régulière est vraisemblablement de mise */ + + if (need_regex) + { + regex = strdup(target); + + regex = strrpl(regex, "*", ".*"); + regex = strprep(regex, "^"); + regex = stradd(regex, "$"); + + ret = regcomp(&preg, regex, REG_NOSUB); + + if (ret != 0) + { + LOG_ERROR_REGCOMP(&preg, ret); + goto done; + } + + result = malloc(rule->bytes_used * sizeof(GSearchPattern *)); + + for (i = 0; i < rule->bytes_used; i++) + { + name = g_search_pattern_get_name(rule->bytes_locals[i]); + + ret = regexec(&preg, name, 0, NULL, 0); + + if (ret != REG_NOMATCH) + { + result[*count] = rule->bytes_locals[i]; + (*count)++; + } + + } + + if (*count == 0) + { + free(result); + result = NULL; + } + + regfree(&preg); + + done: + + free(regex); + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : rule = règle de détection à compléter. * +* expr = expression de condition à satisfaire. * +* * +* Description : Définit l'expression d'une correspondance recherchée. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_scan_rule_set_match_condition(GScanRule *rule, GScanExpression *expr) +{ + rule->condition = expr; + + g_object_ref(G_OBJECT(expr)); + +} + + +/****************************************************************************** +* * +* Paramètres : rule = règle de détection à considérer. * +* backend = moteur d'analyse pour données brutes. * +* context = contexte de l'analyse à mener. * +* * +* Description : Prépare le suivi de recherche de motifs pour une règle. * +* * +* Retour : Bilan de l'opération à renvoyer. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_scan_rule_setup_backend(GScanRule *rule, GEngineBackend *backend, GScanContext *context) +{ + bool result; /* Statut à retourner */ + size_t maxsize; /* Taille maximale des atomes */ + GSearchPattern *pattern; /* Motif à intégrer */ + size_t i; /* Boucle de parcours */ + + /* Suivi des conditions de correspondance */ + + result = g_scan_context_set_rule_condition(context, rule->name, rule->condition); + if (!result) goto exit; + + /* Programmation des motifs recherchés */ + + maxsize = g_engine_backend_get_atom_max_size(backend); + + for (i = 0; i < rule->bytes_used && result; i++) + { + pattern = rule->bytes_locals[i]; + result = g_bytes_token_enroll(G_BYTES_TOKEN(pattern), backend, maxsize); + } + + exit: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : rule = règle de détection à considérer. * +* backend = moteur d'analyse pour données brutes. * +* * +* Description : Récupère les identifiants finaux pour les motifs recherchés. * +* * +* Retour : Bilan de l'opération à renvoyer. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_scan_rule_define_pattern_ids(GScanRule *rule, GEngineBackend *backend) +{ + bool result; /* Statut à retourner */ + size_t i; /* Boucle de parcours */ + GSearchPattern *pattern; /* Motif à intégrer */ + + result = true; + + for (i = 0; i < rule->bytes_used && result; i++) + { + pattern = rule->bytes_locals[i]; + result = g_bytes_token_build_id(G_BYTES_TOKEN(pattern), backend); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : rule = règle de détection à considérer. * +* backend = moteur d'analyse pour données brutes. * +* context = contexte de l'analyse à mener. * +* * +* Description : Lance une analyse d'un contenu binaire selon une règle. * +* * +* Retour : Contexte de suivi pour l'analyse menée. * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_scan_rule_check(GScanRule *rule, GEngineBackend *backend, GScanContext *context) +{ + scan_node_check_params_t params; /* Rassemblement de paramètres */ + vmpa2t start; /* Point de début du contenu */ + vmpa2t end; /* Point de fin du contenu */ + size_t i; /* Boucle de parcours */ + GSearchPattern *pattern; /* Motif à intégrer */ + GScanMatches *matches; /* Correspondances établies */ + + /* Définition d'un contexte */ + + params.context = context; + params.content = g_scan_context_get_content(context); + params.allocator = g_umem_slice_new(sizeof(match_area_t)); + + g_binary_content_compute_start_pos(params.content, &start); + g_binary_content_compute_end_pos(params.content, &end); + + params.content_start = start.physical; + params.content_end = end.physical; + + /* Vérifications */ + + for (i = 0; i < rule->bytes_used; i++) + { + pattern = rule->bytes_locals[i]; + + matches = g_scan_bytes_matches_new(); + + g_bytes_token_check(G_BYTES_TOKEN(pattern), G_SCAN_BYTES_MATCHES(matches), ¶ms); + + g_scan_context_register_full_matches(context, pattern, matches); + + g_object_unref(G_OBJECT(matches)); + + } + + g_object_unref(G_OBJECT(params.content)); + //g_object_unref(G_OBJECT(params.allocator)); + +} + + +/****************************************************************************** +* * +* Paramètres : rule = règle de détection à considérer. * +* context = contexte de l'analyse à mener. * +* full = force un affichage complet des résultats. * +* fd = canal d'écriture. * +* * +* Description : Affiche une règle au format texte. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_scan_rule_output_to_text(const GScanRule *rule, GScanContext *context, bool full, int fd) +{ + GScanOptions *options; /* Options de l'utilisateur */ + bool selected; /* Affichage attendu ? */ + size_t i; /* Boucle de parcours */ + GBinContent *content; /* Contenu binaire scanné */ + char *desc; /* Description de ce contenu */ + + /** + * Si la règle n'a pas fait mouche, rien n'est imprimé. + */ + if (!g_scan_context_has_match_for_rule(context, rule->name)) + return; + + options = g_scan_context_get_options(context); + + selected = g_scan_options_has_tag_as_selected(options, NULL); + + /** + * Si la règle comporte des étiquettes et que l'utilisateur en a spécifié + * également. + */ + if (rule->tags_count > 0 && !selected) + { + for (i = 0; i < rule->tags_count && !selected; i++) + selected = g_scan_options_has_tag_as_selected(options, rule->tags[i]); + } + + if (selected) + { + write(fd, rule->name, strlen(rule->name)); + + if (g_scan_options_get_print_tags(options)) + { + write(fd, " [", 2); + + for (i = 0; i < rule->tags_count; i++) + { + if (i > 0) + write(fd, ",", 1); + + write(fd, rule->tags[i], strlen(rule->tags[i])); + + } + + write(fd, "]", 1); + + } + + write(fd, " ", 1); + + content = g_scan_context_get_content(context); + + desc = g_binary_content_describe(content, true); + + write(fd, desc, strlen(desc)); + write(fd, "\n", 1); + + free(desc); + + g_object_unref(G_OBJECT(content)); + + if (full) + for (i = 0; i < rule->bytes_used; i++) + g_search_pattern_output_to_text(rule->bytes_locals[i], context, fd); + + } + + g_object_unref(G_OBJECT(options)); + +} + + +/****************************************************************************** +* * +* Paramètres : rule = règle de détection à considérer. * +* context = contexte de l'analyse à mener. * +* * +* Description : Convertit une règle en texte. * +* * +* Retour : Données textuelles ou NULL en cas d'erreur. * +* * +* Remarques : - * +* * +******************************************************************************/ + +char *g_scan_rule_convert_as_text(const GScanRule *rule, GScanContext *context) +{ + char *result; /* Données à retourner */ + char *name; /* Nom "unique" pour le canal */ + int ret; /* Bilan de création de nom */ + int fd; /* Canal d'écriture */ + struct stat info; /* Infos. incluant une taille */ + ssize_t got; /* Données effectivement relues*/ + + static unsigned long long counter = 0; + + result = NULL; + + ret = asprintf(&name, "rost-rule2text-%llu", counter++); + if (ret == -1) goto exit; + + fd = memfd_create(name, MFD_CLOEXEC); + if (fd == -1) + { + LOG_ERROR_N("memfd_create"); + goto exit_with_name; + } + + g_scan_rule_output_to_text(rule, context, true, fd); + + ret = fstat(fd, &info); + if (ret != 0) + { + LOG_ERROR_N("fstat"); + goto exit_with_name_and_fd; + } + + result = malloc((info.st_size + 1) * sizeof(char)); + + lseek(fd, SEEK_SET, 0); + + got = read(fd, result, info.st_size); + if (got != info.st_size) + { + LOG_ERROR_N("read"); + free(result); + goto exit_with_name_and_fd; + } + + result[info.st_size] = '\0'; + + exit_with_name_and_fd: + + close(fd); + + exit_with_name: + + free(name); + + exit: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : rule = règle de détection à considérer. * +* context = contexte de l'analyse à mener. * +* padding = éventuel bourrage initial à placer ou NULL. * +* level = profondeur actuelle. * +* fd = canal d'écriture. * +* tail = décline la pose d'une virgule finale ? * +* * +* Description : Affiche une règle au format JSON. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_scan_rule_output_to_json(const GScanRule *rule, GScanContext *context, const sized_string_t *padding, unsigned int level, int fd, bool tail) +{ + size_t i; /* Boucle de parcours #1 */ + bool sub_tail; /* Saut de la virgule finale ? */ + size_t k; /* Boucle de parcours #2 */ + GBinContent *content; /* Contenu binaire scanné */ + char *desc; /* Description de ce contenu */ + + /* Introduction */ + + for (i = 0; i < level; i++) + write(fd, padding->data, padding->len); + + write(fd, "{\n", 2); + + /* Désignation de la règle */ + + for (i = 0; i < (level + 1); i++) + write(fd, padding->data, padding->len); + + write(fd, "\"name\": \"", 9); + + write(fd, rule->name, strlen(rule->name)); + + write(fd, "\",\n", 3); + + /* Etiquettes ? */ + + for (i = 0; i < (level + 1); i++) + write(fd, padding->data, padding->len); + + write(fd, "\"tags\": [", 9); + + if (rule->tags_count > 0) + { + write(fd, "\n", 1); + + for (k = 0; k < rule->tags_count; k++) + { + for (i = 0; i < (level + 2); i++) + write(fd, padding->data, padding->len); + + write(fd, "\"", 1); + + write(fd, rule->tags[k], strlen(rule->tags[k])); + + write(fd, "\"", 1); + + if ((k + 1) < rule->tags_count) + write(fd, ",", 1); + + write(fd, "\n", 1); + + } + + for (i = 0; i < (level + 1); i++) + write(fd, padding->data, padding->len); + + } + + write(fd, "],\n", 3); + + /* Cible du scan */ + + for (i = 0; i < (level + 1); i++) + write(fd, padding->data, padding->len); + + write(fd, "\"target\": \"", 11); + + content = g_scan_context_get_content(context); + + desc = g_binary_content_describe(content, true); + + write(fd, desc, strlen(desc)); + + free(desc); + + g_object_unref(G_OBJECT(content)); + + write(fd, "\",\n", 3); + + /* Affichage des correspondances d'octets */ + + for (i = 0; i < (level + 1); i++) + write(fd, padding->data, padding->len); + + write(fd, "\"bytes_patterns\": [\n", 20); + + for (i = 0; i < rule->bytes_used; i++) + { + sub_tail = ((i + 1) == rule->bytes_used); + + g_search_pattern_output_to_json(rule->bytes_locals[i], context, padding, level + 2, fd, sub_tail); + + } + + for (i = 0; i < (level + 1); i++) + write(fd, padding->data, padding->len); + + write(fd, "],\n", 3); + + /* Bilan du filtrage */ + + for (i = 0; i < (level + 1); i++) + write(fd, padding->data, padding->len); + + write(fd, "\"matched\": ", 11); + + if (g_scan_context_has_match_for_rule(context, rule->name)) + write(fd, "true", 4); + else + write(fd, "false", 5); + + write(fd, "\n", 1); + + /* Conclusion */ + + for (i = 0; i < level; i++) + write(fd, padding->data, padding->len); + + if (tail) + write(fd, "}\n", 2); + else + write(fd, "},\n", 3); + +} + + +/****************************************************************************** +* * +* Paramètres : rule = règle de détection à considérer. * +* context = contexte de l'analyse à mener. * +* * +* Description : Convertit une règle en JSON. * +* * +* Retour : Données textuelles au format JSON ou NULL en cas d'erreur. * +* * +* Remarques : - * +* * +******************************************************************************/ + +char *g_scan_rule_convert_as_json(const GScanRule *rule, GScanContext *context) +{ + char *result; /* Données à retourner */ + char *name; /* Nom "unique" pour le canal */ + int ret; /* Bilan de création de nom */ + int fd; /* Canal d'écriture */ + sized_string_t padding; /* Bourrage pour le JSON */ + struct stat info; /* Infos. incluant une taille */ + ssize_t got; /* Données effectivement relues*/ + + static unsigned long long counter = 0; + + result = NULL; + + ret = asprintf(&name, "rost-rule2json-%llu", counter++); + if (ret == -1) goto exit; + + fd = memfd_create(name, MFD_CLOEXEC); + if (fd == -1) + { + LOG_ERROR_N("memfd_create"); + goto exit_with_name; + } + + padding.data = " "; + padding.len = 3; + + g_scan_rule_output_to_json(rule, context, &padding, 0, fd, false); + + ret = fstat(fd, &info); + if (ret != 0) + { + LOG_ERROR_N("fstat"); + goto exit_with_name_and_fd; + } + + result = malloc((info.st_size + 1) * sizeof(char)); + + lseek(fd, SEEK_SET, 0); + + got = read(fd, result, info.st_size); + if (got != info.st_size) + { + LOG_ERROR_N("read"); + free(result); + goto exit_with_name_and_fd; + } + + result[info.st_size] = '\0'; + + exit_with_name_and_fd: + + close(fd); + + exit_with_name: + + free(name); + + exit: + + return result; + +} |