Proof of security of the CFC counter-measure
Require Import Coqlib List Maps Integers Errors.
Import ListNotations.
Require Import AST Linking Smallstep Events.
Require Import Globalenvs Values Kildall.
Require Import Op Registers Memory RTL.
Require Import CounterMeasures CFC CFCproof.
Require Import RTLtyping RTLpast RTLfault.
Robustness of signatures
Section compute_sigs.
Lemma compute_sigs_robust f :
forall sigs joins pc c rs pc1 pc2 pred,
compute_sigs f =
OK (
sigs,
joins) ->
(
fn_code f)!
pc =
Some (
Icond c rs pc1 pc2 pred) ->
pc1 <>
pc2 ->
get_sig sigs pc1 <>
get_sig sigs pc2.
Proof.
End compute_sigs.
Static specification
Ltac extlia :=
unfold rts,
gsr in *;
Coqlib.extlia.
Ltac destruct_disjs :=
repeat match goal with H: _ \/ _ |- _ =>
destruct H end.
Lemma transf_code_cond_inv f tf env :
forall pc c rs pc1 pc2 pred,
wt_function f env ->
transf_function f =
OK tf ->
do_protect f =
true ->
let code :=
fn_code tf in
code!
pc =
Some (
Icond c rs pc1 pc2 pred) ->
(
exists sigs joins abort pcf c' rs' pc1' pc2' pred',
(
fn_code f)!
pcf =
Some (
Icond c' rs' pc1' pc2' pred')
/\
compute_sigs f =
OK (
sigs,
joins)
/\
spec_seq_inv (
fun pc =>
pc <>
fn_entrypoint tf)
abort code
pc (
Icond c rs pc1 pc2 pred)
pcf (
transf_cond sigs (
gsr f) (
rts f)
pcf c' rs' pc1' pc2' pred') (
CTwoExits pc1' pc2')
/\
code!
abort =
Some (
Ibuiltin EF_cm_catch []
BR_none abort))
\/ (
exists sigs joins abort pcf r,
(
fn_code f)!
pcf =
Some (
Ireturn r)
/\
compute_sigs f =
OK (
sigs,
joins)
/\
spec_seq_inv (
fun pc =>
pc <>
fn_entrypoint tf)
abort code
pc (
Icond c rs pc1 pc2 pred)
pcf (
transf_return sigs (
gsr f)
pcf r)
CNoExit
/\
code!
abort =
Some (
Ibuiltin EF_cm_catch []
BR_none abort)
).
Proof.
Lemma transf_function_protect :
forall f tf,
transf_function f =
OK tf ->
do_protect tf =
do_protect f.
Proof.
intros.
unfold do_protect.
repeat monadInv.
reflexivity.
Qed.
Section CFC.
Variable prog:
program.
Variable tprog:
program.
Hypothesis TRANSL:
match_prog prog tprog.
Let ge :=
Genv.globalenv prog.
Let tge :=
Genv.globalenv tprog.
Lemma functions_translated_inv:
forall v tf,
Genv.find_funct tge v =
Some tf ->
exists f,
Genv.find_funct ge v =
Some f /\
transf_fundef f =
OK tf.
Proof.
Lemma function_ptr_translated_inv:
forall v tf,
Genv.find_funct_ptr tge v =
Some tf ->
exists f,
Genv.find_funct_ptr ge v =
Some f /\
transf_fundef f =
OK tf.
Proof.
Lemma find_function_translated_inv:
forall ros rs tfd,
find_function tge ros rs =
Some tfd ->
exists fd,
find_function ge ros rs =
Some fd /\
transf_fundef fd =
OK tfd.
Proof.
Hypothesis WT:
wt_program prog.
Ltac external_call_nofault :=
exfalso;
repeat
match goal with
|
H:
external_call _ _ _ _ [_] _ _ |- _ =>
eapply external_call_nofault in H;
inv H
|
H:
forall f, _ <> _ |-
False =>
eapply H;
eauto
end.
Ltac simplify_xors :=
match goal with
|
EQ: ?
x =
Vint _ |-
context [?
x] =>
rewrite EQ;
simpl
|
EQ: ?
x =
Vint _,
H:
context [?
x] |- _ =>
rewrite EQ in H;
simpl in H
| |-
context [
Int.xor ?
x (
Int.xor ?
x _)] =>
rewrite <-
Int.xor_assoc,
Int.xor_idem,
Int.xor_zero_l;
simpl
|
H:
context [
Int.xor ?
x (
Int.xor ?
x _)] |- _ =>
rewrite <-
Int.xor_assoc,
Int.xor_idem,
Int.xor_zero_l in H;
simpl in H
end.
Ltac simplify_tests :=
match goal with
| |-
context [
Int.eq ?
x ?
x] =>
rewrite Int.eq_true;
simpl
| |-
context [
Int.eq _ _] =>
rewrite Int.eq_false by (
intros ?;
eauto);
simpl
end.
Ltac imply_condition :=
match goal with
|
H:
eval_condition _ ?
rs _ =
Some _ |-
eval_condition _ ?
rs' _ =
Some _ =>
replace rs' with rs;
eauto;
apply map_ext_in;
intros *
IN;
rewrite Regmap.gso;
auto
|
H1:
eval_condition _ ?
rs _ =
Some _,
H2:
eval_condition _ ?
rs' _ =
Some _ |- _ =>
replace rs' with rs in H2;
[
rewrite H1 in H2;
inv H2|
apply map_ext_in;
intros *
IN;
rewrite Regmap.gso;
auto]
end.
Ltac do_step :=
match goal with
|
H: _ ! ?
pc =
Some (
Inop _) |-
step _ (
RTL.State _ _ _ ?
pc _ _) _ _ =>
eapply RTL.exec_Inop; [
eauto];
simpl;
eauto
|
H: _ ! ?
pc =
Some (
Iop _ _ _ _) |-
step _ (
RTL.State _ _ _ ?
pc _ _) _ _ =>
eapply RTL.exec_Iop; [
now eauto|];
simpl;
eauto
|
H: _ ! ?
pc =
Some (
Ibuiltin _ _ _ _) |-
step _ (
RTL.State _ _ _ ?
pc _ _) _ _ =>
eapply RTL.exec_Ibuiltin;
eauto; [|
constructor];
repeat econstructor
|
H: _ ! ?
pc =
Some (
Icond _ _ _ _ _) |-
step _ (
RTL.State _ _ _ ?
pc _ _) _ _ =>
eapply RTL.exec_Icond;
eauto;
simpl;
try imply_condition;
simpl
| |-
fstep _ _ _ (
Valid _) =>
instantiate (1:=
RTL.State _ _ _ _ _ _);
simpl
|
H: _ ! ?
pc =
Some (
Inop _) |-
fstep _ (
Valid (
State _ _ _ ?
pc _ _)) _ _ =>
constructor
|
H: _ ! ?
pc =
Some (
Iop _ _ _ _) |-
fstep _ (
Valid (
State _ _ _ ?
pc _ _)) _ _ =>
constructor
|
H: _ ! ?
pc =
Some (
Ibuiltin _ _ _ _) |-
fstep _ (
Valid (
RTL.State _ _ _ ?
pc _ _)) _ _ =>
constructor
|
H: _ ! ?
pc =
Some (
Icond _ _ _ _ _) |-
fstep _ (
Valid (
State _ _ _ ?
pc _ _)) _ _ =>
constructor
|
H: _ ! ?
pc =
Some (
Ibuiltin EF_cm_catch _ _ _) |-
fstep _ (
Valid (
State _ _ _ ?
pc _ _)) _ _ =>
eapply exec_IbuiltinCatch;
eauto
end.
Tactic Notation "star_step" int_or_var(
n) :=
do n (
try (
eapply star_left;
eauto using Eapp_E0));
try apply star_refl.
Ltac simplify_regs :=
match goal with
| |-
context [(_ # ?
x <- _) # ?
x] =>
rewrite Regmap.gss
| |-
context [(_ # _ <- _) # _] =>
rewrite Regmap.gso by auto
|
H:
context [(_ # ?
x <- _) # ?
x] |- _ =>
rewrite Regmap.gss in H
|
H:
context [(_ # _ <- _) # _] |- _ =>
rewrite Regmap.gso in H by auto
end.
Ltac simplify_ctx :=
simpl in *;
match goal with
|
H:
Some _ =
Some _ |- _ =>
inv H
|
H:
Vint _ =
Vint _ |- _ =>
inv H
| _ => (
simplify_regs||
simplify_xors||
simplify_tests)
end.
Opaque transf_function.
Actual security proof. First, handle the fault step
Ltac inv_equalities :=
match goal with
|
H1: ?
x =
Some _,
H2: ?
x =
Some _ |- _ =>
rewrite H2 in H1;
inv H1
|
H1: ?
x =
OK _,
H2: ?
x =
OK _ |- _ =>
rewrite H2 in H1;
inv H1
end.
Ltac inv_gsr :=
simpl in *;
repeat
match goal with
|
H:
eval_assert_args _ _ _ _ [_] _ |- _ =>
inversion H as [|???? ?
EVAL ?
NIL];
subst;
clear H;
inv NIL;
inv EVAL
|
H:
Val.cmp_bool Ceq ?
rs # (
gsr ?
f) _ =
Some true |- _ =>
simpl in H;
destruct (
rs # (
gsr f))
eqn:
GSR;
inversion H as [
EQ];
apply Int.same_if_eq in EQ;
subst;
auto
end.
Lemma fault_step:
forall st0 t0 st1 (
attacked:
function)
st2,
do_protect attacked =
true ->
RTL.initial_state tprog st0 ->
star step tge st0 t0 st1 ->
fstep tge (
Valid st1) [
Event_fault (
Fault_invertcond attacked)]
st2 ->
gets_caught tprog st2
\/ (
exists (
st' :
RTL.state) (
t' :
trace),
star fstep tge st2 t' (
Valid st') /\
nofault t' /\
star step tge st1 t' st').
Proof.
intros *
HARDEN INIT STEPS FSTEP.
inv FSTEP.
1:{
apply step_nofault in H0.
inv H0.
specialize (
H2 _
eq_refl).
inv H2. }
apply Eqdep.EqdepTheory.inj_pair2 in H0;
subst.
assert (
exists b ros,
find_function tge b ros =
Some (
Internal attacked))
as (?&?&
FIND).
{
subst tge.
eapply steps_has_function in STEPS;
eauto.
simpl;
auto. }
eapply find_function_translated_inv in FIND as (
fd&
FIND&
EQ);
eauto.
destruct fd;
repeat monadInv.
erewrite transf_function_protect in HARDEN;
eauto.
assert (
exists env,
wt_function f env)
as (
env&
WTF).
{
eapply find_function_inversion in FIND as (?&
IN).
eapply WT in IN.
inv IN.
eauto. }
eapply transf_function_entry in HARDEN as ENTRY;
eauto.
destruct_conjs.
assert (
gsr f <>
rts f)
by (
unfold gsr,
rts;
lia).
eapply transf_code_cond_inv in H1 as [|];
eauto;
destruct_conjs.
-
inv_equalities.
assert (
forall r,
In r x8 ->
r <>
rts f)
as NORTS.
{
intros.
eapply max_reg_function_use in H1;
eauto.
extlia. }
inv_transf_function.
+
assert (
rs # (
gsr f) =
Vint (
get_sig x1 x6))
as GSR.
{
do 1
step_back.
inv_gsr. }
destruct (
peq x9 x10);
subst; [
right|
left].
*
do 3
esplit; [|
split].
--
destruct b;
star_step 6;
repeat do_step;
simpl;
eauto using eval_builtin_args_BA.
1,3:
repeat simplify_ctx;
eauto;
simpl;
eauto.
1,2:
repeat do_step.
--
constructor.
--
destruct b;
star_step 7. 1-6,8-13:
repeat do_step;
simpl;
eauto using eval_builtin_args_BA;
repeat econstructor.
1,2:
repeat simplify_ctx;
eauto.
1,2:
repeat do_step.
*
eapply compute_sigs_robust in n;
eauto.
destruct b;
star_step 7;
repeat do_step;
simpl;
eauto using eval_builtin_args_BA.
1,4:
repeat simplify_ctx;
eauto.
all:
repeat do_step.
+
assert (
rs # (
gsr f) =
Vint (
get_sig x1 x6))
as GSR.
{
do 4
step_back;
repeat simplify_ctx;
inv_gsr. }
assert (
rs # (
rts f) =
Vint (
Int.xor (
get_sig x1 x6) (
if b then get_sig x1 x9 else get_sig x1 x10)))
as RTS.
{
do 4
step_back;
simpl in *.
1,2:
repeat simplify_ctx.
1,2:
assert (
b0 =
b)
by (
now imply_condition);
subst.
1,2:
destruct b;
simpl in *;
auto;
try congruence.
}
destruct (
peq x9 x10);
subst; [
right|
left].
*
do 3
esplit; [|
split].
--
destruct b;
star_step 3;
repeat do_step;
simpl.
1,3:
repeat simplify_ctx;
eauto;
simpl;
eauto.
all:
try congruence;
repeat do_step.
--
constructor.
--
destruct b;
star_step 4. 1-3,5-7:
repeat do_step;
simpl.
1,2:
repeat simplify_ctx;
eauto.
all:
repeat do_step.
*
eapply compute_sigs_robust in n;
eauto.
destruct b;
star_step 4;
repeat do_step;
simpl.
1,4:
repeat simplify_ctx;
reflexivity.
all:
repeat do_step.
+
assert (
b =
false);
subst.
{
do 6
step_back;
inv_gsr.
all:
repeat simplify_ctx;
try reflexivity.
all:
destruct (
peq x9 x10);
subst;
repeat simplify_ctx;
auto.
exfalso.
eapply compute_sigs_robust in n;
eauto.
imply_condition.
destruct b1;
subst;
try congruence.
assert (
Int.xor (
get_sig x1 x6) (
get_sig x1 x9) <>
Int.xor (
get_sig x1 x6) (
get_sig x1 x10)); [|
congruence].
intros EQ;
apply Int.xor_inj_r in EQ;
congruence.
}
left.
star_step 2;
repeat do_step.
+
assert (
b =
false);
subst.
{
do 6
step_back;
inv_gsr.
all:
repeat simplify_ctx;
try reflexivity.
all:
destruct (
peq x9 x10);
subst;
repeat simplify_ctx;
auto.
exfalso.
eapply compute_sigs_robust in n;
eauto.
imply_condition.
destruct b1;
subst;
try congruence.
assert (
Int.xor (
get_sig x1 x6) (
get_sig x1 x9) <>
Int.xor (
get_sig x1 x6) (
get_sig x1 x10)); [|
congruence].
intros EQ;
apply Int.xor_inj_r in EQ;
congruence.
}
left.
star_step 2;
repeat do_step.
-
inv_transf_function;
destruct Compopts.intra_cfc_return;
inv_transf_function.
do 1
step_back.
inv_gsr.
simpl in *.
rewrite Int.eq_true in H2;
inv H2.
left.
star_step 2;
repeat do_step.
Qed.
Theorem transf_program_secure:
forall (
attacked:
function),
do_protect attacked =
true ->
secure_against tprog (
Fault_invertcond attacked).
Proof.
End CFC.