From: Karel Zak Date: Mon, 13 Jul 2026 13:42:14 +0000 (+0200) Subject: libmount: use shared dl-utils for cryptsetup dlopen X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=dfe0a85946a5c1b56c450e89c9b9cbfee0e22a99;p=thirdparty%2Futil-linux.git libmount: use shared dl-utils for cryptsetup dlopen Move the cryptsetup dlopen wrapper out of hook_veritydev.c into lib/dl-cryptsetup.c with a global cached load function ul_dlopen_libcryptsetup(). The function pointers are resolved once and shared across all callers. This removes the CRYPTSETUP_VIA_DLOPEN conditional -- dlopen is now the only supported way to use libcryptsetup. The library is never linked directly. An ELF .note.dlopen metadata note is emitted so that packaging tools can automatically derive the optional runtime dependency. Also fix the CFLAGS order in libmount Makemodule.am to ensure local include paths (-I for blkid, libmount) come before external pkg-config flags that may pull in system headers. Signed-off-by: Karel Zak --- diff --git a/Makefile.am b/Makefile.am index 07ac717b7..4531d23a5 100644 --- a/Makefile.am +++ b/Makefile.am @@ -218,14 +218,9 @@ edit_cmd += -e 's|@LIBSELINUX[@]||g' endif if HAVE_CRYPTSETUP -if CRYPTSETUP_VIA_DLOPEN edit_cmd += -e 's|@LIBCRYPTSETUP[@]||g' edit_cmd += -e 's|@LIBDL[@]|-ldl|g' else -edit_cmd += -e 's|@LIBCRYPTSETUP[@]|libcryptsetup|g' -edit_cmd += -e 's|@LIBDL[@]||g' -endif -else edit_cmd += -e 's|@LIBCRYPTSETUP[@]||g' edit_cmd += -e 's|@LIBDL[@]||g' endif diff --git a/configure.ac b/configure.ac index f3661932d..5544fd3d1 100644 --- a/configure.ac +++ b/configure.ac @@ -3076,7 +3076,6 @@ AC_ARG_WITH([cryptsetup], AS_IF([test "x$with_cryptsetup" = xno], [ AM_CONDITIONAL([HAVE_CRYPTSETUP], [false]) - AM_CONDITIONAL([CRYPTSETUP_VIA_DLOPEN], [false]) ], [ PKG_CHECK_MODULES([CRYPTSETUP], [libcryptsetup], [AC_DEFINE([HAVE_CRYPTSETUP], [1], [Define if cryptsetup is available]) @@ -3089,21 +3088,11 @@ AS_IF([test "x$with_cryptsetup" = xno], [ AC_CHECK_LIB([cryptsetup], [crypt_activate_by_signed_key], [ AC_DEFINE([HAVE_CRYPT_ACTIVATE_BY_SIGNED_KEY], [1], [Define if crypt_activate_by_signed_key exist in -lcryptsetup]) ]) - AS_IF([test "x$with_cryptsetup" = xdlopen], [ - LIBS="-ldl $LIBS" - AC_CHECK_LIB([dl], [dlsym], [ - AC_DEFINE([CRYPTSETUP_VIA_DLOPEN], [1], [Define if cryptsetup is to be loaded via dlopen]) - AM_CONDITIONAL([CRYPTSETUP_VIA_DLOPEN], [true]) - ], [AC_MSG_ERROR([libdl required to build with cryptsetup support])]) - ], [ - AM_CONDITIONAL([CRYPTSETUP_VIA_DLOPEN], [false]) - ]) CFLAGS="$SAVE_CFLAGS" LIBS="$SAVE_LIBS" have_cryptsetup=yes], [have_cryptsetup=no AM_CONDITIONAL([HAVE_CRYPTSETUP], [false]) - AM_CONDITIONAL([CRYPTSETUP_VIA_DLOPEN], [false]) ]) AS_CASE([$with_cryptsetup:$have_cryptsetup], diff --git a/include/Makemodule.am b/include/Makemodule.am index 70a6cca21..a0627a56a 100644 --- a/include/Makemodule.am +++ b/include/Makemodule.am @@ -22,6 +22,7 @@ dist_noinst_HEADERS += \ include/c_strtod.h \ include/debug.h \ include/default_shell.h \ + include/dl-cryptsetup.h \ include/dl-utils.h \ include/encode.h \ include/env.h \ diff --git a/include/dl-cryptsetup.h b/include/dl-cryptsetup.h new file mode 100644 index 000000000..f0d0b4100 --- /dev/null +++ b/include/dl-cryptsetup.h @@ -0,0 +1,49 @@ +/* + * No copyright is claimed. This code is in the public domain; do with + * it what you wish. + */ +#ifndef UTIL_LINUX_DL_CRYPTSETUP_H +#define UTIL_LINUX_DL_CRYPTSETUP_H + +#ifdef HAVE_CRYPTSETUP + +#include + +#include "dl-utils.h" + +/* Pointers to libcryptsetup functions (initialized by dlsym()) */ +struct ul_cryptsetup_opers { + void (*crypt_set_debug_level)(int); + void (*crypt_set_log_callback)(struct crypt_device *, + void (*log)(int, const char *, void *), void *); + int (*crypt_init_data_device)(struct crypt_device **, + const char *, const char *); + int (*crypt_load)(struct crypt_device *, const char *, void *); + int (*crypt_get_volume_key_size)(struct crypt_device *); +#ifdef HAVE_CRYPT_ACTIVATE_BY_SIGNED_KEY + int (*crypt_activate_by_signed_key)(struct crypt_device *, + const char *, const char *, size_t, + const char *, size_t, uint32_t); +#endif + int (*crypt_activate_by_volume_key)(struct crypt_device *, + const char *, const char *, size_t, uint32_t); + void (*crypt_free)(struct crypt_device *); + int (*crypt_init_by_name)(struct crypt_device **, const char *); + int (*crypt_get_verity_info)(struct crypt_device *, + struct crypt_params_verity *); + int (*crypt_volume_key_get)(struct crypt_device *, int, + char *, size_t *, const char *, size_t); + int (*crypt_deactivate_by_name)(struct crypt_device *, + const char *, uint32_t); +}; + +typedef struct ul_cryptsetup_opers ul_cryptsetup_opers; + +extern struct ul_cryptsetup_opers ul_cryptsetup; + +extern int ul_dlopen_libcryptsetup(void); + +#define cryptsetup_call(_func) (ul_cryptsetup._func) + +#endif /* HAVE_CRYPTSETUP */ +#endif /* UTIL_LINUX_DL_CRYPTSETUP_H */ diff --git a/lib/dl-cryptsetup.c b/lib/dl-cryptsetup.c new file mode 100644 index 000000000..d5c20e8e9 --- /dev/null +++ b/lib/dl-cryptsetup.c @@ -0,0 +1,62 @@ +/* + * No copyright is claimed. This code is in the public domain; do with + * it what you wish. + */ +#include + +#include "c.h" +#include "dl-cryptsetup.h" + +#ifdef HAVE_CRYPTSETUP + +UL_ELF_NOTE_DLOPEN("cryptsetup", + "Support for dm-verity devices", + UL_ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED, + "libcryptsetup.so.12"); + +struct ul_cryptsetup_opers ul_cryptsetup; + +static const struct ul_dlsym ul_cryptsetup_symbols[] = +{ + UL_DLSYM( ul_cryptsetup_opers, crypt_set_debug_level ), + UL_DLSYM( ul_cryptsetup_opers, crypt_set_log_callback ), + UL_DLSYM( ul_cryptsetup_opers, crypt_init_data_device ), + UL_DLSYM( ul_cryptsetup_opers, crypt_load ), + UL_DLSYM( ul_cryptsetup_opers, crypt_get_volume_key_size ), +#ifdef HAVE_CRYPT_ACTIVATE_BY_SIGNED_KEY + UL_DLSYM( ul_cryptsetup_opers, crypt_activate_by_signed_key ), +#endif + UL_DLSYM( ul_cryptsetup_opers, crypt_activate_by_volume_key ), + UL_DLSYM( ul_cryptsetup_opers, crypt_free ), + UL_DLSYM( ul_cryptsetup_opers, crypt_init_by_name ), + UL_DLSYM( ul_cryptsetup_opers, crypt_get_verity_info ), + UL_DLSYM( ul_cryptsetup_opers, crypt_volume_key_get ), + + UL_DLSYM( ul_cryptsetup_opers, crypt_deactivate_by_name ), +}; + +int ul_dlopen_libcryptsetup(void) +{ + /* 0 = not tried, 1 = loaded, -1 = failed */ + static int status = 0; + static void *dl = NULL; + int flags = RTLD_LAZY | RTLD_LOCAL; + + if (status) + return status > 0 ? 0 : -ENOSYS; + +#ifdef RTLD_NODELETE + flags |= RTLD_NODELETE; +#endif +#ifdef RTLD_DEEPBIND + flags |= RTLD_DEEPBIND; +#endif + status = ul_dlopen_symbols("libcryptsetup.so.12", flags, + ul_cryptsetup_symbols, + ARRAY_SIZE(ul_cryptsetup_symbols), + &ul_cryptsetup, &dl) == 0 ? 1 : -1; + + return status > 0 ? 0 : -ENOSYS; +} + +#endif /* HAVE_CRYPTSETUP */ diff --git a/lib/meson.build b/lib/meson.build index c193aeda7..88b3fd639 100644 --- a/lib/meson.build +++ b/lib/meson.build @@ -63,6 +63,9 @@ lib_common_shells = static_library('common_shells', dependencies : lib_econf, ) +dl_utils_c = files('dl-utils.c') +dl_cryptsetup_c = files('dl-cryptsetup.c') + selinux_utils_c = files('selinux-utils.c') caputils_c = files('caputils.c') diff --git a/libmount/meson.build b/libmount/meson.build index 233e0ac65..884a28cdc 100644 --- a/libmount/meson.build +++ b/libmount/meson.build @@ -71,6 +71,10 @@ if enable_btrfs lib_mount_sources += 'src/btrfs.c' endif +if lib_cryptsetup.found() + lib_mount_sources += [dl_utils_c, dl_cryptsetup_c] +endif + libmount_sym = 'src/libmount.sym' libmount_sym_path = '@0@/@1@'.format(meson.current_source_dir(), libmount_sym) @@ -78,12 +82,17 @@ if build_libmount and not have_dirfd and not have_ddfd error('neither dirfd nor ddfd are available') endif +lib__mount_compile_deps = [blkid_dep] +if lib_cryptsetup.found() + lib__mount_compile_deps += lib_cryptsetup.partial_dependency(compile_args : true, includes : true) +endif + lib__mount = static_library( '_mount', lib_mount_sources, include_directories : [dir_include, dir_libmount], - dependencies : [blkid_dep]) + dependencies : lib__mount_compile_deps) lib_mount_static = static_library( 'mount_static', @@ -95,7 +104,7 @@ mount_static_dep = declare_dependency(link_with: lib_mount_static, include_direc lib__mount_deps = [ lib_selinux, - cryptsetup_dlopen ? lib_dl : lib_cryptsetup, + lib_dl, realtime_libs ] diff --git a/libmount/src/Makemodule.am b/libmount/src/Makemodule.am index a017543b7..c854a0bc0 100644 --- a/libmount/src/Makemodule.am +++ b/libmount/src/Makemodule.am @@ -62,11 +62,12 @@ libmount_la_LIBADD = \ $(REALTIME_LIBS) if HAVE_CRYPTSETUP -if CRYPTSETUP_VIA_DLOPEN +libmount_la_SOURCES += \ + lib/dl-utils.c \ + include/dl-utils.h \ + lib/dl-cryptsetup.c \ + include/dl-cryptsetup.h libmount_la_LIBADD += -ldl -else -libmount_la_LIBADD += $(CRYPTSETUP_LIBS) -endif endif if USE_LIBMOUNT_UDEV_SUPPORT @@ -75,11 +76,11 @@ endif libmount_la_CFLAGS = \ $(AM_CFLAGS) \ - $(SOLIB_CFLAGS) \ - $(CRYPTSETUP_CFLAGS) \ -I$(ul_libblkid_incdir) \ -I$(ul_libmount_incdir) \ - -I$(top_srcdir)/libmount/src + -I$(top_srcdir)/libmount/src \ + $(SOLIB_CFLAGS) \ + $(CRYPTSETUP_CFLAGS) EXTRA_libmount_la_DEPENDENCIES = \ libmount/src/libmount.sym @@ -120,11 +121,7 @@ libmount_tests_ldadd += $(SELINUX_LIBS) endif if HAVE_CRYPTSETUP -if CRYPTSETUP_VIA_DLOPEN libmount_tests_ldadd += -ldl -else -libmount_tests_ldadd += $(CRYPTSETUP_LIBS) -endif endif test_mount_cache_SOURCES = libmount/src/cache.c diff --git a/libmount/src/hook_veritydev.c b/libmount/src/hook_veritydev.c index 9a8d9f6fe..92c89b0be 100644 --- a/libmount/src/hook_veritydev.c +++ b/libmount/src/hook_veritydev.c @@ -17,83 +17,18 @@ #ifdef HAVE_CRYPTSETUP -#include +#include "dl-cryptsetup.h" #include "path.h" #include "strutils.h" #include "fileutils.h" #include "pathnames.h" -#ifdef CRYPTSETUP_VIA_DLOPEN -# include - -/* Pointers to libcryptsetup functions (initialized by dlsym()) */ -struct verity_opers { - void (*crypt_set_debug_level)(int); - void (*crypt_set_log_callback)(struct crypt_device *, void (*log)(int, const char *, void *), void *); - int (*crypt_init_data_device)(struct crypt_device **, const char *, const char *); - int (*crypt_load)(struct crypt_device *, const char *, void *); - int (*crypt_get_volume_key_size)(struct crypt_device *); -# ifdef HAVE_CRYPT_ACTIVATE_BY_SIGNED_KEY - int (*crypt_activate_by_signed_key)(struct crypt_device *, const char *, const char *, size_t, const char *, size_t, uint32_t); -# endif - int (*crypt_activate_by_volume_key)(struct crypt_device *, const char *, const char *, size_t, uint32_t); - void (*crypt_free)(struct crypt_device *); - int (*crypt_init_by_name)(struct crypt_device **, const char *); - int (*crypt_get_verity_info)(struct crypt_device *, struct crypt_params_verity *); - int (*crypt_volume_key_get)(struct crypt_device *, int, char *, size_t *, const char *, size_t); - - int (*crypt_deactivate_by_name)(struct crypt_device *, const char *, uint32_t); -}; - -/* libcryptsetup functions names and offsets in 'struct verity_opers' */ -struct verity_sym { - const char *name; - size_t offset; /* offset of the symbol in verity_opers */ -}; - -# define DEF_VERITY_SYM(_name) \ - { \ - .name = # _name, \ - .offset = offsetof(struct verity_opers, _name), \ - } - -/* All required symbols */ -static const struct verity_sym verity_symbols[] = -{ - DEF_VERITY_SYM( crypt_set_debug_level ), - DEF_VERITY_SYM( crypt_set_log_callback ), - DEF_VERITY_SYM( crypt_init_data_device ), - DEF_VERITY_SYM( crypt_load ), - DEF_VERITY_SYM( crypt_get_volume_key_size ), -# ifdef HAVE_CRYPT_ACTIVATE_BY_SIGNED_KEY - DEF_VERITY_SYM( crypt_activate_by_signed_key ), -# endif - DEF_VERITY_SYM( crypt_activate_by_volume_key ), - DEF_VERITY_SYM( crypt_free ), - DEF_VERITY_SYM( crypt_init_by_name ), - DEF_VERITY_SYM( crypt_get_verity_info ), - DEF_VERITY_SYM( crypt_volume_key_get ), - - DEF_VERITY_SYM( crypt_deactivate_by_name ), -}; -#endif /* CRYPTSETUP_VIA_DLOPEN */ - - /* Data used by all verity hooks */ struct hookset_data { char *devname; /* the device */ -#ifdef CRYPTSETUP_VIA_DLOPEN - void *dl; /* dlopen() */ - struct verity_opers dl_funcs; /* dlsym() */ -#endif }; -/* libcryptsetup call -- dlopen version requires 'struct hookset_data *hsd' */ -#ifdef CRYPTSETUP_VIA_DLOPEN -# define verity_call(_func) (hsd->dl_funcs._func) -#else -# define verity_call(_func) (_func) -#endif +#define verity_call(_func) cryptsetup_call(_func) static void delete_veritydev(struct libmnt_context *cxt, @@ -101,63 +36,6 @@ static void delete_veritydev(struct libmnt_context *cxt, struct hookset_data *hsd); -#ifdef CRYPTSETUP_VIA_DLOPEN -static int load_libcryptsetup_symbols(struct libmnt_context *cxt, - struct hookset_data *hsd) -{ - size_t i; - const char *errmsg = NULL; - int flags = RTLD_LAZY | RTLD_LOCAL; - - assert(cxt); - assert(hsd); - assert(hsd->dl == NULL); - - /* glibc extension: mnt_context_deferred_delete_veritydev is called immediately after, don't unload on dl_close */ -#ifdef RTLD_NODELETE - flags |= RTLD_NODELETE; -#endif - /* glibc extension: might help to avoid further symbols clashes */ -#ifdef RTLD_DEEPBIND - flags |= RTLD_DEEPBIND; -#endif - /* Don't rely on errno; the dlopen API may not use it. Also, note that - * dlerror() provides complete messages that do not need any additional - * introduction when printed to end users. */ - errno = 0; - - hsd->dl = dlopen("libcryptsetup.so.12", flags); - if (!hsd->dl) { - errmsg = dlerror(); - if (errmsg) - mnt_context_sprintf_mesg(cxt, "e %s", errmsg); - goto failed; - } - - /* clear errors first, then load all the libcryptsetup symbols */ - dlerror(); - - /* dlsym() */ - for (i = 0; i < ARRAY_SIZE(verity_symbols); i++) { - const struct verity_sym *def = &verity_symbols[i]; - void **sym; - - sym = (void **) ((char *) (&hsd->dl_funcs) + def->offset); - *sym = dlsym(hsd->dl, def->name); - - errmsg = dlerror(); - if (errmsg) { - mnt_context_sprintf_mesg(cxt, "e %s", errmsg); - goto failed; - } - } - return 0; -failed: - if (!errno) - errno = ENOTSUP; - return -errno; -} -#endif /* libcryptsetup callback */ static void libcryptsetup_log(int level __attribute__((__unused__)), @@ -177,10 +55,6 @@ static void free_hookset_data( struct libmnt_context *cxt, return; if (hsd->devname) delete_veritydev(cxt, hs, hsd); -#ifdef CRYPTSETUP_VIA_DLOPEN - if (hsd->dl) - dlclose(hsd->dl); -#endif free(hsd); mnt_context_set_hookset_data(cxt, hs, NULL); } @@ -192,6 +66,9 @@ static struct hookset_data *new_hookset_data( { struct hookset_data *hsd; + if (ul_dlopen_libcryptsetup() != 0) + return NULL; + hsd = calloc(1, sizeof(struct hookset_data)); if (!hsd) return NULL; @@ -199,10 +76,6 @@ static struct hookset_data *new_hookset_data( if (mnt_context_set_hookset_data(cxt, hs, hsd) != 0) goto failed; -#ifdef CRYPTSETUP_VIA_DLOPEN - if (load_libcryptsetup_symbols(cxt, hsd) != 0) - goto failed; -#endif if (mnt_context_is_verbose(cxt)) verity_call( crypt_set_debug_level(CRYPT_DEBUG_ALL) ); diff --git a/meson.build b/meson.build index 5f556ebce..c4fe2c6f3 100644 --- a/meson.build +++ b/meson.build @@ -459,23 +459,16 @@ lib_cryptsetup = dependency( required : get_option('cryptsetup')) conf.set('HAVE_CRYPTSETUP', lib_cryptsetup.found() ? 1 : false) -cryptsetup_dlopen = get_option('cryptsetup').allowed() and get_option('cryptsetup-dlopen').enabled() -if cryptsetup_dlopen - if meson.version().version_compare('>= 0.62.0') - lib_dl = dependency('dl') - else - lib_dl = cc.find_library('dl') - endif - conf.set('CRYPTSETUP_VIA_DLOPEN', 1) - summary('cryptsetup support (dlopen)', - 'enabled', - section : 'components') +if meson.version().version_compare('>= 0.62.0') + lib_dl = dependency('dl') else - summary('cryptsetup support', - lib_cryptsetup.found() ? 'enabled' : 'disabled', - section : 'components') + lib_dl = cc.find_library('dl') endif +summary('cryptsetup support (dlopen)', + lib_cryptsetup.found() ? 'enabled' : 'disabled', + section : 'components') + have = cc.has_function( 'crypt_activate_by_signed_key', dependencies : lib_cryptsetup) diff --git a/meson_options.txt b/meson_options.txt index 527246fd4..5ce19ce5b 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -6,7 +6,9 @@ option('ncurses', type : 'feature') option('slang', type : 'feature', value : 'disabled', description : 'compile cfdisk with slang rather than ncurses') option('cryptsetup', type : 'feature') -option('cryptsetup-dlopen', type : 'feature') +option('cryptsetup-dlopen', type : 'feature', + deprecated : true, + description : 'Deprecated, dlopen is now always used') option('zlib', type : 'feature') option('readline', type : 'feature') option('nls', type : 'feature')