Compare commits

...

24 Commits

Author SHA1 Message Date
Lennart Poettering b7142c64a1
Merge 4c9769353e into bbec1c87d3 2024-11-26 10:39:15 -08:00
gerblesh bbec1c87d3 sysext: set SELinux context for hierarchies and workdir 2024-11-26 17:47:32 +00:00
Yu Watanabe f29a07f3fc man: several more assorted fixes
Continuation of 4ebbb5bfe8.
Closes #35307.
2024-11-26 17:28:14 +01:00
Luca Boccassi 0566bd9643
machine: increase timeouts in attempt to fix #35115 (#35117)
An attempt to fix https://github.com/systemd/systemd/issues/35115
2024-11-26 16:12:56 +00:00
Lennart Poettering 7b4b3a8f7b sd-varlink: fix bug when enqueuing messages with fds asynchronously
When determining the poll events to wait for we need to take the queue
of pending messages that carry fds into account. Otherwise we might end
up not waking up if such an fd-carrying message is enqueued
asynchronously (i.e. not from a dispatch callback).
2024-11-26 16:06:53 +00:00
Winterhuman 5bed97dd57
man/systemd-system.conf: Correct "struct" to "strict" (#35364) 2024-11-26 22:41:49 +09:00
Luca Boccassi c4d7a13c06 cryptsetup: convert pkcs11/fido2 to iovec for key handling
key-data might be NULL. Fixes crash:

0  0x0000559c62120530 in attach_luks_or_plain_or_bitlk (cd=0x559c6b192830, name=0x7ffd57981dc4 "root", token_type=TOKEN_FIDO2, key_file=0x0, key_data=0x0, passwords=0x0, flags=524296, until=0)
    at ../src/cryptsetup/cryptsetup.c:2234
        pass_volume_key = false
        r = 1469577760
        __func__ = '\000' <repeats 29 times>
1  0x0000559c6212279c in run (argc=6, argv=0x7ffd5797fe98) at ../src/cryptsetup/cryptsetup.c:2597
        discovered_key_data = {iov_base = 0x0, iov_len = 0}
        key_data = 0x0
        token_type = TOKEN_FIDO2
        destroy_key_file = 0x0
        flags = 524296
        until = 0
        passphrase_type = PASSPHRASE_NONE
        volume = 0x7ffd57981dc4 "root"
        source = 0x7ffd57981dc9 "/dev/disk/by-uuid/8372fb39-9ba4-461a-a618-07dcaae66280"
        status = CRYPT_INACTIVE
        tries = 0
        key_file = 0x0
        config = 0x7ffd57981e05 "luks,discard,fido2-device=auto,x-initrd.attach"
        use_cached_passphrase = true
        try_discover_key = true
        discovered_key_fn = 0x7ffd5797fa70 "root.key"
        passwords = 0x0
        cd = 0x559c6b192830
        verb = 0x7ffd57981dbd "attach"
        r = 0
        __func__ = "\000\000\000"
2  0x0000559c621231e6 in main (argc=6, argv=0x7ffd5797fe98) at ../src/cryptsetup/cryptsetup.c:2674
        r = 32553
        __func__ = "\000\000\000\000"

Follow-up for 53b6c99018
2024-11-26 22:04:24 +09:00
Abderrahim Kitouni 0ae6f4843e updatectl: fix DBus method signature for SetFeatureEnabled
The signature was changed to 'sit' in sysupdated during review, but updatectl
kept using 'sbt'
2024-11-26 22:03:41 +09:00
Yu Watanabe 1ea1a79aa1 Revert "Revert "man: use MIT-0 license for example codes in daemon(7)""
This reverts commit 7a9d0abe4d.
2024-11-26 12:26:10 +01:00
Luca Boccassi 7a9d0abe4d Revert "man: use MIT-0 license for example codes in daemon(7)"
This reverts commit 6046cc3660.
2024-11-26 19:47:21 +09:00
Yu Watanabe 6046cc3660 man: use MIT-0 license for example codes in daemon(7)
This page contains many short example codes. I do not think we should
add SPDX-License-Identifier for all codes.

Closes #35356.
2024-11-26 11:12:08 +01:00
Ivan Kruglov 3aa3f130c1 machine: add debug for systemd-nspawn@.service 2024-11-19 19:12:32 +01:00
Ivan Kruglov df18408ac6 machine: increase timeouts in attempt to fix #35115 2024-11-19 18:04:27 +01:00
Lennart Poettering 4c9769353e doc: add OSC 300819 spec 2024-11-19 00:09:32 +01:00
Lennart Poettering b16c6b0c08 run: generate OSC context sequence in run0/system-run 2024-11-18 23:50:53 +01:00
Lennart Poettering a48ae38ea3 machinectl: add OSC context support to login/shell commands 2024-11-18 23:50:53 +01:00
Lennart Poettering 3722a71a87 vmspawn: generate vm context OSC 2024-11-18 23:50:53 +01:00
Lennart Poettering 805495ade2 nspawn: output context OSC 2024-11-18 23:50:53 +01:00
Lennart Poettering 03d8af8da4 pid1: issue boot context issue at boot 2024-11-18 23:50:52 +01:00
Lennart Poettering 9ed47d39d9 osc-util: add helpers for writing OSC context events 2024-11-18 23:50:52 +01:00
Lennart Poettering 462baeb410 escape: make 'bad' parameter optional 2024-11-18 23:50:52 +01:00
Lennart Poettering 420b74654d hexdump: if size is SIZE_MAX, use strlen()
Similar how we do this as various places: if SIZE_MAX is specified as
size determine the size automatically via strlen().
2024-11-18 23:50:52 +01:00
Lennart Poettering b56421e0dc random-util: include pidfdid in fallback RNG buffer
This doesn't make the RNG cryptographic strength, but if we have it
easily accessible, why not include the pidfd id. It is after all not
vulnerable to reuse.
2024-11-18 23:50:52 +01:00
Lennart Poettering 221d6e54c6 process-util: add helper for getting our own pidfdid 2024-11-18 23:50:52 +01:00
36 changed files with 900 additions and 64 deletions

283
docs/OSC-CONTEXT.md Normal file
View File

@ -0,0 +1,283 @@
---
title: OSC 300819: Hierarchial Context Signalling
category: Interfaces
layout: default
SPDX-License-Identifier: LGPL-2.1-or-later
---
# OSC 300819: Hierarchial Context Signalling
A terminal connects a user with programs. Control of the program side of
terminals is typically passed around to various different components while the
user is active: a shell might pass control to a process it invokes. If that
process is `run0` then primary control is passed to the privileged session of
the target user. If `systemd-nspawn` is invoked to start a container primary
controls is passed to that container, and so on.
A terminal emulator might be interested to know which component is currently is
in primary control of the program side of a terminal. OSC 3000910 is a
mechanism to inform it about such contexts. Each component taking over control
can inform the terminal emulators that a new context begins now, and then use
the terminal or pass control down to further apps, which can introduce
contexts. Each context may carry various discriptive metadata fields.
## Status
This OS is invented by systemd. Currently, no terminal application is known
that consumes these sequences.
## Usecases
Terminal emulators can use hierarchial context information:
1. To introduce markers/bookmarks in the output that the user can jump between.
2. To visually identify output from different contexts. For example the
background can be tinted in a reddish tone when privileges are acquired, and
similar.
3. Meta information on specific output can be shown in a tooltip or similar
4. Programs (and all subcontexts) can be killed by right-clicking on the output
they generate.
5. Failed commands or aborted sessions can be marked requesting use attention.
## Context Types
There are various types of contexts defined by this specification:
1. `boot` → a booted system initiates this context early at boot. (systemd's
PID 1 generates this on `/dev/console`.)
2. `container` → a container managed initialized an interactive connection to a
container. (`systemd-nspawn` generates this when interactively invoking a
container. `machinectl login`, `machinectl shell` do this too.)
3. `vm` → a VMM initialized a terminal connection to VM. (`systemd-vmspawn`
generates this when interactively invoking a VM, as one example.)
4. `elevate` → when the user interactively acquired higher privileges. (`run0`
initiates a context of this type whenever the user invokes it to acquire
root privileges.)
5. `chpriv` → similar, but when the user acquired *different* privileges, not
necessarily higher ones. (`run0` initiates a context of this type whenever
the user invokes it to acquire non-root privileges of another user.)
5. `subcontext` → similar, but the source and target privileges where
identical. (`run0` initiates a context of this type whenever the user
invokes it to acquire privileges of the user itself.)
6. `remote` → a user invoked a tool such as `ssh` to connect to a remote
system.
7. `shell` → an interactive terminal shell initiates this context
8. `command` → a shell interactively invokes a new program.
9. `app` → an interactive program may initiate this context.
10. `service` → the service manager invokes an interactive service on the terminal
11. `session` → a login session of the user is initialized.
## Semantics
Contexts in the sense of OSC 300819 are hierarchial, and describe a tree
structure: whenever a new context is opened it becomes the new active context,
and the previously active context becomes its parent (if there is one). Only
one context is currently active, but previously opened contexts remain valid in
the background. Any other data written or read should be considered associated
with the currently active context.
Each context carries an identifier, chosen by the component opening the
context. The identifier can chosen freely, but must not be longer than 64
characters. The characters may be in the 32…126 byte range. Identifiers should universally
unique, for example randomly generated. A freshly generated UUID would work
well for this, but this could also be something like the Linux boot ID combined
with the 64bit inode number of Linux pidfds, or something hashed from it.
Fundamentally, there are two OSC 300819 commands defined:
1. OSC "`300819;S`" (the *start sequence*) → this initiates, updates or indicates a return to a
context. It carries a context identifier, and typically some metadata. This
may be send to first initiate a context. If sent again for the a context ID
that was initiated already this indicates an update of the existing
context. In this case, any previously set metadata fields for the context
are flushed out, reset to their defaults, and then reinitialized from the
newly supplied data. Also, in this case any subcontects of the contexts are
implicitly terminated.
2. OSC "`300819;X`" (the *end sequence*)→ this terminates a context. It carries a context
identifier to close, initiated before with OSC `300819;S`. It may also carry
additional metadata.
## General Syntax
This builds on ECMA-48, and reuses the OSC and ST concepts introduced there.
For sequences following this specification it is recommended to encode OSC as
0x1B 0x5D, and ST as 0x1B 0x5C.
ECMA-48 only allows characters from the range 0x20…0x7e (i.e. 32…126) inside
OSC sequences. Hence, any fields that shall contain characters outside of this
range require escaping. All textual fields must be encoded in UTF-8, which
then must be escaped.
Escaping shall be applied by taking the byte values of the characters to
escape, and formatting them as lower-case hexadecimal prefixed with
`\x`. Example: `Schöpfgefäß` becomes `Sch\xc3\xb6pfgef\xc3\xa4\xc3\x9f`.
The start sequence begins with OSC, followed by the character `S`, followed by
the context ID. This is then followed by any number of metadata fields,
including none. Metadata fields begin with a semicolon (`;`) and end in a
character identifiying the type of field. The sequence ends in ST.
The end sequence begins with OSC, followed by the character `X`, followed by
the context ID, and a series of metadata fields in the the syntax as for the
start sequence.
## Metadata Fields
The following fields are currently defined:
| Suffix | Context Types | Description |
|--------|---------------|-------------------------------------------------------------------------------------------------------------|
| `u` | *all* | UNIX user name the process issuing the sequence runs as |
| `h` | *all* | UNIX host name of the system the process issuing the sequence runs on |
| `m` | *all* | The machine ID (i.e. `/etc/machine-id`) of the system the process issuing the sequence runs on |
| `b` | *all* | The boot ID (i.e. `/proc/sys/kernel/random/boot_id`) of the system the process issuing the sequence runs on |
| `p` | *all* | The numeric PID of the process issuing the sequence, in decimal notation |
| `P` | *all* | The 64bit inode number of the pidfd of the process issuing the sequence, in decimal notation |
| `c` | *all* | The process name (i.e. `/proc/$PID/comm`, `PR_GET_NAME`) of the process issuing the sequence |
| `v` | `vm` | The name of the VM being invoked |
| `C` | `container` | The name of the container being invoked |
| `U` | `elevate`, `chpriv`, `vm`, `container`, `remote` | Target UNIX user name |
| `H` | `remote` | Target UNIX, DNS host name, or IP address |
All fields are optional, including the context type. However, it is generally
recommended to always include the first 7 fields listed above, to make it easy
to pinpoint the origin of a context in a race-free fashion without any
ambiguities.
## Examples
1. A new container `foobar` has been invoked by user `lennart` on host `zeta`:
`OSC "300819;Sbed86fab93af4328bbed0a1224af6d40;lennartu;zetah;3deb5353d3ba43d08201c136a47ead7bm;d4a3d0fdf2e24fdea6d971ce73f4fbf2b;1062862p;1063162P;foobarc;containert" ST`
2. A context ends: `OSC "300819;Xbed86fab93af4328bbed0a1224af6d40" ST`
## Syntax in ABNF
```abnf
OSC = %x1B %x5D
ST = %x1B %x5C
DECIMAL = "0"-"9"
HEX = "0"-"9" / "A"-"F" / "a-f"
ID128 = 32*36(HEX / "-")
UINT64 = 1*20DECIMAL
ESCAPED = "\x" HEX HEX
SAFE = %x20-3a / %x3c-5b / %x5d-7e / ESCAPED
CTXID = 1*64SAFE
USER = 1*255SAFE "u"
HOSTNAME = 1*255SAFE "h"
MACHINEID = 1D128 "m"
BOOTID = ID128 "b"
PID = UINT64 "p"
PIDFDID = UINT64 "P"
COMM = 1*255SAFE "c"
TYPE = ("service" / "session" / "shell" / "command" / "vm" / "container" / "elevate" / "chpriv" / "subcontext" / "remote" / "boot" / "app") "t"
SESSIONID = 1*255SAFE "s"
CWD = 1*255SAFE "d"
CMDLINE = *255SAFE "L"
VMNAME = 1*255SAFE "v"
CONTAINERNAME= 1*255SAFE "C"
TARGETUSER = 1*255SAFE "U"
TARGETHOST = 1*255SAFE "H"
APPID = 1*255SAFE "A"
STARTFIELD = (USER / HOSTNAME / MACHINEID / BOOTID / PID / PIDFDID / COMM / TYPE / SESSIONID / CWD / CMDLINE / VMNAME / CONTAINERNAME / TARGETUSER / TARGETHOST / APPID)
STARTSEQ = OSC "300819;" CTXID "S" *(";" STARTFIELD) ST
EXIT = "success" / "failure" / "crash" / "interrupt"
STATUS = UINT64
SIGNAL = "SIGBUS" / "SIGTRAP" / "SIGABRT" / "SIGSEGV" / …
ENDFIELD = (EXIT / STATUS / SIGNAL)
ENDSEQ = OSC "300819;" CTXID "X" *(";" ENDFIELD) ST
```
## Known OSC Prefixes
Here's a list of OSC prefixes used by the various sequences currently in public
use in various terminal emulators. It's not going to be complete, but I tried
to do some reasonably thorough research to avoid conflicts with the new OSC
sequence defined above.
| OSC Prefix | Purpose |
|----------------:|------------------------------------------------------------|
| `OSC "0;…"` | Icon name + window title |
| `OSC "1;…"` | Icon name |
| `OSC "2;…"` | Window title |
| `OSC "3;…"` | X11 property |
| `OSC "4;…"` | Palette |
| `OSC "5;…"` | Special palette |
| `OSC "6;…"` | Disable special color |
| `OSC "7;…"` | Report cwd |
| `OSC "8;…"` | Hyperlink |
| `OSC "9;…"` | Progress bar (conemu) [conflict: also growl notifications] |
| `OSC "10;…"` | Change colors |
| `OSC "11;…"` | " |
| `OSC "12;…"` | " |
| `OSC "13;…"` | " |
| `OSC "14;…"` | " |
| `OSC "15;…"` | " |
| `OSC "16;…"` | " |
| `OSC "17;…"` | " |
| `OSC "18;…"` | " |
| `OSC "19;…"` | " |
| `OSC "21;…"` | Query colors (kitty) |
| `OSC "22;…"` | Cursor shape |
| `OSC "46;…"` | Log file |
| `OSC "50;…"` | Set font |
| `OSC "51;…"` | Emacs shell |
| `OSC "52;…"` | Manipulate selection data (aka clipboard) |
| `OSC "60;…"` | Query allowed |
| `OSC "61;…"` | Query disallowed |
| `OSC "99;…"` | Notifications (kitty) |
| `OSC "104;…"` | Reset color |
| `OSC "105;…"` | Enable/disable special color |
| `OSC "110;…"` | Reset colors |
| `OSC "111;…"` | " |
| `OSC "112;…"` | " |
| `OSC "113;…"` | " |
| `OSC "114;…"` | " |
| `OSC "115;…"` | " |
| `OSC "116;…"` | " |
| `OSC "117;…"` | " |
| `OSC "118;…"` | " |
| `OSC "119;…"` | " |
| `OSC "133;…"` | Prompt/command begin/command end (finalterm/iterm2) |
| `OSC "440;…"` | Audio (mintty) |
| `OSC "633;…"` | vscode action (Windows Terminal) |
| `OSC "666;…"` | "termprop" (vte) |
| `OSC "701;…"` | Locale (mintty) |
| `OSC "777;…"` | Notification (rxvt) |
| `OSC "7704;…"` | ANSI colors (mintty) |
| `OSC "7750;…"` | Emoji style (mintty) |
| `OSC "7770;…"` | Font size (mintty) |
| `OSC "7771;…"` | Glyph coverage (mintty) |
| `OSC "7721:…"` | Copy window title (mintty) |
| `OSC "7777;…"` | Window size (mintty) |
| `OSC "9001;…"` | Action (Windows Terminal) |
| `OSC "1337;…"` | iterm2 multiplex seeuqnece |
| `OSC "5522;…"` | Clipboard (kitty) |
| `OSC "30001;…"` | Push color onto stack (kitty) |
| `OSC "30101;…"` | Pop color from stack (kitty) |
| `OSC "77119;…"` | Wide chars (mintty) |

View File

@ -684,6 +684,15 @@ fi</programlisting>
<citerefentry><refentrytitle>file-hierarchy</refentrytitle><manvolnum>7</manvolnum></citerefentry>.</para>
</refsect1>
<refsect1>
<title>Notes</title>
<para>
All example codes in this page are licensed under <literal>MIT No Attribution</literal>
(SPDX-License-Identifier: MIT-0).
</para>
</refsect1>
<refsect1>
<title>See Also</title>
<para><simplelist type="inline">

View File

@ -128,7 +128,8 @@
<para>If <option>-keep-download=yes</option> is specified the image will be downloaded and stored in
a read-only subvolume/directory in the image directory that is named after the specified URL and its
HTTP etag. A writable snapshot is then taken from this subvolume, and named after the specified local
HTTP etag (see <ulink url="https://en.wikipedia.org/wiki/HTTP_ETag">HTTP ETag</ulink> for more
information). A writable snapshot is then taken from this subvolume, and named after the specified local
name. This behavior ensures that creating multiple instances of the same URL is efficient, as
multiple downloads are not necessary. In order to create only the read-only image, and avoid creating
its writable snapshot, specify <literal>-</literal> as local name.</para>

View File

@ -28,7 +28,9 @@
<title>Description</title>
<para><command>pam_systemd_loadkey</command> reads a NUL-separated password list from the kernel keyring,
and sets the last password in the list as the PAM authtok.</para>
and sets the last password in the list as the PAM authtok, which can be used by e.g.
<citerefentry project='man-pages'><refentrytitle>pam_get_authtok</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
</para>
<para>The password list is supposed to be stored in the "user" keyring of the root user,
by an earlier call to

View File

@ -61,7 +61,10 @@
<literal>systemd-run0</literal> PAM stack.</para>
<para>Note that <command>run0</command> is implemented as an alternative multi-call invocation of
<citerefentry><refentrytitle>systemd-run</refentrytitle><manvolnum>1</manvolnum></citerefentry>.</para>
<citerefentry><refentrytitle>systemd-run</refentrytitle><manvolnum>1</manvolnum></citerefentry>. That is,
<command>run0</command> is a symbolic link to <command>systemd-run</command> executable file, and it
behaves as <command>run0</command> if it is invoked through the symbolic link, otherwise behaves as
<command>systemd-run</command>.</para>
</refsect1>
<refsect1>

View File

@ -41,8 +41,10 @@
<refsect1>
<title>Kernel Command Line</title>
<para><filename>systemd-rfkill</filename> understands the
following kernel command line parameter:</para>
<para>
<command>systemd-rfkill</command> understands the following kernel command line parameter. See also
<citerefentry><refentrytitle>kernel-command-line</refentrytitle><manvolnum>7</manvolnum></citerefentry>.
</para>
<variablelist class='kernel-commandline-options'>
<varlistentry>

View File

@ -302,7 +302,7 @@
and running in an initrd equivalent to true, otherwise false. This implements a restricted subset of
the per-unit setting of the same name, see
<citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
details: currently, the <literal>full</literal> or <literal>struct</literal> values are not
details: currently, the <literal>full</literal> or <literal>strict</literal> values are not
supported.</para>
<xi:include href="version-info.xml" xpointer="v256"/></listitem>

View File

@ -394,9 +394,9 @@
<listitem><para>SBAT metadata associated with the UKI or addon. SBAT policies are useful to revoke
whole groups of UKIs or addons with a single, static policy update that does not take space in
DBX/MOKX. If not specified manually, a default metadata entry consisting of
<literal>uki,1,UKI,uki,1,https://uapi-group.org/specifications/specs/unified_kernel_image/</literal>
<programlisting>uki,1,UKI,uki,1,https://uapi-group.org/specifications/specs/unified_kernel_image/</programlisting>
for UKIs and
<literal>uki-addon,1,UKI Addon,addon,1,https://www.freedesktop.org/software/systemd/man/latest/systemd-stub.html</literal>
<programlisting>uki-addon,1,UKI Addon,addon,1,https://www.freedesktop.org/software/systemd/man/latest/systemd-stub.html</programlisting>
for addons will be used, to ensure it is always possible to revoke them. For more information on
SBAT see <ulink url="https://github.com/rhboot/shim/blob/main/SBAT.md">Shim documentation</ulink>.
</para>

View File

@ -365,6 +365,8 @@ char* xescape_full(const char *s, const char *bad, size_t console_width, XEscape
char *ans, *t, *prev, *prev2;
const char *f;
assert(s);
/* Escapes all chars in bad, in addition to \ and all special chars, in \xFF style escaping. May be
* reversed with cunescape(). If XESCAPE_8_BIT is specified, characters >= 127 are let through
* unchanged. This corresponds to non-ASCII printable characters in pre-unicode encodings.
@ -397,7 +399,7 @@ char* xescape_full(const char *s, const char *bad, size_t console_width, XEscape
if ((unsigned char) *f < ' ' ||
(!FLAGS_SET(flags, XESCAPE_8_BIT) && (unsigned char) *f >= 127) ||
*f == '\\' || strchr(bad, *f)) {
*f == '\\' || (bad && strchr(bad, *f))) {
if ((size_t) (t - ans) + 4 + 3 * force_ellipsis > console_width)
break;

View File

@ -289,7 +289,8 @@ int write_string_file_full(
const char *fn,
const char *line,
WriteStringFileFlags flags,
const struct timespec *ts) {
const struct timespec *ts,
const char *label_fn) {
bool call_label_ops_post = false, made_file = false;
_cleanup_fclose_ FILE *f = NULL;
@ -321,7 +322,8 @@ int write_string_file_full(
mode_t mode = write_string_file_flags_to_mode(flags);
if (FLAGS_SET(flags, WRITE_STRING_FILE_LABEL|WRITE_STRING_FILE_CREATE)) {
r = label_ops_pre(dir_fd, fn, mode);
const char *lookup = label_fn ? label_fn : fn;
r = label_ops_pre(dir_fd, lookup, mode);
if (r < 0)
goto fail;

View File

@ -51,12 +51,13 @@ int write_string_stream_full(FILE *f, const char *line, WriteStringFileFlags fla
static inline int write_string_stream(FILE *f, const char *line, WriteStringFileFlags flags) {
return write_string_stream_full(f, line, flags, /* ts= */ NULL);
}
int write_string_file_full(int dir_fd, const char *fn, const char *line, WriteStringFileFlags flags, const struct timespec *ts);
int write_string_file_full(int dir_fd, const char *fn, const char *line, WriteStringFileFlags flags, const struct timespec *ts, const char *label_fn);
static inline int write_string_file(const char *fn, const char *line, WriteStringFileFlags flags) {
return write_string_file_full(AT_FDCWD, fn, line, flags, /* ts= */ NULL);
return write_string_file_full(AT_FDCWD, fn, line, flags, /* ts= */ NULL, /*label_fn=*/ NULL);
}
static inline int write_string_file_at(int dir_fd, const char *fn, const char *line, WriteStringFileFlags flags) {
return write_string_file_full(dir_fd, fn, line, flags, /* ts= */ NULL);
return write_string_file_full(dir_fd, fn, line, flags, /* ts= */ NULL, /*label_fn=*/ NULL);
}
int write_string_filef(const char *fn, WriteStringFileFlags flags, const char *format, ...) _printf_(3, 4);

View File

@ -866,6 +866,9 @@ void hexdump(FILE *f, const void *p, size_t s) {
assert(b || s == 0);
if (s == SIZE_MAX)
s = strlen(p);
if (!f)
f = stdout;

View File

@ -3,6 +3,7 @@
#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include <linux/magic.h>
#include <linux/oom.h>
#include <pthread.h>
#include <spawn.h>
@ -11,6 +12,9 @@
#include <stdlib.h>
#include <sys/mount.h>
#include <sys/personality.h>
#if HAVE_PIDFD_OPEN
#include <sys/pidfd.h>
#endif
#include <sys/prctl.h>
#include <sys/types.h>
#include <sys/wait.h>
@ -40,6 +44,7 @@
#include "log.h"
#include "macro.h"
#include "memory-util.h"
#include "missing_magic.h"
#include "missing_sched.h"
#include "missing_syscall.h"
#include "missing_threads.h"
@ -2289,3 +2294,42 @@ _noreturn_ void report_errno_and_exit(int errno_fd, int error) {
_exit(EXIT_FAILURE);
}
int getpidfdid_cached(uint64_t *ret) {
static uint64_t cached = 0;
static int initialized = 0;
int r;
assert(ret);
if (initialized > 0) {
*ret = cached;
return 0;
}
if (initialized < 0)
return initialized;
_cleanup_close_ int fd = pidfd_open(getpid_cached(), 0);
if (fd < 0) {
if (ERRNO_IS_NOT_SUPPORTED(errno))
return (initialized = -EOPNOTSUPP);
return -errno;
}
r = fd_is_fs_type(fd, PID_FS_MAGIC);
if (r < 0)
return r;
if (r == 0)
return (initialized = -EOPNOTSUPP);
struct stat st;
if (fstat(fd, &st) < 0)
return -errno;
if (st.st_ino == 0)
return (initialized = -EOPNOTSUPP);
*ret = cached = st.st_ino;
initialized = 1;
return 0;
}

View File

@ -275,3 +275,5 @@ int proc_dir_read(DIR *d, pid_t *ret);
int proc_dir_read_pidref(DIR *d, PidRef *ret);
_noreturn_ void report_errno_and_exit(int errno_fd, int error);
int getpidfdid_cached(uint64_t *ret);

View File

@ -42,6 +42,7 @@ static void fallback_random_bytes(void *p, size_t n) {
uint64_t call_id, block_id;
usec_t stamp_mono, stamp_real;
pid_t pid, tid;
uint64_t pidfdid;
uint8_t auxval[16];
} state = {
/* Arbitrary domain separation to prevent other usage of AT_RANDOM from clashing. */
@ -57,6 +58,8 @@ static void fallback_random_bytes(void *p, size_t n) {
memcpy(state.auxval, ULONG_TO_PTR(getauxval(AT_RANDOM)), sizeof(state.auxval));
#endif
(void) getpidfdid_cached(&state.pidfdid);
while (n > 0) {
struct sha256_ctx ctx;

View File

@ -45,6 +45,7 @@
#include "efivars.h"
#include "emergency-action.h"
#include "env-util.h"
#include "escape.h"
#include "exit-status.h"
#include "fd-util.h"
#include "fdset.h"
@ -57,6 +58,7 @@
#include "ima-setup.h"
#include "import-creds.h"
#include "initrd-util.h"
#include "io-util.h"
#include "ipe-setup.h"
#include "killall.h"
#include "kmod-setup.h"
@ -73,6 +75,7 @@
#include "mount-setup.h"
#include "mount-util.h"
#include "os-util.h"
#include "osc-context.h"
#include "pager.h"
#include "parse-argument.h"
#include "parse-util.h"
@ -2380,6 +2383,38 @@ static void log_execution_mode(bool *ret_first_boot) {
*ret_first_boot = first_boot;
}
static int write_boot_or_shutdown_osc(bool boot) {
int r;
if (getenv_terminal_is_dumb())
return 0;
const char *type = boot ? "boot" : "shutdown";
_cleanup_close_ int fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC);
if (fd < 0)
return log_debug_errno(fd, "Failed to open /dev/console to print %s OSC, ignoring: %m", type);
_cleanup_free_ char *seq = NULL;
if (boot)
r = osc_context_open_boot(&seq);
else
r = osc_context_close(SD_ID128_ALLF, &seq);
if (r < 0)
return log_debug_errno(r, "Failed to acquire %s OSC sequence, ignoring: %m", type);
r = loop_write(fd, seq, strlen(seq));
if (r < 0)
return log_debug_errno(r, "Failed to write %s OSC sequence, ignoring: %m", type);
if (DEBUG_LOGGING) {
_cleanup_free_ char *h = cescape(seq);
log_debug("OSC sequence for %s successfully written: %s", type, strna(h));
}
return 0;
}
static int initialize_runtime(
bool skip_setup,
bool first_boot,
@ -2438,6 +2473,8 @@ static int initialize_runtime(
write_container_id();
(void) write_boot_or_shutdown_osc(/* boot= */ true);
/* Copy os-release to the propagate directory, so that we update it for services running
* under RootDirectory=/RootImage= when we do a soft reboot. */
r = setup_os_release(RUNTIME_SCOPE_SYSTEM);
@ -3427,6 +3464,8 @@ finish:
}
#endif
(void) write_boot_or_shutdown_osc(/* boot= */ false);
if (r < 0)
(void) sd_notifyf(/* unset_environment= */ false,
"ERRNO=%i", -r);

View File

@ -16,6 +16,7 @@
#include "fileio.h"
#include "format-util.h"
#include "hexdecoct.h"
#include "iovec-util.h"
#include "macro.h"
#include "memory-util.h"
#include "parse-util.h"
@ -31,8 +32,7 @@ int decrypt_pkcs11_key(
const char *key_file, /* We either expect key_file and associated parameters to be set (for file keys) … */
size_t key_file_size,
uint64_t key_file_offset,
const void *key_data, /* … or key_data and key_data_size (for literal keys) */
size_t key_data_size,
const struct iovec *key_data, /* … or literal keys via key_data */
usec_t until,
AskPasswordFlags askpw_flags,
void **ret_decrypted_key,
@ -47,15 +47,15 @@ int decrypt_pkcs11_key(
assert(friendly_name);
assert(pkcs11_uri);
assert(key_file || key_data);
assert(key_file || iovec_is_set(key_data));
assert(ret_decrypted_key);
assert(ret_decrypted_key_size);
/* The functions called here log about all errors, except for EAGAIN which means "token not found right now" */
if (key_data) {
data.encrypted_key = (void*) key_data;
data.encrypted_key_size = key_data_size;
if (iovec_is_set(key_data)) {
data.encrypted_key = (void*) key_data->iov_base;
data.encrypted_key_size = key_data->iov_len;
data.free_encrypted_key = false;
} else {

View File

@ -16,8 +16,7 @@ int decrypt_pkcs11_key(
const char *key_file,
size_t key_file_size,
uint64_t key_file_offset,
const void *key_data,
size_t key_data_size,
const struct iovec *key_data,
usec_t until,
AskPasswordFlags askpw_flags,
void **ret_decrypted_key,
@ -39,8 +38,7 @@ static inline int decrypt_pkcs11_key(
const char *key_file,
size_t key_file_size,
uint64_t key_file_offset,
const void *key_data,
size_t key_data_size,
const struct iovec *key_data,
usec_t until,
AskPasswordFlags askpw_flags,
void **ret_decrypted_key,

View File

@ -1471,8 +1471,7 @@ static int attach_luks_or_plain_or_bitlk_by_fido2(
struct crypt_device *cd,
const char *name,
const char *key_file,
const void *key_data,
size_t key_data_size,
const struct iovec *key_data,
usec_t until,
uint32_t flags,
bool pass_volume_key) {
@ -1489,7 +1488,7 @@ static int attach_luks_or_plain_or_bitlk_by_fido2(
assert(name);
assert(arg_fido2_device || arg_fido2_device_auto);
if (arg_fido2_cid && !key_file && !key_data)
if (arg_fido2_cid && !key_file && !iovec_is_set(key_data))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"FIDO2 mode with manual parameters selected, but no keyfile specified, refusing.");
@ -1513,7 +1512,7 @@ static int attach_luks_or_plain_or_bitlk_by_fido2(
arg_fido2_rp_id,
arg_fido2_cid, arg_fido2_cid_size,
key_file, arg_keyfile_size, arg_keyfile_offset,
key_data, key_data_size,
key_data,
until,
arg_fido2_manual_flags,
"cryptsetup.fido2-pin",
@ -1623,8 +1622,7 @@ static int attach_luks_or_plain_or_bitlk_by_pkcs11(
struct crypt_device *cd,
const char *name,
const char *key_file,
const void *key_data,
size_t key_data_size,
const struct iovec *key_data,
usec_t until,
uint32_t flags,
bool pass_volume_key) {
@ -1635,6 +1633,7 @@ static int attach_luks_or_plain_or_bitlk_by_pkcs11(
_cleanup_(erase_and_freep) void *decrypted_key = NULL;
_cleanup_(sd_event_unrefp) sd_event *event = NULL;
_cleanup_free_ void *discovered_key = NULL;
struct iovec discovered_key_data = {};
int keyslot = arg_key_slot, r;
const char *uri = NULL;
bool use_libcryptsetup_plugin = use_token_plugins();
@ -1653,13 +1652,13 @@ static int attach_luks_or_plain_or_bitlk_by_pkcs11(
return r;
uri = discovered_uri;
key_data = discovered_key;
key_data_size = discovered_key_size;
discovered_key_data = IOVEC_MAKE(discovered_key, discovered_key_size);
key_data = &discovered_key_data;
}
} else {
uri = arg_pkcs11_uri;
if (!key_file && !key_data)
if (!key_file && !iovec_is_set(key_data))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "PKCS#11 mode selected but no key file specified, refusing.");
}
@ -1682,7 +1681,7 @@ static int attach_luks_or_plain_or_bitlk_by_pkcs11(
friendly,
uri,
key_file, arg_keyfile_size, arg_keyfile_offset,
key_data, key_data_size,
key_data,
until,
arg_ask_password_flags,
&decrypted_key, &decrypted_key_size);
@ -2231,9 +2230,9 @@ static int attach_luks_or_plain_or_bitlk(
if (token_type == TOKEN_TPM2)
return attach_luks_or_plain_or_bitlk_by_tpm2(cd, name, key_file, key_data, until, flags, pass_volume_key);
if (token_type == TOKEN_FIDO2)
return attach_luks_or_plain_or_bitlk_by_fido2(cd, name, key_file, key_data->iov_base, key_data->iov_len, until, flags, pass_volume_key);
return attach_luks_or_plain_or_bitlk_by_fido2(cd, name, key_file, key_data, until, flags, pass_volume_key);
if (token_type == TOKEN_PKCS11)
return attach_luks_or_plain_or_bitlk_by_pkcs11(cd, name, key_file, key_data->iov_base, key_data->iov_len, until, flags, pass_volume_key);
return attach_luks_or_plain_or_bitlk_by_pkcs11(cd, name, key_file, key_data, until, flags, pass_volume_key);
if (key_data)
return attach_luks_or_plain_or_bitlk_by_key_data(cd, name, key_data, flags, pass_volume_key);
if (key_file)

View File

@ -1698,7 +1698,8 @@ _public_ int sd_varlink_get_events(sd_varlink *v) {
ret |= EPOLLIN;
if (!v->write_disconnected &&
v->output_buffer_size > 0)
(v->output_queue ||
v->output_buffer_size > 0))
ret |= EPOLLOUT;
return ret;

View File

@ -45,6 +45,7 @@
#include "main-func.h"
#include "mkdir.h"
#include "nulstr-util.h"
#include "osc-context.h"
#include "pager.h"
#include "parse-argument.h"
#include "parse-util.h"
@ -1227,6 +1228,13 @@ static int process_forward(sd_event *event, PTYForward **forward, int master, PT
log_info("Connected to machine %s. Press ^] three times within 1s to exit session.", name);
}
_cleanup_(osc_context_closep) sd_id128_t osc_context_id = SD_ID128_NULL;
if (!terminal_is_dumb()) {
r = osc_context_open_container(name, /* ret_seq= */ NULL, &osc_context_id);
if (r < 0)
return r;
}
r = sd_event_set_signal_exit(event, true);
if (r < 0)
return log_error_errno(r, "Failed to enable SIGINT/SITERM handling: %m");

View File

@ -84,6 +84,7 @@
#include "nsresource.h"
#include "nulstr-util.h"
#include "os-util.h"
#include "osc-context.h"
#include "pager.h"
#include "parse-argument.h"
#include "parse-util.h"
@ -5684,6 +5685,13 @@ static int run_container(
(void) expose_port_execute(rtnl, &expose_args->fw_ctx, arg_expose_ports, AF_INET6, &expose_args->address6);
}
_cleanup_(osc_context_closep) sd_id128_t osc_context_id = SD_ID128_NULL;
if (IN_SET(arg_console_mode, CONSOLE_INTERACTIVE, CONSOLE_READ_ONLY) && !terminal_is_dumb()) {
r = osc_context_open_container(arg_machine, /* ret_seq= */ NULL, &osc_context_id);
if (r < 0)
return r;
}
if (arg_console_mode != CONSOLE_PIPE) {
_cleanup_close_ int fd = -EBADF;
PTYForwardFlags flags = 0;

View File

@ -30,6 +30,7 @@
#include "fs-util.h"
#include "hostname-util.h"
#include "main-func.h"
#include "osc-context.h"
#include "parse-argument.h"
#include "parse-util.h"
#include "path-util.h"
@ -2041,6 +2042,7 @@ static int start_transient_service(sd_bus *bus) {
return r;
}
_cleanup_(osc_context_closep) sd_id128_t osc_context_id = SD_ID128_NULL;
if (arg_wait || arg_stdio != ARG_STDIO_NONE) {
_cleanup_(run_context_done) RunContext c = {
.cpu_usage_nsec = NSEC_INFINITY,
@ -2067,6 +2069,12 @@ static int start_transient_service(sd_bus *bus) {
return log_oom();
if (pty_fd >= 0) {
if (!terminal_is_dumb() && arg_exec_user) {
r = osc_context_open_chpriv(arg_exec_user, /* ret_seq= */ NULL, &osc_context_id);
if (r < 0)
return r;
}
(void) sd_event_set_signal_exit(c.event, true);
if (!arg_quiet)

View File

@ -24,8 +24,7 @@ int acquire_fido2_key(
const char *key_file,
size_t key_file_size,
uint64_t key_file_offset,
const void *key_data,
size_t key_data_size,
const struct iovec *key_data,
usec_t until,
Fido2EnrollFlags required,
const char *askpw_credential,
@ -45,10 +44,10 @@ int acquire_fido2_key(
"Local verification is required to unlock this volume, but the 'headless' parameter was set.");
assert(cid);
assert(key_file || key_data);
assert(key_file || iovec_is_set(key_data));
if (key_data)
salt = IOVEC_MAKE(key_data, key_data_size);
if (iovec_is_set(key_data))
salt = *key_data;
else {
if (key_file_size > 0)
log_debug("Ignoring 'keyfile-size=' option for a FIDO2 salt file.");
@ -252,7 +251,7 @@ int acquire_fido2_key_auto(
/* key_file= */ NULL, /* salt is read from LUKS header instead of key_file */
/* key_file_size= */ 0,
/* key_file_offset= */ 0,
salt, salt_size,
&IOVEC_MAKE(salt, salt_size),
until,
required,
"cryptsetup.fido2-pin",

View File

@ -20,8 +20,7 @@ int acquire_fido2_key(
const char *key_file,
size_t key_file_size,
uint64_t key_file_offset,
const void *key_data,
size_t key_data_size,
const struct iovec *key_data,
usec_t until,
Fido2EnrollFlags required,
const char *askpw_credential,
@ -52,8 +51,7 @@ static inline int acquire_fido2_key(
const char *key_file,
size_t key_file_size,
uint64_t key_file_offset,
const void *key_data,
size_t key_data_size,
const struct iovec *key_data,
usec_t until,
Fido2EnrollFlags required,
const char *askpw_credential,

View File

@ -132,6 +132,7 @@ shared_sources = files(
'open-file.c',
'openssl-util.c',
'output-mode.c',
'osc-context.c',
'pager.c',
'parse-argument.c',
'parse-helpers.c',

275
src/shared/osc-context.c Normal file
View File

@ -0,0 +1,275 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#if HAVE_SYS_AUXV_H
# include <sys/auxv.h>
#endif
#include "escape.h"
#include "hostname-util.h"
#include "osc-context.h"
#include "process-util.h"
#include "string-util.h"
#include "terminal-util.h"
#include "user-util.h"
/* This currently generates open sequences for OSC 300819 types "boot", "container", "vm", "elevate",
* "chpriv", "subcontext". */
/* TODO:
*
* "service" (from the service manager)
* "session" (from pam_systemd?)
* "shell", "command" (from a bash profile drop-in?)
*
* Not generated by systemd: "remote" (would have to be generated from the SSH client), "app".
*/
static int strextend_escaped(char **s, const char *prefix, const char *value, const char *suffix) {
assert(s);
assert(value);
if (!strextend(s, prefix))
return -ENOMEM;
_cleanup_free_ char *e = xescape(value, ";\\");
if (!e)
return -ENOMEM;
if (!strextend(s, e))
return -ENOMEM;
if (!strextend(s, suffix))
return -ENOMEM;
return 0;
}
static int osc_append_identity(char **s) {
int r;
assert(s);
_cleanup_free_ char *u = getusername_malloc();
if (u) {
r = strextend_escaped(s, ";", u, "u");
if (r < 0)
return r;
}
_cleanup_free_ char *h = gethostname_malloc();
if (h) {
r = strextend_escaped(s, ";", h, "h");
if (r < 0)
return r;
}
sd_id128_t id;
if (sd_id128_get_machine(&id) >= 0) {
r = strextendf(s, ";" SD_ID128_FORMAT_STR "m", SD_ID128_FORMAT_VAL(id));
if (r < 0)
return r;
}
if (sd_id128_get_boot(&id) >= 0) {
r = strextendf(s, ";" SD_ID128_FORMAT_STR "b", SD_ID128_FORMAT_VAL(id));
if (r < 0)
return r;
}
r = strextendf(s, ";" PID_FMT "p", getpid_cached());
if (r < 0)
return r;
uint64_t pidfdid;
r = getpidfdid_cached(&pidfdid);
if (r >= 0) {
r = strextendf(s, ";%" PRIu64 "P", pidfdid);
if (r < 0)
return r;
}
r = strextend_escaped(s, ";", program_invocation_short_name, "c");
if (r < 0)
return r;
return 0;
}
static void osc_context_default_id(sd_id128_t *ret_id) {
/* Usually we only want one context ID per tool. Since we don't want to store the ID let's just hash
* one from process credentials */
struct {
uint64_t pidfdid;
uint8_t auxval[16];
pid_t pid;
} data = {
.pid = getpid_cached(),
};
assert(ret_id);
(void) getpidfdid_cached(&data.pidfdid);
memcpy(data.auxval, ULONG_TO_PTR(getauxval(AT_RANDOM)), sizeof(data.auxval));
ret_id->qwords[0] = siphash24(&data, sizeof(data), SD_ID128_MAKE(3f,8c,ee,e1,fd,35,41,ec,b8,b1,90,d4,59,e2,ae,5b).bytes);
ret_id->qwords[1] = siphash24(&data, sizeof(data), SD_ID128_MAKE(c6,41,ec,1b,d8,85,48,c0,8e,11,d7,e1,e1,fa,9e,03).bytes);
}
static int osc_context_intro(char **ret_seq, sd_id128_t *ret_context_id) {
int r;
assert(ret_seq);
/* If the user passed us a buffer for the context ID generate a randomized one, since we have a place
* to store it. The user should pass the ID back to osc_context_close() later on. if the user did not
* pass us a buffer, we'll use a session ID hashed from process properties that remain stable as long
* our process exists. It hence also remains stable across reexec and similar. */
sd_id128_t id;
if (ret_context_id) {
r = sd_id128_randomize(&id);
if (r < 0)
return r;
} else
osc_context_default_id(&id);
_cleanup_free_ char *seq = NULL;
if (asprintf(&seq, ANSI_OSC "300819;S" SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(id)) < 0)
return -ENOMEM;
r = osc_append_identity(&seq);
if (r < 0)
return r;
if (ret_context_id)
*ret_context_id = id;
*ret_seq = TAKE_PTR(seq);
return 0;
}
static int osc_context_outro(char *_seq, sd_id128_t id, char **ret_seq, sd_id128_t *ret_context_id) {
_cleanup_free_ char *seq = TAKE_PTR(_seq); /* We take possession of the string no matter what */
if (ret_seq)
*ret_seq = TAKE_PTR(seq);
else {
fputs(seq, stdout);
fflush(stdout);
}
if (ret_context_id)
*ret_context_id = id;
return 0;
}
int osc_context_open_boot(char **ret_seq) {
int r;
_cleanup_free_ char *seq = NULL;
sd_id128_t id;
r = osc_context_intro(&seq, /* ret_context_id= */ NULL);
if (r < 0)
return r;
if (!strextend(&seq, ";" "boot" "t" ANSI_ST))
return -ENOMEM;
return osc_context_outro(TAKE_PTR(seq), id, ret_seq, /* ret_context_id= */ NULL);
}
int osc_context_open_container(const char *name, char **ret_seq, sd_id128_t *ret_context_id) {
int r;
_cleanup_free_ char *seq = NULL;
sd_id128_t id;
r = osc_context_intro(&seq, ret_context_id ?: &id);
if (r < 0)
return r;
if (name) {
r = strextend_escaped(&seq, ";", name, "C");
if (r < 0)
return r;
}
if (!strextend(&seq, ";" "container" "t" ANSI_ST))
return -ENOMEM;
return osc_context_outro(TAKE_PTR(seq), id, ret_seq, ret_context_id);
}
int osc_context_open_vm(const char *name, char **ret_seq, sd_id128_t *ret_context_id) {
int r;
assert(name);
_cleanup_free_ char *seq = NULL;
sd_id128_t id;
r = osc_context_intro(&seq, ret_context_id ?: &id);
if (r < 0)
return r;
r = strextend_escaped(&seq, ";", name, "v");
if (r < 0)
return r;
if (!strextend(&seq, ";" "vm" "t" ANSI_ST))
return r;
return osc_context_outro(TAKE_PTR(seq), id, ret_seq, ret_context_id);
}
int osc_context_open_chpriv(const char *target_user, char **ret_seq, sd_id128_t *ret_context_id) {
int r;
assert(target_user);
_cleanup_free_ char *seq = NULL;
sd_id128_t id;
r = osc_context_intro(&seq, ret_context_id ?: &id);
if (r < 0)
return r;
if (STR_IN_SET(target_user, "root", "0")) {
if (!strextend(&seq, ";" "elevate" "t" ANSI_ST))
return -ENOMEM;
} else if (is_this_me(target_user) > 0) {
if (!strextend(&seq, ";" "subcontext" "t" ANSI_ST))
return -ENOMEM;
} else {
r = strextend_escaped(&seq, ";", target_user, "U");
if (r < 0)
return r;
if (!strextend(&seq, ";" "chpriv" "t" ANSI_ST))
return -ENOMEM;
}
return osc_context_outro(TAKE_PTR(seq), id, ret_seq, ret_context_id);
}
int osc_context_close(sd_id128_t id, char **ret_seq) {
if (sd_id128_is_null(id)) /* nil uuid: no session opened */
return 0;
if (sd_id128_is_allf(id)) /* max uuid: default session opened */
osc_context_default_id(&id);
_cleanup_free_ char *seq = NULL;
if (asprintf(&seq, ANSI_OSC "300819;X" SD_ID128_FORMAT_STR ANSI_ST, SD_ID128_FORMAT_VAL(id)) < 0)
return -ENOMEM;
if (ret_seq)
*ret_seq = TAKE_PTR(seq);
else {
fputs(seq, stdout);
fflush(stdout);
}
return 0;
}

14
src/shared/osc-context.h Normal file
View File

@ -0,0 +1,14 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include "sd-id128.h"
int osc_context_open_boot(char **ret_seq);
int osc_context_open_container(const char *name, char **ret_seq, sd_id128_t *ret_context_id);
int osc_context_open_vm(const char *name, char **ret_seq, sd_id128_t *ret_context_id);
int osc_context_open_chpriv(const char *target_user, char **ret_seq, sd_id128_t *ret_context_id);
int osc_context_close(sd_id128_t id, char **ret_seq);
static inline void osc_context_closep(sd_id128_t *context_id) {
(void) osc_context_close(*context_id, NULL);
}

View File

@ -1,5 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <linux/loop.h>
@ -45,6 +46,7 @@
#include "process-util.h"
#include "rm-rf.h"
#include "sort-util.h"
#include "selinux-util.h"
#include "string-table.h"
#include "string-util.h"
#include "terminal-util.h"
@ -899,6 +901,7 @@ static int resolve_mutable_directory(
_cleanup_free_ char *path = NULL, *resolved_path = NULL, *dir_name = NULL;
const char *root = arg_root, *base = MUTABLE_EXTENSIONS_BASE_DIR;
int r;
_cleanup_close_ int atfd = -EBADF;
assert(hierarchy);
assert(ret_resolved_mutable_directory);
@ -943,6 +946,14 @@ static int resolve_mutable_directory(
r = mkdir_p(path_in_root, 0700);
if (r < 0)
return log_error_errno(r, "Failed to create a directory '%s': %m", path_in_root);
atfd = open(path_in_root, O_DIRECTORY|O_CLOEXEC);
if (atfd < 0)
return log_error_errno(errno, "Failed to open directory '%s': %m", path_in_root);
r = mac_selinux_fix_full(atfd, NULL, hierarchy, 0);
if (r < 0)
return log_error_errno(r, "Failed to fix SELinux label for '%s': %m", path_in_root);
}
r = chase(path, root, CHASE_PREFIX_ROOT, &resolved_path, NULL);
@ -1289,6 +1300,7 @@ static int mount_overlayfs_with_op(
int r;
const char *top_layer = NULL;
_cleanup_close_ int atfd = -EBADF;
assert(op);
assert(overlay_path);
@ -1301,10 +1313,28 @@ static int mount_overlayfs_with_op(
if (r < 0)
return log_error_errno(r, "Failed to make directory '%s': %m", meta_path);
atfd = open(meta_path, O_DIRECTORY|O_CLOEXEC);
if (atfd < 0)
return log_error_errno(errno, "Failed to open directory '%s': %m", meta_path);
r = mac_selinux_fix_full(atfd, NULL, op->hierarchy, 0);
if (r < 0)
return log_error_errno(r, "Failed to fix SELinux label for '%s': %m", meta_path);
if (op->upper_dir && op->work_dir) {
r = mkdir_p(op->work_dir, 0700);
if (r < 0)
return log_error_errno(r, "Failed to make directory '%s': %m", op->work_dir);
_cleanup_close_ int dfd = -EBADF;
dfd = open(op->work_dir, O_DIRECTORY|O_CLOEXEC);
if (dfd < 0)
return log_error_errno(errno, "Failed to open directory '%s': %m", op->work_dir);
r = mac_selinux_fix_full(dfd, NULL, op->hierarchy, 0);
if (r < 0)
return log_error_errno(r, "Failed to fix SELinux label for '%s': %m", op->work_dir);
top_layer = op->upper_dir;
} else {
assert(!strv_isempty(op->lower_dirs));
@ -1325,7 +1355,7 @@ static int mount_overlayfs_with_op(
return 0;
}
static int write_extensions_file(ImageClass image_class, char **extensions, const char *meta_path) {
static int write_extensions_file(ImageClass image_class, char **extensions, const char *meta_path, const char *hierarchy) {
_cleanup_free_ char *f = NULL, *buf = NULL;
int r;
@ -1343,14 +1373,15 @@ static int write_extensions_file(ImageClass image_class, char **extensions, cons
if (!buf)
return log_oom();
r = write_string_file(f, buf, WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_MKDIR_0755);
const char *hierarchy_path = path_join(hierarchy, image_class_info[image_class].dot_directory_name, image_class_info[image_class].short_identifier_plural);
r = write_string_file_full(AT_FDCWD,f, buf, WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_MKDIR_0755|WRITE_STRING_FILE_LABEL, NULL, hierarchy_path);
if (r < 0)
return log_error_errno(r, "Failed to write extension meta file '%s': %m", f);
return 0;
}
static int write_dev_file(ImageClass image_class, const char *meta_path, const char *overlay_path) {
static int write_dev_file(ImageClass image_class, const char *meta_path, const char *overlay_path, const char *hierarchy) {
_cleanup_free_ char *f = NULL;
struct stat st;
int r;
@ -1372,14 +1403,15 @@ static int write_dev_file(ImageClass image_class, const char *meta_path, const c
/* Modifying the underlying layers while the overlayfs is mounted is technically undefined, but at
* least it won't crash or deadlock, as per the kernel docs about overlayfs:
* https://www.kernel.org/doc/html/latest/filesystems/overlayfs.html#changes-to-underlying-filesystems */
r = write_string_file(f, FORMAT_DEVNUM(st.st_dev), WRITE_STRING_FILE_CREATE);
const char *hierarchy_path = path_join(hierarchy, image_class_info[image_class].dot_directory_name, image_class_info[image_class].short_identifier_plural);
r = write_string_file_full(AT_FDCWD, f, FORMAT_DEVNUM(st.st_dev), WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_LABEL, NULL, hierarchy_path);
if (r < 0)
return log_error_errno(r, "Failed to write '%s': %m", f);
return 0;
}
static int write_work_dir_file(ImageClass image_class, const char *meta_path, const char *work_dir) {
static int write_work_dir_file(ImageClass image_class, const char *meta_path, const char *work_dir, const char* hierarchy) {
_cleanup_free_ char *escaped_work_dir_in_root = NULL, *f = NULL;
char *work_dir_in_root = NULL;
int r;
@ -1406,7 +1438,8 @@ static int write_work_dir_file(ImageClass image_class, const char *meta_path, co
escaped_work_dir_in_root = cescape(work_dir_in_root);
if (!escaped_work_dir_in_root)
return log_oom();
r = write_string_file(f, escaped_work_dir_in_root, WRITE_STRING_FILE_CREATE);
const char *hierarchy_path = path_join(hierarchy, image_class_info[image_class].dot_directory_name, "work_dir");
r = write_string_file_full(AT_FDCWD, f, escaped_work_dir_in_root, WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_LABEL, NULL, hierarchy_path);
if (r < 0)
return log_error_errno(r, "Failed to write '%s': %m", f);
@ -1418,8 +1451,10 @@ static int store_info_in_meta(
char **extensions,
const char *meta_path,
const char *overlay_path,
const char *work_dir) {
const char *work_dir,
const char *hierarchy) {
_cleanup_free_ char *f = NULL;
_cleanup_close_ int atfd = -EBADF;
int r;
assert(extensions);
@ -1427,15 +1462,32 @@ static int store_info_in_meta(
assert(overlay_path);
/* work_dir may be NULL */
r = write_extensions_file(image_class, extensions, meta_path);
f = path_join(meta_path, image_class_info[image_class].dot_directory_name);
if (!f)
return log_oom();
r = mkdir_p(f, 0755);
if (r < 0)
return r;
r = write_dev_file(image_class, meta_path, overlay_path);
atfd = open(f, O_DIRECTORY|O_CLOEXEC);
if (atfd < 0)
return log_error_errno(errno, "Failed to open directory '%s': %m", f);
r = mac_selinux_fix_full(atfd, NULL, hierarchy, 0);
if (r < 0)
return log_error_errno(r, "Failed to fix SELinux label for '%s': %m", hierarchy);
r = write_extensions_file(image_class, extensions, meta_path, hierarchy);
if (r < 0)
return r;
r = write_work_dir_file(image_class, meta_path, work_dir);
r = write_dev_file(image_class, meta_path, overlay_path, hierarchy);
if (r < 0)
return r;
r = write_work_dir_file(image_class, meta_path, work_dir, hierarchy);
if (r < 0)
return r;
@ -1501,6 +1553,8 @@ static int merge_hierarchy(
assert(overlay_path);
assert(workspace_path);
mac_selinux_init();
r = determine_used_extensions(hierarchy, paths, &used_paths, &extensions_used);
if (r < 0)
return r;
@ -1528,7 +1582,7 @@ static int merge_hierarchy(
if (r < 0)
return r;
r = store_info_in_meta(image_class, extensions, meta_path, overlay_path, op->work_dir);
r = store_info_in_meta(image_class, extensions, meta_path, overlay_path, op->work_dir, op->hierarchy);
if (r < 0)
return r;

View File

@ -1414,7 +1414,7 @@ static int verb_enable(int argc, char **argv, void *userdata) {
"SetFeatureEnabled",
&error,
/* reply= */ NULL,
"sbt",
"sit",
*feature,
(int) enable,
UINT64_C(0));

View File

@ -137,6 +137,7 @@ simple_tests += files(
'test-open-file.c',
'test-ordered-set.c',
'test-os-util.c',
'test-osc-context.c',
'test-parse-argument.c',
'test-parse-helpers.c',
'test-path-lookup.c',

View File

@ -0,0 +1,48 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "hexdecoct.h"
#include "osc-context.h"
#include "tests.h"
#include "escape.h"
TEST(osc) {
_cleanup_free_ char *seq = NULL;
log_info("boot");
assert_se(osc_context_open_boot(&seq) >= 0);
hexdump(/* f = */ NULL, seq, SIZE_MAX);
seq = mfree(seq);
assert_se(osc_context_close(SD_ID128_ALLF, &seq) >= 0);
hexdump(/* f = */ NULL, seq, SIZE_MAX);
seq = mfree(seq);
log_info("container");
sd_id128_t id;
assert_se(osc_context_open_container("foobar", &seq, &id) >= 0);
hexdump(/* f = */ NULL, seq, SIZE_MAX);
seq = mfree(seq);
assert_se(osc_context_close(id, &seq) >= 0);
hexdump(/* f = */ NULL, seq, SIZE_MAX);
seq = mfree(seq);
log_info("vm");
assert_se(osc_context_open_vm("foobar", &seq, &id) >= 0);
hexdump(/* f = */ NULL, seq, SIZE_MAX);
seq = mfree(seq);
assert_se(osc_context_close(id, &seq) >= 0);
hexdump(/* f = */ NULL, seq, SIZE_MAX);
seq = mfree(seq);
printf("%s\n", xescape("Schöpfgefäß", NULL));
}
static int intro(void) {
log_show_color(true);
return EXIT_SUCCESS;
}
DEFINE_TEST_MAIN_WITH_INTRO(LOG_INFO, intro);

View File

@ -994,6 +994,21 @@ TEST(pid_get_start_time) {
ASSERT_GE(start_time2, start_time);
}
TEST(getpidfdid_cached) {
int r;
log_info("pid=" PID_FMT, getpid_cached());
uint64_t id;
r = getpidfdid_cached(&id);
if (ERRNO_IS_NEG_NOT_SUPPORTED(r))
log_info("pidfdid not supported");
else {
assert(r >= 0);
log_info("pidfdid=%" PRIu64, id);
}
}
static int intro(void) {
log_show_color(true);
return EXIT_SUCCESS;

View File

@ -29,7 +29,7 @@ static int apply_timestamp(const char *path, struct timespec *ts) {
timespec_load_nsec(ts)) < 0)
return log_oom();
r = write_string_file_full(AT_FDCWD, path, message, WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC|WRITE_STRING_FILE_LABEL, ts);
r = write_string_file_full(AT_FDCWD, path, message, WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC|WRITE_STRING_FILE_LABEL, ts, NULL);
if (r == -EROFS)
log_debug_errno(r, "Cannot create \"%s\", file system is read-only.", path);
else if (r < 0)

View File

@ -47,6 +47,7 @@
#include "main-func.h"
#include "mkdir.h"
#include "netif-util.h"
#include "osc-context.h"
#include "pager.h"
#include "parse-argument.h"
#include "parse-util.h"
@ -2189,8 +2190,15 @@ static int run_virtual_machine(int kvm_device_fd, int vhost_device_fd) {
/* Exit when the child exits */
(void) event_add_child_pidref(event, NULL, &child_pidref, WEXITED, on_child_exit, NULL);
_cleanup_(osc_context_closep) sd_id128_t osc_context_id = SD_ID128_NULL;
_cleanup_(pty_forward_freep) PTYForward *forward = NULL;
if (master >= 0) {
if (!terminal_is_dumb()) {
r = osc_context_open_vm(arg_machine, /* ret_seq= */ NULL, &osc_context_id);
if (r < 0)
return r;
}
r = pty_forward_new(event, master, ptyfwd_flags, &forward);
if (r < 0)
return log_error_errno(r, "Failed to create PTY forwarder: %m");

View File

@ -22,6 +22,11 @@ trap at_exit EXIT
systemctl service-log-level systemd-machined debug
systemctl service-log-level systemd-importd debug
# per request in https://github.com/systemd/systemd/pull/35117
systemctl edit --runtime --stdin 'systemd-nspawn@.service' --drop-in=debug.conf <<EOF
[Service]
Environment=SYSTEMD_LOG_LEVEL=debug
EOF
# Mount temporary directory over /var/lib/machines to not pollute the image
mkdir -p /var/lib/machines
@ -278,13 +283,13 @@ varlinkctl call /run/systemd/machine/io.systemd.Machine io.systemd.Machine.List
# sending TRAP signal
rm -f /var/lib/machines/long-running/trap
varlinkctl call /run/systemd/machine/io.systemd.Machine io.systemd.Machine.Kill '{"name":"long-running", "whom": "leader", "signal": 5}'
timeout 30 bash -c "until test -e /var/lib/machines/long-running/trap; do sleep .5; done"
timeout 120 bash -c "until test -e /var/lib/machines/long-running/trap; do sleep .5; done"
# test io.systemd.Machine.Terminate
long_running_machine_start
rm -f /var/lib/machines/long-running/terminate
varlinkctl call /run/systemd/machine/io.systemd.Machine io.systemd.Machine.Terminate '{"name":"long-running"}'
timeout 10 bash -c "until test -e /var/lib/machines/long-running/terminate; do sleep .5; done"
timeout 30 bash -c "until test -e /var/lib/machines/long-running/terminate; do sleep .5; done"
timeout 30 bash -c "while varlinkctl call /run/systemd/machine/io.systemd.Machine io.systemd.Machine.List '{\"name\":\"long-running\"}'; do sleep 0.5; done"
# test io.systemd.Machine.Register
@ -356,7 +361,7 @@ journalctl --sync
machinectl terminate container-without-os-release
machinectl terminate long-running
# wait for the container being stopped, otherwise acquiring image metadata by io.systemd.MachineImage.List may fail in the below.
timeout 10 bash -c "while machinectl status long-running &>/dev/null; do sleep .5; done"
timeout 30 bash -c "while machinectl status long-running &>/dev/null; do sleep .5; done"
systemctl kill --signal=KILL systemd-nspawn@long-running.service || :
(ip addr show lo | grep -q 192.168.1.100) || ip address add 192.168.1.100/24 dev lo