x ∉ Lo : `Lx := T, si x n'est pas dans l'ensemble live en sortie, l'affectation est morte et peut être supprimée.if C then ε else ε est inutile si, après élimination du code mort, les deux branches sont vides.x := T est inutile si x ∉ L_out après elle. On la supprime. Un test if C then ε else ε est inutile une fois les deux branches vides.L'analyse de liveness rétrograde permet d'identifier précisément le code mort, notamment les affectations inutiles, pour optimiser le programme en supprimant ces instructions sans impact sur le comportement observable.
if C then S1 else S2 : Calculer L1 (live-in S1) et L2 (live-in S2), puis `Lobs(T) implicite avant chaque affectation pour déterminer les variables bien initialisées comme celles non live en entrée.if, l'ensemble des variables initialisées en sortie est l'intersection des ensembles des deux branches.while, l'ensemble des variables initialisées est calculé comme un point fixe garantissant l'initialisation dans toutes les exécutions.L'analyse en avant permet de vérifier que toutes les variables sont initialisées avant utilisation, tandis que l'analyse en arrière identifie celles qui le sont, garantissant la sécurité en Java.
Syntaxe CFG pour DCE : La syntaxe d’un CFG (Control Flow Graph) pour la DCE (Élimination de Code Mort) est composée d’un corps de programme F défini par une séquence de points de contrôle pc assignés à des blocs ou des branches, avec des branches conditionnelles ou inconditionnelles. La structure Corps F inclut une instruction initiale pc:=PC1 suivie d’une répétition d’assumptions, de blocs Kk et de branches Bk. La branche B peut être un retour, une affectation simple pc:=p, ou une branche conditionnelle pc:=(C ? p1 : p2).
État abstrait A : C’est une fonction qui, pour chaque point de contrôle PCk, associe soit à un ensemble L (live-in), soit à une structure G(p') représentant un goto vers un autre point de contrôle p'. La notation G*A désigne la fermeture transitive de cette association, formant une structure union-find permettant de suivre la connectivité et les cycles. La fonction LA(p) désigne l’ensemble effectif des variables live-in à p, qui est vide si un cycle sur soi-même est détecté.
Règle branchement conditionnel : Lorsqu’un branchement conditionnel pc:=(C?p1:p2) est analysé, si LA(p1) et LA(p2) sont égaux et que la condition C est morte (inutilisable), alors le test est considéré comme inutile. La branche peut alors être simplifiée en une affectation directe pc:=p1. Sinon, l’ensemble a des live-in effectifs est la réunion de LA(p1), LA(p2) et des variables de la condition C.
Itération : La méthode consiste à initialiser l’état abstrait A avec tous les points de contrôle mappés à l’ensemble vide {PCk ↦ ∅}. Ensuite, on remonte en ordre inverse à travers le CFG, en appliquant la mise à jour des états jusqu’à atteindre une stabilité, c’est-à-dire un point fixe où aucune modification supplémentaire n’est possible. Cette procédure permet de calculer précisément les ensembles LA(p).
A associe à chaque PC soit un ensemble L (live-in) soit un goto G(p') vers un autre PC, formant une structure union-find pour gérer la connectivité. La fermeture transitive G*A permet de détecter les cycles dans le CFG, ce qui est essentiel pour l’analyse. La fonction LA(p) représente l’ensemble effectif des variables live-in à un point p, qui est vide si un cycle sur soi-même est identifié. Lorsqu’un branchement conditionnel est analysé, si LA(p1) et LA(p2) sont égaux et que la condition est morte, le test est inutile et peut être simplifié en une affectation directe. L’itération commence avec un état initial vide et remonte en ordre inverse, en appliquant la mise à jour jusqu’à stabilité, permettant de déterminer avec précision les live-in effectifs.L’utilisation combinée des graphes de contrôle de flux et des structures abstraites permet d’affiner l’analyse de la liveness et d’optimiser l’élimination de code mort, en dépassant les simples analyses linéaires. La méthode itérative et la gestion des cycles sont essentielles pour une analyse précise et efficace.
p != NULL et p == NULL croisent l'état avec des valeurs précises modifiant le domaine abstrait, pouvant conduire à un état mort en cas de contradiction.p == q impose que les valeurs nullité de p et q soient compatibles, en intersectant leurs couples (Z, N), sans garantir qu'ils pointent vers la même adresse.p != NULL :*L'interprétation abstraite modélise la nullité des pointeurs pour détecter les erreurs de déréférencement et gérer les assertions de manière sûre.
while (C), croiser l'invariant avec ¬C pour raffiner l'état.requires pour les préconditions, ensures pour les postconditions, et assigns pour indiquer les variables modifiées.i ≤ b - a et i ≤ 31 en combinaison avec la condition de sortie de boucle.Les spécifications ACSL utilisent requires pour les préconditions, ensures pour les postconditions, et assigns pour indiquer les variables modifiées.
size_t pour les tailles et de tests explicites sur les limites permet d'éviter les débordements et erreurs d'allocation.-Wall -Wextra -Werror, -fstack-protector, -ftrapv et -fno-strict-overflow renforcent la détection et la prévention des vulnérabilités liées aux débordements.Identifier les causes classiques de comportements indéfinis en C, notamment les débordements, et appliquer des pratiques de codage rigoureuses ainsi que des options de compilation adaptées pour prévenir les vulnérabilités.
Reconnaître les vecteurs d'injection classiques et appliquer des techniques robustes de validation et d'échappement pour sécuriser les entrées utilisateur.
-fno-stack-protector → pas de canari. En donnant des entrées bien choisies on peut écraser l'adresse de retour et rediriger l'exécution. Avec -fstack-protector → le programme détecte la corruption et appelle __stack_chk_fail().Un débordement de buffer sur la pile permet d'écraser l'adresse de retour et de rediriger l'exécution vers un shellcode.
free(p1), un malloc suivant réutilise la même zone. En contrôlant l'entrée du second malloc on contrôle le pointeur de fonction appelé via p1.L'exemple Python illustre l'importance de toujours abaisser les privilèges même en cas d'exception.
frama-c -eva fichier.c ou frama-c-gui -eva fichier.c pour le plugin EVA, et frama-c -wp -wp-rte -wp-split fichier.c pour le plugin WP.-wp-rte insère automatiquement les assertions d'absence de RTE, et -wp-split découpe les obligations pour localiser précisément les échecs.Exploiter les forces complémentaires d'EVA et WP dans Frama-C permet une analyse statique robuste et une preuve formelle des programmes C.
fgets retourne NULL en cas d'erreur ou de fin de fichier, ce qui doit être vérifié pour éviter des attaques.-O2 peut supprimer des gardes de sécurité si un overflow signé est possible (UB).Anticiper les pièges classiques et maîtriser les bonnes pratiques pour réussir efficacement l'examen 2025 en sécurité et preuve de programmes.
-wp -wp-rte -wp-split, identifier les obligations orange, ajouter invariants et relancer.I doit être vrai à l'entréeLa sûreté des programmes C avec Frama-C WP s'obtient par une démarche rigoureuse et itérative d'annotation, vérification et correction jusqu'à la validation complète des preuves.
obs). ### Règles formelles Affectation x := T : - Si x ∈ Lo : L = (Lo \ {x}) ∪ vars(T) → affectation utile -")x := T : - Si x ∈ Lo : L = (Lo \ {x}) ∪ vars(T) → affectation utile - Si x ∉ Lo : L = Lo → affectation morte, on peut la supprimer If if C then S1 else S2 : Calculer L1 (live-in S1) et (Source: "Affectation x := T : - Si x ∈ Lo : L = (Lo \ {x}) ∪ vars(T) → affectation utile - Si x ∉ Lo : L = Lo → affectation morte, on peut la supprimer If if C then S1 else S2 : Calculer L1 (live-in S1) et L2 (live-in S2), puis L = L1 ∪ L2 ∪ vars(C) While : Invariant = point fixe par itérations. Avec ∇ = ⊔ sur treillis fini :")Linv = Lo ∪ vars(C) ∪ live-in(corps avec Linv en sortie) On itère jusqu'à stabilité. Obs : ♡{L} obs(T) {Lo} → L = Lo ∪ vars(T) Sortie de boucle : En sortie de while (C), croiser l'invariant avec ¬ _(Source: "fini : Linv = Lo ∪ vars(C) ∪ live-in(corps avec Linv en sortie)On itère jusqu'à stabilité. **Obs :**♡{L} obs(T) {Lo}→L = Lo ∪ vars(T)**Sortie de boucle :** En sortie dewhile (C), croiser l'invariant avec ¬Cpour raffiner l'état. ### DCE — Dead Code Elimination Une affectationx := Test inutile six ∉ L_out` après elle. On la supprime.")_if C then ε else ε est inutile une fois les deux branches vides. ### Exemple Figure 1 (exo 1 TD7) Seul obs(s) ligne 19. Affectations mortes : x=d+65, y=d+66, i=y, z=d+67, le bloc if(y>0) z+=68, et _(Source: "Un testif C then ε else εest inutile une fois les deux branches vides. ### Exemple Figure 1 (exo 1 TD7) Seulobs(s)ligne 19. Affectations mortes :x=d+65, y=d+66, i=y, z=d+67, le bloc if(y>0) z+=68, et a=b+s` ligne 18. --- ## PARTIE 2 — ANALYSE D'INITIALISATION JAVA ### Problème Java interdit l'utilisation de variables locales non")_obs(T) implicite avant chaque affectation x := T. Les variables **bien initialis (Source: "non initialisées. Le problème est indécidable → sur-approximation conservative. ### Astuce de Tournesol (analyse en arrière) Ajouter un obs(T) implicite avant chaque affectation x := T. Les variables bien initialisées = celles qui ne sont pas live-in à l'entrée de la fonction. ### Analyse en avant (préférable pour messages d'erreur) - `⟨Li⟩")⟨Li⟩ x:=T ⟨Lo⟩ : si vars(T) ⊆ Li alors Lo = Li ∪ {x}, sinon erreur - ⟨Li⟩ if C ⟨Lo⟩ : Lo = Li1 ∩ Li2 (intersection car on ne sait pas quelle branche) - ⟨Li⟩ while ⟨Lo⟩ : point fixe ; variables initialisées = (Source: "⟨Li⟩ x:=T ⟨Lo⟩ : si vars(T) ⊆ Li alors Lo = Li ∪ {x}, sinon erreur - ⟨Li⟩ if C ⟨Lo⟩ : Lo = Li1 ∩ Li2 (intersection car on ne sait pas quelle branche) - ⟨Li⟩ while ⟨Lo⟩ : point fixe ; variables initialisées = garanties dans toutes les exécutions --- ## PARTIE 3 — DCE AVANCÉ AVEC CFG ### Syntaxe CFG ``` Corps F ::= pc:=PC1; (⋃k assume(pc=PCk);")### État abstrait A - A associe chaque `PCk` soit à `L` (live-in), soit à `G(p')` (= goto p', bloc vide) - `G*A` = fermeture transitive = structure union- _(Source: "Kk; Bk)* Branchement B ::= return | pc:=p | pc:=(C ? p1 : p2) ### État abstrait A - A associe chaque PCk soit à L (live-in), soit à G(p') (= goto p', bloc vide) - G*A = fermeture transitive = structure union-find - LA(p) = live-in effectif (∅ si cycle sur soi-même) ### Règle branchement conditionnel r⟨a⟩ pc:=(C?p1:p2) ⟨A⟩ - Si `LA(p1)")_LA(p1) = LA(p2) et C est morte → test inutile, on simplifie en pc:=p1 - Sinon : a = LA(p1) ∪ LA(p2) ∪ vars(C) ### Itération Partir de A = {PCk ↦ ∅}, itérer en ordre inverse jusqu'à stabilité. --- ## PARTIE 4 — IN (Source: "LA(p1) = LA(p2) et C est morte → test inutile, on simplifie en pc:=p1 - Sinon : a = LA(p1) ∪ LA(p2) ∪ vars(C) ### Itération Partir de A = {PCk ↦ ∅}, itérer en ordre inverse jusqu'à stabilité. --- ## PARTIE 4 — INTERPRÉTATION ABSTRAITE : DOMAINE DES POINTEURS ### Représentation Chaque pointeur p est associé à un couple (Z, N) : - Z = F → p ≠")N = F → p = NULL certain - (T, T) → on ne sait rien - (F, F) → ⊥ (état mort, impossible) ### Règles Déréférencement *p : - Z = F (p ≠ NULL certain) → vert - N = F (p = NULL certain) → rou (Source: "→ p ≠ NULL certain - N = F → p = NULL certain - (T, T) → on ne sait rien - (F, F) → ⊥ (état mort, impossible) ### Règles Déréférencement *p : - Z = F (p ≠ NULL certain) → vert - N = F (p = NULL certain) → rouge - (T, T) → orange (fausse alarme possible) Assert p != NULL : Croiser avec {p ↦ (F, T)} : (Z ∧ F, N ∨ T) = (F, T) si l'état")p == NULL : Croiser avec {p ↦ (T, F)}. Assert p == q (examen 2025) : - Après l'assert, p et q (Source: "n'est pas déjà ⊥. Si N = F (p certainement NULL) avant l'assert → alarme rouge → état devient ⊥ = (F, F). Assert p == NULL : Croiser avec {p ↦ (T, F)}. Assert p == q (examen 2025) : - Après l'assert, p et q doivent être compatibles. - On intersecte : Z_résultat = Z1 ∧ Z2, N_résultat = N1 ∧ N2 - Surappproximation : on ne sait pas si p")(Z1, N1) ⊔ (Z2, N2) = (Z1 ∨ Z2, N1 ∨ N2) — T domine. ⊥ est absorbant : toute op (Source: "pas si p et q pointent vers la même adresse, seulement qu'ils ont des valeurs nullité compatibles. Jointure ⊔ (pour les boucles) : (Z1, N1) ⊔ (Z2, N2) = (Z1 ∨ Z2, N1 ∨ N2) — T domine. ⊥ est absorbant : toute opération sur ⊥ donne ⊥. ### Invariant de boucle (exo Q3 TD5) On itère jusqu'au point fixe. En 4 itérations dans l'exemple : `o1 = o2 = o3 ="), p = (F,T), o4 = (T,F). En sortie de boucle, la condition ¬(o1 == o4)raffine :o4 = (T,F)(NULL certain) donco1 ≠ o4impliqueo1 ≠ NULL→o1 = (F,T) → assert vert. --- ## PARTIE 5 — PREUVE D _(Source: "= o3 = (T,T), p = (F,T), o4 = (T,F). En sortie de boucle, la condition ¬(o1 == o4) raffine : o4 = (T,F) (NULL certain) donc o1 ≠ o4 implique o1 ≠ NULL → o1 = (F,T) → assert vert. --- ## PARTIE 5 — PREUVE DE PROGRAMMES AVEC WP / ACSL (Frama-C) ### Syntaxe ACSL de base ```c /*@ requires P; // précondition ensures Q; // postcondition assigns x,")_### Clause assigns `assigns local[0..31] _(Source: "x, t[..]; // variables modifiées (tout le reste est inchangé) */ /*@ loop invariant I; loop assigns x, t[..]; loop variant V; // pour la terminaison (décroît à chaque tour) */ ### Clause assigns assigns local[0..31] signifie : seuls local[0] à local[31] peuvent être modifiés, tout le reste est inchangé. Si rien n'est modifié : `assigns")_. ### Exemple examen 2025 — fonction local_copy ```c char apdu[126]; char local[32]; /*@ requires ...; assigns local[0..31]; */ int local_copy(char a, char b) { char i = 0; /*@ loop assigns i, local[0..31]; @* _(Source: "\nothing. ### Exemple examen 2025 — fonction local_copy ```c char apdu[126]; char local[32]; /@ requires ...; assigns local[0..31]; / int local_copy(char a, char b) { char i = 0; /@ loop assigns i, local[0..31]; @/ while (i + a <= b) { if (apdu[i+a] == '\0') { memset(local, '\0', 32); return(0); } local[i] = apdu[a+i]; i++; } local[i] = 0;")_**Q1 — Vérifications absence de RTE sur les accès mémoire :** - Ligne 10 : `i + a` ne déborde pas (pas demandé ici) - Ligne 11 : `apdu[i+a]` → vérifier `0 ≤ i+a ≤ 125` - Ligne 13 : `local[i]` → vérifier _(Source: "return(1); } Q1 — Vérifications absence de RTE sur les accès mémoire : - Ligne 10 : i + a ne déborde pas (pas demandé ici) - Ligne 11 : apdu[i+a] → vérifier 0 ≤ i+a ≤ 125 - Ligne 13 : local[i] → vérifier 0 ≤ i ≤ 31 - Ligne 16 : local[i] → vérifier 0 ≤ i ≤ 31 Précondition à renforcer : ```c requires 0 <= a && 0 <= b && b <= 125 &&")_Ainsi `i` varie de 0 à `b-a ≤ 31`, donc `i+a ≤ b ≤ 125` et `i ≤ 31`. **Q2 — Invariant de boucle :**c loop invariant 0 <= i && i <= b - a + 1 && i <= 31; loop invariant a + i <= 126 (Source: "125 && a <= b && (b - a) <= 31; Ainsi `i` varie de 0 à `b-a ≤ 31`, donc `i+a ≤ b ≤ 125` et `i ≤ 31`. **Q2 — Invariant de boucle :**c loop invariant 0 <= i && i <= b - a + 1 && i <= 31; loop invariant a + i <= 126; ``` Justification WP du while : l'invariant I doit vérifier : 1. I est vrai à l'entrée (i=0, trivial si précondition ok) 2. `{I ∧ C}")(conservation) 3.{I ∧ ¬C} implique la propriété voulue en sortie **Q3 — Plus forte postcondition :** ```c ensures \result == 0 || \result == 1; ensures \result == 0 ==> \forall int k; 0 <= k < 32 ==> l _(Source: "∧ C} corps {I} (conservation) 3. {I ∧ ¬C} implique la propriété voulue en sortie Q3 — Plus forte postcondition : c ensures \result == 0 || \result == 1; ensures \result == 0 ==> \forall int k; 0 <= k < 32 ==> local[k] == '\0'; ensures \result == 1 ==> local[b-a+1] == '\0'; L'invariant qui permet de prouver ça : i ≤ b - a et i ≤ 31 en")_int et unsigned int → conversion vers non-sig (Source: "en combinaison avec la condition de sortie de boucle. --- ## PARTIE 6 — VULNÉRABILITÉS C : UB ET DÉBORDEMENTS ### Les UB classiques Mélange signé/non-signé : Comparer int et unsigned int → conversion vers non-signé. Si size = -1 → devient INT_MAX en non-signé → boucle quasi-infinie → segfault. malloc(0) : Comportement non défini. Retourne")capacity = 0 non testé peut y mener. Integer overflow unsigned (wrap-around) : sizeof(double) * capacity peut déborder sur 32 bits si capacity ≥ 2^29 → m (Source: "souvent une adresse non NULL vers une zone de taille 0. Un capacity = 0 non testé peut y mener. Integer overflow unsigned (wrap-around) : sizeof(double) * capacity peut déborder sur 32 bits si capacity ≥ 2^29 → malloc alloue trop peu → écriture hors buffer. Suppression de test par le compilateur : Si offset et len sont des signed int,"), le compilateur peut supprimer (offset + len < 0)car l'overflow signé est un UB → il suppose que ça n'arrive jamais → garde de sécurité effacée silencieusement avec-O2. ### Correction avec size_t ```c #include _(Source: "int, le compilateur peut supprimer (offset + len < 0) car l'overflow signé est un UB → il suppose que ça n'arrive jamais → garde de sécurité effacée silencieusement avec -O2. ### Correction avec size_t ```c #include <stdint.h> double *bufInit(size_t capacity, size_t size, double v) { if (capacity > SIZE_MAX / sizeof(double)) return NULL; if (size >")_### Options de compilation impo _(Source: "(size > capacity) return NULL; double *dst = (double *) malloc(sizeof(double) * capacity); if (dst == NULL) return NULL; for (size_t i = 0; i < size; i++) { dst[i] = v; } return dst; } ### Options de compilation importantes - -Wall -Wextra -Werror : tous les warnings deviennent des erreurs - -fstack-protector : canari sur la pile - -ftrapv :")_-fno-strict-overflow : désactive l'hypothèse "pas d'overflow signé" (le compilateur ne supprime plus les gardes) - -Wconversion : conversions implicites dangereuses - -O1 (Source: ": exception sur overflow d'entiers signés - -fno-strict-overflow : désactive l'hypothèse "pas d'overflow signé" (le compilateur ne supprime plus les gardes) - -Wconversion : conversions implicites dangereuses - -O1 minimum pour des analyses plus fines - Ligne minimale ANSSI : gcc -O1 -Wall -Wextra -Wpedantic -Werror -std=c99 --- ## PARTIE 7 —")php $command = 'ls -l /home/' . $userName; system($command); // Entrée: ";rm -rf /" → exécute rm -rf / Fix : liste blanche (regex ^[a-z0-9_-]{3,15}$), utiliser mkdir() _(Source: "— INJECTIONS ### Injection de commande ```php $command = 'ls -l /home/' . $userName; system($command); // Entrée: ";rm -rf /" → exécute rm -rf / ``` **Fix :** liste blanche (regex ^[a-z0-9_-]{3,15}$), utiliser mkdir()au lieu desystem("mkdir..."), ou spawn()` avec tableau d'arguments (pas de shell interpréteur). ### Injection SQL Entrée")_mysqli_real_escape_string(). ### XSS Injecter <script>alert(document.cookie)</script> dans un champ affiché. %3Cscript%3E contourne (Source: "→ neutralise le WHERE → connexion sans mot de passe. Fix : requêtes préparées, mysqli_real_escape_string(). ### XSS Injecter <script>alert(document.cookie)</script> dans un champ affiché. %3Cscript%3E contourne les filtres naïfs. <scr<script>ipt> contourne les filtres récursifs naïfs. Fix : htmlspecialchars(), strip_tags().")%0d%0a (saut de ligne) dans additional_headers → ajouter Bcc: → spam massif. Fix : valider le format (regex email stricte), échapper les sa (Source: "Toujours utiliser des fonctions éprouvées. ### Injection SMTP Injecter %0d%0a (saut de ligne) dans additional_headers → ajouter Bcc: → spam massif. Fix : valider le format (regex email stricte), échapper les sauts de ligne. ### Path traversal Entrée ../../etc/passwd dans un chemin de fichier → accès à des fichiers hors du répertoire prévu.")### Shellcode Suite d'octets qui exécute `execve("/bin/sh", ...)` avec les droits courants. Compilé avec `-z execstack` (pi _(Source: "bas : [variables locales / buffers] [ancien rbp] [@retour] ← cible de l'attaque [paramètres] ### Shellcode Suite d'octets qui exécute execve("/bin/sh", ...) avec les droits courants. Compilé avec -z execstack (pile exécutable). ### Modification du flot (exemple TD) c ret = buffer + 6; (*ret) = *ret + 8; // saute l'instruction x=1 On écrit")_-fstack-protector). Implémentation : au début de la fonction, copie d'une valeur secrète sur la pile ; à")__stack_chk_fail(). ASLR : Randomisation des adresses (pile, tas, code). Deux exécutions n'ont pas la même structure mémoire → l'attaquant ne peut pas deviner l'adresse d'inj (Source: "; à la fin, vérification ; si modifié → __stack_chk_fail(). ASLR : Randomisation des adresses (pile, tas, code). Deux exécutions n'ont pas la même structure mémoire → l'attaquant ne peut pas deviner l'adresse d'injection. DEP / NX (Data Execution Prevention) : Mémoire non exécutable. Contourné par ROP (Return-Oriented Programming) : enchaîner")...;ret) déjà présents dans le binaire. Shadow stack : Copie séparée des adresses de retour dans une zone protégée. Vérifiée à chaque retour → protège aussi contre ROP. **Contre quoi (Source: "des gadgets (petites séquences ...;ret) déjà présents dans le binaire. Shadow stack : Copie séparée des adresses de retour dans une zone protégée. Vérifiée à chaque retour → protège aussi contre ROP. Contre quoi le canari ne protège pas : les heap overflows, les overflows qui sautent par-dessus le canari (écriture non contiguë), et les")c p1 = malloc(...); free(p1); p2 = malloc(...); // réutilise la même zone mémo _(Source: "les attaques qui lisent le canari avant de l'utiliser. --- ## PARTIE 9 — USE-AFTER-FREE, DOUBLE FREE, MOINDRE PRIVILÈGE ### Use-After-Free c p1 = malloc(...); free(p1); p2 = malloc(...); // réutilise la même zone mémoire strcpy(p2, argv[1]); // écrit l'adresse voulue par l'attaquant p1->f(); // appelle la fonction de l'attaquant ``` L'allocateur")_f de p1. Protection : allocateurs durcis, AddressSanitizer. ### Variable non initialisée (uninit) Une variable locale non (Source: "réutilise la zone libérée pour p2. En écrivant dans p2, on contrôle le pointeur de fonction f de p1. Protection : allocateurs durcis, AddressSanitizer. ### Variable non initialisée (uninit) Une variable locale non initialisée contient ce qui était sur la pile avant. Un attaquant peut placer une valeur choisie dans cette zone (via un appel précédent)")python raisePrivileges() try: _(Source: "→ même exploitation que UAF. ### Moindre privilège (CWE-269) N'élever les privilèges que le temps nécessaire. Toujours les abaisser dans **tous** les chemins, y compris les cas d'erreur. python raisePrivileges() try: os.mkdir(path) os.chmod(path, 0o700) lowerPrivileges() except OSError: lowerPrivileges() # NE PAS OUBLIER return False ``` --- ##")_frama-c -eva fichier.c ou frama-c-gui -eva fichier.c - Détecte : accès hors-limites, overflow, déréférencement NULL - Coul (Source: "--- ## PARTIE 10 — FRAMA-C : EVA ET WP ### Plugin EVA (interprétation abstraite) - Commande : frama-c -eva fichier.c ou frama-c-gui -eva fichier.c - Détecte : accès hors-limites, overflow, déréférencement NULL - Couleurs : vert = garanti sûr, orange = alarme possible (fausse alarme), rouge = erreur certaine - Limite : ne peut pas prouver les inégalités")i < capacity déduit de i < size et size ≤ capacity avec deux inputs non bornés) ### Plugin WP (preuve déductive) - Commande : frama-c -wp -wp-rte -wp-split fichie _(Source: "symboliques par transitivité sans constantes (ex : i < capacitydéduit dei < sizeetsize ≤ capacityavec deux inputs non bornés) ### Plugin WP (preuve déductive) - Commande :frama-c -wp -wp-rte -wp-split fichier.c--wp-rte: insère automatiquement les assertions d'absence de RTE --wp-split` : découpe les obligations de preuve pour")_size = input() et capacity = input() non bornés → alarme sur (Source: "pour identifier où le prouveur échoue - Couleurs : bleu = en attente, vert = prouvé, orange = échec de preuve ### Ce que EVA peut détecter sur bufInit Avec size = input() et capacity = input() non bornés → alarme sur dst[i] hors-limites. Avec l'une des deux fixée comme constante → 0 alarme si le code est correct. ### Utilité comparée des 3 approches")-O2 de supp (Source: "les cas complexes + vérification à l'exécution en développement (ASan). --- ## PARTIE 11 — TP : CE QU'IL FAUT RETENIR ### TP Sécurité C Exercice optimise.c : Un overflow signé permet au compilateur avec -O2 de supprimer une garde de sécurité (le test (offset + len < 0) est supprimé car UB). Sans -O2 le test reste. -fno-strict-overflow force")-O2. Exercice winloose.c (buffer overflow) : Compilé avec -fno-stack-protector → pas de canari. En donnant des entrées bien choisies on peut écraser l'adresse (Source: "force le compilateur à conserver les gardes même avec -O2. Exercice winloose.c (buffer overflow) : Compilé avec -fno-stack-protector → pas de canari. En donnant des entrées bien choisies on peut écraser l'adresse de retour et rediriger l'exécution. Avec -fstack-protector → le programme détecte la corruption et appelle __stack_chk_fail().")ls) sans chemin absolu. En ajoutant . au début du PATH et en créant un faux ls dans le répertoire courant, on fait exécuter notre code (Source: "Exercice bonjour.c (injection PATH) : Le programme appelle un binaire (ex : ls) sans chemin absolu. En ajoutant . au début du PATH et en créant un faux ls dans le répertoire courant, on fait exécuter notre code. Exercice uaf.c : Use-after-free : après free(p1), un malloc suivant réutilise la même zone. En contrôlant l'entrée du second")p1. Exercice fgets.c : fgets retourne NULL en cas d'erreur ou en cas de fin de fichier (Ctrl+D). Si on ne teste pas NULL, la comparaison strcmp peut réu (Source: "malloc on contrôle le pointeur de fonction appelé via p1. Exercice fgets.c : fgets retourne NULL en cas d'erreur ou en cas de fin de fichier (Ctrl+D). Si on ne teste pas NULL, la comparaison strcmp peut réussir sur un buffer non rempli (contenant le mot de passe précédent). Fix : tester la valeur de retour de fgets et nettoyer le buffer")memset_s ou explicit_bzero. Exercice bufInit.c : Vérification des analyses du TD6. Corriger avec size_t et le test capacity > SIZE_MAX/sizeof(double). ### TP WP Frama-C Workflow : 1. Compiler (Source: "buffer avec memset_s ou explicit_bzero. Exercice bufInit.c : Vérification des analyses du TD6. Corriger avec size_t et le test capacity > SIZE_MAX/sizeof(double). ### TP WP Frama-C Workflow : 1. Compiler avec -Wall pour vérifier la syntaxe 2. Lancer frama-c-gui -wp -wp-rte -wp-split fichier.c 3. Identifier les obligations orange (échec")while (C) { corps } avec postcondition Q : - L'invariant I _(Source: "(échec de preuve) 4. Ajouter invariants de boucle et renforcer préconditions 5. Relancer jusqu'à tout vert **Invariant de boucle : méthode** Pour une boucle while (C) { corps }avec postconditionQ: - L'invariantIdoit être vrai à l'entrée -{I ∧ C} corps {I}(conservation) -I ∧ ¬C → Q` (utilité) Variant de boucle : Expression entière qui")_b - a - i pour la fonction local_copy. --- ## PARTIE 12 — POINTS CLÉS POUR L'EXAMEN (format 2025) ### Sur la forme de l'examen ( (Source: "qui décroît strictement à chaque itération et reste ≥ 0 → garantit la terminaison. Ex : b - a - i pour la fonction local_copy. --- ## PARTIE 12 — POINTS CLÉS POUR L'EXAMEN (format 2025) ### Sur la forme de l'examen (d'après le sujet Mai 2025) - Exercice 1 (8 pts) : Preuve de programme ACSL/WP → savoir écrire requires, assigns, `loop")fgets retourne NULL sur EOF aussi → vecteur d'attaque si non vérifié - -O2 peut supprimer des gardes de sécurité si")memset peut être supprimé par le compilateur si la variable n'est plus utilisée ensuite → utiliser memset_s ou explicit_bzero - La surappproximation de l'analyse de pointeurs (Source: "si l'overflow signé est possible (UB) - memset peut être supprimé par le compilateur si la variable n'est plus utilisée ensuite → utiliser memset_s ou explicit_bzero - La surappproximation de l'analyse de pointeurs (Z,N) : assert(p==q) ne prouve pas que p et q pointent vers la même adresse, seulement que leurs valeurs de nullité sont")obs(s) ligne 19. Affectations mortes : x=d+65, y=d+66, i=y, z=d+67, le bloc if(y>0) z+=68, et a=b+s ligne 18. --- ## PARTIE 2 — ANALYSE D'INITIALISATION JAVA ### Problè (Source: "### Exemple Figure 1 (exo 1 TD7) Seul obs(s) ligne 19. Affectations mortes : x=d+65, y=d+66, i=y, z=d+67, le bloc if(y>0) z+=68, et a=b+s ligne 18. --- ## PARTIE 2 — ANALYSE D'INITIALISATION JAVA ### Problème Java interdit l'utilisation de variables locales non initialisées. Le problème est indécidable → sur-approximation conservative. ### A...")Corps F ::= pc:=PC1; (⋃k assume(pc=PCk); Kk; Bk)* Branchement B ::= return | pc:=p | pc:=(C ? p1 : p2) ### État abstrait A - A associe chaque PCk soit à L (live- (Source: "PARTIE 3 — DCE AVANCÉ AVEC CFG ### Syntaxe CFG Corps F ::= pc:=PC1; (⋃k assume(pc=PCk); Kk; Bk)* Branchement B ::= return | pc:=p | pc:=(C ? p1 : p2) ### État abstrait A - A associe chaque PCk soit à L (live-in), soit à G(p') (= goto p', bloc vide) - G*A = fermetu")soit àL(live-in), soit àG(p')(= goto p', bloc vide) -GA= fermeture transitive = structure union-find -LA(p)= live-in effectif (∅ si cycle sur soi-même) ### Règle branchement conditionnelr⟨a⟩ pc:=( _(Source: "PCksoit àL(live-in), soit àG(p')(= goto p', bloc vide) -GA= fermeture transitive = structure union-find -LA(p)= live-in effectif (∅ si cycle sur soi-même) ### Règle branchement conditionnelr⟨a⟩ pc:=(C?p1:p2) ⟨A⟩- SiLA(p1) = LA(p2)` et C est morte → test i")_o1 = o2 = o3 = (T,T), p = (F,T), o4 = (T,F) (Source: "En 4 itérations dans l'exemple : o1 = o2 = o3 = (T,T), p = (F,T), o4 = (T,F)")**Q1 — Vérifications absence de RTE sur les accès mémoire :** - Ligne 10 : `i + a` ne débord _(Source: "b) { if (apdu[i+a] == '\0') { memset(local, '\0', 32); return(0); } local[i] = apdu[a+i]; i++; } local[i] = 0; return(1); } Q1 — Vérifications absence de RTE sur les accès mémoire : - Ligne 10 : i + a ne déborde pas (pas demandé ici) - Ligne 11 : apdu[i+a] → vérifier 0 ≤ i+a ≤ 125 - Ligne 13 : local[i] → vérifier 0 ≤ i ≤ 31 - Ligne 16 :...")_c loop invariant 0 <= i && i <= b - a + 1 && i <= 31; loop invariant a + i <= 126; Justification WP du while : l'invariant I doit vérifier : 1. I est vrai à l'entrée (i=0, trivial si (Source: "Q2 — Invariant de boucle : c loop invariant 0 <= i && i <= b - a + 1 && i <= 31; loop invariant a + i <= 126; Justification WP du while : l'invariant I doit vérifier : 1. I est vrai à l'entrée (i=0, trivial si précondition ok) 2. {I ∧ C} corps {I} (conservation) 3. {I ∧ ¬C} implique la propriété voulue en sortie **Q3 — Plus forte postcondit...")capacity = 0 non testé peut y mener (Source: "0. Un capacity = 0 non testé peut y mener")-Wall -Wextra -Werror : tous les warnings deviennent des erreu...")-fno-strict-overflow : désactive l'hypothèse "pas d'overflow signé" (le compilateur ne supprime plus les gardes) - -Wconversion : conversions implicites dangereuses - -O1 m (Source: "exception sur overflow d'entiers signés - -fno-strict-overflow : désactive l'hypothèse "pas d'overflow signé" (le compilateur ne supprime plus les gardes) - -Wconversion : conversions implicites dangereuses - -O1 minimum pour des analyses plus fines - Ligne minimal")php $command = 'ls -l /home/' . $userName; system($command); // Entrée: ";rm -rf /" → exécute rm -rf / Fix : liste blanche (regex ^[a-z0-9_-]{3,15}$), utiliser mkdir() au lieu de system("mk _(Source: "on de commande ```php $command = 'ls -l /home/' . $userName; system($command); // Entrée: ";rm -rf /" → exécute rm -rf / ``` **Fix :** liste blanche (regex ^[a-z0-9_-]{3,15}$), utiliser mkdir()au lieu desystem("mkdir..."), ou spawn()` avec tableau d'ar")_frama-c -eva fichier.c ou frama-c-gui -eva fichier.c - Détecte : accès hors-limites, overflow, déréférencement NULL - Couleurs : vert = garanti sûr, orange = alarme possible (fausse alarme), rouge = erreur (Source: "nde : frama-c -eva fichier.c ou frama-c-gui -eva fichier.c - Détecte : accès hors-limites, overflow, déréférencement NULL - Couleurs : vert = garanti sûr, orange = alarme possible (fausse alarme), rouge = erreur")-fno-strict-overflow force le compilateur à conserver les gardes même avec -O2 (Source: "-fno-strict-overflow force le compilateur à conserver les gardes même avec -O2")memset_s ou explicit_bzero (Source: "Fix : tester la valeur de retour de fgets et nettoyer le buffer avec memset_s ou explicit_bzero")-Wall pour vérifier la syntaxe 2. Lancer frama-c-gui -wp -wp-rte -wp-split fichier.c 3. Identifier les obligations orange (échec de preuve) 4. Ajouter invariants de b (Source: "### TP WP Frama-C Workflow : 1. Compiler avec -Wall pour vérifier la syntaxe 2. Lancer frama-c-gui -wp -wp-rte -wp-split fichier.c 3. Identifier les obligations orange (échec de preuve) 4. Ajouter invariants de boucle et renforcer préconditions 5. Relancer jusqu'à tout vert Invariant de boucle : méthode Pour une boucle while (C) { corps } av...")requires, assigns, loop invariant, justifier les invariants, donner la postcondi (Source: "2025) ### Sur la forme de l'examen (d'après le sujet Mai 2025) - Exercice 1 (8 pts) : Preuve de programme ACSL/WP → savoir écrire requires, assigns, loop invariant, justifier les invariants, donner la postcondition - Exercice 2 (6 pts) : Analyse de pointeurs (domaine (Z,N)) → savoir appliq")(F,F) = ⊥ signifie code mort, pas simplement "on ne sait rien" (Source: "de nullité sont compatibles - L'invariant (F,F) = ⊥ signifie code mort, pas simplement "on ne sait rien"")while (C) { corps } avec po (Source: "Identifier les obligations orange (échec de preuve) 4. Ajouter invariants de boucle et renforcer préconditions 5. Relancer jusqu'à tout vert Invariant de boucle : méthode Pour une boucle while (C) { corps } avec postcondition Q : - L'invariant I doit être vrai à l'entrée - {I ∧ C} corps {I} (conservation) - I ∧ ¬C → Q (utilité) **Variant de...")while (C) { corps } avec postcondition Q : - L'invariant I doit être vrai à l'entrée - {I ∧ C} corps {I} (conservation) - I ∧ ¬C → _(Source: "5. Relancer jusqu'à tout vert **Invariant de boucle : méthode** Pour une boucle while (C) { corps }avec postconditionQ: - L'invariantIdoit être vrai à l'entrée -{I ∧ C} corps {I}(conservation) -I ∧ ¬C → Q` (utilité) Variant de boucle : Expression entière qui décroît strictement à chaque itération et reste ≥ 0 → garantit la terminaison")_-Wall pour vérifier la syntaxe 2 (Source: "1. Compiler avec -Wall pour vérifier la syntaxe 2")x=d+65, y=d+66, i=y, z=d+67, le bloc if(y>0) z+=68, et a=b+s ligne 18 (Source: "19. Affectations mortes : x=d+65, y=d+66, i=y, z=d+67, le bloc if(y>0) z+=68, et a=b+s ligne 18")Ainsi `i` varie de 0 à `b-a ≤ 31`, donc `i+a ≤ b ≤ 125` et `i ≤ 31` _(Source: "a) <= 31; Ainsi i varie de 0 à b-a ≤ 31, donc i+a ≤ b ≤ 125 et i ≤ 31")_requires, assigns, loop inva _(Source: "--- ## PARTIE 12 — POINTS CLÉS POUR L'EXAMEN (format 2025) ### Sur la forme de l'examen (d'après le sujet Mai 2025) - **Exercice 1 (8 pts) :** Preuve de programme ACSL/WP → savoir écrire requires, assigns, loop invariant`, justifier les invariants, donner la postcondition - Exercice 2 (6 pts) : Analyse de pointeurs (domaine (Z,N)) → savoir appliq...")_ si l'état n'est pas déjà ⊥ _(Source: "T) = (F, T) si l'état n'est pas déjà ⊥")_{I ∧ ¬C} implique la propriété voulue en sortie Q3 — Plus forte postcondition : c ensures \result == 0 || \result == 1; ensures \result == 0 ==> \forall int k; 0 <= k < 32 ==> local[k] == '\0'; ensures \resul _(Source: "3. `{I ∧ ¬C}` implique la propriété voulue en sortie **Q3 — Plus forte postcondition :** c ensures \result == 0 || \result == 1; ensures \result == 0 ==> \forall int k; 0 <= k < 32 ==> local[k] == '\0'; ensures \result == 1 ==> local[b-a+1] == '\0'; ``` L'invariant qui permet de prouver ça : i ≤ b - a et i ≤ 31 en combinaison avec la condition de s...")_p == q (examen 2025) : - Après l'assert, p et q doivent être compatibles (Source: "Assert p == q (examen 2025) : - Après l'assert, p et q doivent être compatibles")local_copy c char apdu[126]; char local[32]; /*@ requires _(Source: "2025 — fonction `local_copy` c char apdu[126]; char local[32]; /*@ requires")_p _(Source: "T) → orange (fausse alarme possible) **Assert p")_^[a-z0-9_-]{3,15}$), utiliser mkdir() au lieu de system("mkdir..."), ou spawn() avec tableau d'arguments (pas de shell interpréteur). ### Injection SQL Entrée Dupont';-- → neutralis (Source: "Fix :** liste blanche (regex ^[a-z0-9_-]{3,15}$), utiliser mkdir() au lieu de system("mkdir..."), ou spawn() avec tableau d'arguments (pas de shell interpréteur). ### Injection SQL Entrée Dupont';-- → neutralise le WHERE → connexion sans mot de passe")sizeof(double) * capacity peut déborder sur 32 bits si capacity ≥ 2^29 → malloc alloue trop peu → écriture hors buffer (Source: "Integer overflow unsigned (wrap-around) : sizeof(double) * capacity peut déborder sur 32 bits si capacity ≥ 2^29 → malloc alloue trop peu → écriture hors buffer")%0d%0a (saut de ligne) dans additional_headers → ajouter Bcc: → spam massif (Source: "### Injection SMTP Injecter %0d%0a (saut de ligne) dans additional_headers → ajouter Bcc: → spam massif")while (C) { corps } avec postcondition Q : - L'invariant I doit être vrai à l'entrée - {I ∧ C} corps {I} (conservation) - I ∧ ¬C → Q (Source: "Relancer jusqu'à tout vert Invariant de boucle : méthode Pour une boucle while (C) { corps } avec postcondition Q : - L'invariant I doit être vrai à l'entrée - {I ∧ C} corps {I} (conservation) - I ∧ ¬C → Q (utilité) Variant de boucle : Expression entière qui décroît strictement à chaque itération et reste ≥ 0 → garantit la terminaison")∇ = ⊔ sur treillis fini : Linv = Lo ∪ vars(C) ∪ live-in(corps avec Linv en sortie) On itère jusqu'à stabilité (Source: "Avec ∇ = ⊔ sur treillis fini : Linv = Lo ∪ vars(C) ∪ live-in(corps avec Linv en sortie) On itère jusqu'à stabilité")♡{L} obs(T) {Lo} → L = Lo ∪ vars(T) Sortie de boucle : En sortie de while (C), croiser l'invariant avec ¬C pour raffiner l'état (Source: "Obs : ♡{L} obs(T) {Lo} → L = Lo ∪ vars(T) Sortie de boucle : En sortie de while (C), croiser l'invariant avec ¬C pour raffiner l'état")Z_résultat = Z1 ∧ Z2, N_résultat = N1 ∧ N2 - Surappproximation : on ne sait pas si p et q pointent vers la même adresse, seulement qu'ils ont des valeurs nullité compatibles (Source: "- On intersecte : Z_résultat = Z1 ∧ Z2, N_résultat = N1 ∧ N2 - Surappproximation : on ne sait pas si p et q pointent vers la même adresse, seulement qu'ils ont des valeurs nullité compatibles")| Concept | Description |
|---|---|
| Variable live | Influence une observation future |
| Affectation utile | x ∈ Lo et x := T avec x dans Lo ou vars(T) |
| Affectation morte | x ∉ Lo après l'affectation, peut être supprimée |
| Boucle while | Invariant calculé par point fixe jusqu'à stabilité |
| Code mort | Suppression d'instructions inutiles sans impact comportemental |
| Aspect | Détails |
|---|---|
| Initialisation Java | Variables non initialisées détectées par sur-approximation |
| Analyse en arrière | Ajoute obs(T) pour variables bien initialisées |
| Analyse en avant | Vérifie que variables utilisées sont initialisées |
| Boucle while | Invariant doit être vrai à l'entrée, conservé, et garantir la postcondition |
| Null pointer | Domaine abstrait modélise nullité pour détection d'erreurs |
Тествайте знанията си по Analyse avancée de la sécurité et preuve de programmes с 12 въпроса с множество отговори с подробни корекции.
1. Quel est le rôle principal de l'analyse de liveness dans l'optimisation des programmes ?
2. En quoi l'analyse d'initialisation en avant diffère-t-elle de l'analyse en arrière en Java ?
Запомнете ключовите концепции на Analyse avancée de la sécurité et preuve de programmes с 24 интерактивни флашкарти.
Analyse de liveness — définition ?
Détermine si une variable influence une observation future.
Affectation morte — quand ?
Quand x ∉ Lo après l'affectation.
Code mort — élimination ?
Suppression d'instructions inutiles sans changer le comportement.
Bases de données
Bases de données
Programmation
Programmation
Импортирайте курса си и AI генерира листове, тестове и флашкарти за 30 секунди.
Генератор на листове