diff options
author | Lubomir Rintel <lkundrak@v3.sk> | 2017-12-26 09:28:54 +0100 |
---|---|---|
committer | Lubomir Rintel <lkundrak@v3.sk> | 2018-01-08 10:15:29 +0100 |
commit | cd476e4dc922f0acfd65b02639032ee67339ad95 (patch) | |
tree | de3b396fe5a6ad5944c692ad4a953dc5b91bfcb9 | |
parent | da4c9e51a038279e261b896e5156308adaea4572 (diff) |
core: load jansson on demand
Avoid using it if the symbols clash is detected.
-rw-r--r-- | Makefile.am | 12 | ||||
-rw-r--r-- | config.h.meson | 3 | ||||
-rw-r--r-- | configure.ac | 10 | ||||
-rw-r--r-- | libnm-core/meson.build | 1 | ||||
-rw-r--r-- | libnm-core/nm-jansson.c | 117 | ||||
-rw-r--r-- | libnm-core/nm-jansson.h | 45 | ||||
-rw-r--r-- | libnm-core/nm-utils.c | 81 | ||||
-rw-r--r-- | meson.build | 14 |
8 files changed, 248 insertions, 35 deletions
diff --git a/Makefile.am b/Makefile.am index c7b8a1b8f7..8584866405 100644 --- a/Makefile.am +++ b/Makefile.am @@ -516,6 +516,14 @@ libnm_core_lib_c_real = \ libnm-core/nm-utils.c \ libnm-core/nm-vpn-editor-plugin.c \ libnm-core/nm-vpn-plugin-info.c + +if WITH_JSON_VALIDATION +libnm_core_lib_h_priv += \ + libnm-core/nm-jansson.h +libnm_core_lib_c_real += \ + libnm-core/nm-jansson.c +endif + libnm_core_lib_c_mkenums = \ libnm-core/nm-core-enum-types.c @@ -596,10 +604,6 @@ libnm_core_libnm_core_la_LIBADD = \ $(UUID_LIBS) \ $(LIBUDEV_LIBS) -if WITH_JSON_VALIDATION -libnm_core_libnm_core_la_LIBADD += $(JANSSON_LIBS) -endif - libnm_core_libnm_core_la_LDFLAGS = \ $(CODE_COVERAGE_LDFLAGS) diff --git a/config.h.meson b/config.h.meson index 67de050b0e..704c0a48d2 100644 --- a/config.h.meson +++ b/config.h.meson @@ -71,6 +71,9 @@ /* Define to path of iptables binary */ #mesondefine IPTABLES_PATH +/* Define to path to the Jansson shared library */ +#mesondefine JANSSON_SONAME + /* Define to path of the kernel firmware directory */ #mesondefine KERNEL_FIRMWARE_DIR diff --git a/configure.ac b/configure.ac index f90a89d45d..141e07a390 100644 --- a/configure.ac +++ b/configure.ac @@ -629,12 +629,20 @@ PKG_CHECK_MODULES(UUID, uuid) PKG_CHECK_MODULES(JANSSON, [jansson], [have_jansson=yes], [have_jansson=no]) if test "$have_jansson" = "yes"; then AC_DEFINE(WITH_JANSSON, 1, [Define if JANSSON is enabled]) + + AC_CHECK_TOOLS(READELF, [eu-readelf readelf]) + JANSSON_LIBDIR=`$PKG_CONFIG --variable=libdir jansson` + JANSSON_SONAME=`$READELF -d $JANSSON_LIBDIR/libjansson.so |sed -n 's/.*SONAME.*\[[\([^]]*\)]]/\1/p'` + + if test "$JANSSON_SONAME" = ""; then + AC_MSG_ERROR(Unable to locate the Jansson library) + fi + AC_DEFINE_UNQUOTED(JANSSON_SONAME, "$JANSSON_SONAME", [Define to path to the Jansson shared library]) else AC_DEFINE(WITH_JANSSON, 0, [Define if JANSSON is enabled]) fi AM_CONDITIONAL(WITH_JANSSON, test "${have_jansson}" = "yes") - PKG_CHECK_MODULES(LIBTEAMDCTL, [libteamdctl >= 1.9], [have_teamdctl=yes],[have_teamdctl=no]) if test "$have_jansson" = "yes" -a "$have_teamdctl" = "yes"; then have_team_prereq=yes diff --git a/libnm-core/meson.build b/libnm-core/meson.build index 97040709f9..7aa85b1728 100644 --- a/libnm-core/meson.build +++ b/libnm-core/meson.build @@ -151,6 +151,7 @@ cflags = [ ] if enable_json_validation + libnm_core_sources += files('nm-jansson.c') deps += jansson_dep endif diff --git a/libnm-core/nm-jansson.c b/libnm-core/nm-jansson.c new file mode 100644 index 0000000000..154afa2749 --- /dev/null +++ b/libnm-core/nm-jansson.c @@ -0,0 +1,117 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright 2017, 2018 Red Hat, Inc. + */ + +#define _GNU_SOURCE +#include <link.h> + +#include "nm-default.h" + +#define NM_JAONSSON_C +#include "nm-jansson.h" + +void *_nm_jansson_json_object_iter_value; +void *_nm_jansson_json_object_key_to_iter; +void *_nm_jansson_json_integer; +void *_nm_jansson_json_object_del; +void *_nm_jansson_json_array_get; +void *_nm_jansson_json_array_size; +void *_nm_jansson_json_array_append_new; +void *_nm_jansson_json_string; +void *_nm_jansson_json_object_iter_next; +void *_nm_jansson_json_loads; +void *_nm_jansson_json_dumps; +void *_nm_jansson_json_object_iter_key; +void *_nm_jansson_json_object; +void *_nm_jansson_json_object_get; +void *_nm_jansson_json_array; +void *_nm_jansson_json_false; +void *_nm_jansson_json_delete; +void *_nm_jansson_json_true; +void *_nm_jansson_json_object_size; +void *_nm_jansson_json_object_set_new; +void *_nm_jansson_json_object_iter; +void *_nm_jansson_json_integer_value; +void *_nm_jansson_json_string_value; + +#define TRY_BIND_SYMBOL(symbol) \ + G_STMT_START { \ + void *sym = dlsym (handle, #symbol); \ + if (_nm_jansson_ ## symbol && sym != _nm_jansson_ ## symbol) \ + return FALSE; \ + _nm_jansson_ ## symbol = sym; \ + } G_STMT_END + +static gboolean +bind_symbols (void *handle) +{ + TRY_BIND_SYMBOL (json_object_iter_value); + TRY_BIND_SYMBOL (json_object_key_to_iter); + TRY_BIND_SYMBOL (json_integer); + TRY_BIND_SYMBOL (json_object_del); + TRY_BIND_SYMBOL (json_array_get); + TRY_BIND_SYMBOL (json_array_size); + TRY_BIND_SYMBOL (json_array_append_new); + TRY_BIND_SYMBOL (json_string); + TRY_BIND_SYMBOL (json_object_iter_next); + TRY_BIND_SYMBOL (json_loads); + TRY_BIND_SYMBOL (json_dumps); + TRY_BIND_SYMBOL (json_object_iter_key); + TRY_BIND_SYMBOL (json_object); + TRY_BIND_SYMBOL (json_object_get); + TRY_BIND_SYMBOL (json_array); + TRY_BIND_SYMBOL (json_false); + TRY_BIND_SYMBOL (json_delete); + TRY_BIND_SYMBOL (json_true); + TRY_BIND_SYMBOL (json_object_size); + TRY_BIND_SYMBOL (json_object_set_new); + TRY_BIND_SYMBOL (json_object_iter); + TRY_BIND_SYMBOL (json_integer_value); + TRY_BIND_SYMBOL (json_string_value); + + return TRUE; +} + +gboolean +nm_jansson_load (void) +{ + static enum { + UNKNOWN, + AVAILABLE, + MISSING, + } state = UNKNOWN; + void *handle; + + if (G_LIKELY (state != UNKNOWN)) + goto out; + + /* First just resolve the symbols to see if there's a conflict already. */ + if (!bind_symbols (RTLD_DEFAULT)) + goto out; + + handle = dlopen (JANSSON_SONAME, RTLD_LAZY | RTLD_LOCAL | RTLD_NODELETE | RTLD_DEEPBIND); + if (!handle) + goto out; + + /* Now do the actual binding. */ + if (!bind_symbols (handle)) + goto out; + + state = AVAILABLE; +out: + return state == AVAILABLE; +} diff --git a/libnm-core/nm-jansson.h b/libnm-core/nm-jansson.h new file mode 100644 index 0000000000..d3e8285e8e --- /dev/null +++ b/libnm-core/nm-jansson.h @@ -0,0 +1,45 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright 2017, 2018 Red Hat, Inc. + */ + +gboolean nm_jansson_load (void); + +#ifndef NM_JAONSSON_C +#define json_object_iter_value (*_nm_jansson_json_object_iter_value) +#define json_object_key_to_iter (*_nm_jansson_json_object_key_to_iter) +#define json_integer (*_nm_jansson_json_integer) +#define json_object_del (*_nm_jansson_json_object_del) +#define json_array_get (*_nm_jansson_json_array_get) +#define json_array_size (*_nm_jansson_json_array_size) +#define json_array_append_new (*_nm_jansson_json_array_append_new) +#define json_string (*_nm_jansson_json_string) +#define json_object_iter_next (*_nm_jansson_json_object_iter_next) +#define json_loads (*_nm_jansson_json_loads) +#define json_dumps (*_nm_jansson_json_dumps) +#define json_object_iter_key (*_nm_jansson_json_object_iter_key) +#define json_object (*_nm_jansson_json_object) +#define json_object_get (*_nm_jansson_json_object_get) +#define json_array (*_nm_jansson_json_array) +#define json_false (*_nm_jansson_json_false) +#define json_delete (*_nm_jansson_json_delete) +#define json_true (*_nm_jansson_json_true) +#define json_object_size (*_nm_jansson_json_object_size) +#define json_object_set_new (*_nm_jansson_json_object_set_new) +#define json_object_iter (*_nm_jansson_json_object_iter) +#define json_integer_value (*_nm_jansson_json_integer_value) +#define json_string_value (*_nm_jansson_json_string_value) +#endif diff --git a/libnm-core/nm-utils.c b/libnm-core/nm-utils.c index f845d14cdf..dbb7a99919 100644 --- a/libnm-core/nm-utils.c +++ b/libnm-core/nm-utils.c @@ -35,6 +35,10 @@ #include <net/if.h> #include <linux/pkt_sched.h> +#if WITH_JSON_VALIDATION +#include "nm-jansson.h" +#endif + #include "nm-utils/nm-jansson.h" #include "nm-utils/nm-enum-utils.h" #include "nm-common-macros.h" @@ -4852,6 +4856,41 @@ const char **nm_utils_enum_get_values (GType type, gint from, gint to) /*****************************************************************************/ +static gboolean +_nm_utils_is_json_object_no_validation (const char *str, GError **error) +{ + if (str) { + /* libjansson also requires only utf-8 encoding. */ + if (!g_utf8_validate (str, -1, NULL)) { + g_set_error_literal (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("not valid utf-8")); + return FALSE; + } + while (g_ascii_isspace (str[0])) + str++; + } + + /* do some very basic validation to see if this might be a JSON object. */ + if (str[0] == '{') { + gsize l; + + l = strlen (str) - 1; + while (l > 0 && g_ascii_isspace (str[l])) + l--; + + if (str[l] == '}') + return TRUE; + } + + g_set_error_literal (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("is not a JSON object")); + return FALSE; +} + #if WITH_JSON_VALIDATION static void @@ -5298,6 +5337,9 @@ nm_utils_is_json_object (const char *str, GError **error) return FALSE; } + if (!nm_jansson_load ()) + return _nm_utils_is_json_object_no_validation (str, error); + json = json_loads (str, JSON_REJECT_DUPLICATES, &jerror); if (!json) { g_set_error (error, @@ -5339,6 +5381,8 @@ _nm_utils_team_config_equal (const char *conf1, if (nm_streq0 (conf1, conf2)) return TRUE; + else if (!nm_jansson_load ()) + return FALSE; /* A NULL configuration is equivalent to default value '{}' */ json1 = json_loads (conf1 ?: "{}", JSON_REJECT_DUPLICATES, &jerror); @@ -5396,6 +5440,9 @@ _nm_utils_team_config_get (const char *conf, if (!key) return NULL; + if (!nm_jansson_load ()) + return NULL; + json = json_loads (conf ?: "{}", JSON_REJECT_DUPLICATES, &jerror); /* Invalid json in conf */ @@ -5503,6 +5550,9 @@ _nm_utils_team_config_set (char **conf, g_return_val_if_fail (key, FALSE); + if (!nm_jansson_load ()) + return FALSE; + json = json_loads (*conf?: "{}", JSON_REJECT_DUPLICATES, &jerror); if (!json) return FALSE; @@ -5620,19 +5670,6 @@ nm_utils_is_json_object (const char *str, GError **error) { g_return_val_if_fail (!error || !*error, FALSE); - if (str) { - /* libjansson also requires only utf-8 encoding. */ - if (!g_utf8_validate (str, -1, NULL)) { - g_set_error_literal (error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - _("not valid utf-8")); - return FALSE; - } - while (g_ascii_isspace (str[0])) - str++; - } - if (!str || !str[0]) { g_set_error_literal (error, NM_CONNECTION_ERROR, @@ -5641,23 +5678,7 @@ nm_utils_is_json_object (const char *str, GError **error) return FALSE; } - /* do some very basic validation to see if this might be a JSON object. */ - if (str[0] == '{') { - gsize l; - - l = strlen (str) - 1; - while (l > 0 && g_ascii_isspace (str[l])) - l--; - - if (str[l] == '}') - return TRUE; - } - - g_set_error_literal (error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - _("is not a JSON object")); - return FALSE; + return _nm_utils_is_json_object_no_validation (str, error); } gboolean diff --git a/meson.build b/meson.build index cc704a47a9..5a033dbd7f 100644 --- a/meson.build +++ b/meson.build @@ -179,6 +179,20 @@ libnl_dep = dependency('libnl-3.0', version: '>= 3.2.8', required: false) jansson_dep = dependency('jansson', required: false) config_h.set10('WITH_JANSSON', jansson_dep.found()) +if jansson_dep.found() + jansson_libdir = jansson_dep.get_pkgconfig_variable('libdir') + readelf = find_program('readelf', 'readelf') + res = run_command(readelf, '-d', join_paths(jansson_libdir, 'libjansson.so')) + jansson_soname = '' + foreach line: res.stdout().split('\n') + if line.strip().contains('SONAME') + jansson_soname = line.split('[')[1].split(']')[0] + endif + endforeach + assert(jansson_soname != '', 'Unable to determine Jansson SONAME') + config_h.set_quoted('JANSSON_SONAME', jansson_soname) +endif + libsystemd_dep = dependency('libsystemd', version: '>= 209', required: false) config_h.set10('HAVE_LIBSYSTEMD', libsystemd_dep.found()) |