Compare commits

..

11 Commits

Author SHA1 Message Date
Lennart Poettering 86e443de2f
Merge pull request #16915 from poettering/cryptsetup-dlopen
pid1,repart,growfs: make libcryptsetup a dlopen() style dep
2020-09-03 14:57:29 +02:00
Lennart Poettering 7cc60ea414
Merge pull request #16821 from cgzones/selinux_status
selinux: use SELinux status page
2020-09-03 14:55:08 +02:00
Lennart Poettering c457bf4741
Merge pull request #16940 from keszybz/socket-enotconn-cleanup
Cleanup socket enotconn handling
2020-09-03 14:51:02 +02:00
Zbigniew Jędrzejewski-Szmek 5cf09553c3 core/socket: use _cleanup_ to close the connection fd
Removing the gotos would lead to a lot of duplicated code, so I left them
as they were.
2020-09-02 18:18:28 +02:00
Zbigniew Jędrzejewski-Szmek b669c20f97 core/socket: fold socket_instantiate_service() into socket_enter_running()
socket_instantiate_service() was doing unit_ref_set(), and the caller was
immediately doing unit_ref_unset(). After we get rid of this, it doesn't seem
worth it to have two functions.
2020-09-02 18:18:28 +02:00
Zbigniew Jędrzejewski-Szmek 86e045ecef core/socket: we may get ENOTCONN from socket_instantiate_service()
This means that the connection was aborted before we even got to figure out
what the service name will be. Let's treat this as a non-event and close the
connection fd without any further messages.

Code last changed in 934ef6a5.
Reported-by: Thiago Macieira <thiago.macieira@intel.com>

With the patch:
systemd[1]: foobar.socket: Incoming traffic
systemd[1]: foobar.socket: Got ENOTCONN on incoming socket, assuming aborted connection attempt, ignoring.
...

Also, when we get ENOMEM, don't give the hint about missing unit.
2020-09-02 18:17:30 +02:00
Lennart Poettering a52dc0b6f3 update TODO 2020-09-02 15:04:06 +02:00
Lennart Poettering 0d12936d9a shared: make libcryptsetup dep dlopen
Let's make libcryptsetup a dlopen() style dep for PID 1 (i.e. for
RootImage= and stuff), systemd-growfs and systemd-repart. (But leave to
be a regulra dep in systemd-cryptsetup, systemd-veritysetup and
systemd-homed since for them the libcryptsetup support is not auxiliary
but pretty much at the core of what they do.)

This should be useful for container images that want systemd in the
payload but don't care for the cryptsetup logic since dm-crypt and stuff
isn't available in containers anyway.

Fixes: #8249
2020-09-02 15:04:06 +02:00
Lennart Poettering 1e2f32305c shared: rename crypt-util.c → cryptsetup-util.c
"crypt-util.c" is such a generic name, let's avoid that, in particular
as libc's/libcrypt's crypt() function is so generically named too that
one might thing this is about that. Let's hence be more precise, and
make clear that this is about cryptsetup, and nothing else.

We already had cryptsetup-util.[ch] in src/cryptsetup/ doing keyfile
management. To avoid the needless confusion, let's rename that file to
cryptsetup-keyfile.[ch].
2020-09-02 15:00:32 +02:00
Christian Göttsche 2df2152c20 selinux: fork label-aware children with up-to-date label database
The parent process may not perform any label operation, so the
database might not get updated on a SELinux policy change on its own.

Reload the label database once on a policy change, instead of n times
in every started child.
2020-08-27 10:28:53 +02:00
Christian Göttsche fd5e402fa9 selinux: use SELinux status page
Switch from security_getenforce() and netlink notifications to the
SELinux status page.

This usage saves system calls and will also be the default in
libselinux > 3.1 [1].

[1]: 05bdc03130
2020-08-27 10:28:53 +02:00
22 changed files with 365 additions and 185 deletions

3
TODO
View File

@ -91,8 +91,7 @@ Features:
- elfutils (always)
- p11-kit-trust (always)
- kmod-libs (only when called from PID 1)
- cryptsetup-libs (only in RootImage= handling in PID 1, but not in systemd-cryptsetup)
- similar: libblkid
- libblkid (only in RootImage= handling in PID 1, but not elsewhere)
- libpam (only when called from PID 1)
- bzip2, xz, lz4 (always — gzip and zstd should probably stay static deps the way they are,
since they are so basic and our defaults)

View File

@ -2272,8 +2272,8 @@ executable(
if conf.get('HAVE_LIBCRYPTSETUP') == 1
systemd_cryptsetup_sources = files('''
src/cryptsetup/cryptsetup-pkcs11.h
src/cryptsetup/cryptsetup-util.c
src/cryptsetup/cryptsetup-util.h
src/cryptsetup/cryptsetup-keyfile.c
src/cryptsetup/cryptsetup-keyfile.h
src/cryptsetup/cryptsetup.c
'''.split())
@ -2297,7 +2297,6 @@ if conf.get('HAVE_LIBCRYPTSETUP') == 1
'src/cryptsetup/cryptsetup-generator.c',
include_directories : includes,
link_with : [libshared],
dependencies : [libcryptsetup],
install_rpath : rootlibexecdir,
install : true,
install_dir : systemgeneratordir)
@ -2317,7 +2316,6 @@ if conf.get('HAVE_LIBCRYPTSETUP') == 1
'src/veritysetup/veritysetup-generator.c',
include_directories : includes,
link_with : [libshared],
dependencies : [libcryptsetup],
install_rpath : rootlibexecdir,
install : true,
install_dir : systemgeneratordir)
@ -2672,7 +2670,6 @@ if conf.get('ENABLE_REPART') == 1
include_directories : includes,
link_with : [libshared],
dependencies : [threads,
libcryptsetup,
libblkid,
libfdisk,
libopenssl],
@ -2755,7 +2752,6 @@ executable('systemd-growfs',
'src/partition/growfs.c',
include_directories : includes,
link_with : [libshared],
dependencies : [libcryptsetup],
install_rpath : rootlibexecdir,
install : true,
install_dir : rootlibexecdir)

View File

@ -35,14 +35,17 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(context_t, context_free);
static int mac_selinux_reload(int seqno);
static int cached_use = -1;
static bool initialized = false;
static int (*enforcing_status_func)(void) = security_getenforce;
static int last_policyload = 0;
static struct selabel_handle *label_hnd = NULL;
#define log_enforcing(...) \
log_full(security_getenforce() != 0 ? LOG_ERR : LOG_WARNING, __VA_ARGS__)
log_full(mac_selinux_enforcing() ? LOG_ERR : LOG_WARNING, __VA_ARGS__)
#define log_enforcing_errno(error, ...) \
({ \
bool _enforcing = security_getenforce() != 0; \
bool _enforcing = mac_selinux_enforcing(); \
int _level = _enforcing ? LOG_ERR : LOG_WARNING; \
int _e = (error); \
\
@ -66,32 +69,33 @@ bool mac_selinux_use(void) {
#endif
}
bool mac_selinux_enforcing(void) {
#if HAVE_SELINUX
return enforcing_status_func() != 0;
#else
return false;
#endif
}
void mac_selinux_retest(void) {
#if HAVE_SELINUX
cached_use = -1;
#endif
}
int mac_selinux_init(void) {
#if HAVE_SELINUX
static int open_label_db(void) {
struct selabel_handle *hnd;
usec_t before_timestamp, after_timestamp;
struct mallinfo before_mallinfo, after_mallinfo;
char timespan[FORMAT_TIMESPAN_MAX];
int l;
selinux_set_callback(SELINUX_CB_POLICYLOAD, (union selinux_callback) mac_selinux_reload);
if (label_hnd)
return 0;
if (!mac_selinux_use())
return 0;
before_mallinfo = mallinfo();
before_timestamp = now(CLOCK_MONOTONIC);
label_hnd = selabel_open(SELABEL_CTX_FILE, NULL, 0);
if (!label_hnd)
hnd = selabel_open(SELABEL_CTX_FILE, NULL, 0);
if (!hnd)
return log_enforcing_errno(errno, "Failed to initialize SELinux labeling handle: %m");
after_timestamp = now(CLOCK_MONOTONIC);
@ -103,37 +107,94 @@ int mac_selinux_init(void) {
format_timespan(timespan, sizeof(timespan), after_timestamp - before_timestamp, 0),
(l+1023)/1024);
/* release memory after measurement */
if (label_hnd)
selabel_close(label_hnd);
label_hnd = TAKE_PTR(hnd);
return 0;
}
#endif
int mac_selinux_init(void) {
#if HAVE_SELINUX
int r;
if (initialized)
return 0;
if (!mac_selinux_use())
return 0;
r = selinux_status_open(/* no netlink fallback */ 0);
if (r < 0)
return log_enforcing_errno(errno, "Failed to open SELinux status page: %m");
r = open_label_db();
if (r < 0) {
selinux_status_close();
return r;
}
/* save the current policyload sequence number, so `mac_selinux_maybe_reload()` does
not trigger on first call without any actual change */
last_policyload = selinux_status_policyload();
/* now that the SELinux status page has been successfully opened,
retrieve the enforcing status over it (to avoid system calls in `security_getenforce()`) */
enforcing_status_func = selinux_status_getenforce;
initialized = true;
#endif
return 0;
}
void mac_selinux_maybe_reload(void) {
#if HAVE_SELINUX
int r;
r = selinux_status_updated();
if (r < 0)
log_debug_errno(errno, "Failed to update SELinux from status page: %m");
if (r > 0) {
int policyload;
log_debug("SELinux status page update");
/* from libselinux > 3.1 callbacks gets automatically called, see
https://github.com/SELinuxProject/selinux/commit/05bdc03130d741e53e1fb45a958d0a2c184be503 */
/* only reload on policy changes, not enforcing status changes */
policyload = selinux_status_policyload();
if (policyload != last_policyload) {
mac_selinux_reload(policyload);
last_policyload = policyload;
}
}
#endif
}
void mac_selinux_finish(void) {
#if HAVE_SELINUX
if (!label_hnd)
return;
if (label_hnd) {
selabel_close(label_hnd);
label_hnd = NULL;
}
selabel_close(label_hnd);
label_hnd = NULL;
enforcing_status_func = security_getenforce;
selinux_status_close();
initialized = false;
#endif
}
#if HAVE_SELINUX
static int mac_selinux_reload(int seqno) {
struct selabel_handle *backup_label_hnd;
log_debug("SELinux reload %d", seqno);
if (!label_hnd)
return 0;
backup_label_hnd = TAKE_PTR(label_hnd);
/* try to initialize new handle
* on success close backup
* on failure restore backup */
if (mac_selinux_init() == 0)
selabel_close(backup_label_hnd);
else
label_hnd = backup_label_hnd;
(void) open_label_db();
return 0;
}
@ -167,7 +228,7 @@ int mac_selinux_fix_container(const char *path, const char *inside_path, LabelFi
return -errno;
/* Check for policy reload so 'label_hnd' is kept up-to-date by callbacks */
(void) avc_netlink_check_nb();
mac_selinux_maybe_reload();
if (selabel_lookup_raw(label_hnd, &fcon, inside_path, st.st_mode) < 0) {
r = -errno;
@ -363,7 +424,7 @@ static int selinux_create_file_prepare_abspath(const char *abspath, mode_t mode)
assert(path_is_absolute(abspath));
/* Check for policy reload so 'label_hnd' is kept up-to-date by callbacks */
(void) avc_netlink_check_nb();
mac_selinux_maybe_reload();
r = selabel_lookup_raw(label_hnd, &filecon, abspath, mode);
if (r < 0) {
@ -507,7 +568,7 @@ int mac_selinux_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) {
path = strndupa(un->sun_path, addrlen - offsetof(struct sockaddr_un, sun_path));
/* Check for policy reload so 'label_hnd' is kept up-to-date by callbacks */
(void) avc_netlink_check_nb();
mac_selinux_maybe_reload();
if (path_is_absolute(path))
r = selabel_lookup_raw(label_hnd, &fcon, path, S_IFSOCK);

View File

@ -17,8 +17,10 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(char*, freecon);
bool mac_selinux_use(void);
void mac_selinux_retest(void);
bool mac_selinux_enforcing(void);
int mac_selinux_init(void);
void mac_selinux_maybe_reload(void);
void mac_selinux_finish(void);
int mac_selinux_fix_container(const char *path, const char *inside_path, LabelFixFlags flags);

View File

@ -4599,6 +4599,10 @@ int exec_spawn(Unit *unit,
if (!line)
return log_oom();
/* fork with up-to-date SELinux label database, so the child inherits the up-to-date db
and, until the next SELinux policy changes, we safe further reloads in future children */
mac_selinux_maybe_reload();
log_struct(LOG_DEBUG,
LOG_UNIT_MESSAGE(unit, "About to execute: %s", line),
"EXECUTABLE=%s", command->path,

View File

@ -198,7 +198,7 @@ int mac_selinux_generic_access_check(
return r;
/* delay call until we checked in `access_init()` if SELinux is actually enabled */
enforce = security_getenforce() != 0;
enforce = mac_selinux_enforcing();
r = sd_bus_query_sender_creds(
message,
@ -278,7 +278,7 @@ int mac_selinux_generic_access_check(
return enforce ? r : 0;
}
#else
#else /* HAVE_SELINUX */
int mac_selinux_generic_access_check(
sd_bus_message *message,
@ -289,4 +289,4 @@ int mac_selinux_generic_access_check(
return 0;
}
#endif
#endif /* HAVE_SELINUX */

View File

@ -18,6 +18,7 @@
#include "dbus-socket.h"
#include "dbus-unit.h"
#include "def.h"
#include "errno-list.h"
#include "exit-status.h"
#include "fd-util.h"
#include "format-util.h"
@ -206,27 +207,6 @@ static int socket_arm_timer(Socket *s, usec_t usec) {
return 0;
}
static int socket_instantiate_service(Socket *s, int cfd) {
Unit *service;
int r;
assert(s);
assert(cfd >= 0);
/* This fills in s->service if it isn't filled in yet. For Accept=yes sockets we create the next
* connection service here. For Accept=no this is mostly a NOP since the service is figured out at
* load time anyway. */
r = socket_load_service_unit(s, cfd, &service);
if (r < 0)
return r;
unit_ref_set(&s->service, UNIT(s), service);
return unit_add_two_dependencies(UNIT(s), UNIT_BEFORE, UNIT_TRIGGERS, service,
false, UNIT_DEPENDENCY_IMPLICIT);
}
static bool have_non_accept_socket(Socket *s) {
SocketPort *p;
@ -1424,11 +1404,12 @@ int socket_load_service_unit(Socket *s, int cfd, Unit **ret) {
if (cfd >= 0) {
r = instance_from_socket(cfd, s->n_accepted, &instance);
if (r == -ENOTCONN)
/* ENOTCONN is legitimate if TCP RST was received.
* This connection is over, but the socket unit lives on. */
if (ERRNO_IS_DISCONNECT(r))
/* ENOTCONN is legitimate if TCP RST was received. Other socket families might return
* different errors. This connection is over, but the socket unit lives on. */
return log_unit_debug_errno(UNIT(s), r,
"Got ENOTCONN on incoming socket, assuming aborted connection attempt, ignoring.");
"Got %s on incoming socket, assuming aborted connection attempt, ignoring.",
errno_to_name(r));
if (r < 0)
return r;
}
@ -2326,13 +2307,14 @@ static void flush_ports(Socket *s) {
}
}
static void socket_enter_running(Socket *s, int cfd) {
static void socket_enter_running(Socket *s, int cfd_in) {
/* Note that this call takes possession of the connection fd passed. It either has to assign it
* somewhere or close it. */
_cleanup_close_ int cfd = cfd_in;
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
int r;
/* Note that this call takes possession of the connection fd passed. It either has to assign it somewhere or
* close it. */
assert(s);
/* We don't take connections anymore if we are supposed to shut down anyway */
@ -2342,9 +2324,8 @@ static void socket_enter_running(Socket *s, int cfd) {
if (cfd >= 0)
goto refuse;
else
flush_ports(s);
flush_ports(s);
return;
}
@ -2370,8 +2351,8 @@ static void socket_enter_running(Socket *s, int cfd) {
if (!pending) {
if (!UNIT_ISSET(s->service)) {
log_unit_error(UNIT(s), "Service to activate vanished, refusing activation.");
r = -ENOENT;
r = log_unit_error_errno(UNIT(s), SYNTHETIC_ERRNO(ENOENT),
"Service to activate vanished, refusing activation.");
goto fail;
}
@ -2383,7 +2364,7 @@ static void socket_enter_running(Socket *s, int cfd) {
socket_set_state(s, SOCKET_RUNNING);
} else {
_cleanup_(socket_peer_unrefp) SocketPeer *p = NULL;
Service *service;
Unit *service;
if (s->n_connections >= s->max_connections) {
log_unit_warning(UNIT(s), "Too many incoming connections (%u), dropping connection.",
@ -2393,8 +2374,10 @@ static void socket_enter_running(Socket *s, int cfd) {
if (s->max_connections_per_source > 0) {
r = socket_acquire_peer(s, cfd, &p);
if (r < 0)
goto refuse;
if (ERRNO_IS_DISCONNECT(r))
return;
if (r < 0) /* We didn't have enough resources to acquire peer information, let's fail. */
goto fail;
if (r > 0 && p->n_ref > s->max_connections_per_source) {
_cleanup_free_ char *t = NULL;
@ -2407,29 +2390,35 @@ static void socket_enter_running(Socket *s, int cfd) {
}
}
r = socket_instantiate_service(s, cfd);
r = socket_load_service_unit(s, cfd, &service);
if (ERRNO_IS_DISCONNECT(r))
return;
if (r < 0)
goto fail;
service = SERVICE(UNIT_DEREF(s->service));
unit_ref_unset(&s->service);
r = unit_add_two_dependencies(UNIT(s), UNIT_BEFORE, UNIT_TRIGGERS, service,
false, UNIT_DEPENDENCY_IMPLICIT);
if (r < 0)
goto fail;
s->n_accepted++;
r = service_set_socket_fd(service, cfd, s, s->selinux_context_from_net);
r = service_set_socket_fd(SERVICE(service), cfd, s, s->selinux_context_from_net);
if (ERRNO_IS_DISCONNECT(r))
return;
if (r < 0)
goto fail;
TAKE_FD(cfd); /* We passed ownership of the fd to the service now. Forget it here. */
s->n_connections++;
service->peer = TAKE_PTR(p); /* Pass ownership of the peer reference */
SERVICE(service)->peer = TAKE_PTR(p); /* Pass ownership of the peer reference */
r = manager_add_job(UNIT(s)->manager, JOB_START, UNIT(service), JOB_REPLACE, NULL, &error, NULL);
r = manager_add_job(UNIT(s)->manager, JOB_START, service, JOB_REPLACE, NULL, &error, NULL);
if (r < 0) {
/* We failed to activate the new service, but it still exists. Let's make sure the
* service closes and forgets the connection fd again, immediately. */
service_close_socket_fd(service);
service_close_socket_fd(SERVICE(service));
goto fail;
}
@ -2437,20 +2426,23 @@ static void socket_enter_running(Socket *s, int cfd) {
unit_add_to_dbus_queue(UNIT(s));
}
TAKE_FD(cfd);
return;
refuse:
s->n_refused++;
safe_close(cfd);
return;
fail:
log_unit_warning(UNIT(s), "Failed to queue service startup job (Maybe the service file is missing or not a %s unit?): %s",
cfd >= 0 ? "template" : "non-template",
bus_error_message(&error, r));
if (ERRNO_IS_RESOURCE(r))
log_unit_warning(UNIT(s), "Failed to queue service startup job: %s",
bus_error_message(&error, r));
else
log_unit_warning(UNIT(s), "Failed to queue service startup job (Maybe the service file is missing or not a %s unit?): %s",
cfd >= 0 ? "template" : "non-template",
bus_error_message(&error, r));
socket_enter_stop_pre(s, SOCKET_FAILURE_RESOURCES);
safe_close(cfd);
}
static void socket_run_next(Socket *s) {

View File

@ -2,7 +2,7 @@
#include <unistd.h>
#include "cryptsetup-util.h"
#include "cryptsetup-keyfile.h"
#include "fd-util.h"
#include "format-util.h"
#include "memory-util.h"

View File

@ -10,7 +10,7 @@
#include "alloc-util.h"
#include "ask-password-api.h"
#include "cryptsetup-pkcs11.h"
#include "cryptsetup-util.h"
#include "cryptsetup-keyfile.h"
#include "escape.h"
#include "fd-util.h"
#include "format-util.h"

View File

@ -11,7 +11,7 @@
#include "alloc-util.h"
#include "ask-password-api.h"
#include "crypt-util.h"
#include "cryptsetup-keyfile.h"
#include "cryptsetup-pkcs11.h"
#include "cryptsetup-util.h"
#include "device-util.h"

View File

@ -1,7 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
#include "crypt-util.h"
#include "cryptsetup-util.h"
#include "homework.h"
#include "user-record.h"

View File

@ -11,7 +11,7 @@
#include <sys/vfs.h>
#include "blockdev-util.h"
#include "crypt-util.h"
#include "cryptsetup-util.h"
#include "device-nodes.h"
#include "dissect-image.h"
#include "escape.h"
@ -30,11 +30,15 @@ static bool arg_dry_run = false;
#if HAVE_LIBCRYPTSETUP
static int resize_crypt_luks_device(dev_t devno, const char *fstype, dev_t main_devno) {
_cleanup_free_ char *devpath = NULL, *main_devpath = NULL;
_cleanup_(crypt_freep) struct crypt_device *cd = NULL;
_cleanup_(sym_crypt_freep) struct crypt_device *cd = NULL;
_cleanup_close_ int main_devfd = -1;
uint64_t size;
int r;
r = dlopen_cryptsetup();
if (r < 0)
return log_error_errno(r, "Cannot resize LUKS device: %m");
r = device_path_make_major_minor(S_IFBLK, main_devno, &main_devpath);
if (r < 0)
return log_error_errno(r, "Failed to format device major/minor path: %m");
@ -52,20 +56,20 @@ static int resize_crypt_luks_device(dev_t devno, const char *fstype, dev_t main_
if (r < 0)
return log_error_errno(r, "Failed to format major/minor path: %m");
r = crypt_init(&cd, devpath);
r = sym_crypt_init(&cd, devpath);
if (r < 0)
return log_error_errno(r, "crypt_init(\"%s\") failed: %m", devpath);
cryptsetup_enable_logging(cd);
r = crypt_load(cd, CRYPT_LUKS, NULL);
r = sym_crypt_load(cd, CRYPT_LUKS, NULL);
if (r < 0)
return log_debug_errno(r, "Failed to load LUKS metadata for %s: %m", devpath);
if (arg_dry_run)
return 0;
r = crypt_resize(cd, main_devpath, 0);
r = sym_crypt_resize(cd, main_devpath, 0);
if (r < 0)
return log_error_errno(r, "crypt_resize() of %s failed: %m", devpath);

View File

@ -24,7 +24,7 @@
#include "btrfs-util.h"
#include "conf-files.h"
#include "conf-parser.h"
#include "crypt-util.h"
#include "cryptsetup-util.h"
#include "def.h"
#include "efivars.h"
#include "errno-util.h"
@ -2370,7 +2370,7 @@ static int partition_encrypt(
char **ret_volume,
int *ret_fd) {
_cleanup_(crypt_freep) struct crypt_device *cd = NULL;
_cleanup_(sym_crypt_freep) struct crypt_device *cd = NULL;
_cleanup_(erase_and_freep) void *volume_key = NULL;
_cleanup_free_ char *dm_name = NULL, *vol = NULL;
char suuid[ID128_UUID_STRING_MAX];
@ -2381,6 +2381,10 @@ static int partition_encrypt(
assert(p);
assert(p->encrypt);
r = dlopen_cryptsetup();
if (r < 0)
return log_error_errno(r, "libcryptsetup not found, cannot encrypt: %m");
if (asprintf(&dm_name, "luks-repart-%08" PRIx64, random_u64()) < 0)
return log_oom();
@ -2404,13 +2408,13 @@ static int partition_encrypt(
if (r < 0)
return log_error_errno(r, "Failed to generate volume key: %m");
r = crypt_init(&cd, node);
r = sym_crypt_init(&cd, node);
if (r < 0)
return log_error_errno(r, "Failed to allocate libcryptsetup context: %m");
cryptsetup_enable_logging(cd);
r = crypt_format(cd,
r = sym_crypt_format(cd,
CRYPT_LUKS2,
"aes",
"xts-plain64",
@ -2424,7 +2428,7 @@ static int partition_encrypt(
if (r < 0)
return log_error_errno(r, "Failed to LUKS2 format future partition: %m");
r = crypt_keyslot_add_by_volume_key(
r = sym_crypt_keyslot_add_by_volume_key(
cd,
CRYPT_ANY_SLOT,
volume_key,
@ -2434,7 +2438,7 @@ static int partition_encrypt(
if (r < 0)
return log_error_errno(r, "Failed to add LUKS2 key: %m");
r = crypt_activate_by_volume_key(
r = sym_crypt_activate_by_volume_key(
cd,
dm_name,
volume_key,
@ -2474,7 +2478,7 @@ static int deactivate_luks(struct crypt_device *cd, const char *node) {
/* udev or so might access out block device in the background while we are done. Let's hence force
* detach the volume. We sync'ed before, hence this should be safe. */
r = crypt_deactivate_by_name(cd, basename(node), CRYPT_DEACTIVATE_FORCE);
r = sym_crypt_deactivate_by_name(cd, basename(node), CRYPT_DEACTIVATE_FORCE);
if (r < 0)
return log_error_errno(r, "Failed to deactivate LUKS device: %m");
@ -2490,7 +2494,7 @@ static int context_copy_blocks(Context *context) {
/* Copy in file systems on the block level */
LIST_FOREACH(partitions, p, context->partitions) {
_cleanup_(crypt_freep) struct crypt_device *cd = NULL;
_cleanup_(sym_crypt_freep) struct crypt_device *cd = NULL;
_cleanup_(loop_device_unrefp) LoopDevice *d = NULL;
_cleanup_free_ char *encrypted = NULL;
_cleanup_close_ int encrypted_dev_fd = -1;
@ -2553,7 +2557,7 @@ static int context_copy_blocks(Context *context) {
if (r < 0)
return r;
crypt_free(cd);
sym_crypt_free(cd);
cd = NULL;
r = loop_device_sync(d);
@ -2694,7 +2698,7 @@ static int context_mkfs(Context *context) {
/* Make a file system */
LIST_FOREACH(partitions, p, context->partitions) {
_cleanup_(crypt_freep) struct crypt_device *cd = NULL;
_cleanup_(sym_crypt_freep) struct crypt_device *cd = NULL;
_cleanup_(loop_device_unrefp) LoopDevice *d = NULL;
_cleanup_free_ char *encrypted = NULL;
_cleanup_close_ int encrypted_dev_fd = -1;
@ -2781,7 +2785,7 @@ static int context_mkfs(Context *context) {
if (r < 0)
return r;
crypt_free(cd);
sym_crypt_free(cd);
cd = NULL;
}

View File

@ -1,34 +0,0 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#if HAVE_LIBCRYPTSETUP
#include "crypt-util.h"
#include "log.h"
static void cryptsetup_log_glue(int level, const char *msg, void *usrptr) {
switch (level) {
case CRYPT_LOG_NORMAL:
level = LOG_NOTICE;
break;
case CRYPT_LOG_ERROR:
level = LOG_ERR;
break;
case CRYPT_LOG_VERBOSE:
level = LOG_INFO;
break;
case CRYPT_LOG_DEBUG:
level = LOG_DEBUG;
break;
default:
log_error("Unknown libcryptsetup log level: %d", level);
level = LOG_ERR;
}
log_full(level, "%s", msg);
}
void cryptsetup_enable_logging(struct crypt_device *cd) {
crypt_set_log_callback(cd, cryptsetup_log_glue, NULL);
crypt_set_debug_level(DEBUG_LOGGING ? CRYPT_DEBUG_ALL : CRYPT_DEBUG_NONE);
}
#endif

View File

@ -1,12 +0,0 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
#if HAVE_LIBCRYPTSETUP
#include <libcryptsetup.h>
#include "macro.h"
DEFINE_TRIVIAL_CLEANUP_FUNC(struct crypt_device *, crypt_free);
void cryptsetup_enable_logging(struct crypt_device *cd);
#endif

View File

@ -0,0 +1,111 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#if HAVE_LIBCRYPTSETUP
#include "alloc-util.h"
#include "cryptsetup-util.h"
#include "dlfcn-util.h"
#include "log.h"
static void *cryptsetup_dl = NULL;
int (*sym_crypt_activate_by_passphrase)(struct crypt_device *cd, const char *name, int keyslot, const char *passphrase, size_t passphrase_size, uint32_t flags);
#if HAVE_CRYPT_ACTIVATE_BY_SIGNED_KEY
int (*sym_crypt_activate_by_signed_key)(struct crypt_device *cd, const char *name, const char *volume_key, size_t volume_key_size, const char *signature, size_t signature_size, uint32_t flags);
#endif
int (*sym_crypt_activate_by_volume_key)(struct crypt_device *cd, const char *name, const char *volume_key, size_t volume_key_size, uint32_t flags);
int (*sym_crypt_deactivate_by_name)(struct crypt_device *cd, const char *name, uint32_t flags);
int (*sym_crypt_format)(struct crypt_device *cd, const char *type, const char *cipher, const char *cipher_mode, const char *uuid, const char *volume_key, size_t volume_key_size, void *params);
void (*sym_crypt_free)(struct crypt_device *cd);
const char *(*sym_crypt_get_dir)(void);
int (*sym_crypt_get_verity_info)(struct crypt_device *cd, struct crypt_params_verity *vp);
int (*sym_crypt_init)(struct crypt_device **cd, const char *device);
int (*sym_crypt_init_by_name)(struct crypt_device **cd, const char *name);
int (*sym_crypt_keyslot_add_by_volume_key)(struct crypt_device *cd, int keyslot, const char *volume_key, size_t volume_key_size, const char *passphrase, size_t passphrase_size);
int (*sym_crypt_load)(struct crypt_device *cd, const char *requested_type, void *params);
int (*sym_crypt_resize)(struct crypt_device *cd, const char *name, uint64_t new_size);
int (*sym_crypt_set_data_device)(struct crypt_device *cd, const char *device);
void (*sym_crypt_set_debug_level)(int level);
void (*sym_crypt_set_log_callback)(struct crypt_device *cd, void (*log)(int level, const char *msg, void *usrptr), void *usrptr);
int (*sym_crypt_volume_key_get)(struct crypt_device *cd, int keyslot, char *volume_key, size_t *volume_key_size, const char *passphrase, size_t passphrase_size);
int dlopen_cryptsetup(void) {
_cleanup_(dlclosep) void *dl = NULL;
int r;
if (cryptsetup_dl)
return 0; /* Already loaded */
dl = dlopen("libcryptsetup.so.12", RTLD_LAZY);
if (!dl)
return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
"libcryptsetup support is not installed: %s", dlerror());
r = dlsym_many_and_warn(
dl,
LOG_DEBUG,
&sym_crypt_activate_by_passphrase, "crypt_activate_by_passphrase",
#if HAVE_CRYPT_ACTIVATE_BY_SIGNED_KEY
&sym_crypt_activate_by_signed_key, "crypt_activate_by_signed_key",
#endif
&sym_crypt_activate_by_volume_key, "crypt_activate_by_volume_key",
&sym_crypt_deactivate_by_name, "crypt_deactivate_by_name",
&sym_crypt_format, "crypt_format",
&sym_crypt_free, "crypt_free",
&sym_crypt_get_dir, "crypt_get_dir",
&sym_crypt_get_verity_info, "crypt_get_verity_info",
&sym_crypt_init, "crypt_init",
&sym_crypt_init_by_name, "crypt_init_by_name",
&sym_crypt_keyslot_add_by_volume_key, "crypt_keyslot_add_by_volume_key",
&sym_crypt_load, "crypt_load",
&sym_crypt_resize, "crypt_resize",
&sym_crypt_set_data_device, "crypt_set_data_device",
&sym_crypt_set_debug_level, "crypt_set_debug_level",
&sym_crypt_set_log_callback, "crypt_set_log_callback",
&sym_crypt_volume_key_get, "crypt_volume_key_get",
NULL);
if (r < 0)
return r;
/* Note that we never release the reference here, because there's no real reason to, after all this
* was traditionally a regular shared library dependency which lives forever too. */
cryptsetup_dl = TAKE_PTR(dl);
return 1;
}
static void cryptsetup_log_glue(int level, const char *msg, void *usrptr) {
switch (level) {
case CRYPT_LOG_NORMAL:
level = LOG_NOTICE;
break;
case CRYPT_LOG_ERROR:
level = LOG_ERR;
break;
case CRYPT_LOG_VERBOSE:
level = LOG_INFO;
break;
case CRYPT_LOG_DEBUG:
level = LOG_DEBUG;
break;
default:
log_error("Unknown libcryptsetup log level: %d", level);
level = LOG_ERR;
}
log_full(level, "%s", msg);
}
void cryptsetup_enable_logging(struct crypt_device *cd) {
if (!cd)
return;
if (dlopen_cryptsetup() < 0) /* If this fails, let's gracefully ignore the issue, this is just debug
* logging after all, and if this failed we already generated a debug
* log message that should help to track things down. */
return;
sym_crypt_set_log_callback(cd, cryptsetup_log_glue, NULL);
sym_crypt_set_debug_level(DEBUG_LOGGING ? CRYPT_DEBUG_ALL : CRYPT_DEBUG_NONE);
}
#endif

View File

@ -0,0 +1,36 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
#include "macro.h"
#if HAVE_LIBCRYPTSETUP
#include <libcryptsetup.h>
extern int (*sym_crypt_activate_by_passphrase)(struct crypt_device *cd, const char *name, int keyslot, const char *passphrase, size_t passphrase_size, uint32_t flags);
#if HAVE_CRYPT_ACTIVATE_BY_SIGNED_KEY
extern int (*sym_crypt_activate_by_signed_key)(struct crypt_device *cd, const char *name, const char *volume_key, size_t volume_key_size, const char *signature, size_t signature_size, uint32_t flags);
#endif
extern int (*sym_crypt_activate_by_volume_key)(struct crypt_device *cd, const char *name, const char *volume_key, size_t volume_key_size, uint32_t flags);
extern int (*sym_crypt_deactivate_by_name)(struct crypt_device *cd, const char *name, uint32_t flags);
extern int (*sym_crypt_format)(struct crypt_device *cd, const char *type, const char *cipher, const char *cipher_mode, const char *uuid, const char *volume_key, size_t volume_key_size, void *params);
extern void (*sym_crypt_free)(struct crypt_device *cd);
extern const char *(*sym_crypt_get_dir)(void);
extern int (*sym_crypt_get_verity_info)(struct crypt_device *cd, struct crypt_params_verity *vp);
extern int (*sym_crypt_init)(struct crypt_device **cd, const char *device);
extern int (*sym_crypt_init_by_name)(struct crypt_device **cd, const char *name);
extern int (*sym_crypt_keyslot_add_by_volume_key)(struct crypt_device *cd, int keyslot, const char *volume_key, size_t volume_key_size, const char *passphrase, size_t passphrase_size);
extern int (*sym_crypt_load)(struct crypt_device *cd, const char *requested_type, void *params);
extern int (*sym_crypt_resize)(struct crypt_device *cd, const char *name, uint64_t new_size);
extern int (*sym_crypt_set_data_device)(struct crypt_device *cd, const char *device);
extern void (*sym_crypt_set_debug_level)(int level);
extern void (*sym_crypt_set_log_callback)(struct crypt_device *cd, void (*log)(int level, const char *msg, void *usrptr), void *usrptr);
extern int (*sym_crypt_volume_key_get)(struct crypt_device *cd, int keyslot, char *volume_key, size_t *volume_key_size, const char *passphrase, size_t passphrase_size);
int dlopen_cryptsetup(void);
DEFINE_TRIVIAL_CLEANUP_FUNC(struct crypt_device *, crypt_free);
DEFINE_TRIVIAL_CLEANUP_FUNC(struct crypt_device *, sym_crypt_free);
void cryptsetup_enable_logging(struct crypt_device *cd);
#endif

View File

@ -19,7 +19,7 @@
#include "blkid-util.h"
#include "blockdev-util.h"
#include "copy.h"
#include "crypt-util.h"
#include "cryptsetup-util.h"
#include "def.h"
#include "device-nodes.h"
#include "device-util.h"
@ -1225,13 +1225,13 @@ DecryptedImage* decrypted_image_unref(DecryptedImage* d) {
DecryptedPartition *p = d->decrypted + i;
if (p->device && p->name && !p->relinquished) {
r = crypt_deactivate(p->device, p->name);
r = sym_crypt_deactivate_by_name(p->device, p->name, 0);
if (r < 0)
log_debug_errno(r, "Failed to deactivate encrypted partition %s", p->name);
}
if (p->device)
crypt_free(p->device);
sym_crypt_free(p->device);
free(p->name);
}
@ -1265,7 +1265,7 @@ static int make_dm_name_and_node(const void *original_node, const char *suffix,
if (!filename_is_valid(name))
return -EINVAL;
node = path_join(crypt_get_dir(), name);
node = path_join(sym_crypt_get_dir(), name);
if (!node)
return -ENOMEM;
@ -1282,7 +1282,7 @@ static int decrypt_partition(
DecryptedImage *d) {
_cleanup_free_ char *node = NULL, *name = NULL;
_cleanup_(crypt_freep) struct crypt_device *cd = NULL;
_cleanup_(sym_crypt_freep) struct crypt_device *cd = NULL;
int r;
assert(m);
@ -1297,6 +1297,10 @@ static int decrypt_partition(
if (!passphrase)
return -ENOKEY;
r = dlopen_cryptsetup();
if (r < 0)
return r;
r = make_dm_name_and_node(m->node, "-decrypted", &name, &node);
if (r < 0)
return r;
@ -1304,19 +1308,19 @@ static int decrypt_partition(
if (!GREEDY_REALLOC0(d->decrypted, d->n_allocated, d->n_decrypted + 1))
return -ENOMEM;
r = crypt_init(&cd, m->node);
r = sym_crypt_init(&cd, m->node);
if (r < 0)
return log_debug_errno(r, "Failed to initialize dm-crypt: %m");
cryptsetup_enable_logging(cd);
r = crypt_load(cd, CRYPT_LUKS, NULL);
r = sym_crypt_load(cd, CRYPT_LUKS, NULL);
if (r < 0)
return log_debug_errno(r, "Failed to load LUKS metadata: %m");
r = crypt_activate_by_passphrase(cd, name, CRYPT_ANY_SLOT, passphrase, strlen(passphrase),
((flags & DISSECT_IMAGE_READ_ONLY) ? CRYPT_ACTIVATE_READONLY : 0) |
((flags & DISSECT_IMAGE_DISCARD_ON_CRYPTO) ? CRYPT_ACTIVATE_ALLOW_DISCARDS : 0));
r = sym_crypt_activate_by_passphrase(cd, name, CRYPT_ANY_SLOT, passphrase, strlen(passphrase),
((flags & DISSECT_IMAGE_READ_ONLY) ? CRYPT_ACTIVATE_READONLY : 0) |
((flags & DISSECT_IMAGE_DISCARD_ON_CRYPTO) ? CRYPT_ACTIVATE_ALLOW_DISCARDS : 0));
if (r < 0) {
log_debug_errno(r, "Failed to activate LUKS device: %m");
return r == -EPERM ? -EKEYREJECTED : r;
@ -1334,23 +1338,26 @@ static int decrypt_partition(
static int verity_can_reuse(const void *root_hash, size_t root_hash_size, bool has_sig, const char *name, struct crypt_device **ret_cd) {
/* If the same volume was already open, check that the root hashes match, and reuse it if they do */
_cleanup_free_ char *root_hash_existing = NULL;
_cleanup_(crypt_freep) struct crypt_device *cd = NULL;
_cleanup_(sym_crypt_freep) struct crypt_device *cd = NULL;
struct crypt_params_verity crypt_params = {};
size_t root_hash_existing_size = root_hash_size;
int r;
assert(ret_cd);
r = crypt_init_by_name(&cd, name);
r = sym_crypt_init_by_name(&cd, name);
if (r < 0)
return log_debug_errno(r, "Error opening verity device, crypt_init_by_name failed: %m");
r = crypt_get_verity_info(cd, &crypt_params);
r = sym_crypt_get_verity_info(cd, &crypt_params);
if (r < 0)
return log_debug_errno(r, "Error opening verity device, crypt_get_verity_info failed: %m");
root_hash_existing = malloc0(root_hash_size);
if (!root_hash_existing)
return -ENOMEM;
r = crypt_volume_key_get(cd, CRYPT_ANY_SLOT, root_hash_existing, &root_hash_existing_size, NULL, 0);
r = sym_crypt_volume_key_get(cd, CRYPT_ANY_SLOT, root_hash_existing, &root_hash_existing_size, NULL, 0);
if (r < 0)
return log_debug_errno(r, "Error opening verity device, crypt_volume_key_get failed: %m");
if (root_hash_size != root_hash_existing_size || memcmp(root_hash_existing, root_hash, root_hash_size) != 0)
@ -1370,7 +1377,8 @@ static int verity_can_reuse(const void *root_hash, size_t root_hash_size, bool h
static inline void dm_deferred_remove_clean(char *name) {
if (!name)
return;
(void) crypt_deactivate_by_name(NULL, name, CRYPT_DEACTIVATE_DEFERRED);
(void) sym_crypt_deactivate_by_name(NULL, name, CRYPT_DEACTIVATE_DEFERRED);
free(name);
}
DEFINE_TRIVIAL_CLEANUP_FUNC(char *, dm_deferred_remove_clean);
@ -1388,7 +1396,7 @@ static int verity_partition(
DecryptedImage *d) {
_cleanup_free_ char *node = NULL, *name = NULL, *hash_sig_from_file = NULL;
_cleanup_(crypt_freep) struct crypt_device *cd = NULL;
_cleanup_(sym_crypt_freep) struct crypt_device *cd = NULL;
_cleanup_(dm_deferred_remove_cleanp) char *restore_deferred_remove = NULL;
int r;
@ -1408,11 +1416,17 @@ static int verity_partition(
return 0;
}
r = dlopen_cryptsetup();
if (r < 0)
return r;
if (FLAGS_SET(flags, DISSECT_IMAGE_VERITY_SHARE)) {
/* Use the roothash, which is unique per volume, as the device node name, so that it can be reused */
_cleanup_free_ char *root_hash_encoded = NULL;
root_hash_encoded = hexmem(root_hash, root_hash_size);
if (!root_hash_encoded)
return -ENOMEM;
r = make_dm_name_and_node(root_hash_encoded, "-verity", &name, &node);
} else
@ -1426,17 +1440,17 @@ static int verity_partition(
return r;
}
r = crypt_init(&cd, verity_data ?: v->node);
r = sym_crypt_init(&cd, verity_data ?: v->node);
if (r < 0)
return r;
cryptsetup_enable_logging(cd);
r = crypt_load(cd, CRYPT_VERITY, NULL);
r = sym_crypt_load(cd, CRYPT_VERITY, NULL);
if (r < 0)
return r;
r = crypt_set_data_device(cd, m->node);
r = sym_crypt_set_data_device(cd, m->node);
if (r < 0)
return r;
@ -1449,12 +1463,12 @@ static int verity_partition(
for (unsigned i = 0; i < N_DEVICE_NODE_LIST_ATTEMPTS; i++) {
if (root_hash_sig || hash_sig_from_file) {
#if HAVE_CRYPT_ACTIVATE_BY_SIGNED_KEY
r = crypt_activate_by_signed_key(cd, name, root_hash, root_hash_size, root_hash_sig ?: hash_sig_from_file, root_hash_sig_size, CRYPT_ACTIVATE_READONLY);
r = sym_crypt_activate_by_signed_key(cd, name, root_hash, root_hash_size, root_hash_sig ?: hash_sig_from_file, root_hash_sig_size, CRYPT_ACTIVATE_READONLY);
#else
r = log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "activation of verity device with signature requested, but not supported by cryptsetup due to missing crypt_activate_by_signed_key()");
#endif
} else
r = crypt_activate_by_volume_key(cd, name, root_hash, root_hash_size, CRYPT_ACTIVATE_READONLY);
r = sym_crypt_activate_by_volume_key(cd, name, root_hash, root_hash_size, CRYPT_ACTIVATE_READONLY);
/* libdevmapper can return EINVAL when the device is already in the activation stage.
* There's no way to distinguish this situation from a genuine error due to invalid
* parameters, so immediately fall back to activating the device with a unique name.
@ -1500,7 +1514,7 @@ static int verity_partition(
return r;
if (cd)
crypt_free(cd);
sym_crypt_free(cd);
cd = existing_cd;
}
}
@ -1664,7 +1678,7 @@ int decrypted_image_relinquish(DecryptedImage *d) {
if (p->relinquished)
continue;
r = crypt_deactivate_by_name(NULL, p->name, CRYPT_DEACTIVATE_DEFERRED);
r = sym_crypt_deactivate_by_name(NULL, p->name, CRYPT_DEACTIVATE_DEFERRED);
if (r < 0)
return log_debug_errno(r, "Failed to mark %s for auto-removal: %m", p->name);

View File

@ -73,8 +73,8 @@ shared_sources = files('''
coredump-util.h
cpu-set-util.c
cpu-set-util.h
crypt-util.c
crypt-util.h
cryptsetup-util.c
cryptsetup-util.h
daemon-util.h
dev-setup.c
dev-setup.h
@ -354,7 +354,6 @@ libshared_deps = [threads,
libblkid,
libcap,
libcrypt,
libcryptsetup,
libgcrypt,
libidn,
libiptc,

View File

@ -656,6 +656,10 @@ static void event_run(Manager *manager, struct event *event) {
/* Re-enable the debug message for the next batch of events */
log_children_max_reached = true;
/* fork with up-to-date SELinux label database, so the child inherits the up-to-date db
and, until the next SELinux policy changes, we safe further reloads in future children */
mac_selinux_maybe_reload();
/* start new worker and pass initial device */
worker_spawn(manager, event);
}

View File

@ -5,7 +5,7 @@
#include <sys/stat.h>
#include "alloc-util.h"
#include "crypt-util.h"
#include "cryptsetup-util.h"
#include "fileio.h"
#include "hexdecoct.h"
#include "log.h"