Skip to content

Commit 8b44490

Browse files
authored
Merge pull request #684 from goblint/ddverify-pcwd
Fix unsound dereferencing of unknown pointer offset chain in DDVerify
2 parents 478e72a + 89a1adf commit 8b44490

File tree

2 files changed

+74
-3
lines changed

2 files changed

+74
-3
lines changed

src/analyses/base.ml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,7 @@ struct
351351
* adding proper dependencies.
352352
* For the exp argument it is always ok to put None. This means not using precise information about
353353
* which part of an array is involved. *)
354-
let rec get ?(full=false) a (gs: glob_fun) (st: store) (addrs:address) (exp:exp option): value =
354+
let rec get ?(top=VD.top ()) ?(full=false) a (gs: glob_fun) (st: store) (addrs:address) (exp:exp option): value =
355355
let at = AD.get_type addrs in
356356
let firstvar = if M.tracing then match AD.to_var_may addrs with [] -> "" | x :: _ -> x.vname else "" in
357357
if M.tracing then M.traceli "get" ~var:firstvar "Address: %a\nState: %a\n" AD.pretty addrs CPA.pretty st.cpa;
@@ -369,7 +369,7 @@ struct
369369
let f = function
370370
| Addr.Addr (x, o) -> f_addr (x, o)
371371
| Addr.NullPtr -> VD.bot () (* TODO: why bot? *)
372-
| Addr.UnknownPtr -> VD.top ()
372+
| Addr.UnknownPtr -> top (* top may be more precise than VD.top, e.g. for address sets, such that known addresses are kept for soundness *)
373373
| Addr.StrPtr _ -> `Int (ID.top_of IChar)
374374
in
375375
(* We form the collecting function by joining *)
@@ -727,10 +727,11 @@ struct
727727
else
728728
false
729729
end
730+
| NullPtr | UnknownPtr -> true (* TODO: are these sound? *)
730731
| _ -> false
731732
in
732733
if AD.for_all cast_ok p then
733-
get a gs st p (Some exp) (* downcasts are safe *)
734+
get ~top:(VD.top_value t) a gs st p (Some exp) (* downcasts are safe *)
734735
else
735736
VD.top () (* upcasts not! *)
736737
in
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
// PARAM: --disable sem.unknown_function.invalidate.globals --disable sem.unknown_function.spawn
2+
// extracted from ddverify pcwd
3+
4+
// header declarations
5+
6+
struct file_operations {
7+
void (*ioctl)();
8+
};
9+
10+
struct miscdevice {
11+
struct file_operations *fops;
12+
};
13+
14+
struct cdev {
15+
struct file_operations *ops;
16+
};
17+
18+
// implementation stub
19+
20+
struct ddv_cdev {
21+
struct cdev *cdevp;
22+
};
23+
24+
#define MAX_CDEV_SUPPORT 1
25+
26+
struct cdev fixed_cdev[MAX_CDEV_SUPPORT];
27+
struct ddv_cdev cdev_registered[MAX_CDEV_SUPPORT];
28+
29+
int cdev_add(struct cdev *p)
30+
{
31+
cdev_registered[0].cdevp = p;
32+
return 0;
33+
}
34+
35+
int misc_register(struct miscdevice *misc) {
36+
fixed_cdev[0].ops = misc->fops;
37+
return cdev_add(&fixed_cdev[0]);
38+
}
39+
40+
void call_cdev_functions()
41+
{
42+
int cdev_no = 0;
43+
if (cdev_registered[cdev_no].cdevp->ops->ioctl) {
44+
(* cdev_registered[cdev_no].cdevp->ops->ioctl)();
45+
}
46+
}
47+
48+
// concrete program
49+
50+
void pcwd_ioctl() {
51+
assert(1); // reachable
52+
}
53+
54+
static const struct file_operations pcwd_fops = {
55+
.ioctl = pcwd_ioctl
56+
};
57+
58+
static struct miscdevice pcwd_miscdev = {
59+
.fops = &pcwd_fops
60+
};
61+
62+
int main() {
63+
misc_register(&pcwd_miscdev);
64+
65+
void (*fp)(struct ddv_cdev*); // unknown function pointer
66+
fp(&cdev_registered); // invalidates argument!
67+
68+
call_cdev_functions();
69+
return 0;
70+
}

0 commit comments

Comments
 (0)