• Aucun résultat trouvé

Notre instrumentation est bas´ee sur l’algorithme d’inf´erence. Elle ins`ere des commandes dans le programme afin que, durant l’ex´ecution, les niveaux de s´ecurit´e des variables qui ´etaient inconnus statiquement soient mis `a jour avec leurs vraies valeurs. Chaque instruction est trait´ee avec son num´ero de ligne et le niveau de s´ecurit´e du contexte qui lui est associ´e. Des instructions peuvent ˆetre ins´er´ees afin d’empˆecher des ex´ecutions non s´ecuritaires. L’algorithme d’instrumentation est pr´esent´e dans le Tableau 3.4. Il re¸coit une commande cmd `a instrumenter et le num´ero associ´e `a cette commande. L’algorithme met `a jour IC : String, qui est le programme instrument´e, comme effet de bord. Il se sert d’une matrice d’environnements de typage G produite par l’algorithme d’inf´erence, qui est une variable globale. G(i) identifie l’environnement de typage de l’instruction i et par cons´equent, G(i)(x) est le type de s´ecurit´e de la variable x `a l’instruction i. Les commandes sont ins´er´ees de telle sorte que le programme instrument´e conserve une table g M des niveaux de s´ecurit´e des variables, se servant de G pour obtenir les types d´ej`a connus. Cette table est ´egalement une variable globale. L’utilisation de g M pr´esente deux avantages, il garde une trace des valeurs les plus r´ecentes des variables. Aucune autre analyse n’est n´ecessaire pour trouver quelle instruction ´etait la derni`ere `

a modifier une variable. La lecture d’une table est ´egalement plus ais´ee que celle de la matrice G. Le programme suivant montre l’utilit´e de g M.

Instrument : cmd * int → int Instrument(c, i) = case c of skip : IC ∧ “ skip ; ” return (i + 1) x := e : τ = evalT(inferE(G(i), e)) case evalN(inferE(G(i), e)) of

val : IC = IC∧ “x := e ; ” if (τ = U ) then

IC = IC∧“updateEnv(G(i), x, sup(evalT(TypeOf Expression(e)), top(pc))val); ” end ;

IC = IC∧ “ updateEnv(g M, x, G(i)(x)) ; ” return (i + 1)

chan : IC = IC∧ “x := e ; ” if (τ = U ) then

IC = IC∧“ updateEnv(G(i), x, TypeOf Channel(e)) ; ” end

IC = IC∧ “ updateEnv(g M, x, G(i)(x)) ; ” return (i + 1)

receivecx1 from x2:

IC = IC ∧ “receivecx1 from x2; ”

if (G(i)(x1) = U val) then

IC = IC∧ “ updateEnv(G(i), x1, sup(evalT(TypeOf Expression(x2)), top(pc))val) ; ”

end

IC = IC∧ “updateEnv(g M, x1, G(i)(x1)) ; ”

return (i + 1) receivenx1 from x2:

IC = IC∧ “receivenx1 from x2 ”;

if (G(i)(x2) ! = L chan)

then IC = IC∧ “ if TypeOf Channel(x1) = L chan and TypeOf Channel(x2) = H chan

then updateEnv(G(i), x1, B chan)

else updateEnv(G(i), x1, TypeOf Channel(x1))

end ”

else IC = IC∧ “updateEnv(G(i), x1, TypeOf Channel(x1))”

end

IC = IC∧ “ updateEnv(g M, x1, G(i)(x1)); ”

return (i + 1) c1; c2 :

j = Instrument(c1, i); k = Instrument(c2, j)

return k send x1 to x2:

if ( (¬lessOrEqual(sup(G(i)(x1), top(pc)), G(i)(x2)) or

(sup(G(i)(x1), top(pc)) = U and G(i)(x2) = U ))

and ¬(sup(G(i)(x1), top(pc)) = B and G(i)(x2) = H) ) then

IC = IC∧ “ tau = TypeOf Expression(x2) ; tau1 = TypeOf Expression(x1);

if (((tau = L chan) and (sup(evalT(tau1), top(pc)) in {H, B})) or (tau = B chan))

then fail else ” end

IC = IC∧ “ send x1 to x2end ; ”

return (i + 1)

if e then c1 else c2 end :

IC = IC∧ “push(sup(top(pc), evalT(TypeOf Expression(e))), pc) ; if e then ” j = Instrument(c1, i + 1) IC = IC∧ “else ” k = Instrument(c2, j) IC = IC∧ “end; pop (pc) ; ” return k while e to c end : IC = IC∧

“push(sup(top(pc), evalT(TypeOf Expression(e))), pc); while e do ”

receiven c from publicChannel ;

receivec a from publicChannel ;

if (a mod 2 6= 0) then receivec a from c

end;

send a to publicChannel

L’algorithme d’inf´erence d´etermine apr`es la premi`ere instruction que le type de c est U chan. La variable a, avant la commande if , a le type L val. L’analyse statique conclura que le type de a apr`es l’ex´ecution de la commande if est U val. Si le pro- gramme instrument´e met `a jour les types des variables, en mˆeme temps dans G et que c a pour type H chan, le type de a sera H val. La commande send qui suit sera consid´er´ee non s´ecuritaire, quelle que soit la valeur dynamique de a. Par contre, notre instrumentation ins´erera des instructions qui mettront dans g M le dernier type de a qui a ´et´e lu. Par cons´equent, selon que l’ex´ecution du programme instrument´e entre dans la branche then ou non, a prendra soit le niveau de s´ecurit´e de c soit conservera celui de publicChannel . Cela permettra de rejeter le programme instrument´e `a l’ex´ecution, uniquement s’il est r´eellement non s´ecuritaire.

Certaines fonctions utilitaires sont d´efinies dans le langage cible et utilis´ees par les programmes instrument´es. La fonction TypeOf Channel joue le rˆole de registre pour les canaux constants d´efini pr´ealablement `a l’ex´ecution. La fonction TypeOf Expression retourne le type courant d’une expression : elle se sert des informations disponibles dans g M pour les variables. TypeOf Channel pour les canaux et prend le supV de ses valeurs lorsque l’expression est e1op e2. TypeOf Expression et TypeOf Channel sont des

commandes ex´ecut´ees par le programme instrument´e. Pour empˆecher les flots impli- cites, des commandes sont ins´er´ees afin que le programme instrument´e garde une pile de contextes pc. Chaque fois que l’ex´ecution branche sur une expression, que ce soit une commande if ou une commande while, le contexte est empil´e. Le contexte est le supremum du type de l’expression e et le contexte dans lequel la commande courante est ex´ecut´ee. Le dernier contexte est d´epil´e chaque fois que l’ex´ecution d’un branchement conditionnel arrive `a terme. La pile pc est initialement vide et le r´esultat de la lecture d’une pile vide est toujours L. Les fonctions push et pop sont utilis´ees pour manipuler la pile de contextes durant l’ex´ecution du programme instrument´e. Les autres fonctions sont une impl´ementation de celle qui leur est ´equivalente dans l’algorithme

dierons quatre exemples. Tous les quatre exemples lors du typage par l’algorithme d’in- f´erence sont indiqu´es comme n´ecessitant une instrumentation.

Exemple 14.

Le premier exemple est le programme de la figure 3.7. Nous le reprenons `a la figure

3.10 tout en rajoutant le code instrument´e car l’algorithme d’inf´erence a conclu que le programme n´ecessite une instrumentation. Le programme est pr´esent´e dans le coin sup´erieur gauche de la figure. Le r´esultat de l’instrumentation est pr´esent´e en bas. la particularit´e de ce programme est que le type du canal c peut-ˆetre aussi bien public que priv´e, suivant la branche de l’instruction if qui est prise. L’algorithme d’inf´erence a donc marqu´e que son type apr`es l’instruction if est inconnu. Les quatri`eme et septi`eme lignes du programme instrument´e mettent `a jour, dans g M , le type de c pour que lors de l’ex´ecution, en fonction de la branche qui est prise, le type r´eel de c soit pris en compte. La quatri`eme instruction est une commande send. Une v´erification est ins´er´ee dans le code instrument´e pour assurer que l’information secr`ete highValue n’est ni envoy´ee sur un canal public ni sur un canal bloqu´e (le type de c ne pouvant ˆetre d´etermin´e statiquement).

Programme `a analyser Analyse d’inf´erence if lowValue then c := publicChannel else c := privateChannel end; send highValue to c Environnement pc i G(1) = [instr 7→ L, highValue 7→ H val] pcif = L 2

G(2) = [instr 7→ L, highValue 7→ H val,

c 7→ L chan] L 3 G(3) = [instr 7→ L, highValue 7→ H val,

c 7→ H chan] L 4 G(1) = [instr 7→ L, highValue 7→ H val,

c 7→ U chan] L 4 G(4) = [instr 7→ U, highValue 7→ H val,

c 7→ U chan] L 5 Instrumentation : push(sup(top(pc), evalT(TypeOf Expression(lowValue))), pc);

if lowValue then c := publicChannel ; updateEnv(g M, c, G(2)(c)); else c := privateChannel ; updateEnv(g M, c, G(3)(c)); end; pop(pc);

tau = TypeOf Expression(c);

t au1= TypeOf Expression(highValue);

if (((tau = Lchan) and (sup(evalT(tau1), top(pc)) = H)) or (tau = B chan))

then fail;

else send highValue to c;

Figure 3.10 – L’envoi d’une valeur priv´ee sur un canal de niveau inconnu provoque une instrumentation

Exemple 15.

Le deuxi`eme exemple est le programme de la figure 3.8. Nous le reprenons `a la figure

3.11 tout en rajoutant le code instrument´e car l’algorithme d’inf´erence a conclu que le programme n´ecessite une instrumentation. Le programme est pr´esent´e dans le coin sup´erieur gauche de la figure. Le r´esultat de l’instrumentation est pr´esent´e en bas. La troisi`eme instruction re¸coit un nom de canal sur un autre. L’instrumentation est n´ecessaire pour obtenir le vrai type du canal `a l’ex´ecution. A la sixi`eme instruction du programme instrument´e, la mise `a jour de G(3) est due au fait que l’algorithme d’inf´erence marque le canal c comme inconnu `a cette ligne. La quatri`eme instruction est une commande send. Une v´erification est ins´er´ee dans le code instrument´e pour assurer qu’aucune information secr`ete n’est ni envoy´ee sur un canal public ni sur un canal bloqu´e (le type de c ´etant inconnu statiquement).

Programme `a analyser Analyse d’inf´erence receivecv from privateChannel ;

if lowV alue then

receivenc from publicChannel ;

send v to c end Environnement pc i G(1) = [instr 7→ L, v 7→ H val] L 2 pcif = L 3 G(3) = [instr 7→ L, v 7→ H val, c 7→ U chan] L 4 G(4) = [instr 7→ U, v 7→ H val, c 7→ U chan] L 5 (else skip) G(5) = [instr 7→ L,

v 7→ H val] L 6 G(2) = [instr 7→ U, v 7→ H val,

c 7→ U chan] L 6 Instrumentation : receivecv from privateChannel ;

updateEnv(g M, v, G(1)(v));

push(sup(top(pc), evalT(TypeOf Expression(lowValue))), pc); if lowValue then

receiven c from publicChannel ;

updateEnv(G(3), x, TypeOf Channel(x)); updateEnv(g M, c, G(3)(c));

tau = TypeOf Expression(c); tau1 = TypeOf Expression(v);

if (((tau = L chan) and (sup(evalT(tau1), top(pc)) = H))

or (tau = B chan)) then fail; else send v to c; else skip; end; pop(pc);

Figure 3.11 – L’envoi d’une valeur priv´ee sur un canal de niveau inconnu provoque une instrumentation

Exemple 16.

Le troisi`eme exemple illustre une situation dans laquelle on a deux commandes if im- briqu´ees. La garde du premier if est typ´ee inconnue et par cons´equent l’envoi dans le second if est effectu´e dans un contexte de niveau inconnu. L’envoi de la valeur de c qui est de type inconnu sur le canal public publicChannel requiert l’instrumentation du programme. Il faut en effet s’assurer que lors de l’ex´ecution, une information priv´ee ne sera pas envoy´ee sur publicChannel. Une v´erification est ins´er´ee dans le code instru- ment´e pour assurer qu’aucune information secr`ete n’est ni envoy´ee sur un canal public ni sur un canal bloqu´e. Il est n´ecessaire d’instrumenter les trois premi`eres commandes car le canal x1est re¸cu sur un autre canal. L’instrumentation est n´ecessaire pour obtenir

son vrai type. Notons ´egalement l’usage des instructions push et pop qui manipulent la pile de contextes afin de garder une trace des contextes d’ex´ecution.

Exemple 17.

Le quatri`eme exemple pr´esente un programme avec une boucle while. Le programme doit ˆetre instrument´e car il pr´esente une tentative d’envoi d’une valeur de type inconnu sur un canal public. La valeur de la variable x est inconnue car elle est lue d’un canal qui est lui-mˆeme lu sur un autre canal. Une v´erification est ins´er´ee dans le code instrument´e pour assurer qu’aucune information secr`ete n’est ni envoy´ee sur un canal public ni sur un canal bloqu´e. Il est n´ecessaire d’instrumenter les deux premi`eres commandes car le canal c2 est re¸cu sur un autre canal. L’instrumentation est n´ecessaire pour obtenir son

vrai type.

Notre approche a ´et´e accept´ee pour publication Bedford et al. [7]. Les algorithmes d’inf´erence et d’instrumentation ont ´et´e implant´es par Andrew Bedford. Un lien est disponible [8] pour tout lecteur qui souhaiterait avoir acc`es au code instrument´e. L’im- pl´ementation est divis´ee en deux parties : un analyseur et une interface. L’analyseur a ´et´e cod´e en Ocaml. Il se sert de Ocamllex et Ocamlyacc pour g´en´erer l’analyseur lexical et le parseur. Afin de rendre l’application tr`es portable, nous nous servons de OCaml-Java pour compiler le code OCaml en bytecode afin qu’il puisse s’ex´ecuter avec la machine virtuelle Java. L’interface est ´ecrite avec Java et se sert de la librairie stan- dard Swing. Lorsqu’une erreur est d´ecel´ee au cours de l’analyse, que ce soit une erreur lexicale, syntaxique, s´emantique soit une erreur li´ee au flot, l’analyseur s’arrˆete et affiche un message expliquant la cause de l’erreur. Si l’analyseur inf`ere que le code `a besoin d’ˆetre instrument´e, il g´en`ere automatiquement et affiche le code instrument´e. Si aucune

Programme `a analyser Analyse d’inf´erence receiven x1 from publicChannel ;

receiveca from x1; receivecc from x1; b := 3 ; if a > 2 then if b = 3 then send c to publicChannel ; end end Environnement pc i G(1) = [instr 7→ L, x1 7→ U chan] L 2 G(2) = G(1)†[a 7→ U val] L 3 G(3) = G(2)†[c 7→ U val] L 4 G(4) = G(3)†[b 7→ L val] L 5 pcif = U 6 pcif = U 7 G(7) = G(4)†[instr 7→ U ] U 8 (else skip de b = 3) G(8) = G(4) U 9 G(6) = supEnv(G(7), G(8)) = G(7) U 9 (else skip de a > 2) G(9) = G(4) L G(5) = supEnv(G(6), G(9)) = G(6) = G(7) U 9 Instrumentation : receiven x1 from publicChannel ;

updateEnv(G(1), x1, TypeOf Channel(x1));

updateEnv(g M, x1, G(1)(x1));

receiveca from x1;

updateEnv(G(2), a, sup(evalT(TypeOf Expression(x1)), top(pc))val);

updateEnv(g M, a, G(2)(a)); receivecc from x1;

updateEnv(G(3), c, sup(evalT(TypeOf Expression(x1)), top(pc))val);

updateEnv(g M, c, G(3)(c)); b := 3

updateEnv(g M, b, G(4)(b));

push(sup(top(pc), evalT(TypeOf Expression(a > 2))), pc); if a > 2 then

push(sup(top(pc), evalT(TypeOf Expression(b = 3))), pc); if b = 3 then;

tau = TypeOf Expression(publicChannel); tau1 = TypeOf Expression(c);

if (((tau = L chan) and (sup(evalT(tau1), top(pc)) = H))

or (tau = B chan)) then fail;

else send c to publicChannel; end; else skip; end; pop(pc); else skip; end; pop(pc);

Figure 3.12 – L’envoi d’une valeur inconnue sur un canal de niveau public provoque une instrumentation

Programme `a analyser Analyse d’inf´erence receivenc2 from publicChannel;

receivecx from c2;

a := 0;

while a < 50 do

send x to publicChannel; receivecx from publicChannel;

a := a + 2; end

It´eration 1 It´eration 2 pc = L et G(1) = [instr 7→ L, c27→ U chan] G(2) = G(1)† [x 7→ U val] G(3) = G(2)† [a 7→ L val] pcwhile= L pcwhile= L G(5) = G(3)†[instr 7→ U ] G(5) = supEnv(G(3), G(7)) †[instr 7→ U ] G(6) = G(5)†[x 7→ L val] G(6) = G(5)†[x 7→ L val] G(7) = G(6)†[a 7→ L val] G(7) = G(6)†[a 7→ L val]

G(4) = G(7) Instrumentation : receivenc2 from publicChannel ;

updateEnv(G(1), c2, TypeOf Channel(c2));

updateEnv(g M, c2, G(1)(c2));

receivecx from c2;

updateEnv(G(2), x, sup(evalT(TypeOf Expression(c2)), top(pc))val);

updateEnv(g M, x, G(2)(x)); a := 0 ;

updateEnv(g M, a, G(3)(a));

push(sup(top(pc), evalT(TypeOf Expression(a < 50))), pc); while a < 50 do

tau = TypeOf Expression(publicChannel); tau1 = TypeOf Expression(x);

if (((tau = L chan) and (sup(evalT(tau1), top(pc)) = H))

or (tau = B chan)) then fail;

else send x to publicChannel; end;

receivecx from publicChannel;

updateEnv(g M, x, G(6)(x)); a := a + 2

updateEnv(g M, a, G(7)(a)); end;

pop(pc);

Apr`es le 2e tour S = supEnv(S, G(7)) ( S l’environnement re¸cu en param`etre de Infer lors du second appel du while. S a pour valeur supEnv(G(3), G(7)) la valeur ici G(7) est celle apr`es le premier appel `a while).

On a donc atteint le point fixe de l’analyse et pouvons arrˆeter les it´erations.

Figure 3.13 – Exemple illustrant l’instrumentation d’un programme avec boucle while

erreur ne se produit et qu’il n’est pas n´ecessaire d’instrumenter, alors un message de correction est affich´e. La figure 3.14illustre un cas de rejet par l’algorithme d’inf´erence et la figure 3.15 un cas d’acceptation avec instrumentation.

3.6

Conclusion

Ce chapitre a port´e sur le d´eveloppement d’une approche hybride combinant analyse statique et dynamique pour v´erifier la non-interf´erence. L’objectif est de rejeter les cas non s´ecuritaires, distinguer les cas incertains statiquement qui sont r´esolus par l’insertion de tests dynamiques appropri´es, et d’accepter les cas s´ecuritaires. Les cas incertains seront accept´es ou rejet´es `a l’ex´ecution selon les valeurs donn´ees aux variables

Figure 3.14 – Exemple de programme rejet´e.

incertaines.

Les pr´ec´edents travaux de Desharnais et al. [12] s’ins`erent dans le mˆeme cadre que notre travail. L’analyse statique qui y a ´et´e faite pr´esente les fondements de ce travail. Ce travail apporte quelques modifications `a celle-ci. Entre autres, nous avons introduit un nouveau type bloqu´e pour empˆecher tout envoi ult´erieur sur un canal qui, le cas ´ech´eant, r´ev´elerait de l’information confidentielle. Si aucun envoi n’est effectu´e sur le canal, le programme n’est pas rejet´e. Les r`egles de typage ont ´et´e modifi´ees en cons´equence.

Chapitre 4

Conclusion

4.1

Contributions

Dans ce m´emoire, nous avons d´evelopp´e une approche hybride pour l’application d’une politique de s´ecurit´e li´ee au contrˆole du flot d’information dans un programme. Cette politique de s´ecurit´e est la non-interf´erence. Nous avons d´ebut´e par la pr´esentation de quelques travaux majeurs traitant du sujet dans le chapitre 2. Nous y avons pr´esent´e les analyses statiques existantes, les analyses dynamiques et aussi celles hybrides. Nous avons mis l’accent sur l’´evolution de ces types d’analyses au fil du temps. Le contrˆole du flot d’information a ´et´e abord´e, en particulier celles utilisant le typage. Nous avons soulev´e deux points importants. Premi`erement, les analyses statiques par manque d’in- formations, doivent souvent ˆetre conservatrices. C’est-`a-dire qu’elles rejettent des pro- grammes corrects alors que ceux-ci s’ex´ecuteraient de fa¸con s´ecuritaire (faux positifs). Deuxi`emement, l’analyse dynamique ne pr´esente pas de faux positifs. En effet, un pro- gramme est rejet´e lorsque son ex´ecution est non s´ecuritaire. Cependant, les analyses dynamiques rajoutent une surcharge d’ex´ecution au programme, du fait des tests dy- namiques qui doivent ˆetre effectu´es. Nous avons ainsi choisi d’adopter une approche combinant les deux autres types d’approches. L’analyse hybride que nous effectuons poss`ede une phase statique qui minimise le plus les faux positifs et une phase dyna- mique pour rechercher les informations qui pourraient manquer `a l’analyse statique. La phase dynamique n’arrive que si la phase statique en identifie le besoin. Notre approche a ´et´e pr´esent´ee dans le chapitre 3. Dans la premi`ere phase de notre approche nous ef- fectuons une analyse statique qui permet de distinguer les programmes s´ecuritaires, des non s´ecuritaires mais aussi des incertains. Les incertains sont des cas qui sont d’habi- tude rejet´es par une analyse statique classique. Nous choisissons plutˆot de marquer les

causes de l’incertitude pour les r´esoudre dans la deuxi`eme phase de notre analyse. Les r´esultats de l’analyse statique sont conserv´es. Dans la deuxi`eme phase pour la r´esolution des incertitudes, nous ins´erons des tests dynamiques judicieusement. En effet, l’analyse statique n’est pas reprise mais nous nous servons de ses r´esultats pour placer des tests dynamiques afin de nous assurer que le programme s’ex´ecutera de fa¸con s´ecuritaire. La finalit´e de notre travail est que nous arrivons `a r´eduire consid´erablement les faux positifs inh´erents aux analyses statiques, tout en minimisant la surcharge d’ex´ecution li´ee `a l’analyse dynamique. En effet les tests dynamiques sont ins´er´es juste aux points o`u ils sont jug´es n´ecessaires.