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