From: "Ivan \"Rambius\" Ivanov" Subject: Re: lang/gbc write overflow To: George Koehler Cc: ports@openbsd.org Date: Mon, 1 Apr 2024 08:36:08 -0400 Ok from me. On Wed, Mar 27, 2024, 7:04 PM George Koehler 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 > + >