From nobody Fri May 17 23:08:22 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of redhat.com designates 170.10.133.124 as permitted sender) client-ip=170.10.133.124; envelope-from=libvir-list-bounces@redhat.com; helo=us-smtp-delivery-124.mimecast.com; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of redhat.com designates 170.10.133.124 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1663947746; cv=none; d=zohomail.com; s=zohoarc; b=Wf1cugO/Ag1xa1O0yMLiAPWJ4Stpvv0/XYb9kjo/1UI1l+Xy03/BqaaB0nB7qctm3OQKsJuvLojpojmmZC5vYzuckkJccA2xn0vkxGEGt/Wr94qtCdXgwdUumVw3WDh028E8aixJj/ohdRjcwGyd1ZAlYL3I/QBjuwaJFiBfigs= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1663947746; h=Content-Type:Content-Transfer-Encoding:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=816tiHOHtxBgEeSP67p0mfK+0e2HVDlQPzbYUuqPDgM=; b=lFbI3FwrxF+Fo8mkHrt1k0JsUAn4CkoYNgQwcc1OlnaVo0bzna1vyVeCRCZhVyDHKiwEtMu3l8IXMDnMVfp6RGIW8s5a8m2PKQAv+y2Wke/wx4mBS2/+y2pgcDZL3WtzHb5e79JtYlOAX+Kqd26zVMF1w105wWNUKyzQES3KI7A= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of redhat.com designates 170.10.133.124 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by mx.zohomail.com with SMTPS id 1663947746704755.3776478815682; Fri, 23 Sep 2022 08:42:26 -0700 (PDT) Received: from mimecast-mx02.redhat.com (mx3-rdu2.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-86-Glh9eD7bMzaE8Uoi55TzyQ-1; Fri, 23 Sep 2022 11:42:23 -0400 Received: from smtp.corp.redhat.com (int-mx10.intmail.prod.int.rdu2.redhat.com [10.11.54.10]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id ADFA33810787; Fri, 23 Sep 2022 15:42:20 +0000 (UTC) Received: from mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (unknown [10.30.29.100]) by smtp.corp.redhat.com (Postfix) with ESMTP id 9BB27492B05; Fri, 23 Sep 2022 15:42:20 +0000 (UTC) Received: from mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (localhost [IPv6:::1]) by mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (Postfix) with ESMTP id 5A92719465B6; Fri, 23 Sep 2022 15:42:20 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) by mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (Postfix) with ESMTP id 9307819465A4 for ; Fri, 23 Sep 2022 15:42:19 +0000 (UTC) Received: by smtp.corp.redhat.com (Postfix) id 866A51121314; Fri, 23 Sep 2022 15:42:19 +0000 (UTC) Received: from speedmetal.lan (unknown [10.40.208.35]) by smtp.corp.redhat.com (Postfix) with ESMTP id 528331121315 for ; Fri, 23 Sep 2022 15:42:17 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1663947745; h=from:from:sender:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:list-id:list-help: list-unsubscribe:list-subscribe:list-post; bh=816tiHOHtxBgEeSP67p0mfK+0e2HVDlQPzbYUuqPDgM=; b=hWpgmfiV5qJJTArriIQvx95lVoawfw12zes3aHo8wxaPRJmmCDPxAQt0+Q5iKzpOmob24Y 6WEI5E3Z9Q/4930lhhd6ovYlYLDO6wrJsuDeVLdlHkEMfReN1Z3vqiZgaMNnqjETXnyVL2 olTm+p/jeFmfUrFrGWiSgglOrpIvr8E= X-MC-Unique: Glh9eD7bMzaE8Uoi55TzyQ-1 X-Original-To: libvir-list@listman.corp.redhat.com From: Peter Krempa To: libvir-list@redhat.com Subject: [PATCH 1/2] util: xml: Introduce infrastructure to support custom XML validators Date: Fri, 23 Sep 2022 17:42:12 +0200 Message-Id: In-Reply-To: References: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.1 on 10.11.54.3 X-BeenThere: libvir-list@redhat.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Development discussions about the libvirt library & tools List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libvir-list-bounces@redhat.com Sender: "libvir-list" X-Scanned-By: MIMEDefang 3.1 on 10.11.54.10 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1663947747719100002 Content-Type: text/plain; charset="utf-8" The XML from libxml2 we use in libvirt has in many cases very bad error messages, which make it very difficult to point to the specific problem with the validated XML. This patch adds infrastructure which will allow users to specify a custom XML validator program which will be used to validate the XML before we invoke libxml's validator. The configuration is done via a global variable as normally the daemon config is not accessible from inside the runtime. Signed-off-by: Peter Krempa Reviewed-by: Michal Privoznik --- src/libvirt_private.syms | 1 + src/util/virxml.c | 93 +++++++++++++++++++++++++++++++++++++++- src/util/virxml.h | 3 ++ 3 files changed, 95 insertions(+), 2 deletions(-) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 25794bc2f4..3e90cd4599 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -3678,6 +3678,7 @@ virXMLNodeNameEqual; virXMLNodeSanitizeNamespaces; virXMLNodeToString; virXMLParseHelper; +virXMLParseSetCustomValidator; virXMLPickShellSafeComment; virXMLPropEnum; virXMLPropEnumDefault; diff --git a/src/util/virxml.c b/src/util/virxml.c index d6e2e5dd91..aea9b3aac3 100644 --- a/src/util/virxml.c +++ b/src/util/virxml.c @@ -33,6 +33,7 @@ #include "virfile.h" #include "virstring.h" #include "virutil.h" +#include "vircommand.h" #include "configmake.h" #define VIR_FROM_THIS VIR_FROM_XML @@ -41,6 +42,8 @@ virReportErrorHelper(from, code, __FILE__, \ __FUNCTION__, __LINE__, __VA_ARGS__) +static char *virXMLCustomValidatorPath; + /* Internal data to be passed to SAX parser and used by error handler. */ struct virParserData { int domcode; @@ -1029,6 +1032,68 @@ catchXMLError(void *ctx, const char *msg G_GNUC_UNUS= ED, ...) } } + +/** + * virXMLParseHelperValidateCustom: + * + * Invokes an external validator program configured in the + * 'virXMLCustomValidatorPath' global variable and captures the validation + * output. The program is invoked as: + * + * /path/to/program /path/to/schema + * + * The XML to validate is fed on stdin of the program. The program is expe= cted + * to return 0 on successful validation and non-zero on failure to validat= e, + * in which case STDOUT of the program is used in the error message report= ed + * by libvirt. + */ +static int +virXMLParseHelperValidateCustom(const char *schema, + const char *filename, + const char *xmlStr) +{ + g_autoptr(virCommand) cmd =3D virCommandNewArgList(virXMLCustomValidat= orPath, + schema, NULL); + g_autofree char *filebuf =3D NULL; + g_autofree char *outbuf =3D NULL; + int exitstatus =3D 0; + + if (filename) { + /* virsh uses 10 MiB as max XML size */ + if (virFileReadAll(filename, 10 * 1024 * 1024, &filebuf) < 0) + return -1; + + xmlStr =3D filebuf; + } + + if (!virFileIsExecutable(virXMLCustomValidatorPath)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("custom XML validator program '%s' is not executa= ble"), + virXMLCustomValidatorPath); + return -1; + } + + virCommandSetInputBuffer(cmd, xmlStr); + virCommandSetOutputBuffer(cmd, &outbuf); + virCommandDoAsyncIO(cmd); + + if (virCommandRunAsync(cmd, NULL) < 0) + return -1; + + if (virCommandWait(cmd, &exitstatus) < 0) + return -1; + + if (exitstatus !=3D 0) { + virReportError(VIR_ERR_XML_INVALID_SCHEMA, + _("Unable to validate doc against %s\n%s"), + schema, outbuf); + return -1; + } + + return 0; +} + + /** * virXMLParseHelper: * @domcode: error domain of the caller, usually VIR_FROM_THIS @@ -1126,8 +1191,14 @@ virXMLParseHelper(int domcode, g_autofree char *schema =3D virFileFindResource(schemafile, abs_top_srcdir "/src= /conf/schemas", PKGDATADIR "/schemas= "); - if (!schema || - (virXMLValidateAgainstSchema(schema, xml) < 0)) + if (!schema) + return NULL; + + if (virXMLCustomValidatorPath && + virXMLParseHelperValidateCustom(schema, filename, xmlStr) < 0) + return NULL; + + if (virXMLValidateAgainstSchema(schema, xml) < 0) return NULL; } @@ -1884,3 +1955,21 @@ virXMLNewNode(xmlNsPtr ns, return ret; } + + +/** + * virXMLParseSetCustomValidator: + * @path: path to the custom validator binary + * + * Set the path to the custom XML validator helper program (see + * virXMLParseHelperValidateCustom). This function must be called only + * during daemon initialization. + */ +void +virXMLParseSetCustomValidator(const char *path) +{ + if (virXMLCustomValidatorPath) + return; + + virXMLCustomValidatorPath =3D g_strdup(path); +} diff --git a/src/util/virxml.h b/src/util/virxml.h index 539228a9ba..41a27a5722 100644 --- a/src/util/virxml.h +++ b/src/util/virxml.h @@ -165,6 +165,9 @@ virXMLPropEnumDefault(xmlNodePtr node, ATTRIBUTE_NONNULL(5); +void +virXMLParseSetCustomValidator(const char *path); + /* Internal function; prefer the macros below. */ xmlDocPtr virXMLParseHelper(int domcode, --=20 2.37.1 From nobody Fri May 17 23:08:22 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of redhat.com designates 170.10.133.124 as permitted sender) client-ip=170.10.133.124; envelope-from=libvir-list-bounces@redhat.com; helo=us-smtp-delivery-124.mimecast.com; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of redhat.com designates 170.10.133.124 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1663947796; cv=none; d=zohomail.com; s=zohoarc; b=CiKpJnJk3qVRqshFu+NEZmZcLRaVKWjrr0SxgEeGtUF0GnzR9xPTZCyYOOnt7WgyCc2fhqnxAJtK/iSKmhxtE1lj+wqXMzpYQfoMpTTOEn2ixEcLhe7l/Hg7vQal/im6aqJFN4cs4JI0CbgZzIMu/vTUYstKCvV+roZ5eVG1uEw= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1663947796; h=Content-Type:Content-Transfer-Encoding:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=Zdq+ituJH/5YnAhzaqrKTi/WyjBxz3RDdIrq2fc8UK8=; b=JKNrkPKzvMN9Qt2u+WuCvI5Wb9/VnECnOZJqAMWbABA0CW55Dcogvdfu2KJaaFdjfFTQCCFuR2x7TeMJjTQJm9JOFQkfZBTsC4NXtwGYIen3vTMy6drtT8+m4I/CZxpvmblN19ZyZfyN4vf4z9JQVsvS+FkjR91uTlqkywkswJc= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of redhat.com designates 170.10.133.124 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by mx.zohomail.com with SMTPS id 1663947796981181.50613778441016; Fri, 23 Sep 2022 08:43:16 -0700 (PDT) Received: from mimecast-mx02.redhat.com (mx3-rdu2.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-627-CTet-eRZMvCMWgU7NuukuQ-1; Fri, 23 Sep 2022 11:42:26 -0400 Received: from smtp.corp.redhat.com (int-mx07.intmail.prod.int.rdu2.redhat.com [10.11.54.7]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id AD4243810797; Fri, 23 Sep 2022 15:42:22 +0000 (UTC) Received: from mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (unknown [10.30.29.100]) by smtp.corp.redhat.com (Postfix) with ESMTP id 9B1F7140EBF4; Fri, 23 Sep 2022 15:42:22 +0000 (UTC) Received: from mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (localhost [IPv6:::1]) by mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (Postfix) with ESMTP id 67A2A19465B6; Fri, 23 Sep 2022 15:42:22 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) by mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (Postfix) with ESMTP id 3FCCA19465A4 for ; Fri, 23 Sep 2022 15:42:21 +0000 (UTC) Received: by smtp.corp.redhat.com (Postfix) id 26E52112131E; Fri, 23 Sep 2022 15:42:21 +0000 (UTC) Received: from speedmetal.lan (unknown [10.40.208.35]) by smtp.corp.redhat.com (Postfix) with ESMTP id 424AD1121314 for ; Fri, 23 Sep 2022 15:42:19 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1663947796; h=from:from:sender:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:list-id:list-help: list-unsubscribe:list-subscribe:list-post; bh=Zdq+ituJH/5YnAhzaqrKTi/WyjBxz3RDdIrq2fc8UK8=; b=CF43TYmgPvUQCSYp85dO98i4l1k3XDqXbZAfLvU6s9owF2xY3JUY5GhUTP+MULswg+moTm shzwW1aqBBKUNchXCF8WTKV4tPxy9xOpuNwLMJmfjik1kVDVUIg09l6iv39922iCQfMK/C 5NtPA3tQoL6iTqS4ceWG3mVXYZCguEs= X-MC-Unique: CTet-eRZMvCMWgU7NuukuQ-1 X-Original-To: libvir-list@listman.corp.redhat.com From: Peter Krempa To: libvir-list@redhat.com Subject: [PATCH 2/2] daemon: Introduce the possibility for users to register custom XML validator Date: Fri, 23 Sep 2022 17:42:13 +0200 Message-Id: <617903dad5e5bbf28b40169921e50bc92c5f9e9d.1663947646.git.pkrempa@redhat.com> In-Reply-To: References: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.1 on 10.11.54.3 X-BeenThere: libvir-list@redhat.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Development discussions about the libvirt library & tools List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libvir-list-bounces@redhat.com Sender: "libvir-list" X-Scanned-By: MIMEDefang 3.1 on 10.11.54.7 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1663947798093100001 Content-Type: text/plain; charset="utf-8" Introduce a new config option 'xml_validator' into the daemon config file which will allow users to make libvirt daemons use a custom XML validator. The rationale is that validators such as 'jing'[1] provide drastically better error specification when compared to the native libxml2 validator we use. A drawback though is that jing is written in Java and thus unusable by libvirt directly and also not a popular package present in distros. For power users and developers it still is worth having this feature to provide better errors in a native way. An example showing the quality of the errors: XML used: asdf8 native validator: error: XML document failed to validate against schema: Unable to validate= doc against /home/pipo/libvirt/src/conf/schemas/domain.rng Extra element vcpu in interleave Invalid sequence in interleave Element domain failed to validate content jing: error: XML document failed to validate against schema: Unable to validate= doc against /home/pipo/libvirt/src/conf/schemas/domain.rng /dev/stdin:6:52: error: character content of element "vcpu" invalid; must= be an integer Example script to make this feature work with jing: #!/bin/bash java -jar /home/pipo/git/jing-trang/build/jing.jar $1 /dev/stdin 2>&1 || = exit 1 [1] https://github.com/relaxng/jing-trang Signed-off-by: Peter Krempa Reviewed-by: Michal Privoznik --- src/remote/libvirtd.aug.in | 1 + src/remote/libvirtd.conf.in | 21 +++++++++++++++++++++ src/remote/remote_daemon.c | 3 +++ src/remote/remote_daemon_config.c | 4 ++++ src/remote/remote_daemon_config.h | 2 ++ src/remote/test_libvirtd.aug.in | 1 + 6 files changed, 32 insertions(+) diff --git a/src/remote/libvirtd.aug.in b/src/remote/libvirtd.aug.in index d744548f41..9a15eb14e5 100644 --- a/src/remote/libvirtd.aug.in +++ b/src/remote/libvirtd.aug.in @@ -91,6 +91,7 @@ module @DAEMON_NAME_UC@ =3D let misc_entry =3D str_entry "host_uuid" | str_entry "host_uuid_source" | int_entry "ovs_timeout" + | str_entry "xml_validator" (* Each entry in the config is one of the following three ... *) let entry =3D sock_acl_entry diff --git a/src/remote/libvirtd.conf.in b/src/remote/libvirtd.conf.in index 80a98b1529..5cfe0c0918 100644 --- a/src/remote/libvirtd.conf.in +++ b/src/remote/libvirtd.conf.in @@ -541,3 +541,24 @@ # potential infinite waits blocking libvirt. # #ovs_timeout =3D 5 + +################################################################### +# Custom XML validator +# +# The following option instructs @DAEMON_NAME@ to use a custom +# XML validator binary or script before invoking the default +# validator from libxml2. +# +# The custom validator is called using following arguments. +# +# /path/to/validator /path/to/schema.rng +# +# The actual XML file is provided on the standard input of the process. +# If the validation fails the process is expected to return a non-zero exit +# code. The standard output and standard error output are used as error me= ssage +# provided back to the user. +# +# Note that the XMLs sent for validation may contain security sensitive +# information. +# +#xml_validator =3D "/path/to/validator" diff --git a/src/remote/remote_daemon.c b/src/remote/remote_daemon.c index f369d09d35..cbbf81e141 100644 --- a/src/remote/remote_daemon.c +++ b/src/remote/remote_daemon.c @@ -936,6 +936,9 @@ int main(int argc, char **argv) { exit(EXIT_FAILURE); } + if (config->xml_validator) + virXMLParseSetCustomValidator(config->xml_validator); + /* Let's try to initialize global variable that holds the host's boot = time. */ if (virHostBootTimeInit() < 0) { /* This is acceptable failure. Maybe we won't need the boot time diff --git a/src/remote/remote_daemon_config.c b/src/remote/remote_daemon_c= onfig.c index 3567e337c4..affafa2a86 100644 --- a/src/remote/remote_daemon_config.c +++ b/src/remote/remote_daemon_config.c @@ -219,6 +219,7 @@ daemonConfigFree(struct daemonConfig *data) g_free(data->host_uuid_source); g_free(data->log_filters); g_free(data->log_outputs); + g_free(data->xml_validator); g_free(data); } @@ -380,6 +381,9 @@ daemonConfigLoadOptions(struct daemonConfig *data, if (virConfGetValueUInt(conf, "ovs_timeout", &data->ovs_timeout) < 0) return -1; + if (virConfGetValueString(conf, "xml_validator", &data->xml_validator)= < 0) + return -1; + return 0; } diff --git a/src/remote/remote_daemon_config.h b/src/remote/remote_daemon_c= onfig.h index 9f9e54e838..4bc8bce90f 100644 --- a/src/remote/remote_daemon_config.h +++ b/src/remote/remote_daemon_config.h @@ -96,6 +96,8 @@ struct daemonConfig { unsigned int admin_keepalive_count; unsigned int ovs_timeout; + + char *xml_validator; }; diff --git a/src/remote/test_libvirtd.aug.in b/src/remote/test_libvirtd.aug= .in index c27680e130..eedc3af24d 100644 --- a/src/remote/test_libvirtd.aug.in +++ b/src/remote/test_libvirtd.aug.in @@ -67,3 +67,4 @@ module Test_@DAEMON_NAME@ =3D { "admin_keepalive_interval" =3D "5" } { "admin_keepalive_count" =3D "5" } { "ovs_timeout" =3D "5" } + { "xml_validator" =3D "/path/to/validator" } --=20 2.37.1