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
integer overflow in line number tracking reported by caller() #15100
Comments
From @kentfredricIn conjunction with any code that can declare an arbitrary line number in the form: #line N If N is larger than: ( 1 << 31 ) - 1 then caller() will return a line number with integer overflow, causing the signed integer This may have slight implications for security related code, as it allows strings of eval'd code to emit numerical ranges that are likely outside the scope that people have tested for, due to assuming an unsigned integer. Its hard to imagine a real usecase for this, but its a bug that probably should be fixed in some regard. Attached is a simple demonstration of an overflow condition that can be constructed, and how you could hide a backdoor in your code, despite Safe. This is not *really* a security hole as such yet, because you could easily achieve intended unusual behavior at a distance simply by passing any other unusually large line number and with a similar specific condition. So this bug is more a representation of the fact you can't *explicitly* declare negative line numbers and have them respected, so it stands to reason caller() shouldn't return negative numbers either. Additional tests attached: Perl Info
|
From @kentfredric#!/usr/bin/env perl use strict; use Carp; sub getlineno { sub mk_bits { use Test::More; sub can_trip { for my $bits ( 2, 31, 32, 63, 64, 65 ) { my $ones = mk_bits( $bits, 1 ); note "Testing: $ones(=$bits)"; can_trip( $ones . ' - 1' ); pass(); |
From @kentfredric#!/usr/bin/env perl use strict; use Test::More; #line -5 done_testing; |
From @tonycozOn Tue Dec 22 07:27:06 2015, kentfredric wrote:
The line number is stored as a line_t which is a typedef for U32, but mPUSHi((I32)CopLINE(lcop)); which should probably change. This still wouldn't give us full 32-bit unsigned line numbers since gp_line in a GP is only 31 bits: GV * gp_egv; /* effective gv, if *glob */ which results in fun like: $ ./perl -we '#line 3000000000' -e 'if ($x = 1) { }' Patch for pp_caller attached. Tony |
From @tonycoz0001-perl-126991-treat-cop_line-as-unsigned-in-caller-sin.patchFrom f1962383f0c9d13ec9de46ef66a8a7033707ad8e Mon Sep 17 00:00:00 2001
From: Tony Cook <tony@develop-help.com>
Date: Mon, 4 Jan 2016 14:05:32 +1100
Subject: [perl #126991] treat cop_line as unsigned in caller() (since it is)
---
pp_ctl.c | 2 +-
t/op/caller.t | 7 ++++++-
2 files changed, 7 insertions(+), 2 deletions(-)
diff --git a/pp_ctl.c b/pp_ctl.c
index c006ce9..011da56 100644
--- a/pp_ctl.c
+++ b/pp_ctl.c
@@ -1808,7 +1808,7 @@ PP(pp_caller)
cx->blk_sub.retop, TRUE);
if (!lcop)
lcop = cx->blk_oldcop;
- mPUSHi((I32)CopLINE(lcop));
+ mPUSHu(CopLINE(lcop));
if (!has_arg)
RETURN;
if (CxTYPE(cx) == CXt_SUB || CxTYPE(cx) == CXt_FORMAT) {
diff --git a/t/op/caller.t b/t/op/caller.t
index 6e56d67..80d3a5a 100644
--- a/t/op/caller.t
+++ b/t/op/caller.t
@@ -5,7 +5,7 @@ BEGIN {
chdir 't' if -d 't';
@INC = '../lib';
require './test.pl';
- plan( tests => 95 );
+ plan( tests => 96 );
}
my @c;
@@ -308,6 +308,11 @@ is eval "s//<<END/e;\nfoo\nEND\n(caller 0)[6]",
is $w, 1, 'value from (caller 0)[9] (bitmask) works in ${^WARNING_BITS}';
}
+# [perl #126991]
+sub getlineno { (caller)[2] }
+my $line = eval "\n#line 3000000000\ngetlineno();";
+is $line, "3000000000", "check large line numbers are preserved";
+
# This was fixed with commit d4d03940c58a0177, which fixed bug #78742
fresh_perl_is <<'END', "__ANON__::doof\n", {},
package foo;
--
2.1.4
|
The RT System itself - Status changed from 'new' to 'open' |
From @tonycozOn Sun Jan 03 19:08:24 2016, tonyc wrote:
Applied as e9e9e54.
This isn't fixed and I don't think it's worth fixing. Tony |
From @bulk88On Wed Jan 20 16:05:38 2016, tonyc wrote:
Attempting to feed > 2 GB of perl source code per perl source code file (a 20 GB .pm, oh really?) through the compiler IMO should fail assuming the OS didn't kill the process due to resource limits first. Some example would be another tool, like a shell script, trying to feed/pipe the same statement line, an infinite number of times, into perl's STDIN. -- |
From @tonycozOn Wed, 20 Jan 2016 16:05:38 -0800, tonyc wrote:
Do we want to do anything else for this ticket? I can see three options: a) reject the remaining issues (line numbers >=2**31 not preserved in GVs, >2**32 not preserved at all) and close the ticket b) mitigate it somehow, eg. warn or croak on line numbers >=2**31. c) leave the ticket open, even if we don't plan to do anything Tony |
From @hvdsOn Tue, 11 Jun 2019 22:45:41 -0700, tonyc wrote:
My inclination is for (b) over (a); however I don't think it's hugely urgent, so in practice that might look more like (c). I've constructed file/line info not relating to a real line in a real file a few times in the past, eg to get useful nytprof results for a Moo application. I think there are legitimate use cases here, and we should be letting the user know if they go beyond what we can support. I think a warning is probably enough though. Hugo |
Migrated from rt.perl.org#126991 (status was 'open')
Searchable as RT126991$
The text was updated successfully, but these errors were encountered: