diff options
author | Nicholas Clark <nick@ccl4.org> | 2021-07-02 09:55:00 +0000 |
---|---|---|
committer | Nicholas Clark <nick@ccl4.org> | 2021-09-22 06:53:03 +0000 |
commit | 2c205b5406a70a5753a289ca1b05dace7c12727a (patch) | |
tree | e36274b41e5697b3f951967a34258168d183569e /t | |
parent | 71e2181fdc1da7dfd599d69d45e604c493276c68 (diff) | |
download | perl-2c205b5406a70a5753a289ca1b05dace7c12727a.tar.gz |
In Perl_gp_free() use PL_tmps_stack to avoid freeing glob entries immediately.
Typeglob assignment causes the current GP to be freed, and hence any package
variables it contains. As Perl's (data) stack is not reference counted, SVs
put on it are assumed to be owned by something else. For package variables,
this assumed owner is the typeglob. Hence if a single statement contains
both assignment to a typeglob and use of one of its variables, the
interpreter can read garbage (with all the usual explosive consequences).
This is yet another manifestation of "the stack is not reference counted",
and whilst troubling from a correctness perspective, can't be exploited
unless one can already run arbitrary code, in which case any attacker has
already won.
Whilst this problematic code doesn't turn up very often in real programs,
let alone hot paths, it is found quite often by researchers running
automated fuzzers. Previously these programs would trigger errors, that the
researchers would (legitimately) report, and then we would spend time
figuring out that the cause was "stack not reference counted" and so not a
dangerous security hole. This consumed a lot of researcher time, our time,
and prevents "interesting" security holes being uncovered.
Hence add code to use the temps stack to paper over the lack of stack
reference counting in this specific case. This should avoid a lot of time
spent on assessing and responding to legitimate but uninteresting security
reports, at a small cost in code complexity.
Diffstat (limited to 't')
-rw-r--r-- | t/op/gv.t | 17 |
1 files changed, 15 insertions, 2 deletions
@@ -12,8 +12,6 @@ BEGIN { use warnings; -plan(tests => 284); - # type coercion on assignment $foo = 'foo'; $bar = *main::foo; @@ -317,6 +315,9 @@ is($j[0], 1); { # Need some sort of die or warn to get the global destruction text if the # bug is still present + # This test is "interesting" because the cleanup is triggered by the call + # op_free(PL_main_root) in perl_destruct, which is *just* before this: + # PERL_SET_PHASE(PERL_PHASE_DESTRUCT); my $output = runperl(prog => <<'EOPROG'); package M; $| = 1; @@ -1225,6 +1226,18 @@ eval << '--'; -- like $@, qr /^Use of inherited AUTOLOAD for non-method main::f\x{1543}\x{18c}\(\) is no longer allowed/, "Cannot inherit AUTOLOAD"; +# ASAN used to get very excited about this: +runperl(prog => '$a += (*a = 2)'); +is ($?, 0, + "work around lack of stack reference counting during typeglob assignment"); + +# and this +runperl(prog => '$$ |= (*$ = $$)'); +is ($?, 0, + "work around lack of stack reference counting during typeglob assignment"); + +done_testing(); + __END__ Perl Rules |