Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SV-COMP "Memory Safety" benchmark additions #1201

Merged
merged 83 commits into from
Oct 14, 2023
Merged
Show file tree
Hide file tree
Changes from 68 commits
Commits
Show all changes
83 commits
Select commit Hold shift + click to select a range
0e849e4
Merge remote-tracking branch 'stanimir/mem-oob-analysis' into staging…
michael-schwarz Sep 6, 2023
9e430ab
Merge remote-tracking branch 'stanimir/improve-uaf-analysis' into sta…
michael-schwarz Sep 6, 2023
dac7983
Fix numbering
michael-schwarz Sep 6, 2023
b3d9fe1
Set the global SV-COMP analysis state vars at all necessary places
mrstanb Sep 6, 2023
46ae6ee
Add extra parentheses in witness.ml for memory safety result generation
mrstanb Sep 6, 2023
d4ef555
Add quick and dirty workaround attempt for working with
mrstanb Sep 6, 2023
2fb4d74
Use logical AND and not OR for the memory-safety category in witness
mrstanb Sep 6, 2023
9cbf2ab
Add util function for setting mem safety global vars
mrstanb Sep 9, 2023
3258cce
Don't warn for pointers that only contain strings in their pts
mrstanb Sep 9, 2023
0881fb7
Set global mem safety flags upon array oob as well
mrstanb Sep 9, 2023
b9faa8f
Cast pointer arithmetic offsets without using Option.get
mrstanb Sep 9, 2023
8a6cf0a
Check and warn everywhere for a top points-to set in memOutOfBounds
mrstanb Sep 10, 2023
29f13a2
Simplify string address check and remove extra warning
mrstanb Sep 10, 2023
7bdce29
Add check for dereferencing a pointer containing an unknown address
mrstanb Sep 10, 2023
3c01418
Remove unused function
mrstanb Sep 13, 2023
15f782b
Add exception handling for intdom arithmetic in memOutOfBounds
mrstanb Sep 13, 2023
20433e3
Ignore info messages for test case 77/05 due to MacOS CI
mrstanb Sep 13, 2023
9e59043
Merge branch 'master' into staging_memsafety
mrstanb Oct 1, 2023
dee2a60
Set SV-COMP memory safety global flags at all necessary locations
mrstanb Oct 1, 2023
da45e40
Clean up UAF analysis a bit
mrstanb Oct 1, 2023
1335123
Recognize mem-safety props in any order
mrstanb Oct 2, 2023
1384f73
Add support for SV-COMP's valid-memcleanup property
mrstanb Oct 2, 2023
4e70422
Set SV-COMP global flag for invalid-memcleanup
mrstanb Oct 2, 2023
00cc9b5
Enable memory safety analyses in autoTune
mrstanb Oct 2, 2023
2c8e927
Rename UAF tests from number 78 to 74
mrstanb Oct 2, 2023
f872854
Fix print for valid-memtrack and valid-memcleanup in `autoTune.ml`
mrstanb Oct 3, 2023
edaef42
Set `ana.malloc.unique_address_count` to `1` when activating memLeak …
mrstanb Oct 3, 2023
7f0b43c
Improve some `AnalysisState` global flag comments
mrstanb Oct 3, 2023
a975702
Clean up some commented out code
mrstanb Oct 3, 2023
b26010a
Set `ana.malloc.unique_address_count` to `1` only if it's not already…
mrstanb Oct 3, 2023
89d68af
Add a valid-memcleanup.prp file
mrstanb Oct 3, 2023
171ba57
Comment out reachability filter in useAfterFree's `enter`
mrstanb Oct 3, 2023
4a1c038
Fix wrong callee_state in enter
mrstanb Oct 3, 2023
bb2091e
Add test case for UAF in callee through a global var
mrstanb Oct 3, 2023
fb4ad24
Fix typo for warning about top address offsets
mrstanb Oct 3, 2023
9d64db1
Add test case with invalid deref in complex loop
mrstanb Oct 3, 2023
1afac02
Disable info messages which confuse `make test` in 77/10
mrstanb Oct 3, 2023
f5c197e
Add option for enabling the marking of variables as pulled out of scope
mrstanb Oct 3, 2023
003b814
Warn for accesses to variables pulled out of scope
mrstanb Oct 3, 2023
ac7dd71
Automatically set `cil.addNestedScopeAttr` in autoTune when running `…
mrstanb Oct 3, 2023
c95a846
Bump goblint-cil
mrstanb Oct 3, 2023
500a444
Merge branch 'master' into svcomp-memsafety-benchmarks
mrstanb Oct 3, 2023
c9a846b
set also for meta property
michael-schwarz Oct 3, 2023
9efae6f
Fix address offset calculation in `memOutOfBounds`
mrstanb Oct 3, 2023
dcc3d5c
Adapt 77/10 test case to correctly account for address offsets
mrstanb Oct 3, 2023
a64e9c3
Add further test case to check address offset calculation in `memOutO…
mrstanb Oct 3, 2023
44476ce
Set `ana.malloc.unique_address_count` for `MemorySafety` as well
mrstanb Oct 3, 2023
e052544
Move `cil.addNestedScopeAttr` setting to `init_options`
mrstanb Oct 4, 2023
3341470
Try with `cil.addNestedScopeAttr` always set to `true`
mrstanb Oct 4, 2023
1211a9f
Use rand() in 77/10
mrstanb Oct 4, 2023
2039675
Activate `cil.addNestedScopeAttr` in cilfacade only conditionally
mrstanb Oct 4, 2023
fb4979b
Activate SV-COMP memory-safety-related options before CIL has complet…
mrstanb Oct 4, 2023
1eb7309
Fix again scoping check
mrstanb Oct 4, 2023
4a4b6ab
Fix conditional enabling of `cil.addNestedScopeAttr`
mrstanb Oct 4, 2023
ead8976
Merge branch 'master' into svcomp-memsafety-benchmarks
mrstanb Oct 4, 2023
395c30d
Warn for invalid deallocation when encountering invalid addresses
mrstanb Oct 4, 2023
055d9cc
Add invalid address test case for invalid deallocation
mrstanb Oct 4, 2023
2c883eb
Warn if lval contains an address with a non-local var
mrstanb Oct 4, 2023
5cb10f6
Don't warn for non-local vars in address set if they're globals
mrstanb Oct 4, 2023
ea4410d
Add test cases for invalid deref due to scoping
mrstanb Oct 4, 2023
6745d79
Slightly refactor `check_count` and check for `src`'s size in `memcpy`
mrstanb Oct 4, 2023
136bec0
Add test case with wrong src size for memcpy
mrstanb Oct 4, 2023
3a2fe3f
Correct test 77/07 to warn for src OOB access in memcpy as well
mrstanb Oct 4, 2023
9b728d3
Set `dest` in `memcpy` to top if `n` doesn't match its size
mrstanb Oct 5, 2023
48f2cfe
Add test case for UAF due to bad memcpy
mrstanb Oct 5, 2023
753b5c1
Check offsets of dereferenced lvalues as well
mrstanb Oct 5, 2023
d683281
Add regr. test case for OOB due to too large lval offset
mrstanb Oct 5, 2023
22e4df5
Fix exceptions due to ID ops
mrstanb Oct 5, 2023
b9c2134
Fix size check in `memory_copying`
mrstanb Oct 6, 2023
625e90b
Use `Option.map_default` instead of `match`
mrstanb Oct 6, 2023
fbab25e
Use `_` in place of unused offset in lambda
mrstanb Oct 6, 2023
91aeee7
Set `Cabs2cil.addNestedScopeAttr` based on the Goblint config option
mrstanb Oct 6, 2023
992e5c0
Remove extra semicolon
mrstanb Oct 6, 2023
cc351e0
Use `Option.default` in place of `Option.value`
mrstanb Oct 6, 2023
de0220b
Use `AD.exists` to warn about non-local vars in address set instead o…
mrstanb Oct 6, 2023
e98911d
Remove unnecessary pin
mrstanb Oct 11, 2023
072f99d
Remove commented out code from `enter` in UAF analysis
mrstanb Oct 11, 2023
e339ed1
Remove unnecessary stuff from test case `74/15`
mrstanb Oct 11, 2023
f018ea3
Reduce duplication
michael-schwarz Oct 11, 2023
a2f36fb
Reorganize memsafety regr. tests
mrstanb Oct 11, 2023
33e69af
Merge branch 'master' into svcomp-memsafety-benchmarks
mrstanb Oct 11, 2023
7fad157
Merge branch 'master' into svcomp-memsafety-benchmarks
michael-schwarz Oct 12, 2023
910a11f
Activate `cil.addNestedScopeAttr` when `memOutOfBounds` analysis is a…
michael-schwarz Oct 12, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions goblint.opam.locked
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,9 @@ build: [
]
dev-repo: "git+https://github.com/goblint/analyzer.git"
available: os-distribution != "alpine" & arch != "arm64"
pin-depends: [
[ "goblint-cil.2.0.2" "git+https://github.com/goblint/cil.git#c7ffc37ad83216a84d90fdbf427cc02a68ea5331" ]
]
mrstanb marked this conversation as resolved.
Show resolved Hide resolved
conflicts: [
"result" {< "1.5"}
]
Expand Down
128 changes: 116 additions & 12 deletions src/analyses/base.ml
Original file line number Diff line number Diff line change
Expand Up @@ -1043,10 +1043,27 @@ struct
| Mem n, ofs -> begin
match (eval_rv a gs st n) with
| Address adr ->
(if AD.is_null adr
then M.error ~category:M.Category.Behavior.Undefined.nullpointer_dereference ~tags:[CWE 476] "Must dereference NULL pointer"
else if AD.may_be_null adr
then M.warn ~category:M.Category.Behavior.Undefined.nullpointer_dereference ~tags:[CWE 476] "May dereference NULL pointer");
(
if AD.is_null adr then (
AnalysisStateUtil.set_mem_safety_flag InvalidDeref;
M.error ~category:M.Category.Behavior.Undefined.nullpointer_dereference ~tags:[CWE 476] "Must dereference NULL pointer"
)
else if AD.may_be_null adr then (
AnalysisStateUtil.set_mem_safety_flag InvalidDeref;
M.warn ~category:M.Category.Behavior.Undefined.nullpointer_dereference ~tags:[CWE 476] "May dereference NULL pointer"
);
(* Warn if any of the addresses contains a non-local variable *)
AD.iter (function
| AD.Addr.Addr (v,o) ->
if not (CPA.mem v st.cpa) && not (is_global a v) then (
(* TODO: Not the smartest move to set the global flag within an iter *)
(* TODO: We can resort to using AD.exists instead *)
mrstanb marked this conversation as resolved.
Show resolved Hide resolved
AnalysisStateUtil.set_mem_safety_flag InvalidDeref;
M.warn "lval %a points to non-local variable %a. Invalid pointer dereference may occur" d_lval lval CilType.Varinfo.pretty v
)
| _ -> ()
) adr
);
AD.map (add_offset_varinfo (convert_offset a gs st ofs)) adr
| _ ->
M.debug ~category:Analyzer "Failed evaluating %a to lvalue" d_lval lval;
Expand Down Expand Up @@ -2023,14 +2040,78 @@ struct
in
match eval_rv_address (Analyses.ask_of_ctx ctx) ctx.global ctx.local ptr with
| Address a ->
if AD.is_top a then
if AD.is_top a then (
AnalysisStateUtil.set_mem_safety_flag InvalidFree;
M.warn ~category:(Behavior (Undefined InvalidMemoryDeallocation)) ~tags:[CWE 590] "Points-to set for pointer %a in function %s is top. Potentially invalid memory deallocation may occur" d_exp ptr special_fn.vname
else if has_non_heap_var a then
) else if has_non_heap_var a then (
AnalysisStateUtil.set_mem_safety_flag InvalidFree;
M.warn ~category:(Behavior (Undefined InvalidMemoryDeallocation)) ~tags:[CWE 590] "Free of non-dynamically allocated memory in function %s for pointer %a" special_fn.vname d_exp ptr
else if has_non_zero_offset a then
) else if has_non_zero_offset a then (
AnalysisStateUtil.set_mem_safety_flag InvalidFree;
M.warn ~category:(Behavior (Undefined InvalidMemoryDeallocation)) ~tags:[CWE 761] "Free of memory not at start of buffer in function %s for pointer %a" special_fn.vname d_exp ptr
| _ -> M.warn ~category:MessageCategory.Analyzer "Pointer %a in function %s doesn't evaluate to a valid address." d_exp ptr special_fn.vname
)
| _ ->
AnalysisStateUtil.set_mem_safety_flag InvalidFree;
M.warn ~category:(Behavior (Undefined InvalidMemoryDeallocation)) ~tags:[CWE 590] "Pointer %a in function %s doesn't evaluate to a valid address. Invalid memory deallocation may occur" d_exp ptr special_fn.vname

let points_to_heap_only ctx ptr =
match ctx.ask (Queries.MayPointTo ptr) with
| a when not (Queries.AD.is_top a)->
Queries.AD.for_all (function
| Addr (v, o) -> ctx.ask (Queries.IsHeapVar v)
mrstanb marked this conversation as resolved.
Show resolved Hide resolved
| _ -> false
) a
| _ -> false

let get_size_of_ptr_target ctx ptr =
let intdom_of_int x =
ID.of_int (Cilfacade.ptrdiff_ikind ()) (Z.of_int x)
in
let size_of_type_in_bytes typ =
let typ_size_in_bytes = (bitsSizeOf typ) / 8 in
intdom_of_int typ_size_in_bytes
in
if points_to_heap_only ctx ptr then
(* Ask for BlobSize from the base address (the second component being set to true) in order to avoid BlobSize giving us bot *)
ctx.ask (Queries.BlobSize {exp = ptr; base_address = true})
else
match ctx.ask (Queries.MayPointTo ptr) with
| a when not (Queries.AD.is_top a) ->
let pts_list = Queries.AD.elements a in
let pts_elems_to_sizes (addr: Queries.AD.elt) =
begin match addr with
| Addr (v, _) ->
begin match v.vtype with
| TArray (item_typ, _, _) ->
let item_typ_size_in_bytes = size_of_type_in_bytes item_typ in
begin match ctx.ask (Queries.EvalLength ptr) with
| `Lifted arr_len ->
let arr_len_casted = ID.cast_to (Cilfacade.ptrdiff_ikind ()) arr_len in
begin
try `Lifted (ID.mul item_typ_size_in_bytes arr_len_casted)
with IntDomain.ArithmeticOnIntegerBot _ -> `Bot
end
| `Bot -> `Bot
| `Top -> `Top
end
| _ ->
let type_size_in_bytes = size_of_type_in_bytes v.vtype in
`Lifted type_size_in_bytes
end
| _ -> `Top
end
in
(* Map each points-to-set element to its size *)
let pts_sizes = List.map pts_elems_to_sizes pts_list in
(* Take the smallest of all sizes that ptr's contents may have *)
begin match pts_sizes with
| [] -> `Bot
| [x] -> x
| x::xs -> List.fold_left ValueDomainQueries.ID.join x xs
end
| _ ->
(M.warn "Pointer %a has a points-to-set of top. An invalid memory access might occur" d_exp ptr;
`Top)

let special ctx (lv:lval option) (f: varinfo) (args: exp list) =
let invalidate_ret_lv st = match lv with
Expand All @@ -2050,13 +2131,36 @@ struct
let st: store = ctx.local in
let gs = ctx.global in
let desc = LF.find f in
let memory_copying dst src =
let memory_copying dst src n =
let dest_size = get_size_of_ptr_target ctx dst in
let n_intdom = match n with
| Some exp -> ctx.ask (Queries.EvalInt exp)
| None -> `Bot
in
mrstanb marked this conversation as resolved.
Show resolved Hide resolved
let dest_size_equal_n =
match dest_size, n_intdom with
| `Top, `Top -> true
| `Bot, `Bot -> true
| `Lifted ds, `Lifted n ->
let casted_ds = ID.cast_to (Cilfacade.ptrdiff_ikind ()) ds in
let casted_n = ID.cast_to (Cilfacade.ptrdiff_ikind ()) n in
let ds_eq_n =
begin try ID.eq casted_ds casted_n
with IntDomain.ArithmeticOnIntegerBot _ -> ID.bot_of @@ Cilfacade.ptrdiff_ikind ()
end
in
begin match ID.to_bool ds_eq_n with
| Some b -> b
| None -> false
end
| _, _ -> false
mrstanb marked this conversation as resolved.
Show resolved Hide resolved
in
let dest_a, dest_typ = addr_type_of_exp dst in
let src_lval = mkMem ~addr:(Cil.stripCasts src) ~off:NoOffset in
let src_typ = eval_lv (Analyses.ask_of_ctx ctx) gs st src_lval
|> AD.type_of in
(* when src and destination type coincide, take value from the source, otherwise use top *)
let value = if typeSig dest_typ = typeSig src_typ then
let value = if (typeSig dest_typ = typeSig src_typ) && dest_size_equal_n then
let src_cast_lval = mkMem ~addr:(Cilfacade.mkCast ~e:src ~newt:(TPtr (dest_typ, []))) ~off:NoOffset in
eval_rv (Analyses.ask_of_ctx ctx) gs st (Lval src_cast_lval)
else
Expand Down Expand Up @@ -2117,13 +2221,13 @@ struct
let value = VD.zero_init_value dest_typ in
set ~ctx (Analyses.ask_of_ctx ctx) gs st dest_a dest_typ value
| Memcpy { dest = dst; src; n; }, _ -> (* TODO: use n *)
memory_copying dst src
memory_copying dst src (Some n)
(* strcpy(dest, src); *)
| Strcpy { dest = dst; src; n = None }, _ ->
let dest_a, dest_typ = addr_type_of_exp dst in
(* when dest surely isn't a string literal, try copying src to dest *)
if AD.string_writing_defined dest_a then
memory_copying dst src
memory_copying dst src None
else
(* else return top (after a warning was issued) *)
set ~ctx (Analyses.ask_of_ctx ctx) gs st dest_a dest_typ (VD.top_value (unrollType dest_typ))
Expand Down
16 changes: 13 additions & 3 deletions src/analyses/memLeak.ml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
open GoblintCil
open Analyses
open MessageCategory
open AnalysisStateUtil

module ToppedVarInfoSet = SetDomain.ToppedSet(CilType.Varinfo)(struct let topname = "All Heap Variables" end)

Expand All @@ -19,15 +20,24 @@ struct

(* HELPER FUNCTIONS *)
let warn_for_multi_threaded ctx =
if not (ctx.ask (Queries.MustBeSingleThreaded { since_start = true })) then
if not (ctx.ask (Queries.MustBeSingleThreaded { since_start = true })) then (
set_mem_safety_flag InvalidMemTrack;
set_mem_safety_flag InvalidMemcleanup;
M.warn ~category:(Behavior (Undefined MemoryLeak)) ~tags:[CWE 401] "Program isn't running in single-threaded mode. A memory leak might occur due to multi-threading"
)

let check_for_mem_leak ?(assert_exp_imprecise = false) ?(exp = None) ctx =
let state = ctx.local in
if not @@ D.is_empty state then
match assert_exp_imprecise, exp with
| true, Some exp -> M.warn ~category:(Behavior (Undefined MemoryLeak)) ~tags:[CWE 401] "assert expression %a is unknown. Memory leak might possibly occur for heap variables: %a" d_exp exp D.pretty state
| _ -> M.warn ~category:(Behavior (Undefined MemoryLeak)) ~tags:[CWE 401] "Memory leak detected for heap variables: %a" D.pretty state
| true, Some exp ->
set_mem_safety_flag InvalidMemTrack;
set_mem_safety_flag InvalidMemcleanup;
M.warn ~category:(Behavior (Undefined MemoryLeak)) ~tags:[CWE 401] "assert expression %a is unknown. Memory leak might possibly occur for heap variables: %a" d_exp exp D.pretty state
| _ ->
set_mem_safety_flag InvalidMemTrack;
set_mem_safety_flag InvalidMemcleanup;
M.warn ~category:(Behavior (Undefined MemoryLeak)) ~tags:[CWE 401] "Memory leak detected for heap variables: %a" D.pretty state

(* TRANSFER FUNCTIONS *)
let return ctx (exp:exp option) (f:fundec) : D.t =
Expand Down
Loading