Index | Thread | Search

From:
"Ivan \"Rambius\" Ivanov" <rambiusparkisanius@gmail.com>
Subject:
Re: lang/gbc write overflow
To:
George Koehler <kernigh@gmail.com>
Cc:
ports@openbsd.org
Date:
Mon, 1 Apr 2024 08:36:08 -0400

Download raw body.

Thread
Ok from me.

On Wed, Mar 27, 2024, 7:04 PM George Koehler <kernigh@gmail.com> wrote:

> 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
> +
>