1
0
mirror of https://github.com/systemd/systemd synced 2026-04-10 09:04:50 +02:00

Compare commits

...

38 Commits

Author SHA1 Message Date
Yu Watanabe
de1253e4c6
Merge pull request #21638 from yuwata/network-dhcp6pd-prefix-lost
network: dhcp6pd: fix prefix lost handling
2021-12-07 02:54:10 +09:00
yangmingtai
5896a9ebdb fix DirectoryNotEmpty when it comes to a Non-directory file 2021-12-07 01:28:07 +09:00
Luca Boccassi
efeecf4010 NEWS: add more entries for v250 2021-12-06 15:58:38 +00:00
Luca Boccassi
11b109223f NEWS: add more entries for v250 2021-12-06 15:29:11 +00:00
Yu Watanabe
2b5587c28f
Merge pull request #21620 from yuwata/udev-path-id
udev/path_id: fix skip_subsystem()
2021-12-06 23:15:43 +09:00
Yu Watanabe
e3a97777ab
Merge pull request #21633 from yuwata/network-route-null-destination
network: route: fix null destination handling
2021-12-06 22:27:37 +09:00
Yu Watanabe
55c3658ba1
Merge pull request #21634 from yuwata/dhcp-header-cleanups
dhcp: trivial header cleanups
2021-12-06 22:26:58 +09:00
Yu Watanabe
da10d2d584 network: dhcp6pd: drop unreachable routes when lease lost 2021-12-06 21:30:57 +09:00
Yu Watanabe
95eb38c8d0 network: route: make route_cancel_request() take Link*
As the Route object may be managed by Manager.
2021-12-06 21:30:57 +09:00
Yu Watanabe
1d44187ce6 network: dhcp6pd: also drop prefix assigned to upstream interface
But do not drop prefixes from downstream which request another uplink.
2021-12-06 21:30:26 +09:00
Yu Watanabe
86a4b84aa9
Merge pull request #21632 from yuwata/network-dhcp6pd-fix-typo-and-split
network: dhcp6pd: fix typo and split file
2021-12-06 21:24:47 +09:00
Yu Watanabe
24888c0b19
Merge pull request #21630 from yuwata/test-network-cleanups
test-network: trivial cleanups
2021-12-06 21:24:26 +09:00
Yu Watanabe
ab106a609b network: eui64 address is supported only ethernet or infiniband
So, this makes prefixstable mode will be used for other interface types.
2021-12-06 21:07:12 +09:00
Zbigniew Jędrzejewski-Szmek
ec1574cd8e
Merge pull request #21454 from bluca/inspect_elf
analyze: add inspect-elf verb to parse package metadata
2021-12-06 12:45:25 +01:00
Pavel Březina
2f121b6fa1 man: fix description of sd_uid_get_sessions 2021-12-06 12:39:03 +01:00
Franck Bui
d5ee050ffc journal: don't remove the flushed flag when journald is stopped
Due to the fact that systemd-journal-flush.service has
"Requires=systemd-journald.service", this service is stopped too when journald
is requested to do so.

However stopping systemd-journal-flush.service implies that journald
relinquishes /var hence implicitly switching back to the volatile storage
mode and removing /run/systemd/journal/flushed.

If journald is started afterwards, it will run in volatile storage mode
regardless of the value of 'Storage=' as it believes now that /var is not yet
ready (because the flushed flag is missing).

Because this flag is mainly an indication for journald that the initialization
of /var/log/journal (during the boot process) has been done,
systemd-journal-flush.service shouldn't be tied to the state of journald itself
but to the state of /var/log/journal, hence to the state of the system.
2021-12-06 11:47:27 +01:00
Joris Hartog
5ef599b324 systemctl: support JSON output for "show-environment"
This commit adds a function which converts a bus message containing the
environment variables to a JSON object and uses this function to support
JSON formatted output for the "systemctl show-environment" command.

Fixes #21348
2021-12-06 11:40:52 +01:00
Zbigniew Jędrzejewski-Szmek
dfaf3ec1bf
Merge pull request #21621 from mrc0mmand/lgtm-false-positive
lgtm: ignore certain cleanup functions
2021-12-06 11:31:38 +01:00
Bastien Nocera
213455e26a hwdb: Allow console users access to rfkill
This rule has been shipped in Fedora's gnome-bluetooth package for 10
years and is used by the gnome-settings-daemon rfkill plugin (used by
gnome-bluetooth, gnome-shell, and gnome-control-center) to monitor
and change software rfkill switch settings.
2021-12-06 11:26:29 +01:00
Urs Ritzmann
25060a570c sd_bus_get_timeout: fix timeout value doc
The documentation of sd_bus_get_timeout wrongfully states that the returned time-value is relative. In fact, it is an absolute value which is based of CLOCK_MONOTONIC. This change corrects that documentation.
2021-12-06 11:21:48 +01:00
Yu Watanabe
133f65ef2c test-network: start dhcpd after address is assigned 2021-12-06 19:18:55 +09:00
Yu Watanabe
5f7f1f824f test-network: make start_isc_dhcpd() take IP version 2021-12-06 19:18:55 +09:00
Yu Watanabe
d5ebcf6533 network: split networkd-dhcp6.c
This moves DHCPv6 prefix delegation related functions to
networkd-dhcp-prefix-delegation.c.
2021-12-06 19:17:09 +09:00
Yu Watanabe
ba466f0d4e network: dhcp6pd: fix copy-and-paste error 2021-12-06 19:17:09 +09:00
Yu Watanabe
cf477495d6 network: route: handle null address with non-zero prefixlen correctly
Previously, even if a link has a route to e.g. ::/96, default gateway
via ::1.2.3.4 cannot be configured.
2021-12-06 19:16:17 +09:00
Yu Watanabe
b489d6a26e network: route: logs null address with non-zero prefixlen correctly 2021-12-06 19:16:17 +09:00
Yu Watanabe
85ede495cc dhcp: fix indentation and alignment 2021-12-06 19:15:42 +09:00
Yu Watanabe
d262928879 dhcp6: drop unnecessary space 2021-12-06 19:15:41 +09:00
Zbigniew Jędrzejewski-Szmek
79fa910333
Merge pull request #21623 from nabijaczleweli/ekstrahuje
man/kernel-install clarifications
2021-12-06 11:10:40 +01:00
Yu Watanabe
6885a857e4 udev/path-id: comment why USB host number is dropped from the PATH_ID
Closes #21617.

The comment is borrowed from https://github.com/systemd/systemd/pull/21620#discussion_r762521508.
2021-12-06 16:06:04 +09:00
Yu Watanabe
56615f203b udev/path_id: fix skip_subsystem()
This partially reverts d340bdd1bd435e9f5524f4246feaf38511b2ff45.

The function previously drops multiple except for the last parents
which matches the specified subsystem.
But the commit d340bdd1bd435e9f5524f4246feaf38511b2ff45 drops all
parents.

E.g. input is pci-pci-pci-usb-usb-usb, then
Before d340bdd: pci-pci-pci-usb
After d340bdd: pci-pci-pci
2021-12-06 16:01:33 +09:00
Frantisek Sumsal
c8fec8bf9b lgtm: detect more possible problematic scenarios
1) don't ignore stack-allocated variables, since they may hide
   heap-allocated stuff (compound types)
2) check if there's a return between the variable declaration and its
   initialization; if so, treat the variable as uninitialized
3) introduction of 2) increased the query runtime exponentially, so
   introduce some optimizations to bring it back to some reasonable
   values
2021-12-05 22:47:14 +01:00
наб
2a0ad72611
kernel-install: fix MACHINE_ID extraction behaviour description 2021-12-05 17:00:22 +01:00
наб
22a81fe49b
kernel-install: note the default $PRETTY_NAME if os-release wasn't found and that only 90-loaderentry uses it 2021-12-05 16:44:49 +01:00
наб
595fd662d4
kernel-install: note that 90-loaderentry will also use /usr/lib/k/cmdline 2021-12-05 16:44:48 +01:00
Frantisek Sumsal
af18682136 lgtm: ignore certain cleanup functions
as they don't do any illegal stuff even when used with an uninitialized
variable.
2021-12-05 15:53:22 +01:00
Luca Boccassi
917e655457 analyze: add inspect-elf verb to parse package metadata
Parses and prints package metadata from executables, libraries and core files

$ systemd-analyze inspect-elf /tmp/core ../fsverity-utils/fsverityb /bin/bash --json=off --no-pager
__________________________
           path: /tmp/core
        elfType: coredump
elfArchitecture: AMD x86-64

    module name: /tmp/crash
           type: deb
           name: hello
        version: 1.0
   architecture: amd64
             os: debian
      osVersion: 11
        buildId: b33541096a09c29a0ba4ec5c69364a2711b7c269

    module name: /usr/lib/x86_64-linux-gnu/libc-2.31.so
           type: deb
           name: hello
        version: 1.0
   architecture: amd64
             os: debian
      osVersion: 11
        buildId: 54eef5ce96cf37cb175b0d93186836ca1caf470c

    module name: /usr/lib/x86_64-linux-gnu/ld-2.31.so
           type: deb
           name: hello
        version: 1.0
   architecture: amd64
             os: debian
      osVersion: 11
        buildId: 32438eb3b034da54caf58c7a65446639f7cfe274
__________________________________________________________________
           path: /home/luca/git/systemd/../fsverity-utils/fsverity
        elfType: executable
elfArchitecture: AMD x86-64

           type: deb
           name: fsverity-utils
        version: 1.3-1
   architecture: amd64
             os: debian
   debugInfoUrl: https://debuginfod.debian.net
        buildId: 05b899e6ee0d3653e20458719b202ed3ca8d566f
_________________________
           path: /bin/bash
        elfType: executable
elfArchitecture: AMD x86-64

        buildId: 4fef260f60e257d2dbd4126bf8add83837aea190
$
$ systemd-analyze inspect-elf /tmp/core ../fsverity-utils/fsverity /bin/bash /tmp/core.test-condition.1000.f9b9a84a9fd1482c9702d6afa6f6934b.37640.1637083078000000 --json=pretty --no-pager
{
	"elfType" : "coredump",
	"elfArchitecture" : "AMD x86-64",
	"/home/bluca/git/fsverity-utils/fsverity" : {
		"type" : "deb",
		"name" : "fsverity-utils",
		"version" : "1.3-1",
		"buildId" : "7c895ecd2a271f93e96268f479fdc3c64a2ec4ee"
	},
	"/home/bluca/git/fsverity-utils/libfsverity.so.0" : {
		"type" : "deb",
		"name" : "fsverity-utils",
		"version" : "1.3-1",
		"buildId" : "b5e428254abf14237b0ae70ed85fffbb98a78f88"
	}
}
{
	"elfType" : "executable",
	"elfArchitecture" : "AMD x86-64",
	"/home/bluca/git/systemd/../fsverity-utils/fsverity" : {
		"type" : "deb",
		"name" : "fsverity-utils",
		"version" : "1.3-1",
		"buildId" : "7c895ecd2a271f93e96268f479fdc3c64a2ec4ee"
	}
}
{
	"elfType" : "executable",
	"elfArchitecture" : "AMD x86-64",
	"/bin/bash" : {
		"buildId" : "3313b4cb119dcce16927a9b6cc61dcd97dfc4d59"
	}
}
{
	"elfType" : "coredump",
	"elfArchitecture" : "AMD x86-64"
}
2021-11-30 23:14:07 +00:00
Luca Boccassi
d48c2721b6 elf-util: add function to parse metadata out of ELF objects
Parse the packaging metadata from an ELF object, if any, and
print a pretty table following the spec defined at:
https://systemd.io/COREDUMP_PACKAGE_METADATA/
2021-11-30 23:14:07 +00:00
41 changed files with 1665 additions and 1175 deletions

View File

@ -16,22 +16,11 @@
import cpp import cpp
import semmle.code.cpp.controlflow.StackVariableReachability import semmle.code.cpp.controlflow.StackVariableReachability
/** /** Auxiliary predicate: List cleanup functions we want to explicitly ignore
* Auxiliary predicate: Types that don't require initialization * since they don't do anything illegal even when the variable is uninitialized
* before they are used, since they're stack-allocated.
*/ */
predicate allocatedType(Type t) { predicate cleanupFunctionDenyList(string fun) {
/* Arrays: "int foo[1]; foo[0] = 42;" is ok. */ fun = "erase_char"
t instanceof ArrayType
or
/* Structs: "struct foo bar; bar.baz = 42" is ok. */
t instanceof Class
or
/* Typedefs to other allocated types are fine. */
allocatedType(t.(TypedefType).getUnderlyingType())
or
/* Type specifiers don't affect whether or not a type is allocated. */
allocatedType(t.getUnspecifiedType())
} }
/** /**
@ -40,11 +29,11 @@ predicate allocatedType(Type t) {
*/ */
DeclStmt declWithNoInit(LocalVariable v) { DeclStmt declWithNoInit(LocalVariable v) {
result.getADeclaration() = v and result.getADeclaration() = v and
not exists(v.getInitializer()) and not v.hasInitializer() and
/* The variable has __attribute__((__cleanup__(...))) set */ /* The variable has __attribute__((__cleanup__(...))) set */
v.getAnAttribute().hasName("cleanup") and v.getAnAttribute().hasName("cleanup") and
/* The type of the variable is not stack-allocated. */ /* Check if the cleanup function is not on a deny list */
exists(Type t | t = v.getType() | not allocatedType(t)) not cleanupFunctionDenyList(v.getAnAttribute().getAnArgument().getValueText())
} }
class UninitialisedLocalReachability extends StackVariableReachability { class UninitialisedLocalReachability extends StackVariableReachability {
@ -69,7 +58,29 @@ class UninitialisedLocalReachability extends StackVariableReachability {
override predicate isBarrier(ControlFlowNode node, StackVariable v) { override predicate isBarrier(ControlFlowNode node, StackVariable v) {
// only report the _first_ possibly uninitialized use // only report the _first_ possibly uninitialized use
useOfVar(v, node) or useOfVar(v, node) or
definitionBarrier(v, node) (
/* If there's an return statement somewhere between the variable declaration
* and a possible definition, don't accept is as a valid initialization.
*
* E.g.:
* _cleanup_free_ char *x;
* ...
* if (...)
* return;
* ...
* x = malloc(...);
*
* is not a valid initialization, since we might return from the function
* _before_ the actual iniitialization (emphasis on _might_, since we
* don't know if the return statement might ever evaluate to true).
*/
definitionBarrier(v, node) and
not exists(ReturnStmt rs |
/* The attribute check is "just" a complexity optimization */
v.getFunction() = rs.getEnclosingFunction() and v.getAnAttribute().hasName("cleanup") |
rs.getLocation().isBefore(node.getLocation())
)
)
} }
} }

17
NEWS
View File

@ -366,6 +366,11 @@ CHANGES WITH 250 in spe:
non-essential output. It's honored by the "dot", "syscall-filter", non-essential output. It's honored by the "dot", "syscall-filter",
"filesystems" commands. "filesystems" commands.
* systemd-analyze learnt a new inspect-elf verb that parses ELF core
files, binaries and executables and prints metadata information,
including the build-id and other info described on:
https://systemd.io/COREDUMP_PACKAGE_METADATA/
* systemd-nspawn's --setenv= switch now supports an additional syntax: * systemd-nspawn's --setenv= switch now supports an additional syntax:
if only a variable name is specified (i.e. without being suffixed by if only a variable name is specified (i.e. without being suffixed by
a '=' character and a value) the current value of the environment a '=' character and a value) the current value of the environment
@ -483,6 +488,9 @@ CHANGES WITH 250 in spe:
about what type of camera discovered cameras are (regular or about what type of camera discovered cameras are (regular or
infrared), and in which direction they point (front or back). infrared), and in which direction they point (front or back).
* A new rule to allow console users access to rfkill by default has been
added to hwdb.
* A new build-time meson option "extra-net-naming-schemes=" has been * A new build-time meson option "extra-net-naming-schemes=" has been
added for defining additional naming schemes schemes definitions for added for defining additional naming schemes schemes definitions for
udev's network interface naming logic. This is useful for enterprise udev's network interface naming logic. This is useful for enterprise
@ -654,12 +662,21 @@ CHANGES WITH 250 in spe:
* If a unit uses RuntimeMaxSec, systemctl show will now display it. * If a unit uses RuntimeMaxSec, systemctl show will now display it.
* systemctl show-environment gained support for --output=json.
* pam_systemd will now first try to use the X11 abstract socket, and * pam_systemd will now first try to use the X11 abstract socket, and
fallback to the socket file in /tmp/.X11-unix/ only if that does not work. fallback to the socket file in /tmp/.X11-unix/ only if that does not work.
* systemd-journald will no longer go back to volatile storage regardless of
configuration when its unit is restarted.
* Initial support for the LoongArch architecture has been added * Initial support for the LoongArch architecture has been added
(system calls, defines, etc). (system calls, defines, etc).
* A LICENSES/ directory is now included in the git tree. It contains a README.md
file that explains the licenses used by source files in this repository.
It also contains the text of all applicable licenses as they appear on spdx.org.
CHANGES WITH 249: CHANGES WITH 249:
* When operating on disk images via the --image= switch of various * When operating on disk images via the --image= switch of various

View File

@ -184,13 +184,15 @@
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>
<term> <term>
<filename>/usr/lib/kernel/cmdline</filename>
<filename>/etc/kernel/cmdline</filename> <filename>/etc/kernel/cmdline</filename>
<filename>/proc/cmdline</filename> <filename>/proc/cmdline</filename>
</term> </term>
<listitem> <listitem>
<para>Read by <filename>90-loaderentry.install</filename>. The content of the file <para>Read by <filename>90-loaderentry.install</filename>. The content of the file
<filename>/etc/kernel/cmdline</filename> specifies the kernel command line to use. If that file does not <filename>/etc/kernel/cmdline</filename> specifies the kernel command line to use. If that file does not
exist, <filename>/proc/cmdline</filename> is used.</para> exist, <filename>/usr/lib/kernel/cmdline</filename> is used. If that also does not exist,
<filename>/proc/cmdline</filename> is used.</para>
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>
@ -212,8 +214,9 @@
</term> </term>
<listitem> <listitem>
<para>The content of this file specifies the machine identification <para>The content of this file specifies the machine identification
<replaceable>MACHINE-ID</replaceable>. If it cannot read <filename>/etc/machine-id</filename>, <replaceable>MACHINE-ID</replaceable>. If <filename>$BOOT/Default</filename> exists,
kernel-install will use "Linux" as the machine ID instead.</para> or <filename>/etc/machine-id</filename> doesn't, <command>kernel-install</command>
will use the literal <literal>Default</literal> as the machine ID instead.</para>
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>
@ -222,7 +225,9 @@
<filename>/usr/lib/os-release</filename> <filename>/usr/lib/os-release</filename>
</term> </term>
<listitem> <listitem>
<para>The content of the file specifies the operating system title <replaceable>PRETTY_NAME</replaceable>.</para> <para>Read by <filename>90-loaderentry.install</filename>.
If available, <varname>PRETTY_NAME</varname> is read from these files and used as the title of the boot menu entry.
Otherwise, <literal>Linux <replaceable>KERNEL-VERSION</replaceable></literal> will be used.</para>
</listitem> </listitem>
</varlistentry> </varlistentry>
</variablelist> </variablelist>

View File

@ -74,9 +74,10 @@
without any applied timeout. Note that the returned timeout should be considered only a without any applied timeout. Note that the returned timeout should be considered only a
maximum sleeping time. It is permissible (and even expected) that shorter timeouts are used by maximum sleeping time. It is permissible (and even expected) that shorter timeouts are used by
the calling program, in case other event sources are polled in the same event loop. Note that the calling program, in case other event sources are polled in the same event loop. Note that
the returned time-value is relative and specified in microseconds. When converting this value in the returned time-value is absolute, based of <constant>CLOCK_MONOTONIC</constant> and specified
order to pass it as third argument to <function>poll()</function> (which expects milliseconds), in microseconds. When converting this value in order to pass it as third argument to
care should be taken to use a division that rounds up to ensure the I/O polling operation <function>poll()</function> (which expects relative milliseconds), care should be taken to convert
to a relative time and use a division that rounds up to ensure the I/O polling operation
doesn't sleep for shorter than necessary, which might result in unintended busy looping doesn't sleep for shorter than necessary, which might result in unintended busy looping
(alternatively, use (alternatively, use
<citerefentry project='man-pages'><refentrytitle>ppoll</refentrytitle><manvolnum>2</manvolnum></citerefentry> <citerefentry project='man-pages'><refentrytitle>ppoll</refentrytitle><manvolnum>2</manvolnum></citerefentry>

View File

@ -101,7 +101,7 @@
<parameter>require_active</parameter> parameter controls whether <parameter>require_active</parameter> parameter controls whether
the returned list shall consist of only those sessions where the the returned list shall consist of only those sessions where the
user is currently active (&gt; 0), where the user is currently user is currently active (&gt; 0), where the user is currently
online but possibly inactive (= 0), or logged in at all but online but possibly inactive (= 0), or logged in but
possibly closing the session (&lt; 0). The call returns a possibly closing the session (&lt; 0). The call returns a
<constant>NULL</constant> terminated string array of session <constant>NULL</constant> terminated string array of session
identifiers in <parameter>sessions</parameter> which needs to be identifiers in <parameter>sessions</parameter> which needs to be

View File

@ -681,6 +681,39 @@ $ systemd-analyze verify /tmp/source:alias.service
</programlisting> </programlisting>
</example> </example>
</refsect2> </refsect2>
<refsect2>
<title><command>systemd-analyze inspect-elf <replaceable>FILE</replaceable>...</command></title>
<para>This command will load the specified file(s), and if they are ELF objects (executables,
libraries, core files, etc.) it will parse the embedded packaging metadata, if any, and print
it in a table or json format. See the <ulink url="https://systemd.io/COREDUMP_PACKAGE_METADATA/">
Packaging Metadata</ulink> documentation for more information.</para>
<example>
<title>Table output</title>
<programlisting>$ systemd-analyze inspect-elf --json=pretty /tmp/core.fsverity.1000.f77dac5dc161402aa44e15b7dd9dcf97.58561.1637106137000000
{
"elfType" : "coredump",
"elfArchitecture" : "AMD x86-64",
"/home/bluca/git/fsverity-utils/fsverity" : {
"type" : "deb",
"name" : "fsverity-utils",
"version" : "1.3-1",
"buildId" : "7c895ecd2a271f93e96268f479fdc3c64a2ec4ee"
},
"/home/bluca/git/fsverity-utils/libfsverity.so.0" : {
"type" : "deb",
"name" : "fsverity-utils",
"version" : "1.3-1",
"buildId" : "b5e428254abf14237b0ae70ed85fffbb98a78f88"
}
}
</programlisting>
</example>
</refsect2>
</refsect1> </refsect1>
<refsect1> <refsect1>

View File

@ -2208,7 +2208,8 @@ Table=1234</programlisting></para>
<term><option>eui64</option></term> <term><option>eui64</option></term>
<listitem> <listitem>
<para> <para>
The EUI-64 algorithm will be used to generate an address for that prefix. The EUI-64 algorithm will be used to generate an address for that prefix. Only
supported by Ethernet or InfiniBand interfaces.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
@ -2267,8 +2268,9 @@ Table=1234</programlisting></para>
<para>If no address generation mode is specified (which is the default), or a received <para>If no address generation mode is specified (which is the default), or a received
prefix does not match any of the addresses provided in <literal>prefixstable</literal> prefix does not match any of the addresses provided in <literal>prefixstable</literal>
mode, then the EUI-64 algorithm will be used to form an interface identifier for that mode, then the EUI-64 algorithm will be used for Ethernet or InfiniBand interfaces,
prefix.</para> otherwise <literal>prefixstable</literal> will be used to form an interface identifier for
that prefix.</para>
<para>This setting can be specified multiple times. If an empty string is assigned, then <para>This setting can be specified multiple times. If an empty string is assigned, then
the all previous assignments are cleared.</para> the all previous assignments are cleared.</para>

View File

@ -1338,6 +1338,10 @@ if want_elfutils != 'false' and not skip_deps
libdw = dependency('libdw', libdw = dependency('libdw',
required : want_elfutils == 'true') required : want_elfutils == 'true')
have = libdw.found() have = libdw.found()
# New in elfutils 0.177
conf.set10('HAVE_DWELF_ELF_E_MACHINE_STRING',
have and cc.has_function('dwelf_elf_e_machine_string', dependencies : libdw))
else else
have = false have = false
libdw = [] libdw = []

View File

@ -63,6 +63,7 @@ _systemd_analyze() {
[CAT_CONFIG]='cat-config' [CAT_CONFIG]='cat-config'
[SECURITY]='security' [SECURITY]='security'
[CONDITION]='condition' [CONDITION]='condition'
[INSPECT_ELF]='inspect-elf'
) )
local CONFIGS='systemd/bootchart.conf systemd/coredump.conf systemd/journald.conf local CONFIGS='systemd/bootchart.conf systemd/coredump.conf systemd/journald.conf
@ -169,6 +170,14 @@ _systemd_analyze() {
fi fi
comps=$( __get_services $mode ) comps=$( __get_services $mode )
fi fi
elif __contains_word "$verb" ${VERBS[INSPECT_ELF]}; then
if [[ $cur = -* ]]; then
comps='--help --version --json=off --json=pretty --json=short'
else
comps=$( compgen -A file -- "$cur" )
compopt -o filenames
fi
fi fi
COMPREPLY=( $(compgen -W '$comps' -- "$cur") ) COMPREPLY=( $(compgen -W '$comps' -- "$cur") )

View File

@ -54,6 +54,7 @@
'timestamp:Parse a systemd syntax timestamp' 'timestamp:Parse a systemd syntax timestamp'
'timespan:Parse a systemd syntax timespan' 'timespan:Parse a systemd syntax timespan'
'security:Analyze security settings of a service' 'security:Analyze security settings of a service'
'inspect-elf:Parse and print ELF package metadata'
# log-level, log-target, service-watchdogs have been deprecated # log-level, log-target, service-watchdogs have been deprecated
) )

128
src/analyze/analyze-elf.c Normal file
View File

@ -0,0 +1,128 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "analyze-elf.h"
#include "elf-util.h"
#include "errno-util.h"
#include "fd-util.h"
#include "format-table.h"
#include "format-util.h"
#include "json.h"
#include "path-util.h"
#include "strv.h"
int analyze_elf(char **filenames, JsonFormatFlags json_flags) {
char **filename;
int r;
STRV_FOREACH(filename, filenames) {
_cleanup_(json_variant_unrefp) JsonVariant *package_metadata = NULL;
_cleanup_(table_unrefp) Table *t = NULL;
_cleanup_free_ char *abspath = NULL;
_cleanup_close_ int fd = -1;
r = path_make_absolute_cwd(*filename, &abspath);
if (r < 0)
return log_error_errno(r, "Could not make an absolute path out of \"%s\": %m", *filename);
path_simplify(abspath);
fd = RET_NERRNO(open(abspath, O_RDONLY|O_CLOEXEC));
if (fd < 0)
return log_error_errno(fd, "Could not open \"%s\": %m", abspath);
r = parse_elf_object(fd, abspath, /* fork_disable_dump= */false, NULL, &package_metadata);
if (r < 0)
return log_error_errno(r, "Parsing \"%s\" as ELF object failed: %m", abspath);
t = table_new("", "");
if (!t)
return log_oom();
r = table_set_align_percent(t, TABLE_HEADER_CELL(0), 100);
if (r < 0)
return table_log_add_error(r);
r = table_add_many(
t,
TABLE_STRING, "path:",
TABLE_STRING, abspath);
if (r < 0)
return table_log_add_error(r);
if (package_metadata) {
JsonVariant *module_json;
const char *module_name;
JSON_VARIANT_OBJECT_FOREACH(module_name, module_json, package_metadata) {
const char *field_name;
JsonVariant *field;
/* The ELF type and architecture are added as top-level objects,
* since they are only parsed for the file itself, but the packaging
* metadata is parsed recursively in core files, so there might be
* multiple modules. */
if (STR_IN_SET(module_name, "elfType", "elfArchitecture")) {
_cleanup_free_ char *suffixed = NULL;
suffixed = strjoin(module_name, ":");
if (!suffixed)
return log_oom();
r = table_add_many(
t,
TABLE_STRING, suffixed,
TABLE_STRING, json_variant_string(module_json));
if (r < 0)
return table_log_add_error(r);
continue;
}
/* path/elfType/elfArchitecture come first just once per file,
* then we might have multiple modules, so add a separator between
* them to make the output more readable. */
r = table_add_many(t, TABLE_EMPTY, TABLE_EMPTY);
if (r < 0)
return table_log_add_error(r);
/* In case of core files the module name will be the executable,
* but for binaries/libraries it's just the path, so don't print it
* twice. */
if (!streq(abspath, module_name)) {
r = table_add_many(
t,
TABLE_STRING, "module name:",
TABLE_STRING, module_name);
if (r < 0)
return table_log_add_error(r);
}
JSON_VARIANT_OBJECT_FOREACH(field_name, field, module_json)
if (json_variant_is_string(field)) {
_cleanup_free_ char *suffixed = NULL;
suffixed = strjoin(field_name, ":");
if (!suffixed)
return log_oom();
r = table_add_many(
t,
TABLE_STRING, suffixed,
TABLE_STRING, json_variant_string(field));
if (r < 0)
return table_log_add_error(r);
}
}
}
if (json_flags & JSON_FORMAT_OFF) {
(void) table_set_header(t, true);
r = table_print(t, NULL);
if (r < 0)
return table_log_print_error(r);
} else
json_variant_dump(package_metadata, json_flags, stdout, NULL);
}
return 0;
}

View File

@ -0,0 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include "json.h"
int analyze_elf(char **filenames, JsonFormatFlags json_flags);

View File

@ -13,6 +13,7 @@
#include "alloc-util.h" #include "alloc-util.h"
#include "analyze-condition.h" #include "analyze-condition.h"
#include "analyze-elf.h"
#include "analyze-security.h" #include "analyze-security.h"
#include "analyze-verify.h" #include "analyze-verify.h"
#include "bus-error.h" #include "bus-error.h"
@ -2431,6 +2432,12 @@ static int do_security(int argc, char *argv[], void *userdata) {
/*flags=*/ 0); /*flags=*/ 0);
} }
static int do_elf_inspection(int argc, char *argv[], void *userdata) {
pager_open(arg_pager_flags);
return analyze_elf(strv_skip(argv, 1), arg_json_format_flags);
}
static int help(int argc, char *argv[], void *userdata) { static int help(int argc, char *argv[], void *userdata) {
_cleanup_free_ char *link = NULL, *dot_link = NULL; _cleanup_free_ char *link = NULL, *dot_link = NULL;
int r; int r;
@ -2473,6 +2480,7 @@ static int help(int argc, char *argv[], void *userdata) {
" timestamp TIMESTAMP... Validate a timestamp\n" " timestamp TIMESTAMP... Validate a timestamp\n"
" timespan SPAN... Validate a time span\n" " timespan SPAN... Validate a time span\n"
" security [UNIT...] Analyze security of unit\n" " security [UNIT...] Analyze security of unit\n"
" inspect-elf FILE... Parse and print ELF package metadata\n"
"\nOptions:\n" "\nOptions:\n"
" --recursive-errors=MODE Control which units are verified\n" " --recursive-errors=MODE Control which units are verified\n"
" --offline=BOOL Perform a security review on unit file(s)\n" " --offline=BOOL Perform a security review on unit file(s)\n"
@ -2759,7 +2767,7 @@ static int parse_argv(int argc, char *argv[]) {
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Option --offline= is only supported for security right now."); "Option --offline= is only supported for security right now.");
if (arg_json_format_flags != JSON_FORMAT_OFF && !streq_ptr(argv[optind], "security")) if (arg_json_format_flags != JSON_FORMAT_OFF && !STRPTR_IN_SET(argv[optind], "security", "inspect-elf"))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Option --json= is only supported for security right now."); "Option --json= is only supported for security right now.");
@ -2835,6 +2843,7 @@ static int run(int argc, char *argv[]) {
{ "timestamp", 2, VERB_ANY, 0, test_timestamp }, { "timestamp", 2, VERB_ANY, 0, test_timestamp },
{ "timespan", 2, VERB_ANY, 0, dump_timespan }, { "timespan", 2, VERB_ANY, 0, dump_timespan },
{ "security", VERB_ANY, VERB_ANY, 0, do_security }, { "security", VERB_ANY, VERB_ANY, 0, do_security },
{ "inspect-elf", 2, VERB_ANY, 0, do_elf_inspection },
{} {}
}; };

View File

@ -4,6 +4,8 @@ systemd_analyze_sources = files('''
analyze.c analyze.c
analyze-condition.c analyze-condition.c
analyze-condition.h analyze-condition.h
analyze-elf.c
analyze-elf.h
analyze-verify.c analyze-verify.c
analyze-verify.h analyze-verify.h
analyze-security.c analyze-security.c

View File

@ -215,7 +215,7 @@ static bool path_spec_check_good(PathSpec *s, bool initial, bool from_trigger_no
int k; int k;
k = dir_is_empty(s->path); k = dir_is_empty(s->path);
good = !(k == -ENOENT || k > 0); good = !(IN_SET(k, -ENOENT, -ENOTDIR) || k > 0);
break; break;
} }

View File

@ -84,4 +84,7 @@ ENV{ID_MAKER_TOOL}=="?*", TAG+="uaccess"
# Protocol analyzers # Protocol analyzers
ENV{ID_SIGNAL_ANALYZER}=="?*", ENV{DEVTYPE}=="usb_device", TAG+="uaccess" ENV{ID_SIGNAL_ANALYZER}=="?*", ENV{DEVTYPE}=="usb_device", TAG+="uaccess"
# rfkill / radio killswitches
KERNEL=="rfkill", SUBSYSTEM=="misc", TAG+="uaccess"
LABEL="uaccess_end" LABEL="uaccess_end"

View File

@ -73,6 +73,8 @@ sources = files('''
networkd-conf.h networkd-conf.h
networkd-dhcp-common.c networkd-dhcp-common.c
networkd-dhcp-common.h networkd-dhcp-common.h
networkd-dhcp-prefix-delegation.c
networkd-dhcp-prefix-delegation.h
networkd-dhcp-server-bus.c networkd-dhcp-server-bus.c
networkd-dhcp-server-bus.h networkd-dhcp-server-bus.h
networkd-dhcp-server-static-lease.c networkd-dhcp-server-static-lease.c

View File

@ -4,6 +4,7 @@
#include "sd-id128.h" #include "sd-id128.h"
#include "arphrd-util.h"
#include "id128-util.h" #include "id128-util.h"
#include "memory-util.h" #include "memory-util.h"
#include "networkd-address-generation.h" #include "networkd-address-generation.h"
@ -39,17 +40,19 @@ typedef struct IPv6Token {
sd_id128_t secret_key; sd_id128_t secret_key;
} IPv6Token; } IPv6Token;
static void generate_eui64_address(const Link *link, const struct in6_addr *prefix, struct in6_addr *ret) { static int generate_eui64_address(const Link *link, const struct in6_addr *prefix, struct in6_addr *ret) {
assert(link); assert(link);
assert(prefix); assert(prefix);
assert(ret); assert(ret);
memcpy(ret->s6_addr, prefix, 8); memcpy(ret->s6_addr, prefix, 8);
if (link->iftype == ARPHRD_INFINIBAND) switch (link->iftype) {
case ARPHRD_INFINIBAND:
/* Use last 8 byte. See RFC4391 section 8 */ /* Use last 8 byte. See RFC4391 section 8 */
memcpy(&ret->s6_addr[8], &link->hw_addr.infiniband[INFINIBAND_ALEN - 8], 8); memcpy(&ret->s6_addr[8], &link->hw_addr.infiniband[INFINIBAND_ALEN - 8], 8);
else { break;
case ARPHRD_ETHER:
/* see RFC4291 section 2.5.1 */ /* see RFC4291 section 2.5.1 */
ret->s6_addr[8] = link->hw_addr.ether.ether_addr_octet[0]; ret->s6_addr[8] = link->hw_addr.ether.ether_addr_octet[0];
ret->s6_addr[9] = link->hw_addr.ether.ether_addr_octet[1]; ret->s6_addr[9] = link->hw_addr.ether.ether_addr_octet[1];
@ -59,9 +62,15 @@ static void generate_eui64_address(const Link *link, const struct in6_addr *pref
ret->s6_addr[13] = link->hw_addr.ether.ether_addr_octet[3]; ret->s6_addr[13] = link->hw_addr.ether.ether_addr_octet[3];
ret->s6_addr[14] = link->hw_addr.ether.ether_addr_octet[4]; ret->s6_addr[14] = link->hw_addr.ether.ether_addr_octet[4];
ret->s6_addr[15] = link->hw_addr.ether.ether_addr_octet[5]; ret->s6_addr[15] = link->hw_addr.ether.ether_addr_octet[5];
break;
default:
return log_link_debug_errno(link, SYNTHETIC_ERRNO(EINVAL),
"Token=eui64 is not supported for interface type %s, ignoring.",
strna(arphrd_to_name(link->iftype)));
} }
ret->s6_addr[8] ^= 1 << 1; ret->s6_addr[8] ^= 1 << 1;
return 0;
} }
static bool stable_private_address_is_valid(const struct in6_addr *addr) { static bool stable_private_address_is_valid(const struct in6_addr *addr) {
@ -188,7 +197,8 @@ static int generate_addresses(
switch (j->type) { switch (j->type) {
case ADDRESS_GENERATION_EUI64: case ADDRESS_GENERATION_EUI64:
generate_eui64_address(link, &masked, &addr); if (generate_eui64_address(link, &masked, &addr) < 0)
continue;
break; break;
case ADDRESS_GENERATION_STATIC: case ADDRESS_GENERATION_STATIC:
@ -226,7 +236,12 @@ static int generate_addresses(
if (!addr) if (!addr)
return -ENOMEM; return -ENOMEM;
generate_eui64_address(link, &masked, addr); if (IN_SET(link->iftype, ARPHRD_ETHER, ARPHRD_INFINIBAND))
r = generate_eui64_address(link, &masked, addr);
else
r = generate_stable_private_address(link, app_id, &SD_ID128_NULL, &masked, addr);
if (r < 0)
return r;
r = set_ensure_consume(&addresses, &in6_addr_hash_ops_free, addr); r = set_ensure_consume(&addresses, &in6_addr_hash_ops_free, addr);
if (r < 0) if (r < 0)

View File

@ -1299,7 +1299,7 @@ int config_parse_uplink(
name = &network->router_uplink_name; name = &network->router_uplink_name;
} else if (streq(section, "DHCPv6PrefixDelegation")) { } else if (streq(section, "DHCPv6PrefixDelegation")) {
index = &network->dhcp6_pd_uplink_index; index = &network->dhcp6_pd_uplink_index;
name = &network->dhcp_server_uplink_name; name = &network->dhcp6_pd_uplink_name;
accept_none = false; accept_none = false;
} else } else
assert_not_reached(); assert_not_reached();

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,19 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <stdbool.h>
#include "conf-parser.h"
typedef struct Link Link;
bool link_dhcp6_pd_is_enabled(Link *link);
bool dhcp6_pd_is_uplink(Link *link, Link *target, bool accept_auto);
int dhcp6_pd_find_uplink(Link *link, Link **ret);
bool dhcp6_lease_has_pd_prefix(sd_dhcp6_lease *lease);
int dhcp6_pd_remove(Link *link, bool only_marked);
int dhcp6_request_prefix_delegation(Link *link);
int dhcp6_pd_prefix_acquired(Link *dhcp6_link);
void dhcp6_pd_prefix_lost(Link *dhcp6_link);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp6_pd_subnet_id);

View File

@ -71,7 +71,7 @@ static int dhcp4_remove_address_and_routes(Link *link, bool only_marked) {
if (k < 0) if (k < 0)
r = k; r = k;
route_cancel_request(route); route_cancel_request(route, link);
} }
SET_FOREACH(address, link->addresses) { SET_FOREACH(address, link->addresses) {

File diff suppressed because it is too large Load Diff

View File

@ -2,7 +2,6 @@
#pragma once #pragma once
#include "conf-parser.h" #include "conf-parser.h"
#include "in-addr-util.h"
#include "macro.h" #include "macro.h"
typedef enum DHCP6ClientStartMode { typedef enum DHCP6ClientStartMode {
@ -17,13 +16,10 @@ typedef struct Link Link;
typedef struct Request Request; typedef struct Request Request;
bool link_dhcp6_with_address_enabled(Link *link); bool link_dhcp6_with_address_enabled(Link *link);
bool link_dhcp6_pd_is_enabled(Link *link); int dhcp6_check_ready(Link *link);
int dhcp6_pd_find_uplink(Link *link, Link **ret);
int dhcp6_pd_remove(Link *link, bool only_marked);
int dhcp6_update_mac(Link *link); int dhcp6_update_mac(Link *link);
int dhcp6_start(Link *link); int dhcp6_start(Link *link);
int dhcp6_start_on_ra(Link *link, bool information_request); int dhcp6_start_on_ra(Link *link, bool information_request);
int dhcp6_request_prefix_delegation(Link *link);
int request_process_dhcp6_client(Request *req); int request_process_dhcp6_client(Request *req);
int link_request_dhcp6_client(Link *link); int link_request_dhcp6_client(Link *link);
@ -33,7 +29,6 @@ int link_serialize_dhcp6_client(Link *link, FILE *f);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp6_pd_prefix_hint); CONFIG_PARSER_PROTOTYPE(config_parse_dhcp6_pd_prefix_hint);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp6_mud_url); CONFIG_PARSER_PROTOTYPE(config_parse_dhcp6_mud_url);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp6_client_start_mode); CONFIG_PARSER_PROTOTYPE(config_parse_dhcp6_client_start_mode);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp6_pd_subnet_id);
const char* dhcp6_client_start_mode_to_string(DHCP6ClientStartMode i) _const_; const char* dhcp6_client_start_mode_to_string(DHCP6ClientStartMode i) _const_;
DHCP6ClientStartMode dhcp6_client_start_mode_from_string(const char *s) _pure_; DHCP6ClientStartMode dhcp6_client_start_mode_from_string(const char *s) _pure_;

View File

@ -35,6 +35,7 @@
#include "networkd-bridge-fdb.h" #include "networkd-bridge-fdb.h"
#include "networkd-bridge-mdb.h" #include "networkd-bridge-mdb.h"
#include "networkd-can.h" #include "networkd-can.h"
#include "networkd-dhcp-prefix-delegation.h"
#include "networkd-dhcp-server.h" #include "networkd-dhcp-server.h"
#include "networkd-dhcp4.h" #include "networkd-dhcp4.h"
#include "networkd-dhcp6.h" #include "networkd-dhcp6.h"

View File

@ -90,7 +90,7 @@ static int ndisc_remove(Link *link, struct in6_addr *router) {
if (k < 0) if (k < 0)
r = k; r = k;
route_cancel_request(route); route_cancel_request(route, link);
} }
SET_FOREACH(address, link->addresses) { SET_FOREACH(address, link->addresses) {

View File

@ -15,6 +15,7 @@ _Pragma("GCC diagnostic ignored \"-Wimplicit-fallthrough\"")
#include "networkd-bridge-mdb.h" #include "networkd-bridge-mdb.h"
#include "networkd-can.h" #include "networkd-can.h"
#include "networkd-dhcp-common.h" #include "networkd-dhcp-common.h"
#include "networkd-dhcp-prefix-delegation.h"
#include "networkd-dhcp-server-static-lease.h" #include "networkd-dhcp-server-static-lease.h"
#include "networkd-dhcp-server.h" #include "networkd-dhcp-server.h"
#include "networkd-dhcp4.h" #include "networkd-dhcp4.h"

View File

@ -756,6 +756,7 @@ static Network *network_free(Network *network) {
free(network->dhcp_server_timezone); free(network->dhcp_server_timezone);
free(network->dhcp_server_uplink_name); free(network->dhcp_server_uplink_name);
free(network->router_uplink_name); free(network->router_uplink_name);
free(network->dhcp6_pd_uplink_name);
for (sd_dhcp_lease_server_type_t t = 0; t < _SD_DHCP_LEASE_SERVER_TYPE_MAX; t++) for (sd_dhcp_lease_server_type_t t = 0; t < _SD_DHCP_LEASE_SERVER_TYPE_MAX; t++)
free(network->dhcp_server_emit[t].addresses); free(network->dhcp_server_emit[t].addresses);

View File

@ -9,7 +9,7 @@
#include "dns-domain.h" #include "dns-domain.h"
#include "networkd-address-generation.h" #include "networkd-address-generation.h"
#include "networkd-address.h" #include "networkd-address.h"
#include "networkd-dhcp6.h" #include "networkd-dhcp-prefix-delegation.h"
#include "networkd-link.h" #include "networkd-link.h"
#include "networkd-manager.h" #include "networkd-manager.h"
#include "networkd-network.h" #include "networkd-network.h"

View File

@ -116,7 +116,7 @@ static bool link_address_is_reachable(Link *link, int family, const union in_add
continue; continue;
if (route->family != family) if (route->family != family)
continue; continue;
if (!in_addr_is_set(route->family, &route->dst)) if (!in_addr_is_set(route->family, &route->dst) && route->dst_prefixlen == 0)
continue; continue;
if (in_addr_prefix_covers(family, &route->dst, route->dst_prefixlen, address) > 0) if (in_addr_prefix_covers(family, &route->dst, route->dst_prefixlen, address) > 0)
return true; return true;

View File

@ -558,7 +558,7 @@ static void log_route_debug(const Route *route, const char *str, const Link *lin
return; return;
(void) network_config_state_to_string_alloc(route->state, &state); (void) network_config_state_to_string_alloc(route->state, &state);
if (in_addr_is_set(route->family, &route->dst)) if (in_addr_is_set(route->family, &route->dst) || route->dst_prefixlen > 0)
(void) in_addr_prefix_to_string(route->family, &route->dst, route->dst_prefixlen, &dst); (void) in_addr_prefix_to_string(route->family, &route->dst, route->dst_prefixlen, &dst);
if (in_addr_is_set(route->family, &route->src)) if (in_addr_is_set(route->family, &route->src))
(void) in_addr_to_string(route->family, &route->src, &src); (void) in_addr_to_string(route->family, &route->src, &src);
@ -1260,24 +1260,25 @@ static int route_configure(
return 0; return 0;
} }
void route_cancel_request(Route *route) { void route_cancel_request(Route *route, Link *link) {
Request req; Request req;
assert(route); assert(route);
link = route->link ?: link;
assert(link);
if (!route_is_requesting(route)) if (!route_is_requesting(route))
return; return;
if (!route->link)
return;
req = (Request) { req = (Request) {
.link = route->link, .link = link,
.type = REQUEST_TYPE_ROUTE, .type = REQUEST_TYPE_ROUTE,
.route = route, .route = route,
}; };
request_drop(ordered_set_get(route->link->manager->request_queue, &req)); request_drop(ordered_set_get(link->manager->request_queue, &req));
route_cancel_requesting(route); route_cancel_requesting(route);
} }

View File

@ -86,7 +86,7 @@ int link_drop_routes(Link *link);
int link_drop_foreign_routes(Link *link); int link_drop_foreign_routes(Link *link);
void link_foreignize_routes(Link *link); void link_foreignize_routes(Link *link);
void route_cancel_request(Route *route); void route_cancel_request(Route *route, Link *link);
int link_request_route( int link_request_route(
Link *link, Link *link,
Route *route, Route *route,

View File

@ -40,6 +40,9 @@ const char *(*sym_dwarf_formstring)(Dwarf_Attribute *);
int (*sym_dwarf_getscopes)(Dwarf_Die *, Dwarf_Addr, Dwarf_Die **); int (*sym_dwarf_getscopes)(Dwarf_Die *, Dwarf_Addr, Dwarf_Die **);
int (*sym_dwarf_getscopes_die)(Dwarf_Die *, Dwarf_Die **); int (*sym_dwarf_getscopes_die)(Dwarf_Die *, Dwarf_Die **);
Elf *(*sym_dwelf_elf_begin)(int); Elf *(*sym_dwelf_elf_begin)(int);
#if HAVE_DWELF_ELF_E_MACHINE_STRING
const char *(*sym_dwelf_elf_e_machine_string)(int);
#endif
ssize_t (*sym_dwelf_elf_gnu_build_id)(Elf *, const void **); ssize_t (*sym_dwelf_elf_gnu_build_id)(Elf *, const void **);
int (*sym_dwarf_tag)(Dwarf_Die *); int (*sym_dwarf_tag)(Dwarf_Die *);
Dwfl_Module *(*sym_dwfl_addrmodule)(Dwfl *, Dwarf_Addr); Dwfl_Module *(*sym_dwfl_addrmodule)(Dwfl *, Dwarf_Addr);
@ -90,6 +93,9 @@ static int dlopen_dw(void) {
DLSYM_ARG(dwarf_diename), DLSYM_ARG(dwarf_diename),
DLSYM_ARG(dwelf_elf_gnu_build_id), DLSYM_ARG(dwelf_elf_gnu_build_id),
DLSYM_ARG(dwelf_elf_begin), DLSYM_ARG(dwelf_elf_begin),
#if HAVE_DWELF_ELF_E_MACHINE_STRING
DLSYM_ARG(dwelf_elf_e_machine_string),
#endif
DLSYM_ARG(dwfl_addrmodule), DLSYM_ARG(dwfl_addrmodule),
DLSYM_ARG(dwfl_frame_pc), DLSYM_ARG(dwfl_frame_pc),
DLSYM_ARG(dwfl_module_addrdie), DLSYM_ARG(dwfl_module_addrdie),
@ -260,7 +266,8 @@ static int thread_callback(Dwfl_Thread *thread, void *userdata) {
return DWARF_CB_OK; return DWARF_CB_OK;
} }
static int parse_package_metadata(const char *name, JsonVariant *id_json, Elf *elf, StackContext *c) { static int parse_package_metadata(const char *name, JsonVariant *id_json, Elf *elf, bool *ret_interpreter_found, StackContext *c) {
bool interpreter_found = false;
size_t n_program_headers; size_t n_program_headers;
int r; int r;
@ -286,9 +293,14 @@ static int parse_package_metadata(const char *name, JsonVariant *id_json, Elf *e
/* Package metadata is in PT_NOTE headers. */ /* Package metadata is in PT_NOTE headers. */
program_header = sym_gelf_getphdr(elf, i, &mem); program_header = sym_gelf_getphdr(elf, i, &mem);
if (!program_header || program_header->p_type != PT_NOTE) if (!program_header || (program_header->p_type != PT_NOTE && program_header->p_type != PT_INTERP))
continue; continue;
if (program_header->p_type == PT_INTERP) {
interpreter_found = true;
continue;
}
/* Fortunately there is an iterator we can use to walk over the /* Fortunately there is an iterator we can use to walk over the
* elements of a PT_NOTE program header. We are interested in the * elements of a PT_NOTE program header. We are interested in the
* note with type. */ * note with type. */
@ -348,11 +360,17 @@ static int parse_package_metadata(const char *name, JsonVariant *id_json, Elf *e
if (r < 0) if (r < 0)
return log_error_errno(r, "set_put_strdup failed: %m"); return log_error_errno(r, "set_put_strdup failed: %m");
if (ret_interpreter_found)
*ret_interpreter_found = interpreter_found;
return 1; return 1;
} }
} }
} }
if (ret_interpreter_found)
*ret_interpreter_found = interpreter_found;
/* Didn't find package metadata for this module - that's ok, just go to the next. */ /* Didn't find package metadata for this module - that's ok, just go to the next. */
return 0; return 0;
} }
@ -426,7 +444,7 @@ static int module_callback(Dwfl_Module *mod, void **userdata, const char *name,
* to the ELF object first. We might be lucky and just get it from elfutils. */ * to the ELF object first. We might be lucky and just get it from elfutils. */
elf = sym_dwfl_module_getelf(mod, &bias); elf = sym_dwfl_module_getelf(mod, &bias);
if (elf) { if (elf) {
r = parse_package_metadata(name, id_json, elf, c); r = parse_package_metadata(name, id_json, elf, NULL, c);
if (r < 0) if (r < 0)
return DWARF_CB_ABORT; return DWARF_CB_ABORT;
if (r > 0) if (r > 0)
@ -468,7 +486,7 @@ static int module_callback(Dwfl_Module *mod, void **userdata, const char *name,
_cleanup_(sym_elf_endp) Elf *memelf = sym_elf_memory(data->d_buf, data->d_size); _cleanup_(sym_elf_endp) Elf *memelf = sym_elf_memory(data->d_buf, data->d_size);
if (!memelf) if (!memelf)
continue; continue;
r = parse_package_metadata(name, id_json, memelf, c); r = parse_package_metadata(name, id_json, memelf, NULL, c);
if (r < 0) if (r < 0)
return DWARF_CB_ABORT; return DWARF_CB_ABORT;
if (r > 0) if (r > 0)
@ -546,6 +564,119 @@ static int parse_core(int fd, const char *executable, char **ret, JsonVariant **
return 0; return 0;
} }
static int parse_elf(int fd, const char *executable, char **ret, JsonVariant **ret_package_metadata) {
_cleanup_(json_variant_unrefp) JsonVariant *package_metadata = NULL, *elf_metadata = NULL;
_cleanup_(set_freep) Set *modules = NULL;
_cleanup_free_ char *buf = NULL; /* buf should be freed last, c.f closed first (via stack_context_destroy) */
_cleanup_(stack_context_destroy) StackContext c = {
.package_metadata = &package_metadata,
.modules = &modules,
};
const char *elf_architecture = NULL, *elf_type;
GElf_Ehdr elf_header;
size_t sz = 0;
int r;
assert(fd >= 0);
if (lseek(fd, 0, SEEK_SET) == (off_t) -1)
return log_warning_errno(errno, "Failed to seek to beginning of the ELF file: %m");
if (ret) {
c.f = open_memstream_unlocked(&buf, &sz);
if (!c.f)
return log_oom();
}
sym_elf_version(EV_CURRENT);
c.elf = sym_elf_begin(fd, ELF_C_READ_MMAP, NULL);
if (!c.elf)
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL), "Could not parse ELF file, elf_begin() failed: %s", sym_elf_errmsg(sym_elf_errno()));
if (!sym_gelf_getehdr(c.elf, &elf_header))
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL), "Could not parse ELF file, gelf_getehdr() failed: %s", sym_elf_errmsg(sym_elf_errno()));
if (elf_header.e_type == ET_CORE) {
_cleanup_free_ char *out = NULL;
r = parse_core(fd, executable, ret ? &out : NULL, &package_metadata);
if (r < 0)
return log_warning_errno(r, "Failed to inspect core file: %m");
if (out)
fprintf(c.f, "%s", out);
elf_type = "coredump";
} else {
_cleanup_(json_variant_unrefp) JsonVariant *id_json = NULL;
bool interpreter_found = false;
r = parse_buildid(NULL, c.elf, executable, &c, &id_json);
if (r < 0)
return log_warning_errno(r, "Failed to parse build-id of ELF file: %m");
r = parse_package_metadata(executable, id_json, c.elf, &interpreter_found, &c);
if (r < 0)
return log_warning_errno(r, "Failed to parse package metadata of ELF file: %m");
/* If we found a build-id and nothing else, return at least that. */
if (!package_metadata && id_json) {
r = json_build(&package_metadata, JSON_BUILD_OBJECT(JSON_BUILD_PAIR(executable, JSON_BUILD_VARIANT(id_json))));
if (r < 0)
return log_warning_errno(r, "Failed to build JSON object: %m");
}
if (interpreter_found)
elf_type = "executable";
else
elf_type = "library";
}
/* Note that e_type is always DYN for both executables and libraries, so we can't tell them apart from the header,
* but we will search for the PT_INTERP section when parsing the metadata. */
r = json_build(&elf_metadata, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("elfType", JSON_BUILD_STRING(elf_type))));
if (r < 0)
return log_warning_errno(r, "Failed to build JSON object: %m");
#if HAVE_DWELF_ELF_E_MACHINE_STRING
elf_architecture = sym_dwelf_elf_e_machine_string(elf_header.e_machine);
#endif
if (elf_architecture) {
_cleanup_(json_variant_unrefp) JsonVariant *json_architecture = NULL;
r = json_build(&json_architecture,
JSON_BUILD_OBJECT(JSON_BUILD_PAIR("elfArchitecture", JSON_BUILD_STRING(elf_architecture))));
if (r < 0)
return log_warning_errno(r, "Failed to build JSON object: %m");
r = json_variant_merge(&elf_metadata, json_architecture);
if (r < 0)
return log_warning_errno(r, "Failed to merge JSON objects: %m");
if (ret)
fprintf(c.f, "ELF object binary architecture: %s\n", elf_architecture);
}
/* We always at least have the ELF type, so merge that (and possibly the arch). */
r = json_variant_merge(&elf_metadata, package_metadata);
if (r < 0)
return log_warning_errno(r, "Failed to merge JSON objects: %m");
if (ret) {
r = fflush_and_check(c.f);
if (r < 0)
return log_warning_errno(r, "Could not parse ELF file, flushing file buffer failed: %m");
c.f = safe_fclose(c.f);
*ret = TAKE_PTR(buf);
}
if (ret_package_metadata)
*ret_package_metadata = TAKE_PTR(elf_metadata);
return 0;
}
int parse_elf_object(int fd, const char *executable, bool fork_disable_dump, char **ret, JsonVariant **ret_package_metadata) { int parse_elf_object(int fd, const char *executable, bool fork_disable_dump, char **ret, JsonVariant **ret_package_metadata) {
_cleanup_close_pair_ int error_pipe[2] = { -1, -1 }, return_pipe[2] = { -1, -1 }, json_pipe[2] = { -1, -1 }; _cleanup_close_pair_ int error_pipe[2] = { -1, -1 }, return_pipe[2] = { -1, -1 }, json_pipe[2] = { -1, -1 };
_cleanup_(json_variant_unrefp) JsonVariant *package_metadata = NULL; _cleanup_(json_variant_unrefp) JsonVariant *package_metadata = NULL;
@ -610,7 +741,7 @@ int parse_elf_object(int fd, const char *executable, bool fork_disable_dump, cha
goto child_fail; goto child_fail;
} }
r = parse_core(fd, executable, ret ? &buf : NULL, ret_package_metadata ? &package_metadata : NULL); r = parse_elf(fd, executable, ret ? &buf : NULL, ret_package_metadata ? &package_metadata : NULL);
if (r < 0) if (r < 0)
goto child_fail; goto child_fail;

View File

@ -8,6 +8,40 @@
#include "systemctl-util.h" #include "systemctl-util.h"
#include "systemctl.h" #include "systemctl.h"
static int json_transform_message(sd_bus_message *m, JsonVariant **ret) {
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
char *text;
int r;
assert(m);
assert(ret);
while ((r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &text)) > 0) {
_cleanup_(json_variant_unrefp) JsonVariant *w = NULL;
char *sep = strchr(text, '=');
if (!sep)
return log_error_errno(SYNTHETIC_ERRNO(EUCLEAN),
"Invalid environment block");
*sep++ = '\0';
r = json_build(&w, JSON_BUILD_OBJECT(JSON_BUILD_PAIR(text, JSON_BUILD_STRING(sep))));
if (r < 0)
return r;
r = json_variant_merge(&v, w);
if (r < 0)
return r;
}
if (r < 0)
return bus_log_parse_error(r);
*ret = TAKE_PTR(v);
return r;
}
static int print_variable(const char *s) { static int print_variable(const char *s) {
const char *sep; const char *sep;
_cleanup_free_ char *esc = NULL; _cleanup_free_ char *esc = NULL;
@ -46,6 +80,16 @@ int show_environment(int argc, char *argv[], void *userdata) {
if (r < 0) if (r < 0)
return bus_log_parse_error(r); return bus_log_parse_error(r);
if (OUTPUT_MODE_IS_JSON(arg_output)) {
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
JsonFormatFlags flags = output_mode_to_json_format_flags(arg_output);
r = json_transform_message(reply, &v);
if (r < 0)
return r;
json_variant_dump(v, flags, stdout, NULL);
} else {
while ((r = sd_bus_message_read_basic(reply, SD_BUS_TYPE_STRING, &text)) > 0) { while ((r = sd_bus_message_read_basic(reply, SD_BUS_TYPE_STRING, &text)) > 0) {
r = print_variable(text); r = print_variable(text);
if (r < 0) if (r < 0)
@ -53,6 +97,7 @@ int show_environment(int argc, char *argv[], void *userdata) {
} }
if (r < 0) if (r < 0)
return bus_log_parse_error(r); return bus_log_parse_error(r);
}
r = sd_bus_message_exit_container(reply); r = sd_bus_message_exit_container(reply);
if (r < 0) if (r < 0)

View File

@ -80,19 +80,29 @@ static int format_lun_number(sd_device *dev, char **path) {
} }
static sd_device *skip_subsystem(sd_device *dev, const char *subsys) { static sd_device *skip_subsystem(sd_device *dev, const char *subsys) {
sd_device *parent;
assert(dev); assert(dev);
assert(subsys); assert(subsys);
for (;;) { /* Unlike the function name, this drops multiple parent devices EXCEPT FOR THE LAST ONE.
* The last one will be dropped at the end of the loop in builtin_path_id().
* E.g.
* Input: /sys/devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.0
* Output: /sys/devices/pci0000:00/0000:00:14.0/usb1
*/
for (parent = dev; ; ) {
const char *subsystem; const char *subsystem;
if (sd_device_get_subsystem(dev, &subsystem) < 0) if (sd_device_get_subsystem(parent, &subsystem) < 0)
break; break;
if (!streq(subsystem, subsys)) if (!streq(subsystem, subsys))
break; break;
if (sd_device_get_parent(dev, &dev) < 0) dev = parent;
if (sd_device_get_parent(dev, &parent) < 0)
break; break;
} }
@ -493,6 +503,10 @@ static sd_device *handle_usb(sd_device *parent, char **path) {
return parent; return parent;
port++; port++;
/* USB host number may change across reboots (and probably even without reboot). The part after
* USB host number is determined by device topology and so does not change. Hence, drop the
* host number and always use '0' instead. */
path_prepend(path, "usb-0:%s", port); path_prepend(path, "usb-0:%s", port);
return skip_subsystem(parent, "usb"); return skip_subsystem(parent, "usb");
} }

View File

@ -547,9 +547,9 @@ def remove_dnsmasq_log_file():
if os.path.exists(dnsmasq_log_file): if os.path.exists(dnsmasq_log_file):
os.remove(dnsmasq_log_file) os.remove(dnsmasq_log_file)
def start_isc_dhcpd(interface, conf_file): def start_isc_dhcpd(interface, conf_file, ip):
conf_file_path = os.path.join(networkd_ci_path, conf_file) conf_file_path = os.path.join(networkd_ci_path, conf_file)
isc_dhcpd_command = f'dhcpd -6 -cf {conf_file_path} -lf {isc_dhcpd_lease_file} -pf {isc_dhcpd_pid_file} {interface}' isc_dhcpd_command = f'dhcpd {ip} -cf {conf_file_path} -lf {isc_dhcpd_lease_file} -pf {isc_dhcpd_pid_file} {interface}'
Path(isc_dhcpd_lease_file).touch() Path(isc_dhcpd_lease_file).touch()
check_output(isc_dhcpd_command) check_output(isc_dhcpd_command)
@ -5047,9 +5047,9 @@ class NetworkdDHCP6PDTests(unittest.TestCase, Utilities):
'13-dummy.netdev', 'dhcp6pd-downstream-dummy99.network') '13-dummy.netdev', 'dhcp6pd-downstream-dummy99.network')
start_networkd() start_networkd()
self.wait_online(['veth-peer:carrier']) self.wait_online(['veth-peer:routable'])
start_isc_dhcpd('veth-peer', 'isc-dhcpd-dhcp6pd.conf') start_isc_dhcpd('veth-peer', 'isc-dhcpd-dhcp6pd.conf', ip='-6')
self.wait_online(['veth-peer:routable', 'veth99:routable', 'test1:routable', 'dummy98:routable', 'dummy99:degraded', self.wait_online(['veth99:routable', 'test1:routable', 'dummy98:routable', 'dummy99:degraded',
'veth97:routable', 'veth97-peer:routable', 'veth98:routable', 'veth98-peer:routable']) 'veth97:routable', 'veth97-peer:routable', 'veth98:routable', 'veth98-peer:routable'])
print('### ip -6 address show dev veth-peer scope global') print('### ip -6 address show dev veth-peer scope global')

View File

@ -19,6 +19,9 @@ systemctl daemon-reload
systemctl show-environment | grep -q '^PATH=.*testaddition$' systemctl show-environment | grep -q '^PATH=.*testaddition$'
systemctl show-environment | grep -q '^FOO=BAR$' systemctl show-environment | grep -q '^FOO=BAR$'
# Check that JSON output is supported
systemctl show-environment --output=json | grep -q '^{.*"FOO":"BAR".*}$'
# Drop both # Drop both
systemctl unset-environment FOO PATH systemctl unset-environment FOO PATH

View File

@ -596,6 +596,10 @@ set -e
rm /tmp/img/usr/lib/systemd/system/testfile.service rm /tmp/img/usr/lib/systemd/system/testfile.service
if systemd-analyze --version | grep -q -F "+ELFUTILS"; then
systemd-analyze inspect-elf --json=short /lib/systemd/systemd | grep -q -F '"elfType":"executable"'
fi
systemd-analyze log-level info systemd-analyze log-level info
echo OK >/testok echo OK >/testok

View File

@ -11,7 +11,6 @@
Description=Flush Journal to Persistent Storage Description=Flush Journal to Persistent Storage
Documentation=man:systemd-journald.service(8) man:journald.conf(5) Documentation=man:systemd-journald.service(8) man:journald.conf(5)
DefaultDependencies=no DefaultDependencies=no
Requires=systemd-journald.service
After=systemd-journald.service systemd-remount-fs.service After=systemd-journald.service systemd-remount-fs.service
Before=systemd-tmpfiles-setup.service Before=systemd-tmpfiles-setup.service
RequiresMountsFor=/var/log/journal RequiresMountsFor=/var/log/journal