summaryrefslogtreecommitdiff
path: root/t
diff options
context:
space:
mode:
authorNicholas Clark <nick@ccl4.org>2021-07-02 09:55:00 +0000
committerNicholas Clark <nick@ccl4.org>2021-09-22 06:53:03 +0000
commit2c205b5406a70a5753a289ca1b05dace7c12727a (patch)
treee36274b41e5697b3f951967a34258168d183569e /t
parent71e2181fdc1da7dfd599d69d45e604c493276c68 (diff)
downloadperl-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.t17
1 files changed, 15 insertions, 2 deletions
diff --git a/t/op/gv.t b/t/op/gv.t
index 4136ca29a3..9e2ce52a06 100644
--- a/t/op/gv.t
+++ b/t/op/gv.t
@@ -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