123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295(**************************************************************************)(* *)(* SPDX-License-Identifier LGPL-2.1 *)(* Copyright (C) *)(* CEA (Commissariat à l'énergie atomique et aux énergies alternatives) *)(* *)(**************************************************************************)(** Server requests about taint analysis. *)openServeropenCil_typesletpackage=Package.package~plugin:"eva"~name:"taint"~title:"Taint Analysis"()(* ----- Taint names -------------------------------------------------------- *)let_signal=States.register_value~package~name:"taintNames"~descr:(Markdown.plain"List of taint names")~output:(moduleData.Jlist(Data.Jstring))~get:Taint_domain.taint_names~add_hook:Update.add_computation_hook()(* List of currently selected taints. *)moduleCurrentTaints=structmoduleInfo=structletname="Eva.Taint_requests.CurrentTaints"letdependencies=[Self.state]letdefault=Taint_domain.taint_namesendincludeState_builder.Ref(Datatype.List(Datatype.String))(Info)end(* At the end of an analysis, select all taint names by default. *)let()=Self.ComputationState.add_hook_on_change(fun_->CurrentTaints.set(Taint_domain.taint_names()))letcurrent_taint_signal=States.register_framac_state~package~name:"currentTaints"~descr:(Markdown.plain"Names of the currently selected taints, if any")~data:(moduleData.Jlist(Data.Jstring))(moduleCurrentTaints)(* Takes into account the currently selected taints. *)letis_taintedzonerequest=matchCurrentTaints.get()with|[]->OkResults.Untainted|names->Results.is_tainted~nameszonerequestlettaint_names_by_kindzonerequest=letopenOption.OperatorsinmatchCurrentTaints.get()with|[]->letempty=Datatype.String.Set.emptyinSomeResults.{direct_taint_names=empty;indirect_taint_names=empty}|current_names->let+names=Results.taint_names_by_kindzonerequest|>Result.to_optioninletselected=Datatype.String.Set.of_listcurrent_namesinletrestrict=Datatype.String.Set.interselectedinletdirect_taint_names=restrictnames.direct_taint_namesinletindirect_taint_names=restrictnames.indirect_taint_namesinResults.{direct_taint_names;indirect_taint_names}letregister_hookf=Update.add_hookf;CurrentTaints.add_hook_on_change(fun_->f())(* ----- Taint statuses ----------------------------------------------------- *)typetaint=Results.taint=Direct|Indirect|Untaintedtypeerror=NotComputed|Irrelevant|LogicErrormoduleTaintStatus=structopenServer.Dataletdictionary=Enum.dictionary()lettagvaluenamelabelshort_descrlong_descr=Enum.tag~name~label:(Markdown.plainlabel)~descr:(Markdown.bold(short_descr^": ")@Markdown.plainlong_descr)~valuedictionarylettag_not_computed=tag(ErrorNotComputed)"not_computed""""Not computed""the Eva taint domain has not been enabled, \
or the Eva analysis has not been run"lettag_error=tag(ErrorLogicError)"error""Error""Error""the memory zone on which this property depends could not be computed"lettag_not_applicable=tag(ErrorIrrelevant)"not_applicable""—""Not applicable""no taint for this kind of property"lettag_direct_taint=tag(OkDirect)"direct_taint""Tainted (direct)""Direct taint""this property is related to a memory location that can be affected \
by an attacker"lettag_indirect_taint=tag(OkIndirect)"indirect_taint""Tainted (indirect)""Indirect taint""this property is related to a memory location whose assignment depends \
on path conditions that can be affected by an attacker"lettag_untainted=tag(OkUntainted)"not_tainted""Untainted""Untainted property""this property is safe"let()=Enum.set_lookupdictionary@@function|ErrorNotComputed->tag_not_computed|ErrorIrrelevant->tag_not_applicable|ErrorLogicError->tag_error|OkDirect->tag_direct_taint|OkIndirect->tag_indirect_taint|OkUntainted->tag_untaintedletdata=Request.dictionary~package~name:"taintStatus"~descr:(Markdown.plain"Taint status of logical properties")dictionaryinclude(valdata:Swithtypet=(taint,error)result)end(* ----- Register Eva taints information ------------------------------------ *)letexpr_of_lvalv=Cil.new_exp~loc:Fileloc.unknown(Lvalv)letterm_lval_to_lvalkftlval=tryletresult=Option.bindEva_utils.find_return_varkfinLogic_to_c.term_lval_to_lval?resulttlvalwithLogic_to_c.No_conversion->raiseNot_foundmoduleEvaTaints=structletevaluateexprrequest=letopenOption.OperatorsinletDeps.{data}=Results.expr_dependenciesexprrequestinlet*taint=is_tainteddatarequest|>Result.to_optioninlet*names=taint_names_by_kinddatarequestinSome(taint,names)letexpr_of_marker=letopenPrinter_taginfunction|PLval(_,Kstmtstmt,lval)->Some(expr_of_lvallval,stmt)|PExp(_,Kstmtstmt,expr)->Some(expr,stmt)|PVDecl(_,Kstmtstmt,vi)->Some(expr_of_lval(Varvi,NoOffset),stmt)|PTermLval(kf,Kstmtstmt,_,tlval)->Some(term_lval_to_lvalkftlval|>expr_of_lval,stmt)|_->Noneletof_markermarker=letopenOption.Operatorsinlet*expr,stmt=expr_of_markermarkerinlet*before=evaluateexpr(Results.beforestmt)inlet*after=evaluateexpr(Results.afterstmt)inSome(before,after)letto_stringtaintResults.{direct_taint_names;indirect_taint_names}=matchtaintwith|Untainted->"untainted"|Indirect->Format.asprintf"indirect taint @[<h>%a@]"Datatype.String.Set.prettyindirect_taint_names|DirectwhenDatatype.String.Set.is_emptyindirect_taint_names->Format.asprintf"direct taint @[<h>%a@]"Datatype.String.Set.prettydirect_taint_names|Direct->Format.asprintf"direct taint @[<h>%a@], indirect taint @[<h>%a@]"Datatype.String.Set.prettydirect_taint_namesDatatype.String.Set.prettyindirect_taint_namesletppfmt=fun(taint,taint_names)->Format.fprintffmt"%s"(to_stringtainttaint_names)letprint_taintfmtmarker=matchof_markermarkerwith|None->raiseNot_found|Some(before,after)->ifbefore=afterthenFormat.fprintffmt"%a"ppbeforeelseFormat.fprintffmt"Before: %a@\nAfter: %a"ppbeforeppafterleteva_taints_descr="Taint status:\n\
- Direct taint: data dependency from values provided by the attacker, \
meaning that the attacker may be able to alter this value\n\
- Indirect taint: the attacker cannot directly alter this value, but he \
may be able to impact the path by which its value is computed.\n\
- Untainted: cannot be modified by the attacker."let()=lettaint_computed=Taint_domain.Store.is_computedinletenable()=Analysis.is_computed()&&taint_computed()inServer.Kernel_ast.Information.register~id:"eva.taint"~label:"Taint"~title:"Taint status according to Eva"~descr:eva_taints_descr~enableprint_taintlet()=CurrentTaints.add_hook_on_change(fun_->Server.Kernel_ast.Information.update())end(* ----- Tainted lvalues ---------------------------------------------------- *)moduleLvalueTaints=structmoduleTable=Cil_datatype.Lval.HashtblmoduleStatus=structtyperecordletrecord:recordData.Record.signature=Data.Record.signature()letfieldnamed=Data.Record.fieldrecord~name~descr:(Markdown.plaind)letlval_field=field"lval""tainted lvalue"(moduleKernel_ast.Lval)lettaint_field=field"taint""taint status"(moduleTaintStatus)letname,descr="LvalueTaints",Markdown.plain"Lvalue taint status"letpublication=Data.Record.publishrecord~package~name~descrinclude(valpublication:Data.Record.Swithtyper=record)letcreatelvaltaint=setlval_fieldlval@@settaint_fieldtaintdefaultendletcurrent_project()=Visitor_behavior.inplace()classtainted_lvaluestaints=object(self)inheritVisitor.generic_frama_c_visitor(current_project())method!vlvallval=letexpr=expr_of_lvallvalinmatchself#current_stmtwith|None->Cil.DoChildren|Somestmt->matchResults.afterstmt|>EvaTaints.evaluateexprwith|Some(Results.Untainted,_)->DoChildren|Some(t,_)->Table.addtaintslval(Kstmtstmt,t);Cil.DoChildren|None->Cil.DoChildrenendletget_tainted_lvalskf=tryletfn=Kernel_function.get_definitionkfinlettaints=Table.create17inVisitor.visitFramacFunction(newtainted_lvaluestaints)fn|>ignore;letfnlval(ki,taint)acc=Status.create(ki,lval)(Oktaint)::accinTable.foldfntaints[]|>List.revwithKernel_function.No_Definition->[]let()=Request.register~package~kind:`GET~name:"taintedLvalues"~descr:(Markdown.plain"Get the tainted lvalues of a given function")~input:(module(Kernel_ast.Decl))~output:(module(Data.Jlist(Status)))~signals:(current_taint_signal::Update.signals)(functionSFunctionkf->get_tainted_lvalskf|_->[])end(* ----- Tainted properties ------------------------------------------------- *)letzone_of_predicatekinstrpredicate=letstate=Results.(before_kinstrkinstr|>get_cvalue_model)inletenv=Eval_terms.env_only_herestateinletlogic_deps=Eval_terms.predicate_depsenvpredicateinmatchOption.mapCil_datatype.Logic_label.Map.bindingslogic_depswith|Some[BuiltinLabelHere,zone]->Okzone|_->ErrorLogicErrorletget_predicate=function|Property.IPCodeAnnotica->beginmatchica.ica_ca.annot_contentwith|AAssert(_,predicate)|AInvariant(_,_,predicate)->Okpredicate.tp_statement|_->ErrorIrrelevantend|IPPropertyInstance{ii_pred=None}->ErrorLogicError|IPPropertyInstance{ii_pred=Someip}->Okip.ip_content.tp_statement|_->ErrorIrrelevantletis_tainted_propertyip=ifAnalysis.is_computed()&&Taint_domain.Store.is_computed()thenlet(let+)=Result.bindinletkinstr=Property.get_kinstripinlet+predicate=get_predicateipinlet+zone=zone_of_predicatekinstrpredicateinletresult=Results.before_kinstrkinstr|>is_taintedzoneinResult.map_error(fun_->NotComputed)resultelseErrorNotComputed