mirror of
https://github.com/systemd/systemd
synced 2025-11-08 19:34:45 +01:00
Compare commits
20 Commits
002674387c
...
2859bb932b
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2859bb932b | ||
|
|
63fdaa36c5 | ||
|
|
8fa2cd83c6 | ||
|
|
2aa5a13aa9 | ||
|
|
f25e9eda52 | ||
|
|
b876b07812 | ||
|
|
ac1f3ad05f | ||
|
|
536879480a | ||
|
|
d81be4e752 | ||
|
|
2ea6247e01 | ||
|
|
0da322d9a4 | ||
|
|
7cbb7d62c6 | ||
|
|
06847d0fba | ||
|
|
e4a321fc08 | ||
|
|
a24153279e | ||
|
|
b4a11ca3f2 | ||
|
|
76cbafcdd4 | ||
|
|
28266c446a | ||
|
|
ae353ec2f6 | ||
|
|
1cdea1a2f7 |
3
TODO
3
TODO
@ -1029,7 +1029,7 @@ Features:
|
||||
- journal: add a setgid "systemd-journal" utility to invoke from libsystemd-journal, which passes fds via STDOUT and does PK access
|
||||
- journactl: support negative filtering, i.e. FOOBAR!="waldo",
|
||||
and !FOOBAR for events without FOOBAR.
|
||||
- journal: store timestamp of journal_file_set_offline() int he header,
|
||||
- journal: store timestamp of journal_file_set_offline() in the header,
|
||||
so it is possible to display when the file was last synced.
|
||||
- journal-send.c, log.c: when the log socket is clogged, and we drop, count this and write a message about this when it gets unclogged again.
|
||||
- journal: find a way to allow dropping history early, based on priority, other rules
|
||||
@ -1071,6 +1071,7 @@ Features:
|
||||
them via machined, and also watch containers coming and going.
|
||||
Benefit: nspawn --ephemeral would start working nicely with the journal.
|
||||
- assign MESSAGE_ID to log messages about failed services
|
||||
- check if loop in decompress_blob_xz() is necessary
|
||||
|
||||
* add a test if all entries in the catalog are properly formatted.
|
||||
(Adding dashes in a catalog entry currently results in the catalog entry
|
||||
|
||||
@ -18,6 +18,7 @@
|
||||
<refnamediv>
|
||||
<refname>sd_journal_get_data</refname>
|
||||
<refname>sd_journal_enumerate_data</refname>
|
||||
<refname>sd_journal_enumerate_available_data</refname>
|
||||
<refname>sd_journal_restart_data</refname>
|
||||
<refname>SD_JOURNAL_FOREACH_DATA</refname>
|
||||
<refname>sd_journal_set_data_threshold</refname>
|
||||
@ -44,6 +45,13 @@
|
||||
<paramdef>size_t *<parameter>length</parameter></paramdef>
|
||||
</funcprototype>
|
||||
|
||||
<funcprototype>
|
||||
<funcdef>int <function>sd_journal_enumerate_available_data</function></funcdef>
|
||||
<paramdef>sd_journal *<parameter>j</parameter></paramdef>
|
||||
<paramdef>const void **<parameter>data</parameter></paramdef>
|
||||
<paramdef>size_t *<parameter>length</parameter></paramdef>
|
||||
</funcprototype>
|
||||
|
||||
<funcprototype>
|
||||
<funcdef>void <function>sd_journal_restart_data</function></funcdef>
|
||||
<paramdef>sd_journal *<parameter>j</parameter></paramdef>
|
||||
@ -73,24 +81,18 @@
|
||||
<refsect1>
|
||||
<title>Description</title>
|
||||
|
||||
<para><function>sd_journal_get_data()</function> gets the data
|
||||
object associated with a specific field from the current journal
|
||||
entry. It takes four arguments: the journal context object, a
|
||||
string with the field name to request, plus a pair of pointers to
|
||||
pointer/size variables where the data object and its size shall be
|
||||
stored in. The field name should be an entry field name.
|
||||
Well-known field names are listed in
|
||||
<citerefentry><refentrytitle>systemd.journal-fields</refentrytitle><manvolnum>7</manvolnum></citerefentry>.
|
||||
The returned data is in a read-only memory map and is only valid
|
||||
until the next invocation of
|
||||
<function>sd_journal_get_data()</function> or
|
||||
<function>sd_journal_enumerate_data()</function>, or the read
|
||||
pointer is altered. Note that the data returned will be prefixed
|
||||
with the field name and '='. Also note that, by default, data fields
|
||||
larger than 64K might get truncated to 64K. This threshold may be
|
||||
changed and turned off with
|
||||
<function>sd_journal_set_data_threshold()</function> (see
|
||||
below).</para>
|
||||
<para><function>sd_journal_get_data()</function> gets the data object associated with a specific field
|
||||
from the current journal entry. It takes four arguments: the journal context object, a string with the
|
||||
field name to request, plus a pair of pointers to pointer/size variables where the data object and its
|
||||
size shall be stored in. The field name should be an entry field name. Well-known field names are listed in
|
||||
<citerefentry><refentrytitle>systemd.journal-fields</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
|
||||
but any field can be specified. The returned data is in a read-only memory map and is only valid until
|
||||
the next invocation of <function>sd_journal_get_data()</function>,
|
||||
<function>sd_journal_enumerate_data()</function>,
|
||||
<function>sd_journal_enumerate_available_data()</function>, or when the read pointer is altered. Note
|
||||
that the data returned will be prefixed with the field name and <literal>=</literal>. Also note that, by
|
||||
default, data fields larger than 64K might get truncated to 64K. This threshold may be changed and turned
|
||||
off with <function>sd_journal_set_data_threshold()</function> (see below).</para>
|
||||
|
||||
<para><function>sd_journal_enumerate_data()</function> may be used
|
||||
to iterate through all fields of the current entry. On each
|
||||
@ -99,15 +101,18 @@
|
||||
format as with <function>sd_journal_get_data()</function> and also
|
||||
follows the same life-time semantics.</para>
|
||||
|
||||
<para><function>sd_journal_enumerate_available_data()</function> is similar to
|
||||
<function>sd_journal_enumerate_data()</function>, but silently skips any fields which may be valid, but
|
||||
are too large or not supported by current implementation.</para>
|
||||
|
||||
<para><function>sd_journal_restart_data()</function> resets the
|
||||
data enumeration index to the beginning of the entry. The next
|
||||
invocation of <function>sd_journal_enumerate_data()</function>
|
||||
will return the first field of the entry again.</para>
|
||||
|
||||
<para>Note that the <function>SD_JOURNAL_FOREACH_DATA()</function>
|
||||
macro may be used as a handy wrapper around
|
||||
<function>sd_journal_restart_data()</function> and
|
||||
<function>sd_journal_enumerate_data()</function>.</para>
|
||||
<para>Note that the <function>SD_JOURNAL_FOREACH_DATA()</function> macro may be used as a handy wrapper
|
||||
around <function>sd_journal_restart_data()</function> and
|
||||
<function>sd_journal_enumerate_available_data()</function>.</para>
|
||||
|
||||
<para>Note that these functions will not work before
|
||||
<citerefentry><refentrytitle>sd_journal_next</refentrytitle><manvolnum>3</manvolnum></citerefentry>
|
||||
@ -139,18 +144,88 @@
|
||||
<refsect1>
|
||||
<title>Return Value</title>
|
||||
|
||||
<para><function>sd_journal_get_data()</function> returns 0 on
|
||||
success or a negative errno-style error code. If the current entry
|
||||
does not include the specified field, -ENOENT is returned. If
|
||||
<citerefentry><refentrytitle>sd_journal_next</refentrytitle><manvolnum>3</manvolnum></citerefentry>
|
||||
has not been called at least once, -EADDRNOTAVAIL is returned.
|
||||
<function>sd_journal_enumerate_data()</function> returns a
|
||||
positive integer if the next field has been read, 0 when no more
|
||||
fields are known, or a negative errno-style error code.
|
||||
<function>sd_journal_restart_data()</function> returns nothing.
|
||||
<function>sd_journal_set_data_threshold()</function> and
|
||||
<function>sd_journal_get_threshold()</function> return 0 on
|
||||
success or a negative errno-style error code.</para>
|
||||
<para><function>sd_journal_get_data()</function> returns 0 on success or a negative errno-style error
|
||||
code. <function>sd_journal_enumerate_data()</function> and
|
||||
<function>sd_journal_enumerate_available_data()</function> return a positive integer if the next field
|
||||
has been read, 0 when no more fields remain, or a negative errno-style error code.
|
||||
<function>sd_journal_restart_data()</function> doesn't return anything.
|
||||
<function>sd_journal_set_data_threshold()</function> and <function>sd_journal_get_threshold()</function>
|
||||
return 0 on success or a negative errno-style error code.</para>
|
||||
|
||||
<refsect2>
|
||||
<title>Errors</title>
|
||||
|
||||
<para>Returned errors may indicate the following problems:</para>
|
||||
|
||||
<variablelist>
|
||||
<varlistentry id='EINVAL'>
|
||||
<term><constant>-EINVAL</constant></term>
|
||||
|
||||
<listitem><para>One of the required parameters is <constant>NULL</constant> or invalid.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry id='ECHILD'>
|
||||
<term><constant>-ECHILD</constant></term>
|
||||
|
||||
<listitem><para>The journal object was created in a different process.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry id='EADDRNOTAVAIL'>
|
||||
<term><constant>-EADDRNOTAVAIL</constant></term>
|
||||
|
||||
<listitem><para>The read pointer is not positioned at a valid entry;
|
||||
<citerefentry><refentrytitle>sd_journal_next</refentrytitle><manvolnum>3</manvolnum></citerefentry>
|
||||
or a related call has not been called at least once.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry id='ENOENT'>
|
||||
<term><constant>-ENOENT</constant></term>
|
||||
|
||||
<listitem><para>The current entry does not include the specified field.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry id='ENOMEM'>
|
||||
<term><constant>-ENOMEM</constant></term>
|
||||
|
||||
<listitem><para>Memory allocation failed.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry id='ENOBUFS'>
|
||||
<term><constant>-ENOBUFS</constant></term>
|
||||
|
||||
<listitem><para>A compressed entry is too large.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry id='E2BIG'>
|
||||
<term><constant>-E2BIG</constant></term>
|
||||
|
||||
<listitem><para>The data field is too large for this computer architecture (e.g. above 4 GB on a
|
||||
32-bit architecture).</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry id='EPROTONOSUPPORT'>
|
||||
<term><constant>-EPROTONOSUPPORT</constant></term>
|
||||
|
||||
<listitem><para>The journal is compressed with an unsupported method or the journal uses an
|
||||
unsupported feature.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry id='EBADMSG'>
|
||||
<term><constant>-EBADMSG</constant></term>
|
||||
|
||||
<listitem><para>The journal is corrupted (possibly just the entry being iterated over).
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry id='EIO'>
|
||||
<term><constant>-EIO</constant></term>
|
||||
|
||||
<listitem><para>An I/O error was reported by the kernel.</para></listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect2>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
|
||||
@ -18,6 +18,7 @@
|
||||
<refnamediv>
|
||||
<refname>sd_journal_query_unique</refname>
|
||||
<refname>sd_journal_enumerate_unique</refname>
|
||||
<refname>sd_journal_enumerate_available_unique</refname>
|
||||
<refname>sd_journal_restart_unique</refname>
|
||||
<refname>SD_JOURNAL_FOREACH_UNIQUE</refname>
|
||||
<refpurpose>Read unique data fields from the journal</refpurpose>
|
||||
@ -33,6 +34,13 @@
|
||||
<paramdef>const char *<parameter>field</parameter></paramdef>
|
||||
</funcprototype>
|
||||
|
||||
<funcprototype>
|
||||
<funcdef>int <function>sd_journal_enumerate_available_unique</function></funcdef>
|
||||
<paramdef>sd_journal *<parameter>j</parameter></paramdef>
|
||||
<paramdef>const void **<parameter>data</parameter></paramdef>
|
||||
<paramdef>size_t *<parameter>length</parameter></paramdef>
|
||||
</funcprototype>
|
||||
|
||||
<funcprototype>
|
||||
<funcdef>int <function>sd_journal_enumerate_unique</function></funcdef>
|
||||
<paramdef>sd_journal *<parameter>j</parameter></paramdef>
|
||||
@ -58,33 +66,31 @@
|
||||
<refsect1>
|
||||
<title>Description</title>
|
||||
|
||||
<para><function>sd_journal_query_unique()</function> queries the
|
||||
journal for all unique values the specified field can take. It
|
||||
takes two arguments: the journal to query and the field name to
|
||||
look for. Well-known field names are listed on
|
||||
<citerefentry><refentrytitle>systemd.journal-fields</refentrytitle><manvolnum>7</manvolnum></citerefentry>.
|
||||
Field names must be specified without a trailing '='. After this
|
||||
function has been executed successfully the field values may be
|
||||
queried using <function>sd_journal_enumerate_unique()</function>.
|
||||
Invoking this call a second time will change the field name being
|
||||
queried and reset the enumeration index to the first field value
|
||||
that matches.</para>
|
||||
<para><function>sd_journal_query_unique()</function> queries the journal for all unique values the
|
||||
specified field can take. It takes two arguments: the journal to query and the field name to look
|
||||
for. Well-known field names are listed on
|
||||
<citerefentry><refentrytitle>systemd.journal-fields</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
|
||||
but any field can be specified. Field names must be specified without a trailing
|
||||
<literal>=</literal>. After this function has been executed successfully the field values may be queried
|
||||
using <function>sd_journal_enumerate_unique()</function> and
|
||||
<function>sd_journal_enumerate_available_unique()</function>. Invoking one of those calls will change the
|
||||
field name being queried and reset the enumeration index to the first field value that matches.</para>
|
||||
|
||||
<para><function>sd_journal_enumerate_unique()</function> may be
|
||||
used to iterate through all data fields which match the previously
|
||||
selected field name as set with
|
||||
<function>sd_journal_query_unique()</function>. On each invocation
|
||||
the next field data matching the field name is returned. The order
|
||||
of the returned data fields is not defined. It takes three
|
||||
arguments: the journal context object, plus a pair of pointers to
|
||||
pointer/size variables where the data object and its size shall be
|
||||
stored in. The returned data is in a read-only memory map and is
|
||||
only valid until the next invocation of
|
||||
<function>sd_journal_enumerate_unique()</function>. Note that the
|
||||
data returned will be prefixed with the field name and '='. Note
|
||||
that this call is subject to the data field size threshold as
|
||||
controlled by
|
||||
<function>sd_journal_set_data_threshold()</function>.</para>
|
||||
<para><function>sd_journal_enumerate_unique()</function> may be used to iterate through all data fields
|
||||
which match the previously selected field name as set with
|
||||
<function>sd_journal_query_unique()</function>. On each invocation the next field data matching the field
|
||||
name is returned. The order of the returned data fields is not defined. It takes three arguments: the
|
||||
journal object, plus a pair of pointers to pointer/size variables where the data object and its size
|
||||
shall be stored. The returned data is in a read-only memory map and is only valid until the next
|
||||
invocation of <function>sd_journal_enumerate_unique()</function>. Note that the data returned will be
|
||||
prefixed with the field name and <literal>=</literal>. Note that this call is subject to the data field
|
||||
size threshold as controlled by <function>sd_journal_set_data_threshold()</function> and only the initial
|
||||
part of the field up to the threshold is returned. An error is returned for fields which cannot be
|
||||
retrieved. See the error list below for details.</para>
|
||||
|
||||
<para><function>sd_journal_enumerate_available_unique()</function> is similar to
|
||||
<function>sd_journal_enumerate_unique()</function>, but silently skips any fields which may be valid, but
|
||||
are too large or not supported by current implementation.</para>
|
||||
|
||||
<para><function>sd_journal_restart_unique()</function> resets the
|
||||
data enumeration index to the beginning of the list. The next
|
||||
@ -92,11 +98,9 @@
|
||||
will return the first field data matching the field name
|
||||
again.</para>
|
||||
|
||||
<para>Note that the
|
||||
<function>SD_JOURNAL_FOREACH_UNIQUE()</function> macro may be used
|
||||
as a handy wrapper around
|
||||
<function>sd_journal_restart_unique()</function> and
|
||||
<function>sd_journal_enumerate_unique()</function>.</para>
|
||||
<para>Note that the <function>SD_JOURNAL_FOREACH_UNIQUE()</function> macro may be used as a handy wrapper
|
||||
around <function>sd_journal_restart_unique()</function> and
|
||||
<function>sd_journal_enumerate_available_unique()</function>.</para>
|
||||
|
||||
<para>Note that these functions currently are not influenced by
|
||||
matches set with <function>sd_journal_add_match()</function> but
|
||||
@ -111,13 +115,29 @@
|
||||
<refsect1>
|
||||
<title>Return Value</title>
|
||||
|
||||
<para><function>sd_journal_query_unique()</function> returns 0 on
|
||||
success or a negative errno-style error code.
|
||||
<function>sd_journal_enumerate_unique()</function> returns a
|
||||
positive integer if the next field data has been read, 0 when no
|
||||
more fields are known, or a negative errno-style error code.
|
||||
<function>sd_journal_restart_unique()</function> returns
|
||||
nothing.</para>
|
||||
<para><function>sd_journal_query_unique()</function> returns 0 on success or a negative errno-style error
|
||||
code. <function>sd_journal_enumerate_unique()</function> and and
|
||||
<function>sd_journal_query_available_unique()</function> return a positive integer if the next field data
|
||||
has been read, 0 when no more fields remain, or a negative errno-style error code.
|
||||
<function>sd_journal_restart_unique()</function> doesn't return anything.</para>
|
||||
|
||||
<refsect2>
|
||||
<title>Errors</title>
|
||||
|
||||
<para>Returned errors may indicate the following problems:</para>
|
||||
|
||||
<variablelist>
|
||||
<xi:include href="sd_journal_get_data.xml" xpointer="EINVAL"/>
|
||||
<xi:include href="sd_journal_get_data.xml" xpointer="ECHILD"/>
|
||||
<xi:include href="sd_journal_get_data.xml" xpointer="EADDRNOTAVAIL"/>
|
||||
<xi:include href="sd_journal_get_data.xml" xpointer="ENOENT"/>
|
||||
<xi:include href="sd_journal_get_data.xml" xpointer="ENOBUFS"/>
|
||||
<xi:include href="sd_journal_get_data.xml" xpointer="E2BIG"/>
|
||||
<xi:include href="sd_journal_get_data.xml" xpointer="EPROTONOSUPPORT"/>
|
||||
<xi:include href="sd_journal_get_data.xml" xpointer="EBADMSG"/>
|
||||
<xi:include href="sd_journal_get_data.xml" xpointer="EIO"/>
|
||||
</variablelist>
|
||||
</refsect2>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
@ -131,10 +151,9 @@
|
||||
<refsect1>
|
||||
<title>Examples</title>
|
||||
|
||||
<para>Use the <function>SD_JOURNAL_FOREACH_UNIQUE</function> macro
|
||||
to iterate through all values a field of the journal can take. The
|
||||
following example lists all unit names referenced in the
|
||||
journal:</para>
|
||||
<para>Use the <function>SD_JOURNAL_FOREACH_UNIQUE</function> macro to iterate through all values a field
|
||||
of the journal can take (and which can be accessed on the given architecture and are not compressed with
|
||||
an unsupported mechanism). The following example lists all unit names referenced in the journal:</para>
|
||||
|
||||
<programlisting><xi:include href="journal-iterate-unique.c" parse="text" /></programlisting>
|
||||
</refsect1>
|
||||
|
||||
@ -2163,13 +2163,7 @@ SystemCallErrorNumber=EPERM</programlisting>
|
||||
<citerefentry><refentrytitle>systemd.socket</refentrytitle><manvolnum>5</manvolnum></citerefentry> for more
|
||||
details about named file descriptors and their ordering.</para>
|
||||
|
||||
<para>This setting defaults to <option>null</option>.</para>
|
||||
|
||||
<para>Note that services which specify <option>DefaultDependencies=no</option> and use
|
||||
<varname>StandardInput=</varname> or <varname>StandardOutput=</varname> with
|
||||
<option>tty</option>/<option>tty-force</option>/<option>tty-fail</option>, should specify
|
||||
<option>After=systemd-vconsole-setup.service</option>, to make sure that the tty initialization is
|
||||
finished before they start.</para></listitem>
|
||||
<para>This setting defaults to <option>null</option>.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
|
||||
@ -177,38 +177,18 @@ static uint64_t storage_size_max(void) {
|
||||
static int fix_acl(int fd, uid_t uid) {
|
||||
|
||||
#if HAVE_ACL
|
||||
_cleanup_(acl_freep) acl_t acl = NULL;
|
||||
acl_entry_t entry;
|
||||
acl_permset_t permset;
|
||||
int r;
|
||||
|
||||
assert(fd >= 0);
|
||||
assert(uid_is_valid(uid));
|
||||
|
||||
if (uid_is_system(uid) || uid_is_dynamic(uid) || uid == UID_NOBODY)
|
||||
return 0;
|
||||
|
||||
/* Make sure normal users can read (but not write or delete)
|
||||
* their own coredumps */
|
||||
|
||||
acl = acl_get_fd(fd);
|
||||
if (!acl)
|
||||
return log_error_errno(errno, "Failed to get ACL: %m");
|
||||
|
||||
if (acl_create_entry(&acl, &entry) < 0 ||
|
||||
acl_set_tag_type(entry, ACL_USER) < 0 ||
|
||||
acl_set_qualifier(entry, &uid) < 0)
|
||||
return log_error_errno(errno, "Failed to patch ACL: %m");
|
||||
|
||||
if (acl_get_permset(entry, &permset) < 0 ||
|
||||
acl_add_perm(permset, ACL_READ) < 0)
|
||||
return log_warning_errno(errno, "Failed to patch ACL: %m");
|
||||
|
||||
r = calc_acl_mask_if_needed(&acl);
|
||||
/* Make sure normal users can read (but not write or delete) their own coredumps */
|
||||
r = add_acls_for_user(fd, uid);
|
||||
if (r < 0)
|
||||
return log_warning_errno(r, "Failed to patch ACL: %m");
|
||||
|
||||
if (acl_set_fd(fd, acl) < 0)
|
||||
return log_error_errno(errno, "Failed to apply ACL: %m");
|
||||
return log_error_errno(r, "Failed to adjust ACL of coredump: %m");
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
||||
@ -16,12 +16,12 @@ struct pkcs11_callback_data {
|
||||
X509 *cert;
|
||||
};
|
||||
|
||||
#if HAVE_P11KIT
|
||||
static void pkcs11_callback_data_release(struct pkcs11_callback_data *data) {
|
||||
erase_and_free(data->pin_used);
|
||||
X509_free(data->cert);
|
||||
}
|
||||
|
||||
#if HAVE_P11KIT
|
||||
static int pkcs11_callback(
|
||||
CK_FUNCTION_LIST *m,
|
||||
CK_SESSION_HANDLE session,
|
||||
|
||||
@ -1295,7 +1295,7 @@ int home_activate_luks(
|
||||
|
||||
loop_device_relinquish(setup.loop);
|
||||
|
||||
r = dm_deferred_remove(setup.dm_name);
|
||||
r = crypt_deactivate_by_name(NULL, setup.dm_name, CRYPT_DEACTIVATE_DEFERRED);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Failed to relinquish DM device, ignoring: %m");
|
||||
|
||||
|
||||
@ -259,10 +259,10 @@ int decompress_blob_lz4(const void *src, uint64_t src_size,
|
||||
|
||||
int decompress_blob_zstd(
|
||||
const void *src, uint64_t src_size,
|
||||
void **dst, size_t *dst_alloc_size, size_t* dst_size, size_t dst_max) {
|
||||
void **dst, size_t *dst_alloc_size, size_t *dst_size, size_t dst_max) {
|
||||
|
||||
#if HAVE_ZSTD
|
||||
size_t space;
|
||||
uint64_t size;
|
||||
|
||||
assert(src);
|
||||
assert(src_size > 0);
|
||||
@ -271,38 +271,40 @@ int decompress_blob_zstd(
|
||||
assert(dst_size);
|
||||
assert(*dst_alloc_size == 0 || *dst);
|
||||
|
||||
if (src_size > SIZE_MAX/2) /* Overflow? */
|
||||
return -ENOBUFS;
|
||||
space = src_size * 2;
|
||||
if (dst_max > 0 && space > dst_max)
|
||||
space = dst_max;
|
||||
size = ZSTD_getFrameContentSize(src, src_size);
|
||||
if (IN_SET(size, ZSTD_CONTENTSIZE_ERROR, ZSTD_CONTENTSIZE_UNKNOWN))
|
||||
return -EBADMSG;
|
||||
|
||||
if (!greedy_realloc(dst, dst_alloc_size, space, 1))
|
||||
if (dst_max > 0 && size > dst_max)
|
||||
size = dst_max;
|
||||
if (size > SIZE_MAX)
|
||||
return -E2BIG;
|
||||
|
||||
if (!(greedy_realloc(dst, dst_alloc_size, MAX(ZSTD_DStreamOutSize(), size), 1)))
|
||||
return -ENOMEM;
|
||||
|
||||
for (;;) {
|
||||
size_t k;
|
||||
_cleanup_(ZSTD_freeDCtxp) ZSTD_DCtx *dctx = ZSTD_createDCtx();
|
||||
if (!dctx)
|
||||
return -ENOMEM;
|
||||
|
||||
k = ZSTD_decompress(*dst, *dst_alloc_size, src, src_size);
|
||||
if (!ZSTD_isError(k)) {
|
||||
*dst_size = k;
|
||||
return 0;
|
||||
}
|
||||
if (ZSTD_getErrorCode(k) != ZSTD_error_dstSize_tooSmall)
|
||||
return zstd_ret_to_errno(k);
|
||||
ZSTD_inBuffer input = {
|
||||
.src = src,
|
||||
.size = src_size,
|
||||
};
|
||||
ZSTD_outBuffer output = {
|
||||
.dst = *dst,
|
||||
.size = *dst_alloc_size,
|
||||
};
|
||||
|
||||
if (dst_max > 0 && space >= dst_max) /* Already at max? */
|
||||
return -ENOBUFS;
|
||||
if (space > SIZE_MAX / 2) /* Overflow? */
|
||||
return -ENOBUFS;
|
||||
|
||||
space *= 2;
|
||||
if (dst_max > 0 && space > dst_max)
|
||||
space = dst_max;
|
||||
|
||||
if (!greedy_realloc(dst, dst_alloc_size, space, 1))
|
||||
return -ENOMEM;
|
||||
size_t k = ZSTD_decompressStream(dctx, &output, &input);
|
||||
if (ZSTD_isError(k)) {
|
||||
log_debug("ZSTD decoder failed: %s", ZSTD_getErrorName(k));
|
||||
return zstd_ret_to_errno(k);
|
||||
}
|
||||
assert(output.pos >= size);
|
||||
|
||||
*dst_size = size;
|
||||
return 0;
|
||||
#else
|
||||
return -EPROTONOSUPPORT;
|
||||
#endif
|
||||
@ -326,7 +328,7 @@ int decompress_blob(
|
||||
src, src_size,
|
||||
dst, dst_alloc_size, dst_size, dst_max);
|
||||
else
|
||||
return -EBADMSG;
|
||||
return -EPROTONOSUPPORT;
|
||||
}
|
||||
|
||||
int decompress_startswith_xz(const void *src, uint64_t src_size,
|
||||
@ -456,9 +458,6 @@ int decompress_startswith_zstd(
|
||||
const void *prefix, size_t prefix_len,
|
||||
uint8_t extra) {
|
||||
#if HAVE_ZSTD
|
||||
_cleanup_(ZSTD_freeDCtxp) ZSTD_DCtx *dctx = NULL;
|
||||
size_t k;
|
||||
|
||||
assert(src);
|
||||
assert(src_size > 0);
|
||||
assert(buffer);
|
||||
@ -466,7 +465,14 @@ int decompress_startswith_zstd(
|
||||
assert(prefix);
|
||||
assert(*buffer_size == 0 || *buffer);
|
||||
|
||||
dctx = ZSTD_createDCtx();
|
||||
uint64_t size = ZSTD_getFrameContentSize(src, src_size);
|
||||
if (IN_SET(size, ZSTD_CONTENTSIZE_ERROR, ZSTD_CONTENTSIZE_UNKNOWN))
|
||||
return -EBADMSG;
|
||||
|
||||
if (size < prefix_len + 1)
|
||||
return 0; /* Decompressed text too short to match the prefix and extra */
|
||||
|
||||
_cleanup_(ZSTD_freeDCtxp) ZSTD_DCtx *dctx = ZSTD_createDCtx();
|
||||
if (!dctx)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -481,30 +487,17 @@ int decompress_startswith_zstd(
|
||||
.dst = *buffer,
|
||||
.size = *buffer_size,
|
||||
};
|
||||
size_t k;
|
||||
|
||||
for (;;) {
|
||||
k = ZSTD_decompressStream(dctx, &output, &input);
|
||||
if (ZSTD_isError(k)) {
|
||||
log_debug("ZSTD decoder failed: %s", ZSTD_getErrorName(k));
|
||||
return zstd_ret_to_errno(k);
|
||||
}
|
||||
|
||||
if (output.pos >= prefix_len + 1)
|
||||
return memcmp(*buffer, prefix, prefix_len) == 0 &&
|
||||
((const uint8_t*) *buffer)[prefix_len] == extra;
|
||||
|
||||
if (input.pos >= input.size)
|
||||
return 0;
|
||||
|
||||
if (*buffer_size > SIZE_MAX/2)
|
||||
return -ENOBUFS;
|
||||
|
||||
if (!(greedy_realloc(buffer, buffer_size, *buffer_size * 2, 1)))
|
||||
return -ENOMEM;
|
||||
|
||||
output.dst = *buffer;
|
||||
output.size = *buffer_size;
|
||||
k = ZSTD_decompressStream(dctx, &output, &input);
|
||||
if (ZSTD_isError(k)) {
|
||||
log_debug("ZSTD decoder failed: %s", ZSTD_getErrorName(k));
|
||||
return zstd_ret_to_errno(k);
|
||||
}
|
||||
assert(output.pos >= prefix_len + 1);
|
||||
|
||||
return memcmp(*buffer, prefix, prefix_len) == 0 &&
|
||||
((const uint8_t*) *buffer)[prefix_len] == extra;
|
||||
#else
|
||||
return -EPROTONOSUPPORT;
|
||||
#endif
|
||||
|
||||
@ -127,3 +127,12 @@ void journal_print_header(sd_journal *j);
|
||||
|
||||
#define JOURNAL_FOREACH_DATA_RETVAL(j, data, l, retval) \
|
||||
for (sd_journal_restart_data(j); ((retval) = sd_journal_enumerate_data((j), &(data), &(l))) > 0; )
|
||||
|
||||
/* All errors that we might encounter while extracting a field that are not real errors,
|
||||
* but only mean that the field is too large or we don't support the compression. */
|
||||
static inline bool JOURNAL_ERRNO_IS_UNAVAILABLE_FIELD(int r) {
|
||||
return IN_SET(abs(r),
|
||||
ENOBUFS, /* Field or decompressed field too large */
|
||||
E2BIG, /* Field too large for pointer width */
|
||||
EPROTONOSUPPORT); /* Unsupported compression */
|
||||
}
|
||||
|
||||
@ -2462,6 +2462,19 @@ _public_ int sd_journal_enumerate_data(sd_journal *j, const void **data, size_t
|
||||
return 1;
|
||||
}
|
||||
|
||||
_public_ int sd_journal_enumerate_available_data(sd_journal *j, const void **data, size_t *size) {
|
||||
for (;;) {
|
||||
int r;
|
||||
|
||||
r = sd_journal_enumerate_data(j, data, size);
|
||||
if (r >= 0)
|
||||
return r;
|
||||
if (!JOURNAL_ERRNO_IS_UNAVAILABLE_FIELD(r))
|
||||
return r;
|
||||
j->current_field++; /* Try with the next field */
|
||||
}
|
||||
}
|
||||
|
||||
_public_ void sd_journal_restart_data(sd_journal *j) {
|
||||
if (!j)
|
||||
return;
|
||||
@ -3002,6 +3015,20 @@ _public_ int sd_journal_enumerate_unique(sd_journal *j, const void **data, size_
|
||||
}
|
||||
}
|
||||
|
||||
_public_ int sd_journal_enumerate_available_unique(sd_journal *j, const void **data, size_t *size) {
|
||||
for (;;) {
|
||||
int r;
|
||||
|
||||
r = sd_journal_enumerate_unique(j, data, size);
|
||||
if (r >= 0)
|
||||
return r;
|
||||
if (!JOURNAL_ERRNO_IS_UNAVAILABLE_FIELD(r))
|
||||
return r;
|
||||
/* Try with the next field. sd_journal_enumerate_unique() modifies state, so on the next try
|
||||
* we will access the next field. */
|
||||
}
|
||||
}
|
||||
|
||||
_public_ void sd_journal_restart_unique(sd_journal *j) {
|
||||
if (!j)
|
||||
return;
|
||||
|
||||
@ -232,6 +232,8 @@ static void test_lz4_decompress_partial(void) {
|
||||
int r;
|
||||
_cleanup_free_ char *huge = NULL;
|
||||
|
||||
log_debug("/* %s */", __func__);
|
||||
|
||||
assert_se(huge = malloc(HUGE_SIZE));
|
||||
memcpy(huge, "HUGE=", STRLEN("HUGE="));
|
||||
memset(&huge[STRLEN("HUGE=")], 'x', HUGE_SIZE - STRLEN("HUGE=") - 1);
|
||||
|
||||
@ -717,4 +717,7 @@ global:
|
||||
sd_path_lookup_strv;
|
||||
|
||||
sd_notify_barrier;
|
||||
|
||||
sd_journal_enumerate_available_data;
|
||||
sd_journal_enumerate_available_unique;
|
||||
} LIBSYSTEMD_245;
|
||||
|
||||
@ -241,7 +241,7 @@ static int manager_udev_process_link(sd_device_monitor *monitor, sd_device *devi
|
||||
return 0;
|
||||
}
|
||||
if (r > 0) {
|
||||
log_device_debug(device, "Interface is under renaming, wait for the interface to be renamed: %m");
|
||||
log_device_debug(device, "Interface is under renaming, wait for the interface to be renamed.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -378,10 +378,13 @@ int acls_for_file(const char *path, acl_type_t type, acl_t new, acl_t *acl) {
|
||||
|
||||
int add_acls_for_user(int fd, uid_t uid) {
|
||||
_cleanup_(acl_freep) acl_t acl = NULL;
|
||||
acl_entry_t entry;
|
||||
acl_permset_t permset;
|
||||
acl_entry_t entry;
|
||||
int r;
|
||||
|
||||
assert(fd >= 0);
|
||||
assert(uid_is_valid(uid));
|
||||
|
||||
acl = acl_get_fd(fd);
|
||||
if (!acl)
|
||||
return -errno;
|
||||
@ -394,8 +397,8 @@ int add_acls_for_user(int fd, uid_t uid) {
|
||||
return -errno;
|
||||
}
|
||||
|
||||
/* We do not recalculate the mask unconditionally here,
|
||||
* so that the fchmod() mask above stays intact. */
|
||||
/* We do not recalculate the mask unconditionally here, so that the fchmod() mask above stays
|
||||
* intact. */
|
||||
if (acl_get_permset(entry, &permset) < 0 ||
|
||||
acl_add_perm(permset, ACL_READ) < 0)
|
||||
return -errno;
|
||||
@ -404,5 +407,8 @@ int add_acls_for_user(int fd, uid_t uid) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return acl_set_fd(fd, acl);
|
||||
if (acl_set_fd(fd, acl) < 0)
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1140,8 +1140,9 @@ static int make_dm_name_and_node(const void *original_node, const char *suffix,
|
||||
|
||||
base = strrchr(original_node, '/');
|
||||
if (!base)
|
||||
return -EINVAL;
|
||||
base++;
|
||||
base = original_node;
|
||||
else
|
||||
base++;
|
||||
if (isempty(base))
|
||||
return -EINVAL;
|
||||
|
||||
@ -1217,6 +1218,50 @@ static int decrypt_partition(
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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)
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Error opening verity device, it already exists but root hashes are different.");
|
||||
#if HAVE_CRYPT_ACTIVATE_BY_SIGNED_KEY
|
||||
/* Ensure that, if signatures are supported, we only reuse the device if the previous mount
|
||||
* used the same settings, so that a previous unsigned mount will not be reused if the user
|
||||
* asks to use signing for the new one, and viceversa. */
|
||||
if (has_sig != !!(crypt_params.flags & CRYPT_VERITY_ROOT_HASH_SIGNATURE))
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Error opening verity device, it already exists but signature settings are not the same.");
|
||||
#endif
|
||||
|
||||
*ret_cd = TAKE_PTR(cd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void dm_deferred_remove_clean(char *name) {
|
||||
if (!name)
|
||||
return;
|
||||
(void) crypt_deactivate_by_name(NULL, name, CRYPT_DEACTIVATE_DEFERRED);
|
||||
free(name);
|
||||
}
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(char *, dm_deferred_remove_clean);
|
||||
|
||||
static int verity_partition(
|
||||
DissectedPartition *m,
|
||||
DissectedPartition *v,
|
||||
@ -1229,8 +1274,9 @@ static int verity_partition(
|
||||
DissectImageFlags flags,
|
||||
DecryptedImage *d) {
|
||||
|
||||
_cleanup_free_ char *node = NULL, *name = NULL;
|
||||
_cleanup_free_ char *node = NULL, *name = NULL, *hash_sig_from_file = NULL;
|
||||
_cleanup_(crypt_freep) struct crypt_device *cd = NULL;
|
||||
_cleanup_(dm_deferred_remove_cleanp) char *restore_deferred_remove = NULL;
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
@ -1249,12 +1295,23 @@ static int verity_partition(
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = make_dm_name_and_node(m->node, "-verity", &name, &node);
|
||||
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
|
||||
r = make_dm_name_and_node(m->node, "-verity", &name, &node);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!GREEDY_REALLOC0(d->decrypted, d->n_allocated, d->n_decrypted + 1))
|
||||
return -ENOMEM;
|
||||
if (!root_hash_sig && root_hash_sig_path) {
|
||||
r = read_full_file_full(AT_FDCWD, root_hash_sig_path, 0, &hash_sig_from_file, &root_hash_sig_size);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
r = crypt_init(&cd, verity_data ?: v->node);
|
||||
if (r < 0)
|
||||
@ -1270,27 +1327,69 @@ static int verity_partition(
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (root_hash_sig || root_hash_sig_path) {
|
||||
if (!GREEDY_REALLOC0(d->decrypted, d->n_allocated, d->n_decrypted + 1))
|
||||
return -ENOMEM;
|
||||
|
||||
/* If activating fails because the device already exists, check the metadata and reuse it if it matches.
|
||||
* In case of ENODEV/ENOENT, which can happen if another process is activating at the exact same time,
|
||||
* retry a few times before giving up. */
|
||||
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
|
||||
if (root_hash_sig)
|
||||
r = crypt_activate_by_signed_key(cd, name, root_hash, root_hash_size, root_hash_sig, root_hash_sig_size, CRYPT_ACTIVATE_READONLY);
|
||||
else {
|
||||
_cleanup_free_ char *hash_sig = NULL;
|
||||
size_t hash_sig_size;
|
||||
|
||||
r = read_full_file_full(AT_FDCWD, root_hash_sig_path, 0, &hash_sig, &hash_sig_size);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = crypt_activate_by_signed_key(cd, name, root_hash, root_hash_size, hash_sig, hash_sig_size, CRYPT_ACTIVATE_READONLY);
|
||||
}
|
||||
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);
|
||||
#else
|
||||
r = log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "activation of verity device with signature requested, but not supported by cryptsetup due to missing crypt_activate_by_signed_key()");
|
||||
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);
|
||||
if (r < 0)
|
||||
return r;
|
||||
} else
|
||||
r = 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 fallback to activating the device with a unique name.
|
||||
* Improvements in libcrypsetup can ensure this never happens: https://gitlab.com/cryptsetup/cryptsetup/-/merge_requests/96 */
|
||||
if (r == -EINVAL && FLAGS_SET(flags, DISSECT_IMAGE_VERITY_SHARE))
|
||||
return verity_partition(m, v, root_hash, root_hash_size, verity_data, NULL, root_hash_sig ?: hash_sig_from_file, root_hash_sig_size, flags & ~DISSECT_IMAGE_VERITY_SHARE, d);
|
||||
if (!IN_SET(r, 0, -EEXIST, -ENODEV))
|
||||
return r;
|
||||
if (r == -EEXIST) {
|
||||
struct crypt_device *existing_cd = NULL;
|
||||
|
||||
if (!restore_deferred_remove){
|
||||
/* To avoid races, disable automatic removal on umount while setting up the new device. Restore it on failure. */
|
||||
r = dm_deferred_remove_cancel(name);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Disabling automated deferred removal for verity device %s failed: %m", node);
|
||||
restore_deferred_remove = strdup(name);
|
||||
if (!restore_deferred_remove)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
r = verity_can_reuse(root_hash, root_hash_size, !!root_hash_sig || !!hash_sig_from_file, name, &existing_cd);
|
||||
/* Same as above, -EINVAL can randomly happen when it actually means -EEXIST */
|
||||
if (r == -EINVAL && FLAGS_SET(flags, DISSECT_IMAGE_VERITY_SHARE))
|
||||
return verity_partition(m, v, root_hash, root_hash_size, verity_data, NULL, root_hash_sig ?: hash_sig_from_file, root_hash_sig_size, flags & ~DISSECT_IMAGE_VERITY_SHARE, d);
|
||||
if (!IN_SET(r, 0, -ENODEV, -ENOENT))
|
||||
return log_debug_errno(r, "Checking whether existing verity device %s can be reused failed: %m", node);
|
||||
if (r == 0) {
|
||||
if (cd)
|
||||
crypt_free(cd);
|
||||
cd = existing_cd;
|
||||
}
|
||||
}
|
||||
if (r == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Sanity check: libdevmapper is known to report that the device already exists and is active,
|
||||
* but it's actually not there, so the later filesystem probe or mount would fail. */
|
||||
if (r == 0)
|
||||
r = access(node, F_OK);
|
||||
/* An existing verity device was reported by libcryptsetup/libdevmapper, but we can't use it at this time.
|
||||
* Fall back to activating it with a unique device name. */
|
||||
if (r != 0 && FLAGS_SET(flags, DISSECT_IMAGE_VERITY_SHARE))
|
||||
return verity_partition(m, v, root_hash, root_hash_size, verity_data, NULL, root_hash_sig ?: hash_sig_from_file, root_hash_sig_size, flags & ~DISSECT_IMAGE_VERITY_SHARE, d);
|
||||
|
||||
/* Everything looks good and we'll be able to mount the device, so deferred remove will be re-enabled at that point. */
|
||||
restore_deferred_remove = mfree(restore_deferred_remove);
|
||||
|
||||
d->decrypted[d->n_decrypted].name = TAKE_PTR(name);
|
||||
d->decrypted[d->n_decrypted].device = TAKE_PTR(cd);
|
||||
@ -1357,7 +1456,7 @@ int dissected_image_decrypt(
|
||||
|
||||
k = PARTITION_VERITY_OF(i);
|
||||
if (k >= 0) {
|
||||
r = verity_partition(p, m->partitions + k, root_hash, root_hash_size, verity_data, root_hash_sig_path, root_hash_sig, root_hash_sig_size, flags, d);
|
||||
r = verity_partition(p, m->partitions + k, root_hash, root_hash_size, verity_data, root_hash_sig_path, root_hash_sig, root_hash_sig_size, flags | DISSECT_IMAGE_VERITY_SHARE, d);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
@ -1437,7 +1536,7 @@ int decrypted_image_relinquish(DecryptedImage *d) {
|
||||
if (p->relinquished)
|
||||
continue;
|
||||
|
||||
r = dm_deferred_remove(p->name);
|
||||
r = 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);
|
||||
|
||||
|
||||
@ -64,6 +64,7 @@ typedef enum DissectImageFlags {
|
||||
DISSECT_IMAGE_RELAX_VAR_CHECK = 1 << 10, /* Don't insist that the UUID of /var is hashed from /etc/machine-id */
|
||||
DISSECT_IMAGE_FSCK = 1 << 11, /* File system check the partition before mounting (no effect when combined with DISSECT_IMAGE_READ_ONLY) */
|
||||
DISSECT_IMAGE_NO_PARTITION_TABLE = 1 << 12, /* Only recognize single file system images */
|
||||
DISSECT_IMAGE_VERITY_SHARE = 1 << 13, /* When activating a verity device, reuse existing one if already open */
|
||||
} DissectImageFlags;
|
||||
|
||||
struct DissectedImage {
|
||||
|
||||
@ -6,35 +6,37 @@
|
||||
#include "fd-util.h"
|
||||
#include "string-util.h"
|
||||
|
||||
int dm_deferred_remove(const char *name) {
|
||||
|
||||
struct dm_ioctl dm = {
|
||||
.version = {
|
||||
DM_VERSION_MAJOR,
|
||||
DM_VERSION_MINOR,
|
||||
DM_VERSION_PATCHLEVEL
|
||||
},
|
||||
.data_size = sizeof(dm),
|
||||
.flags = DM_DEFERRED_REMOVE,
|
||||
};
|
||||
|
||||
int dm_deferred_remove_cancel(const char *name) {
|
||||
_cleanup_close_ int fd = -1;
|
||||
struct message {
|
||||
struct dm_ioctl dm_ioctl;
|
||||
struct dm_target_msg dm_target_msg;
|
||||
char msg_text[STRLEN("@cancel_deferred_remove") + 1];
|
||||
} _packed_ message = {
|
||||
.dm_ioctl = {
|
||||
.version = {
|
||||
DM_VERSION_MAJOR,
|
||||
DM_VERSION_MINOR,
|
||||
DM_VERSION_PATCHLEVEL
|
||||
},
|
||||
.data_size = sizeof(struct message),
|
||||
.data_start = sizeof(struct dm_ioctl),
|
||||
},
|
||||
.msg_text = "@cancel_deferred_remove",
|
||||
};
|
||||
|
||||
assert(name);
|
||||
|
||||
/* Unfortunately, libcryptsetup doesn't provide a proper API for this, hence call the ioctl()
|
||||
* directly. */
|
||||
|
||||
if (strlen(name) >= sizeof(dm.name))
|
||||
if (strlen(name) >= sizeof(message.dm_ioctl.name))
|
||||
return -ENODEV; /* A device with a name longer than this cannot possibly exist */
|
||||
|
||||
strncpy_exact(message.dm_ioctl.name, name, sizeof(message.dm_ioctl.name));
|
||||
|
||||
fd = open("/dev/mapper/control", O_RDWR|O_CLOEXEC);
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
|
||||
strncpy_exact(dm.name, name, sizeof(dm.name));
|
||||
|
||||
if (ioctl(fd, DM_DEV_REMOVE, &dm))
|
||||
if (ioctl(fd, DM_TARGET_MSG, &message))
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1+ */
|
||||
#pragma once
|
||||
|
||||
int dm_deferred_remove(const char *name);
|
||||
int dm_deferred_remove_cancel(const char *name);
|
||||
|
||||
@ -105,6 +105,7 @@ int sd_journal_get_data_threshold(sd_journal *j, size_t *sz);
|
||||
|
||||
int sd_journal_get_data(sd_journal *j, const char *field, const void **data, size_t *l);
|
||||
int sd_journal_enumerate_data(sd_journal *j, const void **data, size_t *l);
|
||||
int sd_journal_enumerate_available_data(sd_journal *j, const void **data, size_t *l);
|
||||
void sd_journal_restart_data(sd_journal *j);
|
||||
|
||||
int sd_journal_add_match(sd_journal *j, const void *data, size_t size);
|
||||
@ -128,6 +129,7 @@ int sd_journal_get_usage(sd_journal *j, uint64_t *bytes);
|
||||
|
||||
int sd_journal_query_unique(sd_journal *j, const char *field);
|
||||
int sd_journal_enumerate_unique(sd_journal *j, const void **data, size_t *l);
|
||||
int sd_journal_enumerate_available_unique(sd_journal *j, const void **data, size_t *l);
|
||||
void sd_journal_restart_unique(sd_journal *j);
|
||||
|
||||
int sd_journal_enumerate_fields(sd_journal *j, const char **field);
|
||||
@ -156,13 +158,13 @@ int sd_journal_has_persistent_files(sd_journal *j);
|
||||
if (sd_journal_seek_tail(j) < 0) { } \
|
||||
else while (sd_journal_previous(j) > 0)
|
||||
|
||||
/* Iterate through the data fields of the current journal entry */
|
||||
/* Iterate through all available data fields of the current journal entry */
|
||||
#define SD_JOURNAL_FOREACH_DATA(j, data, l) \
|
||||
for (sd_journal_restart_data(j); sd_journal_enumerate_data((j), &(data), &(l)) > 0; )
|
||||
for (sd_journal_restart_data(j); sd_journal_enumerate_available_data((j), &(data), &(l)) > 0; )
|
||||
|
||||
/* Iterate through the all known values of a specific field */
|
||||
/* Iterate through all available values of a specific field */
|
||||
#define SD_JOURNAL_FOREACH_UNIQUE(j, data, l) \
|
||||
for (sd_journal_restart_unique(j); sd_journal_enumerate_unique((j), &(data), &(l)) > 0; )
|
||||
for (sd_journal_restart_unique(j); sd_journal_enumerate_available_unique((j), &(data), &(l)) > 0; )
|
||||
|
||||
/* Iterate through all known field names */
|
||||
#define SD_JOURNAL_FOREACH_FIELD(j, field) \
|
||||
|
||||
@ -840,11 +840,6 @@ static int rename_netif(UdevEvent *event) {
|
||||
if (r < 0)
|
||||
return log_device_error_errno(dev, r, "Failed to get ifindex: %m");
|
||||
|
||||
r = rtnl_set_link_name(&event->rtnl, ifindex, event->name);
|
||||
if (r < 0)
|
||||
return log_device_error_errno(dev, r, "Failed to rename network interface %i from '%s' to '%s': %m",
|
||||
ifindex, oldname, event->name);
|
||||
|
||||
/* Set ID_RENAMING boolean property here, and drop it in the corresponding move uevent later. */
|
||||
r = device_add_property(dev, "ID_RENAMING", "1");
|
||||
if (r < 0)
|
||||
@ -854,6 +849,22 @@ static int rename_netif(UdevEvent *event) {
|
||||
if (r < 0)
|
||||
return log_device_warning_errno(dev, r, "Failed to update properties with new name '%s': %m", event->name);
|
||||
|
||||
/* Also set ID_RENAMING boolean property to cloned sd_device object and save it to database
|
||||
* before calling rtnl_set_link_name(). Otherwise, clients (e.g., systemd-networkd) may receive
|
||||
* RTM_NEWLINK netlink message before the database is updated. */
|
||||
r = device_add_property(event->dev_db_clone, "ID_RENAMING", "1");
|
||||
if (r < 0)
|
||||
return log_device_warning_errno(event->dev_db_clone, r, "Failed to add 'ID_RENAMING' property: %m");
|
||||
|
||||
r = device_update_db(event->dev_db_clone);
|
||||
if (r < 0)
|
||||
return log_device_debug_errno(event->dev_db_clone, r, "Failed to update database under /run/udev/data/: %m");
|
||||
|
||||
r = rtnl_set_link_name(&event->rtnl, ifindex, event->name);
|
||||
if (r < 0)
|
||||
return log_device_error_errno(dev, r, "Failed to rename network interface %i from '%s' to '%s': %m",
|
||||
ifindex, oldname, event->name);
|
||||
|
||||
log_device_debug(dev, "Network interface %i is renamed from '%s' to '%s'", ifindex, oldname, event->name);
|
||||
|
||||
return 1;
|
||||
@ -870,8 +881,7 @@ static int update_devnode(UdevEvent *event) {
|
||||
return log_device_error_errno(dev, r, "Failed to get devnum: %m");
|
||||
|
||||
/* remove/update possible left-over symlinks from old database entry */
|
||||
if (event->dev_db_clone)
|
||||
(void) udev_node_update_old_links(dev, event->dev_db_clone);
|
||||
(void) udev_node_update_old_links(dev, event->dev_db_clone);
|
||||
|
||||
if (!uid_is_valid(event->uid)) {
|
||||
r = device_get_devnode_uid(dev, &event->uid);
|
||||
@ -934,8 +944,7 @@ static int udev_event_on_move(UdevEvent *event) {
|
||||
sd_device *dev = event->dev;
|
||||
int r;
|
||||
|
||||
if (event->dev_db_clone &&
|
||||
sd_device_get_devnum(dev, NULL) < 0) {
|
||||
if (sd_device_get_devnum(dev, NULL) < 0) {
|
||||
r = device_copy_properties(dev, event->dev_db_clone);
|
||||
if (r < 0)
|
||||
log_device_debug_errno(dev, r, "Failed to copy properties from cloned sd_device object, ignoring: %m");
|
||||
@ -981,7 +990,7 @@ int udev_event_execute_rules(UdevEvent *event,
|
||||
if (r < 0)
|
||||
return log_device_debug_errno(dev, r, "Failed to clone sd_device object: %m");
|
||||
|
||||
if (event->dev_db_clone && sd_device_get_devnum(dev, NULL) >= 0)
|
||||
if (sd_device_get_devnum(dev, NULL) >= 0)
|
||||
/* Disable watch during event processing. */
|
||||
(void) udev_watch_end(event->dev_db_clone);
|
||||
|
||||
@ -1019,8 +1028,6 @@ int udev_event_execute_rules(UdevEvent *event,
|
||||
|
||||
device_set_is_initialized(dev);
|
||||
|
||||
event->dev_db_clone = sd_device_unref(event->dev_db_clone);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -633,6 +633,9 @@ install_dmevent() {
|
||||
else
|
||||
inst_rules 10-dm.rules 13-dm-disk.rules 95-dm-notify.rules
|
||||
fi
|
||||
if [[ "$LOOKS_LIKE_SUSE" ]]; then
|
||||
inst_rules 60-persistent-storage.rules 61-persistent-storage-compat.rules 99-systemd.rules
|
||||
fi
|
||||
}
|
||||
|
||||
install_systemd() {
|
||||
@ -932,7 +935,7 @@ install_config_files() {
|
||||
inst /etc/sysconfig/init || :
|
||||
inst /etc/passwd
|
||||
inst /etc/shadow
|
||||
inst /etc/login.defs
|
||||
inst_any /etc/login.defs /usr/etc/login.defs
|
||||
inst /etc/group
|
||||
inst /etc/shells
|
||||
inst_any /etc/nsswitch.conf /usr/etc/nsswitch.conf
|
||||
@ -1948,6 +1951,7 @@ setup_suse() {
|
||||
ln -fs ../usr/bin/systemctl $initdir/bin/
|
||||
ln -fs ../usr/lib/systemd $initdir/lib/
|
||||
inst_simple "/usr/lib/systemd/system/haveged.service"
|
||||
instmods ext4
|
||||
}
|
||||
|
||||
_umount_dir() {
|
||||
|
||||
@ -40,12 +40,23 @@ mv ${image}.roothash ${image}.foohash
|
||||
mv ${image}.fooverity ${image}.verity
|
||||
mv ${image}.foohash ${image}.roothash
|
||||
|
||||
mkdir -p ${image_dir}/mount
|
||||
mkdir -p ${image_dir}/mount ${image_dir}/mount2
|
||||
/usr/lib/systemd/systemd-dissect --mount ${image}.raw ${image_dir}/mount
|
||||
cat ${image_dir}/mount/usr/lib/os-release | grep -q -F -f /usr/lib/os-release
|
||||
cat ${image_dir}/mount/etc/os-release | grep -q -F -f /usr/lib/os-release
|
||||
cat ${image_dir}/mount/usr/lib/os-release | grep -q -F "MARKER=1"
|
||||
# Verity volume should be shared (opened only once)
|
||||
/usr/lib/systemd/systemd-dissect --mount ${image}.raw ${image_dir}/mount2
|
||||
verity_count=$(ls -1 /dev/mapper/ | grep -c verity)
|
||||
# In theory we should check that count is exactly one. In practice, libdevmapper
|
||||
# randomly and unpredictably fails with an unhelpful EINVAL when a device is open
|
||||
# (and even mounted and in use), so best-effort is the most we can do for now
|
||||
if [ ${verity_count} -lt 1 ]; then
|
||||
echo "Verity device ${image}.raw not found in /dev/mapper/"
|
||||
exit 1
|
||||
fi
|
||||
umount ${image_dir}/mount
|
||||
umount ${image_dir}/mount2
|
||||
|
||||
systemd-run -t --property RootImage=${image}.raw /usr/bin/cat /usr/lib/os-release | grep -q -F "MARKER=1"
|
||||
mv ${image}.verity ${image}.fooverity
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user