import-creds: add support for binary credentials specified on the kernel cmdline

This commit is contained in:
Lennart Poettering 2023-07-04 11:46:37 +02:00
parent 49850c1ee3
commit de70ecb328
7 changed files with 37 additions and 11 deletions

View file

@ -322,10 +322,11 @@ services where they are ultimately consumed.
be sure they can be accessed securely from initrd context. be sure they can be accessed securely from initrd context.
4. Credentials can also be passed into a system via the kernel command line, 4. Credentials can also be passed into a system via the kernel command line,
via the `systemd.set-credential=` kernel command line option. Note though via the `systemd.set_credential=` and `systemd.set_credential_binary=`
that any data specified here is visible to all userspace applications (even kernel command line options (the latter takes Base64 encoded binary
unprivileged ones) via `/proc/cmdline`. Typically, this is hence not useful data). Note though that any data specified here is visible to all userspace
to pass sensitive information, and should be avoided. applications (even unprivileged ones) via `/proc/cmdline`. Typically, this
is hence not useful to pass sensitive information, and should be avoided.
Credentials passed to the system may be enumerated/displayed via `systemd-creds Credentials passed to the system may be enumerated/displayed via `systemd-creds
--system`. They may also be propagated down to services, via the --system`. They may also be propagated down to services, via the

View file

@ -72,6 +72,7 @@
<term><varname>systemd.setenv=</varname></term> <term><varname>systemd.setenv=</varname></term>
<term><varname>systemd.machine_id=</varname></term> <term><varname>systemd.machine_id=</varname></term>
<term><varname>systemd.set_credential=</varname></term> <term><varname>systemd.set_credential=</varname></term>
<term><varname>systemd.set_credential_binary=</varname></term>
<term><varname>systemd.import_credentials=</varname></term> <term><varname>systemd.import_credentials=</varname></term>
<term><varname>systemd.reload_limit_interval_sec=</varname></term> <term><varname>systemd.reload_limit_interval_sec=</varname></term>
<term><varname>systemd.reload_limit_burst=</varname></term> <term><varname>systemd.reload_limit_burst=</varname></term>

View file

@ -3285,7 +3285,8 @@ StandardInputData=V2XigLJyZSBubyBzdHJhbmdlcnMgdG8gbG92ZQpZb3Uga25vdyB0aGUgcnVsZX
<citerefentry><refentrytitle>systemd-stub</refentrytitle><manvolnum>7</manvolnum></citerefentry>, <citerefentry><refentrytitle>systemd-stub</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
from the initrd (see from the initrd (see
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>), or be <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>), or be
specified on the kernel command line using the <literal>systemd.set_credential=</literal> switch (see specified on the kernel command line using the <literal>systemd.set_credential=</literal> and
<literal>systemd.set_credential_binary=</literal> switches (see
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry> this is <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry> this is
not recommended since unprivileged userspace can read the kernel command line). </para> not recommended since unprivileged userspace can read the kernel command line). </para>

View file

@ -932,12 +932,15 @@
<varlistentry> <varlistentry>
<term><varname>systemd.set_credential=</varname></term> <term><varname>systemd.set_credential=</varname></term>
<term><varname>systemd.set_credential_binary=</varname></term>
<listitem><para>Sets a system credential, which can then be propagated to system services using the <listitem><para>Sets a system credential, which can then be propagated to system services using the
<varname>ImportCredential=</varname> or <varname>LoadCredential=</varname> setting, see <varname>ImportCredential=</varname> or <varname>LoadCredential=</varname> setting, see
<citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry> for <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
details. Takes a pair of credential name and value, separated by a colon. Note that the kernel details. Takes a pair of credential name and value, separated by a colon. The
command line is typically accessible by unprivileged programs in <varname>systemd.set_credential=</varname> parameter expects the credential value in literal text
form, the <varname>systemd.set_credential_binary=</varname> parameter takes binary data encoded in
Base64. Note that the kernel command line is typically accessible by unprivileged programs in
<filename>/proc/cmdline</filename>. Thus, this mechanism is not suitable for transferring sensitive <filename>/proc/cmdline</filename>. Thus, this mechanism is not suitable for transferring sensitive
data. Use it only for data that is not sensitive (e.g. public keys/certificates, rather than private data. Use it only for data that is not sensitive (e.g. public keys/certificates, rather than private
keys), or in testing/debugging environments.</para> keys), or in testing/debugging environments.</para>

View file

@ -278,15 +278,21 @@ static int import_credentials_boot(void) {
static int proc_cmdline_callback(const char *key, const char *value, void *data) { static int proc_cmdline_callback(const char *key, const char *value, void *data) {
ImportCredentialContext *c = ASSERT_PTR(data); ImportCredentialContext *c = ASSERT_PTR(data);
_cleanup_free_ void *binary = NULL;
_cleanup_free_ char *n = NULL; _cleanup_free_ char *n = NULL;
_cleanup_close_ int nfd = -EBADF; _cleanup_close_ int nfd = -EBADF;
const char *colon; const char *colon, *d;
bool base64;
size_t l; size_t l;
int r; int r;
assert(key); assert(key);
if (!proc_cmdline_key_streq(key, "systemd.set_credential")) if (proc_cmdline_key_streq(key, "systemd.set_credential"))
base64 = false;
else if (proc_cmdline_key_streq(key, "systemd.set_credential_binary"))
base64 = true;
else
return 0; return 0;
colon = value ? strchr(value, ':') : NULL; colon = value ? strchr(value, ':') : NULL;
@ -305,7 +311,19 @@ static int proc_cmdline_callback(const char *key, const char *value, void *data)
} }
colon++; colon++;
l = strlen(colon);
if (base64) {
r = unbase64mem(colon, SIZE_MAX, &binary, &l);
if (r < 0) {
log_warning_errno(r, "Failed to decode binary credential '%s' data, ignoring: %m", n);
return 0;
}
d = binary;
} else {
d = colon;
l = strlen(colon);
}
if (!credential_size_ok(c, n, l)) if (!credential_size_ok(c, n, l))
return 0; return 0;
@ -320,7 +338,7 @@ static int proc_cmdline_callback(const char *key, const char *value, void *data)
if (nfd < 0) if (nfd < 0)
return nfd; return nfd;
r = loop_write(nfd, colon, l, /* do_poll= */ false); r = loop_write(nfd, d, l, /* do_poll= */ false);
if (r < 0) { if (r < 0) {
(void) unlinkat(c->target_dir_fd, n, 0); (void) unlinkat(c->target_dir_fd, n, 0);
return log_error_errno(r, "Failed to write credential: %m"); return log_error_errno(r, "Failed to write credential: %m");

View file

@ -25,6 +25,7 @@ KERNEL_CREDS=(
"systemd.set_credential=sysctl.extra:kernel.domainname=sysctltest" "systemd.set_credential=sysctl.extra:kernel.domainname=sysctltest"
"systemd.set_credential=login.motd:hello" "systemd.set_credential=login.motd:hello"
"systemd.set_credential=login.issue:welcome" "systemd.set_credential=login.issue:welcome"
"systemd.set_credential_binary=waldi:d29vb29mZmZ3dWZmZnd1ZmYK"
"rd.systemd.import_credentials=no" "rd.systemd.import_credentials=no"
) )
KERNEL_APPEND="${KERNEL_APPEND:-} ${KERNEL_CREDS[*]}" KERNEL_APPEND="${KERNEL_APPEND:-} ${KERNEL_CREDS[*]}"

View file

@ -176,6 +176,7 @@ if systemd-detect-virt -q -c ; then
elif [ -d /sys/firmware/qemu_fw_cfg/by_name ]; then elif [ -d /sys/firmware/qemu_fw_cfg/by_name ]; then
# Verify that passing creds through kernel cmdline works # Verify that passing creds through kernel cmdline works
[ "$(systemd-creds --system cat kernelcmdlinecred)" = "uff" ] [ "$(systemd-creds --system cat kernelcmdlinecred)" = "uff" ]
[ "$(systemd-creds --system cat waldi)" = "woooofffwufffwuff" ]
# And that it also works via SMBIOS # And that it also works via SMBIOS
[ "$(systemd-creds --system cat smbioscredential)" = "magicdata" ] [ "$(systemd-creds --system cat smbioscredential)" = "magicdata" ]