Skip to content

Commit 788cb49

Browse files
committed
argc may be zero
This commit fixes the entry point generation code to weaken the assumptions on argc. On numerous systems, argc may be zero, as exemplified by this exploit: https://www.qualys.com/2022/01/25/cve-2021-4034/pwnkit.txt The commit includes a test that replicates the loop in pkexec.
1 parent 5917ab4 commit 788cb49

File tree

8 files changed

+47
-18
lines changed

8 files changed

+47
-18
lines changed

regression/cbmc/argc-and-argv/argc1.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
int main(int argc, char **argv)
2+
{
3+
// There is no guarantee that there is at least one, so this
4+
// program is not memory safe.
5+
int n;
6+
7+
for(n = 1; n < argc; n++)
8+
{
9+
// nothing
10+
}
11+
12+
char *path = argv[n]; // out-of-bounds when argc == 0
13+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
CORE
2+
argc1.c
3+
--bounds-check --pointer-check --unwind 0
4+
^EXIT=10$
5+
^SIGNAL=0$
6+
^\[.*\] line .* dereference failure: pointer outside object bounds in argv\[.*n\]: FAILURE$
7+
^VERIFICATION FAILED$
8+
--
9+
^warning: ignoring

regression/cbmc/argc-and-argv/argv1.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
int main(int main_argc, char **main_argv)
2+
{
3+
char *x;
4+
5+
// there is no guarantee that there is at least one,
6+
// but note that argv is NULL-terminated
7+
x = main_argv[0];
8+
assert(main_argc >= 0);
9+
10+
// last one must be NULL
11+
assert(main_argv[main_argc] == 0);
12+
}

regression/cbmc/argv1/test.desc renamed to regression/cbmc/argc-and-argv/argv1.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
CORE
2-
main.c
2+
argv1.c
33
--bounds-check --pointer-check
44
^EXIT=0$
55
^SIGNAL=0$

regression/cbmc/argv1/main.c

Lines changed: 0 additions & 11 deletions
This file was deleted.

regression/cbmc/lhs-pointer-aliases-constant/test.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
#include <assert.h>
22

3-
int main(int argc, char **argv)
3+
int main()
44
{
55
int x;
66
const char *c = "Hello world";
7+
_Bool dummy;
8+
__CPROVER_assume(dummy);
79

8-
int *p = (argc ? &x : (int *)c);
10+
int *p = (dummy ? &x : (int *)c);
911

1012
*p = 1;
1113

regression/cbmc/multiple-goto-traces/main.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ int main(int argc, char **argv)
55
assert(4 != argc);
66
argc++;
77
argc--;
8-
assert(argc >= 1);
8+
assert(argc >= 0);
99
assert(argc != 4);
1010
argc++;
1111
argc--;

src/ansi-c/ansi_c_entry_point.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -304,11 +304,15 @@ bool generate_ansi_c_start_function(
304304
const symbolt &argv_symbol=ns.lookup("argv'");
305305

306306
{
307-
// assume argc is at least one
308-
exprt one=from_integer(1, argc_symbol.type);
307+
// Assume argc is at least zero. Note that we don't assume it's
308+
// at least one, since this isn't guaranteed, as exemplified by
309+
// https://www.qualys.com/2022/01/25/cve-2021-4034/pwnkit.txt
310+
// The C standard only guarantees "The value of argc shall be
311+
// nonnegative." and "argv[argc] shall be a null pointer."
312+
exprt zero = from_integer(0, argc_symbol.type);
309313

310314
binary_relation_exprt ge(
311-
argc_symbol.symbol_expr(), ID_ge, std::move(one));
315+
argc_symbol.symbol_expr(), ID_ge, std::move(zero));
312316

313317
init_code.add(code_assumet(std::move(ge)));
314318
}

0 commit comments

Comments
 (0)