From nobody Sun May 5 17:00:57 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) client-ip=209.132.183.28; envelope-from=libvir-list-bounces@redhat.com; helo=mx1.redhat.com; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass(p=none dis=none) header.from=redhat.com Return-Path: Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) by mx.zohomail.com with SMTPS id 1533048978584522.7450790078848; Tue, 31 Jul 2018 07:56:18 -0700 (PDT) Received: from smtp.corp.redhat.com (int-mx09.intmail.prod.int.phx2.redhat.com [10.5.11.24]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 1932D30820D6; Tue, 31 Jul 2018 14:55:36 +0000 (UTC) Received: from colo-mx.corp.redhat.com (colo-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.20]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 1525B30014A5; Tue, 31 Jul 2018 14:55:35 +0000 (UTC) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by colo-mx.corp.redhat.com (Postfix) with ESMTP id E8FBE18037EF; Tue, 31 Jul 2018 14:55:33 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id w6VEtUTk019864 for ; Tue, 31 Jul 2018 10:55:30 -0400 Received: by smtp.corp.redhat.com (Postfix) id 678BA20180EB; Tue, 31 Jul 2018 14:55:30 +0000 (UTC) Received: from localhost.localdomain.com (unknown [10.42.22.189]) by smtp.corp.redhat.com (Postfix) with ESMTP id DB49F2026D68; Tue, 31 Jul 2018 14:55:29 +0000 (UTC) From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= To: libvir-list@redhat.com Date: Tue, 31 Jul 2018 15:55:28 +0100 Message-Id: <20180731145528.9845-1-berrange@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.78 on 10.11.54.4 X-loop: libvir-list@redhat.com Subject: [libvirt] [PATCH] util: avoid symbol clash between json libraries X-BeenThere: libvir-list@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk List-Id: Development discussions about the libvirt library & tools List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Sender: libvir-list-bounces@redhat.com Errors-To: libvir-list-bounces@redhat.com X-Scanned-By: MIMEDefang 2.84 on 10.5.11.24 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.47]); Tue, 31 Jul 2018 14:56:17 +0000 (UTC) X-ZohoMail: RSF_0 Z_629925259 SPT_0 The jansson and json-glib libraries both export symbols with a json_ name prefix and json_object_iter_next() clashes between them. Unfortunately json_glib is linked in by GTK, so any app using GTK and libvirt will get a clash, resulting in SEGV. This also affects the NSS module provided by libvirt Instead of directly linking to jansson, use dlopen() with the RTLD_LOCAL flag which allows us to hide the symbols from the application that loads libvirt or the NSS module. Some preprocessor black magic and wrapper functions are used to redirect calls into the dlopen resolved symbols. Signed-off-by: Daniel P. Berrang=C3=A9 Reviewed-by: J=EF=BF=BDn Tomko --- libvirt.spec.in | 2 + src/Makefile.am | 3 + src/util/Makefile.inc.am | 3 +- src/util/virjson.c | 9 +- src/util/virjsoncompat.c | 253 +++++++++++++++++++++++++++++++++++++++ src/util/virjsoncompat.h | 86 +++++++++++++ 6 files changed, 354 insertions(+), 2 deletions(-) create mode 100644 src/util/virjsoncompat.c create mode 100644 src/util/virjsoncompat.h diff --git a/libvirt.spec.in b/libvirt.spec.in index 4113579e47..cfe7ab8a09 100644 --- a/libvirt.spec.in +++ b/libvirt.spec.in @@ -898,6 +898,8 @@ Requires: ncurses Requires: gettext # Needed by virt-pki-validate script. Requires: gnutls-utils +# We dlopen() it so need an explicit dep +Requires: libjansson.so.4()(64bit) %if %{with_bash_completion} Requires: %{name}-bash-completion =3D %{version}-%{release} %endif diff --git a/src/Makefile.am b/src/Makefile.am index 83263e69e5..59ae7a2e79 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -690,6 +690,7 @@ libvirt_setuid_rpc_client_la_SOURCES =3D \ util/virhashcode.c \ util/virhostcpu.c \ util/virjson.c \ + util/virjsoncompat.c \ util/virlog.c \ util/virobject.c \ util/virpidfile.c \ @@ -961,6 +962,8 @@ libvirt_nss_la_SOURCES =3D \ util/virhashcode.h \ util/virjson.c \ util/virjson.h \ + util/virjsoncompat.c \ + util/virjsoncompat.h \ util/virkmod.c \ util/virkmod.h \ util/virlease.c \ diff --git a/src/util/Makefile.inc.am b/src/util/Makefile.inc.am index 71b2b93c2d..8ef9ee1dfa 100644 --- a/src/util/Makefile.inc.am +++ b/src/util/Makefile.inc.am @@ -86,6 +86,8 @@ UTIL_SOURCES =3D \ util/viriscsi.h \ util/virjson.c \ util/virjson.h \ + util/virjsoncompat.c \ + util/virjsoncompat.h \ util/virkeycode.c \ util/virkeycode.h \ util/virkeyfile.c \ @@ -264,7 +266,6 @@ libvirt_util_la_CFLAGS =3D \ $(NULL) libvirt_util_la_LIBADD =3D \ $(CAPNG_LIBS) \ - $(JANSSON_LIBS) \ $(LIBNL_LIBS) \ $(THREAD_LIBS) \ $(AUDIT_LIBS) \ diff --git a/src/util/virjson.c b/src/util/virjson.c index 01a387b2f7..5bab662cd3 100644 --- a/src/util/virjson.c +++ b/src/util/virjson.c @@ -1437,7 +1437,8 @@ virJSONValueCopy(const virJSONValue *in) =20 =20 #if WITH_JANSSON -# include + +# include "virjsoncompat.h" =20 static virJSONValuePtr virJSONValueFromJansson(json_t *json) @@ -1524,6 +1525,9 @@ virJSONValueFromString(const char *jsonstring) size_t flags =3D JSON_REJECT_DUPLICATES | JSON_DECODE_ANY; =20 + if (virJSONInitialize() < 0) + return NULL; + if (!(json =3D json_loads(jsonstring, flags, &error))) { virReportError(VIR_ERR_INTERNAL_ERROR, _("failed to parse JSON %d:%d: %s"), @@ -1630,6 +1634,9 @@ virJSONValueToString(virJSONValuePtr object, json_t *json; char *str =3D NULL; =20 + if (virJSONInitialize() < 0) + return NULL; + if (pretty) flags |=3D JSON_INDENT(2); else diff --git a/src/util/virjsoncompat.c b/src/util/virjsoncompat.c new file mode 100644 index 0000000000..c317e50c32 --- /dev/null +++ b/src/util/virjsoncompat.c @@ -0,0 +1,253 @@ +/* + * virjsoncompat.c: JSON object parsing/formatting + * + * Copyright (C) 2018 Red Hat, Inc. + * + * 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 "virthread.h" +#include "virerror.h" +#define VIR_JSON_COMPAT_IMPL +#include "virjsoncompat.h" + +#define VIR_FROM_THIS VIR_FROM_NONE + +#if WITH_JANSSON + +#include + +json_t *(*json_array_ptr)(void); +int (*json_array_append_new_ptr)(json_t *array, json_t *value); +json_t *(*json_array_get_ptr)(const json_t *array, size_t index); +size_t (*json_array_size_ptr)(const json_t *array); +void (*json_delete_ptr)(json_t *json); +char *(*json_dumps_ptr)(const json_t *json, size_t flags); +json_t *(*json_false_ptr)(void); +json_t *(*json_integer_ptr)(json_int_t value); +json_int_t (*json_integer_value_ptr)(const json_t *integer); +json_t *(*json_loads_ptr)(const char *input, size_t flags, json_error_t *e= rror); +json_t *(*json_null_ptr)(void); +json_t *(*json_object_ptr)(void); +void *(*json_object_iter_ptr)(json_t *object); +const char *(*json_object_iter_key_ptr)(void *iter); +void *(*json_object_iter_next_ptr)(json_t *object, void *iter); +json_t *(*json_object_iter_value_ptr)(void *iter); +void *(*json_object_key_to_iter_ptr)(const char *key); +int (*json_object_set_new_ptr)(json_t *object, const char *key, json_t *va= lue); +json_t *(*json_real_ptr)(double value); +double (*json_real_value_ptr)(const json_t *real); +json_t *(*json_string_ptr)(const char *value); +const char *(*json_string_value_ptr)(const json_t *string); +json_t *(*json_true_ptr)(void); + + +static int virJSONJanssonOnceInit(void) +{ + void *handle =3D dlopen("libjansson.so.4", RTLD_LAZY|RTLD_LOCAL|RTLD_D= EEPBIND|RTLD_NODELETE); + if (!handle) { + virReportError(VIR_ERR_NO_SUPPORT, + _("libjansson.so.4 JSON library not available: %s")= , dlerror()); + return -1; + } + +#define LOAD(name) \ + do { \ + if (!(name ## _ptr =3D dlsym(handle, #name))) { \ + virReportError(VIR_ERR_NO_SUPPORT, \ + _("missing symbol '%s' in libjansson.so.4: %s")= , #name, dlerror()); \ + goto error; \ + } \ + fprintf(stderr, "Resolve %s to %p\n", #name, name ## _ptr); \ + } while (0) + + LOAD(json_array); + LOAD(json_array_append_new); + LOAD(json_array_get); + LOAD(json_array_size); + LOAD(json_delete); + LOAD(json_dumps); + LOAD(json_false); + LOAD(json_integer); + LOAD(json_integer_value); + LOAD(json_loads); + LOAD(json_null); + LOAD(json_object); + LOAD(json_object_iter); + LOAD(json_object_iter_key); + LOAD(json_object_iter_next); + LOAD(json_object_iter_value); + LOAD(json_object_key_to_iter); + LOAD(json_object_set_new); + LOAD(json_real); + LOAD(json_real_value); + LOAD(json_string); + LOAD(json_string_value); + LOAD(json_true); + + return 0; + + error: + return -1; +} + +VIR_ONCE_GLOBAL_INIT(virJSONJansson); + +int virJSONInitialize(void) { + return virJSONJanssonInitialize(); +} + +json_t *json_array_impl(void) +{ + return json_array_ptr(); +} + + +int json_array_append_new_impl(json_t *array, json_t *value) +{ + return json_array_append_new_ptr(array, value); +} + + +json_t *json_array_get_impl(const json_t *array, size_t index) +{ + return json_array_get_ptr(array, index); +} + + +size_t json_array_size_impl(const json_t *array) +{ + return json_array_size_ptr(array); +} + + +void json_delete_impl(json_t *json) +{ + return json_delete_ptr(json); +} + + +char *json_dumps_impl(const json_t *json, size_t flags) +{ + return json_dumps_ptr(json, flags); +} + + +json_t *json_false_impl(void) +{ + return json_false_ptr(); +} + + +json_t *json_integer_impl(json_int_t value) +{ + return json_integer_ptr(value); +} + + +json_int_t json_integer_value_impl(const json_t *integer) +{ + return json_integer_value_ptr(integer); +} + + +json_t *json_loads_impl(const char *input, size_t flags, json_error_t *err= or) +{ + return json_loads_ptr(input, flags, error); +} + + +json_t *json_null_impl(void) +{ + return json_null_ptr(); +} + + +json_t *json_object_impl(void) +{ + return json_object_ptr(); +} + + +void *json_object_iter_impl(json_t *object) +{ + return json_object_iter_ptr(object); +} + + +const char *json_object_iter_key_impl(void *iter) +{ + return json_object_iter_key_ptr(iter); +} + + +void *json_object_iter_next_impl(json_t *object, void *iter) +{ + return json_object_iter_next_ptr(object, iter); +} + + +json_t *json_object_iter_value_impl(void *iter) +{ + return json_object_iter_value_ptr(iter); +} + + +void *json_object_key_to_iter_impl(const char *key) +{ + return json_object_key_to_iter_ptr(key); +} + + +int json_object_set_new_impl(json_t *object, const char *key, json_t *valu= e) +{ + return json_object_set_new_ptr(object, key, value); +} + + +json_t *json_real_impl(double value) +{ + return json_real_ptr(value); +} + + +double json_real_value_impl(const json_t *real) +{ + return json_real_value_ptr(real); +} + + +json_t *json_string_impl(const char *value) +{ + return json_string_ptr(value); +} + + +const char *json_string_value_impl(const json_t *string) +{ + return json_string_value_ptr(string); +} + + +json_t *json_true_impl(void) +{ + return json_true_ptr(); +} + +#endif + diff --git a/src/util/virjsoncompat.h b/src/util/virjsoncompat.h new file mode 100644 index 0000000000..c3963a5259 --- /dev/null +++ b/src/util/virjsoncompat.h @@ -0,0 +1,86 @@ +/* + * virjson.h: JSON object parsing/formatting + * + * Copyright (C) 2018 Red Hat, Inc. + * + * 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 + * . + * + */ + + +#ifndef __VIR_JSON_COMPAT_H_ +# define __VIR_JSON_COMPAT_H_ + +#ifndef VIR_JSON_COMPAT_IMPL + +#define json_array json_array_impl +#define json_array_append_new json_array_append_new_impl +#define json_array_get json_array_get_impl +#define json_array_size json_array_size_impl +#define json_delete json_delete_impl +#define json_dumps json_dumps_impl +#define json_false json_false_impl +#define json_integer json_integer_impl +#define json_integer_value json_integer_value_impl +#define json_loads json_loads_impl +#define json_null json_null_impl +#define json_object json_object_impl +#define json_object_iter json_object_iter_impl +#define json_object_iter_key json_object_iter_key_impl +#define json_object_iter_next json_object_iter_next_impl +#define json_object_iter_value json_object_iter_value_impl +#define json_object_key_to_iter json_object_key_to_iter_impl +#define json_object_set_new json_object_set_new_impl +#define json_real json_real_impl +#define json_real_value json_real_value_impl +#define json_string json_string_impl +#define json_string_value json_string_value_impl +#define json_true json_true_impl + +#include + +#else + +#include + +json_t *json_array_impl(void); +int json_array_append_new_impl(json_t *array, json_t *value); +json_t *json_array_get_impl(const json_t *array, size_t index); +size_t json_array_size_impl(const json_t *array); +void json_delete_impl(json_t *json); +char *json_dumps_impl(const json_t *json, size_t flags); +json_t *json_false_impl(void); +json_t *json_integer_impl(json_int_t value); +json_int_t json_integer_value_impl(const json_t *integer); +json_t *json_loads_impl(const char *input, size_t flags, json_error_t *err= or); +json_t *json_null_impl(void); +json_t *json_object_impl(void); +void *json_object_iter_impl(json_t *object); +const char *json_object_iter_key_impl(void *iter); +void *json_object_iter_next_impl(json_t *object, void *iter); +json_t *json_object_iter_value_impl(void *iter); +void *json_object_key_to_iter_impl(const char *key); +int json_object_set_new_impl(json_t *object, const char *key, json_t *valu= e); +json_t *json_real_impl(double value); +double json_real_value_impl(const json_t *real); +json_t *json_string_impl(const char *value); +const char *json_string_value_impl(const json_t *string); +json_t *json_true_impl(void); + +#endif + +int virJSONInitialize(void); + +#endif --=20 2.17.1 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list