Navigation Menu

Skip to content
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

[PATCH] Coverity: regcomp.c etc. #13761

Closed
p5pRT opened this issue Apr 23, 2014 · 18 comments
Closed

[PATCH] Coverity: regcomp.c etc. #13761

p5pRT opened this issue Apr 23, 2014 · 18 comments
Labels

Comments

@p5pRT
Copy link

p5pRT commented Apr 23, 2014

Migrated from rt.perl.org#121712 (status was 'resolved')

Searchable as RT121712$

@p5pRT
Copy link
Author

p5pRT commented Apr 23, 2014

From @jhi

Needed compile-time limits for the PL_reg_intflags_name so that the
bit loop doesn't waltz off past the array. Could not use C_ARRAY_LENGTH
because the size of name array is not visible during compile time
(only const char*[] is), so modified regcomp.pl to generate the size,
made it visible only for the re extension. Did extflags analogously
even though its size currently exactly 32 already. The sizeof(flags)*8
is extra paranoia for ILP64.

Attached.

@p5pRT
Copy link
Author

p5pRT commented Apr 23, 2014

From @jhi

0009-Fix-for-Coverity-perl5-CID-29034.patch
From be565fd45f2ca9507a266617cfeeaaed82d36c3f Mon Sep 17 00:00:00 2001
From: Jarkko Hietaniemi <jhi@iki.fi>
Date: Mon, 21 Apr 2014 21:43:12 -0400
Subject: [PATCH 9/9] Fix for Coverity perl5 CID 29034: Out-of-bounds read
 (OVERRUN) overrun-local: Overrunning array PL_reg_intflags name of 14 8-byte
 elements at element index 31 (byte offset 248) using index bit (which
 evaluates to 31).

Needed compile-time limits for the PL_reg_intflags_name so that the
bit loop doesn't waltz off past the array.  Could not use C_ARRAY_LENGTH
because the size of name array is not visible during compile time
(only const char*[] is), so modified regcomp.pl to generate the size,
made it visible only for the re extension.  Did extflags analogously
even though its size currently exactly 32 already.  The sizeof(flags)*8
is extra paranoia for ILP64.
---
 regcomp.c        |  8 ++++++--
 regen/regcomp.pl | 17 ++++++++++++++++-
 regnodes.h       |  8 ++++++++
 3 files changed, 30 insertions(+), 3 deletions(-)

diff --git a/regcomp.c b/regcomp.c
index 0238af9..66f5c84 100644
--- a/regcomp.c
+++ b/regcomp.c
@@ -15365,7 +15365,9 @@ S_regdump_intflags(pTHX_ const char *lead, const U32 flags)
     int bit;
     int set=0;
 
-    for (bit=0; bit<32; bit++) {
+    for (bit=0;
+         bit<REG_INTFLAGS_NAME_SIZE && bit<sizeof(flags)*8;
+         bit++) {
         if (flags & (1<<bit)) {
             if (!set++ && lead)
                 PerlIO_printf(Perl_debug_log, "%s",lead);
@@ -15387,7 +15389,9 @@ S_regdump_extflags(pTHX_ const char *lead, const U32 flags)
     int set=0;
     regex_charset cs;
 
-    for (bit=0; bit<32; bit++) {
+    for (bit=0;
+         bit<REG_EXTFLAGS_NAME_SIZE && bit<sizeof(flags)*8;
+         bit++) {
         if (flags & (1<<bit)) {
 	    if ((1<<bit) & RXf_PMf_CHARSET) {	/* Output separately, below */
 		continue;
diff --git a/regen/regcomp.pl b/regen/regcomp.pl
index 4a8b9d5..657ca72 100644
--- a/regen/regcomp.pl
+++ b/regen/regcomp.pl
@@ -261,6 +261,7 @@ my %rxfv;
 my %definitions;    # Remember what the symbol definitions are
 my $val = 0;
 my %reverse;
+my $REG_EXTFLAGS_NAME_SIZE = 0;
 foreach my $file ("op_reg_common.h", "regexp.h") {
     open FH,"<$file" or die "Can't read $file: $!";
     while (<FH>) {
@@ -332,6 +333,7 @@ for (0..31) {
     s/\bRXf_(PMf_)?// for $n, $extra;
     printf $out qq(\t%-20s/* 0x%08x%s */\n),
         qq("$n",),$power_of_2, $extra;
+    $REG_EXTFLAGS_NAME_SIZE++;
 }  
  
 print $out <<EOP;
@@ -339,6 +341,12 @@ print $out <<EOP;
 #endif /* DOINIT */
 
 EOP
+print $out <<EOQ
+#ifdef PERL_IN_XSUB_RE
+#  define REG_EXTFLAGS_NAME_SIZE $REG_EXTFLAGS_NAME_SIZE /* sizeof(PL_reg_intflags_name) */
+#endif
+
+EOQ
 }
 {
 print $out <<EOP;
@@ -354,6 +362,7 @@ my %rxfv;
 my %definitions;    # Remember what the symbol definitions are
 my $val = 0;
 my %reverse;
+my $REG_INTFLAGS_NAME_SIZE = 0;
 foreach my $file ("regcomp.h") {
     open my $fh, "<", $file or die "Can't read $file: $!";
     while (<$fh>) {
@@ -369,6 +378,7 @@ foreach my $file ("regcomp.h") {
             $comment= $comment ? " - $comment" : "";
 
             printf $out qq(\t%-30s/* 0x%08x - %s%s */\n), qq("$abbr",), $val, $define, $comment;
+            $REG_INTFLAGS_NAME_SIZE++;
         }
     }
 }
@@ -378,8 +388,13 @@ print $out <<EOP;
 #endif /* DOINIT */
 
 EOP
-}
+print $out <<EOQ;
+#ifdef PERL_IN_XSUB_RE
+#  define REG_INTFLAGS_NAME_SIZE $REG_INTFLAGS_NAME_SIZE /* sizeof(PL_reg_intflags_name) */
+#endif
 
+EOQ
+}
 
 print $out process_flags('V', 'varies', <<'EOC');
 /* The following have no fixed length. U8 so we can do strchr() on it. */
diff --git a/regnodes.h b/regnodes.h
index 4f4ff9e..9dae3af 100644
--- a/regnodes.h
+++ b/regnodes.h
@@ -676,6 +676,10 @@ EXTCONST char * const PL_reg_extflags_name[] = {
 };
 #endif /* DOINIT */
 
+#ifdef PERL_IN_XSUB_RE
+#  define REG_EXTFLAGS_NAME_SIZE 32 /* sizeof(PL_reg_intflags_name) */
+#endif
+
 /* PL_reg_intflags_name[] - Opcode/state names in string form, for debugging */
 
 #ifndef DOINIT
@@ -699,6 +703,10 @@ EXTCONST char * const PL_reg_intflags_name[] = {
 };
 #endif /* DOINIT */
 
+#ifdef PERL_IN_XSUB_RE
+#  define REG_INTFLAGS_NAME_SIZE 14 /* sizeof(PL_reg_intflags_name) */
+#endif
+
 /* The following have no fixed length. U8 so we can do strchr() on it. */
 #define REGNODE_VARIES(node) (PL_varies_bitmask[(node) >> 3] & (1 << ((node) & 7)))
 
-- 
1.8.5.2 (Apple Git-48)

@p5pRT
Copy link
Author

p5pRT commented Apr 23, 2014

From @jhi

On Tuesday-201404-22, 20​:33, perlbug-followup@​perl.org wrote​:

Greetings,

This message has been automatically generated in response to the
creation of a perl bug report regarding​:
"[PATCH] Coverity​: regcomp.c etc.".

Ugh, thought I pasted more to the Subject line... should've been​:

[PATCH] Coverity​: regcomp.c etc. array access past the end

There is no need to reply to this message right now. Your ticket has been
assigned an ID of [perl #121712].

You can view your ticket at
https://rt-archive.perl.org/perl5/Ticket/Display.html?id=121712

Within the next 24 to 72 hours, your message will be posted to the Perl 5 Porters mailing list. Please be patient!

Please include the string​:

\[perl \#121712\]

in the subject line of all future correspondence about this issue. To do so,
you may reply to this message (please delete unnecessary quotes and text.)

Thank you,
perlbug-followup@​perl.org

-------------------------------------------------------------------------
Dkim-Signature​: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=sender​:message-id​:date​:from​:reply-to​:user-agent​:mime-version​:to :subject​:content-type; bh=fdpnDYO0h7syCIot+O8Y8JTBAjM+7xWK1DgAI/vrOg8=; b=Xy8zPZ1mkDRDwWpNt+xtwI3OZBQXPf09/dYPzF6c2Del8FLc2QBUg55g54Wnzii9Na w46iUt1BNXUABs9U+DpIp5CULtAIQHSivR6a8l4rcT8C4b2YnMyVtskMbh41DUsF+/IS sgFZY5Z3aR5B5LxhlxjAY18o92IgWhzqSrF2LqxeZzge3DN3FkmnvZzfVipE55tzc6Vw UpLdyaYfWiNJkbCBZC18yiT4eIM8OD9U1t4yVOIzfvbTzNQJaCtPt/GeaBbPpOGR3IK+ rYCLDTC2BQ51zOdkcs4J7vUycjZHqYPSkgTgu6d3dY5Pm8RgSY4s3hssSaC5xeiV/FCh /9xA==
Received​: (qmail 1298 invoked by uid 225); 23 Apr 2014 00​:33​:03 -0000
Received​: (qmail 1294 invoked by alias); 23 Apr 2014 00​:33​:03 -0000
Received​: from mail-qc0-f173.google.com (HELO mail-qc0-f173.google.com) (209.85.216.173) by la.mx.develooper.com (qpsmtpd/0.28) with ESMTP; Tue, 22 Apr 2014 17​:33​:01 -0700
Received​: by mail-qc0-f173.google.com with SMTP id r5so243082qcx.18 for <perlbug@​perl.org>; Tue, 22 Apr 2014 17​:32​:57 -0700 (PDT)
Received​: from Vredefort-2.local (23-25-193-161-static.hfc.comcastbusiness.net. [23.25.193.161]) by mx.google.com with ESMTPSA id v9sm81865933qav.28.2014.04.22.17.32.55 for <perlbug@​perl.org> (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Tue, 22 Apr 2014 17​:32​:55 -0700 (PDT)
Reply-To​: jhi@​iki.fi

From jhietaniemi@​gmail.com Wed Apr 23 00​:33​:03 2014
From​: Jarkko Hietaniemi <jhi@​iki.fi>
Return-Path​: <jhietaniemi@​gmail.com>
Return-Path​: <jhietaniemi@​gmail.com>
X-Spam-Status​: No, hits=-2.6 required=8.0 tests=BAYES_00,DKIM_SIGNED,DKIM_VALID,FREEMAIL_FROM,RCVD_IN_DNSWL_LOW,SPF_PASS
User-Agent​: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv​:24.0) Gecko/20100101 Thunderbird/24.4.0
X-Received​: by 10.140.101.45 with SMTP id t42mr37344758qge.32.1398213177808; Tue, 22 Apr 2014 17​:32​:57 -0700 (PDT)
Subject​: [PATCH] Coverity​: regcomp.c etc.
MIME-Version​: 1.0
To​: perlbug@​perl.org
Message-ID​: <53570A35.9080207@​iki.fi>
Delivered-To​: rt-perl5@​rt.perl.org
Delivered-To​: perlbug@​perl.org
Date​: Tue, 22 Apr 2014 20​:32​:53 -0400
Content-Type​: multipart/mixed; boundary="------------000502010901090509090305"
Sender​: "jhi@​iki.fi" <jhietaniemi@​gmail.com>
X-Virus-Checked​: Checked
X-Spam-Check-BY​: la.mx.develooper.com
X-RT-Interface​: Email

@p5pRT
Copy link
Author

p5pRT commented Apr 23, 2014

From @tonycoz

On Tue Apr 22 17​:33​:07 2014, jhi wrote​:

Needed compile-time limits for the PL_reg_intflags_name so that the
bit loop doesn't waltz off past the array. Could not use C_ARRAY_LENGTH
because the size of name array is not visible during compile time
(only const char*[] is), so modified regcomp.pl to generate the size,
made it visible only for the re extension. Did extflags analogously
even though its size currently exactly 32 already. The sizeof(flags)*8
is extra paranoia for ILP64.

Wouldn't the paranoia in​:

+ for (bit=0;
+ bit<REG_EXTFLAGS_NAME_SIZE && bit<sizeof(flags)*8;
+ bit++) {

be better handled with an assert? Even a compile-time assert if we had the mechanism for it.

Tony

@p5pRT
Copy link
Author

p5pRT commented Apr 23, 2014

The RT System itself - Status changed from 'new' to 'open'

@p5pRT
Copy link
Author

p5pRT commented Apr 23, 2014

From @jhi

I guess one could assert that the number of names is less than or equal to
the number of bits in U32, yes.
On Apr 22, 2014 9​:43 PM, "Tony Cook via RT" <perlbug-followup@​perl.org>
wrote​:

On Tue Apr 22 17​:33​:07 2014, jhi wrote​:

Needed compile-time limits for the PL_reg_intflags_name so that the
bit loop doesn't waltz off past the array. Could not use C_ARRAY_LENGTH
because the size of name array is not visible during compile time
(only const char*[] is), so modified regcomp.pl to generate the size,
made it visible only for the re extension. Did extflags analogously
even though its size currently exactly 32 already. The sizeof(flags)*8
is extra paranoia for ILP64.

Wouldn't the paranoia in​:

+ for (bit=0;
+ bit<REG_EXTFLAGS_NAME_SIZE && bit<sizeof(flags)*8;
+ bit++) {

be better handled with an assert? Even a compile-time assert if we had
the mechanism for it.

Tony

@p5pRT
Copy link
Author

p5pRT commented Apr 23, 2014

From @bulk88

On Tue Apr 22 18​:43​:07 2014, tonyc wrote​:

be better handled with an assert? Even a compile-time assert if we
had the mechanism for it.

Tony

Add one. For example


#define STATIC_ASSERT(expr) ((void)sizeof(char[1 - 2*!!!(expr)]))


from https://metacpan.org/source/BULKDD/Win32-API-0.77/API.h#L248

I've added new C compiler support macros before in ae103e0#diff-408899f5d0d5a90cdff082c8f0d0441aR3111 .

--
bulk88 ~ bulk88 at hotmail.com

@p5pRT
Copy link
Author

p5pRT commented Apr 23, 2014

From @hvds

There seems also to be a copy/paste in the comments​:
+# define REG_EXTFLAGS_NAME_SIZE $REG_EXTFLAGS_NAME_SIZE /* sizeof(PL_reg_intflags_name) */
+# define REG_EXTFLAGS_NAME_SIZE 32 /* sizeof(PL_reg_intflags_name) */

I assume both should s/int/ext/.

Hugo

@p5pRT
Copy link
Author

p5pRT commented Apr 23, 2014

From @jhi

On Wednesday-201404-23, 15​:06, Hugo van der Sanden via RT wrote​:

There seems also to be a copy/paste in the comments​:
+# define REG_EXTFLAGS_NAME_SIZE $REG_EXTFLAGS_NAME_SIZE /* sizeof(PL_reg_intflags_name) */
+# define REG_EXTFLAGS_NAME_SIZE 32 /* sizeof(PL_reg_intflags_name) */

I assume both should s/int/ext/.

Ah, yes. I'll reissue the patch. Where is my C compiler which proofreds
and insanity checks the comments?

Hugo

@p5pRT
Copy link
Author

p5pRT commented Apr 23, 2014

From @jhi

On Wednesday-201404-23, 4​:38, bulk88 via RT wrote​:

#define STATIC_ASSERT(expr) ((void)sizeof(char[1 - 2*!!!(expr)]))

Sir, please back away from the keyboard and keep your hands above your
head...

@p5pRT
Copy link
Author

p5pRT commented Apr 23, 2014

From @jhi

On Wednesday-201404-23, 15​:06, Hugo van der Sanden via RT wrote​:

There seems also to be a copy/paste in the comments​:
+# define REG_EXTFLAGS_NAME_SIZE $REG_EXTFLAGS_NAME_SIZE /* sizeof(PL_reg_intflags_name) */
+# define REG_EXTFLAGS_NAME_SIZE 32 /* sizeof(PL_reg_intflags_name) */

I assume both should s/int/ext/.

Hugo

The updated patch attached.

It also includes the suggestion to use assert(), though I went ahead and
used the new shiny ASSUME() -- please correct as appropriate, I might
have misunderstood ASSUME.

(Further change from the earlier incarnation is that the new symbols
are made visible under DEBUGGING, not PERL_EXT_RE_BUILD.)

@p5pRT
Copy link
Author

p5pRT commented Apr 23, 2014

From @jhi

0001-Fix-for-Coverity-perl5-CID-29034.patch
From e88c498f5375232e4e18339221c757af026f7b92 Mon Sep 17 00:00:00 2001
From: Jarkko Hietaniemi <jhi@iki.fi>
Date: Mon, 21 Apr 2014 21:43:12 -0400
Subject: [PATCH] Fix for Coverity perl5 CID 29034: Out-of-bounds read
 (OVERRUN) overrun-local: Overrunning array PL_reg_intflags name of 14 8-byte
 elements at element index 31 (byte offset 248) using index bit (which
 evaluates to 31).

Needed compile-time limits for the PL_reg_intflags_name so that the
bit loop doesn't waltz off past the array.  Could not use C_ARRAY_LENGTH
because the size of name array is not visible during compile time
(only const char*[] is), so modified regcomp.pl to generate the size,
made it visible only under DEBUGGING.  Did extflags analogously
even though its size currently exactly 32 already.  The sizeof(flags)*8
is extra paranoia for ILP64.
---
 regcomp.c        |  8 ++++++--
 regen/regcomp.pl | 17 ++++++++++++++++-
 regnodes.h       |  8 ++++++++
 3 files changed, 30 insertions(+), 3 deletions(-)

diff --git a/regcomp.c b/regcomp.c
index 0238af9..920f7cb 100644
--- a/regcomp.c
+++ b/regcomp.c
@@ -15365,7 +15365,9 @@ S_regdump_intflags(pTHX_ const char *lead, const U32 flags)
     int bit;
     int set=0;
 
-    for (bit=0; bit<32; bit++) {
+    ASSUME(REG_INTFLAGS_NAME_SIZE <= sizeof(flags)*8);
+
+    for (bit=0; bit<REG_INTFLAGS_NAME_SIZE; bit++) {
         if (flags & (1<<bit)) {
             if (!set++ && lead)
                 PerlIO_printf(Perl_debug_log, "%s",lead);
@@ -15387,7 +15389,9 @@ S_regdump_extflags(pTHX_ const char *lead, const U32 flags)
     int set=0;
     regex_charset cs;
 
-    for (bit=0; bit<32; bit++) {
+    ASSUME(REG_EXTFLAGS_NAME_SIZE <= sizeof(flags)*8);
+
+    for (bit=0; bit<REG_EXTFLAGS_NAME_SIZE; bit++) {
         if (flags & (1<<bit)) {
 	    if ((1<<bit) & RXf_PMf_CHARSET) {	/* Output separately, below */
 		continue;
diff --git a/regen/regcomp.pl b/regen/regcomp.pl
index 4a8b9d5..779545d 100644
--- a/regen/regcomp.pl
+++ b/regen/regcomp.pl
@@ -261,6 +261,7 @@ my %rxfv;
 my %definitions;    # Remember what the symbol definitions are
 my $val = 0;
 my %reverse;
+my $REG_EXTFLAGS_NAME_SIZE = 0;
 foreach my $file ("op_reg_common.h", "regexp.h") {
     open FH,"<$file" or die "Can't read $file: $!";
     while (<FH>) {
@@ -332,6 +333,7 @@ for (0..31) {
     s/\bRXf_(PMf_)?// for $n, $extra;
     printf $out qq(\t%-20s/* 0x%08x%s */\n),
         qq("$n",),$power_of_2, $extra;
+    $REG_EXTFLAGS_NAME_SIZE++;
 }  
  
 print $out <<EOP;
@@ -339,6 +341,12 @@ print $out <<EOP;
 #endif /* DOINIT */
 
 EOP
+print $out <<EOQ
+#ifdef DEBUGGING
+#  define REG_EXTFLAGS_NAME_SIZE $REG_EXTFLAGS_NAME_SIZE /* sizeof(PL_reg_extflags_name) */
+#endif
+
+EOQ
 }
 {
 print $out <<EOP;
@@ -354,6 +362,7 @@ my %rxfv;
 my %definitions;    # Remember what the symbol definitions are
 my $val = 0;
 my %reverse;
+my $REG_INTFLAGS_NAME_SIZE = 0;
 foreach my $file ("regcomp.h") {
     open my $fh, "<", $file or die "Can't read $file: $!";
     while (<$fh>) {
@@ -369,6 +378,7 @@ foreach my $file ("regcomp.h") {
             $comment= $comment ? " - $comment" : "";
 
             printf $out qq(\t%-30s/* 0x%08x - %s%s */\n), qq("$abbr",), $val, $define, $comment;
+            $REG_INTFLAGS_NAME_SIZE++;
         }
     }
 }
@@ -378,8 +388,13 @@ print $out <<EOP;
 #endif /* DOINIT */
 
 EOP
-}
+print $out <<EOQ;
+#ifdef DEBUGGING
+#  define REG_INTFLAGS_NAME_SIZE $REG_INTFLAGS_NAME_SIZE /* sizeof(PL_reg_intflags_name) */
+#endif
 
+EOQ
+}
 
 print $out process_flags('V', 'varies', <<'EOC');
 /* The following have no fixed length. U8 so we can do strchr() on it. */
diff --git a/regnodes.h b/regnodes.h
index 4f4ff9e..71cc205 100644
--- a/regnodes.h
+++ b/regnodes.h
@@ -676,6 +676,10 @@ EXTCONST char * const PL_reg_extflags_name[] = {
 };
 #endif /* DOINIT */
 
+#ifdef DEBUGGING
+#  define REG_EXTFLAGS_NAME_SIZE 32 /* sizeof(PL_reg_extflags_name) */
+#endif
+
 /* PL_reg_intflags_name[] - Opcode/state names in string form, for debugging */
 
 #ifndef DOINIT
@@ -699,6 +703,10 @@ EXTCONST char * const PL_reg_intflags_name[] = {
 };
 #endif /* DOINIT */
 
+#ifdef DEBUGGING
+#  define REG_INTFLAGS_NAME_SIZE 14 /* sizeof(PL_reg_intflags_name) */
+#endif
+
 /* The following have no fixed length. U8 so we can do strchr() on it. */
 #define REGNODE_VARIES(node) (PL_varies_bitmask[(node) >> 3] & (1 << ((node) & 7)))
 
-- 
1.9.2

@p5pRT
Copy link
Author

p5pRT commented Apr 29, 2014

From @tonycoz

On Wed Apr 23 16​:59​:42 2014, jhi wrote​:

On Wednesday-201404-23, 15​:06, Hugo van der Sanden via RT wrote​:

There seems also to be a copy/paste in the comments​:
+# define REG_EXTFLAGS_NAME_SIZE $REG_EXTFLAGS_NAME_SIZE /*
sizeof(PL_reg_intflags_name) */
+# define REG_EXTFLAGS_NAME_SIZE 32 /* sizeof(PL_reg_intflags_name)
*/

I assume both should s/int/ext/.

Hugo

The updated patch attached.

It also includes the suggestion to use assert(), though I went ahead
and
used the new shiny ASSUME() -- please correct as appropriate, I might
have misunderstood ASSUME.

(Further change from the earlier incarnation is that the new symbols
are made visible under DEBUGGING, not PERL_EXT_RE_BUILD.)

+#ifdef DEBUGGING
+# define REG_INTFLAGS_NAME_SIZE 14 /* sizeof(PL_reg_intflags_name) */
+#endif

It's not really sizeof(), but the element count.

Outside of that I think it's good.

Tony

@p5pRT
Copy link
Author

p5pRT commented Apr 29, 2014

From @jhi

On Monday-201404-28, 20​:32, Tony Cook via RT wrote​:

It's not really sizeof(), but the element count.

Do you want me to regen the patch (with the comment removed, I think)?

@p5pRT
Copy link
Author

p5pRT commented Apr 29, 2014

From @jhi

On Monday-201404-28, 20​:40, Jarkko Hietaniemi wrote​:

On Monday-201404-28, 20​:32, Tony Cook via RT wrote​:

It's not really sizeof(), but the element count.

Do you want me to regen the patch (with the comment removed, I think)?

Regened patch attached.

@p5pRT
Copy link
Author

p5pRT commented Apr 29, 2014

From @jhi

0001-Fix-for-Coverity-perl5-CID-29034.patch
From f287c8d21af3dc56b48ec8d7268d3d92c6688434 Mon Sep 17 00:00:00 2001
From: Jarkko Hietaniemi <jhi@iki.fi>
Date: Mon, 21 Apr 2014 21:43:12 -0400
Subject: [PATCH] Fix for Coverity perl5 CID 29034: Out-of-bounds read
 (OVERRUN) overrun-local: Overrunning array PL_reg_intflags name of 14 8-byte
 elements at element index 31 (byte offset 248) using index bit (which
 evaluates to 31).

Needed compile-time limits for the PL_reg_intflags_name so that the
bit loop doesn't waltz off past the array.  Could not use C_ARRAY_LENGTH
because the size of name array is not visible during compile time
(only const char*[] is), so modified regcomp.pl to generate the size,
made it visible only under DEBUGGING.  Did extflags analogously
even though its size currently exactly 32 already.  The sizeof(flags)*8
is extra paranoia for ILP64.
---
 regcomp.c        |  8 ++++++--
 regen/regcomp.pl | 17 ++++++++++++++++-
 regnodes.h       |  8 ++++++++
 3 files changed, 30 insertions(+), 3 deletions(-)

diff --git a/regcomp.c b/regcomp.c
index 0238af9..920f7cb 100644
--- a/regcomp.c
+++ b/regcomp.c
@@ -15365,7 +15365,9 @@ S_regdump_intflags(pTHX_ const char *lead, const U32 flags)
     int bit;
     int set=0;
 
-    for (bit=0; bit<32; bit++) {
+    ASSUME(REG_INTFLAGS_NAME_SIZE <= sizeof(flags)*8);
+
+    for (bit=0; bit<REG_INTFLAGS_NAME_SIZE; bit++) {
         if (flags & (1<<bit)) {
             if (!set++ && lead)
                 PerlIO_printf(Perl_debug_log, "%s",lead);
@@ -15387,7 +15389,9 @@ S_regdump_extflags(pTHX_ const char *lead, const U32 flags)
     int set=0;
     regex_charset cs;
 
-    for (bit=0; bit<32; bit++) {
+    ASSUME(REG_EXTFLAGS_NAME_SIZE <= sizeof(flags)*8);
+
+    for (bit=0; bit<REG_EXTFLAGS_NAME_SIZE; bit++) {
         if (flags & (1<<bit)) {
 	    if ((1<<bit) & RXf_PMf_CHARSET) {	/* Output separately, below */
 		continue;
diff --git a/regen/regcomp.pl b/regen/regcomp.pl
index 4a8b9d5..2b6d964 100644
--- a/regen/regcomp.pl
+++ b/regen/regcomp.pl
@@ -261,6 +261,7 @@ my %rxfv;
 my %definitions;    # Remember what the symbol definitions are
 my $val = 0;
 my %reverse;
+my $REG_EXTFLAGS_NAME_SIZE = 0;
 foreach my $file ("op_reg_common.h", "regexp.h") {
     open FH,"<$file" or die "Can't read $file: $!";
     while (<FH>) {
@@ -332,6 +333,7 @@ for (0..31) {
     s/\bRXf_(PMf_)?// for $n, $extra;
     printf $out qq(\t%-20s/* 0x%08x%s */\n),
         qq("$n",),$power_of_2, $extra;
+    $REG_EXTFLAGS_NAME_SIZE++;
 }  
  
 print $out <<EOP;
@@ -339,6 +341,12 @@ print $out <<EOP;
 #endif /* DOINIT */
 
 EOP
+print $out <<EOQ
+#ifdef DEBUGGING
+#  define REG_EXTFLAGS_NAME_SIZE $REG_EXTFLAGS_NAME_SIZE
+#endif
+
+EOQ
 }
 {
 print $out <<EOP;
@@ -354,6 +362,7 @@ my %rxfv;
 my %definitions;    # Remember what the symbol definitions are
 my $val = 0;
 my %reverse;
+my $REG_INTFLAGS_NAME_SIZE = 0;
 foreach my $file ("regcomp.h") {
     open my $fh, "<", $file or die "Can't read $file: $!";
     while (<$fh>) {
@@ -369,6 +378,7 @@ foreach my $file ("regcomp.h") {
             $comment= $comment ? " - $comment" : "";
 
             printf $out qq(\t%-30s/* 0x%08x - %s%s */\n), qq("$abbr",), $val, $define, $comment;
+            $REG_INTFLAGS_NAME_SIZE++;
         }
     }
 }
@@ -378,8 +388,13 @@ print $out <<EOP;
 #endif /* DOINIT */
 
 EOP
-}
+print $out <<EOQ;
+#ifdef DEBUGGING
+#  define REG_INTFLAGS_NAME_SIZE $REG_INTFLAGS_NAME_SIZE
+#endif
 
+EOQ
+}
 
 print $out process_flags('V', 'varies', <<'EOC');
 /* The following have no fixed length. U8 so we can do strchr() on it. */
diff --git a/regnodes.h b/regnodes.h
index 4f4ff9e..43ec681 100644
--- a/regnodes.h
+++ b/regnodes.h
@@ -676,6 +676,10 @@ EXTCONST char * const PL_reg_extflags_name[] = {
 };
 #endif /* DOINIT */
 
+#ifdef DEBUGGING
+#  define REG_EXTFLAGS_NAME_SIZE 32
+#endif
+
 /* PL_reg_intflags_name[] - Opcode/state names in string form, for debugging */
 
 #ifndef DOINIT
@@ -699,6 +703,10 @@ EXTCONST char * const PL_reg_intflags_name[] = {
 };
 #endif /* DOINIT */
 
+#ifdef DEBUGGING
+#  define REG_INTFLAGS_NAME_SIZE 14
+#endif
+
 /* The following have no fixed length. U8 so we can do strchr() on it. */
 #define REGNODE_VARIES(node) (PL_varies_bitmask[(node) >> 3] & (1 << ((node) & 7)))
 
-- 
1.9.2

@p5pRT
Copy link
Author

p5pRT commented Apr 30, 2014

From @tonycoz

On Tue Apr 29 05​:09​:17 2014, jhi wrote​:

On Monday-201404-28, 20​:40, Jarkko Hietaniemi wrote​:

On Monday-201404-28, 20​:32, Tony Cook via RT wrote​:

It's not really sizeof(), but the element count.

Do you want me to regen the patch (with the comment removed, I think)?

Regened patch attached.

Thanks, added as a 5.20 blocker and applied as adc2d0c.

Tony

@p5pRT
Copy link
Author

p5pRT commented Apr 30, 2014

@tonycoz - Status changed from 'open' to 'resolved'

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant