systemd-manifest — Generate and verify file manifests of directory trees
systemd-manifest [OPTIONS...] make [DIRECTORY
[MANIFEST]]
systemd-manifest [OPTIONS...] verify [DIRECTORY
[MANIFEST]]
systemd-manifest generates file manifests of directory trees, and verifies directory trees against such manifests. Four manifest formats are supported:
list¶A plain list of file names, one per line. Directories are suffixed with a slash.
sha256sums¶The format generated by
sha256sum(1),
i.e. a hash and a file name per line. Only regular files are listed. This is the format
systemd-sysupdate(8)
consumes as SHA256SUMS file.
mtree¶The BSD mtree format, listing inode type, access mode, ownership, size, hash, symlink target and device numbers of each file. This format is supported for generation only.
uapi16¶A UAPI.16
file manifest, i.e. a JSON-SEQ stream with one object per file. This is the format
systemd-sysupdate(8)
consumes as Uapi16Manifest file, and the same format
systemd-dissect(1)
generates with --uapi16. This is the default.
Manifests are generated and verified in a streaming fashion, i.e. one file at a time, and never loaded into memory as a whole, so that very large trees can be processed.
DIRECTORY [MANIFEST]]¶Generates a manifest of the specified directory tree, and writes it to the specified
manifest file. If no directory is specified, the current working directory is used. If no manifest
file is specified (or if "-" is specified), the manifest is written to standard
output. The manifest file is replaced atomically, i.e. it is only put in place once it has been
written completely.
DIRECTORY [MANIFEST]]¶Verifies the specified directory tree against the specified manifest file. If no
directory is specified, the current working directory is used. If no manifest file is specified (or
if "-" is specified), the manifest is read from standard input. If
--format= is not specified, the format is derived from the file name of the
manifest if possible, and otherwise defaults to uapi16.
Every entry of the manifest is checked against the tree: the file must exist, have the
listed inode type and, as far as the manifest carries this information and the
--field= setting asks for it, the listed size, hash, access mode, ownership,
modification time, extended attributes, symlink target and device numbers. All mismatches are
reported, and the command fails if there was at least one. The mtree format is not
supported for verification.
Note that the check only goes one way: every file listed in the manifest must exist in the tree as described, but the tree may contain additional files that the manifest does not list. These are not reported, and do not cause verification to fail. Hence a successful verification shows that the tree contains everything the manifest describes, but not that it contains nothing else.
The following options are understood:
--format=FORMAT¶Selects the manifest format. Takes one of list,
sha256sums, mtree, uapi16, see above. Defaults
to uapi16 for make. For verify defaults to
the format derived from the file name of the manifest, and uapi16 if that is not
possible.
--field=FIELDS¶Selects the per-file fields to include in the manifest when generating, and to check
when verifying. Takes a comma separated list of the field names listed in the table below. The
special values all, default and none may be used
to select all, the default set or no fields. Items may be prefixed with "+" or
"-" to add or remove fields from the current set instead of replacing it. The option
may be specified multiple times. Note that the inode type is always included, if the format can
express it. The list format carries no fields at all.
Table 1. Manifest fields
| Field | Included by default | Formats | Description |
|---|---|---|---|
mode | yes | mtree, uapi16 | Access mode bits |
uid | yes | mtree, uapi16 | Owning numeric UID |
gid | yes | mtree, uapi16 | Owning numeric GID |
size | yes | mtree, uapi16 | Size of regular files |
hash | yes | mtree, sha256sums, uapi16 | Digest of the contents of regular files |
symlink | yes | mtree, uapi16 | Symlink target |
device | yes | mtree, uapi16 | Major/minor numbers of device nodes |
hardlink | yes | uapi16 | Hardlink relationships |
mtime | no | mtree, uapi16 | Modification time |
user-xattr | yes | uapi16 | Extended attributes in the "user." namespace |
user-name | no | mtree, uapi16 | Owning user name |
group-name | no | mtree, uapi16 | Owning group name |
The fields mtime, user-name and
group-name are not included by default, and have to be enabled
explicitly, for example with "--field=+user-name,+group-name".
Modification times typically complicate reproducibility. User and group names are resolved via the
user database of the host (i.e. via NSS, like
tar(1)
does), hence reflect the host's view, which is not necessarily the one of the tree or image the
manifest describes. IDs that cannot be resolved to a name are counted as omitted metadata. When
verifying, the names are compared with the ones the host resolves the IDs to.
If user-xattr is enabled (which it is by default), the extended attributes in
the "user." namespace of all inodes except symlinks are recorded, including for
inodes that have no such attributes, so that a verifier can tell missing attributes apart from
unrecorded ones. On file systems that do not support extended attributes, inodes are considered to
have none. Extended attributes in other namespaces (such as security labels) are never
included.
The same default set of fields is used by systemd-dissect(1) and systemd-repart(8) when generating manifests.
--hash=ALGORITHM¶Selects the hash algorithm to use for the hash field of the
mtree format. Takes one of sha256 or sha512. With
sha512 a "sha512sum=" keyword is listed instead of
"sha256sum=". The other formats only support sha256. Defaults to
sha256.
--graceful¶When generating a manifest with make, do not fail if some inodes had to be skipped or some of their metadata had to be omitted, because they could not be read (for example due to missing privileges) or are not representable in the selected format. Instead, log a warning and return success. The top-level inode must be covered by the manifest in any case, but its metadata may be incomplete.
--private-key=PATH/URI, --private-key-source=TYPE[:NAME], --certificate=PATH, --certificate-source=TYPE[:NAME]¶Set the private key and certificate to use for signing. When generating a
uapi16 manifest with make, the manifest is signed if (and only
if) --private-key= is specified, in which case --certificate= must
be specified too. A signature object is then appended to the manifest, carrying a detached PKCS#7
(CMS) signature in DER format. The signature covers the exact bytes of the manifest preceding the
signature object (without any color sequences that might be inserted when writing to a terminal).
RSA, ECDSA and Ed25519 keys are supported. For RSA and ECDSA keys the signature is made directly over
the digest of the manifest, for Ed25519 keys it is made over a set of signed attributes carrying the
SHA-512 digest of the manifest, as required by RFC 8419. Signing requires OpenSSL.
When verifying, only --certificate= is used: if specified, the manifest must
carry a signature that verifies against this certificate, instead of one of the certificates found in
the VOA hierarchy, see --verify-signature= below. The
--certificate= option takes a path to a PEM encoded X.509 certificate or a URI
that's passed to the OpenSSL provider configured with --certificate-source=. The
--certificate-source= option takes one of "file" or
"provider", with the latter being followed by a specific provider identifier,
separated with a colon, e.g. "provider:pkcs11". The
--private-key= option can take a path or a URI that will be passed to the OpenSSL
engine or provider, as specified by --private-key-source= as a
"type:name" tuple, such as "engine:pkcs11".
--verify-signature=BOOL¶Controls whether to verify the signature of uapi16 manifests when
verifying a directory tree. Takes a boolean, defaults to true. If enabled, the manifest must carry a
PKCS#7 signature made with the private key of the certificate specified with
--certificate=, or, if that option is not used, of one of the X.509 certificates
found in the File
Hierarchy for the Verification of OS Artifacts (VOA), otherwise verification fails. In the
latter case, certificates are read from
below the VOA load paths OS/manifest/CONTEXT/x509/NAME-certificate.pem/etc/voa/, /run/voa/,
/usr/local/share/voa/ and /usr/share/voa/, where
OS is derived from
os-release(5) and
CONTEXT is configured with --voa-context=. Only artifact
verifiers are supported, i.e. the certificates are trusted as they are, and are not checked against
trust anchors. Verification fails if no certificates are found. If disabled, signature objects in the
manifest are ignored. The list and sha256sums formats carry no
signatures, hence for these this option has no effect, except that explicitly enabling it results in
an error. Requires OpenSSL.
--voa-context=CONTEXT¶Selects the VOA context to look up certificates in, if signatures are verified
without --certificate=, see above. Defaults to "default". Use
--voa-context=sysupdate to verify manifests against the same certificates
systemd-sysupdate(8)
uses for verifying Uapi16Manifest files it downloads.
--json=MODE¶Shows output formatted as JSON. Expects one of "short" (for the
shortest possible output without any redundant whitespace or line breaks), "pretty"
(for a pretty version of the same, with indentation and line breaks) or "off" (to turn
off JSON output, the default).
--no-pager¶Do not pipe output into a pager.
-h, --help¶--version¶Print a short version string and exit.
On success, 0 is returned, a non-zero failure code otherwise. In particular,
verify returns non-zero if the directory tree does not match the manifest, and
make returns non-zero if an inode had to be skipped or some of its requested metadata
had to be omitted, because it could not be read (for example due to missing privileges) or is not
representable in the selected format, unless --graceful is specified. In the latter
cases the manifest is still generated, but is not written to the output file if one is specified. Inodes
other than regular files skipped in sha256sums format are not considered a failure,
since this format does not list them by design.
Example 1. Generate an unsigned UAPI.16 manifest of a directory tree and verify it
$ systemd-manifest make /srv/tree > Uapi16Manifest $ systemd-manifest verify --verify-signature=no /srv/tree Uapi16Manifest
Example 2. Generate a SHA256SUMS file of the current directory, without ownership or mode information
$ systemd-manifest make --format=sha256sums > SHA256SUMS $ sha256sum -c SHA256SUMS
Example 3. Only verify file contents, ignoring ownership and access modes
$ systemd-manifest verify --verify-signature=no --field=size,hash /srv/tree Uapi16Manifest
Example 4. Generate a signed manifest, and verify it against the certificate
$ systemd-manifest make --private-key=foo-private-key.pem --certificate=foo-certificate.pem /srv/tree > Uapi16Manifest $ systemd-manifest verify --certificate=foo-certificate.pem /srv/tree Uapi16Manifest
Example 5. Verify a manifest against the certificates systemd-sysupdate trusts
# cp foo-certificate.pem /etc/voa/$(. /etc/os-release; echo $ID)/manifest/sysupdate/x509/ $ systemd-manifest verify --voa-context=sysupdate /srv/tree Uapi16Manifest