gnome onda 3: las tres piezas de soporte de eds — libsecret, libxml2-shared, libuuid-shared

Leído el CMakeLists real de evolution-data-server 3.56.2, la frontera de la cima
son cuatro cosas, no una. Estas son tres; la cuarta (NSS) va aparte.

  libsecret 0.21.7  b3:b75607c6  CMakeLists:932 la mete en el pkg_check_modules
        (DATA_SERVER REQUIRED …) sin perilla, y libedataserver-1.2 es lo que
        gnome-shell enlaza. En gcr se la había esquivado con -Dssh_agent=false;
        acá no hay cómo: eds guarda ahí las credenciales de correo y calendario.
        -Dcrypto=libgcrypt de las tres del combo — gnutls no existe en el corpus
        y 'disabled' apagaría el cifrado justo en la pieza que guarda contraseñas.

  libxml2-shared    b3:87389636  en libical la libxml2 sólo la enlazaba un binario
        de build y bastó la .a canónica; en eds entra en cuatro .so reales
        (CMakeLists:932,936,937,938) y la .a no es PIC. Mismos patches de CVE que
        la canónica: la superficie de seguridad no diverge.

  libuuid-shared    b3:d42cf850  `uuid` es REQUERIDA (:424). No es un
        "util-linux-shared": --disable-all-programs apaga los ~100 binarios y deja
        una sola librería. Duplicar la lista de --without-* del canónico para
        conseguir un .so de 30 KB sería mantener esa superficie en dos lugares.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-28 20:04:14 -04:00
co-authored by Claude Opus 5
parent 98932ec477
commit fd73295c94
5 changed files with 249 additions and 0 deletions
@@ -0,0 +1,84 @@
--- a/testparser.c
+++ b/testparser.c
@@ -11,6 +11,7 @@
#include <libxml/xmlreader.h>
#include <libxml/xmlwriter.h>
#include <libxml/HTMLparser.h>
+#include <libxml/xmlschemas.h>
#include <string.h>
@@ -777,6 +778,63 @@
}
#endif /* WIN32 */
+#if defined(LIBXML_READER_ENABLED) && defined(LIBXML_SCHEMAS_ENABLED)
+/*
+ * Regression test for CVE-2026-6732: a type confusion in xmlParseReference
+ * crashed a schema-validating xmlTextReader whenever the document expanded
+ * an internal entity. Without the fix this triggers SIGSEGV on the first
+ * read; with the fix the entity expansion is read and the schema correctly
+ * reports the substituted content as invalid against xs:integer.
+ *
+ * Backport of upstream commit 7cea3fd1 adapted for the libxml2 2.13
+ * testparser.c layout (which predates the testReaderSchemaResourceLoader
+ * helper that upstream uses as an anchor on master).
+ */
+static int
+testReaderSchemaEntityExpansion(void) {
+ static const char xsd[] =
+ "<?xml version='1.0'?>\n"
+ "<xs:schema xmlns:xs='http://www.w3.org/2001/XMLSchema'>\n"
+ " <xs:element name='e' type='xs:integer'/>\n"
+ "</xs:schema>\n";
+ static const char xml[] =
+ "<!DOCTYPE e [<!ENTITY n \"not-an-int\">]>\n"
+ "<e>&n;</e>";
+ xmlSchemaParserCtxtPtr spc;
+ xmlSchemaPtr schema;
+ xmlTextReaderPtr reader;
+ int err = 0;
+ int ret;
+
+ spc = xmlSchemaNewMemParserCtxt(xsd, (int) sizeof(xsd) - 1);
+ schema = xmlSchemaParse(spc);
+ xmlSchemaFreeParserCtxt(spc);
+ if (schema == NULL) {
+ fprintf(stderr, "xmlSchemaParse failed\n");
+ return 1;
+ }
+
+ reader = xmlReaderForMemory(xml, (int) sizeof(xml) - 1, "doc.xml", NULL,
+ XML_PARSE_NOENT | XML_PARSE_DTDLOAD);
+ xmlTextReaderSetSchema(reader, schema);
+
+ while ((ret = xmlTextReaderRead(reader)) == 1)
+ ;
+ if (ret != 0) {
+ fprintf(stderr, "reader failed on entity-expanded document\n");
+ err = 1;
+ }
+ if (xmlTextReaderIsValid(reader) != 0) {
+ fprintf(stderr, "schema missed invalid entity-expanded text\n");
+ err = 1;
+ }
+
+ xmlFreeTextReader(reader);
+ xmlSchemaFree(schema);
+ return err;
+}
+#endif
+
int
main(void) {
int err = 0;
@@ -807,6 +865,9 @@
#ifdef LIBXML_XINCLUDE_ENABLED
err |= testReaderXIncludeError();
#endif
+#ifdef LIBXML_SCHEMAS_ENABLED
+ err |= testReaderSchemaEntityExpansion();
+#endif
#endif
#ifdef LIBXML_WRITER_ENABLED
err |= testWriterClose();
@@ -0,0 +1,32 @@
diff --git a/parser.c b/parser.c
index 6e7621a86b5b9256b7a068f09a7e1650e7264aa5..85bc39b1c2739574ab90fde34a24459e5ef9928f 100644
--- a/parser.c
+++ b/parser.c
@@ -7261,10 +7261,10 @@ xmlParseReference(xmlParserCtxt *ctxt) {
if ((cur->type == XML_TEXT_NODE) ||
(ctxt->options & XML_PARSE_NOCDATA)) {
if (ctxt->sax->characters != NULL)
- ctxt->sax->characters(ctxt, cur->content, len);
+ ctxt->sax->characters(ctxt->userData, cur->content, len);
} else {
if (ctxt->sax->cdataBlock != NULL)
- ctxt->sax->cdataBlock(ctxt, cur->content, len);
+ ctxt->sax->cdataBlock(ctxt->userData, cur->content, len);
}
cur = cur->next;
@@ -7284,10 +7284,12 @@ xmlParseReference(xmlParserCtxt *ctxt) {
if ((cur->type == XML_TEXT_NODE) ||
(ctxt->options & XML_PARSE_NOCDATA)) {
if (ctxt->sax->characters != NULL)
- ctxt->sax->characters(ctxt, cur->content, len);
+ ctxt->sax->characters(ctxt->userData, cur->content,
+ len);
} else {
if (ctxt->sax->cdataBlock != NULL)
- ctxt->sax->cdataBlock(ctxt, cur->content, len);
+ ctxt->sax->cdataBlock(ctxt->userData, cur->content,
+ len);
}
break;
+41
View File
@@ -0,0 +1,41 @@
# libsecret 0.21.7 — cliente de la Secret Service API (contraseñas guardadas en el llavero).
#
# Vuelve a la campaña por la puerta de atrás. En gcr se la esquivó a propósito (-Dssh_agent=false la
# sacaba de la frontera, ver el comentario de gcr.toml), pero evolution-data-server la pide DURA:
# CMakeLists.txt:932 la mete en el pkg_check_modules(DATA_SERVER REQUIRED …) junto a gio y libsoup,
# sin perilla. Y libedataserver-1.2 es exactamente lo que gnome-shell enlaza (meson.build:73). O sea
# que esta vez no hay cómo apagarla: eds guarda ahí las credenciales de las cuentas de correo y
# calendario, que es literalmente su trabajo.
#
# -Dcrypto=libgcrypt de las tres opciones del combo ('libgcrypt','gnutls','disabled'): libgcrypt ya
# está sellada y en variante -shared; gnutls no existe en el corpus. Con 'disabled' libsecret deja de
# cifrar la memoria de los secretos en tránsito, que es justo lo que no se quiere apagar en la pieza
# que guarda contraseñas.
#
# Apagados y lo que compran:
# -Dtpm2=false → tss2/tpm2-tss, tres recetas que nadie más pide.
# -Dpam=false → linux-pam; arje-zero no usa PAM (no hay sesión PAM que rellenar).
# -Dmanpage=false -Dgtk_doc=false → xsltproc + docbook-xsl + gi-docgen.
# -Dvapi=false → no hay valac en el corpus.
# -Dbash_completion=disabled → sólo instala un fichero de completado; no cambia la librería.
#
# ISLA DINÁMICA: -Dintrospection=true y shared. eds expone typelibs y su cierre pasa por acá.
name = "libsecret"
version = "0.21.7"
[source]
tarball = "https://download.gnome.org/sources/libsecret/0.21/libsecret-0.21.7.tar.xz"
sha256 = "6b452e4750590a2b5617adc40026f28d2f4903de15f1250e1d1c40bfd68ed55e"
[build]
compiler = "zig-cc"
target = "x86_64-linux-musl"
link = "dynamic"
[build.phases]
configure = "PKG_CONFIG_PATH=/usr/lib/pkgconfig PYTHONPATH=/usr/lib/python3.12/site-packages meson setup output --prefix=/usr --buildtype=release --wrap-mode=nodownload -Ddefault_library=shared -Dcrypto=libgcrypt -Dtpm2=false -Dpam=false -Dmanpage=false -Dgtk_doc=false -Dvapi=false -Dbash_completion=disabled -Dintrospection=true -Dc_args=-Wno-error=date-time"
compile = "PYTHONPATH=/usr/lib/python3.12/site-packages ninja -C output"
install = "PYTHONPATH=/usr/lib/python3.12/site-packages DESTDIR=/out meson install -C output --no-rebuild"
[deps]
build = ["meson", "samurai", "python3", "pkgconf", "gettext-tiny", "py3-setuptools", "gi-foreign-girs", "gobject-introspection", "glib", "glib-introspected", "libgcrypt-shared", "libgpg-error-shared", "libffi", "pcre2", "zlib-shared"]
@@ -0,0 +1,51 @@
# libuuid-shared 2.42.2 — SÓLO libuuid.so del tarball de util-linux, para la isla dinámica.
#
# evolution-data-server pide `uuid` como REQUERIDA (CMakeLists.txt:424) para generar los UID de
# contactos y eventos. El util-linux canónico la provee, pero es `--disable-shared --enable-static`
# y su libuuid.a no es PIC (verificado) ⇒ no entra en libedataserver.so.
#
# La variante NO reconstruye util-linux entero: --disable-all-programs apaga los ~100 binarios
# (mount, fdisk, lsblk…) y --enable-libuuid deja exactamente una librería. Es deliberado que esta
# receta sea angosta y no un "util-linux-shared": el canónico tiene un radio grande y una lista
# larga de --without-* elegidos para el userland estático; duplicar todo eso para conseguir un .so
# de 30 KB sería copiar una superficie que después hay que mantener en dos lugares.
#
# El sed de -mcpu=baseline se conserva del canónico: zig cc traduce ese flag a un `-mcpu=` VACÍO en
# modo preprocesador (`-dM -E -`) y los generadores errnos.h/syscalls.h lo invocan así.
name = "libuuid-shared"
version = "2.42.2"
[source]
tarball = "https://www.kernel.org/pub/linux/utils/util-linux/v2.42/util-linux-2.42.2.tar.xz"
sha256 = "03a05d3adf9602ef128f2da05b84b3205ce60c351e5737c0370f74000679ce8a"
[build]
compiler = "zig-cc"
target = "x86_64-linux-musl"
link = "dynamic"
flags = []
[build.phases]
configure = '''
./configure \
--build=$CBUILD --host=$CHOST \
--prefix=/usr \
--enable-shared --disable-static \
--disable-all-programs \
--enable-libuuid \
--disable-nls --disable-rpath \
--without-python --without-systemd --without-systemdsystemunitdir \
--without-udev --without-ncursesw --without-ncurses --without-tinfo \
--without-readline --without-libz --without-selinux --without-audit --without-econf
'''
compile = '''
for f in tools/all_errnos tools/all_syscalls; do
[ -f "$f" ] || continue
sed -i 's#^"$@" -MD#a=(); for x in "$@"; do [ "$x" = "-mcpu=baseline" ] || a+=("$x"); done\n"${a[@]}" -MD#' "$f"
done
make -j"$(nproc)"
'''
install = 'make DESTDIR=/out install'
[deps]
build = ["linux-headers", "make", "pkgconf"]
@@ -0,0 +1,41 @@
# libxml2-shared 2.13.9 — variante DINÁMICA de libxml2 para la isla dinámica de GNOME.
#
# Por qué existe, y por qué NO existía hasta ahora: en libical la libxml2 sólo la enlazaba un
# ejecutable de build (ical-glib-src-generator), así que la .a canónica alcanzó. En
# evolution-data-server NO: libxml-2.0 es dep REQUERIDA de libedataserver, libebackend, libebook y
# libecal (CMakeLists.txt:932,936,937,938), o sea que entra dentro de .so reales. La libxml2.a
# canónica no es PIC (verificado: reubicaciones R_X86_64_32) ⇒ mismo muro que sqlite y freetype.
#
# Mismo tarball, misma versión y MISMOS patches de CVE que la canónica: no se abre skew entre el
# mundo estático y el dinámico, y la superficie de seguridad es idéntica. Los .patch están copiados
# a esta cola porque se resuelven contra el base_dir de la receta, no contra recipes/.
#
# Se mantienen --without-{python,lzma,zlib} de la canónica: eds parsea XML, no comprime.
name = "libxml2-shared"
version = "2.13.9"
[source]
tarball = "https://download.gnome.org/sources/libxml2/2.13/libxml2-2.13.9.tar.xz"
sha256 = "a2c9ae7b770da34860050c309f903221c67830c86e4a7e760692b803df95143a"
patches = ["CVE-2026-6732.patch", "CVE-2026-6732-test.patch"]
[build]
compiler = "zig-cc"
target = "x86_64-linux-musl"
link = "dynamic"
flags = []
[build.phases]
configure = '''
./configure \
--build=$CBUILD --host=$CHOST \
--prefix=/usr \
--enable-shared --disable-static \
--without-python --without-lzma --without-zlib \
--with-legacy
'''
compile = 'make -j"$(nproc)"'
install = 'make DESTDIR=/out install'
[deps]
build = ["make", "pkgconf"]