1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108(**************************************************************************)(* This file is part of BINSEC. *)(* *)(* Copyright (C) 2016-2026 *)(* CEA (Commissariat à l'énergie atomique et aux énergies *)(* alternatives) *)(* *)(* you can redistribute it and/or modify it under the terms of the GNU *)(* Lesser General Public License as published by the Free Software *)(* Foundation, version 2.1. *)(* *)(* It 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 Lesser General Public License for more details. *)(* *)(* See the GNU Lesser General Public License version 2.1 *)(* for more details (enclosed in the file licenses/LGPLv2.1). *)(* *)(**************************************************************************)openTypesopenIropenScriptmoduleStrMap=Basic_types.String.MapmoduleBiTbl=Basic_types.Integers.Bigint.HtblmoduleLogger=Logger.Sub(structletname="checkct"end)typeleak_info=|HaltLeak(** Halts at first leak *)|InstrLeak(** Reports leaky instructions (each one is reported only once) *)moduleKind=structtypet=Control_flow|Memory_access|Multiplication|Dividend|Divisorletto_string=function|Control_flow->"control flow"|Memory_access->"memory access"|Multiplication->"multiplication"|Dividend->"dividend"|Divisor->"divisor"letof_string=function|"control-flow"->Control_flow|"memory-access"->Memory_access|"multiplication"->Multiplication|"dividend"->Dividend|"divisor"->Divisor|_->raise(Invalid_argument"of_string")letppppft=Format.pp_print_stringppf(to_stringt)endmoduleReport=structtypet={memory:Bitvector.tBitvector.Map.tStrMap.t;public:Bitvector.tlistStrMap.t;secret1:Bitvector.tlistStrMap.t;secret2:Bitvector.tlistStrMap.t;}lettomlt=letopenTomlinlettoml_variable_valsm=Min.of_key_values(StrMap.fold(funnamevalsres->lettoml_vals=Types.NodeString(List.mapBitvector.to_stringvals)in(Min.keyname,Types.TArraytoml_vals)::res)m[])andtoml_array_valsm=Min.of_key_values(Bitvector.Map.fold(funaddrvalueres->(Min.key(Bitvector.to_stringaddr),Types.TString(Bitvector.to_stringvalue))::res)m[])inlettoml_memory_valsm=Min.of_key_values(StrMap.fold(funnamevalsres->(Min.keyname,Types.TTable(toml_array_valsvals))::res)m[])inMin.of_key_values[(Min.key"memory",Types.TTable(toml_memory_valst.memory));(Min.key"public",Types.TTable(toml_variable_valst.public));(Min.key"secret1",Types.TTable(toml_variable_valst.secret1));(Min.key"secret2",Types.TTable(toml_variable_valst.secret2));]letppppft=letpp_categoryppfvars=StrMap.iter(funnamelist->Format.fprintfppf"@[<h> %s : @[<hov>%a@]@]@,"name(Format.pp_print_list~pp_sep:Format.pp_print_spaceBitvector.pp_hex_or_bin)list)varsandpp_arrayppfarray=Bitvector.Map.iter(funaddrvalue->Format.fprintfppf"@[<h> %a : %a@]@,"Bitvector.pp_hex_or_binaddrBitvector.pp_hex_or_binvalue)arrayinletpp_memoryppfmemory=StrMap.iter(funnamevalues->Format.fprintfppf"@[<v 1>%s :@,%a@]@,"namepp_arrayvalues)memoryinFormat.fprintfppf"@[<v 0>%a@[<v 1>public :@,\
%a@]@,\
@[<v 1>secret1 :@,\
%a@]@,\
@[<v 1>secret2 :@,\
%a@]@]"pp_memoryt.memorypp_categoryt.publicpp_categoryt.secret1pp_categoryt.secret2endmoduleStatus=structtypet=Secure|InsecureofReport.t|Unknownletto_string=function|Secure->"secure"|Insecure_->"insecure"|Unknown->"unknown"letppppft=Format.pp_print_stringppf(to_stringt)endtypeAst.Obj.t+=BoolofbooltypeAst.Instr.t+=SecretofAst.Loc.tAst.loctypeAst.Instr.t+=Se_checktypeAst.t+=Globalsofbool*stringlistmoduletypeOPTIONS=sigvalleak_info:leak_infovaltaint:boolvalcv:boolvalrelse:boolvalstats_file:stringoptionvalcheck_branch:boolvalcheck_memory:boolvalcheck_mult:boolvalcheck_dividend:boolvalcheck_divisor:boolendlet(===)=Symbolic.Default.Expr.is_equallet(/==)ee'=not(e===e')moduleCt_state=structopenSymbolic.Defaulttypeload=([`Mem],string,Memory.t)Term.ttypet={mutableconstraints:Expr.tlist;mutableconjunction:Expr.t;secrets:Expr.tExpr.Tbl.t;mirror_e:Expr.tExpr.Tbl.t;mirror_m:Memory.tMemory.Tbl.t;mutableloads:loadlist;roots:Memory.tMemory.Tbl.t;mutablemodels:(int*Model.t)list;}letempty()={constraints=[];conjunction=Expr.one;secrets=Expr.Tbl.create8;mirror_e=Expr.Tbl.create64;mirror_m=Memory.Tbl.create16;loads=[];roots=Memory.Tbl.create16;models=List.init4(funi->(i,Model.empty()));}letforkt={twithmirror_e=Expr.Tbl.copyt.mirror_e;mirror_m=Memory.Tbl.copyt.mirror_m;secrets=Expr.Tbl.copyt.secrets;roots=Memory.Tbl.copyt.roots;}letmirror(e:Expr.t)t=matchewith|Var{name;size;label;_}->lete'=Expr.var("mirror_"^name)sizelabelinExpr.Tbl.addt.mirror_eee';Expr.Tbl.addt.secretse'e|_->raise_notrace(Invalid_argument"mirror")letrecis_tainted(e:Expr.t)t=trye/==Expr.Tbl.findt.mirror_eewithNot_found->(matchewith|Cst_->false|Var_->false|Load{label;_}->t.loads<-Term.to_mem_exne::t.loads;is_tainted_memorylabelt|Unary{x;_}->is_taintedxt|Binary{x;y;_}->is_taintedxt||is_taintedyt|Ite{c;t=x;e=y;_}->is_taintedct||is_taintedxt||is_taintedyt)||(Expr.Tbl.addt.mirror_eee;false)andis_tainted_memory(m:Memory.t)t=trynot(Memory.equalm(Memory.Tbl.findt.mirror_mm))withNot_found->(matchmwithSymbol_->false|Layer_->true)letrecmake_mirror_e(e:Expr.t)t=tryExpr.Tbl.findt.mirror_eewithNot_found->lete'=matchewith|Cst_->e|Var_->e|Load{label;len;dir;addr;_}->t.loads<-Term.to_mem_exne::t.loads;letlabel'=make_mirror_mlabeltinletaddr'=make_mirror_eaddrtinif(not(Memory.equallabellabel'))||(addr/==addr')thenExpr.loadlendiraddr'label'elsee|Unary{x;f;_}->letx'=make_mirror_extinifx/==x'thenExpr._unaryfx'elsee|Binary{x;y;f;_}->letx'=make_mirror_extandy'=make_mirror_eytinif(x/==x')||(y/==y')thenExpr._binaryfx'y'elsee|Expr.Ite{c;t=x;e=y;_}->letc'=make_mirror_ectandx'=make_mirror_extandy'=make_mirror_eytinif(c/==c')||(x/==x')||(y/==y')thenExpr._itec'x'y'elseeinExpr.Tbl.addt.mirror_eee';e'andmake_mirror_m(m:Memory.t)t=tryMemory.Tbl.findt.mirror_mmwithNot_found->letm'=matchmwith|Symbol_->Memory.Tbl.addt.rootsmm;m|Layer{over;addr;store;_}->letsize=Expr.sizeofaddrandaddr'=make_mirror_eaddrtandover'=make_mirror_movertinMemory.Tbl.addt.rootsm(Memory.Tbl.findt.rootsover);letstore',dirty=Store.fold(funoffsetchunk(store',dirty)->letoffset'=Bitvector.createoffsetsizeinifChunk.is_hunkchunkthen(Store.storeoffset'chunkstore',dirty)elseletvalue=Chunk.to_termchunkinletvalue'=make_mirror_evaluetin(Store.storeoffset'(Chunk.of_termvalue')store',dirty||(value/==value')))(Store.empty,false)storeinif(addr/==addr')||dirty||not(Memory.equaloverover')thenMemory.layeraddr'store'over'elseminMemory.Tbl.addt.mirror_mmm';m'letmake_contextconstraintst=letrecvisitconstraintstconjunction=ifconstraints==t.constraintsthenconjunctionelsematchconstraintswith|[]->assertfalse|e::constraints->lete'=make_mirror_eetinvisitconstraintst(ife/==e'thenExpr.logande'conjunctionelseconjunction)int.conjunction<-visitconstraintstt.conjunction;t.constraints<-constraintsletrecfind_rootarrayt=tryMemory.Tbl.findt.rootsarraywithNot_found->letroot=matcharraywith|Symbol_->array|Layer{over;_}->find_rootovertinMemory.Tbl.addt.rootsarrayroot;rootendtype('value,'model,'state,'path,'a)field_id+=|Ct_state:('value,'model,'state,'path,Ct_state.t)field_idletgrammar_extension=[Dyp.Bind_to_cons[("secret_or_public","Obj");("comma_separated_ident_rev_list","Obj")];Dyp.Add_rules[(("secret_or_public",[Dyp.Regexp(RE_String"secret")],"default_priority",[]),fun__->(Binsec_script.Syntax.Obj(Booltrue),[]));(("secret_or_public",[Dyp.Regexp(RE_String"public")],"default_priority",[]),fun__->(Binsec_script.Syntax.Obj(Boolfalse),[]));(("comma_separated_ident_rev_list",[Dyp.Non_ter("ident",No_priority)],"default_priority",[]),fun_->function|[Binsec_script.Syntax.Stringident]->(Binsec_script.Syntax.Obj(String_list[ident]),[])|_->assertfalse);(("comma_separated_ident_rev_list",[Dyp.Non_ter("comma_separated_ident_rev_list",No_priority);Dyp.Regexp(RE_Char',');Dyp.Non_ter("ident",No_priority);],"default_priority",[]),fun_->function|[Binsec_script.Syntax.Obj(String_listl);_;Binsec_script.Syntax.Stringident;]->(Binsec_script.Syntax.Obj(String_list(ident::l)),[])|_->assertfalse);(("decl",[Dyp.Non_ter("secret_or_public",No_priority);Dyp.Regexp(RE_String"global");Dyp.Non_ter("comma_separated_ident_rev_list",No_priority);],"default_priority",[]),fun_->function|[Binsec_script.Syntax.Obj(Boolsecret);_;Binsec_script.Syntax.Obj(String_listnames);]->(Binsec_script.Syntax.(Decl(Globals(secret,names))),[])|_->raiseDyp.Giveup);(("decl",[Dyp.Regexp(RE_String"check");Dyp.Regexp(RE_String"secret");Dyp.Regexp(RE_String"erasure");Dyp.Regexp(RE_String"over");Dyp.Non_ter("symbol",No_priority);],"default_priority",[]),fun_->function|[_;_;_;_;Binsec_script.Syntax.Symbolsymbol]->(Binsec_script.Syntax.Decl(Script.Return_hook(symbol,[Se_check;Script.Instr.halt])),[])|_->assertfalse);(("fallthrough",[Dyp.Non_ter("loc",No_priority);Dyp.Regexp(RE_String":=");Dyp.Non_ter("secret_or_public",No_priority);],"default_priority",[]),fun_->function|[Binsec_script.Syntax.Loclval;_;Binsec_script.Syntax.Obj(Boolsecret);]->(Binsec_script.Syntax.Instr(ifsecretthenSecretlvalelseScript.Instr.nondetlval),[])|_->raiseDyp.Giveup);(("fallthrough",[Dyp.Regexp(RE_String"check");Dyp.Regexp(RE_String"secret");Dyp.Regexp(RE_String"erasure");],"default_priority",[]),fun_->function|[_;_;_]->(Binsec_script.Syntax.InstrSe_check,[])|_->raiseDyp.Giveup);(("instr",[Dyp.Non_ter("loc",No_priority);Dyp.Regexp(RE_String":=");Dyp.Non_ter("secret_or_public",No_priority);Dyp.Non_ter("accept_newline",No_priority);Dyp.Ter"AS";Dyp.Non_ter("ident",No_priority);],"default_priority",[]),fun_->function|[Binsec_script.Syntax.Loclval;_;Binsec_script.Syntax.Obj(Boolsecret);_;_;Binsec_script.Syntax.Stringname;]->letvar=(Ast.Loc.varname~size:(Ast.Size.sizeoflval),Lexing.dummy_pos)in(Binsec_script.Syntax.Stmt[(ifsecretthenSecretvarelseAst.Instr.nondetvar);Ast.Instr.assignlval(Ast.Expr.locvar,Lexing.dummy_pos);],[])|_->assertfalse);];]moduleMake(Options:OPTIONS)(Engine:ENGINEwithtypePath.value=Symbolic.Default.Expr.t):EXTENSIONSwithtypepath=Engine.Path.t=structmodulePath=Engine.PathmoduleState=Path.StatemoduleValue=Path.ValuemodulePath_stats=Engine.Metrics.Exploration.PathsmoduleOther_stats=Engine.Metrics.Explorationtypepath=Path.tletaddr_size=Machine.ISA.word_sizeEngine.isaletkey=Engine.lookupCt_statetypebuiltin+=|MirrorofDba.Var.t|Ct_checkofDba.Expr.t*Kind.t|Se_checkletct_cf_secure=ref0andct_cf_insecure=ref0andct_cf_unknown=ref0andct_mem_secure=ref0andct_mem_insecure=ref0andct_mem_unknown=ref0andct_mult_secure=ref0andct_mult_insecure=ref0andct_mult_unknown=ref0andct_div_secure=ref0andct_div_insecure=ref0andct_div_unknown=ref0andse_secure=ref0andse_insecure=ref0andse_unknown=ref0letct_status(kind:Kind.t)(status:Status.t)=match(kind,status)with|Control_flow,Secure->ct_cf_secure|Control_flow,Insecure_->ct_cf_insecure|Control_flow,Unknown->ct_cf_unknown|Memory_access,Secure->ct_mem_secure|Memory_access,Insecure_->ct_mem_insecure|Memory_access,Unknown->ct_mem_unknown|Multiplication,Secure->ct_mult_secure|Multiplication,Insecure_->ct_mult_insecure|Multiplication,Unknown->ct_mult_unknown|(Dividend|Divisor),Secure->ct_div_secure|(Dividend|Divisor),Insecure_->ct_div_insecure|(Dividend|Divisor),Unknown->ct_div_unknownletse_status(status:Status.t)=matchstatuswith|Secure->se_secure|Insecure_->se_insecure|Unknown->se_unknownletct_addr_status:Status.tVirtual_address.Htbl.t=Virtual_address.Htbl.create128letadd_addr_statusaddrstatus=Virtual_address.Htbl.replacect_addr_statusaddrstatusletis_addr_insecureaddr=matchVirtual_address.Htbl.findct_addr_statusaddrwith|Insecure_->true|(exceptionNot_found)|Secure|Unknown->falseletaddr_status_report()=letinsecure,unknown=Virtual_address.Htbl.fold(funaddr(status:Status.t)(insecure,unknown)->matchstatuswith|Insecure_->(addr::insecure,unknown)|Unknown->(insecure,addr::unknown)|Secure->assertfalse)ct_addr_status([],[])in(List.sortVirtual_address.compareinsecure,List.sortVirtual_address.compareunknown)lettoml_ct_report()=letopenTomlinletl_insecure,l_unknown=addr_status_report()inletls_insecure,ls_unknown=(List.mapVirtual_address.to_stringl_insecure,List.mapVirtual_address.to_stringl_unknown)inletinstructions_status=Min.of_key_values[(Min.key"insecure",Types.TArray(Types.NodeStringls_insecure));(Min.key"unknown",Types.TArray(Types.NodeStringls_unknown));]inletinsecurity_models=Min.of_key_values(Virtual_address.Htbl.fold(funvaddr(status:Status.t)l->matchstatuswith|Insecuremodel->lettoml_model=Report.tomlmodelin(Min.key(Virtual_address.to_stringvaddr),Types.TTabletoml_model)::l|Unknown->l|_->assertfalse)ct_addr_status[])inMin.of_key_values[(Min.key"Instructions status",Types.TTableinstructions_status);(Min.key"Insecurity models",Types.TTableinsecurity_models);]letis_unknown_report()=Path_stats.getPending>0||!ct_cf_unknown+!ct_mem_unknown+!se_unknown>0||Path_stats.statusNon_executable_code>0||Path_stats.statusMax_depth>0||Path_stats.statusEnumeration_limit>0||Path_stats.statusUnresolved_formula>0||Path_stats.status(Error"")>0letmirrorvarpath:Path.tcontinuation=tryCt_state.mirror(State.lookupvar(Path.statepath))(Path.getpathkey);ReturnwithInvalid_argument_->Signal(Error"mirror")letcommand_callback:Ast.t->Script.env->Path.t->bool=letlookup_symbol(env:env)nameattr=matchenv.lookup_symbolnameattrwith|Var{info=Symbol(_,(lazybv));_}->bv|_->assertfalseinfundeclenvpath->matchdeclwith|Globals(secret,names)->List.iter(funname->letaddr=lookup_symbolenvnameValueandbytesize=Size.Byte.create(Bitvector.to_uint(lookup_symbolenvnameSize))inletbitsize=Size.Byte.to_bitsizebytesizeinletvar=Dba.Var.createname~bitsize~tag:Emptyinenv.definevarLexing.dummy_pos;Path.symbolizepathvar;ifsecretthenignore(mirrorvarpath);Path.storepathNone~addr:(Dba.Expr.constantaddr)(Dba.Expr.vvar)LittleEndian)names;true|_->falseletinstruction_callback:Ast.Instr.t->Script.env->Ir.fallthroughlist=letsecret=Printf.sprintf"%%secret%%%d"infuninstenv->matchinstwith|Secretlval->(matchScript.eval_loclvalenvwith|Varvar->[Symbolizevar;Builtin(Mirrorvar)]|Restrict(var,{hi;lo})->letsize'=hi-lo+1inletname'=secretsize'inletvar'=Dba.Var.temporaryname'(Size.Bit.createsize')inletrval=Dba_types.Expr.complement(Dba.Expr.vvar')~lo~hivarin[Symbolizevar';Builtin(Mirrorvar');Assign{var;rval}]|Store(bytes,dir,addr,base)->letsize'=8*bytesinletname'=secretsize'inletvar'=Dba.Var.temporaryname'(Size.Bit.createsize')inletrval=Dba.Expr.vvar'in[Symbolizevar';Builtin(Mirrorvar');Store{base;dir;addr;rval};])|Se_check->[BuiltinSe_check]|_->[]letinstrumentation_routine:Revision.t->unit=letrecvisit_exprgraphvertex(e:Dba.Expr.t)=matchewith|Cst_|Var_|Load_->()|Unary(_,x)->visit_exprgraphvertexx|Binary(Mult,x,y)->ifOptions.check_multthen(Revision.insert_beforegraphvertex(Builtin(Ct_check(x,Multiplication)));Revision.insert_beforegraphvertex(Builtin(Ct_check(y,Multiplication))));visit_exprgraphvertexx;visit_exprgraphvertexy|Binary((DivU|DivS|RemU|RemS),dividend,divisor)->ifOptions.check_dividendthenRevision.insert_beforegraphvertex(Builtin(Ct_check(dividend,Dividend)));ifOptions.check_divisorthenRevision.insert_beforegraphvertex(Builtin(Ct_check(divisor,Divisor)));visit_exprgraphvertexdividend;visit_exprgraphvertexdivisor|Binary(_,x,y)->visit_exprgraphvertexx;visit_exprgraphvertexy|Ite(c,x,y)->visit_exprgraphvertexc;visit_exprgraphvertexx;visit_exprgraphvertexyinfungraph->Revision.iter_new_vertex(funvertex->matchRevision.nodegraphvertexwith|Fallthrough{kind=Load{addr;_};_}->ifOptions.check_memorythenRevision.insert_beforegraphvertex(Builtin(Ct_check(addr,Memory_access)))|Fallthrough{kind=Store{addr;rval;_};_}->ifOptions.check_memorythenRevision.insert_beforegraphvertex(Builtin(Ct_check(addr,Memory_access)));visit_exprgraphvertexrval|Fallthrough{kind=Assign{rval;_};_}->visit_exprgraphvertexrval|Branch{test=expr;_}|Terminator{kind=Jump{target=expr;_};_}->ifOptions.check_branchthenRevision.insert_beforegraphvertex(Builtin(Ct_check(expr,Control_flow)))|_->())graphlettaint_analysisect_state_:Status.t=ifCt_state.is_taintedect_statethenUnknownelseSecureletcv_symbol(ct_state:Ct_state.t)modelie=letopenSymbolic.DefaultinifExpr.Tbl.memct_state.secretsethenmatchiwith|0->Bv.zeros(Expr.sizeofe)|1->Bv.ones(Expr.sizeofe)|2->Bv.fill(Expr.sizeofe)|_->Bv.rand(Expr.sizeofe)elsePath.Model.evalemodelandcv_memory:Path.Model.t->Symbolic.Default.Memory.symbol->Bitvector.t->char=funmodel(Symbol_asarray)addr->letopenSymbolic.DefaultinBv.to_char(Path.Model.eval(Expr.load1LittleEndian(Expr.constantaddr)array)model)letextract_cv_report:Ct_state.t->Value.tlistDba_types.Var.Map.t->Path.Model.t->Symbolic.Default.Model.t->Report.t=funct_statesymbolsmodel0({arrays;_}asmodel1)->letopenSymbolic.Defaultinletmemory=Symbol.Tbl.fold(fun(Symbol{name;index;_})bytesmemory->StrMap.addname(BiTbl.fold(funaddrbytevalues->Bitvector.Map.add(Bv.createaddrindex)(Bv.of_charbyte)values)bytesBitvector.Map.empty)memory)arraysStrMap.emptyinletpublic,secret1,secret2=Dba_types.Var.Map.fold(fun{name;_}values(public,secret1,secret2)->letvpublic,vsecret1,vsecret2=List.fold_left(fun(public,secret1,secret2)value->letvalue'=tryExpr.Tbl.findct_state.mirror_evaluewithNot_found->valueinifvalue/==value'then(public,Path.Model.evalvaluemodel0::secret1,Model.evalmodel1value'::secret2)else(Path.Model.evalvaluemodel0::public,secret1,secret2))([],[],[])valuesin((ifvpublic<>[]thenStrMap.addnamevpublicpublicelsepublic),(ifvsecret1<>[]thenStrMap.addnamevsecret1secret1elsesecret1),ifvsecret2<>[]thenStrMap.addnamevsecret2secret2elsesecret2))symbols(StrMap.empty,StrMap.empty,StrMap.empty)in{memory;public;secret1;secret2}letcv_analysise(ct_state:Ct_state.t)path:Status.t=letopenSymbolic.Defaultinmatchct_state.modelswith|[]->Unknown|models->(letmain_model=List.hd(Path.modelspath)inCt_state.make_context(Path.predicatepath)ct_state;lete'=Ct_state.make_mirror_eect_stateinife===e'thenSecureelseletmemory=cv_memorymain_modelinct_state.models<-List.fold_left(funmodels(i,model)->letsymbols=cv_symbolct_statemain_modeliinletmodel=ifList.exists(fune->Bv.is_zero(Model.eval~symbols~memorymodele))ct_state.constraintsthenModel.empty()elsemodelinifBv.is_one(Model.eval~symbols~memorymodelct_state.conjunction)then(i,model)::modelselsemodels)[]models;letvalue=Path.Model.evalemain_modelinmatchList.find(fun(i,model)->Bv.diffvalue(Model.eval~symbols:(cv_symbolct_statemain_modeli)~memorymodele'))ct_state.modelswith|exceptionNot_found->Unknown|_,model->Insecure(extract_cv_reportct_state(Path.symbolspath)main_modelmodel))letextract_relse_report(ct_state:Ct_state.t)(symbols:Value.tlistDba_types.Var.Map.t)model:Report.t=letopenSymbolic.Defaultinletmemory=List.fold_left(funmemory(Load{label;len;dir;addr;_}:Ct_state.load)->letarray=Ct_state.find_rootlabelct_stateinletname=matcharraywith|Symbol{name;_}->name|Layer_->assertfalseinletbase=Path.Model.evaladdrmodelinletbytes=Path.Model.eval(Expr.loadlendir(Expr.constantbase)array)modelinletvalues=tryStrMap.findnamememorywithNot_found->Bitvector.Map.emptyinStrMap.addname(Bitvector.Map.addbasebytesvalues)memory)StrMap.emptyct_state.loadsinletpublic,secret1,secret2=Dba_types.Var.Map.fold(fun{name;_}valuesbindings->List.fold_left(fun(public,secret1,secret2)value->iftryvalue/==Expr.Tbl.findct_state.mirror_evaluewithNot_found->falsethen(public,(StrMap.updatename(funhistory->Some(Path.Model.evalvaluemodel::(matchhistorywithNone->[]|Someh->h))))secret1,(StrMap.updatename(funhistory->Some(Path.Model.eval(Expr.Tbl.findct_state.mirror_evalue)model::(matchhistorywithNone->[]|Someh->h))))secret2)else((StrMap.updatename(funhistory->Some(Path.Model.evalvaluemodel::(matchhistorywithNone->[]|Someh->h))))public,secret1,secret2))bindingsvalues)symbols(StrMap.empty,StrMap.empty,StrMap.empty)in{memory;public;secret1;secret2}letrelse_analysisect_statepath:Status.t=lete'=Ct_state.make_mirror_eect_stateinife===e'thenSecureelse(Ct_state.make_context(Path.predicatepath)ct_state;matchPath.check_sat_assuming_v~retain:falsepath(Path.Value.binaryAnd(Path.Value.binaryDiffee')ct_state.conjunction)with|exceptionSymbolic.State.Unknown->Unknown|None->Secure|Somemodel->Insecure(extract_relse_reportct_state(Path.symbolspath)model))letanalyses=letanalyses=ifOptions.relsethen[("RelSE",relse_analysis)]else[]inletanalyses=ifOptions.cvthen("chosen value",cv_analysis)::analyseselseanalysesinletanalyses=ifOptions.taintthen("taint",taint_analysis)::analyseselseanalysesinanalysesletanalyzeexprpath=letrecapply_analysesect_statepathanalyses:Status.t=matchanalyseswith|[]->Unknown|(_,analysis)::analyses->letstatus:Status.t=analysisect_statepathinifstatus<>Unknownthenstatuselseapply_analysesect_statepathanalysesinapply_analysesexpr(Path.getpathkey)pathanalysesletct_checkexpr(kind:Kind.t)path:Path.tcontinuation=letaddr=Path.pcpathinifOptions.leak_info=InstrLeak&&is_addr_insecureaddrthenReturnelseletexpr=Path.get_valuepathexprinletstatus=analyzeexprpathinincr(ct_statuskindstatus);matchstatuswith|Secure->Return|Insecure_->add_addr_statusaddrstatus;Logger.result"Instruction %a has %s leak (%.3fs)"Virtual_address.ppaddr(Kind.to_stringkind)(Engine.Metrics.Exploration.Timer.get());ifOptions.leak_info=HaltLeakthenraiseExec.HaltelseReturn|Unknown->add_addr_statusaddrstatus;Returnletse_checkpath:Path.tcontinuation=letaddr=Symbolic.Default.Expr.var"!secret_seeker"addr_size"!secret_seeker"inletread=Path.read_vpathNone~addr1LittleEndianinletstatus=analyzereadpathinincr(se_statusstatus);(matchstatuswith|Unknown|Secure->()|Insecurereport->Logger.result"Secret-erasure check failure %@ %a (%.3fs)@ %a"Virtual_address.pp(Path.pcpath)(Engine.Metrics.Exploration.Timer.get())Report.ppreport);Returnletbuiltin_resolver=function|Mirrorvar->Call(mirrorvar)|Ct_check(expr,kind)->Call(ct_checkexprkind)|Se_check->Callse_check|_->Unknownletbuiltin_printerppf=function|Mirror{name;_}->Format.fprintfppf"secret mirror(%s)"name;true|Ct_check(expr,kind)->Format.fprintfppf"ct %a check(%a)"Kind.ppkindDba_printer.Ascii.pp_bl_termexpr;true|Se_check->Format.pp_print_stringppf"secret-erasure check";true|_->falseletat_exit_callback()=letl_insecure,_=addr_status_report()inletstatus=ifl_insecure<>[]||!se_insecure>0thenFalseelseifis_unknown_report()thenUnknownelseTrueinOption.iter(funfilename->lettoml_data=Toml.Min.of_key_values[(Toml.Min.key"CT report",Toml.Types.TTable(toml_ct_report()));(Toml.Min.key"Exploration",Toml.Types.TTable(Other_stats.to_toml()));]inletoc=open_out_binfilenameinletppf=Format.formatter_of_out_channelocinToml.Printer.tableppftoml_data;close_outoc)Options.stats_file;Logger.result"Program status is : %s (%0.3f)"(matchstatuswith|False->"insecure"|True->"secure"|Unknown->"unknown")(Other_stats.Timer.get());ifOptions.leak_info=InstrLeakthen(letpaths=Path_stats.getCompletedandstatic_instrs=Other_stats.Addresses.unique()inLogger.info"%d visited path%s covering %d instruction%s"paths(ifpaths>1then"s"else"")static_instrs(ifstatic_instrs>1then"s"else"");ifOptions.check_branchthenLogger.info"%d / %d control flow checks pass"!ct_cf_secure(!ct_cf_secure+!ct_cf_insecure+!ct_cf_unknown);ifOptions.check_memorythenLogger.info"%d / %d memory access checks pass"!ct_mem_secure(!ct_mem_secure+!ct_mem_insecure+!ct_mem_unknown);ifOptions.check_multthenLogger.info"%d / %d multiplication checks pass"!ct_mult_secure(!ct_mult_secure+!ct_mult_insecure+!ct_mult_unknown);ifOptions.check_dividend||Options.check_divisorthenLogger.info"%d / %d division checks pass"!ct_div_secure(!ct_div_secure+!ct_div_insecure+!ct_div_unknown);letse_checks=!se_secure+!se_insecure+!se_unknowninifse_checks>0thenLogger.info"%d / %d secret erasure checks pass"!se_securese_checks);ifis_unknown_report()thenLogger.warning"@[<v>Exploration is incomplete:%a@]"(funppf()->letpendings=Path_stats.getPendinginifpendings>0thenFormat.fprintfppf"@ - timeout has left (at least) %d pending paths (-sse-timeout)"pendings;letnon_exec=Path_stats.statusNon_executable_codeinifnon_exec>0thenFormat.fprintfppf"@ - %d paths fell into non executable code segments"non_exec;letmax_depth=Path_stats.statusMax_depthinifmax_depth>0thenFormat.fprintfppf"@ - %d paths have reached the maximal depth and have been cut \
(-sse-depth)"max_depth;letincomplete_enum=Path_stats.statusEnumeration_limitinifincomplete_enum>0thenFormat.fprintfppf"@ - some jump targets may have been omitted (-sse-jump-enum)";letunknown=Path_stats.statusUnresolved_formula+!ct_cf_unknown+!ct_mem_unknown+!se_unknowninifunknown>0thenFormat.fprintfppf"@ - %d SMT solver queries remain unsolved (-smt-timeout)"unknown)()letinstruction_printerppf=function|Secret(loc,_)->Format.fprintfppf"%a := secret"Ast.Loc.pploc;true|Se_check->Format.fprintfppf"check secret erasure";true|_->falseletdeclaration_printerppf=function|Globals(secret,names)->Format.fprintfppf"%s global %a"(ifsecretthen"secret"else"public")(Format.pp_print_list~pp_sep:(funppf()->Format.pp_print_stringppf", ")Format.pp_print_string)names;true|_->falseletlist:Path.textensionlist=[Grammar_extensiongrammar_extension;Command_handlercommand_callback;Command_printerdeclaration_printer;Instruction_resolverinstruction_callback;Instruction_printerinstruction_printer;Instrumentation_routineinstrumentation_routine;Builtin_resolverbuiltin_resolver;Builtin_printerbuiltin_printer;Fork_callback(funpathpath'->Path.setpath'key(Ct_state.fork(Path.getpathkey)));Exit_callbackat_exit_callback;]endmodulePlugin(O:OPTIONS):PLUGIN=structletname="checkct"letfields:(modulePATH)->fieldlist=fun_->[Field{id=Ct_state;default=Ct_state.empty();copy=None;merge=None;};]letextensions:typea.(moduleENGINEwithtypePath.t=a)->aextensionlist=funengine->letmoduleEngine=(valengine)inmatchEngine.Path.State.moreSymbolic.State.ValueKindwith|SomeSymbolic.Default.Term->letmoduleExtensions=Make(O)(Engine)inExtensions.list|Some_|None->Logger.fatal"unable to use 'checkct' within the current symbolic engine"end