mirror of
https://github.com/systemd/systemd.git
synced 2025-03-06 00:58:29 +03:00
factory-reset: rework infrastructure, make it work with gpt-auto, and add support for resetting TPM as part of factory reset (#36512)
This commit is contained in:
commit
c22948f6c2
6
NEWS
6
NEWS
@ -76,6 +76,12 @@ CHANGES WITH 258 in spe:
|
||||
*now* to include a native systemd unit file instead of a legacy
|
||||
System V script to retain compatibility with future systemd releases.
|
||||
|
||||
* Support for systemd-repart's FactoryReset EFI variable has been
|
||||
deprecated and support for it will be removed in v260. Use the newer,
|
||||
more generic FactoryResetRequest variable instead, which can be
|
||||
managed by "systemd-factory-reset request" and "systemd-factory-reset
|
||||
complete".
|
||||
|
||||
* To work around limitations of X11's keyboard handling systemd's
|
||||
keyboard mapping hardware database (hwdb.d/60-keyboard.hwdb) so far
|
||||
mapped the microphone mute and touchpad on/off/toggle keys to the
|
||||
|
7
TODO
7
TODO
@ -125,6 +125,9 @@ Deprecations and removals:
|
||||
* Once baseline is 4.13, remove support for INTERFACE_OLD= checks in "udevadm
|
||||
trigger"'s waiting logic, since we can then rely on uuid-tagged uevents
|
||||
|
||||
* In v260: remove support for deprecated FactoryReset EFI variable in
|
||||
systemd-repart, replaced by FactoryResetRequest.
|
||||
|
||||
Features:
|
||||
|
||||
* Maybe rename pkcs7 and public verbs of systemd-keyutil to be more verb like.
|
||||
@ -830,10 +833,6 @@ Features:
|
||||
AllowPeerGroup= that installs additional user/group ACL entries on AF_UNIX
|
||||
sockets.
|
||||
|
||||
* systemd-tpm2-setup should probably have a factory reset logic, i.e. when some
|
||||
kernel command line option is set we reset the TPM (equivalent of tpm2_clear
|
||||
-c owner? or rather echo 5 >/sys/class/tpm/tpm0/ppi/request?).
|
||||
|
||||
* systemd-tpm2-setup should support a mode where we refuse booting if the SRK
|
||||
changed. (Must be opt-in, to not break systems which are supposed to be
|
||||
migratable between PCs)
|
||||
|
@ -819,3 +819,18 @@ systemd-networkd, has been changed by another, unrelated process
|
||||
and will likely result in problems later on.
|
||||
|
||||
Value changed to "@NEWVALUE@", which should be "@OURVALUE@".
|
||||
|
||||
-- 438188861e0b427a9d638a90487a0ca6
|
||||
Subject: TPM clear requested
|
||||
Defined-By: systemd
|
||||
Support: %SUPPORT_URL%
|
||||
Documentation: man:systemd-tpm2-clear.service(8)
|
||||
|
||||
A request to clear the TPM security chip has been issued to the firmware. This
|
||||
is typically done as part of a comprehensive factory reset operation, and
|
||||
ensures that on the next boot process the firmware will reset the TPM, after
|
||||
interactively requesting confirmation by the user.
|
||||
|
||||
Clearing the TPM has the effect of invalidating all keys locked to the TPM,
|
||||
including full disk encryption keys. Because of that care should be taken that
|
||||
access to relevant resources is retained via other means.
|
||||
|
@ -767,3 +767,10 @@ Tools using the Varlink protocol (such as `varlinkctl`) or sd-bus (such as
|
||||
`process`, `session`, `user`, `user-session`, or `group`. Controls the kernel
|
||||
keyring in which `systemd-ask-password` caches the queried password. Defaults
|
||||
to `user`.
|
||||
|
||||
`systemd-tpm2-clear`:
|
||||
|
||||
* `SYSTEMD_TPM2_ALLOW_CLEAR` – takes a boolean. Overrides the effect of the
|
||||
`systemd.factory_reset=` kernel command line option: if set to false,
|
||||
requesting a TPM clearing is skipped, and the command immediately exits
|
||||
successfully.
|
||||
|
137
docs/FACTORY_RESET.md
Normal file
137
docs/FACTORY_RESET.md
Normal file
@ -0,0 +1,137 @@
|
||||
---
|
||||
title: Factory Reset
|
||||
category: Booting
|
||||
layout: default
|
||||
SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
---
|
||||
|
||||
# Factory Reset
|
||||
|
||||
In various scenarios it is important to be able to reset operating systems back
|
||||
into a "factory state", i.e. where all state, user data and configuration is
|
||||
reset so that it resembles the system state when it was originally shipped.
|
||||
|
||||
systemd natively supports a concept of factory reset, that can both act as a
|
||||
specific implementation for UEFI based systems, as well as a series of hook
|
||||
points and a template for implementations on other systems.
|
||||
|
||||
Factory reset always takes place during early boot, i.e. from a well-defined
|
||||
"clean" state. Factory reset operations may be requested from one boot to be
|
||||
executed on the next.
|
||||
|
||||
Specifically, the following concepts are available:
|
||||
|
||||
* The `factory-reset.target` unit may be used to request a factory reset
|
||||
operation and trigger a reboot in order to execute it. It by default executes
|
||||
three services: `systemd-factory-reset-request.service`,
|
||||
`systemd-tpm2-clear.service` and `systemd-factory-reset-reboot.service`.
|
||||
|
||||
* The
|
||||
[`systemd-factory-reset-request.service`](https://www.freedesktop.org/software/systemd/man/latest/systemd-factory-reset-request.service.html)
|
||||
unit is typically invoked via `factory-reset.target`. It requests a factory
|
||||
reset operation for the next boot by setting the `FactoryResetRequest` EFI
|
||||
variable. The EFI variable contains information about the requesting OS, so
|
||||
that multi-boot scenarios are somewhat covered.
|
||||
|
||||
* The
|
||||
[`systemd-tpm2-clear.service`](https://www.freedesktop.org/software/systemd/man/latest/systemd-tpm2-clear.service.html)
|
||||
unit can request a TPM2 clear operation from the firmware on the next
|
||||
boot. It is also invoked via `factory-reset.target`. UEFI firmwares that
|
||||
support TPMs will ask the user for confirmation and then reset the TPM,
|
||||
invalidating all prior keys associated with the security chip and generating
|
||||
a new seed key.
|
||||
|
||||
* The
|
||||
[`systemd-factory-reset-reboot.service`](https://www.freedesktop.org/software/systemd/man/latest/systemd-factory-reset-reboot.service.html)
|
||||
unit automatically reboots the system as part of `factory-reset.target`. It
|
||||
is ordered after `systemd-tpm2-clear.service` and
|
||||
`systemd-factory-reset-request.service` in order to initiate the reboot that
|
||||
is supposed to execute the factory reset operations.
|
||||
|
||||
* The `factory-reset-now.target` unit is started at boot whenever a factory
|
||||
reset is requested for the boot. A factory reset may be requested via a
|
||||
kernel command line option (`systemd.factory_reset=1`) or via the UEFI
|
||||
variable `FactoryResetRequest` (see above). The
|
||||
`systemd-factory-reset-generator` unit generator checks both these conditions
|
||||
and adds `factory-reset-now.target` to the boot transaction, already in the
|
||||
initial RAM disk (initrd).
|
||||
|
||||
* The
|
||||
[`systemd-factory-reset-complete.service`](https://www.freedesktop.org/software/systemd/man/latest/systemd-factory-reset-complete.service.html)
|
||||
unit is invoked after `factory-reset-now.target` and marks the factory reset
|
||||
operation as complete. The boot process then may continue.
|
||||
|
||||
* The
|
||||
[`systemd-repart`](https://www.freedesktop.org/software/systemd/man/latest/systemd-repart.html)
|
||||
tool can take the factory reset logic into account. Either on explicit
|
||||
request via the `--factory-reset=` logic, or automatically derived from the
|
||||
aforementioned kernel command line switch and EFI variable. When invoked for
|
||||
factory reset it will securely erase all partitions marked for that via the
|
||||
`FactoryReset=` setting in its partition definition files. Once that is
|
||||
complete it will execute the usual setup operation, i.e. format new
|
||||
partitions again.
|
||||
|
||||
* The
|
||||
[`systemd-logind.service(8)`](https://www.freedesktop.org/software/systemd/man/latest/systemd-logind.service.html)
|
||||
unit supports automatically binding factory reset to special keypresses
|
||||
(typically long presses), see the
|
||||
[`logind.conf(5)`](https://www.freedesktop.org/software/systemd/man/latest/logind.conf.html)
|
||||
man page.
|
||||
|
||||
* The
|
||||
[`systemd-factory-reset`](https://www.freedesktop.org/software/systemd/man/latest/systemd-factory-reset.html)
|
||||
tool can be used to query the current state of the factory request mechanism,
|
||||
i.e. whether a factory reset is currently being executed, or if one has been
|
||||
requested for the next boot.
|
||||
|
||||
* The `/run/systemd/io.systemd.FactoryReset` Varlink service provides two IPC
|
||||
APIs for working with factory reset: it permits querying whether the local
|
||||
system supports requesting a factory reset by starting
|
||||
`factory-reset.target`. This may be used by UIs to hide or show in the UI an
|
||||
interface to request a factory reset. The Varlink IPC service also reports
|
||||
the current factory reset state, much like the `systemd-factory-reset` tool
|
||||
mentioned above. This may be used by various early boot services that
|
||||
potentially intent to reset system state during a factory reset operation.
|
||||
|
||||
## Exposure in the UI
|
||||
|
||||
If a graphical UI shall expose a factory reset operation it should first check
|
||||
if requesting a factory reset is supported at all via the Varlink service
|
||||
mentioned above. Once a factory reset shall be executed it shall ask for
|
||||
activation of the `factory-reset.target` unit.
|
||||
|
||||
Alternatively, `systemd-logind.service`'s hotkey support may be used, for
|
||||
example to request factory reset if the reboot button is pressed for a long
|
||||
time.
|
||||
|
||||
## Support for non-UEFI Systems
|
||||
|
||||
The above is a relatively bespoke solution for EFI systems. It uses EFI
|
||||
variables as stateful memory to request the factory reset on the next boot.
|
||||
|
||||
On non-EFI systems, a different mechanism should be devised. A service
|
||||
requesting the factory request can then be plugged into
|
||||
`factory-reset.target`. At boot the request should then be fed back to the
|
||||
booted kernel via the `systemd.factory_reset=1` kernel command line option, in
|
||||
order to execute the reset operation.
|
||||
|
||||
## Support for Resetting other Resources than Partitions + TPM
|
||||
|
||||
By default a factory reset implemented with systemd's tools can reset/erase
|
||||
partitions (via `systemd-repart`, see above) and reset the TPM (via
|
||||
`systemd-tpm2-clear.service`, see above).
|
||||
|
||||
In some cases other resources shall be reset/erased too. To support that,
|
||||
define your own service and plug it into `factory-reset-now.target`, ensuring
|
||||
it is ordered before that.
|
||||
|
||||
## Factory Reset via Boot Menu
|
||||
|
||||
Factory reset can also be requested via the boot menu. A simple factory reset
|
||||
(that does not touch the TPM) at boot can be requested via a boot menu item
|
||||
containing the `systemd.factory_reset=1` kernel command line option. A more
|
||||
comprehensive factory reset operation (that also erases the TPM) can be
|
||||
requested by booting with `rd.systemd.unit=factory-reset.target`. Note that the
|
||||
latter will require one reboot (required since that's how TPM resets work),
|
||||
while the former will reset state and continue running without an additional
|
||||
reboot.
|
@ -752,6 +752,15 @@
|
||||
<xi:include href="version-info.xml" xpointer="v245"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>systemd.tpm2_allow_clear=</varname></term>
|
||||
|
||||
<listitem><para>Controls whether to allow clearing of the TPM chip, implemented by
|
||||
<citerefentry><refentrytitle>systemd-tpm2-clear</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v258"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>systemd.tpm2_wait=</varname></term>
|
||||
|
||||
@ -761,6 +770,17 @@
|
||||
<xi:include href="version-info.xml" xpointer="v256"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>systemd.factory_reset=</varname></term>
|
||||
|
||||
<listitem><para>Controls whether to to boot into factory reset mode, implemented by
|
||||
<citerefentry><refentrytitle>systemd-factory-reset-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>systemd-repart</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
|
||||
and other tools.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v258"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
|
@ -942,6 +942,14 @@ manpages = [
|
||||
['30-systemd-environment-d-generator'],
|
||||
'ENABLE_ENVIRONMENT_D'],
|
||||
['systemd-escape', '1', [], ''],
|
||||
['systemd-factory-reset-generator', '8', [], ''],
|
||||
['systemd-factory-reset',
|
||||
'8',
|
||||
['systemd-factory-reset-complete.service',
|
||||
'systemd-factory-reset-request.service',
|
||||
'systemd-factory-reset.socket',
|
||||
'systemd-factory-reset@.service'],
|
||||
''],
|
||||
['systemd-firstboot', '1', ['systemd-firstboot.service'], 'ENABLE_FIRSTBOOT'],
|
||||
['systemd-fsck@.service',
|
||||
'8',
|
||||
@ -1134,6 +1142,7 @@ manpages = [
|
||||
'systemd-tmpfiles-setup-dev.service',
|
||||
'systemd-tmpfiles-setup.service'],
|
||||
''],
|
||||
['systemd-tpm2-clear.service', '8', [], 'ENABLE_BOOTLOADER'],
|
||||
['systemd-tpm2-generator', '8', [], ''],
|
||||
['systemd-tpm2-setup.service',
|
||||
'8',
|
||||
|
48
man/systemd-factory-reset-generator.xml
Normal file
48
man/systemd-factory-reset-generator.xml
Normal file
@ -0,0 +1,48 @@
|
||||
<?xml version="1.0"?>
|
||||
<!--*-nxml-*-->
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
|
||||
<!-- SPDX-License-Identifier: LGPL-2.1-or-later -->
|
||||
<refentry id="systemd-factory-reset-generator">
|
||||
|
||||
<refentryinfo>
|
||||
<title>systemd-factory-reset-generator</title>
|
||||
<productname>systemd</productname>
|
||||
</refentryinfo>
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>systemd-factory-reset-generator</refentrytitle>
|
||||
<manvolnum>8</manvolnum>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname>systemd-factory-reset-generator</refname>
|
||||
<refpurpose>Pull <filename>factory-reset-now.target</filename> into the initial boot transaction when factory reset has been requested</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<para><filename>/usr/lib/systemd/system-generators/systemd-factory-reset-generator</filename></para>
|
||||
</refsynopsisdiv>
|
||||
|
||||
<refsect1>
|
||||
<title>Description</title>
|
||||
|
||||
<para><filename>systemd-factory-reset-generator</filename> is a generator that pulls
|
||||
<filename>factory-reset-now.target</filename> into the initial boot transaction when the factory reset
|
||||
operation has been requested, either via the <varname>systemd.factory_reset=</varname> kernel command
|
||||
line option or via the <varname>FactoryResetRequest</varname> EFI variable.</para>
|
||||
|
||||
<para><filename>systemd-factory-reset-generator</filename> implements
|
||||
<citerefentry><refentrytitle>systemd.generator</refentrytitle><manvolnum>7</manvolnum></citerefentry>.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>See Also</title>
|
||||
<para><simplelist type="inline">
|
||||
<member><citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
|
||||
<member><citerefentry><refentrytitle>systemd-factory-reset</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
|
||||
<member><ulink url="https://systemd.io/FACTORY_RESET">Factory Reset</ulink></member>
|
||||
</simplelist></para>
|
||||
</refsect1>
|
||||
|
||||
</refentry>
|
176
man/systemd-factory-reset.xml
Normal file
176
man/systemd-factory-reset.xml
Normal file
@ -0,0 +1,176 @@
|
||||
<?xml version="1.0"?>
|
||||
<!--*-nxml-*-->
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
|
||||
<!-- SPDX-License-Identifier: LGPL-2.1-or-later -->
|
||||
<refentry id="systemd-factory-reset"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
|
||||
<refentryinfo>
|
||||
<title>systemd-factory-reset</title>
|
||||
<productname>systemd</productname>
|
||||
</refentryinfo>
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>systemd-factory-reset</refentrytitle>
|
||||
<manvolnum>8</manvolnum>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname>systemd-factory-reset</refname>
|
||||
<refname>systemd-factory-reset-request.service</refname>
|
||||
<refname>systemd-factory-reset-complete.service</refname>
|
||||
<refname>systemd-factory-reset.socket</refname>
|
||||
<refname>systemd-factory-reset@.service</refname>
|
||||
<refpurpose>Request or complete a factory reset operation, or query current factory reset mode</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<para><filename>/usr/lib/systemd/systemd-factory-reset</filename></para>
|
||||
<para><filename>systemd-factory-reset-request.service</filename></para>
|
||||
<para><filename>systemd-factory-reset-complete.service</filename></para>
|
||||
<para><filename>systemd-factory-reset.socket</filename></para>
|
||||
<para><filename>systemd-factory-reset@.service</filename></para>
|
||||
</refsynopsisdiv>
|
||||
|
||||
<refsect1>
|
||||
<title>Description</title>
|
||||
|
||||
<para><filename>systemd-factory-reset</filename> is a tool that can query the current factory reset
|
||||
state, request factory request operations or complete them.</para>
|
||||
|
||||
<para>Some of the functionality is also available via the
|
||||
<filename>/run/systemd/io.systemd.FactoryReset</filename> Varlink service (implemented via the
|
||||
<filename>systemd-factory-reset.socket</filename>/<filename>systemd-factory-reset@.service</filename>
|
||||
units.</para>
|
||||
|
||||
<para>See <ulink url="https://systemd.io/FACTORY_RESET">Factory Reset</ulink> for an overview of the
|
||||
factory reset logic.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Commands</title>
|
||||
|
||||
<para>The <filename>/usr/lib/systemd/systemd-factory-reset</filename> executable may also be invoked from the
|
||||
command line, taking one of the following command arguments:</para>
|
||||
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><option>status</option></term>
|
||||
|
||||
<listitem><para>Report current factory reset state. Reports one of <literal>unsupported</literal> (if
|
||||
the OS does not support a factory reset logic), <literal>unspecified</literal> (if no factory reset
|
||||
was requested, but it wasn't turned off explicitly either), <literal>off</literal> (if the factory
|
||||
reset logic was explicitly turned off via the kernel command line option), <literal>on</literal> (if
|
||||
the factory reset is currently enabled and executed), <literal>complete</literal> (if the factory
|
||||
reset logic ran during the current boot but is complete now), <literal>pending</literal> (if a
|
||||
factory reset has been requested for the next boot).</para>
|
||||
|
||||
<para>Returns with an exit status of 0 if the factory reset mechanism is currently not in effect, 10
|
||||
if a factory reset is currently being executed, or 11 if it is pending for the next boot.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v258"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>request</option></term>
|
||||
|
||||
<listitem><para>Request a factory reset operation to be executed on next boot.</para>
|
||||
|
||||
<para>Note that this is a relatively low-level operation. The primary interface for requesting a
|
||||
factory reset operation is by starting the <filename>factory-reset.target</filename>
|
||||
unit.</para>
|
||||
|
||||
<para>This sets the <varname>FactoryResetRequested</varname> EFI variable, see below.</para>
|
||||
|
||||
<para>This operation is executed when the <filename>systemd-factory-reset-request.service</filename>
|
||||
unit is started (which is typically one of the services hooked into
|
||||
and ordered before <filename>factory-reset.target</filename>).</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v258"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>cancel</option></term>
|
||||
|
||||
<listitem><para>Cancel any previously requested (but not yet executed) factory reset
|
||||
operation.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v258"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>complete</option></term>
|
||||
|
||||
<listitem><para>Mark an ongoing factory reset operation as complete.</para>
|
||||
|
||||
<para>This operation is executed when the <filename>systemd-factory-reset-complete.service</filename>
|
||||
unit is started (which is typically one of the services hooked into and ordered after
|
||||
<filename>factory-reset-now.target</filename>).</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v258"/></listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Options</title>
|
||||
|
||||
<para>The following options are understood:</para>
|
||||
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><option>--retrigger</option></term>
|
||||
|
||||
<listitem><para>When used with the <command>complete</command> command retriggers all block devices,
|
||||
which might result in auto-discovered devices being usable that previously weren't because the factory
|
||||
reset logic was in place.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v258"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--quiet</option></term>
|
||||
<term><option>-q</option></term>
|
||||
|
||||
<listitem><para>Suppresses the state output of <command>status</command>, but still sets the exit
|
||||
status as documented.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v258"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<xi:include href="standard-options.xml" xpointer="help" />
|
||||
<xi:include href="standard-options.xml" xpointer="version" />
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>EFI Variables</title>
|
||||
|
||||
<para>The following EFI variable is set and read by <command>systemd-factory-reset</command>, under the
|
||||
vendor UUID <literal>8cf2644b-4b0b-428f-9387-6d876050dc67</literal>, for communication between this boot
|
||||
and the next.</para>
|
||||
|
||||
<variablelist class='efi-variables'>
|
||||
<varlistentry>
|
||||
<term><varname>FactoryResetRequest</varname></term>
|
||||
|
||||
<listitem><para>Set whenever a factory reset is requested from the next boot, deleted once the
|
||||
factory reset is complete. Contains JSON data describing the requesting OS, in order to avoid
|
||||
confusion in multi-boot systems.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v258"/></listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>See Also</title>
|
||||
<para><simplelist type="inline">
|
||||
<member><citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
|
||||
<member><citerefentry><refentrytitle>systemd-factory-reset-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
|
||||
<member><citerefentry><refentrytitle>systemd.special</refentrytitle><manvolnum>7</manvolnum></citerefentry></member>
|
||||
<member><ulink url="https://systemd.io/FACTORY_RESET">Factory Reset</ulink></member>
|
||||
</simplelist></para>
|
||||
</refsect1>
|
||||
</refentry>
|
@ -322,16 +322,20 @@
|
||||
<term><varname>rootflags=</varname></term>
|
||||
|
||||
<listitem><para>When <varname>root=</varname> is used with the special value
|
||||
<literal>gpt-auto</literal>, full automatic discovery of the root
|
||||
partition based on the GPT partition type is enabled. Any other value disables this
|
||||
logic.</para>
|
||||
<literal>gpt-auto</literal>, full automatic discovery of the root partition based on the GPT
|
||||
partition type is enabled. Use of the root partition is delayed until factory reset mode is left, in
|
||||
case it is enabled during the current boot. See <ulink url="https://systemd.io/FACTORY_RESET">Factory
|
||||
Reset</ulink> for more information on that. If <literal>gpt-auto-force</literal> is specified
|
||||
automatic discovery of the root partition is enabled, ignoring any factory reset mode. Any other
|
||||
value disables this logic.</para>
|
||||
|
||||
<para>If <varname>root=</varname> is not specified at all on the kernel command line automatic
|
||||
discovery of the root partition via the boot loader reported ESP is also enabled, however in this
|
||||
case discovery based on the loopback block device <literal>.lo_name</literal> field is not enabled.</para>
|
||||
discovery of the root partition via the ESP reported by the boot loader is also enabled (taking
|
||||
factory reset state into account), however in this case discovery based on the loopback block device
|
||||
<literal>.lo_name</literal> field is not enabled.</para>
|
||||
|
||||
<para>The <varname>rootfstype=</varname> and <varname>rootflags=</varname> are used to select the
|
||||
file system type and options when the root file system is automatically discovered.</para>
|
||||
<para>The <varname>rootfstype=</varname> and <varname>rootflags=</varname> options are used to select
|
||||
the file system type and options when the root file system is automatically discovered.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v242"/></listitem>
|
||||
</varlistentry>
|
||||
|
@ -130,9 +130,9 @@
|
||||
<command>systemd-repart</command> may be used to erase existing partitions to reset an installation back
|
||||
to vendor defaults. This mode of operation is used when either the <option>--factory-reset=yes</option>
|
||||
switch is passed on the tool's command line, or the <option>systemd.factory_reset=yes</option> option is
|
||||
specified on the kernel command line, or the <varname>FactoryReset</varname> EFI variable (vendor UUID
|
||||
<constant>8cf2644b-4b0b-428f-9387-6d876050dc67</constant>) is set to "yes". It alters the algorithm above
|
||||
slightly: between the 3rd and the 4th step above any partition marked explicitly via the
|
||||
specified on the kernel command line, or the <varname>FactoryResetRequest</varname> EFI variable (vendor
|
||||
UUID <constant>8cf2644b-4b0b-428f-9387-6d876050dc67</constant>) is set to "yes". It alters the algorithm
|
||||
above slightly: between the 3rd and the 4th step above any partition marked explicitly via the
|
||||
<varname>FactoryReset=</varname> boolean is deleted, and the algorithm restarted, thus immediately
|
||||
re-creating these partitions anew empty.</para>
|
||||
|
||||
|
90
man/systemd-tpm2-clear.service.xml
Normal file
90
man/systemd-tpm2-clear.service.xml
Normal file
@ -0,0 +1,90 @@
|
||||
<?xml version="1.0"?>
|
||||
<!--*-nxml-*-->
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
|
||||
<!-- SPDX-License-Identifier: LGPL-2.1-or-later -->
|
||||
<refentry id="systemd-tpm2-clear.service" conditional='ENABLE_BOOTLOADER'
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
|
||||
<refentryinfo>
|
||||
<title>systemd-tpm2-clear.service</title>
|
||||
<productname>systemd</productname>
|
||||
</refentryinfo>
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>systemd-tpm2-clear.service</refentrytitle>
|
||||
<manvolnum>8</manvolnum>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname>systemd-tpm2-clear.service</refname>
|
||||
<refpurpose>Request that the TPM security chip is cleared on next boot</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<para><filename>systemd-tpm2-clear.service</filename></para>
|
||||
<para><filename>/usr/lib/systemd/systemd-tpm2-clear</filename></para>
|
||||
</refsynopsisdiv>
|
||||
|
||||
<refsect1>
|
||||
<title>Description</title>
|
||||
|
||||
<para><filename>systemd-tpm2-clear.service</filename> is a service that requests that the TPM is reset by
|
||||
the PC firmware on the next boot. It makes use of the TPM Physical Presence Interface (PPI). Note that
|
||||
this service does not immediately execute the clear operation, but simply asks the PC firmware to execute
|
||||
it at next boot, where the user will be asked for confirmation before the operation is done.</para>
|
||||
|
||||
<para><filename>systemd-tpm2-clear.service</filename> is typically hooked into the
|
||||
<filename>factory-reset.target</filename> unit in order to request the TPM request before an immediate
|
||||
reboot. See <ulink url="https://systemd.io/FACTORY_RESET">Factory Reset</ulink> for more
|
||||
information.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Options</title>
|
||||
|
||||
<para>The following options are understood:</para>
|
||||
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><option>--graceful</option></term>
|
||||
|
||||
<listitem><para>Exit cleanly and execute no operation if the system does not possess a TPM
|
||||
chip.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v258"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<xi:include href="standard-options.xml" xpointer="help" />
|
||||
<xi:include href="standard-options.xml" xpointer="version" />
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Kernel Command Line</title>
|
||||
|
||||
<para><filename>systemd-tpm2-clear</filename> understands the following kernel command line
|
||||
parameters:</para>
|
||||
|
||||
<variablelist class='kernel-commandline-options'>
|
||||
<varlistentry>
|
||||
<term><varname>systemd.tpm2_allow_clear=</varname></term>
|
||||
|
||||
<listitem><para>Takes a boolean argument. If false the service will succeed, but instead of requesting
|
||||
the TPM clear operation from the PC firmware it will not execute any operation. If not specified
|
||||
defaults to true.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v258"/></listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>See Also</title>
|
||||
<para><simplelist type="inline">
|
||||
<member><citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
|
||||
<member><citerefentry><refentrytitle>systemd-tpm2-setup.service</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
|
||||
<member><citerefentry><refentrytitle>systemd-factory-reset-request.service</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
|
||||
</simplelist></para>
|
||||
</refsect1>
|
||||
</refentry>
|
@ -34,6 +34,7 @@
|
||||
<filename>emergency.target</filename>,
|
||||
<filename>exit.target</filename>,
|
||||
<filename>factory-reset.target</filename>,
|
||||
<filename>factory-reset-now.target</filename>,
|
||||
<filename>final.target</filename>,
|
||||
<filename>first-boot-complete.target</filename>,
|
||||
<filename>getty.target</filename>,
|
||||
@ -304,11 +305,30 @@
|
||||
<varlistentry>
|
||||
<term><filename>factory-reset.target</filename></term>
|
||||
<listitem>
|
||||
<para>A special target to trigger a factory reset.</para>
|
||||
<para>A special target to request a factory reset operation. This will typically persistently
|
||||
store a request flag for the next boot and then reboot in order to reset the system to factory
|
||||
state.</para>
|
||||
|
||||
<para>See <ulink url="https://systemd.io/FACTORY_RESET">Factory Reset</ulink> for more
|
||||
information.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v250"/>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><filename>factory-reset-now.target</filename></term>
|
||||
<listitem>
|
||||
<para>A special target that is started on boots that shall execute a factory reset. It may be
|
||||
used to pull in additional services that shall be invoked during a factory reset operation. It
|
||||
also acts as ordering barrier: once the target is reached the factory reset state is marked as
|
||||
"completed".</para>
|
||||
|
||||
<para>See <ulink url="https://systemd.io/FACTORY_RESET">Factory Reset</ulink> for more
|
||||
information.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v258"/>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><filename>final.target</filename></term>
|
||||
<listitem>
|
||||
|
@ -2299,6 +2299,7 @@ subdir('src/detect-virt')
|
||||
subdir('src/dissect')
|
||||
subdir('src/environment-d-generator')
|
||||
subdir('src/escape')
|
||||
subdir('src/factory-reset')
|
||||
subdir('src/firstboot')
|
||||
subdir('src/fsck')
|
||||
subdir('src/fstab-generator')
|
||||
|
@ -33,6 +33,7 @@ enable systemd-pstore.service
|
||||
enable systemd-resolved.service
|
||||
enable systemd-sysext.service
|
||||
enable systemd-timesyncd.service
|
||||
enable systemd-tpm2-clear.service
|
||||
enable systemd-userdbd.socket
|
||||
|
||||
disable console-getty.service
|
||||
|
@ -34,10 +34,25 @@ SUBSYSTEM=="block", ENV{DM_UDEV_DISABLE_OTHER_RULES_FLAG}=="1", ENV{SYSTEMD_READ
|
||||
# we are probably still calling mke2fs or mkswap on it.
|
||||
SUBSYSTEM=="block", ENV{DM_UUID}=="CRYPT-*", ENV{ID_PART_TABLE_TYPE}=="", ENV{ID_FS_USAGE}=="", ENV{SYSTEMD_READY}="0"
|
||||
|
||||
# add symlink to GPT root disk
|
||||
SUBSYSTEM=="block", ENV{ID_PART_GPT_AUTO_ROOT}=="1", ENV{ID_FS_TYPE}!="crypto_LUKS", SYMLINK+="gpt-auto-root"
|
||||
SUBSYSTEM=="block", ENV{ID_PART_GPT_AUTO_ROOT}=="1", ENV{ID_FS_TYPE}=="crypto_LUKS", SYMLINK+="gpt-auto-root-luks"
|
||||
SUBSYSTEM=="block", ENV{DM_UUID}=="CRYPT-*", ENV{DM_NAME}=="root", SYMLINK+="gpt-auto-root"
|
||||
# Add symlink to GPT root disk – in two flavours: one which takes the factory
|
||||
# reset state into account, and one which does not. The former is useful for
|
||||
# wipe-rootfs-on-factory-reset scenarios where we should not be tempted to use
|
||||
# the root fs before factory reset is complete. The latter is useful for
|
||||
# wipe-only-/var-on-factory-reset where we should use it (because that's where
|
||||
# repart.d/ definitions are placed which tell us what to wipe).
|
||||
SUBSYSTEM!="block", GOTO="gpt_auto_root_end"
|
||||
ENV{ID_PART_GPT_AUTO_ROOT}!="1", GOTO="gpt_auto_root_end"
|
||||
IMPORT{builtin}="factory_reset status"
|
||||
ENV{ID_FS_TYPE}!="crypto_LUKS", ENV{ID_FACTORY_RESET}!="on", SYMLINK+="gpt-auto-root"
|
||||
ENV{ID_FS_TYPE}!="crypto_LUKS", ENV{ID_FACTORY_RESET}=="on|complete", SYMLINK+="gpt-auto-root-ignore-factory-reset"
|
||||
ENV{ID_FS_TYPE}=="crypto_LUKS", ENV{ID_FACTORY_RESET}!="on", SYMLINK+="gpt-auto-root-luks"
|
||||
ENV{ID_FS_TYPE}=="crypto_LUKS", ENV{ID_FACTORY_RESET}=="on|complete", SYMLINK+="gpt-auto-root-luks-ignore-factory-reset"
|
||||
LABEL="gpt_auto_root_end"
|
||||
# Note we don't need to condition the gpt-auto-root LUKS symlink for
|
||||
# auto-discovered LUKS devices, because it's sufficient if we do this for the
|
||||
# underlying partition block device, which is covered by the above.
|
||||
SUBSYSTEM=="block", ENV{DM_UUID}=="CRYPT-*", ENV{DM_NAME}=="root", SYMLINK+="gpt-auto-root", IMPORT{builtin}="factory_reset status"
|
||||
SUBSYSTEM=="block", ENV{DM_UUID}=="CRYPT-*", ENV{DM_NAME}=="root", ENV{ID_FACTORY_RESET}=="on|complete", SYMLINK+="gpt-auto-root-ignore-factory-reset"
|
||||
|
||||
# Ignore raid devices that are not yet assembled and started
|
||||
SUBSYSTEM=="block", ENV{DEVTYPE}=="disk", KERNEL=="md*", TEST!="md/array_state", ENV{SYSTEMD_READY}="0"
|
||||
|
28
src/factory-reset/factory-reset-generator.c
Normal file
28
src/factory-reset/factory-reset-generator.c
Normal file
@ -0,0 +1,28 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include "factory-reset.h"
|
||||
#include "generator.h"
|
||||
#include "special.h"
|
||||
|
||||
/* This generator pulls factory-reset-now.target into the initial transaction the kernel command line's
|
||||
* systemd.factor_reset= variable, or the FactoryResetRequest EFI variable say so. */
|
||||
|
||||
static int run(const char *dest, const char *dest_early, const char *dest_late) {
|
||||
assert(dest_early);
|
||||
|
||||
FactoryResetMode f = factory_reset_mode();
|
||||
if (f < 0)
|
||||
return log_error_errno(f, "Failed to determine factory reset mode: %m");
|
||||
if (f != FACTORY_RESET_ON) {
|
||||
log_debug("Not in factory reset mode, skipping.");
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
log_debug("Detected factory reset mode, pulling in factory-reset-now.target.");
|
||||
|
||||
/* We pull this in from basic.target so that it ends up in all "regular" boot ups, but not in
|
||||
* rescue.target or even emergency.target. */
|
||||
return generator_add_symlink(dest_early, SPECIAL_BASIC_TARGET, "wants", "factory-reset-now.target");
|
||||
}
|
||||
|
||||
DEFINE_MAIN_GENERATOR_FUNCTION(run);
|
385
src/factory-reset/factory-reset-tool.c
Normal file
385
src/factory-reset/factory-reset-tool.c
Normal file
@ -0,0 +1,385 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include <getopt.h>
|
||||
|
||||
#include "sd-json.h"
|
||||
#include "sd-varlink.h"
|
||||
|
||||
#include "ansi-color.h"
|
||||
#include "build.h"
|
||||
#include "device-util.h"
|
||||
#include "efivars.h"
|
||||
#include "factory-reset.h"
|
||||
#include "fs-util.h"
|
||||
#include "json-util.h"
|
||||
#include "main-func.h"
|
||||
#include "os-util.h"
|
||||
#include "pretty-print.h"
|
||||
#include "udev-util.h"
|
||||
#include "varlink-io.systemd.FactoryReset.h"
|
||||
#include "varlink-util.h"
|
||||
#include "verbs.h"
|
||||
|
||||
static bool arg_retrigger = false;
|
||||
static bool arg_quiet = false;
|
||||
static bool arg_varlink = false;
|
||||
|
||||
static int help(void) {
|
||||
_cleanup_free_ char *link = NULL;
|
||||
int r;
|
||||
|
||||
r = terminal_urlify_man("systemd-factory-reset", "8", &link);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
printf("%1$s [OPTIONS...] COMMAND\n"
|
||||
"\n%5$sQuery, request, cancel factory reset operation.%6$s\n"
|
||||
"\n%3$sCommands:%4$s\n"
|
||||
" status Report current factory reset status\n"
|
||||
" request Request a factory reset on next boot\n"
|
||||
" cancel Cancel a prior factory reset request for next boot\n"
|
||||
" complete Mark a factory reset as complete\n"
|
||||
"\n%3$sOptions:%4$s\n"
|
||||
" -h --help Show this help\n"
|
||||
" --version Print version\n"
|
||||
" --retrigger Retrigger block devices\n"
|
||||
" -q --quiet Suppress output\n"
|
||||
"\nSee the %2$s for details.\n",
|
||||
program_invocation_short_name,
|
||||
link,
|
||||
ansi_underline(),
|
||||
ansi_normal(),
|
||||
ansi_highlight(),
|
||||
ansi_normal());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_argv(int argc, char *argv[]) {
|
||||
enum {
|
||||
ARG_VERSION = 0x100,
|
||||
ARG_RETRIGGER,
|
||||
};
|
||||
|
||||
static const struct option options[] = {
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "version", no_argument, NULL, ARG_VERSION },
|
||||
{ "retrigger", no_argument, NULL, ARG_RETRIGGER },
|
||||
{ "quiet", no_argument, NULL, 'q' },
|
||||
{}
|
||||
};
|
||||
|
||||
int r, c;
|
||||
|
||||
assert(argc >= 0);
|
||||
assert(argv);
|
||||
|
||||
while ((c = getopt_long(argc, argv, "hq", options, NULL)) >= 0)
|
||||
switch (c) {
|
||||
|
||||
case 'h':
|
||||
return help();
|
||||
|
||||
case ARG_VERSION:
|
||||
return version();
|
||||
|
||||
case ARG_RETRIGGER:
|
||||
arg_retrigger = true;
|
||||
break;
|
||||
|
||||
case 'q':
|
||||
arg_quiet = true;
|
||||
break;
|
||||
|
||||
case '?':
|
||||
return -EINVAL;
|
||||
|
||||
default:
|
||||
assert_not_reached();
|
||||
}
|
||||
|
||||
r = sd_varlink_invocation(SD_VARLINK_ALLOW_ACCEPT);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to check if invoked in Varlink mode: %m");
|
||||
if (r > 0)
|
||||
arg_varlink = true;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int verb_status(int argc, char *argv[], void *userdata) {
|
||||
static const int exit_status_table[_FACTORY_RESET_MODE_MAX] = {
|
||||
/* Report current mode also as via exit status, but only return a subset of states */
|
||||
[FACTORY_RESET_UNSUPPORTED] = EXIT_SUCCESS,
|
||||
[FACTORY_RESET_UNSPECIFIED] = EXIT_SUCCESS,
|
||||
[FACTORY_RESET_OFF] = EXIT_SUCCESS,
|
||||
[FACTORY_RESET_ON] = 10,
|
||||
[FACTORY_RESET_COMPLETE] = EXIT_SUCCESS,
|
||||
[FACTORY_RESET_PENDING] = 11,
|
||||
};
|
||||
|
||||
FactoryResetMode f = factory_reset_mode();
|
||||
if (f < 0)
|
||||
return log_error_errno(f, "Failed to determine factory reset mode: %m");
|
||||
|
||||
if (!arg_quiet)
|
||||
puts(factory_reset_mode_to_string(f));
|
||||
|
||||
return exit_status_table[f];
|
||||
}
|
||||
|
||||
static int verb_request(int argc, char *argv[], void *userdata) {
|
||||
int r;
|
||||
|
||||
FactoryResetMode f = factory_reset_mode();
|
||||
if (f < 0)
|
||||
return log_error_errno(f, "Failed to determine current factory reset mode: %m");
|
||||
if (f == FACTORY_RESET_ON)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EBUSY), "System is currently in factory reset mode, refusing to request another one.");
|
||||
if (f == FACTORY_RESET_PENDING) {
|
||||
if (!arg_quiet)
|
||||
log_info("Factory reset already requested, skipping.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!is_efi_boot())
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
|
||||
"Not an EFI boot, requesting factory reset via EFI variable not supported.");
|
||||
|
||||
_cleanup_free_ char *id = NULL, *image_id = NULL, *version_id = NULL, *image_version = NULL;
|
||||
r = parse_os_release(
|
||||
/* root= */ NULL,
|
||||
"ID", &id,
|
||||
"IMAGE_ID", &image_id,
|
||||
"VERSION_ID", &version_id,
|
||||
"IMAGE_VERSION", &image_version);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to parse os-release: %m");
|
||||
|
||||
if (!id)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EBADR), "os-release data lacks ID= field, refusing.");
|
||||
|
||||
sd_id128_t boot_id;
|
||||
r = sd_id128_get_boot(&boot_id);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to get boot ID: %m");
|
||||
|
||||
/* NB: we don't really use the version fields for anything on the parsing side, because we want to
|
||||
* allow some flexbility between OS/image versions that request the factory reset and that execute
|
||||
* it. However, we include it nonetheless to make things more clearly debuggable. */
|
||||
_cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
|
||||
r = sd_json_buildo(
|
||||
&v,
|
||||
SD_JSON_BUILD_PAIR_STRING("osReleaseId", id),
|
||||
JSON_BUILD_PAIR_STRING_NON_EMPTY("osReleaseVersionId", version_id),
|
||||
JSON_BUILD_PAIR_STRING_NON_EMPTY("osReleaseImageId", image_id),
|
||||
JSON_BUILD_PAIR_STRING_NON_EMPTY("osReleaseImageVersion", image_version),
|
||||
SD_JSON_BUILD_PAIR_ID128("bootId", boot_id));
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to build JSON object: %m");
|
||||
|
||||
_cleanup_free_ char *formatted = NULL;
|
||||
r = sd_json_variant_format(v, /* flags= */ 0, &formatted);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to format JSON object: %m");
|
||||
|
||||
r = efi_set_variable_string(EFI_SYSTEMD_VARIABLE_STR("FactoryResetRequest"), formatted);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to set EFI variable FactoryResetRequest: %m");
|
||||
|
||||
log_debug("Set EFI variable FactoryResetRequest to '%s'.", formatted);
|
||||
|
||||
if (!arg_quiet)
|
||||
log_info("Factory reset requested.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int verb_cancel(int argc, char *argv[], void *userdata) {
|
||||
int r;
|
||||
|
||||
FactoryResetMode f = factory_reset_mode();
|
||||
if (f < 0)
|
||||
return log_error_errno(f, "Failed to determine current factory reset mode: %m");
|
||||
if (f == FACTORY_RESET_ON)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EBUSY), "System already executing factory reset, cannot cancel.");
|
||||
if (f != FACTORY_RESET_PENDING) {
|
||||
if (!arg_quiet)
|
||||
log_info("No factory reset has been requested, cannot cancel, skipping.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!is_efi_boot()) {
|
||||
if (!arg_quiet)
|
||||
log_info("Not an EFI boot, cannot remove FactoryResetMode EFI variable, not cancelling.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = efi_set_variable(EFI_SYSTEMD_VARIABLE_STR("FactoryResetRequest"), /* value= */ NULL, /* size= */ 0);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to remove FactoryResetRequest EFI variable: %m");
|
||||
|
||||
if (!arg_quiet)
|
||||
log_info("Factory reset cancelled.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int retrigger_block_devices(void) {
|
||||
int r;
|
||||
|
||||
/* Let's retrigger block devices after factory reset is complete: it's quite likely that some
|
||||
* partitions went away or got recreated, and will only be considered relevant once factory reset
|
||||
* mode is left. For example, /dev/disk/gpt-auto-root is like that: it is only created once factory
|
||||
* reset mode is complete. */
|
||||
|
||||
if (!udev_available()) {
|
||||
if (!arg_quiet)
|
||||
log_info("Skipping triggering of block devices, as udev is not available.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
_cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
|
||||
r = sd_device_enumerator_new(&e);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to allocate device enumerator: %m");
|
||||
|
||||
r = sd_device_enumerator_allow_uninitialized(e);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to enable enumeration of uninitialized devices: %m");
|
||||
|
||||
r = sd_device_enumerator_add_match_subsystem(e, "block", /* match = */ true);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to filter device enumeration by 'block' subsystem: %m");
|
||||
|
||||
if (!arg_quiet)
|
||||
log_info("Retriggering block devices.");
|
||||
|
||||
FOREACH_DEVICE(e, d) {
|
||||
r = sd_device_trigger(d, SD_DEVICE_CHANGE);
|
||||
if (r < 0)
|
||||
/* Devices can appear anytime, let's not loudly log about that. */
|
||||
log_device_full_errno(
|
||||
d,
|
||||
ERRNO_IS_DEVICE_ABSENT(r) ? LOG_DEBUG : LOG_WARNING,
|
||||
r,
|
||||
"Failed to trigger block device, ignoring: %m");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int verb_complete(int argc, char *argv[], void *userdata) {
|
||||
int r;
|
||||
|
||||
FactoryResetMode f = factory_reset_mode();
|
||||
if (f < 0)
|
||||
return log_error_errno(f, "Failed to dermine factory reset mode: %m");
|
||||
log_debug("Current factory reset mode is: %s", factory_reset_mode_to_string(f));
|
||||
if (f != FACTORY_RESET_ON) {
|
||||
if (!arg_quiet)
|
||||
log_info("Attempted to leave factory reset mode, even though we are not in factory reset mode. Ignoring.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (is_efi_boot()) {
|
||||
r = efi_set_variable(EFI_SYSTEMD_VARIABLE_STR("FactoryResetRequest"), /* value= */ NULL, /* size= */ 0);
|
||||
if (r < 0)
|
||||
log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, r,
|
||||
"Failed to remove FactoryResetRequest EFI variable: %m");
|
||||
}
|
||||
|
||||
r = touch("/run/systemd/factory-reset-complete");
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to create /run/systemd/factory-reset-complete file: %m");
|
||||
|
||||
if (!arg_quiet)
|
||||
log_info("Successfully left factory reset mode.");
|
||||
|
||||
if (arg_retrigger)
|
||||
(void) retrigger_block_devices();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vl_method_get_factory_reset_mode(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
|
||||
int r;
|
||||
|
||||
assert(parameters);
|
||||
|
||||
r = sd_varlink_dispatch(link, parameters, /* table= */ NULL, /* userdata= */ NULL);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
FactoryResetMode f = factory_reset_mode();
|
||||
if (f < 0)
|
||||
return f;
|
||||
|
||||
return sd_varlink_replybo(link, SD_JSON_BUILD_PAIR_STRING("mode", factory_reset_mode_to_string(f)));
|
||||
}
|
||||
|
||||
static int vl_method_can_request_factory_reset(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
|
||||
int r;
|
||||
|
||||
assert(parameters);
|
||||
|
||||
r = sd_varlink_dispatch(link, parameters, /* table= */ NULL, /* userdata= */ NULL);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
return sd_varlink_replybo(link, SD_JSON_BUILD_PAIR_BOOLEAN("supported", is_efi_boot()));
|
||||
}
|
||||
|
||||
static int varlink_service(void) {
|
||||
int r;
|
||||
|
||||
/* Invocation as Varlink service */
|
||||
|
||||
_cleanup_(sd_varlink_server_unrefp) sd_varlink_server *varlink_server = NULL;
|
||||
r = varlink_server_new(&varlink_server, /* flags= */ 0, /* userdata= */ NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to allocate Varlink server: %m");
|
||||
|
||||
r = sd_varlink_server_add_interface(varlink_server, &vl_interface_io_systemd_FactoryReset);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to add Varlink interface: %m");
|
||||
|
||||
r = sd_varlink_server_bind_method_many(
|
||||
varlink_server,
|
||||
"io.systemd.FactoryReset.GetFactoryResetMode", vl_method_get_factory_reset_mode,
|
||||
"io.systemd.FactoryReset.CanRequestFactoryReset", vl_method_can_request_factory_reset);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to bind Varlink methods: %m");
|
||||
|
||||
r = sd_varlink_server_loop_auto(varlink_server);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to run Varlink event loop: %m");
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
static int run(int argc, char *argv[]) {
|
||||
static const Verb verbs[] = {
|
||||
{ "status", VERB_ANY, 1, VERB_DEFAULT, verb_status },
|
||||
{ "request", VERB_ANY, 1, 0, verb_request },
|
||||
{ "cancel", VERB_ANY, 1, 0, verb_cancel },
|
||||
{ "complete", VERB_ANY, 1, 0, verb_complete },
|
||||
{}
|
||||
};
|
||||
|
||||
int r;
|
||||
|
||||
log_setup();
|
||||
|
||||
r = parse_argv(argc, argv);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
if (arg_varlink)
|
||||
return varlink_service();
|
||||
|
||||
return dispatch_verb(argc, argv, verbs, /* userdata= */ NULL);
|
||||
}
|
||||
|
||||
DEFINE_MAIN_FUNCTION_WITH_POSITIVE_FAILURE(run);
|
12
src/factory-reset/meson.build
Normal file
12
src/factory-reset/meson.build
Normal file
@ -0,0 +1,12 @@
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
executables += [
|
||||
libexec_template + {
|
||||
'name' : 'systemd-factory-reset',
|
||||
'sources' : files('factory-reset-tool.c'),
|
||||
},
|
||||
generator_template + {
|
||||
'name' : 'systemd-factory-reset-generator',
|
||||
'sources' : files('factory-reset-generator.c'),
|
||||
},
|
||||
]
|
@ -1119,7 +1119,7 @@ static bool validate_root_or_usr_mount_source(const char *what, const char *swit
|
||||
return false;
|
||||
}
|
||||
|
||||
if (streq(what, "gpt-auto")) {
|
||||
if (parse_gpt_auto_root(what) > 0) {
|
||||
/* This is handled by gpt-auto-generator */
|
||||
log_debug("Skipping %s directory handling, as gpt-auto was requested.", switch_name);
|
||||
return false;
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "dissect-image.h"
|
||||
#include "dropin.h"
|
||||
#include "efi-loader.h"
|
||||
#include "factory-reset.h"
|
||||
#include "fd-util.h"
|
||||
#include "fileio.h"
|
||||
#include "fs-util.h"
|
||||
@ -39,7 +40,7 @@
|
||||
|
||||
static const char *arg_dest = NULL;
|
||||
static bool arg_enabled = true;
|
||||
static int arg_root_enabled = -1; /* tristate */
|
||||
static GptAutoRoot arg_auto_root = _GPT_AUTO_ROOT_INVALID;
|
||||
static bool arg_swap_enabled = true;
|
||||
static char *arg_root_fstype = NULL;
|
||||
static char *arg_root_options = NULL;
|
||||
@ -47,7 +48,6 @@ static int arg_root_rw = -1;
|
||||
static ImagePolicy *arg_image_policy = NULL;
|
||||
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_image_policy, image_policy_freep);
|
||||
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_root_fstype, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_root_options, freep);
|
||||
|
||||
@ -661,7 +661,19 @@ static int add_root_cryptsetup(void) {
|
||||
/* If a device /dev/gpt-auto-root-luks appears, then make it pull in systemd-cryptsetup-root.service, which
|
||||
* sets it up, and causes /dev/gpt-auto-root to appear which is all we are looking for. */
|
||||
|
||||
return add_cryptsetup("root", "/dev/gpt-auto-root-luks", arg_root_options, /* rw= */ true, /* require= */ false, /* measure= */ true, NULL);
|
||||
const char *bdev = "/dev/gpt-auto-root-luks";
|
||||
|
||||
if (arg_auto_root == GPT_AUTO_ROOT_FORCE) {
|
||||
/* Similar logic as in add_root_mount(), see below */
|
||||
FactoryResetMode f = factory_reset_mode();
|
||||
if (f < 0)
|
||||
log_warning_errno(f, "Failed to determine whether we are in factory reset mode, assuming not: %m");
|
||||
|
||||
if (IN_SET(f, FACTORY_RESET_ON, FACTORY_RESET_COMPLETE))
|
||||
bdev = "/dev/gpt-auto-root-luks-ignore-factory-reset";
|
||||
}
|
||||
|
||||
return add_cryptsetup("root", bdev, arg_root_options, /* rw= */ true, /* require= */ false, /* measure= */ true, NULL);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
@ -674,11 +686,11 @@ static int add_root_mount(void) {
|
||||
int r;
|
||||
|
||||
/* Explicitly disabled? Then exit immediately */
|
||||
if (arg_root_enabled == 0)
|
||||
if (arg_auto_root == GPT_AUTO_ROOT_OFF)
|
||||
return 0;
|
||||
|
||||
/* Neither explicitly enabled nor disabled? Then decide based on the EFI partition variables to be set */
|
||||
if (arg_root_enabled < 0) {
|
||||
if (arg_auto_root < 0) {
|
||||
if (!is_efi_boot()) {
|
||||
log_debug("Not an EFI boot, not creating root mount.");
|
||||
return 0;
|
||||
@ -695,10 +707,27 @@ static int add_root_mount(void) {
|
||||
}
|
||||
|
||||
/* OK, we shall look for a root device, so let's wait for a root device to show up. A udev rule will
|
||||
* create the link for us under the right name. */
|
||||
* create the link for us under the right name.
|
||||
*
|
||||
* There are two distinct names: the /dev/gpt-auto-root-ignore-factory-reset symlink is created for
|
||||
* the root partition if factory reset mode is enabled or complete, and the /dev/gpt-auto-root
|
||||
* symlink is only created if factory reset mode is off or already complete (thus taking factory
|
||||
* reset state into account). In scenarios where the root disk is partially reformatted during
|
||||
* factory reset the latter is the link to use, otherwise the former (so that we don't accidentally
|
||||
* mount a root partition too early that is about to be wiped and replaced by another one). */
|
||||
|
||||
const char *bdev = "/dev/gpt-auto-root";
|
||||
if (arg_auto_root == GPT_AUTO_ROOT_FORCE) {
|
||||
FactoryResetMode f = factory_reset_mode();
|
||||
if (f < 0)
|
||||
log_warning_errno(f, "Failed to determine whether we are in factory reset mode, assuming not: %m");
|
||||
|
||||
if (IN_SET(f, FACTORY_RESET_ON, FACTORY_RESET_COMPLETE))
|
||||
bdev = "/dev/gpt-auto-root-ignore-factory-reset";
|
||||
}
|
||||
|
||||
if (in_initrd()) {
|
||||
r = generator_write_initrd_root_device_deps(arg_dest, "/dev/gpt-auto-root");
|
||||
r = generator_write_initrd_root_device_deps(arg_dest, bdev);
|
||||
if (r < 0)
|
||||
return 0;
|
||||
|
||||
@ -727,7 +756,7 @@ static int add_root_mount(void) {
|
||||
|
||||
return add_mount(
|
||||
"root",
|
||||
"/dev/gpt-auto-root",
|
||||
bdev,
|
||||
in_initrd() ? "/sysroot" : "/",
|
||||
arg_root_fstype,
|
||||
/* rw= */ arg_root_rw > 0,
|
||||
@ -909,16 +938,11 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
|
||||
if (proc_cmdline_value_missing(key, value))
|
||||
return 0;
|
||||
|
||||
/* Disable root disk logic if there's a root= value
|
||||
* specified (unless it happens to be "gpt-auto") */
|
||||
/* Disable root disk logic if there's a root= value specified (unless it happens to be
|
||||
* "gpt-auto" or "gpt-auto-force") */
|
||||
|
||||
if (streq(value, "gpt-auto")) {
|
||||
arg_root_enabled = true;
|
||||
log_debug("Enabling root partition auto-detection, root= is explicitly set to 'gpt_auto'.");
|
||||
} else {
|
||||
arg_root_enabled = false;
|
||||
log_debug("Disabling root partition auto-detection, root= is neither unset, nor set to 'gpt-auto'.");
|
||||
}
|
||||
arg_auto_root = parse_gpt_auto_root(value);
|
||||
assert(arg_auto_root >= 0);
|
||||
|
||||
} else if (streq(key, "roothash")) {
|
||||
|
||||
@ -927,7 +951,7 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
|
||||
|
||||
/* Disable root disk logic if there's roothash= defined (i.e. verity enabled) */
|
||||
|
||||
arg_root_enabled = false;
|
||||
arg_auto_root = GPT_AUTO_ROOT_OFF;
|
||||
log_debug("Disabling root partition auto-detection, roothash= is set.");
|
||||
|
||||
} else if (streq(key, "rootfstype")) {
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include "dirent-util.h"
|
||||
#include "efivars.h"
|
||||
#include "errno-util.h"
|
||||
#include "factory-reset.h"
|
||||
#include "fd-util.h"
|
||||
#include "fdisk-util.h"
|
||||
#include "fileio.h"
|
||||
@ -8712,23 +8713,20 @@ static int parse_argv(int argc, char *argv[], X509 **ret_certificate, EVP_PKEY *
|
||||
}
|
||||
|
||||
static int parse_proc_cmdline_factory_reset(void) {
|
||||
bool b;
|
||||
int r;
|
||||
|
||||
if (arg_factory_reset >= 0) /* Never override what is specified on the process command line */
|
||||
return 0;
|
||||
|
||||
if (!in_initrd()) /* Never honour kernel command line factory reset request outside of the initrd */
|
||||
return 0;
|
||||
|
||||
r = proc_cmdline_get_bool("systemd.factory_reset", /* flags = */ 0, &b);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to parse systemd.factory_reset kernel command line argument: %m");
|
||||
if (r > 0) {
|
||||
arg_factory_reset = b;
|
||||
FactoryResetMode f = factory_reset_mode();
|
||||
if (f < 0)
|
||||
return log_error_errno(f, "Failed to determine factory reset status: %m");
|
||||
if (f != FACTORY_RESET_UNSPECIFIED) {
|
||||
arg_factory_reset = f == FACTORY_RESET_ON;
|
||||
|
||||
if (b)
|
||||
log_notice("Honouring factory reset requested via kernel command line.");
|
||||
if (arg_factory_reset)
|
||||
log_notice("Honouring factory reset requested via kernel command line or EFI variable.");
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -8738,6 +8736,10 @@ static int parse_efi_variable_factory_reset(void) {
|
||||
_cleanup_free_ char *value = NULL;
|
||||
int r;
|
||||
|
||||
/* NB: This is legacy, people should move to the newer FactoryResetRequest variable! */
|
||||
|
||||
// FIXME: Remove this in v260
|
||||
|
||||
if (arg_factory_reset >= 0) /* Never override what is specified on the process command line */
|
||||
return 0;
|
||||
|
||||
@ -8751,6 +8753,8 @@ static int parse_efi_variable_factory_reset(void) {
|
||||
return log_error_errno(r, "Failed to read EFI variable FactoryReset: %m");
|
||||
}
|
||||
|
||||
log_warning("Warning, EFI variable FactoryReset is in use, please migrate to use FactoryResetRequest instead, support will be removed in v260!");
|
||||
|
||||
r = parse_boolean(value);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to parse EFI variable FactoryReset: %m");
|
||||
@ -8765,6 +8769,8 @@ static int parse_efi_variable_factory_reset(void) {
|
||||
static int remove_efi_variable_factory_reset(void) {
|
||||
int r;
|
||||
|
||||
// FIXME: Remove this in v260, see above
|
||||
|
||||
r = efi_set_variable(EFI_SYSTEMD_VARIABLE_STR("FactoryReset"), NULL, 0);
|
||||
if (r < 0) {
|
||||
if (r == -ENOENT || ERRNO_IS_NOT_SUPPORTED(r))
|
||||
|
125
src/shared/factory-reset.c
Normal file
125
src/shared/factory-reset.c
Normal file
@ -0,0 +1,125 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include "sd-json.h"
|
||||
|
||||
#include "efivars.h"
|
||||
#include "env-util.h"
|
||||
#include "factory-reset.h"
|
||||
#include "os-util.h"
|
||||
#include "proc-cmdline.h"
|
||||
#include "string-table.h"
|
||||
|
||||
static bool factory_reset_supported(void) {
|
||||
int r;
|
||||
|
||||
r = secure_getenv_bool("SYSTEMD_FACTORY_RESET_SUPPORTED");
|
||||
if (r >= 0)
|
||||
return r;
|
||||
if (r != -ENXIO)
|
||||
log_debug_errno(r, "Unable to parse $SYSTEMD_FACTORY_RESET_SUPPORTED, ignoring: %m");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static FactoryResetMode factory_reset_mode_efi_variable(void) {
|
||||
int r;
|
||||
|
||||
if (!is_efi_boot()) {
|
||||
log_debug("Not booted in EFI mode, not checking FactoryResetRequest variable.");
|
||||
return FACTORY_RESET_UNSPECIFIED;
|
||||
}
|
||||
|
||||
_cleanup_free_ char *req_str = NULL;
|
||||
r = efi_get_variable_string(EFI_SYSTEMD_VARIABLE_STR("FactoryResetRequest"), &req_str);
|
||||
if (r == -ENOENT) {
|
||||
log_debug_errno(r, "EFI variable FactoryResetRequest is not set, skipping.");
|
||||
return FACTORY_RESET_UNSPECIFIED;
|
||||
}
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to get EFI variable FactoryResetRequest: %m");
|
||||
|
||||
_cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
|
||||
r = sd_json_parse(req_str, /* flags= */ 0, &v, /* ret_line= */ NULL, /* ret_column= */ NULL);
|
||||
if (r < 0) {
|
||||
log_debug_errno(r, "EFI variable FactoryResetRequest set to invalid JSON, ignoring: %m");
|
||||
return FACTORY_RESET_UNSPECIFIED;
|
||||
}
|
||||
|
||||
struct {
|
||||
const char *id;
|
||||
const char *image_id;
|
||||
sd_id128_t boot_id;
|
||||
} req = {};
|
||||
static const sd_json_dispatch_field dispatch_table[] = {
|
||||
{ "osReleaseId", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, voffsetof(req, id), SD_JSON_MANDATORY },
|
||||
{ "osReleaseImageId", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, voffsetof(req, image_id), 0 },
|
||||
{ "bootId", SD_JSON_VARIANT_STRING, sd_json_dispatch_id128, voffsetof(req, boot_id), SD_JSON_MANDATORY },
|
||||
{},
|
||||
};
|
||||
|
||||
r = sd_json_dispatch(v, dispatch_table, SD_JSON_ALLOW_EXTENSIONS, &req);
|
||||
if (r < 0) {
|
||||
log_debug_errno(r, "Unable to dispatch EFI variable FactoryResetRequest, ignoring: %m");
|
||||
return FACTORY_RESET_UNSPECIFIED;
|
||||
}
|
||||
|
||||
_cleanup_free_ char *id = NULL, *image_id = NULL;
|
||||
r = parse_os_release(
|
||||
/* root= */ NULL,
|
||||
"ID", &id,
|
||||
"IMAGE_ID", &image_id);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to parse os-release: %m");
|
||||
|
||||
if (!streq_ptr(req.id, id) || !streq_ptr(req.image_id, image_id)) {
|
||||
log_debug("FactoryResetRequest EFI variable set, but not for us, ignoring.");
|
||||
return FACTORY_RESET_UNSPECIFIED;
|
||||
}
|
||||
|
||||
sd_id128_t boot_id;
|
||||
r = sd_id128_get_boot(&boot_id);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to query boot ID: %m");
|
||||
|
||||
if (sd_id128_equal(req.boot_id, boot_id)) {
|
||||
/* NB: if the boot ID in the EFI variable matches our *current* one, then the request is not
|
||||
* intended for us, but for the *next* boot. */
|
||||
log_debug("EFI variable FactoryResetRequest set for next boot.");
|
||||
return FACTORY_RESET_PENDING;
|
||||
}
|
||||
|
||||
return FACTORY_RESET_ON;
|
||||
}
|
||||
|
||||
FactoryResetMode factory_reset_mode(void) {
|
||||
int r;
|
||||
|
||||
if (!factory_reset_supported())
|
||||
return FACTORY_RESET_UNSUPPORTED;
|
||||
|
||||
/* First check if we already completed a factory reset in this boot */
|
||||
if (access("/run/systemd/factory-reset-complete", F_OK) >= 0)
|
||||
return FACTORY_RESET_COMPLETE;
|
||||
if (errno != ENOENT)
|
||||
return log_debug_errno(errno, "Can't determine if /run/systemd/factory-reset-complete exists: %m");
|
||||
|
||||
bool b;
|
||||
r = proc_cmdline_get_bool("systemd.factory_reset", /* flags= */ 0, &b);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to parse systemd.factory_reset kernel command line argument: %m");
|
||||
if (r == 0) /* Check EFI variable in case kernel cmdline switch is not specified */
|
||||
return factory_reset_mode_efi_variable();
|
||||
|
||||
return b ? FACTORY_RESET_ON : FACTORY_RESET_OFF; /* Honour if explicitly turned off or on via kernel cmdline */
|
||||
}
|
||||
|
||||
static const char* const factory_reset_mode_table[_FACTORY_RESET_MODE_MAX] = {
|
||||
[FACTORY_RESET_UNSUPPORTED] = "unsupported",
|
||||
[FACTORY_RESET_UNSPECIFIED] = "unspecified",
|
||||
[FACTORY_RESET_OFF] = "off",
|
||||
[FACTORY_RESET_ON] = "on",
|
||||
[FACTORY_RESET_COMPLETE] = "complete",
|
||||
[FACTORY_RESET_PENDING] = "pending",
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP(factory_reset_mode, FactoryResetMode);
|
24
src/shared/factory-reset.h
Normal file
24
src/shared/factory-reset.h
Normal file
@ -0,0 +1,24 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include "errno-list.h"
|
||||
#include "macro.h"
|
||||
|
||||
typedef enum FactoryResetMode {
|
||||
FACTORY_RESET_UNSUPPORTED, /* feature not available on this OS */
|
||||
FACTORY_RESET_UNSPECIFIED, /* not specified on the kernel cmdline, nor via EFI variable */
|
||||
FACTORY_RESET_OFF, /* explicitly turned off on kernel cmdline */
|
||||
FACTORY_RESET_ON, /* turned on via kernel cmdline or EFI variable */
|
||||
FACTORY_RESET_COMPLETE, /* turned on via kernel cmdline or EFI variable, but marked as complete now */
|
||||
FACTORY_RESET_PENDING, /* marked for next boot via EFI variable, but not in effect on this boot */
|
||||
_FACTORY_RESET_MODE_MAX,
|
||||
_FACTORY_RESET_MODE_INVALID = -EINVAL,
|
||||
_FACTORY_RESET_MODE_ERRNO_MAX = -ERRNO_MAX,
|
||||
} FactoryResetMode;
|
||||
|
||||
FactoryResetMode factory_reset_mode(void);
|
||||
|
||||
const char* factory_reset_mode_to_string(FactoryResetMode) _const_;
|
||||
FactoryResetMode factory_reset_mode_from_string(const char *s) _pure_;
|
@ -1030,3 +1030,22 @@ bool generator_soft_rebooted(void) {
|
||||
|
||||
return (cached = (u > 0));
|
||||
}
|
||||
|
||||
GptAutoRoot parse_gpt_auto_root(const char *value) {
|
||||
assert(value);
|
||||
|
||||
/* Parses the 'gpt-auto'/'gpt-auto-root' parameters to root= */
|
||||
|
||||
if (streq(value, "gpt-auto")) {
|
||||
log_debug("Enabling root partition auto-detection (respecting factory reset mode), root= is explicitly set to 'gpt-auto'.");
|
||||
return GPT_AUTO_ROOT_ON;
|
||||
}
|
||||
|
||||
if (streq(value, "gpt-auto-force")) {
|
||||
log_debug("Enabling root partition auto-detection (ignoring factory reset mode), root= is explicitly set to 'gpt-auto-force'.");
|
||||
return GPT_AUTO_ROOT_FORCE;
|
||||
}
|
||||
|
||||
log_debug("Disabling root partition auto-detection, root= is neither unset, nor set to 'gpt-auto' or 'gpt-auto-force'.");
|
||||
return GPT_AUTO_ROOT_OFF;
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "errno-list.h"
|
||||
#include "macro.h"
|
||||
#include "main-func.h"
|
||||
|
||||
@ -114,3 +115,13 @@ bool generator_soft_rebooted(void);
|
||||
argv[argc == 4 ? 3 : 1]), \
|
||||
exit_failure_if_negative, \
|
||||
exit_failure_if_negative)
|
||||
|
||||
typedef enum GptAutoRoot {
|
||||
GPT_AUTO_ROOT_OFF = 0, /* root= set to something else */
|
||||
GPT_AUTO_ROOT_ON, /* root= set explicitly to "gpt-auto" */
|
||||
GPT_AUTO_ROOT_FORCE, /* root= set explicitly to "gpt-auto-force" → ignores factory reset mode */
|
||||
_GPT_AUTO_ROOT_MAX,
|
||||
_GPT_AUTO_ROOT_INVALID = -EINVAL,
|
||||
} GptAutoRoot;
|
||||
|
||||
GptAutoRoot parse_gpt_auto_root(const char *value);
|
||||
|
@ -70,6 +70,7 @@ shared_sources = files(
|
||||
'exec-util.c',
|
||||
'exit-status.c',
|
||||
'extension-util.c',
|
||||
'factory-reset.c',
|
||||
'fdset.c',
|
||||
'fido2-util.c',
|
||||
'find-esp.c',
|
||||
@ -183,6 +184,7 @@ shared_sources = files(
|
||||
'varlink-io.systemd.AskPassword.c',
|
||||
'varlink-io.systemd.BootControl.c',
|
||||
'varlink-io.systemd.Credentials.c',
|
||||
'varlink-io.systemd.FactoryReset.c',
|
||||
'varlink-io.systemd.Hostname.c',
|
||||
'varlink-io.systemd.Import.c',
|
||||
'varlink-io.systemd.Journal.c',
|
||||
|
39
src/shared/varlink-io.systemd.FactoryReset.c
Normal file
39
src/shared/varlink-io.systemd.FactoryReset.c
Normal file
@ -0,0 +1,39 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include "varlink-io.systemd.FactoryReset.h"
|
||||
#include "sd-varlink-idl.h"
|
||||
|
||||
static SD_VARLINK_DEFINE_ENUM_TYPE(
|
||||
FactoryResetMode,
|
||||
SD_VARLINK_FIELD_COMMENT("Factory reset is not supported on this OS."),
|
||||
SD_VARLINK_DEFINE_ENUM_VALUE(unsupported),
|
||||
SD_VARLINK_FIELD_COMMENT("Factory reset not requested."),
|
||||
SD_VARLINK_DEFINE_ENUM_VALUE(unspecified),
|
||||
SD_VARLINK_FIELD_COMMENT("Factory reset explicitly turned off."),
|
||||
SD_VARLINK_DEFINE_ENUM_VALUE(off),
|
||||
SD_VARLINK_FIELD_COMMENT("Factory reset is currently being executed."),
|
||||
SD_VARLINK_DEFINE_ENUM_VALUE(on),
|
||||
SD_VARLINK_FIELD_COMMENT("Factory reset has been completed during the current boot."),
|
||||
SD_VARLINK_DEFINE_ENUM_VALUE(complete),
|
||||
SD_VARLINK_FIELD_COMMENT("Factory reset has been requested for the next boot."),
|
||||
SD_VARLINK_DEFINE_ENUM_VALUE(pending));
|
||||
|
||||
static SD_VARLINK_DEFINE_METHOD(
|
||||
GetFactoryResetMode,
|
||||
SD_VARLINK_FIELD_COMMENT("The current factory reset mode"),
|
||||
SD_VARLINK_DEFINE_OUTPUT_BY_TYPE(mode, FactoryResetMode, 0));
|
||||
|
||||
static SD_VARLINK_DEFINE_METHOD(
|
||||
CanRequestFactoryReset,
|
||||
SD_VARLINK_DEFINE_OUTPUT(supported, SD_VARLINK_BOOL, 0));
|
||||
|
||||
SD_VARLINK_DEFINE_INTERFACE(
|
||||
io_systemd_FactoryReset,
|
||||
"io.systemd.FactoryReset",
|
||||
SD_VARLINK_INTERFACE_COMMENT("APIs to query factory reset status"),
|
||||
SD_VARLINK_SYMBOL_COMMENT("Encodes the current factory reset status"),
|
||||
&vl_type_FactoryResetMode,
|
||||
SD_VARLINK_SYMBOL_COMMENT("Report the current factory reset status"),
|
||||
&vl_method_GetFactoryResetMode,
|
||||
SD_VARLINK_SYMBOL_COMMENT("Returns whether requesting a factory reset is available (by invoking the factory-reset.target unit)."),
|
||||
&vl_method_CanRequestFactoryReset);
|
6
src/shared/varlink-io.systemd.FactoryReset.h
Normal file
6
src/shared/varlink-io.systemd.FactoryReset.h
Normal file
@ -0,0 +1,6 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include "sd-varlink-idl.h"
|
||||
|
||||
extern const sd_varlink_interface vl_interface_io_systemd_FactoryReset;
|
@ -278,6 +278,8 @@ _SD_BEGIN_DECLARATIONS;
|
||||
|
||||
#define SD_MESSAGE_SRK_ENROLLMENT_NEEDS_AUTHORIZATION SD_ID128_MAKE(ad,70,89,f9,28,ac,4f,7e,a0,0c,07,45,7d,47,ba,8a)
|
||||
#define SD_MESSAGE_SRK_ENROLLMENT_NEEDS_AUTHORIZATION_STR SD_ID128_MAKE_STR(ad,70,89,f9,28,ac,4f,7e,a0,0c,07,45,7d,47,ba,8a)
|
||||
#define SD_MESSAGE_TPM2_CLEAR_REQUESTED SD_ID128_MAKE(43,81,88,86,1e,0b,42,7a,9d,63,8a,90,48,7a,0c,a6)
|
||||
#define SD_MESSAGE_TPM2_CLEAR_REQUESTED_STR SD_ID128_MAKE_STR(43,81,88,86,1e,0b,42,7a,9d,63,8a,90,48,7a,0c,a6)
|
||||
|
||||
#define SD_MESSAGE_SYSCTL_CHANGED SD_ID128_MAKE(9c,f5,6b,8b,af,95,46,cf,94,78,78,3a,8d,e4,21,13)
|
||||
#define SD_MESSAGE_SYSCTL_CHANGED_STR SD_ID128_MAKE_STR(9c,f5,6b,8b,af,95,46,cf,94,78,78,3a,8d,e4,21,13)
|
||||
|
@ -10,9 +10,10 @@
|
||||
#include "tests.h"
|
||||
#include "varlink-idl-util.h"
|
||||
#include "varlink-io.systemd.h"
|
||||
#include "varlink-io.systemd.BootControl.h"
|
||||
#include "varlink-io.systemd.AskPassword.h"
|
||||
#include "varlink-io.systemd.BootControl.h"
|
||||
#include "varlink-io.systemd.Credentials.h"
|
||||
#include "varlink-io.systemd.FactoryReset.h"
|
||||
#include "varlink-io.systemd.Import.h"
|
||||
#include "varlink-io.systemd.Journal.h"
|
||||
#include "varlink-io.systemd.Login.h"
|
||||
@ -203,6 +204,8 @@ TEST(parse_format) {
|
||||
print_separator();
|
||||
test_parse_format_one(&vl_interface_io_systemd_Login);
|
||||
print_separator();
|
||||
test_parse_format_one(&vl_interface_io_systemd_FactoryReset);
|
||||
print_separator();
|
||||
test_parse_format_one(&vl_interface_xyz_test);
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,13 @@ executables += [
|
||||
libopenssl,
|
||||
],
|
||||
},
|
||||
libexec_template + {
|
||||
'name' : 'systemd-tpm2-clear',
|
||||
'sources' : files('tpm2-clear.c'),
|
||||
'conditions' : [
|
||||
'HAVE_TPM2',
|
||||
],
|
||||
},
|
||||
generator_template + {
|
||||
'name' : 'systemd-tpm2-generator',
|
||||
'sources' : files('tpm2-generator.c'),
|
||||
|
140
src/tpm2-setup/tpm2-clear.c
Normal file
140
src/tpm2-setup/tpm2-clear.c
Normal file
@ -0,0 +1,140 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include <getopt.h>
|
||||
|
||||
#include "sd-messages.h"
|
||||
|
||||
#include "build.h"
|
||||
#include "env-util.h"
|
||||
#include "fileio.h"
|
||||
#include "main-func.h"
|
||||
#include "pretty-print.h"
|
||||
#include "proc-cmdline.h"
|
||||
#include "tpm2-util.h"
|
||||
|
||||
static bool arg_graceful = false;
|
||||
|
||||
static int help(void) {
|
||||
_cleanup_free_ char *link = NULL;
|
||||
int r;
|
||||
|
||||
r = terminal_urlify_man("systemd-tpm2-clear", "8", &link);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
printf("%1$s [OPTIONS...]\n"
|
||||
"\n%5$sRequest clearing of the TPM2 from PC firmware.%6$s\n"
|
||||
"\n%3$sOptions:%4$s\n"
|
||||
" -h --help Show this help\n"
|
||||
" --version Show package version\n"
|
||||
" --graceful Exit gracefully if no TPM2 device is found\n"
|
||||
"\nSee the %2$s for details.\n",
|
||||
program_invocation_short_name,
|
||||
link,
|
||||
ansi_underline(),
|
||||
ansi_normal(),
|
||||
ansi_highlight(),
|
||||
ansi_normal());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_argv(int argc, char *argv[]) {
|
||||
enum {
|
||||
ARG_VERSION = 0x100,
|
||||
ARG_GRACEFUL,
|
||||
};
|
||||
|
||||
static const struct option options[] = {
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "version", no_argument, NULL, ARG_VERSION },
|
||||
{ "graceful", no_argument, NULL, ARG_GRACEFUL },
|
||||
{}
|
||||
};
|
||||
|
||||
int c;
|
||||
|
||||
assert(argc >= 0);
|
||||
assert(argv);
|
||||
|
||||
while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
|
||||
switch (c) {
|
||||
|
||||
case 'h':
|
||||
return help();
|
||||
|
||||
case ARG_VERSION:
|
||||
return version();
|
||||
|
||||
case ARG_GRACEFUL:
|
||||
arg_graceful = true;
|
||||
break;
|
||||
|
||||
case '?':
|
||||
return -EINVAL;
|
||||
|
||||
default:
|
||||
assert_not_reached();
|
||||
}
|
||||
|
||||
if (optind != argc)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "This program expects no arguments.");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int request_tpm2_clear(void) {
|
||||
int r, clear = -1;
|
||||
|
||||
r = secure_getenv_bool("SYSTEMD_TPM2_ALLOW_CLEAR");
|
||||
if (r < 0 && r != -ENXIO)
|
||||
log_warning_errno(r, "Failed to parse $SYSTEMD_TPM2_ALLOW_CLEAR, ignoring: %m");
|
||||
if (r >= 0)
|
||||
clear = r;
|
||||
|
||||
if (clear < 0) {
|
||||
bool b;
|
||||
r = proc_cmdline_get_bool("systemd.tpm2_allow_clear", /* flags= */ 0, &b);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to parse systemd.tpm2_allow_clear kernel command line argument: %m");
|
||||
if (r > 0)
|
||||
clear = b;
|
||||
}
|
||||
|
||||
if (clear == 0) {
|
||||
log_info("Clearing TPM2 disabled, exiting early.");
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
/* Now issue PPI request */
|
||||
r = write_string_file("/sys/class/tpm/tpm0/ppi/request", "5", /* flags= */ 0);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to request TPM2 cleaing via PPI, unable to write to /sys/class/tpm/tpm0/ppi/request: %m");
|
||||
|
||||
log_struct(LOG_NOTICE,
|
||||
"MESSAGE_ID=" SD_MESSAGE_TPM2_CLEAR_REQUESTED_STR,
|
||||
LOG_MESSAGE("Requested TPM2 clearing via PPI. Firmware will verify with user and clear TPM on reboot."));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int run(int argc, char *argv[]) {
|
||||
int r;
|
||||
|
||||
log_setup();
|
||||
|
||||
r = parse_argv(argc, argv);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
/* If we don't fully support the TPM we are unlikely able to reinitialize it after boot, hence don't
|
||||
* be tempted to reset it in graceful mode. Otherwise we might destroy something without being able
|
||||
* to rebuild it. */
|
||||
if (arg_graceful && !tpm2_is_fully_supported()) {
|
||||
log_notice("No complete TPM2 support detected, exiting gracefully.");
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
return request_tpm2_clear();
|
||||
}
|
||||
|
||||
DEFINE_MAIN_FUNCTION_WITH_POSITIVE_FAILURE(run);
|
@ -20,7 +20,9 @@ udevadm_sources = files(
|
||||
|
||||
libudevd_core_sources = files(
|
||||
'net/link-config.c',
|
||||
'udev-builtin.c',
|
||||
'udev-builtin-btrfs.c',
|
||||
'udev-builtin-factory_reset.c',
|
||||
'udev-builtin-hwdb.c',
|
||||
'udev-builtin-input_id.c',
|
||||
'udev-builtin-keyboard.c',
|
||||
@ -29,7 +31,6 @@ libudevd_core_sources = files(
|
||||
'udev-builtin-net_setup_link.c',
|
||||
'udev-builtin-path_id.c',
|
||||
'udev-builtin-usb_id.c',
|
||||
'udev-builtin.c',
|
||||
'udev-config.c',
|
||||
'udev-ctrl.c',
|
||||
'udev-dump.c',
|
||||
|
34
src/udev/udev-builtin-factory_reset.c
Normal file
34
src/udev/udev-builtin-factory_reset.c
Normal file
@ -0,0 +1,34 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "device-util.h"
|
||||
#include "factory-reset.h"
|
||||
#include "udev-builtin.h"
|
||||
|
||||
/* Sometimes it is relevant in udev rules to know whether factory reset is currently in effect or not. Report
|
||||
* the current state at moment of probing as a udev property. This can be used to create certain device node
|
||||
* symlinks only once factory reset is complete, or even mark whole devices as SYSTEMD_READY=0 as long as
|
||||
* factory reset is still ongoing. */
|
||||
|
||||
static int builtin_factory_reset(UdevEvent *event, int argc, char *argv[]) {
|
||||
sd_device *dev = ASSERT_PTR(ASSERT_PTR(event)->dev);
|
||||
|
||||
if (argc != 2 || !streq(argv[1], "status"))
|
||||
return log_device_warning_errno(
|
||||
dev, SYNTHETIC_ERRNO(EINVAL), "%s: expected: status", argv[0]);
|
||||
|
||||
/* Report factory reset mode at the moment of probing a device. */
|
||||
FactoryResetMode f = factory_reset_mode();
|
||||
if (f < 0) {
|
||||
log_device_debug_errno(dev, f, "Unable to detect factory reset mode, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return udev_builtin_add_property(event, "ID_FACTORY_RESET", factory_reset_mode_to_string(f));
|
||||
}
|
||||
|
||||
const UdevBuiltin udev_builtin_factory_reset = {
|
||||
.name = "factory_reset",
|
||||
.cmd = builtin_factory_reset,
|
||||
.help = "Factory Reset Mode",
|
||||
.run_once = true,
|
||||
};
|
@ -15,6 +15,7 @@ static const UdevBuiltin *const builtins[_UDEV_BUILTIN_MAX] = {
|
||||
[UDEV_BUILTIN_BLKID] = &udev_builtin_blkid,
|
||||
#endif
|
||||
[UDEV_BUILTIN_BTRFS] = &udev_builtin_btrfs,
|
||||
[UDEV_BUILTIN_FACTORY_RESET] = &udev_builtin_factory_reset,
|
||||
[UDEV_BUILTIN_HWDB] = &udev_builtin_hwdb,
|
||||
[UDEV_BUILTIN_INPUT_ID] = &udev_builtin_input_id,
|
||||
[UDEV_BUILTIN_KEYBOARD] = &udev_builtin_keyboard,
|
||||
|
@ -37,6 +37,7 @@ typedef struct UdevBuiltin {
|
||||
extern const UdevBuiltin udev_builtin_blkid;
|
||||
#endif
|
||||
extern const UdevBuiltin udev_builtin_btrfs;
|
||||
extern const UdevBuiltin udev_builtin_factory_reset;
|
||||
extern const UdevBuiltin udev_builtin_hwdb;
|
||||
extern const UdevBuiltin udev_builtin_input_id;
|
||||
extern const UdevBuiltin udev_builtin_keyboard;
|
||||
|
@ -40,6 +40,7 @@ typedef enum UdevBuiltinCommand {
|
||||
UDEV_BUILTIN_BLKID,
|
||||
#endif
|
||||
UDEV_BUILTIN_BTRFS,
|
||||
UDEV_BUILTIN_FACTORY_RESET,
|
||||
UDEV_BUILTIN_HWDB,
|
||||
UDEV_BUILTIN_INPUT_ID,
|
||||
UDEV_BUILTIN_KEYBOARD,
|
||||
|
13
units/factory-reset-now.target
Normal file
13
units/factory-reset-now.target
Normal file
@ -0,0 +1,13 @@
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
#
|
||||
# This file is part of systemd.
|
||||
#
|
||||
# systemd is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation; either version 2.1 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
[Unit]
|
||||
Description=Factory Reset Execution
|
||||
Documentation=man:systemd.special(7)
|
||||
Wants=systemd-factory-reset-complete.service
|
@ -8,5 +8,7 @@
|
||||
# (at your option) any later version.
|
||||
|
||||
[Unit]
|
||||
Description=Factory Reset
|
||||
Description=Factory Reset Initiation
|
||||
Documentation=man:systemd.special(7)
|
||||
Wants=systemd-factory-reset-reboot.service
|
||||
Before=systemd-factory-reset-reboot.service
|
||||
|
@ -37,6 +37,7 @@ units = [
|
||||
{ 'file' : 'emergency.target' },
|
||||
{ 'file' : 'exit.target' },
|
||||
{ 'file' : 'factory-reset.target' },
|
||||
{ 'file' : 'factory-reset-now.target' },
|
||||
{ 'file' : 'final.target' },
|
||||
{ 'file' : 'first-boot-complete.target' },
|
||||
{ 'file' : 'getty-pre.target' },
|
||||
@ -322,6 +323,19 @@ units = [
|
||||
},
|
||||
{ 'file' : 'systemd-creds@.service' },
|
||||
{ 'file' : 'systemd-exit.service' },
|
||||
{
|
||||
'file' : 'systemd-factory-reset@.service.in',
|
||||
},
|
||||
{
|
||||
'file' : 'systemd-factory-reset.socket',
|
||||
'symlinks' : ['sockets.target.wants/'],
|
||||
},
|
||||
{ 'file' : 'systemd-factory-reset-complete.service.in' },
|
||||
{ 'file' : 'systemd-factory-reset-reboot.service' },
|
||||
{
|
||||
'file' : 'systemd-factory-reset-request.service.in',
|
||||
'symlinks' : ['factory-reset.target.wants/'],
|
||||
},
|
||||
{
|
||||
'file' : 'systemd-firstboot.service',
|
||||
'conditions' : ['ENABLE_FIRSTBOOT'],
|
||||
@ -557,6 +571,10 @@ units = [
|
||||
'conditions' : ['ENABLE_BOOTLOADER', 'HAVE_OPENSSL', 'HAVE_TPM2'],
|
||||
'symlinks' : ['sysinit.target.wants/'],
|
||||
},
|
||||
{
|
||||
'file' : 'systemd-tpm2-clear.service.in',
|
||||
'conditions' : ['ENABLE_BOOTLOADER', 'HAVE_OPENSSL', 'HAVE_TPM2'],
|
||||
},
|
||||
{
|
||||
'file' : 'systemd-tpm2-setup.service.in',
|
||||
'conditions' : ['ENABLE_BOOTLOADER', 'HAVE_OPENSSL', 'HAVE_TPM2'],
|
||||
|
22
units/systemd-factory-reset-complete.service.in
Normal file
22
units/systemd-factory-reset-complete.service.in
Normal file
@ -0,0 +1,22 @@
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
#
|
||||
# This file is part of systemd.
|
||||
#
|
||||
# systemd is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation; either version 2.1 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
[Unit]
|
||||
Description=Mark the Factory Reset as Completed
|
||||
Documentation=man:systemd-factory-reset-complete.service(8)
|
||||
DefaultDependencies=no
|
||||
Requires=factory-reset-now.target
|
||||
After=factory-reset-now.target
|
||||
Conflicts=shutdown.target
|
||||
Before=shutdown.target
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
RemainAfterExit=yes
|
||||
ExecStart={{LIBEXECDIR}}/systemd-factory-reset complete --retrigger
|
17
units/systemd-factory-reset-reboot.service
Normal file
17
units/systemd-factory-reset-reboot.service
Normal file
@ -0,0 +1,17 @@
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
#
|
||||
# This file is part of systemd.
|
||||
#
|
||||
# systemd is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation; either version 2.1 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
[Unit]
|
||||
Description=Reboot to Execute Factory Reset
|
||||
Documentation=man:systemd.special(7)
|
||||
DefaultDependencies=no
|
||||
After=factory-reset.target
|
||||
Conflicts=shutdown.target
|
||||
Before=shutdown.target
|
||||
SuccessAction=reboot
|
22
units/systemd-factory-reset-request.service.in
Normal file
22
units/systemd-factory-reset-request.service.in
Normal file
@ -0,0 +1,22 @@
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
#
|
||||
# This file is part of systemd.
|
||||
#
|
||||
# systemd is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation; either version 2.1 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
[Unit]
|
||||
Description=Request Factory Reset on Next Boot
|
||||
Documentation=man:systemd-factory-reset-request.service(8)
|
||||
DefaultDependencies=no
|
||||
Conflicts=shutdown.target
|
||||
After=systemd-pcrphase-factory-reset.service
|
||||
Before=factory-reset.target shutdown.target
|
||||
ConditionFirmware=uefi
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
RemainAfterExit=yes
|
||||
ExecStart={{LIBEXECDIR}}/systemd-factory-reset request
|
24
units/systemd-factory-reset.socket
Normal file
24
units/systemd-factory-reset.socket
Normal file
@ -0,0 +1,24 @@
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
#
|
||||
# This file is part of systemd.
|
||||
#
|
||||
# systemd is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation; either version 2.1 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
[Unit]
|
||||
Description=Factory Reset Management
|
||||
Documentation=man:systemd-factory-reset.service(8)
|
||||
DefaultDependencies=no
|
||||
Before=sockets.target
|
||||
|
||||
[Socket]
|
||||
ListenStream=/run/systemd/io.systemd.FactoryReset
|
||||
FileDescriptorName=varlink
|
||||
SocketMode=0666
|
||||
Accept=yes
|
||||
MaxConnectionsPerSource=16
|
||||
|
||||
[Install]
|
||||
WantedBy=sockets.target
|
18
units/systemd-factory-reset@.service.in
Normal file
18
units/systemd-factory-reset@.service.in
Normal file
@ -0,0 +1,18 @@
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
#
|
||||
# This file is part of systemd.
|
||||
#
|
||||
# systemd is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation; either version 2.1 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
[Unit]
|
||||
Description=Factory Reset Management (Varlink)
|
||||
Documentation=man:systemd-factory-reset@.service(8)
|
||||
DefaultDependencies=no
|
||||
Conflicts=shutdown.target
|
||||
Before=shutdown.target
|
||||
|
||||
[Service]
|
||||
ExecStart=-{{LIBEXECDIR}}/systemd-factory-reset
|
@ -22,7 +22,7 @@ ConditionDirectoryNotEmpty=|/sysusr/usr/local/lib/repart.d
|
||||
DefaultDependencies=no
|
||||
Wants=modprobe@loop.service modprobe@dm_mod.service
|
||||
After=initrd-usr-fs.target modprobe@loop.service modprobe@dm_mod.service systemd-tpm2-setup-early.service
|
||||
Before=initrd-root-fs.target
|
||||
Before=initrd-root-fs.target factory-reset-now.target
|
||||
Conflicts=shutdown.target initrd-switch-root.target
|
||||
Before=shutdown.target initrd-switch-root.target
|
||||
|
||||
|
33
units/systemd-tpm2-clear.service.in
Normal file
33
units/systemd-tpm2-clear.service.in
Normal file
@ -0,0 +1,33 @@
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
#
|
||||
# This file is part of systemd.
|
||||
#
|
||||
# systemd is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation; either version 2.1 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
[Unit]
|
||||
Description=Issue TPM Clear Request
|
||||
Documentation=man:systemd-tpm2-clear.service(8)
|
||||
DefaultDependencies=no
|
||||
Conflicts=shutdown.target
|
||||
After=tpm2.target systemd-pcrphase-factory-reset.service
|
||||
Before=factory-reset.target shutdown.target
|
||||
|
||||
# Note all systems that have a TPM implement the "Physical Presence Interface" (PPI)
|
||||
ConditionPathExists=/sys/class/tpm/tpm0/ppi/request
|
||||
|
||||
# Only do this if we can be reasonably sure people accept our TPM use, which we
|
||||
# derive here from the fact that UKIs are used. Because if they do they are OK
|
||||
# with our SRK initialization and our PCR measurements, and hence should also
|
||||
# be OK with our TPM resets.
|
||||
ConditionSecurity=measured-uki
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
RemainAfterExit=yes
|
||||
ExecStart={{LIBEXECDIR}}/systemd-tpm2-clear --graceful
|
||||
|
||||
[Install]
|
||||
WantedBy=factory-reset.target
|
@ -12,5 +12,5 @@ Description=Trusted Platform Module
|
||||
Documentation=man:systemd.special(7)
|
||||
|
||||
# Make this a synchronization point on the first TPM device found
|
||||
After=dev-tpmrm0.device
|
||||
Wants=dev-tpmrm0.device
|
||||
After=dev-tpmrm0.device dev-tpm0.device
|
||||
Wants=dev-tpmrm0.device dev-tpm0.device
|
||||
|
Loading…
x
Reference in New Issue
Block a user