diff options
author | Cyrille Bagard <nocbos@gmail.com> | 2024-12-13 23:19:31 (GMT) |
---|---|---|
committer | Cyrille Bagard <nocbos@gmail.com> | 2024-12-13 23:19:31 (GMT) |
commit | c9207edf32d966e67bccc1ed82cf0958de459817 (patch) | |
tree | 166d4dee8dbc689672da410cea9d7d271b4ac5c7 /src | |
parent | 6433f2aa7552b43b3d0d753f0d525e2040a5b922 (diff) |
Update the exploitation of the GObject memory hole.
Diffstat (limited to 'src')
-rw-r--r-- | src/common/Makefile.am | 1 | ||||
-rw-r--r-- | src/glibext/Makefile.am | 4 | ||||
-rw-r--r-- | src/glibext/objhole-int.h | 166 | ||||
-rw-r--r-- | src/glibext/objhole.c | 191 | ||||
-rw-r--r-- | src/glibext/objhole.h | 114 |
5 files changed, 369 insertions, 107 deletions
diff --git a/src/common/Makefile.am b/src/common/Makefile.am index 7925b66..687cb63 100644 --- a/src/common/Makefile.am +++ b/src/common/Makefile.am @@ -50,6 +50,7 @@ libcommon4_la_SOURCES = \ asm.h asm.c \ bits.h bits.c \ compiler.h \ + cpp.h \ datatypes.h \ dllist.h dllist.c \ entropy.h entropy.c \ diff --git a/src/glibext/Makefile.am b/src/glibext/Makefile.am index 816f033..738f5b3 100644 --- a/src/glibext/Makefile.am +++ b/src/glibext/Makefile.am @@ -13,7 +13,7 @@ noinst_LTLIBRARIES = libglibext.la libglibextui.la # glinecursor.h glinecursor.c \ # gnhash.h gnhash.c \ # notifier.h \ -# objhole.h \ +# \ # proto.h \ # seq.h seq.c \ # _signal.h signal.c \ @@ -41,6 +41,8 @@ noinst_LTLIBRARIES = libglibext.la libglibextui.la libglibext_la_SOURCES = \ chrysamarshal.h chrysamarshal.c \ helpers.h \ + objhole-int.h \ + objhole.h objhole.c \ portion-int.h \ portion.h portion.c \ singleton-int.h \ diff --git a/src/glibext/objhole-int.h b/src/glibext/objhole-int.h new file mode 100644 index 0000000..b4abf6f --- /dev/null +++ b/src/glibext/objhole-int.h @@ -0,0 +1,166 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * objhole.h - définitions internes pour ll'utilisation d'un espace inutilisé dans la structure GObject + * + * Copyright (C) 2024 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 Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _GLIBEXT_OBJHOLE_INT_H +#define _GLIBEXT_OBJHOLE_INT_H + + +#include "objhole.h" + + +#include "../common/cpp.h" + + + +/** + * Une structure GObject a la définition suivante : + * + * struct _GObject + * { + * GTypeInstance g_type_instance; + * volatile guint ref_count; + * GData *qdata; + * }; + * + * Chaque objet GLib alloué comporte ainsi 4 octets inutilisés : + * + * (gdb) pt /o GObject + * type = struct _GObject { + * / 0 | 8 / GTypeInstance g_type_instance; + * / 8 | 4 / guint ref_count; + * / XXX 4-byte hole / + * / 16 | 8 / GData *qdata; + * + * / total size (bytes): 24 / + * } + * + * La situation n'a pas échappé aux développeurs GLib, avec la définition réelle + * de la structure (cf. https://github.com/GNOME/glib/blob/main/gobject/gobject.c) : + * + * #if SIZEOF_INT == 4 && GLIB_SIZEOF_VOID_P == 8 + * #define HAVE_OPTIONAL_FLAGS + * #endif + * + * typedef struct + * { + * GTypeInstance g_type_instance; + * guint ref_count; + * #ifdef HAVE_OPTIONAL_FLAGS + * guint optional_flags; + * #endif + * GData *qdata; + * } GObjectReal; + * + * G_STATIC_ASSERT(sizeof(GObject) == sizeof(GObjectReal)); + * G_STATIC_ASSERT(G_STRUCT_OFFSET(GObject, ref_count) == G_STRUCT_OFFSET(GObjectReal, ref_count)); + * G_STATIC_ASSERT(G_STRUCT_OFFSET(GObject, qdata) == G_STRUCT_OFFSET(GObjectReal, qdata)); + * + * L'espace entre les deux derniers champs ne peut donc être pleinement exploité deux fois. + */ + +/** + * Les bits effectivements utilisés par GLib s'identifie ainsi (02/12/24) : + * + * $ wget -qO /dev/stdout https://raw.githubusercontent.com/GNOME/glib/refs/heads/main/gobject/gobject.c \ + * | grep ' * #define OPTIONAL_FLAG_' + * #define OPTIONAL_FLAG_IN_CONSTRUCTION (1 << 0) + * #define OPTIONAL_FLAG_HAS_SIGNAL_HANDLER (1 << 1) + * #define OPTIONAL_FLAG_HAS_NOTIFY_HANDLER (1 << 2) + * #define OPTIONAL_FLAG_LOCK (1 << 3) + * #define OPTIONAL_FLAG_EVER_HAD_WEAK_REF (1 << 4) + * + * Les n premiers bits doivent ainsi être préservés, même s'il est possible de + * partager le bit de verrouilage OPTIONAL_FLAG_LOCK. + */ + + +#ifndef HAVE_OPTIONAL_FLAGS_IN_GOBJECT + +# if SIZEOF_INT == 4 && GLIB_SIZEOF_VOID_P >= 8 +# define HAVE_OPTIONAL_FLAGS_IN_GOBJECT 1 +# else +# define HAVE_OPTIONAL_FLAGS_IN_GOBJECT 0 +# endif + +#endif + + +/* Nouvelle version dense des objets (instance) */ +typedef struct _GThickObject +{ + /** + * (cf. structure GObjectReal officielle). + */ + + GTypeInstance g_type_instance; /* Type d'objet */ + guint ref_count; /* Décompte des références */ + +#ifdef HAVE_OPTIONAL_FLAGS_IN_GOBJECT + guint extra; /* Zone partagée avec GLib */ +#endif + + GData *qdata; /* Données complémentaires ? */ + +#ifndef HAVE_OPTIONAL_FLAGS_IN_GOBJECT + guint extra; /* Zone supplémentaire propre */ +#endif + +} GThickObject; + +/* Nouvelle version dense des objets (classe) */ +struct _GThickObjectClass +{ + GObjectClass parent; /* A laisser en premier */ + +}; + + +/** + * Définition du périmètre et des moyens d'accès. + */ + +/* GLib 2.83.0 - cfa36f5e9 */ +#define GOBJECT_RESERVED_EXTRA_BITS 5 + +#define GET_GOBJECT_EXTRA(obj, tp) \ + ({ \ + BUILD_BUG_ON(sizeof(tp) > sizeof(guint)); \ + tp *___result; \ + guint __val; \ + __val = g_thick_object_get_extra(obj); \ + ___result = (tp *)(guint []){ __val }; \ + ___result; \ + }) + +#define SET_GOBJECT_EXTRA(obj, tp, data) \ + ({ \ + BUILD_BUG_ON(sizeof(tp) > sizeof(guint)); \ + BUILD_BUG_ON(sizeof(data) > sizeof(guint *)); \ + guint __val; \ + __val = *(guint *)data; \ + g_thick_object_set_extra(obj, __val); \ + }) + + + +#endif /* _GLIBEXT_OBJHOLE_INT_H */ diff --git a/src/glibext/objhole.c b/src/glibext/objhole.c new file mode 100644 index 0000000..20bb2a8 --- /dev/null +++ b/src/glibext/objhole.c @@ -0,0 +1,191 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * objhole.c - utilisation d'un espace inutilisé dans la structure GObject + * + * Copyright (C) 2024 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 Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "objhole.h" + + +#include <assert.h> + + +#include "objhole-int.h" + + + +/* Initialise la classe des objets à la structure dense. */ +static void g_thick_object_class_init(GThickObjectClass *); + +/* Initialise une instance d'objet à la structure dense. */ +static void g_thick_object_init(GThickObject *); + +/* Supprime toutes les références externes. */ +static void g_thick_object_dispose(GThickObject *); + +/* Procède à la libération totale de la mémoire. */ +static void g_thick_object_finalize(GThickObject *); + + + +G_DEFINE_TYPE(GThickObject, g_thick_object, G_TYPE_OBJECT); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des objets à la structure dense. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_thick_object_class_init(GThickObjectClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_thick_object_dispose; + object->finalize = (GObjectFinalizeFunc)g_thick_object_finalize; + +} + + +/****************************************************************************** +* * +* Paramètres : obj = instance à initialiser. * +* * +* Description : Initialise une instance d'objet à la structure dense. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_thick_object_init(GThickObject *obj) +{ + obj->extra = 0; + +} + + +/****************************************************************************** +* * +* Paramètres : obj = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_thick_object_dispose(GThickObject *obj) +{ + G_OBJECT_CLASS(g_thick_object_parent_class)->dispose(G_OBJECT(obj)); + +} + + +/****************************************************************************** +* * +* Paramètres : obj = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_thick_object_finalize(GThickObject *obj) +{ + G_OBJECT_CLASS(g_thick_object_parent_class)->finalize(G_OBJECT(obj)); + +} + + +/****************************************************************************** +* * +* Paramètres : obj = instance d'objet GLib à consulter. * +* * +* Description : Fournit la valeur courante de la zone de stockage d'un objet.* +* * +* Retour : Valeur de 32 lues et expurgées des bits GLib. * +* * +* Remarques : - * +* * +******************************************************************************/ + +guint g_thick_object_get_extra(const GThickObject *obj) +{ + guint result; /* Valeur à retourner */ + guint mask; /* Masque à appliquer */ + + result = g_atomic_int_get(&obj->extra); + + assert(GOBJECT_RESERVED_EXTRA_BITS < 30); + + mask = (1 << GOBJECT_RESERVED_EXTRA_BITS) - 1; + + result &= ~mask; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : obj = instance d'objet GLib à consulter. * +* val = valeur de 32 à conserver. * +* * +* Description : Définit la valeur courante de la zone de stockage d'un objet.* +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_thick_object_set_extra(GThickObject *obj, guint val) +{ + guint mask; /* Masque à appliquer */ + + assert(GOBJECT_RESERVED_EXTRA_BITS < 30); + + mask = (1 << GOBJECT_RESERVED_EXTRA_BITS) - 1; + + assert((val & mask) == 0); + + val &= ~mask; + + g_atomic_int_and(&obj->extra, val | mask); + + g_atomic_int_or(&obj->extra, val); + +} diff --git a/src/glibext/objhole.h b/src/glibext/objhole.h index 38f4bd5..c1e8cf1 100644 --- a/src/glibext/objhole.h +++ b/src/glibext/objhole.h @@ -2,7 +2,7 @@ /* Chrysalide - Outil d'analyse de fichiers binaires * objhole.h - prototypes pour l'utilisation d'un espace inutilisé dans la structure GObject * - * Copyright (C) 2020 Cyrille Bagard + * Copyright (C) 2020-2024 Cyrille Bagard * * This file is part of Chrysalide. * @@ -25,118 +25,20 @@ #define _GLIBEXT_OBJHOLE_H -#include <glib.h> -#include <glib-object.h> +#include "../glibext/helpers.h" -#include "../common/cpp.h" +#define G_TYPE_THICK_OBJECT (g_thick_object_get_type()) +DECLARE_GTYPE(GThickObject, g_thick_object, G, THICK_OBJECT); -/** - * Une structure GObject a la définition suivante : - * - * struct _GObject - * { - * GTypeInstance g_type_instance; - * volatile guint ref_count; - * GData *qdata; - * }; - * - * En revanche, le fichier "glib/gobject/gobject.c" précise la définition - * réelle de la structure selon l'environnement : - * - * #if SIZEOF_INT == 4 && GLIB_SIZEOF_VOID_P == 8 - * #define HAVE_OPTIONAL_FLAGS - * #endif - * - * typedef struct - * { - * GTypeInstance g_type_instance; - * guint ref_count; - * #ifdef HAVE_OPTIONAL_FLAGS - * guint optional_flags; - * #endif - * GData *qdata; - * } GObjectReal; - * - * G_STATIC_ASSERT(sizeof(GObject) == sizeof(GObjectReal)); - * G_STATIC_ASSERT(G_STRUCT_OFFSET(GObject, ref_count) == G_STRUCT_OFFSET(GObjectReal, ref_count)); - * G_STATIC_ASSERT(G_STRUCT_OFFSET(GObject, qdata) == G_STRUCT_OFFSET(GObjectReal, qdata)); - * - * L'espace entre les deux derniers champs ne peut donc être pleinement exploité deux fois. - */ - -#if 0 - -# define GET_GOBJECT_EXTRA(obj, tp) \ - ({ \ - BUILD_BUG_ON(sizeof(tp) > sizeof(guint)); \ - tp *___result; \ - ___result = (tp *)(((guint *)&obj->ref_count) + 1); \ - BUILD_BUG_ON((___result + 1) == (tp *)&obj->qdata); \ - ___result; \ - }) - -#endif - - -/** - * Choix du bit de verrou pour le champ "lock". - * - * Dans la structure exploitant le mot utilisé ici, ce verrou est généralement - * placé dans le bit de poids fort pour les objets qui l'utilisent. - */ - -#if __BYTE_ORDER == __LITTLE_ENDIAN - -# define HOLE_LOCK_BIT 31 - -#elif __BYTE_ORDER == __BIG_ENDIAN - -# define HOLE_LOCK_BIT 0 - -#else - -# error "Unknown byte order" - -#endif - - -/* Verrou d'accès pour une encapsulation */ -typedef struct _lockable_obj_extra_t -{ - gint lock; /* Gestion d'accès aux fanions */ - -} lockable_obj_extra_t; - - -#define INIT_GOBJECT_EXTRA_LOCK(xtr) \ - do \ - { \ - lockable_obj_extra_t *__lockable; \ - __lockable = (lockable_obj_extra_t *)xtr; \ - __lockable->lock = 0; \ - } \ - while (0) -#define LOCK_GOBJECT_EXTRA(xtr) \ - do \ - { \ - lockable_obj_extra_t *__lockable; \ - __lockable = (lockable_obj_extra_t *)xtr; \ - g_bit_lock(&__lockable->lock, HOLE_LOCK_BIT); \ - } \ - while (0) +/* Fournit la valeur courante de la zone de stockage d'un objet. */ +guint g_thick_object_get_extra(const GThickObject *); -#define UNLOCK_GOBJECT_EXTRA(xtr) \ - do \ - { \ - lockable_obj_extra_t *__lockable; \ - __lockable = (lockable_obj_extra_t *)xtr; \ - g_bit_unlock(&__lockable->lock, HOLE_LOCK_BIT); \ - } \ - while (0) +/* Définit la valeur courante de la zone de stockage d'un objet. */ +void g_thick_object_set_extra(GThickObject *, guint); |