mirror of
https://github.com/systemd/systemd
synced 2026-03-25 00:04:53 +01:00
Compare commits
No commits in common. "2f363b407f134441108871428f4d55943968ea68" and "9e418cd075aa29fb595b7a1ad5aaeb9f13f9c61e" have entirely different histories.
2f363b407f
...
9e418cd075
6
TODO
6
TODO
@ -137,12 +137,6 @@ Deprecations and removals:
|
|||||||
|
|
||||||
Features:
|
Features:
|
||||||
|
|
||||||
* systemd-repart: implement Integrity=data/meta and Integrity=inline for non-LUKS
|
|
||||||
case. Currently, only Integrity=inline combined with Encrypt= is implemented
|
|
||||||
and uses libcryptsetup features. Add support for plain dm-integrity setups when
|
|
||||||
integrity tags are stored by the device (inline), interleaved with data (data),
|
|
||||||
and on a separate device (meta).
|
|
||||||
|
|
||||||
* networkd/machined: implement reverse name lookups in the resolved hook
|
* networkd/machined: implement reverse name lookups in the resolved hook
|
||||||
|
|
||||||
* networkd's resolved hook: optionally map all lease IP addresses handed out to
|
* networkd's resolved hook: optionally map all lease IP addresses handed out to
|
||||||
|
|||||||
@ -13,27 +13,27 @@ SPDX-License-Identifier: LGPL-2.1-or-later
|
|||||||
4. Update hwdb (`ninja -C build update-hwdb`, `ninja -C build update-hwdb-autosuspend`, commit separately).
|
4. Update hwdb (`ninja -C build update-hwdb`, `ninja -C build update-hwdb-autosuspend`, commit separately).
|
||||||
5. Update syscall numbers (`ninja -C build update-syscall-tables update-syscall-header`).
|
5. Update syscall numbers (`ninja -C build update-syscall-tables update-syscall-header`).
|
||||||
6. [RC1] Update library numbers in `meson.build`
|
6. [RC1] Update library numbers in `meson.build`
|
||||||
7. [RC1] Switch `versionrewrite-pattern` and `versionrewrite-replacement` to RC mode in https://build.opensuse.org/projects/system:systemd/packages/systemd/files/_service?expand=1
|
8. [RC1] Switch `versionrewrite-pattern` and `versionrewrite-replacement` to RC mode in https://build.opensuse.org/projects/system:systemd/packages/systemd/files/_service?expand=1
|
||||||
8. Update version number in `meson.version` (e.g. from `256~devel` to `256~rc1` or from `256~rc3` to `256`). Note that this uses a tilde (\~) instead of a hyphen (-) because tildes sort lower in version comparisons according to the [UAPI.10 Version Format Specification](https://uapi-group.org/specifications/specs/version_format_specification/), and we want `255~rc1` to sort lower than `255`.
|
9. Update version number in `meson.version` (e.g. from `256~devel` to `256~rc1` or from `256~rc3` to `256`). Note that this uses a tilde (\~) instead of a hyphen (-) because tildes sort lower in version comparisons according to the [UAPI.10 Version Format Specification](https://uapi-group.org/specifications/specs/version_format_specification/), and we want `255~rc1` to sort lower than `255`.
|
||||||
9. Check dbus docs with `ninja -C build update-dbus-docs`
|
10. Check dbus docs with `ninja -C build update-dbus-docs`
|
||||||
10. Check manpages list with `ninja -C build update-man-rules`
|
11. Check manpages list with `ninja -C build update-man-rules`
|
||||||
11. Update translation strings (`ninja -C build systemd-pot`, `ninja -C build systemd-update-po`) - drop the header comments from `systemd.pot` + re-add SPDX before committing. If the only change in a file is the 'POT-Creation-Date' field, then ignore that file.
|
12. Update translation strings (`ninja -C build systemd-pot`, `ninja -C build systemd-update-po`) - drop the header comments from `systemd.pot` + re-add SPDX before committing. If the only change in a file is the 'POT-Creation-Date' field, then ignore that file.
|
||||||
12. Tag the release: `version="v$(sed 's/~/-/g' meson.version)" && git tag -s "${version}" -m "systemd ${version}"` (tildes are replaced with hyphens, because git doesn't accept the former).
|
13. Tag the release: `version="v$(sed 's/~/-/g' meson.version)" && git tag -s "${version}" -m "systemd ${version}"` (tildes are replaced with hyphens, because git doesn't accept the former).
|
||||||
13. Do `ninja -C build`
|
14. Do `ninja -C build`
|
||||||
14. Make sure that the version string and package string match: `build/systemctl --version`
|
15. Make sure that the version string and package string match: `build/systemctl --version`
|
||||||
15. [FINAL] Close the github milestone and open a new one (https://github.com/systemd/systemd/milestones)
|
16. [FINAL] Close the github milestone and open a new one (https://github.com/systemd/systemd/milestones)
|
||||||
16. "Draft" a new release on github (https://github.com/systemd/systemd/releases/new), mark "This is a pre-release" if appropriate.
|
17. "Draft" a new release on github (https://github.com/systemd/systemd/releases/new), mark "This is a pre-release" if appropriate.
|
||||||
17. Check that announcement to systemd-devel, with a copy&paste from NEWS, was sent. This should happen automatically.
|
18. Check that announcement to systemd-devel, with a copy&paste from NEWS, was sent. This should happen automatically.
|
||||||
18. Update IRC topic (`/msg chanserv TOPIC #systemd Version NNN released | Online resources https://systemd.io/`)
|
19. Update IRC topic (`/msg chanserv TOPIC #systemd Version NNN released | Online resources https://systemd.io/`)
|
||||||
19. [FINAL] Create an empty -stable branch: `git push systemd origin/main:refs/heads/v${version}-stable`.
|
20. [FINAL] Create an empty -stable branch: `git push systemd origin/main:refs/heads/v${version}-stable`.
|
||||||
20. [FINAL] Build and upload the documentation (on the -stable branch): `ninja -C build doc-sync`
|
21. [FINAL] Build and upload the documentation (on the -stable branch): `ninja -C build doc-sync`
|
||||||
21. [FINAL] Create a new `ci/v${version}-stable` branch for deb package builds on https://salsa.debian.org/systemd-team/systemd
|
22. [FINAL] Create a new `ci/v${version}-stable` branch for deb package builds on https://salsa.debian.org/systemd-team/systemd
|
||||||
22. [FINAL] Switch `.semaphore/semaphore-runner.sh` and `mkosi/mkosi.pkgenv/mkosi.conf.d/debian-ubuntu.conf`
|
23. [FINAL] Switch `.semaphore/semaphore-runner.sh` and `mkosi/mkosi.pkgenv/mkosi.conf.d/debian-ubuntu.conf`
|
||||||
to the new `ci/v${version}-stable` branch on the -stable branch
|
to the new `ci/v${version}-stable` branch on the -stable branch
|
||||||
23. [FINAL] Switch `versionrewrite-pattern` and `versionrewrite-replacement` to release mode in https://build.opensuse.org/projects/system:systemd/packages/systemd/files/_service?expand=1
|
24. [FINAL] Switch `versionrewrite-pattern` and `versionrewrite-replacement` to release mode in https://build.opensuse.org/projects/system:systemd/packages/systemd/files/_service?expand=1
|
||||||
24. [FINAL] Change the Github Pages branch to the newly created branch (https://github.com/systemd/systemd/settings/pages) and set the 'Custom domain' to 'systemd.io'
|
25. [FINAL] Change the Github Pages branch to the newly created branch (https://github.com/systemd/systemd/settings/pages) and set the 'Custom domain' to 'systemd.io'
|
||||||
25. [FINAL] Update version number in `meson.version` to the devel version of the next release (e.g. from `256` to `257~devel`)
|
26. [FINAL] Update version number in `meson.version` to the devel version of the next release (e.g. from `256` to `257~devel`)
|
||||||
26. [FINAL] Build and upload the documentation (on the main branch): `ninja -C build doc-sync`
|
27. [FINAL] Build and upload the documentation (on the main branch): `ninja -C build doc-sync`
|
||||||
|
|
||||||
# Steps to a Successful Stable Release
|
# Steps to a Successful Stable Release
|
||||||
|
|
||||||
|
|||||||
@ -909,27 +909,6 @@
|
|||||||
<xi:include href="version-info.xml" xpointer="v259"/></listitem>
|
<xi:include href="version-info.xml" xpointer="v259"/></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
|
||||||
<term><varname>Integrity=</varname></term>
|
|
||||||
|
|
||||||
<listitem><para>Enable integrity checking for the partition. Currently, the only supported option
|
|
||||||
is <varname>Integrity=inline</varname> which enables authenticated disk encryption for LUKS2 devices.
|
|
||||||
The option requires <varname>Encrypt=</varname> setting and can only be used in online image build.
|
|
||||||
Defaults to <literal>off</literal>, i.e. integrity protection is disabled.</para>
|
|
||||||
<para>Note: authenticated disk encryption is considered EXPERIMENTAL by cryptsetup.</para>
|
|
||||||
|
|
||||||
<xi:include href="version-info.xml" xpointer="v260"/></listitem>
|
|
||||||
</varlistentry>
|
|
||||||
|
|
||||||
<varlistentry>
|
|
||||||
<term><varname>IntegrityAlgorithm=</varname></term>
|
|
||||||
<listitem><para>Specify the integrity algorithm to be used for integrity verification. For
|
|
||||||
<varname>Integrity=inline</varname> the supported values are: <literal>hmac-sha1</literal>,
|
|
||||||
<literal>hmac-sha256</literal>(default), and <literal>hmac-sha512</literal>.</para>
|
|
||||||
|
|
||||||
<xi:include href="version-info.xml" xpointer="v260"/></listitem>
|
|
||||||
</varlistentry>
|
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><varname>Compression=</varname></term>
|
<term><varname>Compression=</varname></term>
|
||||||
|
|
||||||
|
|||||||
@ -1206,7 +1206,7 @@ manpages = [
|
|||||||
'systemd-tmpfiles-setup.service'],
|
'systemd-tmpfiles-setup.service'],
|
||||||
''],
|
''],
|
||||||
['systemd-tpm2-clear.service', '8', [], 'ENABLE_BOOTLOADER'],
|
['systemd-tpm2-clear.service', '8', [], 'ENABLE_BOOTLOADER'],
|
||||||
['systemd-tpm2-generator', '8', [], 'ENABLE_BOOTLOADER'],
|
['systemd-tpm2-generator', '8', [], ''],
|
||||||
['systemd-tpm2-setup.service',
|
['systemd-tpm2-setup.service',
|
||||||
'8',
|
'8',
|
||||||
['systemd-tpm2-setup', 'systemd-tpm2-setup-early.service'],
|
['systemd-tpm2-setup', 'systemd-tpm2-setup-early.service'],
|
||||||
|
|||||||
@ -56,7 +56,7 @@
|
|||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><command>extract-public</command></term>
|
<term><command>public</command></term>
|
||||||
|
|
||||||
<listitem><para>This commands prints the public key in PEM format extracted from either the
|
<listitem><para>This commands prints the public key in PEM format extracted from either the
|
||||||
certificate given with <option>--certificate=</option> or the private key given with
|
certificate given with <option>--certificate=</option> or the private key given with
|
||||||
@ -65,17 +65,6 @@
|
|||||||
<xi:include href="version-info.xml" xpointer="v257"/></listitem>
|
<xi:include href="version-info.xml" xpointer="v257"/></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
|
||||||
<term><command>extract-certificate</command></term>
|
|
||||||
|
|
||||||
<listitem><para>This command prints the X.509 certificate in PEM format extracted from the
|
|
||||||
certificate given with <option>--certificate=</option>. This is useful when loading a certificate
|
|
||||||
from an OpenSSL provider (e.g. a hardware token) and wanting to output a standalone PEM certificate
|
|
||||||
that can be used without the provider.</para>
|
|
||||||
|
|
||||||
<xi:include href="version-info.xml" xpointer="v260"/></listitem>
|
|
||||||
</varlistentry>
|
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><command>pkcs7</command></term>
|
<term><command>pkcs7</command></term>
|
||||||
|
|
||||||
|
|||||||
@ -9,5 +9,5 @@ Environment=
|
|||||||
GIT_URL=https://salsa.debian.org/systemd-team/systemd.git
|
GIT_URL=https://salsa.debian.org/systemd-team/systemd.git
|
||||||
GIT_SUBDIR=debian
|
GIT_SUBDIR=debian
|
||||||
GIT_BRANCH=debian/master
|
GIT_BRANCH=debian/master
|
||||||
GIT_COMMIT=d9f2aa1704bc98d1aec6519a863a07eaf12b76ad
|
GIT_COMMIT=6f15bdaae7014c233b662ac4a33d464893b81b36
|
||||||
PKG_SUBDIR=debian
|
PKG_SUBDIR=debian
|
||||||
|
|||||||
@ -20,8 +20,8 @@ static int table_add_designator_line(Table *table, PartitionDesignator d, Partit
|
|||||||
return log_oom();
|
return log_oom();
|
||||||
|
|
||||||
color = (f & _PARTITION_POLICY_USE_MASK) == PARTITION_POLICY_IGNORE ? ansi_grey() :
|
color = (f & _PARTITION_POLICY_USE_MASK) == PARTITION_POLICY_IGNORE ? ansi_grey() :
|
||||||
((f & (PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ENCRYPTED|PARTITION_POLICY_ENCRYPTEDWITHINTEGRITY|PARTITION_POLICY_VERITY|PARTITION_POLICY_SIGNED|PARTITION_POLICY_ABSENT)) ==
|
((f & (PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ENCRYPTED|PARTITION_POLICY_VERITY|PARTITION_POLICY_SIGNED|PARTITION_POLICY_ABSENT)) ==
|
||||||
(PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ENCRYPTED|PARTITION_POLICY_ENCRYPTEDWITHINTEGRITY|PARTITION_POLICY_VERITY|PARTITION_POLICY_SIGNED|PARTITION_POLICY_ABSENT)) ? ansi_highlight_yellow() :
|
(PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ENCRYPTED|PARTITION_POLICY_VERITY|PARTITION_POLICY_SIGNED|PARTITION_POLICY_ABSENT)) ? ansi_highlight_yellow() :
|
||||||
(f & _PARTITION_POLICY_USE_MASK) == PARTITION_POLICY_ABSENT ? ansi_highlight_red() :
|
(f & _PARTITION_POLICY_USE_MASK) == PARTITION_POLICY_ABSENT ? ansi_highlight_red() :
|
||||||
!(f & PARTITION_POLICY_UNPROTECTED) ? ansi_highlight_green() : NULL;
|
!(f & PARTITION_POLICY_UNPROTECTED) ? ansi_highlight_green() : NULL;
|
||||||
|
|
||||||
|
|||||||
@ -2374,12 +2374,17 @@ int terminal_get_size_by_dsr(
|
|||||||
assert(input_fd >= 0);
|
assert(input_fd >= 0);
|
||||||
assert(output_fd >= 0);
|
assert(output_fd >= 0);
|
||||||
|
|
||||||
/* Tries to determine the terminal dimension by means of ANSI sequences.
|
/* Tries to determine the terminal dimension by means of ANSI sequences rather than TIOCGWINSZ
|
||||||
|
* ioctl(). Why bother with this? The ioctl() information is often incorrect on serial terminals
|
||||||
|
* (since there's no handshake or protocol to determine the right dimensions in RS232), but since the
|
||||||
|
* ANSI sequences are interpreted by the final terminal instead of an intermediary tty driver they
|
||||||
|
* should be more accurate.
|
||||||
*
|
*
|
||||||
* We position the cursor briefly at an absolute location very far down and very far to the right,
|
* Unfortunately there's no direct ANSI sequence to query terminal dimensions. But we can hack around
|
||||||
* and then read back where we actually ended up. Because cursor locations are capped at the terminal
|
* it: we position the cursor briefly at an absolute location very far down and very far to the
|
||||||
* width/height we should then see the right values. In order to not risk integer overflows in
|
* right, and then read back where we actually ended up. Because cursor locations are capped at the
|
||||||
* terminal applications we'll use INT16_MAX-1 as location to jump to — hopefully a value that is
|
* terminal width/height we should then see the right values. In order to not risk integer overflows
|
||||||
|
* in terminal applications we'll use INT16_MAX-1 as location to jump to — hopefully a value that is
|
||||||
* large enough for any real-life terminals, but small enough to not overflow anything or be
|
* large enough for any real-life terminals, but small enough to not overflow anything or be
|
||||||
* recognized as a "niche" value. (Note that the dimension fields in "struct winsize" are 16bit only,
|
* recognized as a "niche" value. (Note that the dimension fields in "struct winsize" are 16bit only,
|
||||||
* too). */
|
* too). */
|
||||||
@ -2513,143 +2518,12 @@ finish:
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* See https://terminalguide.namepad.de/seq/csi_st-18/,
|
|
||||||
* https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Functions-using-CSI-_-ordered-by-the-final-character_s_.
|
|
||||||
*/
|
|
||||||
#define CSI18_Q "\x1B[18t" /* Report the size of the text area in characters */
|
|
||||||
#define CSI18_Rp "\x1B[8;" /* Reply prefix */
|
|
||||||
#define CSI18_R0 CSI18_Rp "1;1t" /* Shortest reply */
|
|
||||||
#define CSI18_R1 CSI18_Rp "32766;32766t" /* Longest reply */
|
|
||||||
|
|
||||||
static int scan_text_area_size_response(
|
|
||||||
const char *buf,
|
|
||||||
size_t size,
|
|
||||||
unsigned *ret_rows,
|
|
||||||
unsigned *ret_columns) {
|
|
||||||
|
|
||||||
assert(buf);
|
|
||||||
assert(ret_rows);
|
|
||||||
assert(ret_columns);
|
|
||||||
|
|
||||||
/* Check if we have enough space for the shortest possible answer. */
|
|
||||||
if (size < STRLEN(CSI18_R0))
|
|
||||||
return -EAGAIN;
|
|
||||||
|
|
||||||
/* Check if the terminating sequence is present */
|
|
||||||
if (buf[size - 1] != 't')
|
|
||||||
return -EAGAIN;
|
|
||||||
|
|
||||||
unsigned short rows, columns;
|
|
||||||
if (sscanf(buf, CSI18_Rp "%hu;%hut", &rows, &columns) != 2)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
*ret_rows = rows;
|
|
||||||
*ret_columns = columns;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int terminal_get_size_by_csi18(
|
|
||||||
int input_fd,
|
|
||||||
int output_fd,
|
|
||||||
unsigned *ret_rows,
|
|
||||||
unsigned *ret_columns) {
|
|
||||||
int r;
|
|
||||||
|
|
||||||
assert(input_fd >= 0);
|
|
||||||
assert(output_fd >= 0);
|
|
||||||
|
|
||||||
/* Tries to determine the terminal dimension by means of an ANSI sequence CSI 18. */
|
|
||||||
|
|
||||||
if (terminal_is_dumb())
|
|
||||||
return -EOPNOTSUPP;
|
|
||||||
|
|
||||||
r = terminal_verify_same(input_fd, output_fd);
|
|
||||||
if (r < 0)
|
|
||||||
return log_debug_errno(r, "Called with distinct input/output fds: %m");
|
|
||||||
|
|
||||||
/* Open a 2nd input fd, in non-blocking mode, so that we won't ever hang in read()
|
|
||||||
* should someone else process the POLLIN. Do all subsequent operations on the new fd. */
|
|
||||||
_cleanup_close_ int nonblock_input_fd = r = fd_reopen(input_fd, O_RDONLY|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
struct termios old_termios;
|
|
||||||
if (tcgetattr(nonblock_input_fd, &old_termios) < 0)
|
|
||||||
return log_debug_errno(errno, "Failed to get terminal settings: %m");
|
|
||||||
|
|
||||||
struct termios new_termios = old_termios;
|
|
||||||
termios_disable_echo(&new_termios);
|
|
||||||
|
|
||||||
if (tcsetattr(nonblock_input_fd, TCSANOW, &new_termios) < 0)
|
|
||||||
return log_debug_errno(errno, "Failed to set new terminal settings: %m");
|
|
||||||
|
|
||||||
r = loop_write(output_fd, CSI18_Q, SIZE_MAX);
|
|
||||||
if (r < 0)
|
|
||||||
goto finish;
|
|
||||||
|
|
||||||
usec_t end = usec_add(now(CLOCK_MONOTONIC), CONSOLE_REPLY_WAIT_USEC);
|
|
||||||
char buf[STRLEN(CSI18_R1)];
|
|
||||||
size_t bytes = 0;
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
usec_t n = now(CLOCK_MONOTONIC);
|
|
||||||
if (n >= end) {
|
|
||||||
r = -EOPNOTSUPP;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
r = fd_wait_for_event(nonblock_input_fd, POLLIN, usec_sub_unsigned(end, n));
|
|
||||||
if (r < 0)
|
|
||||||
break;
|
|
||||||
if (r == 0) {
|
|
||||||
r = -EOPNOTSUPP;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* On the first read, read multiple characters, i.e. the shortest valid reply. Afterwards
|
|
||||||
* read byte by byte, since we don't want to read too much and drop characters from the input
|
|
||||||
* queue. */
|
|
||||||
ssize_t l = read(nonblock_input_fd, buf + bytes, bytes == 0 ? STRLEN(CSI18_R0) : 1);
|
|
||||||
if (l < 0) {
|
|
||||||
if (errno == EAGAIN)
|
|
||||||
continue;
|
|
||||||
r = -errno;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert((size_t) l <= sizeof(buf) - bytes);
|
|
||||||
bytes += l;
|
|
||||||
|
|
||||||
r = scan_text_area_size_response(buf, bytes, ret_rows, ret_columns);
|
|
||||||
if (r != -EAGAIN)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (bytes == sizeof(buf)) {
|
|
||||||
r = -EOPNOTSUPP; /* The response has the right prefix, but we didn't find a valid
|
|
||||||
* answer with a terminator in the allotted space. Something is
|
|
||||||
* wrong, possibly some unrelated bytes got injected into the
|
|
||||||
* answer. */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
finish:
|
|
||||||
(void) tcsetattr(nonblock_input_fd, TCSANOW, &old_termios);
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
int terminal_fix_size(int input_fd, int output_fd) {
|
int terminal_fix_size(int input_fd, int output_fd) {
|
||||||
unsigned rows, columns;
|
unsigned rows, columns;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
/* Tries to update the current terminal dimensions to the ones reported via ANSI sequences.
|
/* Tries to update the current terminal dimensions to the ones reported via ANSI sequences */
|
||||||
*
|
|
||||||
* Why bother with this? The ioctl() information is often incorrect on serial terminals (since
|
|
||||||
* there's no handshake or protocol to determine the right dimensions in RS232), but since the ANSI
|
|
||||||
* sequences are interpreted by the final terminal instead of an intermediary tty driver they should
|
|
||||||
* be more accurate.
|
|
||||||
*/
|
|
||||||
r = terminal_verify_same(input_fd, output_fd);
|
r = terminal_verify_same(input_fd, output_fd);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
@ -2658,11 +2532,6 @@ int terminal_fix_size(int input_fd, int output_fd) {
|
|||||||
if (ioctl(output_fd, TIOCGWINSZ, &ws) < 0)
|
if (ioctl(output_fd, TIOCGWINSZ, &ws) < 0)
|
||||||
return log_debug_errno(errno, "Failed to query terminal dimensions, ignoring: %m");
|
return log_debug_errno(errno, "Failed to query terminal dimensions, ignoring: %m");
|
||||||
|
|
||||||
r = terminal_get_size_by_csi18(input_fd, output_fd, &rows, &columns);
|
|
||||||
if (IN_SET(r, -EOPNOTSUPP, -EINVAL))
|
|
||||||
/* We get -EOPNOTSUPP if the query fails and -EINVAL when the received answer is invalid.
|
|
||||||
* Try the fallback method. It is more involved and moves the cursor, but seems to have wider
|
|
||||||
* support. */
|
|
||||||
r = terminal_get_size_by_dsr(input_fd, output_fd, &rows, &columns);
|
r = terminal_get_size_by_dsr(input_fd, output_fd, &rows, &columns);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_debug_errno(r, "Failed to acquire terminal dimensions via ANSI sequences, not adjusting terminal dimensions: %m");
|
return log_debug_errno(r, "Failed to acquire terminal dimensions via ANSI sequences, not adjusting terminal dimensions: %m");
|
||||||
|
|||||||
@ -150,7 +150,6 @@ void termios_disable_echo(struct termios *termios);
|
|||||||
|
|
||||||
int get_default_background_color(double *ret_red, double *ret_green, double *ret_blue);
|
int get_default_background_color(double *ret_red, double *ret_green, double *ret_blue);
|
||||||
int terminal_get_size_by_dsr(int input_fd, int output_fd, unsigned *ret_rows, unsigned *ret_columns);
|
int terminal_get_size_by_dsr(int input_fd, int output_fd, unsigned *ret_rows, unsigned *ret_columns);
|
||||||
int terminal_get_size_by_csi18(int input_fd, int output_fd, unsigned *ret_rows, unsigned *ret_columns);
|
|
||||||
int terminal_fix_size(int input_fd, int output_fd);
|
int terminal_fix_size(int input_fd, int output_fd);
|
||||||
|
|
||||||
int terminal_get_terminfo_by_dcs(int fd, char **ret_name);
|
int terminal_get_terminfo_by_dcs(int fd, char **ret_name);
|
||||||
|
|||||||
@ -1792,39 +1792,6 @@ bool in_utc_timezone(void) {
|
|||||||
return timezone == 0 && daylight == 0;
|
return timezone == 0 && daylight == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int usleep_safe(usec_t usec) {
|
|
||||||
int r;
|
|
||||||
|
|
||||||
/* usleep() takes useconds_t that is (typically?) uint32_t. Also, usleep() may only support the
|
|
||||||
* range [0, 1000000]. See usleep(3). Let's override usleep() with clock_nanosleep().
|
|
||||||
*
|
|
||||||
* ⚠️ Note we are not using plain nanosleep() here, since that operates on CLOCK_REALTIME, not
|
|
||||||
* CLOCK_MONOTONIC! */
|
|
||||||
|
|
||||||
if (usec == 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (usec == USEC_INFINITY)
|
|
||||||
return RET_NERRNO(pause());
|
|
||||||
|
|
||||||
struct timespec t;
|
|
||||||
timespec_store(&t, usec);
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
struct timespec remaining;
|
|
||||||
|
|
||||||
/* `clock_nanosleep()` does not use `errno`, but returns positive error codes. */
|
|
||||||
r = -clock_nanosleep(CLOCK_MONOTONIC, /* flags= */ 0, &t, &remaining);
|
|
||||||
if (r == -EINTR) {
|
|
||||||
/* Interrupted. Continue sleeping for the remaining time. */
|
|
||||||
t = remaining;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int time_change_fd(void) {
|
int time_change_fd(void) {
|
||||||
|
|
||||||
/* We only care for the cancellation event, hence we set the timeout to the latest possible value. */
|
/* We only care for the cancellation event, hence we set the timeout to the latest possible value. */
|
||||||
|
|||||||
@ -213,7 +213,19 @@ static inline usec_t usec_sub_signed(usec_t timestamp, int64_t delta) {
|
|||||||
return usec_sub_unsigned(timestamp, (usec_t) delta);
|
return usec_sub_unsigned(timestamp, (usec_t) delta);
|
||||||
}
|
}
|
||||||
|
|
||||||
int usleep_safe(usec_t usec);
|
static inline int usleep_safe(usec_t usec) {
|
||||||
|
/* usleep() takes useconds_t that is (typically?) uint32_t. Also, usleep() may only support the
|
||||||
|
* range [0, 1000000]. See usleep(3). Let's override usleep() with clock_nanosleep().
|
||||||
|
*
|
||||||
|
* ⚠️ Note we are not using plain nanosleep() here, since that operates on CLOCK_REALTIME, not
|
||||||
|
* CLOCK_MONOTONIC! */
|
||||||
|
|
||||||
|
if (usec == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* `clock_nanosleep()` does not use `errno`, but returns positive error codes. */
|
||||||
|
return -clock_nanosleep(CLOCK_MONOTONIC, 0, TIMESPEC_STORE(usec), NULL);
|
||||||
|
}
|
||||||
|
|
||||||
/* The last second we can format is 31. Dec 9999, 1s before midnight, because otherwise we'd enter 5 digit
|
/* The last second we can format is 31. Dec 9999, 1s before midnight, because otherwise we'd enter 5 digit
|
||||||
* year territory. However, since we want to stay away from this in all timezones we take one day off. */
|
* year territory. However, since we want to stay away from this in all timezones we take one day off. */
|
||||||
|
|||||||
@ -3338,15 +3338,17 @@ int bus_exec_context_set_transient_property(
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
if (!isempty(s)) {
|
||||||
if (!path_is_absolute(s))
|
if (!path_is_absolute(s))
|
||||||
return sd_bus_error_setf(reterr_error, SD_BUS_ERROR_INVALID_ARGS, "Path %s is not absolute", s);
|
return sd_bus_error_setf(reterr_error, SD_BUS_ERROR_INVALID_ARGS, "Path %s is not absolute", s);
|
||||||
if (!path_is_normalized(s))
|
if (!path_is_normalized(s))
|
||||||
return sd_bus_error_setf(reterr_error, SD_BUS_ERROR_INVALID_ARGS, "Path %s is not normalized", s);
|
return sd_bus_error_setf(reterr_error, SD_BUS_ERROR_INVALID_ARGS, "Path %s is not normalized", s);
|
||||||
|
}
|
||||||
|
|
||||||
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
|
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
|
||||||
|
|
||||||
if (streq(name, "StandardInputFile")) {
|
if (streq(name, "StandardInputFile")) {
|
||||||
r = free_and_strdup(&c->stdio_file[STDIN_FILENO], s);
|
r = free_and_strdup(&c->stdio_file[STDIN_FILENO], empty_to_null(s));
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
@ -3354,7 +3356,7 @@ int bus_exec_context_set_transient_property(
|
|||||||
unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "StandardInput=file:%s", s);
|
unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "StandardInput=file:%s", s);
|
||||||
|
|
||||||
} else if (STR_IN_SET(name, "StandardOutputFile", "StandardOutputFileToAppend", "StandardOutputFileToTruncate")) {
|
} else if (STR_IN_SET(name, "StandardOutputFile", "StandardOutputFileToAppend", "StandardOutputFileToTruncate")) {
|
||||||
r = free_and_strdup(&c->stdio_file[STDOUT_FILENO], s);
|
r = free_and_strdup(&c->stdio_file[STDOUT_FILENO], empty_to_null(s));
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
@ -3372,7 +3374,7 @@ int bus_exec_context_set_transient_property(
|
|||||||
} else {
|
} else {
|
||||||
assert(STR_IN_SET(name, "StandardErrorFile", "StandardErrorFileToAppend", "StandardErrorFileToTruncate"));
|
assert(STR_IN_SET(name, "StandardErrorFile", "StandardErrorFileToAppend", "StandardErrorFileToTruncate"));
|
||||||
|
|
||||||
r = free_and_strdup(&c->stdio_file[STDERR_FILENO], s);
|
r = free_and_strdup(&c->stdio_file[STDERR_FILENO], empty_to_null(s));
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
|||||||
@ -16,10 +16,11 @@ void bus_manager_send_finished(
|
|||||||
usec_t initrd_usec,
|
usec_t initrd_usec,
|
||||||
usec_t userspace_usec,
|
usec_t userspace_usec,
|
||||||
usec_t total_usec);
|
usec_t total_usec);
|
||||||
|
|
||||||
void bus_manager_send_reloading(Manager *m, bool active);
|
void bus_manager_send_reloading(Manager *m, bool active);
|
||||||
void bus_manager_send_change_signal(Manager *m);
|
void bus_manager_send_change_signal(Manager *m);
|
||||||
|
|
||||||
|
int verify_run_space_and_log(const char *message);
|
||||||
|
|
||||||
int bus_property_get_oom_policy(
|
int bus_property_get_oom_policy(
|
||||||
sd_bus *bus,
|
sd_bus *bus,
|
||||||
const char *path,
|
const char *path,
|
||||||
@ -28,7 +29,6 @@ int bus_property_get_oom_policy(
|
|||||||
sd_bus_message *reply,
|
sd_bus_message *reply,
|
||||||
void *userdata,
|
void *userdata,
|
||||||
sd_bus_error *reterr_error);
|
sd_bus_error *reterr_error);
|
||||||
|
|
||||||
int bus_property_get_emergency_action(
|
int bus_property_get_emergency_action(
|
||||||
sd_bus *bus,
|
sd_bus *bus,
|
||||||
const char *path,
|
const char *path,
|
||||||
|
|||||||
@ -308,6 +308,7 @@ static int acquire_path(const char *path, int flags, mode_t mode) {
|
|||||||
|
|
||||||
static int fixup_input(
|
static int fixup_input(
|
||||||
const ExecContext *context,
|
const ExecContext *context,
|
||||||
|
int socket_fd,
|
||||||
bool apply_tty_stdin) {
|
bool apply_tty_stdin) {
|
||||||
|
|
||||||
ExecInput std_input;
|
ExecInput std_input;
|
||||||
@ -319,12 +320,23 @@ static int fixup_input(
|
|||||||
if (exec_input_is_terminal(std_input) && !apply_tty_stdin)
|
if (exec_input_is_terminal(std_input) && !apply_tty_stdin)
|
||||||
return EXEC_INPUT_NULL;
|
return EXEC_INPUT_NULL;
|
||||||
|
|
||||||
|
if (std_input == EXEC_INPUT_SOCKET && socket_fd < 0)
|
||||||
|
return EXEC_INPUT_NULL;
|
||||||
|
|
||||||
if (std_input == EXEC_INPUT_DATA && context->stdin_data_size == 0)
|
if (std_input == EXEC_INPUT_DATA && context->stdin_data_size == 0)
|
||||||
return EXEC_INPUT_NULL;
|
return EXEC_INPUT_NULL;
|
||||||
|
|
||||||
return std_input;
|
return std_input;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int fixup_output(ExecOutput output, int socket_fd) {
|
||||||
|
|
||||||
|
if (output == EXEC_OUTPUT_SOCKET && socket_fd < 0)
|
||||||
|
return EXEC_OUTPUT_INHERIT;
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
static int setup_input(
|
static int setup_input(
|
||||||
const ExecContext *context,
|
const ExecContext *context,
|
||||||
const ExecParameters *params,
|
const ExecParameters *params,
|
||||||
@ -349,7 +361,7 @@ static int setup_input(
|
|||||||
return STDIN_FILENO;
|
return STDIN_FILENO;
|
||||||
}
|
}
|
||||||
|
|
||||||
i = fixup_input(context, params->flags & EXEC_APPLY_TTY_STDIN);
|
i = fixup_input(context, socket_fd, params->flags & EXEC_APPLY_TTY_STDIN);
|
||||||
|
|
||||||
switch (i) {
|
switch (i) {
|
||||||
|
|
||||||
@ -418,8 +430,8 @@ static int setup_input(
|
|||||||
|
|
||||||
assert(context->stdio_file[STDIN_FILENO]);
|
assert(context->stdio_file[STDIN_FILENO]);
|
||||||
|
|
||||||
rw = (context->std_output == EXEC_OUTPUT_FILE && path_equal(context->stdio_file[STDIN_FILENO], context->stdio_file[STDOUT_FILENO])) ||
|
rw = (context->std_output == EXEC_OUTPUT_FILE && streq_ptr(context->stdio_file[STDIN_FILENO], context->stdio_file[STDOUT_FILENO])) ||
|
||||||
(context->std_error == EXEC_OUTPUT_FILE && path_equal(context->stdio_file[STDIN_FILENO], context->stdio_file[STDERR_FILENO]));
|
(context->std_error == EXEC_OUTPUT_FILE && streq_ptr(context->stdio_file[STDIN_FILENO], context->stdio_file[STDERR_FILENO]));
|
||||||
|
|
||||||
fd = acquire_path(context->stdio_file[STDIN_FILENO], rw ? O_RDWR : O_RDONLY, 0666 & ~context->umask);
|
fd = acquire_path(context->stdio_file[STDIN_FILENO], rw ? O_RDWR : O_RDONLY, 0666 & ~context->umask);
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
@ -433,68 +445,30 @@ static int setup_input(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool can_inherit_stderr_from_stdout(const ExecContext *context) {
|
static bool can_inherit_stderr_from_stdout(
|
||||||
ExecOutput o, e;
|
const ExecContext *context,
|
||||||
|
ExecOutput o,
|
||||||
|
ExecOutput e) {
|
||||||
|
|
||||||
assert(context);
|
assert(context);
|
||||||
|
|
||||||
/* Returns true, if given the specified STDERR and STDOUT output we can directly dup() the stdout fd to the
|
/* Returns true, if given the specified STDERR and STDOUT output we can directly dup() the stdout fd to the
|
||||||
* stderr fd */
|
* stderr fd */
|
||||||
|
|
||||||
o = context->std_output;
|
|
||||||
e = context->std_error;
|
|
||||||
|
|
||||||
if (e == EXEC_OUTPUT_INHERIT)
|
if (e == EXEC_OUTPUT_INHERIT)
|
||||||
return true;
|
return true;
|
||||||
if (e != o)
|
if (e != o)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/* Let's not shortcut named fds here, even though we in theory can by comparing fd names, since
|
|
||||||
* we have the named_iofds array readily available, and the inherit practice would simply be duplicative. */
|
|
||||||
if (e == EXEC_OUTPUT_NAMED_FD)
|
if (e == EXEC_OUTPUT_NAMED_FD)
|
||||||
return false;
|
return streq_ptr(context->stdio_fdname[STDOUT_FILENO], context->stdio_fdname[STDERR_FILENO]);
|
||||||
|
|
||||||
if (IN_SET(e, EXEC_OUTPUT_FILE, EXEC_OUTPUT_FILE_APPEND, EXEC_OUTPUT_FILE_TRUNCATE))
|
if (IN_SET(e, EXEC_OUTPUT_FILE, EXEC_OUTPUT_FILE_APPEND, EXEC_OUTPUT_FILE_TRUNCATE))
|
||||||
return path_equal(context->stdio_file[STDOUT_FILENO], context->stdio_file[STDERR_FILENO]);
|
return streq_ptr(context->stdio_file[STDOUT_FILENO], context->stdio_file[STDERR_FILENO]);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int maybe_inherit_stdout_from_stdin(const ExecContext *context, ExecInput i) {
|
|
||||||
int r;
|
|
||||||
|
|
||||||
assert(context);
|
|
||||||
|
|
||||||
if (context->std_output != EXEC_OUTPUT_INHERIT)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* If input got downgraded, inherit the original value */
|
|
||||||
if (i == EXEC_INPUT_NULL && exec_input_is_terminal(context->std_input))
|
|
||||||
return open_terminal_as(exec_context_tty_path(context), O_WRONLY, STDOUT_FILENO);
|
|
||||||
|
|
||||||
if (!exec_input_is_inheritable(i))
|
|
||||||
goto fallback;
|
|
||||||
|
|
||||||
r = fd_is_writable(STDIN_FILENO);
|
|
||||||
if (r <= 0) {
|
|
||||||
if (r < 0)
|
|
||||||
log_warning_errno(r, "Failed to check if inherited stdin is writable for stdout, using fallback: %m");
|
|
||||||
else
|
|
||||||
log_warning("Inherited stdin is not writable for stdout, using fallback: %m");
|
|
||||||
goto fallback;
|
|
||||||
}
|
|
||||||
|
|
||||||
return RET_NERRNO(dup2(STDIN_FILENO, STDOUT_FILENO));
|
|
||||||
|
|
||||||
fallback:
|
|
||||||
/* If we are not started from PID 1 we just inherit STDOUT from our parent process. */
|
|
||||||
if (getppid() != 1)
|
|
||||||
return STDOUT_FILENO;
|
|
||||||
|
|
||||||
/* We need to open /dev/null here anew, to get the right access mode. */
|
|
||||||
return open_null_as(O_WRONLY, STDOUT_FILENO);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int setup_output(
|
static int setup_output(
|
||||||
const ExecContext *context,
|
const ExecContext *context,
|
||||||
const ExecParameters *params,
|
const ExecParameters *params,
|
||||||
@ -532,33 +506,65 @@ static int setup_output(
|
|||||||
return STDERR_FILENO;
|
return STDERR_FILENO;
|
||||||
}
|
}
|
||||||
|
|
||||||
i = fixup_input(context, params->flags & EXEC_APPLY_TTY_STDIN);
|
i = fixup_input(context, socket_fd, params->flags & EXEC_APPLY_TTY_STDIN);
|
||||||
|
o = fixup_output(context->std_output, socket_fd);
|
||||||
|
|
||||||
if (fileno == STDERR_FILENO) {
|
if (fileno == STDERR_FILENO) {
|
||||||
|
ExecOutput e;
|
||||||
|
e = fixup_output(context->std_error, socket_fd);
|
||||||
|
|
||||||
/* This expects the input and output are already set up */
|
/* This expects the input and output are already set up */
|
||||||
|
|
||||||
/* Don't change the stderr file descriptor if we inherit all
|
/* Don't change the stderr file descriptor if we inherit all
|
||||||
* the way and are not on a tty */
|
* the way and are not on a tty */
|
||||||
if (context->std_error == EXEC_OUTPUT_INHERIT &&
|
if (e == EXEC_OUTPUT_INHERIT &&
|
||||||
context->std_output == EXEC_OUTPUT_INHERIT &&
|
o == EXEC_OUTPUT_INHERIT &&
|
||||||
i == EXEC_INPUT_NULL && !exec_input_is_terminal(context->std_input) &&
|
i == EXEC_INPUT_NULL &&
|
||||||
|
!exec_input_is_terminal(context->std_input) &&
|
||||||
getppid() != 1)
|
getppid() != 1)
|
||||||
return fileno;
|
return fileno;
|
||||||
|
|
||||||
/* Duplicate from stdout if possible */
|
/* Duplicate from stdout if possible */
|
||||||
if (can_inherit_stderr_from_stdout(context))
|
if (can_inherit_stderr_from_stdout(context, o, e)) {
|
||||||
|
r = fd_is_writable(STDOUT_FILENO);
|
||||||
|
if (r <= 0) {
|
||||||
|
if (r < 0)
|
||||||
|
log_warning_errno(r, "Failed to check if inherited stdout is writable for stderr, falling back to /dev/null.");
|
||||||
|
else
|
||||||
|
log_warning("Inherited stdout is not writable for stderr, falling back to /dev/null.");
|
||||||
|
return open_null_as(O_WRONLY, fileno);
|
||||||
|
}
|
||||||
return RET_NERRNO(dup2(STDOUT_FILENO, fileno));
|
return RET_NERRNO(dup2(STDOUT_FILENO, fileno));
|
||||||
|
}
|
||||||
|
|
||||||
o = context->std_error;
|
o = e;
|
||||||
|
|
||||||
} else {
|
} else if (o == EXEC_OUTPUT_INHERIT) {
|
||||||
assert(fileno == STDOUT_FILENO);
|
/* If input got downgraded, inherit the original value */
|
||||||
|
if (i == EXEC_INPUT_NULL && exec_input_is_terminal(context->std_input))
|
||||||
|
return open_terminal_as(exec_context_tty_path(context), O_WRONLY, fileno);
|
||||||
|
|
||||||
r = maybe_inherit_stdout_from_stdin(context, i);
|
/* If the input is connected to anything that's not a /dev/null or a data fd, inherit that... */
|
||||||
if (r != 0)
|
if (!IN_SET(i, EXEC_INPUT_NULL, EXEC_INPUT_DATA)) {
|
||||||
return r;
|
r = fd_is_writable(STDIN_FILENO);
|
||||||
|
if (r <= 0) {
|
||||||
|
if (r < 0)
|
||||||
|
log_warning_errno(r, "Failed to check if inherited stdin is writable for %s, falling back to /dev/null.",
|
||||||
|
fileno == STDOUT_FILENO ? "stdout" : "stderr");
|
||||||
|
else
|
||||||
|
log_warning("Inherited stdin is not writable for %s, falling back to /dev/null.",
|
||||||
|
fileno == STDOUT_FILENO ? "stdout" : "stderr");
|
||||||
|
return open_null_as(O_WRONLY, fileno);
|
||||||
|
}
|
||||||
|
return RET_NERRNO(dup2(STDIN_FILENO, fileno));
|
||||||
|
}
|
||||||
|
|
||||||
o = context->std_output;
|
/* If we are not started from PID 1 we just inherit STDOUT from our parent process. */
|
||||||
|
if (getppid() != 1)
|
||||||
|
return fileno;
|
||||||
|
|
||||||
|
/* We need to open /dev/null here anew, to get the right access mode. */
|
||||||
|
return open_null_as(O_WRONLY, fileno);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (o) {
|
switch (o) {
|
||||||
@ -624,14 +630,15 @@ static int setup_output(
|
|||||||
case EXEC_OUTPUT_FILE:
|
case EXEC_OUTPUT_FILE:
|
||||||
case EXEC_OUTPUT_FILE_APPEND:
|
case EXEC_OUTPUT_FILE_APPEND:
|
||||||
case EXEC_OUTPUT_FILE_TRUNCATE: {
|
case EXEC_OUTPUT_FILE_TRUNCATE: {
|
||||||
|
bool rw;
|
||||||
int fd, flags;
|
int fd, flags;
|
||||||
|
|
||||||
assert(context->stdio_file[fileno]);
|
assert(context->stdio_file[fileno]);
|
||||||
|
|
||||||
/* stdin points to the same file hence setup_input() opened it as rw already?
|
rw = context->std_input == EXEC_INPUT_FILE &&
|
||||||
* Then just duplicate it. */
|
streq_ptr(context->stdio_file[fileno], context->stdio_file[STDIN_FILENO]);
|
||||||
if (context->std_input == EXEC_INPUT_FILE &&
|
|
||||||
path_equal(context->stdio_file[fileno], context->stdio_file[STDIN_FILENO]))
|
if (rw)
|
||||||
return RET_NERRNO(dup2(STDIN_FILENO, fileno));
|
return RET_NERRNO(dup2(STDIN_FILENO, fileno));
|
||||||
|
|
||||||
flags = O_WRONLY;
|
flags = O_WRONLY;
|
||||||
@ -4787,34 +4794,28 @@ static int exec_context_named_iofds(
|
|||||||
|
|
||||||
/* Note that socket fds are always placed at the beginning of the fds array, no need for extra
|
/* Note that socket fds are always placed at the beginning of the fds array, no need for extra
|
||||||
* manipulation. */
|
* manipulation. */
|
||||||
for (size_t i = 0; i < p->n_socket_fds && targets > 0; i++) {
|
for (size_t i = 0; i < p->n_socket_fds && targets > 0; i++)
|
||||||
if (named_iofds[STDIN_FILENO] < 0 &&
|
if (named_iofds[STDIN_FILENO] < 0 &&
|
||||||
c->std_input == EXEC_INPUT_NAMED_FD &&
|
c->std_input == EXEC_INPUT_NAMED_FD &&
|
||||||
streq(p->fd_names[i], stdio_fdname[STDIN_FILENO])) {
|
streq(p->fd_names[i], stdio_fdname[STDIN_FILENO])) {
|
||||||
|
|
||||||
named_iofds[STDIN_FILENO] = p->fds[i];
|
named_iofds[STDIN_FILENO] = p->fds[i];
|
||||||
targets--;
|
targets--;
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Allow stdout and stderr to use the same named fd */
|
} else if (named_iofds[STDOUT_FILENO] < 0 &&
|
||||||
|
|
||||||
if (named_iofds[STDOUT_FILENO] < 0 &&
|
|
||||||
c->std_output == EXEC_OUTPUT_NAMED_FD &&
|
c->std_output == EXEC_OUTPUT_NAMED_FD &&
|
||||||
streq(p->fd_names[i], stdio_fdname[STDOUT_FILENO])) {
|
streq(p->fd_names[i], stdio_fdname[STDOUT_FILENO])) {
|
||||||
|
|
||||||
named_iofds[STDOUT_FILENO] = p->fds[i];
|
named_iofds[STDOUT_FILENO] = p->fds[i];
|
||||||
targets--;
|
targets--;
|
||||||
}
|
|
||||||
|
|
||||||
if (named_iofds[STDERR_FILENO] < 0 &&
|
} else if (named_iofds[STDERR_FILENO] < 0 &&
|
||||||
c->std_error == EXEC_OUTPUT_NAMED_FD &&
|
c->std_error == EXEC_OUTPUT_NAMED_FD &&
|
||||||
streq(p->fd_names[i], stdio_fdname[STDERR_FILENO])) {
|
streq(p->fd_names[i], stdio_fdname[STDERR_FILENO])) {
|
||||||
|
|
||||||
named_iofds[STDERR_FILENO] = p->fds[i];
|
named_iofds[STDERR_FILENO] = p->fds[i];
|
||||||
targets--;
|
targets--;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return targets == 0 ? 0 : -ENOENT;
|
return targets == 0 ? 0 : -ENOENT;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1539,6 +1539,48 @@ static int exec_parameters_deserialize(ExecParameters *p, FILE *f, FDSet *fds) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int serialize_std_out_err(const ExecContext *c, FILE *f, int fileno) {
|
||||||
|
char *key, *value;
|
||||||
|
const char *type;
|
||||||
|
|
||||||
|
assert(c);
|
||||||
|
assert(f);
|
||||||
|
assert(IN_SET(fileno, STDOUT_FILENO, STDERR_FILENO));
|
||||||
|
|
||||||
|
type = fileno == STDOUT_FILENO ? "output" : "error";
|
||||||
|
|
||||||
|
switch (fileno == STDOUT_FILENO ? c->std_output : c->std_error) {
|
||||||
|
case EXEC_OUTPUT_NAMED_FD:
|
||||||
|
key = strjoina("exec-context-std-", type, "-fd-name");
|
||||||
|
value = c->stdio_fdname[fileno];
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EXEC_OUTPUT_FILE:
|
||||||
|
key = strjoina("exec-context-std-", type, "-file");
|
||||||
|
value = c->stdio_file[fileno];
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EXEC_OUTPUT_FILE_APPEND:
|
||||||
|
key = strjoina("exec-context-std-", type, "-file-append");
|
||||||
|
value = c->stdio_file[fileno];
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EXEC_OUTPUT_FILE_TRUNCATE:
|
||||||
|
key = strjoina("exec-context-std-", type, "-file-truncate");
|
||||||
|
value = c->stdio_file[fileno];
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return serialize_item(f, key, value);
|
||||||
|
}
|
||||||
|
|
||||||
static int exec_context_serialize(const ExecContext *c, FILE *f) {
|
static int exec_context_serialize(const ExecContext *c, FILE *f) {
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
@ -1962,10 +2004,6 @@ static int exec_context_serialize(const ExecContext *c, FILE *f) {
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = serialize_bool_elide(f, "exec-context-root-directory-as-fd", c->root_directory_as_fd);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
r = serialize_item(f, "exec-context-std-input", exec_input_to_string(c->std_input));
|
r = serialize_item(f, "exec-context-std-input", exec_input_to_string(c->std_input));
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
@ -1982,60 +2020,36 @@ static int exec_context_serialize(const ExecContext *c, FILE *f) {
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
switch (c->std_input) {
|
r = serialize_bool_elide(f, "exec-context-root-directory-as-fd", c->root_directory_as_fd);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
switch (c->std_input) {
|
||||||
case EXEC_INPUT_NAMED_FD:
|
case EXEC_INPUT_NAMED_FD:
|
||||||
r = serialize_item(f, "exec-context-std-input-fd-name", c->stdio_fdname[STDIN_FILENO]);
|
r = serialize_item(f, "exec-context-std-input-fd-name", c->stdio_fdname[STDIN_FILENO]);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EXEC_INPUT_FILE:
|
case EXEC_INPUT_FILE:
|
||||||
r = serialize_item_escaped(f, "exec-context-std-input-file", c->stdio_file[STDIN_FILENO]);
|
r = serialize_item(f, "exec-context-std-input-file", c->stdio_file[STDIN_FILENO]);
|
||||||
break;
|
if (r < 0)
|
||||||
|
return r;
|
||||||
case EXEC_INPUT_DATA:
|
|
||||||
r = serialize_item_base64mem(f, "exec-context-std-input-data", c->stdin_data, c->stdin_data_size);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
r = 0;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
r = serialize_std_out_err(c, f, STDOUT_FILENO);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
switch (c->std_output) {
|
r = serialize_std_out_err(c, f, STDERR_FILENO);
|
||||||
|
|
||||||
case EXEC_OUTPUT_NAMED_FD:
|
|
||||||
r = serialize_item(f, "exec-context-std-output-fd-name", c->stdio_fdname[STDOUT_FILENO]);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case EXEC_OUTPUT_FILE:
|
|
||||||
case EXEC_OUTPUT_FILE_APPEND:
|
|
||||||
case EXEC_OUTPUT_FILE_TRUNCATE:
|
|
||||||
r = serialize_item_escaped(f, "exec-context-std-output-file", c->stdio_file[STDOUT_FILENO]);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
r = 0;
|
|
||||||
}
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
r = serialize_item_base64mem(f, "exec-context-stdin-data", c->stdin_data, c->stdin_data_size);
|
||||||
switch (c->std_error) {
|
|
||||||
|
|
||||||
case EXEC_OUTPUT_NAMED_FD:
|
|
||||||
r = serialize_item(f, "exec-context-std-error-fd-name", c->stdio_fdname[STDERR_FILENO]);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case EXEC_OUTPUT_FILE:
|
|
||||||
case EXEC_OUTPUT_FILE_APPEND:
|
|
||||||
case EXEC_OUTPUT_FILE_TRUNCATE:
|
|
||||||
r = serialize_item_escaped(f, "exec-context-std-error-file", c->stdio_file[STDERR_FILENO]);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
r = 0;
|
|
||||||
}
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
@ -3003,11 +3017,6 @@ static int exec_context_deserialize(ExecContext *c, FILE *f) {
|
|||||||
r = deserialize_usec(val, (usec_t *)&c->timer_slack_nsec);
|
r = deserialize_usec(val, (usec_t *)&c->timer_slack_nsec);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
} else if ((val = startswith(l, "exec-context-root-directory-as-fd="))) {
|
|
||||||
r = parse_boolean(val);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
c->root_directory_as_fd = r;
|
|
||||||
} else if ((val = startswith(l, "exec-context-std-input="))) {
|
} else if ((val = startswith(l, "exec-context-std-input="))) {
|
||||||
c->std_input = exec_input_from_string(val);
|
c->std_input = exec_input_from_string(val);
|
||||||
if (c->std_input < 0)
|
if (c->std_input < 0)
|
||||||
@ -3025,13 +3034,11 @@ static int exec_context_deserialize(ExecContext *c, FILE *f) {
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
c->stdio_as_fds = r;
|
c->stdio_as_fds = r;
|
||||||
} else if ((val = startswith(l, "exec-context-std-input-data="))) {
|
} else if ((val = startswith(l, "exec-context-root-directory-as-fd="))) {
|
||||||
if (c->stdin_data)
|
r = parse_boolean(val);
|
||||||
return -EINVAL; /* duplicated */
|
|
||||||
|
|
||||||
r = unbase64mem(val, &c->stdin_data, &c->stdin_data_size);
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
c->root_directory_as_fd = r;
|
||||||
} else if ((val = startswith(l, "exec-context-std-input-fd-name="))) {
|
} else if ((val = startswith(l, "exec-context-std-input-fd-name="))) {
|
||||||
r = free_and_strdup(&c->stdio_fdname[STDIN_FILENO], val);
|
r = free_and_strdup(&c->stdio_fdname[STDIN_FILENO], val);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
@ -3045,35 +3052,40 @@ static int exec_context_deserialize(ExecContext *c, FILE *f) {
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
} else if ((val = startswith(l, "exec-context-std-input-file="))) {
|
} else if ((val = startswith(l, "exec-context-std-input-file="))) {
|
||||||
ssize_t k;
|
r = free_and_strdup(&c->stdio_file[STDIN_FILENO], val);
|
||||||
char *p;
|
if (r < 0)
|
||||||
|
return r;
|
||||||
k = cunescape(val, 0, &p);
|
|
||||||
if (k < 0)
|
|
||||||
return k;
|
|
||||||
|
|
||||||
free_and_replace(c->stdio_file[STDIN_FILENO], p);
|
|
||||||
|
|
||||||
} else if ((val = startswith(l, "exec-context-std-output-file="))) {
|
} else if ((val = startswith(l, "exec-context-std-output-file="))) {
|
||||||
ssize_t k;
|
r = free_and_strdup(&c->stdio_file[STDOUT_FILENO], val);
|
||||||
char *p;
|
if (r < 0)
|
||||||
|
return r;
|
||||||
k = cunescape(val, 0, &p);
|
} else if ((val = startswith(l, "exec-context-std-output-file-append="))) {
|
||||||
if (k < 0)
|
r = free_and_strdup(&c->stdio_file[STDOUT_FILENO], val);
|
||||||
return k;
|
if (r < 0)
|
||||||
|
return r;
|
||||||
free_and_replace(c->stdio_file[STDOUT_FILENO], p);
|
} else if ((val = startswith(l, "exec-context-std-output-file-truncate="))) {
|
||||||
|
r = free_and_strdup(&c->stdio_file[STDOUT_FILENO], val);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
} else if ((val = startswith(l, "exec-context-std-error-file="))) {
|
} else if ((val = startswith(l, "exec-context-std-error-file="))) {
|
||||||
ssize_t k;
|
r = free_and_strdup(&c->stdio_file[STDERR_FILENO], val);
|
||||||
char *p;
|
if (r < 0)
|
||||||
|
return r;
|
||||||
k = cunescape(val, 0, &p);
|
} else if ((val = startswith(l, "exec-context-std-error-file-append="))) {
|
||||||
if (k < 0)
|
r = free_and_strdup(&c->stdio_file[STDERR_FILENO], val);
|
||||||
return k;
|
if (r < 0)
|
||||||
|
return r;
|
||||||
free_and_replace(c->stdio_file[STDERR_FILENO], p);
|
} else if ((val = startswith(l, "exec-context-std-error-file-truncate="))) {
|
||||||
|
r = free_and_strdup(&c->stdio_file[STDERR_FILENO], val);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
} else if ((val = startswith(l, "exec-context-stdin-data="))) {
|
||||||
|
if (c->stdin_data)
|
||||||
|
return -EINVAL; /* duplicated */
|
||||||
|
|
||||||
|
r = unbase64mem(val, &c->stdin_data, &c->stdin_data_size);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
} else if ((val = startswith(l, "exec-context-tty-path="))) {
|
} else if ((val = startswith(l, "exec-context-tty-path="))) {
|
||||||
r = free_and_strdup(&c->tty_path, val);
|
r = free_and_strdup(&c->tty_path, val);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
|
|||||||
@ -480,16 +480,6 @@ static inline bool exec_context_has_tty(const ExecContext *context) {
|
|||||||
context->std_error == EXEC_OUTPUT_TTY;
|
context->std_error == EXEC_OUTPUT_TTY;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool exec_input_is_inheritable(ExecInput i) {
|
|
||||||
/* We assume these listed inputs refer to bidirectional streams, and hence duplicating them from
|
|
||||||
* stdin to stdout/stderr makes sense and hence allowing EXEC_OUTPUT_INHERIT makes sense, too.
|
|
||||||
* Outputs such as regular files or sealed data memfds otoh don't really make sense to be
|
|
||||||
* duplicated for both input and output at the same time (since they then would cause a feedback
|
|
||||||
* loop). */
|
|
||||||
|
|
||||||
return exec_input_is_terminal(i) || IN_SET(i, EXEC_INPUT_SOCKET, EXEC_INPUT_NAMED_FD);
|
|
||||||
}
|
|
||||||
|
|
||||||
int exec_spawn(
|
int exec_spawn(
|
||||||
Unit *unit,
|
Unit *unit,
|
||||||
ExecCommand *command,
|
ExecCommand *command,
|
||||||
|
|||||||
@ -113,7 +113,7 @@
|
|||||||
/* How many units and jobs to process of the bus queue before returning to the event loop. */
|
/* How many units and jobs to process of the bus queue before returning to the event loop. */
|
||||||
#define MANAGER_BUS_MESSAGE_BUDGET 100U
|
#define MANAGER_BUS_MESSAGE_BUDGET 100U
|
||||||
|
|
||||||
#define DEFAULT_TASKS_MAX ((const CGroupTasksMax) { 15U, 100U }) /* 15% */
|
#define DEFAULT_TASKS_MAX ((CGroupTasksMax) { 15U, 100U }) /* 15% */
|
||||||
|
|
||||||
static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata);
|
static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata);
|
||||||
static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata);
|
static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata);
|
||||||
|
|||||||
@ -808,11 +808,19 @@ static void service_fix_stdio(Service *s) {
|
|||||||
s->exec_context.stdin_data_size > 0)
|
s->exec_context.stdin_data_size > 0)
|
||||||
s->exec_context.std_input = EXEC_INPUT_DATA;
|
s->exec_context.std_input = EXEC_INPUT_DATA;
|
||||||
|
|
||||||
if (exec_input_is_inheritable(s->exec_context.std_input))
|
if (IN_SET(s->exec_context.std_input,
|
||||||
|
EXEC_INPUT_TTY,
|
||||||
|
EXEC_INPUT_TTY_FORCE,
|
||||||
|
EXEC_INPUT_TTY_FAIL,
|
||||||
|
EXEC_INPUT_SOCKET,
|
||||||
|
EXEC_INPUT_NAMED_FD))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Override EXEC_OUTPUT_INHERIT with the default stderr/stdout setting if not applicable for
|
/* We assume these listed inputs refer to bidirectional streams, and hence duplicating them from
|
||||||
* given stdin mode. */
|
* stdin to stdout/stderr makes sense and hence leaving EXEC_OUTPUT_INHERIT in place makes sense,
|
||||||
|
* too. Outputs such as regular files or sealed data memfds otoh don't really make sense to be
|
||||||
|
* duplicated for both input and output at the same time (since they then would cause a feedback
|
||||||
|
* loop), hence override EXEC_OUTPUT_INHERIT with the default stderr/stdout setting. */
|
||||||
|
|
||||||
if (s->exec_context.std_error == EXEC_OUTPUT_INHERIT &&
|
if (s->exec_context.std_error == EXEC_OUTPUT_INHERIT &&
|
||||||
s->exec_context.std_output == EXEC_OUTPUT_INHERIT)
|
s->exec_context.std_output == EXEC_OUTPUT_INHERIT)
|
||||||
|
|||||||
@ -341,7 +341,7 @@ static int on_first_event(sd_event_source *s, void *userdata) {
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
if (arg_follow && !c->has_cursor && !arg_since_set) {
|
if (arg_follow && !arg_reverse && !c->has_cursor && !arg_since_set) {
|
||||||
r = sd_journal_get_cursor(c->journal, /* ret_cursor= */ NULL);
|
r = sd_journal_get_cursor(c->journal, /* ret_cursor= */ NULL);
|
||||||
if (r == -EADDRNOTAVAIL) {
|
if (r == -EADDRNOTAVAIL) {
|
||||||
/* If we shall operate in --follow mode, and we are unable to get a cursor after
|
/* If we shall operate in --follow mode, and we are unable to get a cursor after
|
||||||
|
|||||||
@ -48,8 +48,7 @@ static int help(int argc, char *argv[], void *userdata) {
|
|||||||
"\n%5$sPerform various operations on private keys and certificates.%6$s\n"
|
"\n%5$sPerform various operations on private keys and certificates.%6$s\n"
|
||||||
"\n%3$sCommands:%4$s\n"
|
"\n%3$sCommands:%4$s\n"
|
||||||
" validate Load and validate the given certificate and private key\n"
|
" validate Load and validate the given certificate and private key\n"
|
||||||
" extract-public Extract a public key\n"
|
" public Extract a public key\n"
|
||||||
" extract-certificate Extract a certificate\n"
|
|
||||||
" pkcs7 Generate a PKCS#7 signature\n"
|
" pkcs7 Generate a PKCS#7 signature\n"
|
||||||
"\n%3$sOptions:%4$s\n"
|
"\n%3$sOptions:%4$s\n"
|
||||||
" -h --help Show this help\n"
|
" -h --help Show this help\n"
|
||||||
@ -248,7 +247,7 @@ static int verb_validate(int argc, char *argv[], void *userdata) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int verb_extract_public(int argc, char *argv[], void *userdata) {
|
static int verb_public(int argc, char *argv[], void *userdata) {
|
||||||
_cleanup_(EVP_PKEY_freep) EVP_PKEY *public_key = NULL;
|
_cleanup_(EVP_PKEY_freep) EVP_PKEY *public_key = NULL;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
@ -315,33 +314,6 @@ static int verb_extract_public(int argc, char *argv[], void *userdata) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int verb_extract_certificate(int argc, char *argv[], void *userdata) {
|
|
||||||
_cleanup_(X509_freep) X509 *certificate = NULL;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
if (!arg_certificate)
|
|
||||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "--certificate= must be specified.");
|
|
||||||
|
|
||||||
if (arg_certificate_source_type == OPENSSL_CERTIFICATE_SOURCE_FILE) {
|
|
||||||
r = parse_path_argument(arg_certificate, /* suppress_root= */ false, &arg_certificate);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
r = openssl_load_x509_certificate(
|
|
||||||
arg_certificate_source_type,
|
|
||||||
arg_certificate_source,
|
|
||||||
arg_certificate,
|
|
||||||
&certificate);
|
|
||||||
if (r < 0)
|
|
||||||
return log_error_errno(r, "Failed to load X.509 certificate from %s: %m", arg_certificate);
|
|
||||||
|
|
||||||
if (PEM_write_X509(stdout, certificate) == 0)
|
|
||||||
return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to write certificate to stdout.");
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int verb_pkcs7(int argc, char *argv[], void *userdata) {
|
static int verb_pkcs7(int argc, char *argv[], void *userdata) {
|
||||||
_cleanup_(X509_freep) X509 *certificate = NULL;
|
_cleanup_(X509_freep) X509 *certificate = NULL;
|
||||||
_cleanup_free_ char *pkcs1 = NULL;
|
_cleanup_free_ char *pkcs1 = NULL;
|
||||||
@ -429,9 +401,7 @@ static int run(int argc, char *argv[]) {
|
|||||||
static const Verb verbs[] = {
|
static const Verb verbs[] = {
|
||||||
{ "help", VERB_ANY, VERB_ANY, 0, help },
|
{ "help", VERB_ANY, VERB_ANY, 0, help },
|
||||||
{ "validate", VERB_ANY, 1, 0, verb_validate },
|
{ "validate", VERB_ANY, 1, 0, verb_validate },
|
||||||
{ "extract-public", VERB_ANY, 1, 0, verb_extract_public },
|
{ "public", VERB_ANY, 1, 0, verb_public },
|
||||||
{ "public", VERB_ANY, 1, 0, verb_extract_public }, /* Deprecated but kept for backwards compat. */
|
|
||||||
{ "extract-certificate", VERB_ANY, 1, 0, verb_extract_certificate },
|
|
||||||
{ "pkcs7", VERB_ANY, VERB_ANY, 0, verb_pkcs7 },
|
{ "pkcs7", VERB_ANY, VERB_ANY, 0, verb_pkcs7 },
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -105,7 +105,7 @@
|
|||||||
/* To do LUKS2 offline encryption, we need to keep some extra free space at the end of the partition. */
|
/* To do LUKS2 offline encryption, we need to keep some extra free space at the end of the partition. */
|
||||||
#define LUKS2_METADATA_KEEP_FREE (LUKS2_METADATA_SIZE*2ULL)
|
#define LUKS2_METADATA_KEEP_FREE (LUKS2_METADATA_SIZE*2ULL)
|
||||||
|
|
||||||
/* LUKS2 default volume key size (no integrity). */
|
/* LUKS2 volume key size. */
|
||||||
#define VOLUME_KEY_SIZE (512ULL/8ULL)
|
#define VOLUME_KEY_SIZE (512ULL/8ULL)
|
||||||
|
|
||||||
/* Use 4K as the default filesystem sector size because as long as the partitions are aligned to 4K, the
|
/* Use 4K as the default filesystem sector size because as long as the partitions are aligned to 4K, the
|
||||||
@ -266,21 +266,6 @@ typedef enum EncryptMode {
|
|||||||
_ENCRYPT_MODE_INVALID = -EINVAL,
|
_ENCRYPT_MODE_INVALID = -EINVAL,
|
||||||
} EncryptMode;
|
} EncryptMode;
|
||||||
|
|
||||||
typedef enum IntegrityMode {
|
|
||||||
INTEGRITY_OFF,
|
|
||||||
INTEGRITY_INLINE,
|
|
||||||
_INTEGRITY_MODE_MAX,
|
|
||||||
_INTEGRITY_MODE_INVALID = -EINVAL,
|
|
||||||
} IntegrityMode;
|
|
||||||
|
|
||||||
typedef enum IntegrityAlg {
|
|
||||||
INTEGRITY_ALG_HMAC_SHA1,
|
|
||||||
INTEGRITY_ALG_HMAC_SHA256,
|
|
||||||
INTEGRITY_ALG_HMAC_SHA512,
|
|
||||||
_INTEGRITY_ALG_MAX,
|
|
||||||
_INTEGRITY_ALG_INVALID = -EINVAL,
|
|
||||||
} IntegrityAlg;
|
|
||||||
|
|
||||||
typedef enum VerityMode {
|
typedef enum VerityMode {
|
||||||
VERITY_OFF,
|
VERITY_OFF,
|
||||||
VERITY_DATA,
|
VERITY_DATA,
|
||||||
@ -459,8 +444,6 @@ typedef struct Partition {
|
|||||||
struct iovec key;
|
struct iovec key;
|
||||||
Tpm2PCRValue *tpm2_hash_pcr_values;
|
Tpm2PCRValue *tpm2_hash_pcr_values;
|
||||||
size_t tpm2_n_hash_pcr_values;
|
size_t tpm2_n_hash_pcr_values;
|
||||||
IntegrityMode integrity;
|
|
||||||
IntegrityAlg integrity_alg;
|
|
||||||
VerityMode verity;
|
VerityMode verity;
|
||||||
char *verity_match_key;
|
char *verity_match_key;
|
||||||
MinimizeMode minimize;
|
MinimizeMode minimize;
|
||||||
@ -569,22 +552,6 @@ static const char *encrypt_mode_table[_ENCRYPT_MODE_MAX] = {
|
|||||||
[ENCRYPT_KEY_FILE_TPM2] = "key-file+tpm2",
|
[ENCRYPT_KEY_FILE_TPM2] = "key-file+tpm2",
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Going forward, the plan is to add two more modes:
|
|
||||||
* [INTEGRITY_DATA] = "data" (interleave data and integrity tags on the same device),
|
|
||||||
* [INTEGRITY_META] = "meta" (use a separate device for storing integrity tags).
|
|
||||||
* Also, INTEGRITY_INLINE will be using hardware sector integrity fields when used
|
|
||||||
* without encryption. */
|
|
||||||
static const char *integrity_mode_table[_INTEGRITY_MODE_MAX] = {
|
|
||||||
[INTEGRITY_OFF] = "off", /* no integrity protection */
|
|
||||||
[INTEGRITY_INLINE] = "inline", /* luks2 storage when encrypted */
|
|
||||||
};
|
|
||||||
|
|
||||||
static const char *integrity_alg_table[_INTEGRITY_ALG_MAX] = {
|
|
||||||
[INTEGRITY_ALG_HMAC_SHA1] = "hmac-sha1",
|
|
||||||
[INTEGRITY_ALG_HMAC_SHA256] = "hmac-sha256",
|
|
||||||
[INTEGRITY_ALG_HMAC_SHA512] = "hmac-sha512",
|
|
||||||
};
|
|
||||||
|
|
||||||
static const char *verity_mode_table[_VERITY_MODE_MAX] = {
|
static const char *verity_mode_table[_VERITY_MODE_MAX] = {
|
||||||
[VERITY_OFF] = "off",
|
[VERITY_OFF] = "off",
|
||||||
[VERITY_DATA] = "data",
|
[VERITY_DATA] = "data",
|
||||||
@ -617,8 +584,6 @@ static const char *progress_phase_table[_PROGRESS_PHASE_MAX] = {
|
|||||||
DEFINE_PRIVATE_STRING_TABLE_LOOKUP(empty_mode, EmptyMode);
|
DEFINE_PRIVATE_STRING_TABLE_LOOKUP(empty_mode, EmptyMode);
|
||||||
DEFINE_PRIVATE_STRING_TABLE_LOOKUP(append_mode, AppendMode);
|
DEFINE_PRIVATE_STRING_TABLE_LOOKUP(append_mode, AppendMode);
|
||||||
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_BOOLEAN(encrypt_mode, EncryptMode, ENCRYPT_KEY_FILE);
|
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_BOOLEAN(encrypt_mode, EncryptMode, ENCRYPT_KEY_FILE);
|
||||||
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_BOOLEAN(integrity_mode, IntegrityMode, INTEGRITY_INLINE);
|
|
||||||
DEFINE_PRIVATE_STRING_TABLE_LOOKUP(integrity_alg, IntegrityAlg);
|
|
||||||
DEFINE_PRIVATE_STRING_TABLE_LOOKUP(verity_mode, VerityMode);
|
DEFINE_PRIVATE_STRING_TABLE_LOOKUP(verity_mode, VerityMode);
|
||||||
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_BOOLEAN(minimize_mode, MinimizeMode, MINIMIZE_BEST);
|
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_BOOLEAN(minimize_mode, MinimizeMode, MINIMIZE_BEST);
|
||||||
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(progress_phase, ProgressPhase);
|
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(progress_phase, ProgressPhase);
|
||||||
@ -2668,9 +2633,6 @@ static int config_parse_key_file(
|
|||||||
return parse_key_file(rvalue, &partition->key);
|
return parse_key_file(rvalue, &partition->key);
|
||||||
}
|
}
|
||||||
|
|
||||||
static DEFINE_CONFIG_PARSE_ENUM_WITH_DEFAULT(config_parse_integrity, integrity_mode, IntegrityMode, INTEGRITY_OFF);
|
|
||||||
static DEFINE_CONFIG_PARSE_ENUM_WITH_DEFAULT(config_parse_integrity_alg, integrity_alg, IntegrityAlg, INTEGRITY_ALG_HMAC_SHA256);
|
|
||||||
|
|
||||||
static DEFINE_CONFIG_PARSE_ENUM_WITH_DEFAULT(config_parse_verity, verity_mode, VerityMode, VERITY_OFF);
|
static DEFINE_CONFIG_PARSE_ENUM_WITH_DEFAULT(config_parse_verity, verity_mode, VerityMode, VERITY_OFF);
|
||||||
static DEFINE_CONFIG_PARSE_ENUM_WITH_DEFAULT(config_parse_minimize, minimize_mode, MinimizeMode, MINIMIZE_OFF);
|
static DEFINE_CONFIG_PARSE_ENUM_WITH_DEFAULT(config_parse_minimize, minimize_mode, MinimizeMode, MINIMIZE_OFF);
|
||||||
|
|
||||||
@ -2825,8 +2787,6 @@ static int partition_read_definition(
|
|||||||
{ "Partition", "EncryptedVolume", config_parse_encrypted_volume, 0, p },
|
{ "Partition", "EncryptedVolume", config_parse_encrypted_volume, 0, p },
|
||||||
{ "Partition", "TPM2PCRs", config_parse_tpm2_pcrs, 0, p },
|
{ "Partition", "TPM2PCRs", config_parse_tpm2_pcrs, 0, p },
|
||||||
{ "Partition", "KeyFile", config_parse_key_file, 0, p },
|
{ "Partition", "KeyFile", config_parse_key_file, 0, p },
|
||||||
{ "Partition", "Integrity", config_parse_integrity, 0, &p->integrity },
|
|
||||||
{ "Partition", "IntegrityAlgorithm", config_parse_integrity_alg, 0, &p->integrity_alg },
|
|
||||||
{ "Partition", "Compression", config_parse_string, CONFIG_PARSE_STRING_SAFE_AND_ASCII, &p->compression },
|
{ "Partition", "Compression", config_parse_string, CONFIG_PARSE_STRING_SAFE_AND_ASCII, &p->compression },
|
||||||
{ "Partition", "CompressionLevel", config_parse_string, CONFIG_PARSE_STRING_SAFE_AND_ASCII, &p->compression_level },
|
{ "Partition", "CompressionLevel", config_parse_string, CONFIG_PARSE_STRING_SAFE_AND_ASCII, &p->compression_level },
|
||||||
{ "Partition", "SupplementFor", config_parse_string, 0, &p->supplement_for_name },
|
{ "Partition", "SupplementFor", config_parse_string, 0, &p->supplement_for_name },
|
||||||
@ -2961,10 +2921,6 @@ static int partition_read_definition(
|
|||||||
"SizeMinBytes=/SizeMaxBytes= cannot be used with Verity=%s.",
|
"SizeMinBytes=/SizeMaxBytes= cannot be used with Verity=%s.",
|
||||||
verity_mode_to_string(p->verity));
|
verity_mode_to_string(p->verity));
|
||||||
|
|
||||||
if (p->integrity == INTEGRITY_INLINE && p->encrypt == ENCRYPT_OFF)
|
|
||||||
return log_syntax(NULL, LOG_ERR, path, 1, SYNTHETIC_ERRNO(EINVAL),
|
|
||||||
"Integrity=inline requires Encrypt=.");
|
|
||||||
|
|
||||||
if (p->default_subvolume && !ordered_hashmap_contains(p->subvolumes, p->default_subvolume))
|
if (p->default_subvolume && !ordered_hashmap_contains(p->subvolumes, p->default_subvolume))
|
||||||
return log_syntax(NULL, LOG_ERR, path, 1, SYNTHETIC_ERRNO(EINVAL),
|
return log_syntax(NULL, LOG_ERR, path, 1, SYNTHETIC_ERRNO(EINVAL),
|
||||||
"DefaultSubvolume= must be one of the paths in Subvolumes=.");
|
"DefaultSubvolume= must be one of the paths in Subvolumes=.");
|
||||||
@ -5033,39 +4989,6 @@ static int partition_target_sync(Context *context, Partition *p, PartitionTarget
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* libcryptsetup uses its own names for integrity algorithms, e.g. 'hmac(sha1)' but systemd
|
|
||||||
* prefers more standardized 'hmac-sha1', do the conversion here. Default to hmac(sha256). */
|
|
||||||
static const char* dmcrypt_integrity_alg_name(Partition *p) {
|
|
||||||
if (p->integrity != INTEGRITY_INLINE)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
switch (p->integrity_alg) {
|
|
||||||
case INTEGRITY_ALG_HMAC_SHA1:
|
|
||||||
return "hmac(sha1)";
|
|
||||||
case INTEGRITY_ALG_HMAC_SHA512:
|
|
||||||
return "hmac(sha512)";
|
|
||||||
case INTEGRITY_ALG_HMAC_SHA256:
|
|
||||||
default:
|
|
||||||
return "hmac(sha256)";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Integrity puts specific limitations on the key size depending on the algorithm */
|
|
||||||
static size_t dmcrypt_proper_key_size(Partition *p) {
|
|
||||||
if (p->integrity != INTEGRITY_INLINE)
|
|
||||||
return VOLUME_KEY_SIZE;
|
|
||||||
|
|
||||||
switch (p->integrity_alg) {
|
|
||||||
case INTEGRITY_ALG_HMAC_SHA1:
|
|
||||||
return 672/8;
|
|
||||||
case INTEGRITY_ALG_HMAC_SHA512:
|
|
||||||
return 1024/8;
|
|
||||||
case INTEGRITY_ALG_HMAC_SHA256:
|
|
||||||
default:
|
|
||||||
return 768/8;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int partition_encrypt(Context *context, Partition *p, PartitionTarget *target, bool offline) {
|
static int partition_encrypt(Context *context, Partition *p, PartitionTarget *target, bool offline) {
|
||||||
#if HAVE_LIBCRYPTSETUP
|
#if HAVE_LIBCRYPTSETUP
|
||||||
#if HAVE_TPM2
|
#if HAVE_TPM2
|
||||||
@ -5074,7 +4997,6 @@ static int partition_encrypt(Context *context, Partition *p, PartitionTarget *ta
|
|||||||
_cleanup_fclose_ FILE *h = NULL;
|
_cleanup_fclose_ FILE *h = NULL;
|
||||||
_cleanup_free_ char *hp = NULL, *vol = NULL, *dm_name = NULL;
|
_cleanup_free_ char *hp = NULL, *vol = NULL, *dm_name = NULL;
|
||||||
const char *passphrase = NULL;
|
const char *passphrase = NULL;
|
||||||
const size_t volume_key_size = dmcrypt_proper_key_size(p);
|
|
||||||
size_t passphrase_size = 0;
|
size_t passphrase_size = 0;
|
||||||
const char *vt;
|
const char *vt;
|
||||||
int r;
|
int r;
|
||||||
@ -5099,7 +5021,6 @@ static int partition_encrypt(Context *context, Partition *p, PartitionTarget *ta
|
|||||||
.label = vl,
|
.label = vl,
|
||||||
.sector_size = partition_fs_sector_size(context, p),
|
.sector_size = partition_fs_sector_size(context, p),
|
||||||
.data_device = offline ? node : NULL,
|
.data_device = offline ? node : NULL,
|
||||||
.integrity = dmcrypt_integrity_alg_name(p),
|
|
||||||
};
|
};
|
||||||
struct crypt_params_reencrypt reencrypt_params = {
|
struct crypt_params_reencrypt reencrypt_params = {
|
||||||
.mode = CRYPT_REENCRYPT_ENCRYPT,
|
.mode = CRYPT_REENCRYPT_ENCRYPT,
|
||||||
@ -5111,10 +5032,6 @@ static int partition_encrypt(Context *context, Partition *p, PartitionTarget *ta
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (offline) {
|
if (offline) {
|
||||||
/* libcryptsetup does not currently support reencryption of devices with integrity profiles.*/
|
|
||||||
if (p->integrity == INTEGRITY_INLINE)
|
|
||||||
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Integrity=inline cannot be enabled in offline mode.");
|
|
||||||
|
|
||||||
r = var_tmp_dir(&vt);
|
r = var_tmp_dir(&vt);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to determine temporary files directory: %m");
|
return log_error_errno(r, "Failed to determine temporary files directory: %m");
|
||||||
@ -5167,7 +5084,7 @@ static int partition_encrypt(Context *context, Partition *p, PartitionTarget *ta
|
|||||||
"xts-plain64",
|
"xts-plain64",
|
||||||
SD_ID128_TO_UUID_STRING(p->luks_uuid),
|
SD_ID128_TO_UUID_STRING(p->luks_uuid),
|
||||||
NULL,
|
NULL,
|
||||||
/* volume_key_size= */ volume_key_size,
|
VOLUME_KEY_SIZE,
|
||||||
&luks_params);
|
&luks_params);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to LUKS2 format future partition: %m");
|
return log_error_errno(r, "Failed to LUKS2 format future partition: %m");
|
||||||
@ -5180,7 +5097,7 @@ static int partition_encrypt(Context *context, Partition *p, PartitionTarget *ta
|
|||||||
cd,
|
cd,
|
||||||
CRYPT_ANY_SLOT,
|
CRYPT_ANY_SLOT,
|
||||||
NULL,
|
NULL,
|
||||||
/* volume_key_size= */ volume_key_size,
|
VOLUME_KEY_SIZE,
|
||||||
strempty(iovec_key->iov_base),
|
strempty(iovec_key->iov_base),
|
||||||
iovec_key->iov_len);
|
iovec_key->iov_len);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
@ -5355,7 +5272,7 @@ static int partition_encrypt(Context *context, Partition *p, PartitionTarget *ta
|
|||||||
cd,
|
cd,
|
||||||
CRYPT_ANY_SLOT,
|
CRYPT_ANY_SLOT,
|
||||||
/* volume_key= */ NULL,
|
/* volume_key= */ NULL,
|
||||||
/* volume_key_size= */ volume_key_size,
|
/* volume_key_size= */ VOLUME_KEY_SIZE,
|
||||||
base64_encoded,
|
base64_encoded,
|
||||||
base64_encoded_size);
|
base64_encoded_size);
|
||||||
if (keyslot < 0)
|
if (keyslot < 0)
|
||||||
@ -5455,30 +5372,11 @@ static int partition_encrypt(Context *context, Partition *p, PartitionTarget *ta
|
|||||||
cd,
|
cd,
|
||||||
dm_name,
|
dm_name,
|
||||||
NULL,
|
NULL,
|
||||||
/* volume_key_size= */ volume_key_size,
|
VOLUME_KEY_SIZE,
|
||||||
(arg_discard && p->integrity != INTEGRITY_INLINE ? CRYPT_ACTIVATE_ALLOW_DISCARDS : 0) | CRYPT_ACTIVATE_PRIVATE);
|
(arg_discard ? CRYPT_ACTIVATE_ALLOW_DISCARDS : 0) | CRYPT_ACTIVATE_PRIVATE);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to activate LUKS superblock: %m");
|
return log_error_errno(r, "Failed to activate LUKS superblock: %m");
|
||||||
|
|
||||||
/* crypt_wipe() the whole device to avoid integrity errors upon mkfs */
|
|
||||||
if (p->integrity == INTEGRITY_INLINE) {
|
|
||||||
r = sym_crypt_wipe(
|
|
||||||
cd,
|
|
||||||
vol,
|
|
||||||
CRYPT_WIPE_ZERO,
|
|
||||||
/* offset= */ 0,
|
|
||||||
/* length= */ 0,
|
|
||||||
/* wipe_block_size= */ 1 * U64_MB,
|
|
||||||
/* flags= */ 0,
|
|
||||||
/* progress= */ NULL,
|
|
||||||
/* usrptr= */ NULL);
|
|
||||||
if (r < 0)
|
|
||||||
return log_error_errno(r, "Failed to wipe LUKS device: %m");
|
|
||||||
|
|
||||||
log_info("%s integrity protection for future partition %" PRIu64 " initialized.",
|
|
||||||
integrity_alg_to_string(p->integrity_alg), p->partno);
|
|
||||||
}
|
|
||||||
|
|
||||||
dev_fd = open(vol, O_RDWR|O_CLOEXEC|O_NOCTTY);
|
dev_fd = open(vol, O_RDWR|O_CLOEXEC|O_NOCTTY);
|
||||||
if (dev_fd < 0)
|
if (dev_fd < 0)
|
||||||
return log_error_errno(errno, "Failed to open LUKS volume '%s': %m", vol);
|
return log_error_errno(errno, "Failed to open LUKS volume '%s': %m", vol);
|
||||||
|
|||||||
@ -70,8 +70,6 @@ DLSYM_PROTOTYPE(crypt_token_set_external_path) = NULL;
|
|||||||
DLSYM_PROTOTYPE(crypt_token_status) = NULL;
|
DLSYM_PROTOTYPE(crypt_token_status) = NULL;
|
||||||
DLSYM_PROTOTYPE(crypt_volume_key_get) = NULL;
|
DLSYM_PROTOTYPE(crypt_volume_key_get) = NULL;
|
||||||
DLSYM_PROTOTYPE(crypt_volume_key_keyring) = NULL;
|
DLSYM_PROTOTYPE(crypt_volume_key_keyring) = NULL;
|
||||||
DLSYM_PROTOTYPE(crypt_wipe) = NULL;
|
|
||||||
DLSYM_PROTOTYPE(crypt_get_integrity_info) = NULL;
|
|
||||||
|
|
||||||
static void cryptsetup_log_glue(int level, const char *msg, void *usrptr) {
|
static void cryptsetup_log_glue(int level, const char *msg, void *usrptr) {
|
||||||
|
|
||||||
@ -276,9 +274,7 @@ int dlopen_cryptsetup(void) {
|
|||||||
#endif
|
#endif
|
||||||
DLSYM_ARG(crypt_token_status),
|
DLSYM_ARG(crypt_token_status),
|
||||||
DLSYM_ARG(crypt_volume_key_get),
|
DLSYM_ARG(crypt_volume_key_get),
|
||||||
DLSYM_ARG(crypt_volume_key_keyring),
|
DLSYM_ARG(crypt_volume_key_keyring));
|
||||||
DLSYM_ARG(crypt_wipe),
|
|
||||||
DLSYM_ARG(crypt_get_integrity_info));
|
|
||||||
if (r <= 0)
|
if (r <= 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
|||||||
@ -68,8 +68,6 @@ extern DLSYM_PROTOTYPE(crypt_token_set_external_path);
|
|||||||
extern DLSYM_PROTOTYPE(crypt_token_status);
|
extern DLSYM_PROTOTYPE(crypt_token_status);
|
||||||
extern DLSYM_PROTOTYPE(crypt_volume_key_get);
|
extern DLSYM_PROTOTYPE(crypt_volume_key_get);
|
||||||
extern DLSYM_PROTOTYPE(crypt_volume_key_keyring);
|
extern DLSYM_PROTOTYPE(crypt_volume_key_keyring);
|
||||||
extern DLSYM_PROTOTYPE(crypt_wipe);
|
|
||||||
extern DLSYM_PROTOTYPE(crypt_get_integrity_info);
|
|
||||||
|
|
||||||
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(struct crypt_device *, crypt_free, NULL);
|
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(struct crypt_device *, crypt_free, NULL);
|
||||||
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(struct crypt_device *, sym_crypt_free, NULL);
|
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(struct crypt_device *, sym_crypt_free, NULL);
|
||||||
|
|||||||
@ -397,114 +397,6 @@ static int image_policy_check_protection(
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* internal LUKS2 header defines */
|
|
||||||
#define LUKS2_FIXED_HDR_SIZE UINT64_C(0x1000)
|
|
||||||
#define LUKS2_MAGIC "LUKS\xba\xbe"
|
|
||||||
|
|
||||||
/* Matches the beginning of 'struct luks2_hdr_disk' from cryptsetup */
|
|
||||||
struct luks_header_incomplete {
|
|
||||||
char luks_magic[sizeof(LUKS2_MAGIC) - 1];
|
|
||||||
be16_t version;
|
|
||||||
be64_t hdr_len;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* 'integrity' information from LUKS JSON header. Currenly, only 'type' is extracted/checked. */
|
|
||||||
struct luks_integrity_data {
|
|
||||||
char *type;
|
|
||||||
};
|
|
||||||
|
|
||||||
static int integrity_information(const char *name, sd_json_variant *v, sd_json_dispatch_flags_t flags, void *userdata) {
|
|
||||||
static const sd_json_dispatch_field table[] = {
|
|
||||||
{ "type", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, offsetof(struct luks_integrity_data, type), SD_JSON_MANDATORY },
|
|
||||||
{}
|
|
||||||
};
|
|
||||||
|
|
||||||
return sd_json_dispatch(v, table, flags, userdata);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* cryptsetup needs a loop device to work with a partition which has offset/size but
|
|
||||||
* dissect may be running unpriviliged. Implement a minimal custom LUKS header parser
|
|
||||||
* checking integrity protection information. */
|
|
||||||
static int partition_is_luks2_integrity(int part_fd, uint64_t offset, uint64_t size) {
|
|
||||||
_cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
|
|
||||||
_cleanup_free_ char *json = NULL;
|
|
||||||
sd_json_variant *w;
|
|
||||||
const char *key;
|
|
||||||
struct luks_header_incomplete header;
|
|
||||||
ssize_t sz, json_len;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
assert(part_fd >= 0);
|
|
||||||
|
|
||||||
if (size < LUKS2_FIXED_HDR_SIZE) {
|
|
||||||
log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Partition is too small to contain a LUKS header.");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
sz = pread(part_fd, &header, sizeof(header), offset);
|
|
||||||
if (sz < 0)
|
|
||||||
return log_error_errno(errno, "Failed to read LUKS header.");
|
|
||||||
if (sz != sizeof(header))
|
|
||||||
return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to read LUKS header.");
|
|
||||||
|
|
||||||
if (memcmp(header.luks_magic, LUKS2_MAGIC, sizeof(header.luks_magic)) != 0)
|
|
||||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Partition's magic is not LUKS.");
|
|
||||||
|
|
||||||
if (be16toh(header.version) != 2)
|
|
||||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Unsupported LUKS header version: %" PRIu16 ".", be16toh(header.version));
|
|
||||||
|
|
||||||
if (be64toh(header.hdr_len) > size)
|
|
||||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "LUKS header length exceeds partition size.");
|
|
||||||
|
|
||||||
if (be64toh(header.hdr_len) <= LUKS2_FIXED_HDR_SIZE || offset > UINT64_MAX - be64toh(header.hdr_len))
|
|
||||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid LUKS header length: %" PRIu64 ".", be64toh(header.hdr_len));
|
|
||||||
|
|
||||||
json_len = be64toh(header.hdr_len) - LUKS2_FIXED_HDR_SIZE;
|
|
||||||
json = malloc(json_len + 1);
|
|
||||||
if (!json)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
sz = pread(part_fd, json, json_len, offset + LUKS2_FIXED_HDR_SIZE);
|
|
||||||
if (sz < 0)
|
|
||||||
return log_error_errno(errno, "Failed to read LUKS JSON header.");
|
|
||||||
if (sz != json_len)
|
|
||||||
return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to read LUKS JSON header.");
|
|
||||||
json[sz] = '\0';
|
|
||||||
|
|
||||||
r = sd_json_parse(json, /* flags = */ 0, &v, /* reterr_line = */ NULL, /* reterr_column = */ NULL);
|
|
||||||
if (r < 0)
|
|
||||||
return log_error_errno(r, "Failed to parse LUKS JSON header.");
|
|
||||||
|
|
||||||
v = sd_json_variant_by_key(v, "segments");
|
|
||||||
if (!v || !sd_json_variant_is_object(v)) {
|
|
||||||
log_debug("LUKS JSON header lacks 'segments' information, assuming no integrity.");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Verify that all segments have integrity protection */
|
|
||||||
JSON_VARIANT_OBJECT_FOREACH(key, w, v) {
|
|
||||||
struct luks_integrity_data data = {};
|
|
||||||
|
|
||||||
static const sd_json_dispatch_field dispatch_segment[] = {
|
|
||||||
{ "integrity", SD_JSON_VARIANT_OBJECT, integrity_information, 0, SD_JSON_MANDATORY },
|
|
||||||
{}
|
|
||||||
};
|
|
||||||
|
|
||||||
r = sd_json_dispatch(w, dispatch_segment, SD_JSON_ALLOW_EXTENSIONS, &data);
|
|
||||||
if (r < 0) {
|
|
||||||
log_debug("Failed to get integrity information from LUKS JSON for segment %s, assuming no integrity.", key);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We don't require a particular integrity algorithm, everything but 'none' (which shouldn't
|
|
||||||
* be there in the first place but is theoretically possible) works. */
|
|
||||||
if (streq(data.type, "none"))
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int image_policy_check_partition_flags(
|
static int image_policy_check_partition_flags(
|
||||||
const ImagePolicy *policy,
|
const ImagePolicy *policy,
|
||||||
PartitionDesignator designator,
|
PartitionDesignator designator,
|
||||||
@ -565,16 +457,7 @@ static int dissected_image_probe_filesystems(
|
|||||||
|
|
||||||
if (streq_ptr(p->fstype, "crypto_LUKS")) {
|
if (streq_ptr(p->fstype, "crypto_LUKS")) {
|
||||||
m->encrypted = true;
|
m->encrypted = true;
|
||||||
|
found_flags = PARTITION_POLICY_UNUSED|PARTITION_POLICY_ENCRYPTED; /* found this one, and its definitely encrypted */
|
||||||
if (p->mount_node_fd >= 0)
|
|
||||||
r = partition_is_luks2_integrity(p->mount_node_fd, /* offset = */ 0, /* size = */ UINT64_MAX);
|
|
||||||
else
|
|
||||||
r = partition_is_luks2_integrity(fd, p->offset, p->size);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
/* found this one, it's definitely encrypted + with or without integrity checking */
|
|
||||||
found_flags = PARTITION_POLICY_UNUSED|(r > 0 ? PARTITION_POLICY_ENCRYPTEDWITHINTEGRITY : PARTITION_POLICY_ENCRYPTED);
|
|
||||||
} else
|
} else
|
||||||
/* found it, but it's definitely not encrypted, hence mask the encrypted flag, but
|
/* found it, but it's definitely not encrypted, hence mask the encrypted flag, but
|
||||||
* set all other ways that indicate "present". */
|
* set all other ways that indicate "present". */
|
||||||
@ -1065,14 +948,8 @@ static int dissect_image(
|
|||||||
|
|
||||||
if (verity_settings_data_covers(verity, PARTITION_ROOT))
|
if (verity_settings_data_covers(verity, PARTITION_ROOT))
|
||||||
found_flags = iovec_is_set(&verity->root_hash_sig) ? PARTITION_POLICY_SIGNED : PARTITION_POLICY_VERITY;
|
found_flags = iovec_is_set(&verity->root_hash_sig) ? PARTITION_POLICY_SIGNED : PARTITION_POLICY_VERITY;
|
||||||
else if (encrypted) {
|
else
|
||||||
r = partition_is_luks2_integrity(fd, /* offset = */ 0, /* size = */ UINT64_MAX);
|
found_flags = encrypted ? PARTITION_POLICY_ENCRYPTED : PARTITION_POLICY_UNPROTECTED;
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
found_flags = r > 0 ? PARTITION_POLICY_ENCRYPTEDWITHINTEGRITY : PARTITION_POLICY_ENCRYPTED;
|
|
||||||
} else
|
|
||||||
found_flags = PARTITION_POLICY_UNPROTECTED;
|
|
||||||
|
|
||||||
r = image_policy_check_protection(policy, PARTITION_ROOT, found_flags);
|
r = image_policy_check_protection(policy, PARTITION_ROOT, found_flags);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
@ -1855,7 +1732,7 @@ static int dissect_image(
|
|||||||
/* Determine the verity protection level for this partition. */
|
/* Determine the verity protection level for this partition. */
|
||||||
PartitionPolicyFlags found_flags;
|
PartitionPolicyFlags found_flags;
|
||||||
if (m->partitions[di].found) {
|
if (m->partitions[di].found) {
|
||||||
found_flags = PARTITION_POLICY_ENCRYPTED|PARTITION_POLICY_ENCRYPTEDWITHINTEGRITY|PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_UNUSED;
|
found_flags = PARTITION_POLICY_ENCRYPTED|PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_UNUSED;
|
||||||
|
|
||||||
PartitionDesignator vi = partition_verity_hash_of(di);
|
PartitionDesignator vi = partition_verity_hash_of(di);
|
||||||
if (vi >= 0 && m->partitions[vi].found) {
|
if (vi >= 0 && m->partitions[vi].found) {
|
||||||
|
|||||||
@ -78,7 +78,7 @@ static PartitionPolicyFlags partition_policy_normalized_flags(const PartitionPol
|
|||||||
* all needs no protection, because it *is* the protection */
|
* all needs no protection, because it *is* the protection */
|
||||||
if (partition_verity_hash_to_data(policy->designator) >= 0 ||
|
if (partition_verity_hash_to_data(policy->designator) >= 0 ||
|
||||||
partition_verity_sig_to_data(policy->designator) >= 0)
|
partition_verity_sig_to_data(policy->designator) >= 0)
|
||||||
flags &= ~(PARTITION_POLICY_VERITY|PARTITION_POLICY_SIGNED|PARTITION_POLICY_ENCRYPTED|PARTITION_POLICY_ENCRYPTEDWITHINTEGRITY);
|
flags &= ~(PARTITION_POLICY_VERITY|PARTITION_POLICY_SIGNED|PARTITION_POLICY_ENCRYPTED);
|
||||||
|
|
||||||
/* if this designator has no verity concept, then mask off verity protection flags */
|
/* if this designator has no verity concept, then mask off verity protection flags */
|
||||||
if (partition_verity_hash_of(policy->designator) < 0)
|
if (partition_verity_hash_of(policy->designator) < 0)
|
||||||
@ -187,8 +187,6 @@ static PartitionPolicyFlags policy_flag_from_string_one(const char *s) {
|
|||||||
return PARTITION_POLICY_SIGNED;
|
return PARTITION_POLICY_SIGNED;
|
||||||
if (streq(s, "encrypted"))
|
if (streq(s, "encrypted"))
|
||||||
return PARTITION_POLICY_ENCRYPTED;
|
return PARTITION_POLICY_ENCRYPTED;
|
||||||
if (streq(s, "encryptedwithintegrity"))
|
|
||||||
return PARTITION_POLICY_ENCRYPTEDWITHINTEGRITY;
|
|
||||||
if (streq(s, "unprotected"))
|
if (streq(s, "unprotected"))
|
||||||
return PARTITION_POLICY_UNPROTECTED;
|
return PARTITION_POLICY_UNPROTECTED;
|
||||||
if (streq(s, "unused"))
|
if (streq(s, "unused"))
|
||||||
@ -425,8 +423,6 @@ int partition_policy_flags_to_string(PartitionPolicyFlags flags, bool simplify,
|
|||||||
l[m++] = "signed";
|
l[m++] = "signed";
|
||||||
if (flags & PARTITION_POLICY_ENCRYPTED)
|
if (flags & PARTITION_POLICY_ENCRYPTED)
|
||||||
l[m++] = "encrypted";
|
l[m++] = "encrypted";
|
||||||
if (flags & PARTITION_POLICY_ENCRYPTEDWITHINTEGRITY)
|
|
||||||
l[m++] = "encryptedwithintegrity";
|
|
||||||
if (flags & PARTITION_POLICY_UNPROTECTED)
|
if (flags & PARTITION_POLICY_UNPROTECTED)
|
||||||
l[m++] = "unprotected";
|
l[m++] = "unprotected";
|
||||||
if (flags & PARTITION_POLICY_UNUSED)
|
if (flags & PARTITION_POLICY_UNUSED)
|
||||||
@ -867,8 +863,8 @@ const ImagePolicy image_policy_sysext = {
|
|||||||
* be. */
|
* be. */
|
||||||
.n_policies = 2,
|
.n_policies = 2,
|
||||||
.policies = {
|
.policies = {
|
||||||
{ PARTITION_ROOT, PARTITION_POLICY_VERITY|PARTITION_POLICY_SIGNED|PARTITION_POLICY_ENCRYPTED|PARTITION_POLICY_ENCRYPTEDWITHINTEGRITY|PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ABSENT },
|
{ PARTITION_ROOT, PARTITION_POLICY_VERITY|PARTITION_POLICY_SIGNED|PARTITION_POLICY_ENCRYPTED|PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ABSENT },
|
||||||
{ PARTITION_USR, PARTITION_POLICY_VERITY|PARTITION_POLICY_SIGNED|PARTITION_POLICY_ENCRYPTED|PARTITION_POLICY_ENCRYPTEDWITHINTEGRITY|PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ABSENT },
|
{ PARTITION_USR, PARTITION_POLICY_VERITY|PARTITION_POLICY_SIGNED|PARTITION_POLICY_ENCRYPTED|PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ABSENT },
|
||||||
},
|
},
|
||||||
.default_flags = PARTITION_POLICY_IGNORE,
|
.default_flags = PARTITION_POLICY_IGNORE,
|
||||||
};
|
};
|
||||||
@ -888,7 +884,7 @@ const ImagePolicy image_policy_confext = {
|
|||||||
* are only interested in the /etc/ tree anyway, and that's really the only place it can be. */
|
* are only interested in the /etc/ tree anyway, and that's really the only place it can be. */
|
||||||
.n_policies = 1,
|
.n_policies = 1,
|
||||||
.policies = {
|
.policies = {
|
||||||
{ PARTITION_ROOT, PARTITION_POLICY_VERITY|PARTITION_POLICY_SIGNED|PARTITION_POLICY_ENCRYPTED|PARTITION_POLICY_ENCRYPTEDWITHINTEGRITY|PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ABSENT },
|
{ PARTITION_ROOT, PARTITION_POLICY_VERITY|PARTITION_POLICY_SIGNED|PARTITION_POLICY_ENCRYPTED|PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ABSENT },
|
||||||
},
|
},
|
||||||
.default_flags = PARTITION_POLICY_IGNORE,
|
.default_flags = PARTITION_POLICY_IGNORE,
|
||||||
};
|
};
|
||||||
@ -905,14 +901,14 @@ const ImagePolicy image_policy_container = {
|
|||||||
/* For systemd-nspawn containers we use all partitions, with the exception of swap */
|
/* For systemd-nspawn containers we use all partitions, with the exception of swap */
|
||||||
.n_policies = 8,
|
.n_policies = 8,
|
||||||
.policies = {
|
.policies = {
|
||||||
{ PARTITION_ROOT, PARTITION_POLICY_VERITY|PARTITION_POLICY_SIGNED|PARTITION_POLICY_ENCRYPTED|PARTITION_POLICY_ENCRYPTEDWITHINTEGRITY|PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ABSENT },
|
{ PARTITION_ROOT, PARTITION_POLICY_VERITY|PARTITION_POLICY_SIGNED|PARTITION_POLICY_ENCRYPTED|PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ABSENT },
|
||||||
{ PARTITION_USR, PARTITION_POLICY_VERITY|PARTITION_POLICY_SIGNED|PARTITION_POLICY_ENCRYPTED|PARTITION_POLICY_ENCRYPTEDWITHINTEGRITY|PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ABSENT },
|
{ PARTITION_USR, PARTITION_POLICY_VERITY|PARTITION_POLICY_SIGNED|PARTITION_POLICY_ENCRYPTED|PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ABSENT },
|
||||||
{ PARTITION_HOME, PARTITION_POLICY_ENCRYPTED|PARTITION_POLICY_ENCRYPTEDWITHINTEGRITY|PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ABSENT },
|
{ PARTITION_HOME, PARTITION_POLICY_ENCRYPTED|PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ABSENT },
|
||||||
{ PARTITION_SRV, PARTITION_POLICY_ENCRYPTED|PARTITION_POLICY_ENCRYPTEDWITHINTEGRITY|PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ABSENT },
|
{ PARTITION_SRV, PARTITION_POLICY_ENCRYPTED|PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ABSENT },
|
||||||
{ PARTITION_ESP, PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ABSENT },
|
{ PARTITION_ESP, PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ABSENT },
|
||||||
{ PARTITION_XBOOTLDR, PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ABSENT },
|
{ PARTITION_XBOOTLDR, PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ABSENT },
|
||||||
{ PARTITION_TMP, PARTITION_POLICY_ENCRYPTED|PARTITION_POLICY_ENCRYPTEDWITHINTEGRITY|PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ABSENT },
|
{ PARTITION_TMP, PARTITION_POLICY_ENCRYPTED|PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ABSENT },
|
||||||
{ PARTITION_VAR, PARTITION_POLICY_ENCRYPTED|PARTITION_POLICY_ENCRYPTEDWITHINTEGRITY|PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ABSENT },
|
{ PARTITION_VAR, PARTITION_POLICY_ENCRYPTED|PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ABSENT },
|
||||||
},
|
},
|
||||||
.default_flags = PARTITION_POLICY_IGNORE,
|
.default_flags = PARTITION_POLICY_IGNORE,
|
||||||
};
|
};
|
||||||
@ -921,15 +917,15 @@ const ImagePolicy image_policy_host = {
|
|||||||
/* For the host policy we basically use everything */
|
/* For the host policy we basically use everything */
|
||||||
.n_policies = 9,
|
.n_policies = 9,
|
||||||
.policies = {
|
.policies = {
|
||||||
{ PARTITION_ROOT, PARTITION_POLICY_VERITY|PARTITION_POLICY_SIGNED|PARTITION_POLICY_ENCRYPTED|PARTITION_POLICY_ENCRYPTEDWITHINTEGRITY|PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ABSENT },
|
{ PARTITION_ROOT, PARTITION_POLICY_VERITY|PARTITION_POLICY_SIGNED|PARTITION_POLICY_ENCRYPTED|PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ABSENT },
|
||||||
{ PARTITION_USR, PARTITION_POLICY_VERITY|PARTITION_POLICY_SIGNED|PARTITION_POLICY_ENCRYPTED|PARTITION_POLICY_ENCRYPTEDWITHINTEGRITY|PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ABSENT },
|
{ PARTITION_USR, PARTITION_POLICY_VERITY|PARTITION_POLICY_SIGNED|PARTITION_POLICY_ENCRYPTED|PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ABSENT },
|
||||||
{ PARTITION_HOME, PARTITION_POLICY_ENCRYPTED|PARTITION_POLICY_ENCRYPTEDWITHINTEGRITY|PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ABSENT },
|
{ PARTITION_HOME, PARTITION_POLICY_ENCRYPTED|PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ABSENT },
|
||||||
{ PARTITION_SRV, PARTITION_POLICY_ENCRYPTED|PARTITION_POLICY_ENCRYPTEDWITHINTEGRITY|PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ABSENT },
|
{ PARTITION_SRV, PARTITION_POLICY_ENCRYPTED|PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ABSENT },
|
||||||
{ PARTITION_ESP, PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ABSENT },
|
{ PARTITION_ESP, PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ABSENT },
|
||||||
{ PARTITION_XBOOTLDR, PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ABSENT },
|
{ PARTITION_XBOOTLDR, PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ABSENT },
|
||||||
{ PARTITION_SWAP, PARTITION_POLICY_ENCRYPTED|PARTITION_POLICY_ENCRYPTEDWITHINTEGRITY|PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ABSENT },
|
{ PARTITION_SWAP, PARTITION_POLICY_ENCRYPTED|PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ABSENT },
|
||||||
{ PARTITION_TMP, PARTITION_POLICY_ENCRYPTED|PARTITION_POLICY_ENCRYPTEDWITHINTEGRITY|PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ABSENT },
|
{ PARTITION_TMP, PARTITION_POLICY_ENCRYPTED|PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ABSENT },
|
||||||
{ PARTITION_VAR, PARTITION_POLICY_ENCRYPTED|PARTITION_POLICY_ENCRYPTEDWITHINTEGRITY|PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ABSENT },
|
{ PARTITION_VAR, PARTITION_POLICY_ENCRYPTED|PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ABSENT },
|
||||||
},
|
},
|
||||||
.default_flags = PARTITION_POLICY_IGNORE,
|
.default_flags = PARTITION_POLICY_IGNORE,
|
||||||
};
|
};
|
||||||
@ -938,12 +934,12 @@ const ImagePolicy image_policy_service = {
|
|||||||
/* For RootImage= in services we skip ESP/XBOOTLDR and swap */
|
/* For RootImage= in services we skip ESP/XBOOTLDR and swap */
|
||||||
.n_policies = 6,
|
.n_policies = 6,
|
||||||
.policies = {
|
.policies = {
|
||||||
{ PARTITION_ROOT, PARTITION_POLICY_VERITY|PARTITION_POLICY_SIGNED|PARTITION_POLICY_ENCRYPTED|PARTITION_POLICY_ENCRYPTEDWITHINTEGRITY|PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ABSENT },
|
{ PARTITION_ROOT, PARTITION_POLICY_VERITY|PARTITION_POLICY_SIGNED|PARTITION_POLICY_ENCRYPTED|PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ABSENT },
|
||||||
{ PARTITION_USR, PARTITION_POLICY_VERITY|PARTITION_POLICY_SIGNED|PARTITION_POLICY_ENCRYPTED|PARTITION_POLICY_ENCRYPTEDWITHINTEGRITY|PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ABSENT },
|
{ PARTITION_USR, PARTITION_POLICY_VERITY|PARTITION_POLICY_SIGNED|PARTITION_POLICY_ENCRYPTED|PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ABSENT },
|
||||||
{ PARTITION_HOME, PARTITION_POLICY_ENCRYPTED|PARTITION_POLICY_ENCRYPTEDWITHINTEGRITY|PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ABSENT },
|
{ PARTITION_HOME, PARTITION_POLICY_ENCRYPTED|PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ABSENT },
|
||||||
{ PARTITION_SRV, PARTITION_POLICY_ENCRYPTED|PARTITION_POLICY_ENCRYPTEDWITHINTEGRITY|PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ABSENT },
|
{ PARTITION_SRV, PARTITION_POLICY_ENCRYPTED|PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ABSENT },
|
||||||
{ PARTITION_TMP, PARTITION_POLICY_ENCRYPTED|PARTITION_POLICY_ENCRYPTEDWITHINTEGRITY|PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ABSENT },
|
{ PARTITION_TMP, PARTITION_POLICY_ENCRYPTED|PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ABSENT },
|
||||||
{ PARTITION_VAR, PARTITION_POLICY_ENCRYPTED|PARTITION_POLICY_ENCRYPTEDWITHINTEGRITY|PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ABSENT },
|
{ PARTITION_VAR, PARTITION_POLICY_ENCRYPTED|PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ABSENT },
|
||||||
},
|
},
|
||||||
.default_flags = PARTITION_POLICY_IGNORE,
|
.default_flags = PARTITION_POLICY_IGNORE,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -17,20 +17,19 @@ typedef enum PartitionPolicyFlags {
|
|||||||
PARTITION_POLICY_VERITY = 1 << 0, /* must exist, activate with verity (only applies to root/usr partitions) */
|
PARTITION_POLICY_VERITY = 1 << 0, /* must exist, activate with verity (only applies to root/usr partitions) */
|
||||||
PARTITION_POLICY_SIGNED = 1 << 1, /* must exist, activate with signed verity (only applies to root/usr partitions) */
|
PARTITION_POLICY_SIGNED = 1 << 1, /* must exist, activate with signed verity (only applies to root/usr partitions) */
|
||||||
PARTITION_POLICY_ENCRYPTED = 1 << 2, /* must exist, activate with LUKS encryption (applies to any data partition, but not to verity/signature partitions */
|
PARTITION_POLICY_ENCRYPTED = 1 << 2, /* must exist, activate with LUKS encryption (applies to any data partition, but not to verity/signature partitions */
|
||||||
PARTITION_POLICY_ENCRYPTEDWITHINTEGRITY = 1 << 3, /* same as PARTITION_POLICY_ENCRYPTED but also requires integrity checking */
|
PARTITION_POLICY_UNPROTECTED = 1 << 3, /* must exist, activate without encryption/verity */
|
||||||
PARTITION_POLICY_UNPROTECTED = 1 << 4, /* must exist, activate without encryption/verity */
|
PARTITION_POLICY_UNUSED = 1 << 4, /* must exist, don't use */
|
||||||
PARTITION_POLICY_UNUSED = 1 << 5, /* must exist, don't use */
|
PARTITION_POLICY_ABSENT = 1 << 5, /* must not exist */
|
||||||
PARTITION_POLICY_ABSENT = 1 << 6, /* must not exist */
|
PARTITION_POLICY_OPEN = PARTITION_POLICY_VERITY|PARTITION_POLICY_SIGNED|PARTITION_POLICY_ENCRYPTED|
|
||||||
PARTITION_POLICY_OPEN = PARTITION_POLICY_VERITY|PARTITION_POLICY_SIGNED|PARTITION_POLICY_ENCRYPTED|PARTITION_POLICY_ENCRYPTEDWITHINTEGRITY|
|
|
||||||
PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_UNUSED|PARTITION_POLICY_ABSENT,
|
PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_UNUSED|PARTITION_POLICY_ABSENT,
|
||||||
PARTITION_POLICY_IGNORE = PARTITION_POLICY_UNUSED|PARTITION_POLICY_ABSENT,
|
PARTITION_POLICY_IGNORE = PARTITION_POLICY_UNUSED|PARTITION_POLICY_ABSENT,
|
||||||
_PARTITION_POLICY_USE_MASK = PARTITION_POLICY_OPEN,
|
_PARTITION_POLICY_USE_MASK = PARTITION_POLICY_OPEN,
|
||||||
|
|
||||||
PARTITION_POLICY_READ_ONLY_OFF = 1 << 7, /* State of GPT partition flag "read-only" must be on */
|
PARTITION_POLICY_READ_ONLY_OFF = 1 << 6, /* State of GPT partition flag "read-only" must be on */
|
||||||
PARTITION_POLICY_READ_ONLY_ON = 1 << 8,
|
PARTITION_POLICY_READ_ONLY_ON = 1 << 7,
|
||||||
_PARTITION_POLICY_READ_ONLY_MASK = PARTITION_POLICY_READ_ONLY_OFF|PARTITION_POLICY_READ_ONLY_ON,
|
_PARTITION_POLICY_READ_ONLY_MASK = PARTITION_POLICY_READ_ONLY_OFF|PARTITION_POLICY_READ_ONLY_ON,
|
||||||
PARTITION_POLICY_GROWFS_OFF = 1 << 9, /* State of GPT partition flag "growfs" must be on */
|
PARTITION_POLICY_GROWFS_OFF = 1 << 8, /* State of GPT partition flag "growfs" must be on */
|
||||||
PARTITION_POLICY_GROWFS_ON = 1 << 10,
|
PARTITION_POLICY_GROWFS_ON = 1 << 9,
|
||||||
_PARTITION_POLICY_GROWFS_MASK = PARTITION_POLICY_GROWFS_OFF|PARTITION_POLICY_GROWFS_ON,
|
_PARTITION_POLICY_GROWFS_MASK = PARTITION_POLICY_GROWFS_OFF|PARTITION_POLICY_GROWFS_ON,
|
||||||
_PARTITION_POLICY_PFLAGS_MASK = _PARTITION_POLICY_READ_ONLY_MASK|_PARTITION_POLICY_GROWFS_MASK,
|
_PARTITION_POLICY_PFLAGS_MASK = _PARTITION_POLICY_READ_ONLY_MASK|_PARTITION_POLICY_GROWFS_MASK,
|
||||||
|
|
||||||
|
|||||||
@ -1763,7 +1763,7 @@ int openssl_extract_public_key(EVP_PKEY *private_key, EVP_PKEY **ret) {
|
|||||||
_cleanup_(memstream_done) MemStream m = {};
|
_cleanup_(memstream_done) MemStream m = {};
|
||||||
FILE *tf = memstream_init(&m);
|
FILE *tf = memstream_init(&m);
|
||||||
if (!tf)
|
if (!tf)
|
||||||
return -ENOMEM;
|
return log_oom();
|
||||||
|
|
||||||
if (i2d_PUBKEY_fp(tf, private_key) != 1)
|
if (i2d_PUBKEY_fp(tf, private_key) != 1)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
@ -1774,7 +1774,7 @@ int openssl_extract_public_key(EVP_PKEY *private_key, EVP_PKEY **ret) {
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
const unsigned char *t = (const unsigned char*) buf;
|
const unsigned char *t = (unsigned char*) buf;
|
||||||
if (!d2i_PUBKEY(ret, &t, len))
|
if (!d2i_PUBKEY(ret, &t, len))
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
|
|||||||
@ -13,7 +13,7 @@ typedef enum SocketAddressBindIPv6Only {
|
|||||||
|
|
||||||
const char* socket_address_bind_ipv6_only_to_string(SocketAddressBindIPv6Only b) _const_;
|
const char* socket_address_bind_ipv6_only_to_string(SocketAddressBindIPv6Only b) _const_;
|
||||||
SocketAddressBindIPv6Only socket_address_bind_ipv6_only_from_string(const char *s) _pure_;
|
SocketAddressBindIPv6Only socket_address_bind_ipv6_only_from_string(const char *s) _pure_;
|
||||||
SocketAddressBindIPv6Only socket_address_bind_ipv6_only_or_bool_from_string(const char *s) _pure_;
|
SocketAddressBindIPv6Only socket_address_bind_ipv6_only_or_bool_from_string(const char *s);
|
||||||
|
|
||||||
int socket_address_listen(
|
int socket_address_listen(
|
||||||
const SocketAddress *a,
|
const SocketAddress *a,
|
||||||
|
|||||||
@ -14,9 +14,6 @@
|
|||||||
#include "socket-util.h"
|
#include "socket-util.h"
|
||||||
#include "string-util.h"
|
#include "string-util.h"
|
||||||
#include "strv.h"
|
#include "strv.h"
|
||||||
#include "time-util.h"
|
|
||||||
|
|
||||||
#define HEADER_READ_TIMEOUT_USEC (5 * USEC_PER_SEC)
|
|
||||||
|
|
||||||
static int process_vsock_cid(unsigned cid, const char *port) {
|
static int process_vsock_cid(unsigned cid, const char *port) {
|
||||||
int r;
|
int r;
|
||||||
@ -94,125 +91,6 @@ static int process_unix(const char *path) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int skip_ok_port_res(int fd, const char *path, const char *port) {
|
|
||||||
struct timeval oldtv;
|
|
||||||
socklen_t oldtv_size = sizeof(oldtv);
|
|
||||||
if (getsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &oldtv, &oldtv_size) < 0)
|
|
||||||
return log_error_errno(errno, "Failed to get socket receive timeout for %s: %m", path);
|
|
||||||
if (oldtv_size != sizeof(oldtv))
|
|
||||||
return log_error_errno(SYNTHETIC_ERRNO(EIO), "Unexpected size of socket receive timeout for %s", path);
|
|
||||||
if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, TIMEVAL_STORE(HEADER_READ_TIMEOUT_USEC), sizeof(struct timeval)) < 0)
|
|
||||||
return log_error_errno(errno, "Failed to set socket receive timeout for %s: %m", path);
|
|
||||||
|
|
||||||
char recv_buf[STRLEN("OK 65535\n")];
|
|
||||||
size_t bytes_recv = 0, bytes_avail = 0, pos = 0;
|
|
||||||
static const char expected_prefix[] = "OK ";
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
if (pos >= bytes_avail) {
|
|
||||||
assert(bytes_recv <= bytes_avail);
|
|
||||||
if (bytes_avail >= sizeof(recv_buf)) {
|
|
||||||
/*
|
|
||||||
Full buffer means that we have peeked as many bytes as possible and not seeing the ending \n .
|
|
||||||
So the server is believed to not send OK PORT response, and we just pass out the socket to ssh client,
|
|
||||||
and let it handle the connection.
|
|
||||||
|
|
||||||
If we have not received any bytes from the socket buffer, we can safely pass out the socket,
|
|
||||||
since no change has been made to the socket buffer. Otherwise, if some bytes have been received,
|
|
||||||
the socket buffer has been changed, the only option is to give up and terminate the connection.
|
|
||||||
Similar logic applies below when we meet other kinds of unexpected responses.
|
|
||||||
*/
|
|
||||||
if (bytes_recv == 0) {
|
|
||||||
log_debug("Received too many bytes while waiting for OK PORT response from %s\n"
|
|
||||||
"Assume the multiplexer is not sending OK PORT.",
|
|
||||||
path);
|
|
||||||
goto passout_fd;
|
|
||||||
}
|
|
||||||
return log_error_errno(SYNTHETIC_ERRNO(EIO), "Received too many bytes while waiting for OK PORT response from %s", path);
|
|
||||||
}
|
|
||||||
if (bytes_avail > bytes_recv) {
|
|
||||||
/*
|
|
||||||
Discard already peeked bytes before peeking more.
|
|
||||||
|
|
||||||
XXX: We cannot use SO_RCVLOWAT to set the minimum number of bytes to be peeked to peek entire
|
|
||||||
OK PORT response at once to prevent changes to the recving buffer, because SO_RCVLOWAT
|
|
||||||
does not work on unix sockets with recv(..., MSG_PEEK). Also poll() does not help here,
|
|
||||||
because poll() returns readable as long as there is any data in the socket buffer for
|
|
||||||
unix sockets, not respecting SO_RCVLOWAT.
|
|
||||||
|
|
||||||
XXX: We could have used SO_PEEK_OFF to continously peek more data without changing the socket
|
|
||||||
receive buffer, but this fucntion breaks since Linux 4.3 due to a kernel bug, which is fixed
|
|
||||||
in Linux 6.18 commit 7bf3a476ce43 ("af_unix: Read sk_peek_offset() again after sleeping in
|
|
||||||
unix_stream_read_generic()."). It is also not possible to detect whether the kernel is
|
|
||||||
affected by this bug at runtime.
|
|
||||||
|
|
||||||
As a result, we have no other choice but to discard already peeked data here.
|
|
||||||
*/
|
|
||||||
ssize_t rlen = recv(fd, recv_buf + bytes_recv, bytes_avail - bytes_recv, /* flags= */ 0);
|
|
||||||
if (rlen < 0)
|
|
||||||
return log_error_errno(errno, "Failed to discard OK PORT response from %s: %m", path);
|
|
||||||
if ((size_t) rlen != bytes_avail - bytes_recv)
|
|
||||||
return log_error_errno(SYNTHETIC_ERRNO(EIO), "Short read while discarding OK PORT response from %s", path);
|
|
||||||
log_debug("Successfully discarded %zi bytes of response: %.*s", rlen, (int) rlen, recv_buf + bytes_recv);
|
|
||||||
bytes_recv = bytes_avail;
|
|
||||||
}
|
|
||||||
ssize_t len = recv(fd, recv_buf + bytes_avail, sizeof(recv_buf) - bytes_avail, MSG_PEEK);
|
|
||||||
if (len < 0) {
|
|
||||||
if (errno != EAGAIN)
|
|
||||||
return log_error_errno(errno, "Failed to receive OK from %s: %m", path);
|
|
||||||
if (bytes_recv == 0) {
|
|
||||||
log_debug("Timeout while waiting for OK PORT response from %s\n"
|
|
||||||
"Assume the multiplexer will not send OK PORT.",
|
|
||||||
path);
|
|
||||||
goto passout_fd;
|
|
||||||
}
|
|
||||||
return log_error_errno(SYNTHETIC_ERRNO(EIO), "Timed out to receive OK PORT from %s", path);
|
|
||||||
|
|
||||||
}
|
|
||||||
if (len == 0) {
|
|
||||||
log_debug("Connection closed while waiting for OK PORT response from %s", path);
|
|
||||||
if (bytes_recv == 0) {
|
|
||||||
log_debug("No data received, which means the connecting port is not open.");
|
|
||||||
return log_error_errno(SYNTHETIC_ERRNO(ECONNREFUSED), "Port %s on %s is not open", port, path);
|
|
||||||
}
|
|
||||||
return log_error_errno(SYNTHETIC_ERRNO(EIO), "Connection closed before full OK PORT response received from %s.", path);
|
|
||||||
}
|
|
||||||
bytes_avail += len;
|
|
||||||
}
|
|
||||||
assert(pos < bytes_avail);
|
|
||||||
if (pos < strlen(expected_prefix) && recv_buf[pos] != expected_prefix[pos]) {
|
|
||||||
if (bytes_recv == 0) {
|
|
||||||
log_debug("Received response does not start with expected OK PORT response from %s\n"
|
|
||||||
"Assume the multiplexer will not send OK PORT.",
|
|
||||||
path);
|
|
||||||
goto passout_fd;
|
|
||||||
}
|
|
||||||
return log_error_errno(SYNTHETIC_ERRNO(EIO), "Received invalid response while waiting for OK PORT from %s", path);
|
|
||||||
}
|
|
||||||
if (recv_buf[pos] == '\n') {
|
|
||||||
pos += 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
pos += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(pos <= sizeof(recv_buf));
|
|
||||||
assert(bytes_recv <= pos);
|
|
||||||
if (bytes_recv < pos) {
|
|
||||||
ssize_t len = recv(fd, recv_buf + bytes_recv, pos - bytes_recv, /* flags= */ 0);
|
|
||||||
if (len < 0)
|
|
||||||
return log_error_errno(errno, "Failed to discard OK PORT response from %s: %m", path);
|
|
||||||
if ((size_t) len != pos - bytes_recv)
|
|
||||||
return log_error_errno(SYNTHETIC_ERRNO(EIO), "Short read while discarding OK PORT response from %s", path);
|
|
||||||
log_debug("Successfully discarded response from %s: %.*s", path, (int) pos, recv_buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
passout_fd:
|
|
||||||
if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &oldtv, sizeof(oldtv)) < 0)
|
|
||||||
return log_error_errno(errno, "Failed to restore socket receive timeout for %s: %m", path);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int process_vsock_mux(const char *path, const char *port) {
|
static int process_vsock_mux(const char *path, const char *port) {
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
@ -249,10 +127,6 @@ static int process_vsock_mux(const char *path, const char *port) {
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to send CONNECT to %s:%s: %m", path, port);
|
return log_error_errno(r, "Failed to send CONNECT to %s:%s: %m", path, port);
|
||||||
|
|
||||||
r = skip_ok_port_res(fd, path, port);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
r = send_one_fd_iov(STDOUT_FILENO, fd, &iovec_nul_byte, /* iovlen= */ 1, /* flags= */ 0);
|
r = send_one_fd_iov(STDOUT_FILENO, fd, &iovec_nul_byte, /* iovlen= */ 1, /* flags= */ 0);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to send socket via STDOUT: %m");
|
return log_error_errno(r, "Failed to send socket via STDOUT: %m");
|
||||||
|
|||||||
@ -460,10 +460,6 @@ executables += [
|
|||||||
libbasic_static,
|
libbasic_static,
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
test_template + {
|
|
||||||
'sources' : files('test-sleep.c'),
|
|
||||||
'type' : 'manual',
|
|
||||||
},
|
|
||||||
test_template + {
|
test_template + {
|
||||||
'sources' : files('test-time-util.c'),
|
'sources' : files('test-time-util.c'),
|
||||||
'timeout' : 120,
|
'timeout' : 120,
|
||||||
|
|||||||
@ -99,8 +99,8 @@ TEST_RET(test_image_policy_to_string) {
|
|||||||
test_policy_equiv("~", image_policy_equiv_deny);
|
test_policy_equiv("~", image_policy_equiv_deny);
|
||||||
test_policy_equiv("=absent", image_policy_equiv_deny);
|
test_policy_equiv("=absent", image_policy_equiv_deny);
|
||||||
test_policy_equiv("=open", image_policy_equiv_allow);
|
test_policy_equiv("=open", image_policy_equiv_allow);
|
||||||
test_policy_equiv("=verity+signed+encrypted+encryptedwithintegrity+unprotected+unused+absent", image_policy_equiv_allow);
|
test_policy_equiv("=verity+signed+encrypted+unprotected+unused+absent", image_policy_equiv_allow);
|
||||||
test_policy_equiv("=signed+verity+encrypted+encryptedwithintegrity+unused+unprotected+absent", image_policy_equiv_allow);
|
test_policy_equiv("=signed+verity+encrypted+unused+unprotected+absent", image_policy_equiv_allow);
|
||||||
test_policy_equiv("=ignore", image_policy_equiv_ignore);
|
test_policy_equiv("=ignore", image_policy_equiv_ignore);
|
||||||
test_policy_equiv("=absent+unused", image_policy_equiv_ignore);
|
test_policy_equiv("=absent+unused", image_policy_equiv_ignore);
|
||||||
test_policy_equiv("=unused+absent", image_policy_equiv_ignore);
|
test_policy_equiv("=unused+absent", image_policy_equiv_ignore);
|
||||||
|
|||||||
@ -1,24 +0,0 @@
|
|||||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
|
||||||
|
|
||||||
#include "log.h"
|
|
||||||
#include "main-func.h"
|
|
||||||
#include "time-util.h"
|
|
||||||
|
|
||||||
static int run(int argc, char *argv[]) {
|
|
||||||
usec_t usec = USEC_INFINITY;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
if (argc > 1) {
|
|
||||||
r = parse_sec(argv[1], &usec);
|
|
||||||
if (r < 0)
|
|
||||||
return log_error_errno(r, "Failed to parse timespan '%s': %m", argv[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
r = usleep_safe(usec);
|
|
||||||
if (r < 0)
|
|
||||||
return log_error_errno(r, "Failed to sleep: %m");
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
DEFINE_MAIN_FUNCTION(run);
|
|
||||||
@ -172,27 +172,6 @@ TEST(get_default_background_color) {
|
|||||||
log_notice("R=%g G=%g B=%g", red, green, blue);
|
log_notice("R=%g G=%g B=%g", red, green, blue);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(terminal_get_size_by_csi18) {
|
|
||||||
unsigned rows, columns;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
usec_t n = now(CLOCK_MONOTONIC);
|
|
||||||
r = terminal_get_size_by_csi18(STDIN_FILENO, STDOUT_FILENO, &rows, &columns);
|
|
||||||
log_info("%s took %s", __func__+5,
|
|
||||||
FORMAT_TIMESPAN(usec_sub_unsigned(now(CLOCK_MONOTONIC), n), USEC_PER_MSEC));
|
|
||||||
if (r < 0)
|
|
||||||
return (void) log_notice_errno(r, "Can't get screen dimensions via CSI 18: %m");
|
|
||||||
|
|
||||||
log_notice("terminal size via CSI 18: rows=%u columns=%u", rows, columns);
|
|
||||||
|
|
||||||
struct winsize ws = {};
|
|
||||||
|
|
||||||
if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) < 0)
|
|
||||||
log_warning_errno(errno, "Can't get terminal size via ioctl, ignoring: %m");
|
|
||||||
else
|
|
||||||
log_notice("terminal size via ioctl: rows=%u columns=%u", ws.ws_row, ws.ws_col);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(terminal_get_size_by_dsr) {
|
TEST(terminal_get_size_by_dsr) {
|
||||||
unsigned rows, columns;
|
unsigned rows, columns;
|
||||||
int r;
|
int r;
|
||||||
|
|||||||
@ -1364,7 +1364,7 @@ def make_uki(opts: UkifyConfig) -> None:
|
|||||||
pcrpkey: Union[bytes, Path, None] = opts.pcrpkey
|
pcrpkey: Union[bytes, Path, None] = opts.pcrpkey
|
||||||
if pcrpkey is None:
|
if pcrpkey is None:
|
||||||
keyutil_tool = find_tool('systemd-keyutil', '/usr/lib/systemd/systemd-keyutil')
|
keyutil_tool = find_tool('systemd-keyutil', '/usr/lib/systemd/systemd-keyutil')
|
||||||
cmd = [keyutil_tool, 'extract-public']
|
cmd = [keyutil_tool, 'public']
|
||||||
|
|
||||||
if opts.pcr_public_keys and len(opts.pcr_public_keys) == 1:
|
if opts.pcr_public_keys and len(opts.pcr_public_keys) == 1:
|
||||||
# If we're using an engine or provider, the public key will be an X.509 certificate.
|
# If we're using an engine or provider, the public key will be an X.509 certificate.
|
||||||
|
|||||||
@ -63,10 +63,14 @@ exec-context-stdio-as-fds=
|
|||||||
exec-context-std-input-fd-name=
|
exec-context-std-input-fd-name=
|
||||||
exec-context-std-output-fd-name=
|
exec-context-std-output-fd-name=
|
||||||
exec-context-std-error-fd-name=
|
exec-context-std-error-fd-name=
|
||||||
exec-context-std-input-data=
|
|
||||||
exec-context-std-input-file=
|
exec-context-std-input-file=
|
||||||
exec-context-std-output-file=
|
exec-context-std-output-file=
|
||||||
|
exec-context-std-output-file-append=
|
||||||
|
exec-context-std-output-file-truncate=
|
||||||
exec-context-std-error-file=
|
exec-context-std-error-file=
|
||||||
|
exec-context-std-error-file-append=
|
||||||
|
exec-context-std-error-file-truncate=
|
||||||
|
exec-context-stdin-data=
|
||||||
exec-context-tty-path=
|
exec-context-tty-path=
|
||||||
exec-context-tty-reset=
|
exec-context-tty-reset=
|
||||||
exec-context-tty-vhangup=
|
exec-context-tty-vhangup=
|
||||||
|
|||||||
@ -75,6 +75,18 @@ class Summary:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def tools_os_release(field: str) -> str:
|
||||||
|
return subprocess.run(
|
||||||
|
[
|
||||||
|
'bash',
|
||||||
|
'-c',
|
||||||
|
f'set -eu; . /etc/os-release; echo ${field}',
|
||||||
|
],
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
text=True,
|
||||||
|
).stdout.rstrip()
|
||||||
|
|
||||||
|
|
||||||
def process_coredumps(args: argparse.Namespace, journal_file: Path) -> bool:
|
def process_coredumps(args: argparse.Namespace, journal_file: Path) -> bool:
|
||||||
# Collect executable paths of all coredumps and filter out the expected ones.
|
# Collect executable paths of all coredumps and filter out the expected ones.
|
||||||
|
|
||||||
@ -615,6 +627,16 @@ def main() -> None:
|
|||||||
*(['--', '--capability=CAP_BPF'] if not vm else []),
|
*(['--', '--capability=CAP_BPF'] if not vm else []),
|
||||||
] # fmt: skip
|
] # fmt: skip
|
||||||
|
|
||||||
|
# XXX: debug for https://github.com/systemd/systemd/issues/38240
|
||||||
|
if vm:
|
||||||
|
# Tracing is not supported in centos/fedora qemu builds
|
||||||
|
if tools_os_release('ID') in ('centos', 'fedora'):
|
||||||
|
cmd += ['--qemu-args=-d cpu_reset,guest_errors -D /dev/stderr']
|
||||||
|
else:
|
||||||
|
cmd += [
|
||||||
|
'--qemu-args=-d cpu_reset,guest_errors,trace:kvm_run_exit_system_event,trace:qemu_system_*_request -D /dev/stderr' # noqa: E501
|
||||||
|
]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
result = subprocess.run(cmd)
|
result = subprocess.run(cmd)
|
||||||
|
|
||||||
|
|||||||
@ -1,48 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
|
||||||
set -eux
|
|
||||||
set -o pipefail
|
|
||||||
|
|
||||||
defs="$(mktemp --directory "/tmp/test-repart.defs.XXXXXXXXXX")"
|
|
||||||
imgs="$(mktemp --directory "/var/tmp/test-repart.imgs.XXXXXXXXXX")"
|
|
||||||
# shellcheck disable=SC2064
|
|
||||||
trap "rm -rf '$defs' '$imgs'" RETURN
|
|
||||||
chmod 0755 "$defs"
|
|
||||||
|
|
||||||
echo "*** testcase for systemd-dissect and encrypted partitions ***"
|
|
||||||
|
|
||||||
tee "$defs/root.conf" <<EOF
|
|
||||||
[Partition]
|
|
||||||
Type=root
|
|
||||||
Format=ext4
|
|
||||||
Encrypt=key-file
|
|
||||||
Integrity=off
|
|
||||||
EOF
|
|
||||||
|
|
||||||
systemd-repart --pretty=yes \
|
|
||||||
--definitions "$defs" \
|
|
||||||
--empty=create \
|
|
||||||
--size=100M \
|
|
||||||
--dry-run=no \
|
|
||||||
--offline=no \
|
|
||||||
"$imgs/encint.img"
|
|
||||||
|
|
||||||
systemd-dissect --validate --image-policy "root=encrypted" "$imgs/encint.img"
|
|
||||||
|
|
||||||
tee "$defs/root.conf" <<EOF
|
|
||||||
[Partition]
|
|
||||||
Type=root
|
|
||||||
Format=ext4
|
|
||||||
Encrypt=key-file
|
|
||||||
Integrity=inline
|
|
||||||
EOF
|
|
||||||
|
|
||||||
systemd-repart --pretty=yes \
|
|
||||||
--definitions "$defs" \
|
|
||||||
--empty=create \
|
|
||||||
--size=100M \
|
|
||||||
--dry-run=no \
|
|
||||||
--offline=no \
|
|
||||||
"$imgs/encint_int.img"
|
|
||||||
|
|
||||||
systemd-dissect --validate --image-policy "root=encryptedwithintegrity" "$imgs/encint_int.img"
|
|
||||||
@ -1838,67 +1838,6 @@ EOF
|
|||||||
cmp "$imgs/disk1.img" "$imgs/disk3.img"
|
cmp "$imgs/disk1.img" "$imgs/disk3.img"
|
||||||
}
|
}
|
||||||
|
|
||||||
_test_luks2_integrity() {
|
|
||||||
local defs imgs output root
|
|
||||||
|
|
||||||
if [[ "$OFFLINE" != "no" ]]; then
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
defs="$(mktemp --directory "/tmp/test-repart.defs.XXXXXXXXXX")"
|
|
||||||
imgs="$(mktemp --directory "/var/tmp/test-repart.imgs.XXXXXXXXXX")"
|
|
||||||
root="$(mktemp --directory "/var/test-repart.root.XXXXXXXXXX")"
|
|
||||||
# shellcheck disable=SC2064
|
|
||||||
trap "rm -rf '$defs' '$imgs' '$root'" RETURN
|
|
||||||
chmod 0755 "$defs"
|
|
||||||
|
|
||||||
echo "*** testcase for LUKS2 integrity ***"
|
|
||||||
|
|
||||||
tee "$defs/root.conf" <<EOF
|
|
||||||
[Partition]
|
|
||||||
Type=root
|
|
||||||
Format=ext4
|
|
||||||
Encrypt=key-file
|
|
||||||
Integrity=inline
|
|
||||||
EOF
|
|
||||||
|
|
||||||
[ -n "$1" ] && echo "IntegrityAlgorithm=$1" >> "$defs/root.conf"
|
|
||||||
|
|
||||||
systemd-repart --pretty=yes \
|
|
||||||
--definitions "$defs" \
|
|
||||||
--empty=create \
|
|
||||||
--size=100M \
|
|
||||||
--seed="$seed" \
|
|
||||||
--dry-run=no \
|
|
||||||
--offline=no \
|
|
||||||
"$imgs/encint.img"
|
|
||||||
|
|
||||||
loop="$(losetup -P --show --find "$imgs/encint.img")"
|
|
||||||
udevadm wait --timeout=60 --settle "${loop:?}p1"
|
|
||||||
|
|
||||||
volume="test-repart-luksint-$RANDOM"
|
|
||||||
dmstatus="$imgs/dmsetup-$RANDOM"
|
|
||||||
|
|
||||||
touch "$imgs/empty-password"
|
|
||||||
|
|
||||||
# the expectation for hmac-sha256 is 'integrity: hmac(sha256)'
|
|
||||||
cryptsetup luksDump "${loop}p1" | grep -q "integrity: $(echo "$1" | sed -r 's/^hmac-(.*)$/hmac(\1)/')"
|
|
||||||
|
|
||||||
cryptsetup open --type=luks2 --key-file="$imgs/empty-password" "${loop}p1" "$volume"
|
|
||||||
dmsetup status > "$dmstatus"
|
|
||||||
cryptsetup close "$volume"
|
|
||||||
losetup -d "$loop"
|
|
||||||
# Check that there's a dm-integrity entry
|
|
||||||
grep -q "$volume""_dif.* integrity " "$dmstatus"
|
|
||||||
}
|
|
||||||
|
|
||||||
testcase_luks2_integrity() {
|
|
||||||
_test_luks2_integrity ""
|
|
||||||
_test_luks2_integrity "hmac-sha1"
|
|
||||||
_test_luks2_integrity "hmac-sha256"
|
|
||||||
_test_luks2_integrity "hmac-sha512"
|
|
||||||
}
|
|
||||||
|
|
||||||
OFFLINE="yes"
|
OFFLINE="yes"
|
||||||
run_testcases
|
run_testcases
|
||||||
|
|
||||||
|
|||||||
@ -1083,7 +1083,7 @@ check deny no "$name"
|
|||||||
|
|
||||||
# Let's also test the "image-policy" verb
|
# Let's also test the "image-policy" verb
|
||||||
|
|
||||||
systemd-analyze image-policy '*' 2>&1 | grep -F "Long form: =verity+signed+encrypted+encryptedwithintegrity+unprotected+unused+absent" >/dev/null
|
systemd-analyze image-policy '*' 2>&1 | grep -F "Long form: =verity+signed+encrypted+unprotected+unused+absent" >/dev/null
|
||||||
systemd-analyze image-policy '-' 2>&1 | grep -F "Long form: =unused+absent" >/dev/null
|
systemd-analyze image-policy '-' 2>&1 | grep -F "Long form: =unused+absent" >/dev/null
|
||||||
systemd-analyze image-policy 'home=encrypted:usr=verity' 2>&1 | grep -F "Long form: usr=verity:home=encrypted:=unused+absent" >/dev/null
|
systemd-analyze image-policy 'home=encrypted:usr=verity' 2>&1 | grep -F "Long form: usr=verity:home=encrypted:=unused+absent" >/dev/null
|
||||||
systemd-analyze image-policy 'home=encrypted:usr=verity' 2>&1 | grep -e '^home \+encrypted \+' >/dev/null
|
systemd-analyze image-policy 'home=encrypted:usr=verity' 2>&1 | grep -e '^home \+encrypted \+' >/dev/null
|
||||||
|
|||||||
@ -37,21 +37,14 @@ testcase_validate() {
|
|||||||
/usr/lib/systemd/systemd-keyutil validate --certificate /tmp/test.crt --private-key /tmp/test.key
|
/usr/lib/systemd/systemd-keyutil validate --certificate /tmp/test.crt --private-key /tmp/test.key
|
||||||
}
|
}
|
||||||
|
|
||||||
testcase_extract_public() {
|
testcase_public() {
|
||||||
PUBLIC="$(/usr/lib/systemd/systemd-keyutil extract-public --certificate /tmp/test.crt)"
|
PUBLIC="$(/usr/lib/systemd/systemd-keyutil public --certificate /tmp/test.crt)"
|
||||||
assert_eq "$PUBLIC" "$(openssl x509 -in /tmp/test.crt -pubkey -noout)"
|
assert_eq "$PUBLIC" "$(openssl x509 -in /tmp/test.crt -pubkey -noout)"
|
||||||
|
|
||||||
PUBLIC="$(/usr/lib/systemd/systemd-keyutil extract-public --private-key /tmp/test.key)"
|
PUBLIC="$(/usr/lib/systemd/systemd-keyutil public --private-key /tmp/test.key)"
|
||||||
assert_eq "$PUBLIC" "$(openssl x509 -in /tmp/test.crt -pubkey -noout)"
|
assert_eq "$PUBLIC" "$(openssl x509 -in /tmp/test.crt -pubkey -noout)"
|
||||||
|
|
||||||
(! /usr/lib/systemd/systemd-keyutil extract-public)
|
(! /usr/lib/systemd/systemd-keyutil public)
|
||||||
}
|
|
||||||
|
|
||||||
testcase_extract_certificate() {
|
|
||||||
CERT="$(/usr/lib/systemd/systemd-keyutil extract-certificate --certificate /tmp/test.crt)"
|
|
||||||
assert_eq "$CERT" "$(cat /tmp/test.crt)"
|
|
||||||
|
|
||||||
(! /usr/lib/systemd/systemd-keyutil extract-certificate)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
verify_pkcs7() {
|
verify_pkcs7() {
|
||||||
|
|||||||
@ -90,12 +90,16 @@ if [ -f /run/TEST-82-SOFTREBOOT.touch3 ]; then
|
|||||||
|
|
||||||
# Check that the surviving services are still around
|
# Check that the surviving services are still around
|
||||||
test "$(systemctl show -P ActiveState TEST-82-SOFTREBOOT-survive.service)" = "active"
|
test "$(systemctl show -P ActiveState TEST-82-SOFTREBOOT-survive.service)" = "active"
|
||||||
|
if [[ ! -L $(command -v sleep) ]]; then
|
||||||
test "$(systemctl show -P ActiveState TEST-82-SOFTREBOOT-survive-argv.service)" = "active"
|
test "$(systemctl show -P ActiveState TEST-82-SOFTREBOOT-survive-argv.service)" = "active"
|
||||||
|
fi
|
||||||
test "$(systemctl show -P ActiveState TEST-82-SOFTREBOOT-nosurvive-sigterm.service)" != "active"
|
test "$(systemctl show -P ActiveState TEST-82-SOFTREBOOT-nosurvive-sigterm.service)" != "active"
|
||||||
test "$(systemctl show -P ActiveState TEST-82-SOFTREBOOT-nosurvive.service)" != "active"
|
test "$(systemctl show -P ActiveState TEST-82-SOFTREBOOT-nosurvive.service)" != "active"
|
||||||
|
|
||||||
[[ ! -e /run/credentials/TEST-82-SOFTREBOOT-nosurvive.service ]]
|
[[ ! -e /run/credentials/TEST-82-SOFTREBOOT-nosurvive.service ]]
|
||||||
|
if [[ ! -L $(command -v sleep) ]]; then
|
||||||
assert_eq "$(cat /run/credentials/TEST-82-SOFTREBOOT-survive-argv.service/preserve)" "yay"
|
assert_eq "$(cat /run/credentials/TEST-82-SOFTREBOOT-survive-argv.service/preserve)" "yay"
|
||||||
|
fi
|
||||||
|
|
||||||
# There may be huge amount of pending messages in sockets. Processing them may cause journal rotation and
|
# There may be huge amount of pending messages in sockets. Processing them may cause journal rotation and
|
||||||
# removal of old archived journal files. If a journal file is removed during journalctl reading it,
|
# removal of old archived journal files. If a journal file is removed during journalctl reading it,
|
||||||
@ -130,7 +134,9 @@ elif [ -f /run/TEST-82-SOFTREBOOT.touch2 ]; then
|
|||||||
|
|
||||||
# Check that the surviving services are still around
|
# Check that the surviving services are still around
|
||||||
test "$(systemctl show -P ActiveState TEST-82-SOFTREBOOT-survive.service)" = "active"
|
test "$(systemctl show -P ActiveState TEST-82-SOFTREBOOT-survive.service)" = "active"
|
||||||
|
if [[ ! -L $(command -v sleep) ]]; then
|
||||||
test "$(systemctl show -P ActiveState TEST-82-SOFTREBOOT-survive-argv.service)" = "active"
|
test "$(systemctl show -P ActiveState TEST-82-SOFTREBOOT-survive-argv.service)" = "active"
|
||||||
|
fi
|
||||||
test "$(systemctl show -P ActiveState TEST-82-SOFTREBOOT-nosurvive-sigterm.service)" != "active"
|
test "$(systemctl show -P ActiveState TEST-82-SOFTREBOOT-nosurvive-sigterm.service)" != "active"
|
||||||
test "$(systemctl show -P ActiveState TEST-82-SOFTREBOOT-nosurvive.service)" != "active"
|
test "$(systemctl show -P ActiveState TEST-82-SOFTREBOOT-nosurvive.service)" != "active"
|
||||||
|
|
||||||
@ -186,7 +192,9 @@ elif [ -f /run/TEST-82-SOFTREBOOT.touch ]; then
|
|||||||
|
|
||||||
# Check that the surviving services are still around
|
# Check that the surviving services are still around
|
||||||
test "$(systemctl show -P ActiveState TEST-82-SOFTREBOOT-survive.service)" = "active"
|
test "$(systemctl show -P ActiveState TEST-82-SOFTREBOOT-survive.service)" = "active"
|
||||||
|
if [[ ! -L $(command -v sleep) ]]; then
|
||||||
test "$(systemctl show -P ActiveState TEST-82-SOFTREBOOT-survive-argv.service)" = "active"
|
test "$(systemctl show -P ActiveState TEST-82-SOFTREBOOT-survive-argv.service)" = "active"
|
||||||
|
fi
|
||||||
test "$(systemctl show -P ActiveState TEST-82-SOFTREBOOT-nosurvive-sigterm.service)" != "active"
|
test "$(systemctl show -P ActiveState TEST-82-SOFTREBOOT-nosurvive-sigterm.service)" != "active"
|
||||||
test "$(systemctl show -P ActiveState TEST-82-SOFTREBOOT-nosurvive.service)" != "active"
|
test "$(systemctl show -P ActiveState TEST-82-SOFTREBOOT-nosurvive.service)" != "active"
|
||||||
|
|
||||||
@ -253,9 +261,7 @@ EOF
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
systemd-notify --ready
|
systemd-notify --ready
|
||||||
rm "$survive_argv"
|
rm "$survive_argv"
|
||||||
# Here, we use our own sleep implementation, to support coreutils built with
|
exec -a @sleep sleep infinity
|
||||||
# --enable-single-binary=symlinks, in that case we cannot rename COMM of sleep command.
|
|
||||||
exec -a @sleep /usr/lib/systemd/tests/unit-tests/manual/test-sleep infinity
|
|
||||||
EOF
|
EOF
|
||||||
chmod +x "$survive_argv"
|
chmod +x "$survive_argv"
|
||||||
# This sets DefaultDependencies=no so that they remain running until the very end, and
|
# This sets DefaultDependencies=no so that they remain running until the very end, and
|
||||||
@ -276,6 +282,7 @@ EOF
|
|||||||
# soft reboots due to journald being temporarily stopped.
|
# soft reboots due to journald being temporarily stopped.
|
||||||
# Note, when coreutils is built with --enable-single-binary=symlinks, unfortunately we cannot freely rename
|
# Note, when coreutils is built with --enable-single-binary=symlinks, unfortunately we cannot freely rename
|
||||||
# sleep command, hence we cannot test the feature.
|
# sleep command, hence we cannot test the feature.
|
||||||
|
if [[ ! -L $(command -v sleep) ]]; then
|
||||||
systemd-run --service-type=notify --unit=TEST-82-SOFTREBOOT-survive-argv.service \
|
systemd-run --service-type=notify --unit=TEST-82-SOFTREBOOT-survive-argv.service \
|
||||||
--property SurviveFinalKillSignal=no \
|
--property SurviveFinalKillSignal=no \
|
||||||
--property IgnoreOnIsolate=yes \
|
--property IgnoreOnIsolate=yes \
|
||||||
@ -285,6 +292,7 @@ EOF
|
|||||||
--property "Before=reboot.target kexec.target poweroff.target halt.target emergency.target rescue.target" \
|
--property "Before=reboot.target kexec.target poweroff.target halt.target emergency.target rescue.target" \
|
||||||
--property SetCredential=preserve:yay \
|
--property SetCredential=preserve:yay \
|
||||||
"$survive_argv"
|
"$survive_argv"
|
||||||
|
fi
|
||||||
# shellcheck disable=SC2016
|
# shellcheck disable=SC2016
|
||||||
systemd-run --service-type=exec --unit=TEST-82-SOFTREBOOT-survive.service \
|
systemd-run --service-type=exec --unit=TEST-82-SOFTREBOOT-survive.service \
|
||||||
--property TemporaryFileSystem="/run /tmp /var" \
|
--property TemporaryFileSystem="/run /tmp /var" \
|
||||||
|
|||||||
@ -6,6 +6,11 @@ set -o pipefail
|
|||||||
# shellcheck source=test/units/util.sh
|
# shellcheck source=test/units/util.sh
|
||||||
. "$(dirname "$0")"/util.sh
|
. "$(dirname "$0")"/util.sh
|
||||||
|
|
||||||
|
if [[ -L $(command -v sleep) ]]; then
|
||||||
|
# coreutils is built with --enable-single-binary=symlinks, and we cannot rename it.
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
# Make sure the binary name fits into 15 characters
|
# Make sure the binary name fits into 15 characters
|
||||||
CORE_TEST_BIN="/tmp/test-dump"
|
CORE_TEST_BIN="/tmp/test-dump"
|
||||||
CORE_TEST_UNPRIV_BIN="/tmp/test-usr-dump"
|
CORE_TEST_UNPRIV_BIN="/tmp/test-usr-dump"
|
||||||
@ -30,8 +35,8 @@ sysctl kernel.core_pattern | grep systemd-coredump
|
|||||||
|
|
||||||
# Prepare "fake" binaries for coredumps, so we can properly exercise
|
# Prepare "fake" binaries for coredumps, so we can properly exercise
|
||||||
# the matching stuff too
|
# the matching stuff too
|
||||||
cp -vf /usr/lib/systemd/tests/unit-tests/manual/test-sleep "${CORE_TEST_BIN:?}"
|
cp -vf /bin/sleep "${CORE_TEST_BIN:?}"
|
||||||
cp -vf /usr/lib/systemd/tests/unit-tests/manual/test-sleep "${CORE_TEST_UNPRIV_BIN:?}"
|
cp -vf /bin/sleep "${CORE_TEST_UNPRIV_BIN:?}"
|
||||||
# Simple script that spawns given "fake" binary and then kills it with
|
# Simple script that spawns given "fake" binary and then kills it with
|
||||||
# given signal
|
# given signal
|
||||||
cat >"${MAKE_DUMP_SCRIPT:?}" <<\EOF
|
cat >"${MAKE_DUMP_SCRIPT:?}" <<\EOF
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user