|
|
@ -38,20 +38,14 @@ fail at runtime.
|
|
|
|
Use cases
|
|
|
|
Use cases
|
|
|
|
=========
|
|
|
|
=========
|
|
|
|
|
|
|
|
|
|
|
|
By itself, the base fs-verity feature only provides integrity
|
|
|
|
By itself, fs-verity only provides integrity protection, i.e.
|
|
|
|
protection, i.e. detection of accidental (non-malicious) corruption.
|
|
|
|
detection of accidental (non-malicious) corruption.
|
|
|
|
|
|
|
|
|
|
|
|
However, because fs-verity makes retrieving the file hash extremely
|
|
|
|
However, because fs-verity makes retrieving the file hash extremely
|
|
|
|
efficient, it's primarily meant to be used as a tool to support
|
|
|
|
efficient, it's primarily meant to be used as a tool to support
|
|
|
|
authentication (detection of malicious modifications) or auditing
|
|
|
|
authentication (detection of malicious modifications) or auditing
|
|
|
|
(logging file hashes before use).
|
|
|
|
(logging file hashes before use).
|
|
|
|
|
|
|
|
|
|
|
|
Trusted userspace code (e.g. operating system code running on a
|
|
|
|
|
|
|
|
read-only partition that is itself authenticated by dm-verity) can
|
|
|
|
|
|
|
|
authenticate the contents of an fs-verity file by using the
|
|
|
|
|
|
|
|
`FS_IOC_MEASURE_VERITY`_ ioctl to retrieve its hash, then verifying a
|
|
|
|
|
|
|
|
digital signature of it.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
A standard file hash could be used instead of fs-verity. However,
|
|
|
|
A standard file hash could be used instead of fs-verity. However,
|
|
|
|
this is inefficient if the file is large and only a small portion may
|
|
|
|
this is inefficient if the file is large and only a small portion may
|
|
|
|
be accessed. This is often the case for Android application package
|
|
|
|
be accessed. This is often the case for Android application package
|
|
|
@ -69,24 +63,31 @@ still be used on read-only filesystems. fs-verity is for files that
|
|
|
|
must live on a read-write filesystem because they are independently
|
|
|
|
must live on a read-write filesystem because they are independently
|
|
|
|
updated and potentially user-installed, so dm-verity cannot be used.
|
|
|
|
updated and potentially user-installed, so dm-verity cannot be used.
|
|
|
|
|
|
|
|
|
|
|
|
The base fs-verity feature is a hashing mechanism only; actually
|
|
|
|
fs-verity does not mandate a particular scheme for authenticating its
|
|
|
|
authenticating the files may be done by:
|
|
|
|
file hashes. (Similarly, dm-verity does not mandate a particular
|
|
|
|
|
|
|
|
scheme for authenticating its block device root hashes.) Options for
|
|
|
|
|
|
|
|
authenticating fs-verity file hashes include:
|
|
|
|
|
|
|
|
|
|
|
|
* Userspace-only
|
|
|
|
- Trusted userspace code. Often, the userspace code that accesses
|
|
|
|
|
|
|
|
files can be trusted to authenticate them. Consider e.g. an
|
|
|
|
|
|
|
|
application that wants to authenticate data files before using them,
|
|
|
|
|
|
|
|
or an application loader that is part of the operating system (which
|
|
|
|
|
|
|
|
is already authenticated in a different way, such as by being loaded
|
|
|
|
|
|
|
|
from a read-only partition that uses dm-verity) and that wants to
|
|
|
|
|
|
|
|
authenticate applications before loading them. In these cases, this
|
|
|
|
|
|
|
|
trusted userspace code can authenticate a file's contents by
|
|
|
|
|
|
|
|
retrieving its fs-verity digest using `FS_IOC_MEASURE_VERITY`_, then
|
|
|
|
|
|
|
|
verifying a signature of it using any userspace cryptographic
|
|
|
|
|
|
|
|
library that supports digital signatures.
|
|
|
|
|
|
|
|
|
|
|
|
* Builtin signature verification + userspace policy
|
|
|
|
- Integrity Measurement Architecture (IMA). IMA supports fs-verity
|
|
|
|
|
|
|
|
file digests as an alternative to its traditional full file digests.
|
|
|
|
fs-verity optionally supports a simple signature verification
|
|
|
|
"IMA appraisal" enforces that files contain a valid, matching
|
|
|
|
mechanism where users can configure the kernel to require that
|
|
|
|
signature in their "security.ima" extended attribute, as controlled
|
|
|
|
all fs-verity files be signed by a key loaded into a keyring;
|
|
|
|
by the IMA policy. For more information, see the IMA documentation.
|
|
|
|
see `Built-in signature verification`_.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
* Integrity Measurement Architecture (IMA)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
IMA supports including fs-verity file digests and signatures in the
|
|
|
|
|
|
|
|
IMA measurement list and verifying fs-verity based file signatures
|
|
|
|
|
|
|
|
stored as security.ima xattrs, based on policy.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- Trusted userspace code in combination with `Built-in signature
|
|
|
|
|
|
|
|
verification`_. This approach should be used only with great care.
|
|
|
|
|
|
|
|
|
|
|
|
User API
|
|
|
|
User API
|
|
|
|
========
|
|
|
|
========
|
|
|
@ -111,8 +112,7 @@ follows::
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
This structure contains the parameters of the Merkle tree to build for
|
|
|
|
This structure contains the parameters of the Merkle tree to build for
|
|
|
|
the file, and optionally contains a signature. It must be initialized
|
|
|
|
the file. It must be initialized as follows:
|
|
|
|
as follows:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- ``version`` must be 1.
|
|
|
|
- ``version`` must be 1.
|
|
|
|
- ``hash_algorithm`` must be the identifier for the hash algorithm to
|
|
|
|
- ``hash_algorithm`` must be the identifier for the hash algorithm to
|
|
|
@ -129,12 +129,14 @@ as follows:
|
|
|
|
file or device. Currently the maximum salt size is 32 bytes.
|
|
|
|
file or device. Currently the maximum salt size is 32 bytes.
|
|
|
|
- ``salt_ptr`` is the pointer to the salt, or NULL if no salt is
|
|
|
|
- ``salt_ptr`` is the pointer to the salt, or NULL if no salt is
|
|
|
|
provided.
|
|
|
|
provided.
|
|
|
|
- ``sig_size`` is the size of the signature in bytes, or 0 if no
|
|
|
|
- ``sig_size`` is the size of the builtin signature in bytes, or 0 if no
|
|
|
|
signature is provided. Currently the signature is (somewhat
|
|
|
|
builtin signature is provided. Currently the builtin signature is
|
|
|
|
arbitrarily) limited to 16128 bytes. See `Built-in signature
|
|
|
|
(somewhat arbitrarily) limited to 16128 bytes.
|
|
|
|
verification`_ for more information.
|
|
|
|
- ``sig_ptr`` is the pointer to the builtin signature, or NULL if no
|
|
|
|
- ``sig_ptr`` is the pointer to the signature, or NULL if no
|
|
|
|
builtin signature is provided. A builtin signature is only needed
|
|
|
|
signature is provided.
|
|
|
|
if the `Built-in signature verification`_ feature is being used. It
|
|
|
|
|
|
|
|
is not needed for IMA appraisal, and it is not needed if the file
|
|
|
|
|
|
|
|
signature is being handled entirely in userspace.
|
|
|
|
- All reserved fields must be zeroed.
|
|
|
|
- All reserved fields must be zeroed.
|
|
|
|
|
|
|
|
|
|
|
|
FS_IOC_ENABLE_VERITY causes the filesystem to build a Merkle tree for
|
|
|
|
FS_IOC_ENABLE_VERITY causes the filesystem to build a Merkle tree for
|
|
|
@ -158,7 +160,7 @@ fatal signal), no changes are made to the file.
|
|
|
|
FS_IOC_ENABLE_VERITY can fail with the following errors:
|
|
|
|
FS_IOC_ENABLE_VERITY can fail with the following errors:
|
|
|
|
|
|
|
|
|
|
|
|
- ``EACCES``: the process does not have write access to the file
|
|
|
|
- ``EACCES``: the process does not have write access to the file
|
|
|
|
- ``EBADMSG``: the signature is malformed
|
|
|
|
- ``EBADMSG``: the builtin signature is malformed
|
|
|
|
- ``EBUSY``: this ioctl is already running on the file
|
|
|
|
- ``EBUSY``: this ioctl is already running on the file
|
|
|
|
- ``EEXIST``: the file already has verity enabled
|
|
|
|
- ``EEXIST``: the file already has verity enabled
|
|
|
|
- ``EFAULT``: the caller provided inaccessible memory
|
|
|
|
- ``EFAULT``: the caller provided inaccessible memory
|
|
|
@ -168,10 +170,10 @@ FS_IOC_ENABLE_VERITY can fail with the following errors:
|
|
|
|
reserved bits are set; or the file descriptor refers to neither a
|
|
|
|
reserved bits are set; or the file descriptor refers to neither a
|
|
|
|
regular file nor a directory.
|
|
|
|
regular file nor a directory.
|
|
|
|
- ``EISDIR``: the file descriptor refers to a directory
|
|
|
|
- ``EISDIR``: the file descriptor refers to a directory
|
|
|
|
- ``EKEYREJECTED``: the signature doesn't match the file
|
|
|
|
- ``EKEYREJECTED``: the builtin signature doesn't match the file
|
|
|
|
- ``EMSGSIZE``: the salt or signature is too long
|
|
|
|
- ``EMSGSIZE``: the salt or builtin signature is too long
|
|
|
|
- ``ENOKEY``: the fs-verity keyring doesn't contain the certificate
|
|
|
|
- ``ENOKEY``: the ".fs-verity" keyring doesn't contain the certificate
|
|
|
|
needed to verify the signature
|
|
|
|
needed to verify the builtin signature
|
|
|
|
- ``ENOPKG``: fs-verity recognizes the hash algorithm, but it's not
|
|
|
|
- ``ENOPKG``: fs-verity recognizes the hash algorithm, but it's not
|
|
|
|
available in the kernel's crypto API as currently configured (e.g.
|
|
|
|
available in the kernel's crypto API as currently configured (e.g.
|
|
|
|
for SHA-512, missing CONFIG_CRYPTO_SHA512).
|
|
|
|
for SHA-512, missing CONFIG_CRYPTO_SHA512).
|
|
|
@ -180,8 +182,8 @@ FS_IOC_ENABLE_VERITY can fail with the following errors:
|
|
|
|
support; or the filesystem superblock has not had the 'verity'
|
|
|
|
support; or the filesystem superblock has not had the 'verity'
|
|
|
|
feature enabled on it; or the filesystem does not support fs-verity
|
|
|
|
feature enabled on it; or the filesystem does not support fs-verity
|
|
|
|
on this file. (See `Filesystem support`_.)
|
|
|
|
on this file. (See `Filesystem support`_.)
|
|
|
|
- ``EPERM``: the file is append-only; or, a signature is required and
|
|
|
|
- ``EPERM``: the file is append-only; or, a builtin signature is
|
|
|
|
one was not provided.
|
|
|
|
required and one was not provided.
|
|
|
|
- ``EROFS``: the filesystem is read-only
|
|
|
|
- ``EROFS``: the filesystem is read-only
|
|
|
|
- ``ETXTBSY``: someone has the file open for writing. This can be the
|
|
|
|
- ``ETXTBSY``: someone has the file open for writing. This can be the
|
|
|
|
caller's file descriptor, another open file descriptor, or the file
|
|
|
|
caller's file descriptor, another open file descriptor, or the file
|
|
|
@ -270,9 +272,9 @@ This ioctl takes in a pointer to the following structure::
|
|
|
|
- ``FS_VERITY_METADATA_TYPE_DESCRIPTOR`` reads the fs-verity
|
|
|
|
- ``FS_VERITY_METADATA_TYPE_DESCRIPTOR`` reads the fs-verity
|
|
|
|
descriptor. See `fs-verity descriptor`_.
|
|
|
|
descriptor. See `fs-verity descriptor`_.
|
|
|
|
|
|
|
|
|
|
|
|
- ``FS_VERITY_METADATA_TYPE_SIGNATURE`` reads the signature which was
|
|
|
|
- ``FS_VERITY_METADATA_TYPE_SIGNATURE`` reads the builtin signature
|
|
|
|
passed to FS_IOC_ENABLE_VERITY, if any. See `Built-in signature
|
|
|
|
which was passed to FS_IOC_ENABLE_VERITY, if any. See `Built-in
|
|
|
|
verification`_.
|
|
|
|
signature verification`_.
|
|
|
|
|
|
|
|
|
|
|
|
The semantics are similar to those of ``pread()``. ``offset``
|
|
|
|
The semantics are similar to those of ``pread()``. ``offset``
|
|
|
|
specifies the offset in bytes into the metadata item to read from, and
|
|
|
|
specifies the offset in bytes into the metadata item to read from, and
|
|
|
@ -299,7 +301,7 @@ FS_IOC_READ_VERITY_METADATA can fail with the following errors:
|
|
|
|
overflowed
|
|
|
|
overflowed
|
|
|
|
- ``ENODATA``: the file is not a verity file, or
|
|
|
|
- ``ENODATA``: the file is not a verity file, or
|
|
|
|
FS_VERITY_METADATA_TYPE_SIGNATURE was requested but the file doesn't
|
|
|
|
FS_VERITY_METADATA_TYPE_SIGNATURE was requested but the file doesn't
|
|
|
|
have a built-in signature
|
|
|
|
have a builtin signature
|
|
|
|
- ``ENOTTY``: this type of filesystem does not implement fs-verity, or
|
|
|
|
- ``ENOTTY``: this type of filesystem does not implement fs-verity, or
|
|
|
|
this ioctl is not yet implemented on it
|
|
|
|
this ioctl is not yet implemented on it
|
|
|
|
- ``EOPNOTSUPP``: the kernel was not configured with fs-verity
|
|
|
|
- ``EOPNOTSUPP``: the kernel was not configured with fs-verity
|
|
|
@ -347,8 +349,8 @@ non-verity one, with the following exceptions:
|
|
|
|
with EIO (for read()) or SIGBUS (for mmap() reads).
|
|
|
|
with EIO (for read()) or SIGBUS (for mmap() reads).
|
|
|
|
|
|
|
|
|
|
|
|
- If the sysctl "fs.verity.require_signatures" is set to 1 and the
|
|
|
|
- If the sysctl "fs.verity.require_signatures" is set to 1 and the
|
|
|
|
file is not signed by a key in the fs-verity keyring, then opening
|
|
|
|
file is not signed by a key in the ".fs-verity" keyring, then
|
|
|
|
the file will fail. See `Built-in signature verification`_.
|
|
|
|
opening the file will fail. See `Built-in signature verification`_.
|
|
|
|
|
|
|
|
|
|
|
|
Direct access to the Merkle tree is not supported. Therefore, if a
|
|
|
|
Direct access to the Merkle tree is not supported. Therefore, if a
|
|
|
|
verity file is copied, or is backed up and restored, then it will lose
|
|
|
|
verity file is copied, or is backed up and restored, then it will lose
|
|
|
@ -433,20 +435,25 @@ root hash as well as other fields such as the file size::
|
|
|
|
Built-in signature verification
|
|
|
|
Built-in signature verification
|
|
|
|
===============================
|
|
|
|
===============================
|
|
|
|
|
|
|
|
|
|
|
|
With CONFIG_FS_VERITY_BUILTIN_SIGNATURES=y, fs-verity supports putting
|
|
|
|
CONFIG_FS_VERITY_BUILTIN_SIGNATURES=y adds supports for in-kernel
|
|
|
|
a portion of an authentication policy (see `Use cases`_) in the
|
|
|
|
verification of fs-verity builtin signatures.
|
|
|
|
kernel. Specifically, it adds support for:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1. At fs-verity module initialization time, a keyring ".fs-verity" is
|
|
|
|
**IMPORTANT**! Please take great care before using this feature.
|
|
|
|
created. The root user can add trusted X.509 certificates to this
|
|
|
|
It is not the only way to do signatures with fs-verity, and the
|
|
|
|
keyring using the add_key() system call, then (when done)
|
|
|
|
alternatives (such as userspace signature verification, and IMA
|
|
|
|
optionally use keyctl_restrict_keyring() to prevent additional
|
|
|
|
appraisal) can be much better. It's also easy to fall into a trap
|
|
|
|
certificates from being added.
|
|
|
|
of thinking this feature solves more problems than it actually does.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Enabling this option adds the following:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1. At boot time, the kernel creates a keyring named ".fs-verity". The
|
|
|
|
|
|
|
|
root user can add trusted X.509 certificates to this keyring using
|
|
|
|
|
|
|
|
the add_key() system call.
|
|
|
|
|
|
|
|
|
|
|
|
2. `FS_IOC_ENABLE_VERITY`_ accepts a pointer to a PKCS#7 formatted
|
|
|
|
2. `FS_IOC_ENABLE_VERITY`_ accepts a pointer to a PKCS#7 formatted
|
|
|
|
detached signature in DER format of the file's fs-verity digest.
|
|
|
|
detached signature in DER format of the file's fs-verity digest.
|
|
|
|
On success, this signature is persisted alongside the Merkle tree.
|
|
|
|
On success, the ioctl persists the signature alongside the Merkle
|
|
|
|
Then, any time the file is opened, the kernel will verify the
|
|
|
|
tree. Then, any time the file is opened, the kernel verifies the
|
|
|
|
file's actual digest against this signature, using the certificates
|
|
|
|
file's actual digest against this signature, using the certificates
|
|
|
|
in the ".fs-verity" keyring.
|
|
|
|
in the ".fs-verity" keyring.
|
|
|
|
|
|
|
|
|
|
|
@ -454,8 +461,8 @@ kernel. Specifically, it adds support for:
|
|
|
|
When set to 1, the kernel requires that all verity files have a
|
|
|
|
When set to 1, the kernel requires that all verity files have a
|
|
|
|
correctly signed digest as described in (2).
|
|
|
|
correctly signed digest as described in (2).
|
|
|
|
|
|
|
|
|
|
|
|
fs-verity file digests must be signed in the following format, which
|
|
|
|
The data that the signature as described in (2) must be a signature of
|
|
|
|
is similar to the structure used by `FS_IOC_MEASURE_VERITY`_::
|
|
|
|
is the fs-verity file digest in the following format::
|
|
|
|
|
|
|
|
|
|
|
|
struct fsverity_formatted_digest {
|
|
|
|
struct fsverity_formatted_digest {
|
|
|
|
char magic[8]; /* must be "FSVerity" */
|
|
|
|
char magic[8]; /* must be "FSVerity" */
|
|
|
@ -464,13 +471,66 @@ is similar to the structure used by `FS_IOC_MEASURE_VERITY`_::
|
|
|
|
__u8 digest[];
|
|
|
|
__u8 digest[];
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
fs-verity's built-in signature verification support is meant as a
|
|
|
|
That's it. It should be emphasized again that fs-verity builtin
|
|
|
|
relatively simple mechanism that can be used to provide some level of
|
|
|
|
signatures are not the only way to do signatures with fs-verity. See
|
|
|
|
authenticity protection for verity files, as an alternative to doing
|
|
|
|
`Use cases`_ for an overview of ways in which fs-verity can be used.
|
|
|
|
the signature verification in userspace or using IMA-appraisal.
|
|
|
|
fs-verity builtin signatures have some major limitations that should
|
|
|
|
However, with this mechanism, userspace programs still need to check
|
|
|
|
be carefully considered before using them:
|
|
|
|
that the verity bit is set, and there is no protection against verity
|
|
|
|
|
|
|
|
files being swapped around.
|
|
|
|
- Builtin signature verification does *not* make the kernel enforce
|
|
|
|
|
|
|
|
that any files actually have fs-verity enabled. Thus, it is not a
|
|
|
|
|
|
|
|
complete authentication policy. Currently, if it is used, the only
|
|
|
|
|
|
|
|
way to complete the authentication policy is for trusted userspace
|
|
|
|
|
|
|
|
code to explicitly check whether files have fs-verity enabled with a
|
|
|
|
|
|
|
|
signature before they are accessed. (With
|
|
|
|
|
|
|
|
fs.verity.require_signatures=1, just checking whether fs-verity is
|
|
|
|
|
|
|
|
enabled suffices.) But, in this case the trusted userspace code
|
|
|
|
|
|
|
|
could just store the signature alongside the file and verify it
|
|
|
|
|
|
|
|
itself using a cryptographic library, instead of using this feature.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- A file's builtin signature can only be set at the same time that
|
|
|
|
|
|
|
|
fs-verity is being enabled on the file. Changing or deleting the
|
|
|
|
|
|
|
|
builtin signature later requires re-creating the file.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- Builtin signature verification uses the same set of public keys for
|
|
|
|
|
|
|
|
all fs-verity enabled files on the system. Different keys cannot be
|
|
|
|
|
|
|
|
trusted for different files; each key is all or nothing.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- The sysctl fs.verity.require_signatures applies system-wide.
|
|
|
|
|
|
|
|
Setting it to 1 only works when all users of fs-verity on the system
|
|
|
|
|
|
|
|
agree that it should be set to 1. This limitation can prevent
|
|
|
|
|
|
|
|
fs-verity from being used in cases where it would be helpful.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- Builtin signature verification can only use signature algorithms
|
|
|
|
|
|
|
|
that are supported by the kernel. For example, the kernel does not
|
|
|
|
|
|
|
|
yet support Ed25519, even though this is often the signature
|
|
|
|
|
|
|
|
algorithm that is recommended for new cryptographic designs.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- fs-verity builtin signatures are in PKCS#7 format, and the public
|
|
|
|
|
|
|
|
keys are in X.509 format. These formats are commonly used,
|
|
|
|
|
|
|
|
including by some other kernel features (which is why the fs-verity
|
|
|
|
|
|
|
|
builtin signatures use them), and are very feature rich.
|
|
|
|
|
|
|
|
Unfortunately, history has shown that code that parses and handles
|
|
|
|
|
|
|
|
these formats (which are from the 1990s and are based on ASN.1)
|
|
|
|
|
|
|
|
often has vulnerabilities as a result of their complexity. This
|
|
|
|
|
|
|
|
complexity is not inherent to the cryptography itself.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fs-verity users who do not need advanced features of X.509 and
|
|
|
|
|
|
|
|
PKCS#7 should strongly consider using simpler formats, such as plain
|
|
|
|
|
|
|
|
Ed25519 keys and signatures, and verifying signatures in userspace.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fs-verity users who choose to use X.509 and PKCS#7 anyway should
|
|
|
|
|
|
|
|
still consider that verifying those signatures in userspace is more
|
|
|
|
|
|
|
|
flexible (for other reasons mentioned earlier in this document) and
|
|
|
|
|
|
|
|
eliminates the need to enable CONFIG_FS_VERITY_BUILTIN_SIGNATURES
|
|
|
|
|
|
|
|
and its associated increase in kernel attack surface. In some cases
|
|
|
|
|
|
|
|
it can even be necessary, since advanced X.509 and PKCS#7 features
|
|
|
|
|
|
|
|
do not always work as intended with the kernel. For example, the
|
|
|
|
|
|
|
|
kernel does not check X.509 certificate validity times.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Note: IMA appraisal, which supports fs-verity, does not use PKCS#7
|
|
|
|
|
|
|
|
for its signatures, so it partially avoids the issues discussed
|
|
|
|
|
|
|
|
here. IMA appraisal does use X.509.
|
|
|
|
|
|
|
|
|
|
|
|
Filesystem support
|
|
|
|
Filesystem support
|
|
|
|
==================
|
|
|
|
==================
|
|
|
|