Commit eaf51726 by Enkelmann Committed by Thomas Barabosch

Corrected dune linter warnings, linter warnings are now handled like errors. (#20)

parent 09f6dbb0
.PHONY: all clean test uninstall .PHONY: all clean test uninstall
all: all:
dune build --profile release dune build
dune install dune install
cd plugins/cwe_checker; make all; cd ../.. cd plugins/cwe_checker; make all; cd ../..
cd plugins/cwe_checker_emulation; make all; cd ../.. cd plugins/cwe_checker_emulation; make all; cd ../..
...@@ -8,7 +8,7 @@ all: ...@@ -8,7 +8,7 @@ all:
cd plugins/cwe_checker_type_inference_print; make all; cd ../.. cd plugins/cwe_checker_type_inference_print; make all; cd ../..
test: test:
dune runtest --profile release # TODO: correct all dune linter warnings so that we can remove --profile release dune runtest
cd test/artificial_samples; scons; cd ../.. cd test/artificial_samples; scons; cd ../..
pytest -v pytest -v
......
...@@ -52,7 +52,7 @@ If you plan to develop cwe_checker, it is recommended to build it using the prov ...@@ -52,7 +52,7 @@ If you plan to develop cwe_checker, it is recommended to build it using the prov
- Opam 2.0.2 - Opam 2.0.2
- dune >= 1.6 - dune >= 1.6
- BAP 1.6 (and its dependencies) - BAP 1.6 (and its dependencies)
- yojson >= 1.4.1 - yojson >= 1.6.0
- alcotest >= 0.8.3 - alcotest >= 0.8.3
- Sark (latest) for IDA Pro annotations - Sark (latest) for IDA Pro annotations
- pytest >= 3.5.1 - pytest >= 3.5.1
......
...@@ -14,7 +14,7 @@ dev-repo: "git+https://github.com/fkie-cad/cwe_checker" ...@@ -14,7 +14,7 @@ dev-repo: "git+https://github.com/fkie-cad/cwe_checker"
depends: [ depends: [
"ocaml" {>= "4.05"} "ocaml" {>= "4.05"}
"dune" {>= "1.6"} "dune" {>= "1.6"}
"yojson" {>= "1.4.1"} "yojson" {>= "1.6.0"}
"bap" {>= "1.6"} "bap" {>= "1.6"}
"alcotest" {>= "0.8.3"} "alcotest" {>= "0.8.3"}
"core_kernel" {>= "v0.11" & < "v0.12"} "core_kernel" {>= "v0.11" & < "v0.12"}
......
...@@ -57,13 +57,13 @@ let partial_run project config modules = ...@@ -57,13 +57,13 @@ let partial_run project config modules =
let tid_address_map = Address_translation.generate_tid_map program in let tid_address_map = Address_translation.generate_tid_map program in
let json = Yojson.Basic.from_file config in let json = Yojson.Basic.from_file config in
Log_utils.info "[cwe_checker] Just running the following analyses: %s." modules; Log_utils.info "[cwe_checker] Just running the following analyses: %s." modules;
List.iter (String.split modules ~on: ',') ~f:(fun cwe -> try List.iter (String.split modules ~on: ',') ~f:(fun cwe ->
begin let cwe_mod = match List.find known_modules ~f:(fun x -> x.name = cwe) with
let cwe_mod = List.find_exn known_modules ~f:(fun x -> x.name = cwe) in | Some(module_) -> module_
| None -> failwith "[CWE_CHECKER] Unknown CWE module" in
let program = Project.program project in let program = Project.program project in
execute_cwe_module cwe_mod json program project tid_address_map execute_cwe_module cwe_mod json program project tid_address_map
end )
with Not_found -> failwith "[CWE_CHECKER] Unknown CWE module")
let full_run project config = let full_run project config =
let program = Project.program project in let program = Project.program project in
......
...@@ -6,7 +6,7 @@ let (+), (-) = Bitvector.(+), Bitvector.(-) ...@@ -6,7 +6,7 @@ let (+), (-) = Bitvector.(+), Bitvector.(-)
let (>) x y = Bitvector.(>) (Bitvector.signed x) (Bitvector.signed y) let (>) x y = Bitvector.(>) (Bitvector.signed x) (Bitvector.signed y)
let (<) x y = Bitvector.(<) (Bitvector.signed x) (Bitvector.signed y) let (<) x y = Bitvector.(<) (Bitvector.signed x) (Bitvector.signed y)
let (>=) x y = Bitvector.(>=) (Bitvector.signed x) (Bitvector.signed y) (* let (>=) x y = Bitvector.(>=) (Bitvector.signed x) (Bitvector.signed y) *)
let (<=) x y = Bitvector.(<=) (Bitvector.signed x) (Bitvector.signed y) let (<=) x y = Bitvector.(<=) (Bitvector.signed x) (Bitvector.signed y)
let (=) x y = Bitvector.(=) x y let (=) x y = Bitvector.(=) x y
...@@ -74,16 +74,6 @@ let rec get mem_region pos = ...@@ -74,16 +74,6 @@ let rec get mem_region pos =
else else
Some(Error(())) (* pos intersects some data, but does not equal its starting address*) Some(Error(())) (* pos intersects some data, but does not equal its starting address*)
(* Helper function. Removes all elements with position <= pos. *)
let rec remove_until mem_region pos =
match mem_region with
| [] -> []
| hd :: tl ->
if hd.pos <= pos then
remove_until tl pos
else
mem_region
let rec remove mem_region ~pos ~size = let rec remove mem_region ~pos ~size =
let () = if pos + size < pos then failwith "[CWE-checker] element out of bounds for mem_region" in let () = if pos + size < pos then failwith "[CWE-checker] element out of bounds for mem_region" in
...@@ -91,11 +81,11 @@ let rec remove mem_region ~pos ~size = ...@@ -91,11 +81,11 @@ let rec remove mem_region ~pos ~size =
| [] -> [] | [] -> []
| hd :: tl -> | hd :: tl ->
if hd.pos + hd.size <= pos then if hd.pos + hd.size <= pos then
hd :: remove tl pos size hd :: remove tl ~pos ~size
else if pos + size <= hd.pos then else if pos + size <= hd.pos then
mem_region mem_region
else else
let mem_region = remove tl pos size in let mem_region = remove tl ~pos ~size in
let mem_region = let mem_region =
if hd.pos + hd.size > pos + size then if hd.pos + hd.size > pos + size then
error_elem ~pos:(pos + size) ~size:(hd.pos + hd.size - (pos + size)) :: mem_region error_elem ~pos:(pos + size) ~size:(hd.pos + hd.size - (pos + size)) :: mem_region
...@@ -111,12 +101,12 @@ let rec remove mem_region ~pos ~size = ...@@ -111,12 +101,12 @@ let rec remove mem_region ~pos ~size =
let rec mark_error mem_region ~pos ~size = let rec mark_error mem_region ~pos ~size =
let () = if pos + size < pos then failwith "[CWE-checker] element out of bounds for mem_region" in let () = if pos + size < pos then failwith "[CWE-checker] element out of bounds for mem_region" in
match mem_region with match mem_region with
| [] -> (error_elem pos size) :: [] | [] -> (error_elem ~pos ~size) :: []
| hd :: tl -> | hd :: tl ->
if hd.pos + hd.size <= pos then if hd.pos + hd.size <= pos then
hd :: (mark_error tl pos size) hd :: (mark_error tl ~pos ~size)
else if pos + size <= hd.pos then else if pos + size <= hd.pos then
(error_elem pos size) :: mem_region (error_elem ~pos ~size) :: mem_region
else else
let start_pos = min pos hd.pos in let start_pos = min pos hd.pos in
let end_pos_plus_one = max (pos + size) (hd.pos + hd.size) in let end_pos_plus_one = max (pos + size) (hd.pos + hd.size) in
...@@ -130,22 +120,22 @@ let rec merge mem_region1 mem_region2 ~data_merge = ...@@ -130,22 +120,22 @@ let rec merge mem_region1 mem_region2 ~data_merge =
| ([], value) -> value | ([], value) -> value
| (hd1 :: tl1, hd2 :: tl2) -> | (hd1 :: tl1, hd2 :: tl2) ->
if hd1.pos + hd1.size <= hd2.pos then if hd1.pos + hd1.size <= hd2.pos then
hd1 :: merge tl1 mem_region2 data_merge hd1 :: merge tl1 mem_region2 ~data_merge
else if hd2.pos + hd2.size <= hd1.pos then else if hd2.pos + hd2.size <= hd1.pos then
hd2 :: merge mem_region1 tl2 data_merge hd2 :: merge mem_region1 tl2 ~data_merge
else if hd1.pos = hd2.pos && hd1.size = hd2.size then else if hd1.pos = hd2.pos && hd1.size = hd2.size then
match (hd1.data, hd2.data) with match (hd1.data, hd2.data) with
| (Ok(data1), Ok(data2)) -> begin | (Ok(data1), Ok(data2)) -> begin
match data_merge data1 data2 with match data_merge data1 data2 with
| Some(Ok(value)) -> { hd1 with data = Ok(value) } :: merge tl1 tl2 ~data_merge | Some(Ok(value)) -> { hd1 with data = Ok(value) } :: merge tl1 tl2 ~data_merge
| Some(Error(_)) -> {hd1 with data = Error(())} :: merge tl1 tl2 ~data_merge | Some(Error(_)) -> {hd1 with data = Error(())} :: merge tl1 tl2 ~data_merge
| None -> merge tl1 tl2 data_merge | None -> merge tl1 tl2 ~data_merge
end end
| _ -> { hd1 with data = Error(()) } :: merge tl1 tl2 ~data_merge | _ -> { hd1 with data = Error(()) } :: merge tl1 tl2 ~data_merge
else else
let start_pos = min hd1.pos hd2.pos in let start_pos = min hd1.pos hd2.pos in
let end_pos_plus_one = max (hd1.pos + hd1.size) (hd2.pos + hd2.size) in let end_pos_plus_one = max (hd1.pos + hd1.size) (hd2.pos + hd2.size) in
let mem_region = merge tl1 tl2 data_merge in let mem_region = merge tl1 tl2 ~data_merge in
mark_error mem_region ~pos:start_pos ~size:(end_pos_plus_one - start_pos) mark_error mem_region ~pos:start_pos ~size:(end_pos_plus_one - start_pos)
...@@ -156,8 +146,8 @@ let rec equal (mem_region1:'a t) (mem_region2:'a t) ~data_equal : bool = ...@@ -156,8 +146,8 @@ let rec equal (mem_region1:'a t) (mem_region2:'a t) ~data_equal : bool =
if hd1.pos = hd2.pos && hd1.size = hd2.size then if hd1.pos = hd2.pos && hd1.size = hd2.size then
match (hd1.data, hd2.data) with match (hd1.data, hd2.data) with
| (Ok(data1), Ok(data2)) when data_equal data1 data2 -> | (Ok(data1), Ok(data2)) when data_equal data1 data2 ->
equal tl1 tl2 data_equal equal tl1 tl2 ~data_equal
| (Error(()), Error(())) -> equal tl1 tl2 data_equal | (Error(()), Error(())) -> equal tl1 tl2 ~data_equal
| _ -> false | _ -> false
else else
false false
......
...@@ -37,7 +37,7 @@ let binop_result_option val1 val2 ~op = ...@@ -37,7 +37,7 @@ let binop_result_option val1 val2 ~op =
(* generic merge of two ('a, unit) Result.t Map.t*) (* generic merge of two ('a, unit) Result.t Map.t*)
let merge_result_map val1 val2 ~value_merge = let merge_result_map val1 val2 ~value_merge =
Map.merge val1 val2 ~f:(fun ~key values -> Map.merge val1 val2 ~f:(fun ~key:_ values ->
match values with match values with
| `Left(x) | `Left(x)
| `Right(x) -> Some(x) | `Right(x) -> Some(x)
...@@ -78,7 +78,7 @@ module Register = struct ...@@ -78,7 +78,7 @@ module Register = struct
let merge reg1 reg2 = let merge reg1 reg2 =
match (reg1, reg2) with match (reg1, reg2) with
| (Pointer(target_info1), Pointer(target_info2)) -> | (Pointer(target_info1), Pointer(target_info2)) ->
Ok(Pointer(Map.merge target_info1 target_info2 ~f:(fun ~key values -> Ok(Pointer(Map.merge target_info1 target_info2 ~f:(fun ~key:_ values ->
match values with match values with
| `Left(info) | `Left(info)
| `Right(info) -> Some(info) | `Right(info) -> Some(info)
...@@ -118,7 +118,7 @@ module Register = struct ...@@ -118,7 +118,7 @@ module Register = struct
let set_unknown_offsets register = let set_unknown_offsets register =
match register with match register with
| Pointer(targets) -> | Pointer(targets) ->
let new_targets = Map.map targets ~f:(fun target -> { PointerTargetInfo.offset = None; alignment = None }) in let new_targets = Map.map targets ~f:(fun _target -> { PointerTargetInfo.offset = None; alignment = None }) in
Pointer(new_targets) Pointer(new_targets)
| Data -> Data | Data -> Data
...@@ -172,7 +172,7 @@ module TypeInfo = struct ...@@ -172,7 +172,7 @@ module TypeInfo = struct
| None -> None in | None -> None in
let stack_info = { PointerTargetInfo.offset = offset; alignment = alignment;} in let stack_info = { PointerTargetInfo.offset = offset; alignment = alignment;} in
let stack_target_map = Map.set Tid.Map.empty ~key:sub_tid ~data:stack_info in let stack_target_map = Map.set Tid.Map.empty ~key:sub_tid ~data:stack_info in
{ state with reg = Map.set state.reg stack_register (Ok(Register.Pointer(stack_target_map))); } { state with reg = Map.set state.reg ~key:stack_register ~data:(Ok(Register.Pointer(stack_target_map))); }
(** Returns a TypeInfo.t with only the stack pointer as pointer register (with (** Returns a TypeInfo.t with only the stack pointer as pointer register (with
unknown offset) and only the flag registers as data registers. The stack is empty. *) unknown offset) and only the flag registers as data registers. The stack is empty. *)
...@@ -196,19 +196,6 @@ module TypeInfo = struct ...@@ -196,19 +196,6 @@ module TypeInfo = struct
let remove_virtual_registers state = let remove_virtual_registers state =
{ state with reg = Map.filter_keys state.reg ~f:(fun var -> Var.is_physical var) } { state with reg = Map.filter_keys state.reg ~f:(fun var -> Var.is_physical var) }
(** udate offsets of all possible targets of the register by adding the given value *)
(* TODO: also implement correct offset for AND and OR if the alignment is known *)
let register_offset_add state register (value:Bitvector.t) =
match Map.find state.reg register with
| Some(Ok(Pointer(targets))) ->
let updated_targets = Map.map targets ~f:(fun type_info ->
match type_info.offset with
| Some(Ok(x)) -> { type_info with offset = Some(Ok(Bitvector.(+) x value ))}
| _ -> type_info
) in
{ state with reg = Map.set state.reg ~key:register ~data:(Ok(Pointer(updated_targets))) }
| _ -> state
(** if the addr_exp is a (computable) stack offset, return the offset. In cases where addr_expr (** if the addr_exp is a (computable) stack offset, return the offset. In cases where addr_expr
may or may not be a stack offset (i.e. offset of a register which may point to the stack or may or may not be a stack offset (i.e. offset of a register which may point to the stack or
to some other memory region), it still returns an offset. *) to some other memory region), it still returns an offset. *)
...@@ -251,8 +238,8 @@ let rec nested_exp_list exp : Exp.t list = ...@@ -251,8 +238,8 @@ let rec nested_exp_list exp : Exp.t list =
let nested_exp = match exp with let nested_exp = match exp with
| Bil.Load(exp1, exp2, _, _) -> exp :: (nested_exp_list exp1) @ (nested_exp_list exp2) | Bil.Load(exp1, exp2, _, _) -> exp :: (nested_exp_list exp1) @ (nested_exp_list exp2)
| Bil.Store(exp1, exp2, exp3, _, _) -> nested_exp_list exp1 @ nested_exp_list exp2 @ nested_exp_list exp3 | Bil.Store(exp1, exp2, exp3, _, _) -> nested_exp_list exp1 @ nested_exp_list exp2 @ nested_exp_list exp3
| Bil.BinOp(op, exp1, exp2) -> nested_exp_list exp1 @ nested_exp_list exp2 | Bil.BinOp(_op, exp1, exp2) -> nested_exp_list exp1 @ nested_exp_list exp2
| Bil.UnOp(op, exp1) -> nested_exp_list exp1 | Bil.UnOp(_op, exp1) -> nested_exp_list exp1
| Bil.Var(_) -> [] | Bil.Var(_) -> []
| Bil.Int(_) -> [] | Bil.Int(_) -> []
| Bil.Cast(_, _, exp1) -> nested_exp_list exp1 | Bil.Cast(_, _, exp1) -> nested_exp_list exp1
...@@ -270,8 +257,8 @@ let rec nested_exp_list exp : Exp.t list = ...@@ -270,8 +257,8 @@ let rec nested_exp_list exp : Exp.t list =
TODO: Bil.AND and Bil.OR are ignored, because we do not track alignment yet. *) TODO: Bil.AND and Bil.OR are ignored, because we do not track alignment yet. *)
let get_stack_elem state exp ~sub_tid ~project = let get_stack_elem state exp ~sub_tid ~project =
match exp with match exp with
| Bil.Load(_, addr, endian, size) -> begin (* TODO: add a test for correct endianess *) | Bil.Load(_, addr, _endian, size) -> begin (* TODO: add a test for correct endianess *)
match TypeInfo.compute_stack_offset state addr sub_tid project with match TypeInfo.compute_stack_offset state addr ~sub_tid ~project with
| Some(offset) -> begin | Some(offset) -> begin
match Mem_region.get state.TypeInfo.stack offset with match Mem_region.get state.TypeInfo.stack offset with
| Some(Ok(elem, elem_size)) -> | Some(Ok(elem, elem_size)) ->
...@@ -301,26 +288,26 @@ let rec type_of_exp exp (state: TypeInfo.t) ~sub_tid ~project = ...@@ -301,26 +288,26 @@ let rec type_of_exp exp (state: TypeInfo.t) ~sub_tid ~project =
get_stack_elem state exp ~sub_tid ~project get_stack_elem state exp ~sub_tid ~project
| Bil.Store(_) -> None (* Stores are handled in another function. *) | Bil.Store(_) -> None (* Stores are handled in another function. *)
| Bil.BinOp(binop, exp1, exp2) -> begin | Bil.BinOp(binop, exp1, exp2) -> begin
match (binop, type_of_exp exp1 state sub_tid project, type_of_exp exp2 state sub_tid project) with match (binop, type_of_exp exp1 state ~sub_tid ~project, type_of_exp exp2 state ~sub_tid ~project) with
(* pointer arithmetics *) (* pointer arithmetics *)
| (Bil.PLUS, Some(Ok(Pointer(_))), Some(Ok(Pointer(_)))) -> Some(Error(())) | (Bil.PLUS, Some(Ok(Pointer(_))), Some(Ok(Pointer(_)))) -> Some(Error(()))
| (Bil.PLUS, Some(Ok(Pointer(targets))), summand) -> Some(Ok(Register.add_to_offsets (Pointer(targets)) (value_of_exp exp2))) | (Bil.PLUS, Some(Ok(Pointer(targets))), _summand) -> Some(Ok(Register.add_to_offsets (Pointer(targets)) (value_of_exp exp2)))
| (Bil.PLUS, summand, Some(Ok(Pointer(targets)))) -> Some(Ok(Register.add_to_offsets (Pointer(targets)) (value_of_exp exp1))) | (Bil.PLUS, _summand, Some(Ok(Pointer(targets)))) -> Some(Ok(Register.add_to_offsets (Pointer(targets)) (value_of_exp exp1)))
| (Bil.PLUS, Some(Ok(Data)), Some(Ok(Data))) -> Some(Ok(Data)) | (Bil.PLUS, Some(Ok(Data)), Some(Ok(Data))) -> Some(Ok(Data))
| (Bil.PLUS, _, _) -> None | (Bil.PLUS, _, _) -> None
| (Bil.MINUS, Some(Ok(Pointer(_))), Some(Ok(Pointer(_)))) -> Some(Ok(Data)) (* Pointer subtraction to determine offset is CWE-469, this should be logged. *) | (Bil.MINUS, Some(Ok(Pointer(_))), Some(Ok(Pointer(_)))) -> Some(Ok(Data)) (* Pointer subtraction to determine offset is CWE-469, this should be logged. *)
| (Bil.MINUS, Some(Ok(Pointer(targets))), other) -> Some(Ok(Register.sub_from_offsets (Pointer(targets)) (value_of_exp exp2))) (* We assume that other is not a pointer. This can only generate errors in the presence of CWE-469 *) | (Bil.MINUS, Some(Ok(Pointer(targets))), _other) -> Some(Ok(Register.sub_from_offsets (Pointer(targets)) (value_of_exp exp2))) (* We assume that other is not a pointer. This can only generate errors in the presence of CWE-469 *)
| (Bil.MINUS, Some(Ok(Data)), Some(Ok(Data))) -> Some(Ok(Data)) | (Bil.MINUS, Some(Ok(Data)), Some(Ok(Data))) -> Some(Ok(Data))
| (Bil.MINUS, _, _) -> None | (Bil.MINUS, _, _) -> None
(* bitwise AND and OR can be used as addition and subtraction if some alignment of the pointer is known *) (* bitwise AND and OR can be used as addition and subtraction if some alignment of the pointer is known *)
| (Bil.AND, Some(Ok(Pointer(_))), Some(Ok(Pointer(_)))) -> Some(Error(())) (* TODO: This could be a pointer, but is there any case where this is used in practice? *) | (Bil.AND, Some(Ok(Pointer(_))), Some(Ok(Pointer(_)))) -> Some(Error(())) (* TODO: This could be a pointer, but is there any case where this is used in practice? *)
| (Bil.AND, Some(Ok(Pointer(targets))), other) | (Bil.AND, Some(Ok(Pointer(targets))), _other)
| (Bil.AND, other, Some(Ok(Pointer(targets)))) -> Some(Ok(Register.set_unknown_offsets (Pointer(targets)))) | (Bil.AND, _other, Some(Ok(Pointer(targets)))) -> Some(Ok(Register.set_unknown_offsets (Pointer(targets))))
| (Bil.AND, Some(Ok(Data)), Some(Ok(Data))) -> Some(Ok(Data)) | (Bil.AND, Some(Ok(Data)), Some(Ok(Data))) -> Some(Ok(Data))
| (Bil.AND, _, _) -> None | (Bil.AND, _, _) -> None
| (Bil.OR, Some(Ok(Pointer(_))), Some(Ok(Pointer(_)))) -> Some(Error(())) (* TODO: This could be a pointer, but is there any case where this is used in practice? *) | (Bil.OR, Some(Ok(Pointer(_))), Some(Ok(Pointer(_)))) -> Some(Error(())) (* TODO: This could be a pointer, but is there any case where this is used in practice? *)
| (Bil.OR, Some(Ok(Pointer(targets))), other) | (Bil.OR, Some(Ok(Pointer(targets))), _other)
| (Bil.OR, other, Some(Ok(Pointer(targets)))) -> Some(Ok(Register.set_unknown_offsets (Pointer(targets)))) | (Bil.OR, _other, Some(Ok(Pointer(targets)))) -> Some(Ok(Register.set_unknown_offsets (Pointer(targets))))
| (Bil.OR, Some(Ok(Data)), Some(Ok(Data))) -> Some(Ok(Data)) | (Bil.OR, Some(Ok(Data)), Some(Ok(Data))) -> Some(Ok(Data))
| (Bil.OR, _, _) -> None | (Bil.OR, _, _) -> None
| _ -> Some(Ok(Data)) (* every other operation should not yield valid pointers *) | _ -> Some(Ok(Data)) (* every other operation should not yield valid pointers *)
...@@ -330,11 +317,11 @@ let rec type_of_exp exp (state: TypeInfo.t) ~sub_tid ~project = ...@@ -330,11 +317,11 @@ let rec type_of_exp exp (state: TypeInfo.t) ~sub_tid ~project =
| Bil.Int(_) -> None (* TODO: For non-relocateable binaries this could be a pointer to a function/global variable *) | Bil.Int(_) -> None (* TODO: For non-relocateable binaries this could be a pointer to a function/global variable *)
| Bil.Cast(Bil.SIGNED, _, _) -> Some(Ok(Data)) | Bil.Cast(Bil.SIGNED, _, _) -> Some(Ok(Data))
| Bil.Cast(_, size, exp) -> | Bil.Cast(_, size, exp) ->
if size = (Symbol_utils.arch_pointer_size_in_bytes project * 8) then type_of_exp exp state sub_tid project else Some(Ok(Data)) (* TODO: There is probably a special case when 64bit addresses are converted to 32bit addresses here, which can yield pointers *) if size = (Symbol_utils.arch_pointer_size_in_bytes project * 8) then type_of_exp exp state ~sub_tid ~project else Some(Ok(Data)) (* TODO: There is probably a special case when 64bit addresses are converted to 32bit addresses here, which can yield pointers *)
| Bil.Let(_) -> None | Bil.Let(_) -> None
| Bil.Unknown(_) -> None | Bil.Unknown(_) -> None
| Bil.Ite(if_, then_, else_) -> begin | Bil.Ite(_if_, then_, else_) -> begin
match (type_of_exp then_ state sub_tid project, type_of_exp else_ state sub_tid project) with match (type_of_exp then_ state ~sub_tid ~project, type_of_exp else_ state ~sub_tid ~project) with
| (Some(value1), Some(value2)) -> if value1 = value2 then Some(value1) else None | (Some(value1), Some(value2)) -> if value1 = value2 then Some(value1) else None
| _ -> None | _ -> None
end end
...@@ -352,7 +339,7 @@ let pointer_size_as_bitvector project = ...@@ -352,7 +339,7 @@ let pointer_size_as_bitvector project =
is unclear, whether it really was a store onto the stack or to somewhere else. *) is unclear, whether it really was a store onto the stack or to somewhere else. *)
let set_stack_elem state exp ~sub_tid ~project = let set_stack_elem state exp ~sub_tid ~project =
match exp with match exp with
| Bil.Store(_, addr_exp, value_exp, endian, size) -> | Bil.Store(_, addr_exp, value_exp, _endian, size) ->
let stack_offset = TypeInfo.compute_stack_offset state addr_exp ~sub_tid ~project in let stack_offset = TypeInfo.compute_stack_offset state addr_exp ~sub_tid ~project in
let value = type_of_exp value_exp state ~sub_tid ~project in let value = type_of_exp value_exp state ~sub_tid ~project in
let addr_type = type_of_exp addr_exp state ~sub_tid ~project in let addr_type = type_of_exp addr_exp state ~sub_tid ~project in
...@@ -406,7 +393,7 @@ let add_mem_address_registers state exp ~sub_tid ~project = ...@@ -406,7 +393,7 @@ let add_mem_address_registers state exp ~sub_tid ~project =
| Bil.BinOp(Bil.OR, Bil.Int(_), Bil.Var(addr)) -> | Bil.BinOp(Bil.OR, Bil.Int(_), Bil.Var(addr)) ->
begin match Map.find state.TypeInfo.reg addr with begin match Map.find state.TypeInfo.reg addr with
| Some(Ok(Pointer(_))) -> state | Some(Ok(Pointer(_))) -> state
| _ -> { state with TypeInfo.reg = Map.set state.TypeInfo.reg addr (Ok(Register.Pointer(Tid.Map.empty))) } (* TODO: there are some false positives here for indices in global data arrays, where the immediate is the pointer. Maybe remove all cases with potential false positives? *) | _ -> { state with TypeInfo.reg = Map.set state.TypeInfo.reg ~key:addr ~data:(Ok(Register.Pointer(Tid.Map.empty))) } (* TODO: there are some false positives here for indices in global data arrays, where the immediate is the pointer. Maybe remove all cases with potential false positives? *)
end end
| Bil.BinOp(Bil.PLUS, Bil.Var(addr), exp2) | Bil.BinOp(Bil.PLUS, Bil.Var(addr), exp2)
| Bil.BinOp(Bil.PLUS, exp2, Bil.Var(addr)) | Bil.BinOp(Bil.PLUS, exp2, Bil.Var(addr))
...@@ -415,10 +402,10 @@ let add_mem_address_registers state exp ~sub_tid ~project = ...@@ -415,10 +402,10 @@ let add_mem_address_registers state exp ~sub_tid ~project =
| Bil.BinOp(Bil.AND, exp2, Bil.Var(addr)) | Bil.BinOp(Bil.AND, exp2, Bil.Var(addr))
| Bil.BinOp(Bil.OR, Bil.Var(addr), exp2) | Bil.BinOp(Bil.OR, Bil.Var(addr), exp2)
| Bil.BinOp(Bil.OR, exp2, Bil.Var(addr)) -> | Bil.BinOp(Bil.OR, exp2, Bil.Var(addr)) ->
if type_of_exp exp2 state sub_tid project = Some(Ok(Register.Data)) then if type_of_exp exp2 state ~sub_tid ~project = Some(Ok(Register.Data)) then
begin match Map.find state.TypeInfo.reg addr with begin match Map.find state.TypeInfo.reg addr with
| Some(Ok(Pointer(_))) -> state | Some(Ok(Pointer(_))) -> state
| _ -> { state with TypeInfo.reg = Map.set state.TypeInfo.reg addr (Ok(Register.Pointer(Tid.Map.empty))) } | _ -> { state with TypeInfo.reg = Map.set state.TypeInfo.reg ~key:addr ~data:(Ok(Register.Pointer(Tid.Map.empty))) }
end end
else else
state state
...@@ -433,16 +420,16 @@ let keep_only_stack_register state ~sub_tid ~project = ...@@ -433,16 +420,16 @@ let keep_only_stack_register state ~sub_tid ~project =
let stack_pointer_value = Map.find state.TypeInfo.reg (Symbol_utils.stack_register project) in let stack_pointer_value = Map.find state.TypeInfo.reg (Symbol_utils.stack_register project) in
let new_state = TypeInfo.only_stack_pointer_and_flags sub_tid project in let new_state = TypeInfo.only_stack_pointer_and_flags sub_tid project in
match stack_pointer_value with match stack_pointer_value with
| Some(value) -> { new_state with TypeInfo.reg = Map.set state.reg (Symbol_utils.stack_register project) value } | Some(value) -> { new_state with TypeInfo.reg = Map.set state.reg ~key:(Symbol_utils.stack_register project) ~data:value }
| None -> new_state | None -> new_state
let update_state_def state def ~sub_tid ~project = let update_state_def state def ~sub_tid ~project =
(* add all registers that are used as address registers in load/store expressions to the state *) (* add all registers that are used as address registers in load/store expressions to the state *)
let state = add_mem_address_registers state (Def.rhs def) sub_tid project in let state = add_mem_address_registers state (Def.rhs def) ~sub_tid ~project in
(* update the lhs of the definition with its new type *) (* update the lhs of the definition with its new type *)
let state = match type_of_exp (Def.rhs def) state sub_tid project with let state = match type_of_exp (Def.rhs def) state ~sub_tid ~project with
| Some(value) -> | Some(value) ->
let reg = Map.set state.TypeInfo.reg (Def.lhs def) value in let reg = Map.set state.TypeInfo.reg ~key:(Def.lhs def) ~data:value in
{ state with TypeInfo.reg = reg } { state with TypeInfo.reg = reg }
| None -> (* We don't know the type of the new value *) | None -> (* We don't know the type of the new value *)
let reg = Map.remove state.TypeInfo.reg (Def.lhs def) in let reg = Map.remove state.TypeInfo.reg (Def.lhs def) in
...@@ -490,7 +477,7 @@ let update_state_malloc_call state malloc_like_tid jmp_term ~project = ...@@ -490,7 +477,7 @@ let update_state_malloc_call state malloc_like_tid jmp_term ~project =
let return_reg = match Bap.Std.Arg.rhs return_arg with let return_reg = match Bap.Std.Arg.rhs return_arg with
| Bil.Var(var) -> var | Bil.Var(var) -> var
| _ -> failwith "[CWE-checker] Return register of malloc-like function wasn't a register." in | _ -> failwith "[CWE-checker] Return register of malloc-like function wasn't a register." in
let target_map = Map.set Tid.Map.empty (Term.tid jmp_term) { PointerTargetInfo.offset = Some(Ok(Bitvector.of_int 0 ~width:(Symbol_utils.arch_pointer_size_in_bytes project * 8))); alignment = None} in let target_map = Map.set Tid.Map.empty ~key:(Term.tid jmp_term) ~data:{ PointerTargetInfo.offset = Some(Ok(Bitvector.of_int 0 ~width:(Symbol_utils.arch_pointer_size_in_bytes project * 8))); alignment = None} in
{ state with TypeInfo.reg = Var.Map.set state.reg ~key:return_reg ~data:(Ok(Pointer(target_map))) } { state with TypeInfo.reg = Var.Map.set state.reg ~key:return_reg ~data:(Ok(Pointer(target_map))) }
...@@ -508,25 +495,25 @@ let update_state_jmp state jmp ~sub_tid ~project = ...@@ -508,25 +495,25 @@ let update_state_jmp state jmp ~sub_tid ~project =
| None -> Tid.name tid in | None -> Tid.name tid in
if String.Set.mem (Cconv.parse_dyn_syms project) func_name then if String.Set.mem (Cconv.parse_dyn_syms project) func_name then
begin if List.exists (malloc_like_function_list ()) ~f:(fun elem -> elem = func_name) then begin if List.exists (malloc_like_function_list ()) ~f:(fun elem -> elem = func_name) then
update_state_malloc_call state tid jmp project update_state_malloc_call state tid jmp ~project
else else
let empty_state = TypeInfo.empty () in (* TODO: to preserve stack information we need to be sure that the callee does not write on the stack. Can we already check that? *) let empty_state = TypeInfo.empty () in (* TODO: to preserve stack information we need to be sure that the callee does not write on the stack. Can we already check that? *)
{ empty_state with { empty_state with
TypeInfo.reg = Var.Map.filter_keys state.TypeInfo.reg ~f:(fun var -> Cconv.is_callee_saved var project) } TypeInfo.reg = Var.Map.filter_keys state.TypeInfo.reg ~f:(fun var -> Cconv.is_callee_saved var project) }
end end
else else
keep_only_stack_register state sub_tid project (* TODO: add interprocedural analysis here. *) keep_only_stack_register state ~sub_tid ~project (* TODO: add interprocedural analysis here. *)
| Indirect(_) -> keep_only_stack_register state sub_tid project in (* TODO: when we have value tracking and interprocedural analysis, we can add indirect calls to the regular analysis. *) | Indirect(_) -> keep_only_stack_register state ~sub_tid ~project in (* TODO: when we have value tracking and interprocedural analysis, we can add indirect calls to the regular analysis. *)
(* The callee is responsible for removing the return address from the stack, so we have to adjust the stack offset accordingly. *) (* The callee is responsible for removing the return address from the stack, so we have to adjust the stack offset accordingly. *)
(* TODO: x86/x64, arm, mips and ppc all use descending stacks and we assume here that a descending stack is used. Can this be checked by some info given from bap? Is there an architecture with an upward growing stack? *) (* TODO: x86/x64, arm, mips and ppc all use descending stacks and we assume here that a descending stack is used. Can this be checked by some info given from bap? Is there an architecture with an upward growing stack? *)
add_to_stack_offset return_state (Symbol_utils.arch_pointer_size_in_bytes project) project add_to_stack_offset return_state (Symbol_utils.arch_pointer_size_in_bytes project) ~project
| Int(_, _) -> (* TODO: We need stubs and/or interprocedural analysis here *) | Int(_, _) -> (* TODO: We need stubs and/or interprocedural analysis here *)
keep_only_stack_register state sub_tid project (* TODO: Are there cases where the stack offset has to be adjusted here? *) keep_only_stack_register state ~sub_tid ~project (* TODO: Are there cases where the stack offset has to be adjusted here? *)
| Goto(Indirect(Bil.Var(var))) (* TODO: warn when jumping to something that is marked as data. *) | Goto(Indirect(Bil.Var(var))) (* TODO: warn when jumping to something that is marked as data. *)
| Ret(Indirect(Bil.Var(var))) -> | Ret(Indirect(Bil.Var(var))) ->
begin match Map.find state.TypeInfo.reg var with begin match Map.find state.TypeInfo.reg var with
| Some(Ok(Pointer(_))) -> state | Some(Ok(Pointer(_))) -> state
| _ -> { state with TypeInfo.reg = Map.set state.TypeInfo.reg var (Ok(Register.Pointer(Tid.Map.empty))) } | _ -> { state with TypeInfo.reg = Map.set state.TypeInfo.reg ~key:var ~data:(Ok(Register.Pointer(Tid.Map.empty))) }
end end
| Goto(_) | Goto(_)
| Ret(_) -> state | Ret(_) -> state
...@@ -535,7 +522,7 @@ let update_state_jmp state jmp ~sub_tid ~project = ...@@ -535,7 +522,7 @@ let update_state_jmp state jmp ~sub_tid ~project =
let update_type_info block_elem state ~sub_tid ~project = let update_type_info block_elem state ~sub_tid ~project =
match block_elem with match block_elem with
| `Def def -> update_state_def state def ~sub_tid ~project | `Def def -> update_state_def state def ~sub_tid ~project
| `Phi phi -> state (* We ignore phi terms for this analysis. *) | `Phi _phi -> state (* We ignore phi terms for this analysis. *)
| `Jmp jmp -> update_state_jmp state jmp ~sub_tid ~project | `Jmp jmp -> update_state_jmp state jmp ~sub_tid ~project
(** updates a block analysis. *) (** updates a block analysis. *)
...@@ -560,7 +547,7 @@ let intraprocedural_fixpoint func ~project = ...@@ -560,7 +547,7 @@ let intraprocedural_fixpoint func ~project =
let fn_start_state = update_block_analysis fn_start_block fn_start_state ~sub_tid ~project in let fn_start_state = update_block_analysis fn_start_block fn_start_state ~sub_tid ~project in
let fn_start_node = Seq.find_exn (Graphs.Ir.nodes cfg) ~f:(fun node -> (Term.tid fn_start_block) = (Term.tid (Graphs.Ir.Node.label node))) in let fn_start_node = Seq.find_exn (Graphs.Ir.nodes cfg) ~f:(fun node -> (Term.tid fn_start_block) = (Term.tid (Graphs.Ir.Node.label node))) in
let empty = Map.empty (module Graphs.Ir.Node) in let empty = Map.empty (module Graphs.Ir.Node) in
let with_start_node = Map.set empty fn_start_node fn_start_state in let with_start_node = Map.set empty ~key:fn_start_node ~data:fn_start_state in
let init = Graphlib.Std.Solution.create with_start_node only_sp in let init = Graphlib.Std.Solution.create with_start_node only_sp in
let equal = TypeInfo.equal in let equal = TypeInfo.equal in
let merge = TypeInfo.merge in let merge = TypeInfo.merge in
...@@ -585,28 +572,16 @@ let extract_start_state node ~cfg ~solution ~sub_tid ~project = ...@@ -585,28 +572,16 @@ let extract_start_state node ~cfg ~solution ~sub_tid ~project =
TypeInfo.merge state (Graphlib.Std.Solution.get solution node) TypeInfo.merge state (Graphlib.Std.Solution.get solution node)
) )
(** Returns a list of pairs (tid, state) for each def in a (blk_t-)node. The state
is the state _after execution of the node. *)
let state_list_def node ~cfg ~solution ~sub_tid ~project =
let input_state = extract_start_state node ~cfg ~solution ~sub_tid ~project in
let block = Graphs.Ir.Node.label node in
let defs = Term.enum def_t block in
let (output, _) = Seq.fold defs ~init:([], input_state) ~f:(fun (list_, state) def ->
let state = update_state_def state def sub_tid project in
( (Term.tid def, state) :: list_, state)
) in
output
let compute_pointer_register project = let compute_pointer_register project =
let program = Project.program project in let program = Project.program project in
let program_with_tags = Term.map sub_t program ~f:(fun func -> let program_with_tags = Term.map sub_t program ~f:(fun func ->
let cfg = Sub.to_cfg func in let cfg = Sub.to_cfg func in
let sub_tid = Term.tid func in let sub_tid = Term.tid func in
let solution = intraprocedural_fixpoint func project in let solution = intraprocedural_fixpoint func ~project in
Seq.fold (Graphs.Ir.nodes cfg) ~init:func ~f:(fun func node -> Seq.fold (Graphs.Ir.nodes cfg) ~init:func ~f:(fun func node ->
let block = Graphs.Ir.Node.label node in let block = Graphs.Ir.Node.label node in
let start_state = extract_start_state node cfg solution sub_tid project in let start_state = extract_start_state node ~cfg ~solution ~sub_tid ~project in
let tagged_block = Term.set_attr block type_info_tag start_state in let tagged_block = Term.set_attr block type_info_tag start_state in
Term.update blk_t func tagged_block Term.update blk_t func tagged_block
) )
...@@ -619,7 +594,7 @@ let print_type_info_to_debug state block_tid ~tid_map ~sub_tid ~project = ...@@ -619,7 +594,7 @@ let print_type_info_to_debug state block_tid ~tid_map ~sub_tid ~project =
match reg with match reg with
| Ok(Register.Pointer(targets)) -> | Ok(Register.Pointer(targets)) ->
(Var.name var ^ ":Pointer(targets: " ^ (Var.name var ^ ":Pointer(targets: " ^
(Map.fold targets ~init:"" ~f:(fun ~key ~data accum_string -> (Tid.name key) ^ "," ^ accum_string)) ^ (Map.fold targets ~init:"" ~f:(fun ~key ~data:_ accum_string -> (Tid.name key) ^ "," ^ accum_string)) ^
")") :: str_list ")") :: str_list
| Ok(Register.Data) -> (Var.name var ^ ":Data, ") :: str_list | Ok(Register.Data) -> (Var.name var ^ ":Data, ") :: str_list
| Error(_) -> (Var.name var ^ ":Error, ") :: str_list ) in | Error(_) -> (Var.name var ^ ":Error, ") :: str_list ) in
......
...@@ -7,7 +7,7 @@ let version = "0.1" ...@@ -7,7 +7,7 @@ let version = "0.1"
let collect_muliplications = Exp.fold ~init:0 (object let collect_muliplications = Exp.fold ~init:0 (object
inherit [Int.t] Exp.visitor inherit [Int.t] Exp.visitor
method! enter_binop op o1 o2 binops = match op with method! enter_binop op _o1 _o2 binops = match op with
| Bil.TIMES | Bil.LSHIFT -> binops + 1 | Bil.TIMES | Bil.LSHIFT -> binops + 1
| _ -> binops | _ -> binops
end) end)
...@@ -17,7 +17,7 @@ let contains_multiplication d = ...@@ -17,7 +17,7 @@ let contains_multiplication d =
let binops = collect_muliplications rhs in let binops = collect_muliplications rhs in
binops > 0 binops > 0
let check_multiplication_before_symbol proj prog sub blk jmp tid_map symbols = let check_multiplication_before_symbol _proj _prog _sub blk jmp tid_map symbols =
Seq.iter (Term.enum def_t blk) Seq.iter (Term.enum def_t blk)
~f:(fun d -> if contains_multiplication d then ~f:(fun d -> if contains_multiplication d then
Log_utils.warn Log_utils.warn
......
open Core_kernel open Core_kernel
open Bap.Std open Bap.Std
open Unix
(* TODO: IVG via gitter: (* TODO: IVG via gitter:
I see, so you need the CU information, and yes BAP doesn't provide this. I see, so you need the CU information, and yes BAP doesn't provide this.
...@@ -19,16 +19,6 @@ but in general case it is better to use the approach described above. *) ...@@ -19,16 +19,6 @@ but in general case it is better to use the approach described above. *)
let name = "CWE215" let name = "CWE215"
let version = "0.1" let version = "0.1"
let read_lines in_chan =
let lines = ref [] in
try
while true; do
lines := input_line in_chan :: !lines
done; !lines
with End_of_file ->
In_channel.close in_chan;
List.rev !lines
(* TODO: check if program contains strings like "DEBUG"*) (* TODO: check if program contains strings like "DEBUG"*)
let check_cwe _ project _ _ _ = let check_cwe _ project _ _ _ =
match Project.get project filename with match Project.get project filename with
...@@ -36,7 +26,7 @@ let check_cwe _ project _ _ _ = ...@@ -36,7 +26,7 @@ let check_cwe _ project _ _ _ =
let cmd = Format.sprintf "readelf --debug-dump=decodedline %s | grep CU" fname in let cmd = Format.sprintf "readelf --debug-dump=decodedline %s | grep CU" fname in
try try
let in_chan = Unix.open_process_in cmd in let in_chan = Unix.open_process_in cmd in
read_lines in_chan |> List.iter ~f:(fun l -> Log_utils.warn "[%s] {%s} (Information Exposure Through Debug Information) %s" name version l) In_channel.input_lines in_chan |> List.iter ~f:(fun l -> Log_utils.warn "[%s] {%s} (Information Exposure Through Debug Information) %s" name version l)
with with
Unix.Unix_error (e,fm,argm) -> Unix.Unix_error (e,fm,argm) ->
Log_utils.error "[%s] {%s} %s %s %s" name version (Unix.error_message e) fm argm Log_utils.error "[%s] {%s} %s %s %s" name version (Unix.error_message e) fm argm
......
...@@ -50,7 +50,7 @@ let check_route sub symbols = ...@@ -50,7 +50,7 @@ let check_route sub symbols =
if res then res else res if res then res else res
(** Checks one possible valid path (combination of APIs) of chroot. *) (** Checks one possible valid path (combination of APIs) of chroot. *)
let check_path prog tid_map sub path = let check_path prog _tid_map sub path =
let symbols = build_symbols path prog in let symbols = build_symbols path prog in
if List.length symbols = List.length path then if List.length symbols = List.length path then
begin begin
...@@ -81,7 +81,7 @@ let check_subfunction prog tid_map sub pathes = ...@@ -81,7 +81,7 @@ let check_subfunction prog tid_map sub pathes =
(Term.name sub) (Term.name sub)
end end
let check_cwe prog proj tid_map pathes _ = let check_cwe prog _proj tid_map pathes _ =
let chroot_symbol = find_symbol prog "chroot" in let chroot_symbol = find_symbol prog "chroot" in
match chroot_symbol with match chroot_symbol with
| Some _ -> | Some _ ->
......
...@@ -27,7 +27,7 @@ let contains_symbol block symbol_name = ...@@ -27,7 +27,7 @@ let contains_symbol block symbol_name =
(* Checks whether a subfunction contains a catch block. *) (* Checks whether a subfunction contains a catch block. *)
let contains_catch subfunction = let contains_catch subfunction =
let blocks = Term.enum blk_t subfunction in let blocks = Term.enum blk_t subfunction in
Seq.exists blocks (fun block -> contains_symbol block "@__cxa_begin_catch") Seq.exists blocks ~f:(fun block -> contains_symbol block "@__cxa_begin_catch")
(* Find all calls to subfunctions that are reachable from this subfunction. The calls are returned (* Find all calls to subfunctions that are reachable from this subfunction. The calls are returned
as a list, except for calls to "@__cxa_throw", which are logged as possibly uncaught exceptions. *) as a list, except for calls to "@__cxa_throw", which are logged as possibly uncaught exceptions. *)
...@@ -59,7 +59,7 @@ let rec find_uncaught_exceptions subfunction already_checked_functions program ~ ...@@ -59,7 +59,7 @@ let rec find_uncaught_exceptions subfunction already_checked_functions program ~
(* Search for uncatched exceptions for each entry point into the binary. (* Search for uncatched exceptions for each entry point into the binary.
TODO: Exceptions, that are catched when starting from one entry point, but not from another, are masked this TODO: Exceptions, that are catched when starting from one entry point, but not from another, are masked this
way. We should check whether this produces a lot of false negatives. *) way. We should check whether this produces a lot of false negatives. *)
let check_cwe program project tid_map symbol_pairs _ = let check_cwe program _project tid_map _symbol_pairs _ =
let entry_points = Symbol_utils.get_program_entry_points program in let entry_points = Symbol_utils.get_program_entry_points program in
let _ = Seq.fold entry_points ~init:[] ~f:(fun already_checked_functions sub -> find_uncaught_exceptions ~tid_map:tid_map sub already_checked_functions program) in let _ = Seq.fold entry_points ~init:[] ~f:(fun already_checked_functions sub -> find_uncaught_exceptions ~tid_map:tid_map sub already_checked_functions program) in
() ()
open Core_kernel open Core_kernel
open Bap.Std
open Graph_utils
open Symbol_utils open Symbol_utils
let name = "CWE332" let name = "CWE332"
let version = "0.1" let version = "0.1"
let check_cwe program proj tid_map symbol_pairs _ = let check_cwe program _proj _tid_map _symbol_pairs _ =
match Option.both (find_symbol program "srand") (find_symbol program "rand") with match Option.both (find_symbol program "srand") (find_symbol program "rand") with
| None -> begin | None -> begin
match (find_symbol program "rand") with match (find_symbol program "rand") with
| None -> () | None -> ()
| Some _ -> Log_utils.warn "[%s] {%s} (Insufficient Entropy in PRNG) program uses rand without calling srand before" name version | Some _ -> Log_utils.warn "[%s] {%s} (Insufficient Entropy in PRNG) program uses rand without calling srand before" name version
end end
| Some (srand_tid, rand_tid) -> () | Some (_srand_tid, _rand_tid) -> ()
...@@ -34,7 +34,7 @@ let is_reachable sub source sink = ...@@ -34,7 +34,7 @@ let is_reachable sub source sink =
let sink_blk = get_blk_tid_of_tid sub sink_tid in let sink_blk = get_blk_tid_of_tid sub sink_tid in
Graphlib.Std.Graphlib.is_reachable (module Graphs.Tid) cfg source_blk sink_blk Graphlib.Std.Graphlib.is_reachable (module Graphs.Tid) cfg source_blk sink_blk
let handle_sub sub program tid_map symbols source sink = let handle_sub sub program tid_map _symbols source sink =
if (Symbol_utils.sub_calls_symbol program sub source) && (Symbol_utils.sub_calls_symbol program sub sink) then if (Symbol_utils.sub_calls_symbol program sub source) && (Symbol_utils.sub_calls_symbol program sub sink) then
begin begin
let calls = Symbol_utils.get_direct_callsites_of_sub sub in let calls = Symbol_utils.get_direct_callsites_of_sub sub in
...@@ -57,6 +57,6 @@ let handle_sub sub program tid_map symbols source sink = ...@@ -57,6 +57,6 @@ let handle_sub sub program tid_map symbols source sink =
else else
() ()
let check_cwe program proj tid_map symbol_pairs _ = let check_cwe program _proj tid_map _symbol_pairs _ =
let symbols = Symbol_utils.build_symbols ["access"; "open";] in let symbols = Symbol_utils.build_symbols ["access"; "open";] in
Seq.iter (Term.enum sub_t program) ~f:(fun s -> handle_sub s program tid_map symbols "access" "open") Seq.iter (Term.enum sub_t program) ~f:(fun s -> handle_sub s program tid_map symbols "access" "open")
...@@ -21,7 +21,7 @@ let handle_sub sub program tid_map symbols = ...@@ -21,7 +21,7 @@ let handle_sub sub program tid_map symbols =
end end
else () else ()
let check_cwe program proj tid_map symbols _ = let check_cwe program _proj tid_map symbols _ =
match symbols with match symbols with
| hd::[] -> | hd::[] ->
Seq.iter (Term.enum sub_t program) ~f:(fun s -> handle_sub s program tid_map hd) Seq.iter (Term.enum sub_t program) ~f:(fun s -> handle_sub s program tid_map hd)
......
...@@ -10,7 +10,7 @@ let get_defs sub_ssa = ...@@ -10,7 +10,7 @@ let get_defs sub_ssa =
let collect_stores_of_exp = Exp.fold ~init:0 (object let collect_stores_of_exp = Exp.fold ~init:0 (object
inherit [int] Exp.visitor inherit [int] Exp.visitor
method! enter_store ~mem:_ ~addr:addr ~exp:exp _ _ stores = method! enter_store ~mem:_ ~addr:_ ~exp:_ _ _ stores =
stores + 1 stores + 1
end) end)
...@@ -62,7 +62,7 @@ let is_interesting_load_store def fp_pointer = ...@@ -62,7 +62,7 @@ let is_interesting_load_store def fp_pointer =
(*TODO: implement real filtering*) (*TODO: implement real filtering*)
let filter_mem_address i min_fp_offset = Set.filter i ~f:(fun elem -> (Word.of_int ~width:32 min_fp_offset) < elem) let filter_mem_address i min_fp_offset = Set.filter i ~f:(fun elem -> (Word.of_int ~width:32 min_fp_offset) < elem)
let check_subfunction prog proj tid_map sub = let check_subfunction _prog proj tid_map sub =
let fp_pointer = get_fp_of_arch (Project.arch proj) in let fp_pointer = get_fp_of_arch (Project.arch proj) in
let min_fp_offset = get_min_fp_offset (Project.arch proj) in let min_fp_offset = get_min_fp_offset (Project.arch proj) in
let stores = ref [||] in let stores = ref [||] in
...@@ -92,5 +92,5 @@ let check_subfunction prog proj tid_map sub = ...@@ -92,5 +92,5 @@ let check_subfunction prog proj tid_map sub =
end end
end) end)
let check_cwe prog proj tid_map symbol_names _ = let check_cwe prog proj tid_map _symbol_names _ =
Seq.iter (Term.enum sub_t prog) ~f:(fun sub -> check_subfunction prog proj tid_map sub) Seq.iter (Term.enum sub_t prog) ~f:(fun sub -> check_subfunction prog proj tid_map sub)
...@@ -8,7 +8,7 @@ let version = "0.1" ...@@ -8,7 +8,7 @@ let version = "0.1"
let get_pointer_size arch = let get_pointer_size arch =
Size.in_bytes @@ Arch.addr_size arch Size.in_bytes @@ Arch.addr_size arch
let check_input_is_pointer_size proj prog sub blk jmp tid_map symbols = let check_input_is_pointer_size proj _prog _sub blk jmp tid_map symbols =
Seq.iter (Term.enum def_t blk) ~f:(fun d -> match Exp.eval @@ Def.rhs d with Seq.iter (Term.enum def_t blk) ~f:(fun d -> match Exp.eval @@ Def.rhs d with
| Imm w -> | Imm w ->
begin begin
......
...@@ -53,7 +53,7 @@ module State = struct ...@@ -53,7 +53,7 @@ module State = struct
(** two states are equal if they contain the same set of tainted registers*) (** two states are equal if they contain the same set of tainted registers*)
let equal state1 state2 = let equal state1 state2 =
(List.length state1) = (List.length state2) && (List.length state1) = (List.length state2) &&
not (List.exists state1 ~f:(fun (var, tid) -> Option.is_none (find state2 var) )) not (List.exists state1 ~f:(fun (var, _tid) -> Option.is_none (find state2 var) ))
(** The union of two states is the union of the tainted registers*) (** The union of two states is the union of the tainted registers*)
let union state1 state2 = let union state1 state2 =
...@@ -66,14 +66,14 @@ module State = struct ...@@ -66,14 +66,14 @@ module State = struct
(** remove virtual registers from the state (useful at the end of a block) *) (** remove virtual registers from the state (useful at the end of a block) *)
let remove_virtual_registers state = let remove_virtual_registers state =
List.filter state ~f:(fun (var, tid) -> Var.is_physical var) List.filter state ~f:(fun (var, _tid) -> Var.is_physical var)
end end
(* check whether an expression contains an unchecked value. *) (* check whether an expression contains an unchecked value. *)
let rec contains_unchecked exp state : access_type = let rec contains_unchecked exp state : access_type =
match exp with match exp with
| Bil.Load(mem, addr, _, _)-> | Bil.Load(_mem, addr, _, _)->
begin begin
let acc = contains_unchecked addr state in let acc = contains_unchecked addr state in
match acc with match acc with
...@@ -81,7 +81,7 @@ let rec contains_unchecked exp state : access_type = ...@@ -81,7 +81,7 @@ let rec contains_unchecked exp state : access_type =
| Access(var) -> MemAccess(var) | Access(var) -> MemAccess(var)
| NoAccess -> NoAccess | NoAccess -> NoAccess
end end
| Bil.Store(mem, addr, val_expression, _,_) -> | Bil.Store(_mem, addr, val_expression, _,_) ->
begin begin
let acc = union_access (contains_unchecked addr state) (contains_unchecked val_expression state) in let acc = union_access (contains_unchecked addr state) (contains_unchecked val_expression state) in
match acc with match acc with
...@@ -111,7 +111,7 @@ let rec contains_unchecked exp state : access_type = ...@@ -111,7 +111,7 @@ let rec contains_unchecked exp state : access_type =
to the source of this return value from state. *) to the source of this return value from state. *)
let checks_value exp state : State.t = let checks_value exp state : State.t =
match exp with match exp with
| Bil.Ite(if_, then_, else_) -> begin | Bil.Ite(if_, _then_, _else_) -> begin
match contains_unchecked if_ state with match contains_unchecked if_ state with
| Access(var) -> | Access(var) ->
(* We filter out all registers with the same generating tid, since we have checked (* We filter out all registers with the same generating tid, since we have checked
...@@ -138,7 +138,7 @@ let flag_any_access exp state ~cwe_hits = ...@@ -138,7 +138,7 @@ let flag_any_access exp state ~cwe_hits =
(** flag all unchecked registers as cwe_hits, return empty state *) (** flag all unchecked registers as cwe_hits, return empty state *)
let flag_all_unchecked_registers state ~cwe_hits = let flag_all_unchecked_registers state ~cwe_hits =
let () = List.iter state ~f:(fun (var, tid) -> let () = List.iter state ~f:(fun (_var, tid) ->
append_to_hits cwe_hits tid) in append_to_hits cwe_hits tid) in
[] []
...@@ -190,30 +190,30 @@ let update_state_jmp jmp state ~cwe_hits ~function_names ~program ~block ~strict ...@@ -190,30 +190,30 @@ let update_state_jmp jmp state ~cwe_hits ~function_names ~program ~block ~strict
| NoAccess -> state | NoAccess -> state
end in end in
match Jmp.kind jmp with match Jmp.kind jmp with
| Goto(Indirect(exp)) -> flag_any_access exp state cwe_hits | Goto(Indirect(exp)) -> flag_any_access exp state ~cwe_hits
| Goto(Direct(_)) -> state | Goto(Direct(_)) -> state
| Ret(_) -> if strict_call_policy then | Ret(_) -> if strict_call_policy then
flag_all_unchecked_registers state cwe_hits flag_all_unchecked_registers state ~cwe_hits
else else
state state
| Int(_, _) -> flag_all_unchecked_registers state cwe_hits | Int(_, _) -> flag_all_unchecked_registers state ~cwe_hits
| Call(call) -> | Call(call) ->
let state = match Call.return call with let state = match Call.return call with
| Some(Indirect(exp)) -> flag_any_access exp state cwe_hits | Some(Indirect(exp)) -> flag_any_access exp state ~cwe_hits
| _ -> state in | _ -> state in
let state = match Call.target call with let state = match Call.target call with
| Indirect(exp) -> flag_any_access exp state cwe_hits | Indirect(exp) -> flag_any_access exp state ~cwe_hits
| _ -> state in | _ -> state in
let state = match strict_call_policy with let state = match strict_call_policy with
| true -> (* all unchecked registers get flagged as hits *) | true -> (* all unchecked registers get flagged as hits *)
flag_all_unchecked_registers state cwe_hits flag_all_unchecked_registers state ~cwe_hits
| false -> (* we assume that the callee will check all remaining unchecked values *) | false -> (* we assume that the callee will check all remaining unchecked values *)
[] in [] in
match Call.target call with match Call.target call with
| Indirect(_) -> state (* already handled above *) | Indirect(_) -> state (* already handled above *)
| Direct(tid) -> | Direct(tid) ->
if List.exists function_names ~f:(fun elem -> String.(=) elem (Tid.name tid)) then if List.exists function_names ~f:(fun elem -> String.(=) elem (Tid.name tid)) then
taint_return_registers tid state program block taint_return_registers tid state ~program ~block
else else
state state
...@@ -227,7 +227,7 @@ let update_block_analysis block register_state ~cwe_hits ~function_names ~progra ...@@ -227,7 +227,7 @@ let update_block_analysis block register_state ~cwe_hits ~function_names ~progra
let register_state = Seq.fold elements ~init:register_state ~f:(fun state element -> let register_state = Seq.fold elements ~init:register_state ~f:(fun state element ->
match element with match element with
| `Def def -> update_state_def def state ~cwe_hits | `Def def -> update_state_def def state ~cwe_hits
| `Phi phi -> state (* We ignore phi terms for this analysis. *) | `Phi _phi -> state (* We ignore phi terms for this analysis. *)
| `Jmp jmp -> update_state_jmp jmp state ~cwe_hits ~function_names ~program ~block ~strict_call_policy | `Jmp jmp -> update_state_jmp jmp state ~cwe_hits ~function_names ~program ~block ~strict_call_policy
) in ) in
State.remove_virtual_registers register_state (* virtual registers should not be accessed outside of the block where they are defined. *) State.remove_virtual_registers register_state (* virtual registers should not be accessed outside of the block where they are defined. *)
...@@ -255,7 +255,7 @@ let print_hit tid ~sub ~function_names ~tid_map = ...@@ -255,7 +255,7 @@ let print_hit tid ~sub ~function_names ~tid_map =
| _ -> false | _ -> false
) in () ) in ()
let check_cwe prog proj tid_map symbol_names parameters = let check_cwe prog _proj tid_map symbol_names parameters =
let symbols = match symbol_names with let symbols = match symbol_names with
| hd :: _ -> hd | hd :: _ -> hd
| _ -> failwith "[CWE476] symbol_names not as expected" in | _ -> failwith "[CWE476] symbol_names not as expected" in
......
...@@ -4,7 +4,7 @@ open Bap.Std ...@@ -4,7 +4,7 @@ open Bap.Std
let name = "CWE676" let name = "CWE676"
let version = "0.1" let version = "0.1"
let get_call_to_target cg callee target = let get_call_to_target _cg callee target =
Term.enum blk_t callee |> Term.enum blk_t callee |>
Seq.concat_map ~f:(fun blk -> Seq.concat_map ~f:(fun blk ->
Term.enum jmp_t blk |> Seq.filter_map ~f:(fun j -> Term.enum jmp_t blk |> Seq.filter_map ~f:(fun j ->
...@@ -35,7 +35,7 @@ let resolve_symbols prog symbols = ...@@ -35,7 +35,7 @@ let resolve_symbols prog symbols =
Seq.filter ~f:(fun s -> List.exists ~f:(fun x -> x = Sub.name s) symbols) Seq.filter ~f:(fun s -> List.exists ~f:(fun x -> x = Sub.name s) symbols)
let check_cwe prog proj tid_map symbol_names _ = let check_cwe prog _proj tid_map symbol_names _ =
match symbol_names with match symbol_names with
| hd::[] -> | hd::[] ->
let subfunctions = Term.enum sub_t prog in let subfunctions = Term.enum sub_t prog in
......
open Core_kernel
open Bap.Std open Bap.Std
let name = "CWE782" let name = "CWE782"
let version = "0.1" let version = "0.1"
(*TODO: check if binary is setuid*) (*TODO: check if binary is setuid*)
let handle_sub sub program tid_map symbols = let handle_sub sub program tid_map _symbols =
if Symbol_utils.sub_calls_symbol program sub "ioctl" then if Symbol_utils.sub_calls_symbol program sub "ioctl" then
Log_utils.warn "[%s] {%s} (Exposed IOCTL with Insufficient Access Control) Program uses ioctl at %s (%s). Be sure to double check the program and the corresponding driver." Log_utils.warn "[%s] {%s} (Exposed IOCTL with Insufficient Access Control) Program uses ioctl at %s (%s). Be sure to double check the program and the corresponding driver."
name name
...@@ -15,5 +14,5 @@ let handle_sub sub program tid_map symbols = ...@@ -15,5 +14,5 @@ let handle_sub sub program tid_map symbols =
else else
() ()
let check_cwe program proj tid_map symbols _ = let check_cwe program _proj tid_map symbols _ =
Seq.iter (Term.enum sub_t program) ~f:(fun s -> handle_sub s program tid_map symbols) Seq.iter (Term.enum sub_t program) ~f:(fun s -> handle_sub s program tid_map symbols)
...@@ -14,7 +14,7 @@ dev-repo: "git+https://github.com/fkie-cad/cwe_checker" ...@@ -14,7 +14,7 @@ dev-repo: "git+https://github.com/fkie-cad/cwe_checker"
depends: [ depends: [
"ocaml" {>= "4.05"} "ocaml" {>= "4.05"}
"dune" {>= "1.6"} "dune" {>= "1.6"}
"yojson" {>= "1.4.1"} "yojson" {>= "1.6.0"}
"bap" {>= "1.6"} "bap" {>= "1.6"}
"core_kernel" {>= "v0.11" & < "v0.12"} "core_kernel" {>= "v0.11" & < "v0.12"}
"ppx_jane" {>= "v0.11" & < "v0.12"} "ppx_jane" {>= "v0.11" & < "v0.12"}
......
...@@ -9,7 +9,7 @@ let translate_tid_to_assembler_address_string tid tid_map = ...@@ -9,7 +9,7 @@ let translate_tid_to_assembler_address_string tid tid_map =
let generate_tid_map prog = let generate_tid_map prog =
(object (object
inherit [addr Tid.Map.t] Term.visitor inherit [addr Tid.Map.t] Term.visitor
method enter_term _ t addrs = match Term.get_attr t address with method! enter_term _ t addrs = match Term.get_attr t address with
| None -> addrs | None -> addrs
| Some addr -> Map.add_exn addrs ~key:(Term.tid t) ~data:addr | Some addr -> Map.add_exn addrs ~key:(Term.tid t) ~data:addr
end)#run prog Tid.Map.empty end)#run prog Tid.Map.empty
...@@ -13,8 +13,10 @@ let callee_saved_register_list project = ...@@ -13,8 +13,10 @@ let callee_saved_register_list project =
match arch with match arch with
| `x86_64 -> (* System V ABI *) | `x86_64 -> (* System V ABI *)
"RBX" :: "RSP" :: "RBP" :: "R12" :: "R13" :: "R14" :: "R15" :: [] "RBX" :: "RSP" :: "RBP" :: "R12" :: "R13" :: "R14" :: "R15" :: []
| `x86_64 -> (* Microsoft x64 calling convention *) (* TODO: How to distinguish from System V? For the time being, only use the System V ABI, since it saves less registers. *) (* Microsoft x64 calling convention. Unused at the moment, since Windows binaries are not yet supported.
| `x86_64 -> (* Microsoft x64 calling convention *)
"RBX" :: "RBP" :: "RDI" :: "RSI" :: "RSP" :: "R12" :: "R13" :: "R14" :: "R15" :: [] "RBX" :: "RBP" :: "RDI" :: "RSI" :: "RSP" :: "R12" :: "R13" :: "R14" :: "R15" :: []
*)
| `x86 -> (* Both Windows and Linux save the same registers *) | `x86 -> (* Both Windows and Linux save the same registers *)
"EBX" :: "ESI" :: "EDI" :: "EBP" :: [] "EBX" :: "ESI" :: "EDI" :: "EBP" :: []
| `armv4 | `armv5 | `armv6 | `armv7 | `armv4 | `armv5 | `armv6 | `armv7
......
open Core_kernel
open Bap.Std
open Graphlib.Std
type path = {
start_node: Bap.Std.tid;
nodes: Bap.Std.tid array;
end_node: Bap.Std.tid;
}
let get_entry_blk_of_sub sub =
match Term.first blk_t sub with
| Some blk -> blk
| _ -> failwith "Could not determine first block of sub."
let print_path p =
Format.printf "%s\n" (Array.fold p.nodes ~init:"" ~f:(fun acc n -> acc ^ " -> " ^ (Tid.to_string n)))
let print_path_length p =
Format.printf "%d\n" (Array.length p.nodes)
(* ToDo: remove *)
let print_current_edge a b =
Format.printf "\t%s -> %s\n" (Tid.to_string a) (Tid.to_string b)
let fork_path current_path current_node =
let new_path = Array.append (Array.copy current_path.nodes) [|current_node|] in
{start_node = current_path.start_node; nodes = new_path; end_node = current_path.end_node;}
let node_already_visited_on_path node path =
node = path.start_node || Array.exists path.nodes ~f:(fun n -> n = node)
let rec get_all_paths_from_node node g current_path =
match Seq.to_list (Graphs.Tid.Node.succs node g) with
| [] -> [current_path]
| succs -> List.concat_map succs
~f:(fun succ ->
if node_already_visited_on_path succ current_path then
[]
else
get_all_paths_from_node succ g (fork_path current_path node))
(* Please mind the path explosion !!! *)
let enumerate_paths_between_blks sub blk_start_tid blk_end_tid limit =
let g = Sub.to_graph sub in
let pathes = get_all_paths_from_node blk_start_tid g {start_node = blk_start_tid; nodes = [||]; end_node = blk_end_tid} in
Format.printf "\tFound %d pathes.\n" (List.length pathes); []
(** This module implements functionality that works on graphs like the CFG.
Most of its functionality is implemented by using BAP's Graphlib.Std. *)
(* This module implements functionality related to parsing the JSON configuration file. *) (* This module implements functionality related to parsing the JSON configuration file. *)
val get_symbol_lists_from_json : Yojson.Basic.json -> string -> string list list val get_symbol_lists_from_json : Yojson.Basic.t -> string -> string list list
val get_symbols_from_json : Yojson.Basic.json -> string -> string list val get_symbols_from_json : Yojson.Basic.t -> string -> string list
val get_parameter_list_from_json : Yojson.Basic.json -> string -> string list val get_parameter_list_from_json : Yojson.Basic.t -> string -> string list
...@@ -166,7 +166,7 @@ module Make (S: SECTION) = struct ...@@ -166,7 +166,7 @@ module Make (S: SECTION) = struct
!prefix !prefix
(* example for a shorter timestamp string *) (* example for a shorter timestamp string *)
let short_timestamp_str lvl = let _short_timestamp_str lvl =
sprintf "%.3f %s: " (Unix.gettimeofday()) (string_of_level lvl) sprintf "%.3f %s: " (Unix.gettimeofday()) (string_of_level lvl)
let log lvl fmt = let log lvl fmt =
......
...@@ -48,7 +48,7 @@ Term.enum blk_t sub |> ...@@ -48,7 +48,7 @@ Term.enum blk_t sub |>
match Jmp.kind j with match Jmp.kind j with
| Goto _ | Ret _ | Int (_,_) -> None | Goto _ | Ret _ | Int (_,_) -> None
| Call destination -> begin match Call.target destination with | Call destination -> begin match Call.target destination with
| Direct tid -> Some j | Direct _tid -> Some j
| _ -> None | _ -> None
end)) end))
......
open Bap.Std open Bap.Std
open Core_kernel (* open Core_kernel *)
open Cwe_checker_core open Cwe_checker_core
let check msg x = Alcotest.(check bool) msg true x let check msg x = Alcotest.(check bool) msg true x
......
open Bap.Std
open Core_kernel
val tests: unit Alcotest.test_case list val tests: unit Alcotest.test_case list
...@@ -29,16 +29,16 @@ let test_preamble () = ...@@ -29,16 +29,16 @@ let test_preamble () =
(project, stack_register, sub, sub_tid, fn_start_state) (project, stack_register, sub, sub_tid, fn_start_state)
let test_update_stack_offset () = let test_update_stack_offset () =
let (project, stack_register, sub, sub_tid, fn_start_state) = test_preamble () in let (project, stack_register, _sub, sub_tid, fn_start_state) = test_preamble () in
let def1 = Def.create stack_register (Bil.binop Bil.plus (Bil.var stack_register) (Bil.int (bv 8))) in let def1 = Def.create stack_register (Bil.binop Bil.plus (Bil.var stack_register) (Bil.int (bv 8))) in
let def2 = Def.create stack_register (Bil.binop Bil.minus (Bil.var stack_register) (Bil.int (bv 16))) in let def2 = Def.create stack_register (Bil.binop Bil.minus (Bil.var stack_register) (Bil.int (bv 16))) in
let block = create_block_from_defs [def1; def2] in let block = create_block_from_defs [def1; def2] in
let state = update_block_analysis block fn_start_state sub_tid project in let state = update_block_analysis block fn_start_state ~sub_tid ~project in
let () = check "update_stack_offset" ( (compute_stack_offset state (Bil.var stack_register) sub_tid project) = Some(Bitvector.unsigned (bv (-8)))) in let () = check "update_stack_offset" ( (compute_stack_offset state (Bil.var stack_register) ~sub_tid ~project) = Some(Bitvector.unsigned (bv (-8)))) in
() ()
let test_preserve_stack_offset_on_stubs () = let test_preserve_stack_offset_on_stubs () =
let (project, stack_register, sub, sub_tid, fn_start_state) = test_preamble () in let (project, stack_register, _sub, sub_tid, fn_start_state) = test_preamble () in
let register1 = Var.create "Register1" (Bil.Imm (Symbol_utils.arch_pointer_size_in_bytes project * 8)) in let register1 = Var.create "Register1" (Bil.Imm (Symbol_utils.arch_pointer_size_in_bytes project * 8)) in
let mem_reg = Var.create "Mem_reg" (Bil.Imm (Symbol_utils.arch_pointer_size_in_bytes project * 8)) in let mem_reg = Var.create "Mem_reg" (Bil.Imm (Symbol_utils.arch_pointer_size_in_bytes project * 8)) in
let def1 = Def.create register1 (Bil.unop Bil.NEG (Bil.var register1)) in let def1 = Def.create register1 (Bil.unop Bil.NEG (Bil.var register1)) in
...@@ -49,9 +49,9 @@ let test_preserve_stack_offset_on_stubs () = ...@@ -49,9 +49,9 @@ let test_preserve_stack_offset_on_stubs () =
let () = Blk.Builder.add_def block def2 in let () = Blk.Builder.add_def block def2 in
let () = Blk.Builder.add_jmp block call_term in let () = Blk.Builder.add_jmp block call_term in
let block = Blk.Builder.result block in let block = Blk.Builder.result block in
let state = update_block_analysis block fn_start_state sub_tid project in let state = update_block_analysis block fn_start_state ~sub_tid ~project in
let pointer_size = Symbol_utils.arch_pointer_size_in_bytes project in (* since the callee removes the return address from the stack, the stack offset is adjusted accordingly. *) let pointer_size = Symbol_utils.arch_pointer_size_in_bytes project in (* since the callee removes the return address from the stack, the stack offset is adjusted accordingly. *)
let () = check "preserve_stack_offset_inner_call" ( (compute_stack_offset state (Bil.var stack_register) sub_tid project) = Some(Bitvector.unsigned (bv pointer_size))) in let () = check "preserve_stack_offset_inner_call" ( (compute_stack_offset state (Bil.var stack_register) ~sub_tid ~project) = Some(Bitvector.unsigned (bv pointer_size))) in
let () = check "delete_stack_info_inner_call" (Mem_region.get state.TypeInfo.stack (bv (-8)) = None) in let () = check "delete_stack_info_inner_call" (Mem_region.get state.TypeInfo.stack (bv (-8)) = None) in
(* find the malloc extern call. This fails if the example project does not contain a call to malloc. *) (* find the malloc extern call. This fails if the example project does not contain a call to malloc. *)
let malloc_sub = Seq.find_exn (Term.enum sub_t (Project.program project)) ~f:(fun sub -> Sub.name sub = "malloc") in let malloc_sub = Seq.find_exn (Term.enum sub_t (Project.program project)) ~f:(fun sub -> Sub.name sub = "malloc") in
...@@ -61,8 +61,8 @@ let test_preserve_stack_offset_on_stubs () = ...@@ -61,8 +61,8 @@ let test_preserve_stack_offset_on_stubs () =
let () = Blk.Builder.add_def block def2 in let () = Blk.Builder.add_def block def2 in
let () = Blk.Builder.add_jmp block call_term in let () = Blk.Builder.add_jmp block call_term in
let block = Blk.Builder.result block in let block = Blk.Builder.result block in
let state = update_block_analysis block fn_start_state sub_tid project in let state = update_block_analysis block fn_start_state ~sub_tid ~project in
let () = check "preserve_stack_offset_extern_malloc_call" ( (compute_stack_offset state (Bil.var stack_register) sub_tid project) = Some(Bitvector.unsigned (bv pointer_size))) in let () = check "preserve_stack_offset_extern_malloc_call" ( (compute_stack_offset state (Bil.var stack_register) ~sub_tid ~project) = Some(Bitvector.unsigned (bv pointer_size))) in
let () = check "preserve_stack_info_extern_malloc_call" (Mem_region.get state.TypeInfo.stack (bv (-8)) = Some(Ok((Data, bv 8)))) in let () = check "preserve_stack_info_extern_malloc_call" (Mem_region.get state.TypeInfo.stack (bv (-8)) = Some(Ok((Data, bv 8)))) in
(* find the "free" extern call. This fails if the example project does not contain a call to "free". *) (* find the "free" extern call. This fails if the example project does not contain a call to "free". *)
let extern_sub = Seq.find_exn (Term.enum sub_t (Project.program project)) ~f:(fun sub -> Sub.name sub = "free") in let extern_sub = Seq.find_exn (Term.enum sub_t (Project.program project)) ~f:(fun sub -> Sub.name sub = "free") in
...@@ -72,19 +72,19 @@ let test_preserve_stack_offset_on_stubs () = ...@@ -72,19 +72,19 @@ let test_preserve_stack_offset_on_stubs () =
let () = Blk.Builder.add_def block def2 in let () = Blk.Builder.add_def block def2 in
let () = Blk.Builder.add_jmp block call_term in let () = Blk.Builder.add_jmp block call_term in
let block = Blk.Builder.result block in let block = Blk.Builder.result block in
let state = update_block_analysis block fn_start_state sub_tid project in let state = update_block_analysis block fn_start_state ~sub_tid ~project in
let () = check "preserve_stack_offset_extern_call" ( (compute_stack_offset state (Bil.var stack_register) sub_tid project) = Some(Bitvector.unsigned (bv pointer_size))) in let () = check "preserve_stack_offset_extern_call" ( (compute_stack_offset state (Bil.var stack_register) ~sub_tid ~project) = Some(Bitvector.unsigned (bv pointer_size))) in
let () = check "delete_stack_info_extern_call" (Mem_region.get state.TypeInfo.stack (bv (-8)) <> Some(Ok((Data, bv 8)))) in let () = check "delete_stack_info_extern_call" (Mem_region.get state.TypeInfo.stack (bv (-8)) <> Some(Ok((Data, bv 8)))) in
() ()
let test_update_reg () = let test_update_reg () =
let (project, stack_register, sub, sub_tid, fn_start_state) = test_preamble () in let (project, stack_register, _sub, sub_tid, fn_start_state) = test_preamble () in
let register1 = Var.create "Register1" (Bil.Imm (Symbol_utils.arch_pointer_size_in_bytes project * 8)) in let register1 = Var.create "Register1" (Bil.Imm (Symbol_utils.arch_pointer_size_in_bytes project * 8)) in
let register2 = Var.create "Register2" (Bil.Imm (Symbol_utils.arch_pointer_size_in_bytes project * 8)) in let register2 = Var.create "Register2" (Bil.Imm (Symbol_utils.arch_pointer_size_in_bytes project * 8)) in
let def1 = Def.create register1 (Bil.binop Bil.AND (Bil.var stack_register) (Bil.int (bv 8))) in let def1 = Def.create register1 (Bil.binop Bil.AND (Bil.var stack_register) (Bil.int (bv 8))) in
let def2 = Def.create register2 (Bil.binop Bil.XOR (Bil.var register1) (Bil.var stack_register)) in let def2 = Def.create register2 (Bil.binop Bil.XOR (Bil.var register1) (Bil.var stack_register)) in
let block = create_block_from_defs [def1; def2] in let block = create_block_from_defs [def1; def2] in
let state = update_block_analysis block fn_start_state sub_tid project in let state = update_block_analysis block fn_start_state ~sub_tid ~project in
let () = check "update_pointer_register" ( let () = check "update_pointer_register" (
match Var.Map.find state.TypeInfo.reg register1 with match Var.Map.find state.TypeInfo.reg register1 with
| Some(Ok(Pointer(_))) -> true | Some(Ok(Pointer(_))) -> true
...@@ -93,7 +93,7 @@ let test_update_reg () = ...@@ -93,7 +93,7 @@ let test_update_reg () =
let () = check "update_data_register" (Var.Map.find state.TypeInfo.reg register2 = Some(Ok(Data))) in let () = check "update_data_register" (Var.Map.find state.TypeInfo.reg register2 = Some(Ok(Data))) in
let def1 = Def.create register1 (Bil.Load (Bil.var register1, Bil.var register2, Bitvector.LittleEndian, `r64) ) in let def1 = Def.create register1 (Bil.Load (Bil.var register1, Bil.var register2, Bitvector.LittleEndian, `r64) ) in
let block = create_block_from_defs [def1;] in let block = create_block_from_defs [def1;] in
let state = update_block_analysis block fn_start_state sub_tid project in let state = update_block_analysis block fn_start_state ~sub_tid ~project in
let () = check "add_mem_address_registers" ( let () = check "add_mem_address_registers" (
match Var.Map.find state.TypeInfo.reg register2 with match Var.Map.find state.TypeInfo.reg register2 with
| Some(Ok(Pointer(_))) -> true | Some(Ok(Pointer(_))) -> true
...@@ -102,7 +102,7 @@ let test_update_reg () = ...@@ -102,7 +102,7 @@ let test_update_reg () =
() ()
let test_update_stack () = let test_update_stack () =
let (project, stack_register, sub, sub_tid, fn_start_state) = test_preamble () in let (project, stack_register, _sub, sub_tid, fn_start_state) = test_preamble () in
let register1 = Var.create "Register1" (Bil.Imm (Symbol_utils.arch_pointer_size_in_bytes project * 8)) in let register1 = Var.create "Register1" (Bil.Imm (Symbol_utils.arch_pointer_size_in_bytes project * 8)) in
let register2 = Var.create "Register2" (Bil.Imm (Symbol_utils.arch_pointer_size_in_bytes project * 8)) in let register2 = Var.create "Register2" (Bil.Imm (Symbol_utils.arch_pointer_size_in_bytes project * 8)) in
let mem_reg = Var.create "Mem_reg" (Bil.Imm (Symbol_utils.arch_pointer_size_in_bytes project * 8)) in let mem_reg = Var.create "Mem_reg" (Bil.Imm (Symbol_utils.arch_pointer_size_in_bytes project * 8)) in
...@@ -110,10 +110,10 @@ let test_update_stack () = ...@@ -110,10 +110,10 @@ let test_update_stack () =
let def2 = Def.create mem_reg (Bil.Store ((Bil.var mem_reg), (Bil.binop Bil.PLUS (Bil.var stack_register) (Bil.int (bv (-8)))), (Bil.var stack_register), Bitvector.LittleEndian, `r64)) in let def2 = Def.create mem_reg (Bil.Store ((Bil.var mem_reg), (Bil.binop Bil.PLUS (Bil.var stack_register) (Bil.int (bv (-8)))), (Bil.var stack_register), Bitvector.LittleEndian, `r64)) in
let def3 = Def.create register2 (Bil.Load (Bil.var mem_reg, (Bil.binop Bil.MINUS (Bil.var stack_register) (Bil.int (bv 8))), Bitvector.LittleEndian, `r64) ) in let def3 = Def.create register2 (Bil.Load (Bil.var mem_reg, (Bil.binop Bil.MINUS (Bil.var stack_register) (Bil.int (bv 8))), Bitvector.LittleEndian, `r64) ) in
let block = create_block_from_defs [def1; def2; def3;] in let block = create_block_from_defs [def1; def2; def3;] in
let state = update_block_analysis block fn_start_state sub_tid project in let state = update_block_analysis block fn_start_state ~sub_tid ~project in
let () = check "write_to_stack" ( let () = check "write_to_stack" (
match Mem_region.get state.TypeInfo.stack (bv (-8)) with match Mem_region.get state.TypeInfo.stack (bv (-8)) with
| Some(Ok(Pointer(targets), size )) when size = bv (Symbol_utils.arch_pointer_size_in_bytes project) -> true | Some(Ok(Pointer(_targets), size )) when size = bv (Symbol_utils.arch_pointer_size_in_bytes project) -> true
| _ -> false | _ -> false
) in ) in
let () = check "load_from_stack" ( let () = check "load_from_stack" (
...@@ -124,7 +124,7 @@ let test_update_stack () = ...@@ -124,7 +124,7 @@ let test_update_stack () =
() ()
let test_address_registers_on_load_and_store () = let test_address_registers_on_load_and_store () =
let (project, stack_register, sub, sub_tid, fn_start_state) = test_preamble () in let (project, stack_register, _sub, sub_tid, fn_start_state) = test_preamble () in
let register1 = Var.create "Register1" (Bil.Imm (Symbol_utils.arch_pointer_size_in_bytes project * 8)) in let register1 = Var.create "Register1" (Bil.Imm (Symbol_utils.arch_pointer_size_in_bytes project * 8)) in
let register2 = Var.create "Register2" (Bil.Imm (Symbol_utils.arch_pointer_size_in_bytes project * 8)) in let register2 = Var.create "Register2" (Bil.Imm (Symbol_utils.arch_pointer_size_in_bytes project * 8)) in
let mem_reg = Var.create "Mem_reg" (Bil.Imm (Symbol_utils.arch_pointer_size_in_bytes project * 8)) in let mem_reg = Var.create "Mem_reg" (Bil.Imm (Symbol_utils.arch_pointer_size_in_bytes project * 8)) in
...@@ -132,52 +132,52 @@ let test_address_registers_on_load_and_store () = ...@@ -132,52 +132,52 @@ let test_address_registers_on_load_and_store () =
let def2 = Def.create mem_reg (Bil.Store ((Bil.var mem_reg), (Bil.var register1) , (Bil.var stack_register), Bitvector.LittleEndian, `r64)) in let def2 = Def.create mem_reg (Bil.Store ((Bil.var mem_reg), (Bil.var register1) , (Bil.var stack_register), Bitvector.LittleEndian, `r64)) in
let def3 = Def.create register2 (Bil.Load (Bil.var mem_reg, (Bil.binop Bil.MINUS (Bil.var stack_register) (Bil.int (bv 8))), Bitvector.LittleEndian, `r64) ) in let def3 = Def.create register2 (Bil.Load (Bil.var mem_reg, (Bil.binop Bil.MINUS (Bil.var stack_register) (Bil.int (bv 8))), Bitvector.LittleEndian, `r64) ) in
let block = create_block_from_defs [def1; def2; def3;] in let block = create_block_from_defs [def1; def2; def3;] in
let state = update_block_analysis block fn_start_state sub_tid project in let state = update_block_analysis block fn_start_state ~sub_tid ~project in
let () = check "mark_store_address_as_pointer" ( let () = check "mark_store_address_as_pointer" (
match Map.find_exn state.TypeInfo.reg register1 with match Map.find_exn state.TypeInfo.reg register1 with
| Ok(Pointer(targets)) -> (Map.is_empty targets) | Ok(Pointer(targets)) -> (Map.is_empty targets)
| _ -> false | _ -> false
) in ) in
let () = check "dont_change_offsets_on_address_register" (compute_stack_offset state (Bil.var stack_register) sub_tid project = Some(bv 0)) in let () = check "dont_change_offsets_on_address_register" (compute_stack_offset state (Bil.var stack_register) ~sub_tid ~project = Some(bv 0)) in
() ()
let test_merge_type_infos () = let test_merge_type_infos () =
let (project, stack_register, sub, sub_tid, fn_start_state) = test_preamble () in let (project, stack_register, _sub, sub_tid, fn_start_state) = test_preamble () in
let generic_empty_state = only_stack_pointer_and_flags sub_tid project in let generic_empty_state = only_stack_pointer_and_flags sub_tid project in
let def1 = Def.create stack_register (Bil.binop Bil.plus (Bil.var stack_register) (Bil.int (bv 8))) in let def1 = Def.create stack_register (Bil.binop Bil.plus (Bil.var stack_register) (Bil.int (bv 8))) in
let block = create_block_from_defs [def1;] in let block = create_block_from_defs [def1;] in
let state1 = update_block_analysis block fn_start_state sub_tid project in let state1 = update_block_analysis block fn_start_state ~sub_tid ~project in
let state2 = update_block_analysis block generic_empty_state sub_tid project in let state2 = update_block_analysis block generic_empty_state ~sub_tid ~project in
let merged_state = merge_type_infos state1 state1 in let merged_state = merge_type_infos state1 state1 in
let () = check "merge_same_stack_offset" (compute_stack_offset merged_state (Bil.var stack_register) sub_tid project = Some(Bitvector.unsigned (bv 8))) in let () = check "merge_same_stack_offset" (compute_stack_offset merged_state (Bil.var stack_register) ~sub_tid ~project = Some(Bitvector.unsigned (bv 8))) in
let merged_state = merge_type_infos fn_start_state state1 in let merged_state = merge_type_infos fn_start_state state1 in
let () = check "merge_different_stack_offsets" (compute_stack_offset merged_state (Bil.var stack_register) sub_tid project = None) in let () = check "merge_different_stack_offsets" (compute_stack_offset merged_state (Bil.var stack_register) ~sub_tid ~project = None) in
let merged_state = merge_type_infos generic_empty_state state1 in let merged_state = merge_type_infos generic_empty_state state1 in
let () = check "merge_with_unknown_stack_offset" (compute_stack_offset merged_state (Bil.var stack_register) sub_tid project = Some(Bitvector.unsigned (bv 8))) in let () = check "merge_with_unknown_stack_offset" (compute_stack_offset merged_state (Bil.var stack_register) ~sub_tid ~project = Some(Bitvector.unsigned (bv 8))) in
let merged_state = merge_type_infos generic_empty_state state2 in let merged_state = merge_type_infos generic_empty_state state2 in
let () = check "merge_empty_stack_offsets" (compute_stack_offset merged_state (Bil.var stack_register) sub_tid project = None) in let () = check "merge_empty_stack_offsets" (compute_stack_offset merged_state (Bil.var stack_register) ~sub_tid ~project = None) in
() ()
let test_type_info_equal () = let test_type_info_equal () =
let (project, stack_register, sub, sub_tid, fn_start_state) = test_preamble () in let (project, _stack_register, _sub, sub_tid, fn_start_state) = test_preamble () in
let generic_empty_state = only_stack_pointer_and_flags sub_tid project in let generic_empty_state = only_stack_pointer_and_flags sub_tid project in
let () = check "empty_state_neq_fn_start_state" (false = (type_info_equal fn_start_state generic_empty_state)) in let () = check "empty_state_neq_fn_start_state" (false = (type_info_equal fn_start_state generic_empty_state)) in
() ()
let test_malloc_call_return_reg () = let test_malloc_call_return_reg () =
let (project, stack_register, sub, sub_tid, fn_start_state) = test_preamble () in let (project, _stack_register, _sub, sub_tid, fn_start_state) = test_preamble () in
(* find the malloc extern call. This fails if the example project does not contain a call to malloc. *) (* find the malloc extern call. This fails if the example project does not contain a call to malloc. *)
let malloc_sub = Seq.find_exn (Term.enum sub_t (Project.program project)) ~f:(fun sub -> Sub.name sub = "malloc") in let malloc_sub = Seq.find_exn (Term.enum sub_t (Project.program project)) ~f:(fun sub -> Sub.name sub = "malloc") in
let call_term = Jmp.create (Call (Call.create ~target:(Label.direct (Term.tid malloc_sub)) () )) in let call_term = Jmp.create (Call (Call.create ~target:(Label.direct (Term.tid malloc_sub)) () )) in
let block = Blk.Builder.create () in let block = Blk.Builder.create () in
let () = Blk.Builder.add_jmp block call_term in let () = Blk.Builder.add_jmp block call_term in
let block = Blk.Builder.result block in let block = Blk.Builder.result block in
let state = update_block_analysis block fn_start_state sub_tid project in let state = update_block_analysis block fn_start_state ~sub_tid ~project in
(* test whether the return register is marked as a pointer register. This fails if the example project is not a x64 binary. *) (* test whether the return register is marked as a pointer register. This fails if the example project is not a x64 binary. *)
let state_reg_list = Map.to_alist state.TypeInfo.reg in let state_reg_list = Map.to_alist state.TypeInfo.reg in
let () = String.Set.iter (Cconv.parse_dyn_syms project) ~f:(fun elem -> print_endline elem) in let () = String.Set.iter (Cconv.parse_dyn_syms project) ~f:(fun elem -> print_endline elem) in
let () = check "malloc_return_register_marked" (match List.find state_reg_list ~f:(fun (var, register_info) -> Var.name var = "RAX") with let () = check "malloc_return_register_marked" (match List.find state_reg_list ~f:(fun (var, _register_info) -> Var.name var = "RAX") with
| Some((var, register_info)) -> (* TODO: test whether the target is set correctly. *) | Some((_var, register_info)) -> (* TODO: test whether the target is set correctly. *)
begin match register_info with begin match register_info with
| Ok(Pointer(targets)) -> | Ok(Pointer(targets)) ->
begin match Map.to_alist targets with begin match Map.to_alist targets with
......
open Bap.Std open Bap.Std
open Core_kernel open Core_kernel
open Cwe_checker_core
let run_tests project = let run_tests project =
Type_inference_test.example_project := Some(project); Type_inference_test.example_project := Some(project);
......
...@@ -24,7 +24,7 @@ let test_parse_dyn_syms () = ...@@ -24,7 +24,7 @@ let test_parse_dyn_syms () =
let () = check "__libc_start_main_as_dyn_sym" (String.Set.mem (parse_dyn_syms project) "__libc_start_main") in let () = check "__libc_start_main_as_dyn_sym" (String.Set.mem (parse_dyn_syms project) "__libc_start_main") in
let () = check "malloc_as_dyn_sym" (String.Set.mem (parse_dyn_syms project) "malloc") in let () = check "malloc_as_dyn_sym" (String.Set.mem (parse_dyn_syms project) "malloc") in
let () = check "__cxa_finalize_as_dyn_sym" (String.Set.mem (parse_dyn_syms project) "__cxa_finalize") in let () = check "__cxa_finalize_as_dyn_sym" (String.Set.mem (parse_dyn_syms project) "__cxa_finalize") in
let () = check "dyn_sym_count" (String.Set.count (parse_dyn_syms project) ~f:(fun elem -> true) = 4) in let () = check "dyn_sym_count" (String.Set.count (parse_dyn_syms project) ~f:(fun _elem -> true) = 4) in
() ()
let tests = [ let tests = [
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment