Index | Thread | Search

From:
George Koehler <kernigh@gmail.com>
Subject:
lang/gbc write overflow
To:
ports@openbsd.org
Cc:
Ivan Ivanov <rambiusparkisanius@gmail.com>
Date:
Wed, 27 Mar 2024 19:04:28 -0400

Download raw body.

Thread
Here's a diff to fix GNU bc 1.07.1 in OpenBSD ports.

Wrong code in bc/scan.c was using (yy_size_t *)&result to write to an
int.  This was an overflow on LP64_ARCHS, by writing 8 bytes to a
4-byte int.  The problem was more obvious when big-endian.

If we would read 51 bytes,
 - a little-endian amd64 would write (int []){51, 0}, so result = 51
   was correct, but the extra 0 clobbered 4 bytes of other memory.
 - my big-endian powerpc64 wrote (int []){0, 51}, so result = 0 caused
   an early end of file.  This broke my powerpc64 build when bc tried
   to compile its math library, but the compiled code was empty.

The new patch does "result = ...", so the C compiler writes the
correct size.  Now my powerpc64 can package and run gbc.

The patch causes flex(1) to remake scan.c from scan.l.  OpenBSD's
flex changes result from int to yy_size_t, but "result = ..." should
work with either type.  (When I tried (int *)&result, I built a broken
bc that wrote 4 bytes to an 8-byte size.)

Also delete BROKEN-sparc64, but I don't have a sparc64.  I suspect
that (yy_size_t *)&result was not a multiple of 8 and raised a SIGBUS
for misalignment on sparc64, but I don't know.

ok?

Index: Makefile
===================================================================
RCS file: /cvs/ports/math/gbc/Makefile,v
diff -u -p -r1.6 Makefile
--- Makefile	27 Sep 2023 09:27:54 -0000	1.6
+++ Makefile	27 Mar 2024 22:04:45 -0000
@@ -1,9 +1,7 @@
-BROKEN-sparc64 =	Bus error during build
-
 COMMENT =	GNU version of the arbitrary precision calculators bc and dc
 DISTNAME =	bc-1.07.1
 PKGNAME =	g${DISTNAME}
-REVISION =	0
+REVISION =	1
 CATEGORIES =	math
 
 HOMEPAGE =	https://www.gnu.org/software/bc/
Index: patches/patch-bc_scan_l
===================================================================
RCS file: patches/patch-bc_scan_l
diff -N patches/patch-bc_scan_l
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ patches/patch-bc_scan_l	27 Mar 2024 22:04:45 -0000
@@ -0,0 +1,74 @@
+The cast (yy_size_t *)&result was wrong, because result was an int in
+upstream's flex; this caused an overflow on LP64_ARCHS (by writing 8
+bytes to a 4-byte int), which broke the build on powerpc64.
+
+This patch causes the build to run flex(1), overwriting scan.c from
+upstream.  OpenBSD's flex changes result from int to yy_size_t.
+
+Index: bc/scan.l
+--- bc/scan.l.orig
++++ bc/scan.l
+@@ -59,7 +59,7 @@ int yywrap (void);
+ /* Have input call the following function. */
+ #undef  YY_INPUT
+ #define YY_INPUT(buf,result,max_size) \
+-		bcel_input((char *)buf, (yy_size_t *)&result, max_size)
++		result = bcel_input((char *)buf, max_size)
+ 
+ /* Variables to help interface editline with bc. */
+ static const char *bcel_line = (char *)NULL;
+@@ -70,10 +70,11 @@ static int   bcel_len = 0;
+    stdin, use editline.  Otherwise, just read it.
+ */
+ 
+-static void
+-bcel_input (char *buf, yy_size_t  *result, int max)
++static int
++bcel_input (char *buf, int max)
+ {
+   ssize_t rdsize;
++  int result;
+   if (!edit || yyin != stdin)
+     {
+       while ( (rdsize = read( fileno(yyin), buf, max )) < 0 )
+@@ -82,8 +83,7 @@ bcel_input (char *buf, yy_size_t  *result, int max)
+ 	    yyerror( "read() in flex scanner failed" );
+ 	    bc_exit (1);
+ 	  }
+-      *result = (yy_size_t) rdsize;
+-      return;
++      return rdsize;
+     }
+ 
+   /* Do we need a new string? */
+@@ -92,9 +92,8 @@ bcel_input (char *buf, yy_size_t  *result, int max)
+       bcel_line = el_gets(edit, &bcel_len);
+       if (bcel_line == NULL) {
+ 	/* end of file */
+-	*result = 0;
+ 	bcel_len = 0;
+-	return;
++	return 0;
+       }
+       if (bcel_len != 0)
+ 	history (hist, &histev, H_ENTER, bcel_line); 
+@@ -104,16 +103,17 @@ bcel_input (char *buf, yy_size_t  *result, int max)
+   if (bcel_len <= max)
+     {
+       strncpy (buf, bcel_line, bcel_len);
+-      *result = bcel_len;
++      result = bcel_len;
+       bcel_len = 0;
+     }
+   else
+     {
+       strncpy (buf, bcel_line, max);
+-      *result = max;
++      result = max;
+       bcel_line += max;
+       bcel_len -= max;
+     }
++  return result;
+ }
+ #endif
+