From nobody Sat Nov 23 17:39:31 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) client-ip=8.43.85.245; envelope-from=devel-bounces@lists.libvirt.org; helo=lists.libvirt.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) smtp.mailfrom=devel-bounces@lists.libvirt.org; dmarc=fail(p=none dis=none) header.from=gmail.com Return-Path: Received: from lists.libvirt.org (lists.libvirt.org [8.43.85.245]) by mx.zohomail.com with SMTPS id 1724085034162274.0938267987351; Mon, 19 Aug 2024 09:30:34 -0700 (PDT) Received: by lists.libvirt.org (Postfix, from userid 996) id ECECD15C6; Mon, 19 Aug 2024 12:30:32 -0400 (EDT) Received: from lists.libvirt.org (localhost [IPv6:::1]) by lists.libvirt.org (Postfix) with ESMTP id 7CCCF161F; Mon, 19 Aug 2024 12:20:51 -0400 (EDT) Received: by lists.libvirt.org (Postfix, from userid 996) id 517F415E8; Mon, 19 Aug 2024 12:20:42 -0400 (EDT) Received: from mail-ed1-f52.google.com (mail-ed1-f52.google.com [209.85.208.52]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by lists.libvirt.org (Postfix) with ESMTPS id 0E9391610 for ; Mon, 19 Aug 2024 12:20:08 -0400 (EDT) Received: by mail-ed1-f52.google.com with SMTP id 4fb4d7f45d1cf-5becc379f3fso3111149a12.3 for ; Mon, 19 Aug 2024 09:20:07 -0700 (PDT) Received: from localhost.localdomain ([37.186.51.21]) by smtp.gmail.com with ESMTPSA id 4fb4d7f45d1cf-5bebbde4964sm5738298a12.24.2024.08.19.09.20.05 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 19 Aug 2024 09:20:06 -0700 (PDT) X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on lists.libvirt.org X-Spam-Level: X-Spam-Status: No, score=-0.6 required=5.0 tests=DKIM_ADSP_CUSTOM_MED, DKIM_INVALID,DKIM_SIGNED,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,MAILING_LIST_MULTI,RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2,SPF_HELO_NONE,T_SCC_BODY_TEXT_LINE autolearn=unavailable autolearn_force=no version=3.4.4 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1724084407; x=1724689207; darn=lists.libvirt.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=CnnutAHY444kPD7qK5BKaZO6tDzfei0SOOfnSThq1m4=; b=Puq+gs8ZjZ3vq4d6gJUMOxrbclhgLc8dUtiajNOZioWfKJgAXiEoJvvax3nF25zD9x vwvXT9KsT4gGyGfCLdcpBGoLb1dKeSfI9H5eiYSbqWQPl0+SVT2Nxt7GQRejpITTMHpf reZ2ihqdVqSb/h4mfzM50XC24KOWCbdwmKdp9TZfyBu+RnHyccZR5PUVmV3YXczVYbR7 MAPK1TOZONoKpSpw7zmtH8cI/RiiFMSf2Wqu6YvjtcjO1G2267U1P9N7ACix1ep5arNJ xYogTvSPB/oWd3q/kx3ebyWdt4jXzSb2muD9kTZr7wVRRZmTTZmJj+5FHskETvZT48q9 W/rg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1724084407; x=1724689207; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=CnnutAHY444kPD7qK5BKaZO6tDzfei0SOOfnSThq1m4=; b=DCksRvd3LTr+BDfDdOnhOxZCIFDtn/bj4QlwwOWy6Z/5HDTrxYoLnFV3a67K0Y9Yav F7uZavkOflVskyB2yGdaVu4yI+/OVfNApt0mox8UsCNIa6GctNOHqXRFQuJs5Rr/Xi2Y HH8TciZTbGfHQCPRDSfIVzGGdbg4nDzl3Yua533hiaQl4OeCi7sfiVMdXiOpAzPH5LKm 1ExcIKUueNI0s5eBzqr1rK7XmtKfQPGrsMIRkU/gFU1DrrJ4yt6VKqMLnrnKxav7e6h8 VCeXdazH7yLY4hCDBc+p2VEzR6Ng/Y0fbzB2I498O7qqWWvvzH9zmZcaejD1bvzsy4g8 21Hg== X-Gm-Message-State: AOJu0Yyx5bjoG80pPZXLq2tI7mU1hUuL5ThHKNF7qux7HS53b52wiOW0 PFA7XsOyPQtrHySr1GAjuNITCSOF9w2GOo1YcDgsFkNoHoX/qznBp1C9IA== X-Google-Smtp-Source: AGHT+IGdLbVvggaxMklrqofhCgdoulVbiALQTbEhGJaMEbtez4vGoYPkOi0wRSD028cm9dWFpSp0XQ== X-Received: by 2002:a05:6402:35d2:b0:5be:d704:e724 with SMTP id 4fb4d7f45d1cf-5bed704ea8amr6855461a12.10.1724084406480; Mon, 19 Aug 2024 09:20:06 -0700 (PDT) From: Rayhan Faizel To: devel@lists.libvirt.org Subject: [PATCH 12/14] fuzz: Implement libXL XML domain fuzzer Date: Mon, 19 Aug 2024 21:39:50 +0530 Message-Id: <20240819160952.351383-13-rayhan.faizel@gmail.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240819160952.351383-1-rayhan.faizel@gmail.com> References: <20240819160952.351383-1-rayhan.faizel@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Message-ID-Hash: FFR2M6GMDRN7CWLBYK7H7IM5L725QOJS X-Message-ID-Hash: FFR2M6GMDRN7CWLBYK7H7IM5L725QOJS X-MailFrom: rayhan.faizel@gmail.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; header-match-config-1; header-match-config-2; header-match-config-3; header-match-devel.lists.libvirt.org-0; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; suspicious-header CC: Rayhan Faizel X-Mailman-Version: 3.2.2 Precedence: list List-Id: Development discussions about the libvirt library & tools Archived-At: List-Archive: List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1724085035512116600 Content-Type: text/plain; charset="utf-8" This patch adds the harness for the xen driver to fuzz XML parsing, domconfig generation and JSON conversion. libxlmock.so is required to make the libXL fuzzer work outside of xen hosts. However, LD_PRELOAD breaks the fuzzer when ASAN/UBSAN is present. This is because LD_PRELOAD gets propagated to llvm-symbolizer which is undesirable and causes various undefined symbol errors. We add a wrapper binary which e= xecs the real llvm-symbolizer with the environment unset. However, LD_PRELOAD still breaks parallel fuzzing so it is disabled for the time being. Signed-off-by: Rayhan Faizel --- tests/fuzz/libxl_xml_domain_fuzz.cc | 159 +++++++++++++++++++++++++++ tests/fuzz/llvm_symbolizer_wrapper.c | 11 ++ tests/fuzz/meson.build | 31 ++++++ tests/fuzz/proto_to_xml.cc | 18 +++ tests/fuzz/proto_to_xml.h | 3 + tests/fuzz/run_fuzz.in | 15 +++ 6 files changed, 237 insertions(+) create mode 100644 tests/fuzz/libxl_xml_domain_fuzz.cc create mode 100644 tests/fuzz/llvm_symbolizer_wrapper.c diff --git a/tests/fuzz/libxl_xml_domain_fuzz.cc b/tests/fuzz/libxl_xml_dom= ain_fuzz.cc new file mode 100644 index 0000000000..a8fcb62d06 --- /dev/null +++ b/tests/fuzz/libxl_xml_domain_fuzz.cc @@ -0,0 +1,159 @@ +/* + * libxl_xml_domain_fuzz.cc: libXL domain fuzzing harness + * + * Copyright (C) 2024 Rayhan Faizel + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * . + */ + +#include +#include "proto_header_common.h" + +#include +#include +#include + +#include +#include +#include +#include +#include + +extern "C" { +#include "testutils.h" +#include "internal.h" +#include "libxl/libxl_conf.h" +#include "testutilsxen.h" +} + +#include "port/protobuf.h" +#include "proto_to_xml.h" +#include "src/libfuzzer/libfuzzer_macro.h" + +uint64_t parse_pass =3D 0; +uint64_t format_pass =3D 0; +uint64_t config_pass =3D 0; +uint64_t json_pass =3D 0; +uint64_t command_line_pass =3D 0; +uint64_t success =3D 0; + +bool enable_xml_dump =3D false; +bool enable_xml_format =3D false; + +static void +fuzzXMLToCommandLine(libxlDriverPrivate *driver, + const char *xml_string) +{ + virDomainDef *def =3D NULL; + const char *formatted_xml =3D NULL; + g_autofree char *json_string =3D NULL; + libxl_domain_config config; + virPortAllocatorRange *gports =3D NULL; + bool config_init =3D false; + + g_autoptr(libxlDriverConfig) cfg =3D libxlDriverConfigGet(driver); + + parse_pass++; + if (!(def =3D virDomainDefParseString(xml_string, driver->xmlopt, NULL, + VIR_DOMAIN_DEF_PARSE_INACTIVE))) + goto cleanup; + + if (enable_xml_format) { + format_pass++; + if (!(formatted_xml =3D virDomainDefFormat(def, driver->xmlopt, + VIR_DOMAIN_DEF_FORMAT_SEC= URE))) + goto cleanup; + } + + libxl_domain_config_init(&config); + config_init =3D true; + + if (!(gports =3D virPortAllocatorRangeNew("vnc", 5900, 6000))) + goto cleanup; + + config_pass++; + if (libxlBuildDomainConfig(gports, def, cfg, &config) < 0) + goto cleanup; + + json_pass++; + if (!(json_string =3D libxl_domain_config_to_json(cfg->ctx, &config))) + goto cleanup; + + success++; + + cleanup: + + virPortAllocatorRangeFree(gports); + if (config_init) + libxl_domain_config_dispose(&config); + virDomainDefFree(def); +} + + +DEFINE_PROTO_FUZZER(const libvirt::MainObj &message) +{ + static libxlDriverPrivate *driver =3D NULL; + + static bool initialized =3D false; + + static const char *arch_env =3D g_getenv("LPM_FUZZ_ARCH"); + static const char *dump_xml_env =3D g_getenv("LPM_XML_DUMP_INPUT"); + static const char *format_xml_env =3D g_getenv("LPM_XML_FORMAT_ENABLE"= ); + + static std::string arch =3D ""; + + std::string xml =3D ""; + + + /* + * One-time setup of libXL driver. Re-running them in every + * iteration incurs a significant penalty to the speed of the fuzzer. + */ + if (!initialized) { + FUZZ_COMMON_INIT(); + + /* NOTE: Driver initialization will fail without libxlmock */ + if ((driver =3D testXLInitDriver()) =3D=3D NULL) + exit(EXIT_FAILURE); + + if (arch_env) { + arch =3D arch_env; + } else { + arch =3D "x86_64"; + } + + /* Enable printing of XML to stdout (useful for debugging crashes)= */ + if (dump_xml_env && STREQ(dump_xml_env, "YES")) + enable_xml_dump =3D true; + + /* Enable fuzzing of XML formatting */ + if (format_xml_env && STREQ(format_xml_env, "YES")) + enable_xml_format =3D true; + + initialized =3D true; + } + + convertProtoTolibXLXMLDomain(message, arch, xml); + + if (enable_xml_dump) + printf("%s\n", xml.c_str()); + + fuzzXMLToCommandLine(driver, xml.c_str()); + + if (parse_pass % 1000 =3D=3D 0) + printf("[FUZZ METRICS] Parse: %lu, Format: %lu, Config: %lu, JSON:= %lu, Success: %lu\n", + parse_pass, format_pass, config_pass, json_pass, success); + +} diff --git a/tests/fuzz/llvm_symbolizer_wrapper.c b/tests/fuzz/llvm_symboli= zer_wrapper.c new file mode 100644 index 0000000000..d0aeba61fe --- /dev/null +++ b/tests/fuzz/llvm_symbolizer_wrapper.c @@ -0,0 +1,11 @@ +#include + +#include +#include + +int main(int argc, char **argv) { + // Avoid unused error. + (void) argc; + + execve("/usr/bin/llvm-symbolizer", argv, NULL); +} diff --git a/tests/fuzz/meson.build b/tests/fuzz/meson.build index 88b5fe103c..417b8dc1ef 100644 --- a/tests/fuzz/meson.build +++ b/tests/fuzz/meson.build @@ -90,6 +90,24 @@ if conf.has('WITH_VMX') ] endif =20 +if conf.has('WITH_LIBXL') + fuzzer_src =3D [ + 'libxl_xml_domain_fuzz.cc', + 'proto_to_xml.cc', + ] + + libxl_libs =3D [ + test_xen_driver_lib, + test_utils_xen_lib, + test_utils_lib, + libvirt_lib, + ] + + xml_fuzzers +=3D [ + { 'name': 'libxl_xml_domain_fuzz', 'src': [ fuzzer_src, xml_domain_pro= to_src ], 'libs': libxl_libs, 'macro': '-DXML_DOMAIN', 'deps': [ fuzz_autog= en_xml_domain_dep, libxl_dep ] }, + ] +endif + foreach fuzzer: xml_fuzzers xml_domain_fuzz =3D executable(fuzzer['name'], fuzzer['src'], @@ -102,6 +120,19 @@ foreach fuzzer: xml_fuzzers available_fuzzers +=3D '"' + fuzzer['name'] + '"' + ',' endforeach =20 +# Wrapper binary which execs the real llvm-symbolizer but +# unsets the env vars to avoid propagating LD_PRELOAD to the +# real llvm-symbolizer and causing undefined symbol errors when ASAN/UBSAN +# is enabled. + +llvm_symbolizer_wrapper =3D executable( + 'llvm-symbolizer-wrapper', + 'llvm_symbolizer_wrapper.c', + dependencies: [ + tests_dep, + ], +) + run_conf =3D configuration_data({ 'abs_builddir': meson.project_build_root(), 'available_fuzzers': available_fuzzers, diff --git a/tests/fuzz/proto_to_xml.cc b/tests/fuzz/proto_to_xml.cc index 983256bcae..fde3394cc7 100644 --- a/tests/fuzz/proto_to_xml.cc +++ b/tests/fuzz/proto_to_xml.cc @@ -252,6 +252,24 @@ void convertProtoToVMXXMLDomain(const libvirt::MainObj= &message, } =20 =20 +void convertProtoTolibXLXMLDomain(const libvirt::MainObj &message, + std::string arch, + std::string &xml) +{ + xml =3D "\n" + " MyGuest\n" + " 4dea22b3-1d52-d8f3-2516-782e98ab3fa0\n" + " \n" + " hvm\n" + " \n" + " 4096\n"; + + convertProtoToXMLInternal(message, xml, true); + + xml +=3D "\n"; +} + + void convertProtoToXML(const libvirt::MainObj &message, std::string &xml) { diff --git a/tests/fuzz/proto_to_xml.h b/tests/fuzz/proto_to_xml.h index 89e6726611..b4849890cc 100644 --- a/tests/fuzz/proto_to_xml.h +++ b/tests/fuzz/proto_to_xml.h @@ -32,5 +32,8 @@ void convertProtoToCHXMLDomain(const libvirt::MainObj &me= ssage, void convertProtoToVMXXMLDomain(const libvirt::MainObj &message, std::string arch, std::string &xml); +void convertProtoTolibXLXMLDomain(const libvirt::MainObj &message, + std::string arch, + std::string &xml); void convertProtoToXML(const libvirt::MainObj &message, std::string &xml); diff --git a/tests/fuzz/run_fuzz.in b/tests/fuzz/run_fuzz.in index 414b99b6cf..a2b0c66c32 100644 --- a/tests/fuzz/run_fuzz.in +++ b/tests/fuzz/run_fuzz.in @@ -118,6 +118,21 @@ if args.fuzzer =3D=3D "qemu_xml_hotplug_fuzz": # so we have to disable LeakSanitizer env["ASAN_OPTIONS"] =3D "detect_leaks=3D0" =20 +if args.fuzzer =3D=3D "libxl_xml_domain_fuzz": + # To make LD_PRELOAD work without running into undefined symbol + # errors, we need to override ASAN_SYMBOLIZER_PATH with a wrapper + # that unsets LD_PRELOAD before running the real llvm-symbolizer. + + env["ASAN_SYMBOLIZER_PATH"] =3D llvm_symbolizer_path + env["LD_PRELOAD"] =3D f"{abs_builddir}/tests/libxlmock.so" + + # Note: Above workaround breaks multithreaded mode, + # so inform the user of the same. + + if args.jobs > 1: + print("libxl_xml_domain_fuzz cannot be used in parallel mode.") + sys.exit(1) + if args.libfuzzer_options: process_args.extend([x for x in args.libfuzzer_options.split(' ') if x= !=3D '']) =20 --=20 2.34.1