From 1c5a0e67186def152536d9c506e2e6c3a3a265c5 Mon Sep 17 00:00:00 2001 From: Cyrille Bagard Date: Mon, 7 Aug 2023 02:32:09 +0200 Subject: Reject any rule referencing itself as match condition --- src/analysis/scan/Makefile.am | 2 + src/analysis/scan/context.c | 16 ++- src/analysis/scan/exprs/access.c | 17 +++- src/analysis/scan/scope-int.h | 54 ++++++++++ src/analysis/scan/scope.c | 209 +++++++++++++++++++++++++++++++++++++++ src/analysis/scan/scope.h | 24 ++++- tests/analysis/scan/fuzzing.py | 15 +++ 7 files changed, 329 insertions(+), 8 deletions(-) create mode 100644 src/analysis/scan/scope-int.h create mode 100644 src/analysis/scan/scope.c diff --git a/src/analysis/scan/Makefile.am b/src/analysis/scan/Makefile.am index d4d7aa4..d24f4a8 100644 --- a/src/analysis/scan/Makefile.am +++ b/src/analysis/scan/Makefile.am @@ -36,6 +36,8 @@ libanalysisscan_la_SOURCES = \ rule.h rule.c \ scanner-int.h \ scanner.h scanner.c \ + scope-int.h \ + scope.h scope.c \ space-int.h \ space.h space.c \ tokens.l \ diff --git a/src/analysis/scan/context.c b/src/analysis/scan/context.c index 1f9c38e..f108e93 100644 --- a/src/analysis/scan/context.c +++ b/src/analysis/scan/context.c @@ -763,7 +763,9 @@ bool g_scan_context_has_match_for_rule(GScanContext *context, const char *name) bool result; /* Bilan à retourner */ size_t i; /* Boucle de parcours */ rule_condition_t *cond; /* Condition à considérer */ + GScanScope *scope; /* Définition de portées */ GScanExpression *new; /* Nouvelle expression réduite */ + ScanReductionState state; /* Statut d'une réduction */ bool valid; /* Validité d'une récupération */ result = false; @@ -786,20 +788,26 @@ bool g_scan_context_has_match_for_rule(GScanContext *context, const char *name) if (!cond->final_reduced) { - valid = g_scan_expression_reduce(cond->expr, context, NULL, &new); - if (!valid || new == NULL) goto exit; + scope = g_scan_scope_new(name); + + state = g_scan_expression_reduce(cond->expr, context, scope, &new); + if (state == SRS_UNRESOLVABLE) goto exit_reduction; g_object_unref(G_OBJECT(cond->expr)); cond->expr = new; - valid = g_scan_expression_reduce_to_boolean(cond->expr, context, NULL, &new); - if (!valid || new == NULL) goto exit; + valid = g_scan_expression_reduce_to_boolean(cond->expr, context, scope, &new); + if (!valid || new == NULL) goto exit_reduction; g_object_unref(G_OBJECT(cond->expr)); cond->expr = new; cond->final_reduced = true; + exit_reduction: + + g_object_unref(G_OBJECT(scope)); + } /* Tentative de récupération d'un bilan final */ diff --git a/src/analysis/scan/exprs/access.c b/src/analysis/scan/exprs/access.c index 1c3a880..a8f0dc9 100644 --- a/src/analysis/scan/exprs/access.c +++ b/src/analysis/scan/exprs/access.c @@ -428,6 +428,7 @@ static ScanReductionState g_scan_named_access_reduce(GScanNamedAccess *expr, GSc ScanReductionState result; /* Etat synthétisé à retourner */ GRegisteredItem *resolved; /* Cible concrète obtenue */ GScanExpression *new_next; /* Nouvelle version du suivant */ + const char *current_rule; /* Nom de la règle courante */ bool status; /* Bilan d'une autre règle */ resolved = _g_scan_named_access_prepare_reduction(expr, ctx, scope); @@ -478,10 +479,20 @@ static ScanReductionState g_scan_named_access_reduce(GScanNamedAccess *expr, GSc if (g_scan_context_has_rule_for_name(ctx, expr->target)) { - status = g_scan_context_has_match_for_rule(ctx, expr->target); + current_rule = g_scan_scope_get_rule_name(scope); - *out = g_scan_literal_expression_new(LVT_BOOLEAN, &status); - result = SRS_REDUCED; + /* Si référence circulaire il y a... */ + if (strcmp(current_rule, expr->target) == 0) + result = SRS_UNRESOLVABLE; + + else + { + status = g_scan_context_has_match_for_rule(ctx, expr->target); + + *out = g_scan_literal_expression_new(LVT_BOOLEAN, &status); + result = SRS_REDUCED; + + } } diff --git a/src/analysis/scan/scope-int.h b/src/analysis/scan/scope-int.h new file mode 100644 index 0000000..2d70532 --- /dev/null +++ b/src/analysis/scan/scope-int.h @@ -0,0 +1,54 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * scope-int.h - prototypes internes pour la définition d'une portée locale de variables + * + * Copyright (C) 2023 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 . + */ + + +#ifndef _ANALYSIS_SCAN_SCOPE_INT_H +#define _ANALYSIS_SCAN_SCOPE_INT_H + + +#include "scope.h" + + + +/* Portée locale de variables et règle d'appartenance (instance) */ +struct _GScanScope +{ + GObject parent; /* A laisser en premier */ + + char *rule; /* Règle d'appartenance */ + +}; + +/* Portée locale de variables et règle d'appartenance (classe) */ +struct _GScanScopeClass +{ + GObjectClass parent; /* A laisser en premier */ + +}; + + +/* Met en place une définition de portée pour variables. */ +bool g_scan_scope_create(GScanScope *, const char *); + + + +#endif /* _ANALYSIS_SCAN_SCOPE_INT_H */ diff --git a/src/analysis/scan/scope.c b/src/analysis/scan/scope.c new file mode 100644 index 0000000..852b1d3 --- /dev/null +++ b/src/analysis/scan/scope.c @@ -0,0 +1,209 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * scope.c - définition d'une portée locale de variables + * + * Copyright (C) 2023 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 . + */ + + +#include "scope.h" + + +#include +#include + + +#include "scope-int.h" + + + +/* Initialise la classe des définitions de portée locale. */ +static void g_scan_scope_class_init(GScanScopeClass *); + +/* Initialise une instance de définition de portée locale. */ +static void g_scan_scope_init(GScanScope *); + +/* Supprime toutes les références externes. */ +static void g_scan_scope_dispose(GScanScope *); + +/* Procède à la libération totale de la mémoire. */ +static void g_scan_scope_finalize(GScanScope *); + + + +/* Indique le type défini pour la définition de portée de variables. */ +G_DEFINE_TYPE(GScanScope, g_scan_scope, G_TYPE_OBJECT); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des définitions de portée locale. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_scope_class_init(GScanScopeClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_scope_dispose; + object->finalize = (GObjectFinalizeFunc)g_scan_scope_finalize; + +} + + +/****************************************************************************** +* * +* Paramètres : scope = instance à initialiser. * +* * +* Description : Initialise une instance de définition de portée locale. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_scope_init(GScanScope *scope) +{ + scope->rule = NULL; + +} + + +/****************************************************************************** +* * +* Paramètres : scope = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_scope_dispose(GScanScope *scope) +{ + G_OBJECT_CLASS(g_scan_scope_parent_class)->dispose(G_OBJECT(scope)); + +} + + +/****************************************************************************** +* * +* Paramètres : scope = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_scope_finalize(GScanScope *scope) +{ + if (scope->rule != NULL) + free(scope->rule); + + G_OBJECT_CLASS(g_scan_scope_parent_class)->finalize(G_OBJECT(scope)); + +} + + +/****************************************************************************** +* * +* Paramètres : rule = désignation de la règle courante dans l'analyse. * +* * +* Description : Prépare une définition de portée pour variables. * +* * +* Retour : Définition mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanScope *g_scan_scope_new(const char *rule) +{ + GScanScope *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_SCAN_SCOPE, NULL); + + if (!g_scan_scope_create(result, rule)) + g_clear_object(&result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : scope = définition de portée à à initialiser pleinement. * +* rule = désignation de la règle courante dans l'analyse. * +* * +* Description : Met en place une définition de portée pour variables. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_scan_scope_create(GScanScope *scope, const char *rule) +{ + bool result; /* Bilan à retourner */ + + result = true; + + scope->rule = strdup(rule); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : scope = définition de portée à consulter. * +* * +* Description : Fournit le nom de la règle d'appartenance. * +* * +* Retour : Nom de la règle courante pour une analyse. * +* * +* Remarques : - * +* * +******************************************************************************/ + +const char *g_scan_scope_get_rule_name(const GScanScope *scope) +{ + const char *result; /* Chemin à retourner */ + + result = scope->rule; + + return result; + +} diff --git a/src/analysis/scan/scope.h b/src/analysis/scan/scope.h index 1e5de2c..26b8757 100644 --- a/src/analysis/scan/scope.h +++ b/src/analysis/scan/scope.h @@ -25,12 +25,34 @@ #define _ANALYSIS_SCAN_SCOPE_H +#include +#include -typedef void *GScanScope; +#define G_TYPE_SCAN_SCOPE g_scan_scope_get_type() +#define G_SCAN_SCOPE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_SCOPE, GScanScope)) +#define G_IS_SCAN_SCOPE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_SCOPE)) +#define G_SCAN_SCOPE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_SCOPE, GScanScopeClass)) +#define G_IS_SCAN_SCOPE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_SCOPE)) +#define G_SCAN_SCOPE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_SCOPE, GScanScopeClass)) +/* Portée locale de variables et règle d'appartenance (instance) */ +typedef struct _GScanScope GScanScope; + +/* Portée locale de variables et règle d'appartenance (classe) */ +typedef struct _GScanScopeClass GScanScopeClass; + + +/* Indique le type défini pour la définition de portée de variables. */ +GType g_scan_scope_get_type(void); + +/* Prépare une définition de portée pour variables. */ +GScanScope *g_scan_scope_new(const char *); + +/* Fournit le nom de la règle d'appartenance. */ +const char *g_scan_scope_get_rule_name(const GScanScope *); diff --git a/tests/analysis/scan/fuzzing.py b/tests/analysis/scan/fuzzing.py index d5fce4b..53227af 100644 --- a/tests/analysis/scan/fuzzing.py +++ b/tests/analysis/scan/fuzzing.py @@ -93,3 +93,18 @@ rule test { ''' self.check_rule_failure(rule) + + + def testSelfReferencingRule(self): + """Reject any rule referencing itself as match condition.""" + + rule = ''' +rule test { + + condition: + test + +} +''' + + self.check_rule_failure(rule) -- cgit v0.11.2-87-g4458