Re: [PATCH v3] libio: Fix CVE-2026-18374 heap buffer overflow in ccs= handling

Florian Weimer <[email protected]>
Newsgroups gmane.comp.lib.glibc.alpha
Message-ID <[email protected]>
* 손동균:

> When fopen is called with a ,ccs= specification whose value is not empty
> but becomes empty after strip() (for example "r,ccs=/,..."), the code took
> the fallback branch
>
>     __wcsmbs_named_conv (&fcts, ccs[2] == '\0' ? upstr (ccs, cs + 5) : ccs)
>
> and upstr() copied from cs + 5 up to the terminating NUL of the whole mode
> string -- past the ',' delimiter at endp -- into ccs, which is only
> allocated for endp - (cs + 5) + 3 bytes.  This overflows the heap buffer.
>
> Checking for an empty ccs= token before strip() (as an earlier attempt did)
> does not help, because in the reproducer the token is only empty after
> strip(), not before.
>
> Bound the fallback copy to the [cs + 5, endp) charset token so it can no
> longer read past the delimiter.  A specification that is empty after
> strip() has no valid charset name and keeps failing with EINVAL from
> __wcsmbs_named_conv.
>
> A regression test that reproduces the overflow (and the trivial empty
> ,ccs= case) is added to libio/tst-fopenloc.c.
>
> CVE-2026-18374 - CVSS 4.9 (AV:L/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L)
> Reported-by: AISLE in partnership with Red Hat
> Signed-off-by: Dongkyun Son <[email protected]>

Please add a reference to bug 34574 to the commit message.

> diff --git a/libio/fileops.c b/libio/fileops.c
> index 9348d7c3a1..f42588a94f 100644
> --- a/libio/fileops.c
> +++ b/libio/fileops.c
> @@ -355,8 +355,19 @@ _IO_new_file_fopen (FILE *fp, const char *filename, const char *mode,
>  	  *((char *) __mempcpy (ccs, cs + 5, endp - (cs + 5))) = '\0';
>  	  strip (ccs, ccs);
>  
> -	  if (__wcsmbs_named_conv (&fcts, ccs[2] == '\0'
> -				   ? upstr (ccs, cs + 5) : ccs) != 0)
> +	  /* If strip() reduced the specification to the empty string (leaving
> +	     only the "//" that strip() always appends), fall back to the
> +	     original charset name.  Bound the copy by ENDP so we do not read
> +	     past the ',' delimiter and overflow CCS (CVE-2026-18374).  */
> +	  if (ccs[2] == '\0')
> +	    {
> +	      char *wp = ccs;
> +	      for (const char *rp = cs + 5; rp < endp; ++rp)
> +		*wp++ = __toupper_l (*rp, _nl_C_locobj_ptr);
> +	      *wp = '\0';
> +	    }

I think the idea to return EINVAL in case the ccs= argument is
(effectively) empty was the right approach.  No need to convert the
widespace to upper case.

> diff --git a/libio/tst-fopenloc.c b/libio/tst-fopenloc.c
> index ea3f7b5265..5ce3bc5abb 100644
> --- a/libio/tst-fopenloc.c
> +++ b/libio/tst-fopenloc.c
> @@ -85,6 +85,54 @@ do_bz18906 (void)
>    return EXIT_SUCCESS;
>  }
>  
> +static int
> +do_cve_2026_18374 (void)
> +{
> +  /* CVE-2026-18374 -- a ,ccs= specification that is not empty but becomes
> +     empty after strip() must not make fopen read past the ',' delimiter and
> +     overflow the heap buffer.  It has to fail cleanly with EINVAL.  */

I would recommend adding a new test, adapted from the reproducer on the
bug.  It can open /dev/null for reading, and it should expect the EINVAL
failure.

If you don't want to write an actual heap overflow, I can add the new
test in a separate commit.

Thanks,
Florian
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.