On Mon, Jun 23, 2025 at 12:02:31 +0100, Daniel P. Berrangé via Devel wrote:
> From: Daniel P. Berrangé <berra...@redhat.com>
> 
> The main XML parser code global initializer historically had a mutex
> protecting it, and more recently uses a pthread_once. The RelaxNG
> code, however, relies on three other global initializers that are
> not thread safe, just relying on setting an integer "initialized"
> flag.
> 
> Calling the relevant initializers from libvirt in a protected global
> initializer will protect libvirt's own concurrent usage, however, it
> cannot protect against other libraries loaded in process that might
> be using libxml2's schema code. Fortunately:
> 
>  * The chances of other loaded non-libvirt code using libxml is
>    relatively low
>  * The chances of other loaded non-libvirt code using the schema
>    validation / catalog functionality inside libxml is even
>    lower
>  * The chances of both libvirt and the non-libvirt usage having
>    their *1st* usage of libxml2 be concurrent is tiny

Additionaly IIUC this could be problem only when using the embedded
driver mode as we don't use libxml2 in the exported API

> IOW, in practice, although our solution doesn't fully fix the thread
> safety, it is good enough.
> 
> libxml2 should none the less still be fixed to make its global
> initializers be thread safe without special actions by its API
> consumers.
> 
> Resolves: https://gitlab.com/libvirt/libvirt/-/issues/788
> Signed-off-by: Daniel P. Berrangé <berra...@redhat.com>
> ---
>  src/util/virxml.c | 25 +++++++++++++++++++++++++
>  1 file changed, 25 insertions(+)
> 
> diff --git a/src/util/virxml.c b/src/util/virxml.c
> index 9d46e5f32f..c2d5a109dc 100644
> --- a/src/util/virxml.c
> +++ b/src/util/virxml.c
> @@ -26,6 +26,8 @@
>  
>  #include <libxml/xmlsave.h>
>  #include <libxml/xpathInternals.h>
> +#include <libxml/xmlschemastypes.h>
> +#include <libxml/catalog.h>
>  
>  #include "virerror.h"
>  #include "virxml.h"
> @@ -35,6 +37,7 @@
>  #include "virstring.h"
>  #include "virutil.h"
>  #include "viruuid.h"
> +#include "virthread.h"
>  #include "configmake.h"
>  
>  #define VIR_FROM_THIS VIR_FROM_XML
> @@ -50,6 +53,25 @@ struct virParserData {
>  };
>  
>  
> +static int virXMLSchemaOnceInit(void)

Please use the preferred style of return type on it's own line.

> +{
> +    if (xmlSchemaInitTypes() < 0) {
> +        virReportError(VIR_ERR_INTERNAL_ERROR,
> +                       _("Unable to initialize libxml2 schema types"));
> +        return -1;
> +    }
> +    if (xmlRelaxNGInitTypes() < 0) {
> +        virReportError(VIR_ERR_INTERNAL_ERROR,
> +                       _("Unable to initialize libxml2 RelaxNG data"));
> +        return -1;
> +    }
> +    /* No return value, it just ignores errors :-( */
> +    xmlInitializeCatalog();
> +    return 0;
> +}
> +
> +VIR_ONCE_GLOBAL_INIT(virXMLSchema);
> +
>  static xmlXPathContextPtr
>  virXMLXPathContextNew(xmlDocPtr xml)
>  {
> @@ -1603,6 +1625,9 @@ virXMLValidatorInit(const char *schemafile)
>  {
>      g_autoptr(virXMLValidator) validator = NULL;
>  
> +    if (virXMLSchemaInitialize() < 0)
> +        return NULL;
> +
>      validator = g_new0(virXMLValidator, 1);
>  
>      validator->schemafile = g_strdup(schemafile);
> -- 
> 2.49.0
> 

Reviewed-by: Peter Krempa <pkre...@redhat.com>

Reply via email to