요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.
1. 요약·해설
원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.
Policy 작성과 배포
ipe.rst:140-312Rule 문법, DEFAULT, boot policy, PKCS#7 서명, securityfs 배포·활성화·삭제 절차를 정리합니다.
Mode와 audit event
ipe.rst:313-539Permissive/enforced mode와 네 종류의 audit record, field 및 error code를 설명합니다.
Operation과 무결성 property
ipe.rst:540-702`op`, `action`, initramfs, dm-verity, fs-verity 관련 property를 설명합니다.
Policy 예제와 참고 자료
ipe.rst:703-824허용·거부 policy 예제, IMA·LoadPin 비교와 관련 자료를 제공합니다.
2. 영어 원문 전체
번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.
원문 전체 펼치기
.. SPDX-License-Identifier: GPL-2.0
Integrity Policy Enforcement (IPE)
==================================
.. NOTE::
This is the documentation for admins, system builders, or individuals
attempting to use IPE. If you're looking for more developer-focused
documentation about IPE please see :doc:`the design docs </security/ipe>`.
Overview
--------
Integrity Policy Enforcement (IPE) is a Linux Security Module that takes a
complementary approach to access control. Unlike traditional access control
mechanisms that rely on labels and paths for decision-making, IPE focuses
on the immutable security properties inherent to system components. These
properties are fundamental attributes or features of a system component
that cannot be altered, ensuring a consistent and reliable basis for
security decisions.
To elaborate, in the context of IPE, system components primarily refer to
files or the devices these files reside on. However, this is just a
starting point. The concept of system components is flexible and can be
extended to include new elements as the system evolves. The immutable
properties include the origin of a file, which remains constant and
unchangeable over time. For example, IPE policies can be crafted to trust
files originating from the initramfs. Since initramfs is typically verified
by the bootloader, its files are deemed trustworthy; "file is from
initramfs" becomes an immutable property under IPE's consideration.
The immutable property concept extends to the security features enabled on
a file's origin, such as dm-verity or fs-verity, which provide a layer of
integrity and trust. For example, IPE allows the definition of policies
that trust files from a dm-verity protected device. dm-verity ensures the
integrity of an entire device by providing a verifiable and immutable state
of its contents. Similarly, fs-verity offers filesystem-level integrity
checks, allowing IPE to enforce policies that trust files protected by
fs-verity. These two features cannot be turned off once established, so
they are considered immutable properties. These examples demonstrate how
IPE leverages immutable properties, such as a file's origin and its
integrity protection mechanisms, to make access control decisions.
For the IPE policy, specifically, it grants the ability to enforce
stringent access controls by assessing security properties against
reference values defined within the policy. This assessment can be based on
the existence of a security property (e.g., verifying if a file originates
from initramfs) or evaluating the internal state of an immutable security
property. The latter includes checking the roothash of a dm-verity
protected device, determining whether dm-verity possesses a valid
signature, assessing the digest of a fs-verity protected file, or
determining whether fs-verity possesses a valid built-in signature. This
nuanced approach to policy enforcement enables a highly secure and
customizable system defense mechanism, tailored to specific security
requirements and trust models.
To enable IPE, ensure that ``CONFIG_SECURITY_IPE`` (under
:menuselection:`Security -> Integrity Policy Enforcement (IPE)`) config
option is enabled.
Use Cases
---------
IPE works best in fixed-function devices: devices in which their purpose
is clearly defined and not supposed to be changed (e.g. network firewall
device in a data center, an IoT device, etcetera), where all software and
configuration is built and provisioned by the system owner.
IPE is a long-way off for use in general-purpose computing: the Linux
community as a whole tends to follow a decentralized trust model (known as
the web of trust), which IPE has no support for it yet. Instead, IPE
supports PKI (public key infrastructure), which generally designates a
set of trusted entities that provide a measure of absolute trust.
Additionally, while most packages are signed today, the files inside
the packages (for instance, the executables), tend to be unsigned. This
makes it difficult to utilize IPE in systems where a package manager is
expected to be functional, without major changes to the package manager
and ecosystem behind it.
The digest_cache LSM [#digest_cache_lsm]_ is a system that when combined with IPE,
could be used to enable and support general-purpose computing use cases.
Known Limitations
-----------------
IPE cannot verify the integrity of anonymous executable memory, such as
the trampolines created by gcc closures and libffi (<3.4.2), or JIT'd code.
Unfortunately, as this is dynamically generated code, there is no way
for IPE to ensure the integrity of this code to form a trust basis.
IPE cannot verify the integrity of programs written in interpreted
languages when these scripts are invoked by passing these program files
to the interpreter. This is because the way interpreters execute these
files; the scripts themselves are not evaluated as executable code
through one of IPE's hooks, but they are merely text files that are read
(as opposed to compiled executables) [#interpreters]_.
Threat Model
------------
IPE specifically targets the risk of tampering with user-space executable
code after the kernel has initially booted, including the kernel modules
loaded from userspace via ``modprobe`` or ``insmod``.
To illustrate, consider a scenario where an untrusted binary, possibly
malicious, is downloaded along with all necessary dependencies, including a
loader and libc. The primary function of IPE in this context is to prevent
the execution of such binaries and their dependencies.
IPE achieves this by verifying the integrity and authenticity of all
executable code before allowing them to run. It conducts a thorough
check to ensure that the code's integrity is intact and that they match an
authorized reference value (digest, signature, etc) as per the defined
policy. If a binary does not pass this verification process, either
because its integrity has been compromised or it does not meet the
authorization criteria, IPE will deny its execution. Additionally, IPE
generates audit logs which may be utilized to detect and analyze failures
resulting from policy violation.
Tampering threat scenarios include modification or replacement of
executable code by a range of actors including:
- Actors with physical access to the hardware
- Actors with local network access to the system
- Actors with access to the deployment system
- Compromised internal systems under external control
- Malicious end users of the system
- Compromised end users of the system
- Remote (external) compromise of the system
IPE does not mitigate threats arising from malicious but authorized
developers (with access to a signing certificate), or compromised
developer tools used by them (i.e. return-oriented programming attacks).
Additionally, IPE draws hard security boundary between userspace and
kernelspace. As a result, kernel-level exploits are considered outside
the scope of IPE and mitigation is left to other mechanisms.
Policy
------
IPE policy is a plain-text [#devdoc]_ policy composed of multiple statements
over several lines. There is one required line, at the top of the
policy, indicating the policy name, and the policy version, for
instance::
policy_name=Ex_Policy policy_version=0.0.0
The policy name is a unique key identifying this policy in a human
readable name. This is used to create nodes under securityfs as well as
uniquely identify policies to deploy new policies vs update existing
policies.
The policy version indicates the current version of the policy (NOT the
policy syntax version). This is used to prevent rollback of policy to
potentially insecure previous versions of the policy.
The next portion of IPE policy are rules. Rules are formed by key=value
pairs, known as properties. IPE rules require two properties: ``action``,
which determines what IPE does when it encounters a match against the
rule, and ``op``, which determines when the rule should be evaluated.
The ordering is significant, a rule must start with ``op``, and end with
``action``. Thus, a minimal rule is::
op=EXECUTE action=ALLOW
This example will allow any execution. Additional properties are used to
assess immutable security properties about the files being evaluated.
These properties are intended to be descriptions of systems within the
kernel that can provide a measure of integrity verification, such that IPE
can determine the trust of the resource based on the value of the property.
Rules are evaluated top-to-bottom. As a result, any revocation rules,
or denies should be placed early in the file to ensure that these rules
are evaluated before a rule with ``action=ALLOW``.
IPE policy supports comments. The character '#' will function as a
comment, ignoring all characters to the right of '#' until the newline.
The default behavior of IPE evaluations can also be expressed in policy,
through the ``DEFAULT`` statement. This can be done at a global level,
or a per-operation level::
# Global
DEFAULT action=ALLOW
# Operation Specific
DEFAULT op=EXECUTE action=ALLOW
A default must be set for all known operations in IPE. If you want to
preserve older policies being compatible with newer kernels that can introduce
new operations, set a global default of ``ALLOW``, then override the
defaults on a per-operation basis (as above).
With configurable policy-based LSMs, there's several issues with
enforcing the configurable policies at startup, around reading and
parsing the policy:
1. The kernel *should* not read files from userspace, so directly reading
the policy file is prohibited.
2. The kernel command line has a character limit, and one kernel module
should not reserve the entire character limit for its own
configuration.
3. There are various boot loaders in the kernel ecosystem, so handing
off a memory block would be costly to maintain.
As a result, IPE has addressed this problem through a concept of a "boot
policy". A boot policy is a minimal policy which is compiled into the
kernel. This policy is intended to get the system to a state where
userspace is set up and ready to receive commands, at which point a more
complex policy can be deployed via securityfs. The boot policy can be
specified via ``SECURITY_IPE_BOOT_POLICY`` config option, which accepts
a path to a plain-text version of the IPE policy to apply. This policy
will be compiled into the kernel. If not specified, IPE will be disabled
until a policy is deployed and activated through securityfs.
Deploying Policies
~~~~~~~~~~~~~~~~~~
Policies can be deployed from userspace through securityfs. These policies
are signed through the PKCS#7 message format to enforce some level of
authorization of the policies (prohibiting an attacker from gaining
unconstrained root, and deploying an "allow all" policy). These
policies must be signed by a certificate that chains to the
``SYSTEM_TRUSTED_KEYRING``, or to the secondary and/or platform keyrings if
``CONFIG_IPE_POLICY_SIG_SECONDARY_KEYRING`` and/or
``CONFIG_IPE_POLICY_SIG_PLATFORM_KEYRING`` are enabled, respectively.
With openssl, the policy can be signed by::
openssl smime -sign \
-in "$MY_POLICY" \
-signer "$MY_CERTIFICATE" \
-inkey "$MY_PRIVATE_KEY" \
-noattr \
-nodetach \
-nosmimecap \
-outform der \
-out "$MY_POLICY.p7b"
Deploying the policies is done through securityfs, through the
``new_policy`` node. To deploy a policy, simply cat the file into the
securityfs node::
cat "$MY_POLICY.p7b" > /sys/kernel/security/ipe/new_policy
Upon success, this will create one subdirectory under
``/sys/kernel/security/ipe/policies/``. The subdirectory will be the
``policy_name`` field of the policy deployed, so for the example above,
the directory will be ``/sys/kernel/security/ipe/policies/Ex_Policy``.
Within this directory, there will be seven files: ``pkcs7``, ``policy``,
``name``, ``version``, ``active``, ``update``, and ``delete``.
The ``pkcs7`` file is read-only. Reading it returns the raw PKCS#7 data
that was provided to the kernel, representing the policy. If the policy being
read is the boot policy, this will return ``ENOENT``, as it is not signed.
The ``policy`` file is read only. Reading it returns the PKCS#7 inner
content of the policy, which will be the plain text policy.
The ``active`` file is used to set a policy as the currently active policy.
This file is rw, and accepts a value of ``"1"`` to set the policy as active.
Since only a single policy can be active at one time, all other policies
will be marked inactive. The policy being marked active must have a policy
version greater or equal to the currently-running version.
The ``update`` file is used to update a policy that is already present
in the kernel. This file is write-only and accepts a PKCS#7 signed
policy. Two checks will always be performed on this policy: First, the
``policy_names`` must match with the updated version and the existing
version. Second the updated policy must have a policy version greater than
the currently-running version. This is to prevent rollback attacks.
The ``delete`` file is used to remove a policy that is no longer needed.
This file is write-only and accepts a value of ``1`` to delete the policy.
On deletion, the securityfs node representing the policy will be removed.
However, delete the current active policy is not allowed and will return
an operation not permitted error.
Similarly, writing to both ``update`` and ``new_policy`` could result in
bad message(policy syntax error) or file exists error. The latter error happens
when trying to deploy a policy with a ``policy_name`` while the kernel already
has a deployed policy with the same ``policy_name``.
Deploying a policy will *not* cause IPE to start enforcing the policy. IPE will
only enforce the policy marked active. Note that only one policy can be active
at a time.
Once deployment is successful, the policy can be activated, by writing file
``/sys/kernel/security/ipe/policies/$policy_name/active``.
For example, the ``Ex_Policy`` can be activated by::
echo 1 > "/sys/kernel/security/ipe/policies/Ex_Policy/active"
From above point on, ``Ex_Policy`` is now the enforced policy on the
system.
IPE also provides a way to delete policies. This can be done via the
``delete`` securityfs node,
``/sys/kernel/security/ipe/policies/$policy_name/delete``.
Writing ``1`` to that file deletes the policy::
echo 1 > "/sys/kernel/security/ipe/policies/$policy_name/delete"
There is only one requirement to delete a policy: the policy being deleted
must be inactive.
.. NOTE::
If a traditional MAC system is enabled (SELinux, apparmor, smack), all
writes to ipe's securityfs nodes require ``CAP_MAC_ADMIN``.
Modes
~~~~~
IPE supports two modes of operation: permissive (similar to SELinux's
permissive mode) and enforced. In permissive mode, all events are
checked and policy violations are logged, but the policy is not really
enforced. This allows users to test policies before enforcing them.
The default mode is enforce, and can be changed via the kernel command
line parameter ``ipe.enforce=(0|1)``, or the securityfs node
``/sys/kernel/security/ipe/enforce``.
.. NOTE::
If a traditional MAC system is enabled (SELinux, apparmor, smack, etcetera),
all writes to ipe's securityfs nodes require ``CAP_MAC_ADMIN``.
Audit Events
~~~~~~~~~~~~
1420 AUDIT_IPE_ACCESS
^^^^^^^^^^^^^^^^^^^^^
Event Examples::
type=1420 audit(1653364370.067:61): ipe_op=EXECUTE ipe_hook=MMAP enforcing=1 pid=2241 comm="ld-linux.so" path="/deny/lib/libc.so.6" dev="sda2" ino=14549020 rule="DEFAULT action=DENY"
type=1300 audit(1653364370.067:61): SYSCALL arch=c000003e syscall=9 success=no exit=-13 a0=7f1105a28000 a1=195000 a2=5 a3=812 items=0 ppid=2219 pid=2241 auid=0 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts0 ses=2 comm="ld-linux.so" exe="/tmp/ipe-test/lib/ld-linux.so" subj=unconfined key=(null)
type=1327 audit(1653364370.067:61): 707974686F6E3300746573742F6D61696E2E7079002D6E00
type=1420 audit(1653364735.161:64): ipe_op=EXECUTE ipe_hook=MMAP enforcing=1 pid=2472 comm="mmap_test" path=? dev=? ino=? rule="DEFAULT action=DENY"
type=1300 audit(1653364735.161:64): SYSCALL arch=c000003e syscall=9 success=no exit=-13 a0=0 a1=1000 a2=4 a3=21 items=0 ppid=2219 pid=2472 auid=0 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts0 ses=2 comm="mmap_test" exe="/root/overlake_test/upstream_test/vol_fsverity/bin/mmap_test" subj=unconfined key=(null)
type=1327 audit(1653364735.161:64): 707974686F6E3300746573742F6D61696E2E7079002D6E00
This event indicates that IPE made an access control decision; the IPE
specific record (1420) is always emitted in conjunction with a
``AUDITSYSCALL`` record.
Determining whether IPE is in permissive or enforced mode can be derived
from ``success`` property and exit code of the ``AUDITSYSCALL`` record.
Field descriptions:
+-----------+------------+-----------+---------------------------------------------------------------------------------+
| Field | Value Type | Optional? | Description of Value |
+===========+============+===========+=================================================================================+
| ipe_op | string | No | The IPE operation name associated with the log |
+-----------+------------+-----------+---------------------------------------------------------------------------------+
| ipe_hook | string | No | The name of the LSM hook that triggered the IPE event |
+-----------+------------+-----------+---------------------------------------------------------------------------------+
| enforcing | integer | No | The current IPE enforcing state 1 is in enforcing mode, 0 is in permissive mode |
+-----------+------------+-----------+---------------------------------------------------------------------------------+
| pid | integer | No | The pid of the process that triggered the IPE event. |
+-----------+------------+-----------+---------------------------------------------------------------------------------+
| comm | string | No | The command line program name of the process that triggered the IPE event |
+-----------+------------+-----------+---------------------------------------------------------------------------------+
| path | string | Yes | The absolute path to the evaluated file |
+-----------+------------+-----------+---------------------------------------------------------------------------------+
| ino | integer | Yes | The inode number of the evaluated file |
+-----------+------------+-----------+---------------------------------------------------------------------------------+
| dev | string | Yes | The device name of the evaluated file, e.g. vda |
+-----------+------------+-----------+---------------------------------------------------------------------------------+
| rule | string | No | The matched policy rule |
+-----------+------------+-----------+---------------------------------------------------------------------------------+
1421 AUDIT_IPE_CONFIG_CHANGE
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Event Example::
type=1421 audit(1653425583.136:54): old_active_pol_name="Allow_All" old_active_pol_version=0.0.0 old_policy_digest=sha256:E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855 new_active_pol_name="boot_verified" new_active_pol_version=0.0.0 new_policy_digest=sha256:820EEA5B40CA42B51F68962354BA083122A20BB846F26765076DD8EED7B8F4DB auid=4294967295 ses=4294967295 lsm=ipe res=1
type=1300 audit(1653425583.136:54): SYSCALL arch=c000003e syscall=1 success=yes exit=2 a0=3 a1=5596fcae1fb0 a2=2 a3=2 items=0 ppid=184 pid=229 auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts0 ses=4294967295 comm="python3" exe="/usr/bin/python3.10" key=(null)
type=1327 audit(1653425583.136:54): PROCTITLE proctitle=707974686F6E3300746573742F6D61696E2E7079002D66002E2
This event indicates that IPE switched the active poliy from one to another
along with the version and the hash digest of the two policies.
Note IPE can only have one policy active at a time, all access decision
evaluation is based on the current active policy.
The normal procedure to deploy a new policy is loading the policy to deploy
into the kernel first, then switch the active policy to it.
This record will always be emitted in conjunction with a ``AUDITSYSCALL`` record for the ``write`` syscall.
Field descriptions:
+------------------------+------------+-----------+---------------------------------------------------+
| Field | Value Type | Optional? | Description of Value |
+========================+============+===========+===================================================+
| old_active_pol_name | string | Yes | The name of previous active policy |
+------------------------+------------+-----------+---------------------------------------------------+
| old_active_pol_version | string | Yes | The version of previous active policy |
+------------------------+------------+-----------+---------------------------------------------------+
| old_policy_digest | string | Yes | The hash of previous active policy |
+------------------------+------------+-----------+---------------------------------------------------+
| new_active_pol_name | string | No | The name of current active policy |
+------------------------+------------+-----------+---------------------------------------------------+
| new_active_pol_version | string | No | The version of current active policy |
+------------------------+------------+-----------+---------------------------------------------------+
| new_policy_digest | string | No | The hash of current active policy |
+------------------------+------------+-----------+---------------------------------------------------+
| auid | integer | No | The login user ID |
+------------------------+------------+-----------+---------------------------------------------------+
| ses | integer | No | The login session ID |
+------------------------+------------+-----------+---------------------------------------------------+
| lsm | string | No | The lsm name associated with the event |
+------------------------+------------+-----------+---------------------------------------------------+
| res | integer | No | The result of the audited operation(success/fail) |
+------------------------+------------+-----------+---------------------------------------------------+
1422 AUDIT_IPE_POLICY_LOAD
^^^^^^^^^^^^^^^^^^^^^^^^^^
Event Example::
type=1422 audit(1653425529.927:53): policy_name="boot_verified" policy_version=0.0.0 policy_digest=sha256:820EEA5B40CA42B51F68962354BA083122A20BB846F26765076DD8EED7B8F4DB auid=4294967295 ses=4294967295 lsm=ipe res=1 errno=0
type=1300 audit(1653425529.927:53): arch=c000003e syscall=1 success=yes exit=2567 a0=3 a1=5596fcae1fb0 a2=a07 a3=2 items=0 ppid=184 pid=229 auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts0 ses=4294967295 comm="python3" exe="/usr/bin/python3.10" key=(null)
type=1327 audit(1653425529.927:53): PROCTITLE proctitle=707974686F6E3300746573742F6D61696E2E7079002D66002E2E
This record indicates a new policy has been loaded into the kernel with the policy name, policy version and policy hash.
This record will always be emitted in conjunction with a ``AUDITSYSCALL`` record for the ``write`` syscall.
Field descriptions:
+----------------+------------+-----------+-------------------------------------------------------------+
| Field | Value Type | Optional? | Description of Value |
+================+============+===========+=============================================================+
| policy_name | string | Yes | The policy_name |
+----------------+------------+-----------+-------------------------------------------------------------+
| policy_version | string | Yes | The policy_version |
+----------------+------------+-----------+-------------------------------------------------------------+
| policy_digest | string | Yes | The policy hash |
+----------------+------------+-----------+-------------------------------------------------------------+
| auid | integer | No | The login user ID |
+----------------+------------+-----------+-------------------------------------------------------------+
| ses | integer | No | The login session ID |
+----------------+------------+-----------+-------------------------------------------------------------+
| lsm | string | No | The lsm name associated with the event |
+----------------+------------+-----------+-------------------------------------------------------------+
| res | integer | No | The result of the audited operation(success/fail) |
+----------------+------------+-----------+-------------------------------------------------------------+
| errno | integer | No | Error code from policy loading operations (see table below) |
+----------------+------------+-----------+-------------------------------------------------------------+
Policy error codes (errno):
The following table lists the error codes that may appear in the errno field while loading or updating the policy:
+----------------+--------------------------------------------------------+
| Error Code | Description |
+================+========================================================+
| 0 | Success |
+----------------+--------------------------------------------------------+
| -EPERM | Insufficient permission |
+----------------+--------------------------------------------------------+
| -EEXIST | Same name policy already deployed |
+----------------+--------------------------------------------------------+
| -EBADMSG | Policy is invalid |
+----------------+--------------------------------------------------------+
| -ENOMEM | Out of memory (OOM) |
+----------------+--------------------------------------------------------+
| -ERANGE | Policy version number overflow |
+----------------+--------------------------------------------------------+
| -EINVAL | Policy version parsing error |
+----------------+--------------------------------------------------------+
| -ENOKEY | Key used to sign the IPE policy not found in keyring |
+----------------+--------------------------------------------------------+
| -EKEYREJECTED | Policy signature verification failed |
+----------------+--------------------------------------------------------+
| -ESTALE | Attempting to update an IPE policy with older version |
+----------------+--------------------------------------------------------+
| -ENOENT | Policy was deleted while updating |
+----------------+--------------------------------------------------------+
1404 AUDIT_MAC_STATUS
^^^^^^^^^^^^^^^^^^^^^
Event Examples::
type=1404 audit(1653425689.008:55): enforcing=0 old_enforcing=1 auid=4294967295 ses=4294967295 enabled=1 old-enabled=1 lsm=ipe res=1
type=1300 audit(1653425689.008:55): arch=c000003e syscall=1 success=yes exit=2 a0=1 a1=55c1065e5c60 a2=2 a3=0 items=0 ppid=405 pid=441 auid=0 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=)
type=1327 audit(1653425689.008:55): proctitle="-bash"
type=1404 audit(1653425689.008:55): enforcing=1 old_enforcing=0 auid=4294967295 ses=4294967295 enabled=1 old-enabled=1 lsm=ipe res=1
type=1300 audit(1653425689.008:55): arch=c000003e syscall=1 success=yes exit=2 a0=1 a1=55c1065e5c60 a2=2 a3=0 items=0 ppid=405 pid=441 auid=0 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=)
type=1327 audit(1653425689.008:55): proctitle="-bash"
This record will always be emitted in conjunction with a ``AUDITSYSCALL`` record for the ``write`` syscall.
Field descriptions:
+---------------+------------+-----------+-------------------------------------------------------------------------------------------------+
| Field | Value Type | Optional? | Description of Value |
+===============+============+===========+=================================================================================================+
| enforcing | integer | No | The enforcing state IPE is being switched to, 1 is in enforcing mode, 0 is in permissive mode |
+---------------+------------+-----------+-------------------------------------------------------------------------------------------------+
| old_enforcing | integer | No | The enforcing state IPE is being switched from, 1 is in enforcing mode, 0 is in permissive mode |
+---------------+------------+-----------+-------------------------------------------------------------------------------------------------+
| auid | integer | No | The login user ID |
+---------------+------------+-----------+-------------------------------------------------------------------------------------------------+
| ses | integer | No | The login session ID |
+---------------+------------+-----------+-------------------------------------------------------------------------------------------------+
| enabled | integer | No | The new TTY audit enabled setting |
+---------------+------------+-----------+-------------------------------------------------------------------------------------------------+
| old-enabled | integer | No | The old TTY audit enabled setting |
+---------------+------------+-----------+-------------------------------------------------------------------------------------------------+
| lsm | string | No | The lsm name associated with the event |
+---------------+------------+-----------+-------------------------------------------------------------------------------------------------+
| res | integer | No | The result of the audited operation(success/fail) |
+---------------+------------+-----------+-------------------------------------------------------------------------------------------------+
Success Auditing
^^^^^^^^^^^^^^^^
IPE supports success auditing. When enabled, all events that pass IPE
policy and are not blocked will emit an audit event. This is disabled by
default, and can be enabled via the kernel command line
``ipe.success_audit=(0|1)`` or
``/sys/kernel/security/ipe/success_audit`` securityfs file.
This is *very* noisy, as IPE will check every userspace binary on the
system, but is useful for debugging policies.
.. NOTE::
If a traditional MAC system is enabled (SELinux, apparmor, smack, etcetera),
all writes to ipe's securityfs nodes require ``CAP_MAC_ADMIN``.
Properties
----------
As explained above, IPE properties are ``key=value`` pairs expressed in IPE
policy. Two properties are built-into the policy parser: 'op' and 'action'.
The other properties are used to restrict immutable security properties
about the files being evaluated. Currently those properties are:
'``boot_verified``', '``dmverity_signature``', '``dmverity_roothash``',
'``fsverity_signature``', '``fsverity_digest``'. A description of all
properties supported by IPE are listed below:
op
~~
Indicates the operation for a rule to apply to. Must be in every rule,
as the first token. IPE supports the following operations:
``EXECUTE``
Pertains to any file attempting to be executed, or loaded as an
executable.
``FIRMWARE``:
Pertains to firmware being loaded via the firmware_class interface.
This covers both the preallocated buffer and the firmware file
itself.
``KMODULE``:
Pertains to loading kernel modules via ``modprobe`` or ``insmod``.
``KEXEC_IMAGE``:
Pertains to kernel images loading via ``kexec``.
``KEXEC_INITRAMFS``
Pertains to initrd images loading via ``kexec --initrd``.
``POLICY``:
Controls loading policies via reading a kernel-space initiated read.
An example of such is loading IMA policies by writing the path
to the policy file to ``$securityfs/ima/policy``
``X509_CERT``:
Controls loading IMA certificates through the Kconfigs,
``CONFIG_IMA_X509_PATH`` and ``CONFIG_EVM_X509_PATH``.
action
~~~~~~
Determines what IPE should do when a rule matches. Must be in every
rule, as the final clause. Can be one of:
``ALLOW``:
If the rule matches, explicitly allow access to the resource to proceed
without executing any more rules.
``DENY``:
If the rule matches, explicitly prohibit access to the resource to
proceed without executing any more rules.
boot_verified
~~~~~~~~~~~~~
This property can be utilized for authorization of files from initramfs.
The format of this property is::
boot_verified=(TRUE|FALSE)
.. WARNING::
This property will trust files from initramfs(rootfs). It should
only be used during early booting stage. Before mounting the real
rootfs on top of the initramfs, initramfs script will recursively
remove all files and directories on the initramfs. This is typically
implemented by using switch_root(8) [#switch_root]_. Therefore the
initramfs will be empty and not accessible after the real
rootfs takes over. It is advised to switch to a different policy
that doesn't rely on the property after this point.
This ensures that the trust policies remain relevant and effective
throughout the system's operation.
dmverity_roothash
~~~~~~~~~~~~~~~~~
This property can be utilized for authorization or revocation of
specific dm-verity volumes, identified via their root hashes. It has a
dependency on the DM_VERITY module. This property is controlled by
the ``IPE_PROP_DM_VERITY`` config option, it will be automatically
selected when ``SECURITY_IPE`` and ``DM_VERITY`` are all enabled.
The format of this property is::
dmverity_roothash=DigestName:HexadecimalString
The supported DigestNames for dmverity_roothash are [#dmveritydigests]_
+ blake2b-512
+ blake2s-256
+ sha256
+ sha384
+ sha512
+ sha3-224
+ sha3-256
+ sha3-384
+ sha3-512
+ sm3
+ rmd160
dmverity_signature
~~~~~~~~~~~~~~~~~~
This property can be utilized for authorization of all dm-verity
volumes that have a signed roothash that validated by a keyring
specified by dm-verity's configuration, either the system trusted
keyring, or the secondary keyring. It depends on
``DM_VERITY_VERIFY_ROOTHASH_SIG`` config option and is controlled by
the ``IPE_PROP_DM_VERITY_SIGNATURE`` config option, it will be automatically
selected when ``SECURITY_IPE``, ``DM_VERITY`` and
``DM_VERITY_VERIFY_ROOTHASH_SIG`` are all enabled.
The format of this property is::
dmverity_signature=(TRUE|FALSE)
fsverity_digest
~~~~~~~~~~~~~~~
This property can be utilized for authorization of specific fsverity
enabled files, identified via their fsverity digests.
It depends on ``FS_VERITY`` config option and is controlled by
the ``IPE_PROP_FS_VERITY`` config option, it will be automatically
selected when ``SECURITY_IPE`` and ``FS_VERITY`` are all enabled.
The format of this property is::
fsverity_digest=DigestName:HexadecimalString
The supported DigestNames for fsverity_digest are [#fsveritydigest]_
+ sha256
+ sha512
fsverity_signature
~~~~~~~~~~~~~~~~~~
This property is used to authorize all fs-verity enabled files that have
been verified by fs-verity's built-in signature mechanism. The signature
verification relies on a key stored within the ".fs-verity" keyring. It
depends on ``FS_VERITY_BUILTIN_SIGNATURES`` config option and
it is controlled by the ``IPE_PROP_FS_VERITY`` config option,
it will be automatically selected when ``SECURITY_IPE``, ``FS_VERITY``
and ``FS_VERITY_BUILTIN_SIGNATURES`` are all enabled.
The format of this property is::
fsverity_signature=(TRUE|FALSE)
Policy Examples
---------------
Allow all
~~~~~~~~~
::
policy_name=Allow_All policy_version=0.0.0
DEFAULT action=ALLOW
Allow only initramfs
~~~~~~~~~~~~~~~~~~~~
::
policy_name=Allow_Initramfs policy_version=0.0.0
DEFAULT action=DENY
op=EXECUTE boot_verified=TRUE action=ALLOW
Allow any signed and validated dm-verity volume and the initramfs
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
::
policy_name=Allow_Signed_DMV_And_Initramfs policy_version=0.0.0
DEFAULT action=DENY
op=EXECUTE boot_verified=TRUE action=ALLOW
op=EXECUTE dmverity_signature=TRUE action=ALLOW
Prohibit execution from a specific dm-verity volume
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
::
policy_name=Deny_DMV_By_Roothash policy_version=0.0.0
DEFAULT action=DENY
op=EXECUTE dmverity_roothash=sha256:cd2c5bae7c6c579edaae4353049d58eb5f2e8be0244bf05345bc8e5ed257baff action=DENY
op=EXECUTE boot_verified=TRUE action=ALLOW
op=EXECUTE dmverity_signature=TRUE action=ALLOW
Allow only a specific dm-verity volume
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
::
policy_name=Allow_DMV_By_Roothash policy_version=0.0.0
DEFAULT action=DENY
op=EXECUTE dmverity_roothash=sha256:401fcec5944823ae12f62726e8184407a5fa9599783f030dec146938 action=ALLOW
Allow any fs-verity file with a valid built-in signature
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
::
policy_name=Allow_Signed_And_Validated_FSVerity policy_version=0.0.0
DEFAULT action=DENY
op=EXECUTE fsverity_signature=TRUE action=ALLOW
Allow execution of a specific fs-verity file
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
::
policy_name=ALLOW_FSV_By_Digest policy_version=0.0.0
DEFAULT action=DENY
op=EXECUTE fsverity_digest=sha256:fd88f2b8824e197f850bf4c5109bea5cf0ee38104f710843bb72da796ba5af9e action=ALLOW
Additional Information
----------------------
- `Github Repository <https://github.com/microsoft/ipe>`_
- :doc:`Developer and design docs for IPE </security/ipe>`
FAQ
---
Q:
What's the difference between other LSMs which provide a measure of
trust-based access control?
A:
In general, there's two other LSMs that can provide similar functionality:
IMA, and Loadpin.
IMA and IPE are functionally very similar. The significant difference between
the two is the policy. [#devdoc]_
Loadpin and IPE differ fairly dramatically, as Loadpin only covers the IPE's
kernel read operations, whereas IPE is capable of controlling execution
on top of kernel read. The trust model is also different; Loadpin roots its
trust in the initial super-block, whereas trust in IPE is stemmed from kernel
itself (via ``SYSTEM_TRUSTED_KEYS``).
-----------
.. [#digest_cache_lsm] https://lore.kernel.org/lkml/20240415142436.2545003-1-roberto.sassu@huaweicloud.com/
.. [#interpreters] There is `some interest in solving this issue <https://lore.kernel.org/lkml/20220321161557.495388-1-mic@digikod.net/>`_.
.. [#devdoc] Please see :doc:`the design docs </security/ipe>` for more on
this topic.
.. [#switch_root] https://man7.org/linux/man-pages/man8/switch_root.8.html
.. [#dmveritydigests] These hash algorithms are based on values accepted by
the Linux crypto API; IPE does not impose any
restrictions on the digest algorithm itself;
thus, this list may be out of date.
.. [#fsveritydigest] These hash algorithms are based on values accepted by the
kernel's fsverity support; IPE does not impose any
restrictions on the digest algorithm itself;
thus, this list may be out of date.
3. 한국어 전문 번역
영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.
문서 대상
1-10이 문서는 IPE를 사용하려는 관리자, 시스템 제작자, 개인을 위한 문서입니다. 개발자 중심의 IPE 설명은 `security/ipe`의 설계 문서를 참조하십시오.
개요
11-21Integrity Policy Enforcement(IPE)는 접근 제어에 보완적 접근을 취하는 Linux Security Module입니다. 의사 결정에 label과 path를 사용하는 전통적 접근 제어와 달리 IPE는 시스템 구성 요소에 내재한 불변 보안 속성에 초점을 둡니다. 이러한 속성은 변경할 수 없는 구성 요소의 근본적 특성 또는 기능이므로 일관되고 신뢰할 수 있는 보안 결정의 기반이 됩니다.
구성 요소와 출처
22-32IPE에서 시스템 구성 요소는 주로 file 또는 그 file이 위치한 device를 뜻하지만, 시스템이 발전하면 새로운 요소를 포함하도록 확장할 수 있습니다. 불변 속성에는 시간이 지나도 바뀌지 않는 file의 출처가 포함됩니다.
예를 들어 bootloader가 일반적으로 initramfs를 검증하므로 IPE policy는 initramfs에서 온 file을 신뢰하도록 작성할 수 있습니다. 이때 `file is from initramfs`는 IPE가 판단에 사용하는 불변 속성이 됩니다.
dm-verity와 fs-verity
33-43불변 속성 개념은 file의 출처에서 활성화된 dm-verity 또는 fs-verity 같은 보안 기능에도 적용됩니다. IPE는 dm-verity 보호 device에서 온 file을 신뢰하는 policy를 정의할 수 있습니다. dm-verity는 전체 device 내용에 검증 가능하고 불변인 상태를 제공하고, fs-verity는 filesystem 수준 무결성 검사를 제공합니다.
두 기능은 일단 설정되면 끌 수 없으므로 불변 속성으로 간주됩니다. IPE는 이처럼 file의 출처와 무결성 보호 메커니즘을 이용해 접근 제어를 결정합니다.
Policy의 기준값 평가
44-60IPE policy는 보안 속성을 policy에 정의한 기준값과 비교해 엄격한 접근 제어를 시행합니다. 속성의 존재 여부, 예를 들어 file이 initramfs에서 왔는지를 확인하거나 불변 보안 속성의 내부 상태를 평가할 수 있습니다.
내부 상태 평가는 dm-verity 보호 device의 roothash, dm-verity의 유효한 signature 보유 여부, fs-verity 보호 file의 digest, fs-verity의 유효한 built-in signature 보유 여부 등을 확인합니다. 이 방식은 특정 보안 요구와 신뢰 모델에 맞춘 강력하고 사용자 정의 가능한 방어를 제공합니다.
IPE를 활성화하려면 `Security -> Integrity Policy Enforcement (IPE)` 아래의 `CONFIG_SECURITY_IPE` config option을 켜십시오.
사용 사례
61-84IPE는 data center의 network firewall이나 IoT device처럼 목적이 명확하고 변경되지 않으며 모든 software와 configuration을 시스템 소유자가 구축하고 provisioning하는 고정 기능 device에 가장 적합합니다.
일반 목적 computing에 사용하기에는 아직 갈 길이 멉니다. Linux community는 대체로 분산 신뢰 모델인 web of trust를 따르지만 IPE는 아직 이를 지원하지 않습니다. 대신 절대적 신뢰 수준을 제공하는 trusted entity 집합을 지정하는 PKI(public key infrastructure)를 지원합니다.
오늘날 package 자체는 대부분 서명되지만 package 안의 executable 같은 file은 대개 서명되지 않습니다. 따라서 package manager와 그 ecosystem을 크게 바꾸지 않고 package manager가 동작해야 하는 시스템에 IPE를 적용하기는 어렵습니다.
`digest_cache` LSM은 IPE와 결합했을 때 일반 목적 computing 사용 사례를 활성화하고 지원하는 데 사용할 수 있는 시스템입니다.
알려진 제한
85-99IPE는 gcc closure와 libffi 3.4.2 미만이 만드는 trampoline 또는 JIT code 같은 anonymous executable memory의 무결성을 검증할 수 없습니다. 동적으로 생성되는 code이므로 신뢰 기반을 만들 수 있는 무결성을 보장할 방법이 없습니다.
또한 script file을 interpreter에 인자로 넘겨 실행하는 interpreted language program의 무결성을 검증할 수 없습니다. script 자체가 IPE hook을 통해 executable code로 평가되지 않고 compiled executable과 달리 단순히 읽히는 text file이기 때문입니다.
위협 모델
100-121IPE는 kernel이 처음 boot한 뒤 user-space executable code가 변조되는 위험을 특히 겨냥하며, `modprobe` 또는 `insmod`로 userspace에서 load하는 kernel module도 포함합니다.
예를 들어 악성일 수 있는 신뢰하지 않는 binary와 loader, libc를 포함한 모든 dependency가 download되었다면 IPE의 주된 역할은 그 binary와 dependency의 실행을 막는 것입니다.
IPE는 모든 executable code의 무결성과 진위를 실행 전에 검증합니다. code의 무결성이 유지되고 정의된 policy가 허가한 reference value(digest, signature 등)와 일치하는지 확인합니다. 무결성이 훼손되었거나 허가 기준을 충족하지 못하면 실행을 거부하고, policy 위반 실패를 탐지하고 분석할 수 있는 audit log를 생성합니다.
변조 주체와 범위 밖 위협
122-139Executable code를 수정하거나 교체하는 변조 위협의 주체에는 다음이 포함됩니다.
| 위협 주체 | 접근 경로 |
|---|---|
| Hardware에 물리적으로 접근하는 주체 | Physical access |
| 시스템의 local network에 접근하는 주체 | Local network |
| Deployment system에 접근하는 주체 | Deployment pipeline |
| 외부 통제 아래 놓인 침해된 내부 시스템 | Compromised internal system |
| 악의적인 시스템 end user | Malicious end user |
| 침해된 시스템 end user | Compromised end user |
| 시스템의 remote(external) compromise | Remote compromise |
IPE는 signing certificate에 접근할 수 있는 악의적이지만 허가된 개발자나, 그 개발자가 사용하는 침해된 개발 도구에서 비롯한 위협(예: return-oriented programming attack)을 완화하지 않습니다. IPE는 userspace와 kernelspace 사이에 단단한 보안 경계를 두므로 kernel-level exploit도 범위 밖이며 다른 메커니즘이 완화해야 합니다.
Policy header
140-157IPE policy는 여러 줄의 statement로 구성된 plain-text policy입니다. 첫 줄에는 사람이 읽을 수 있는 고유 식별자인 policy name과 현재 policy version을 반드시 지정합니다.
policy_name=Ex_Policy policy_version=0.0.0
Policy name은 securityfs node를 만들고 새 policy 배포와 기존 policy update를 구별하는 고유 key입니다. Policy version은 policy syntax version이 아니라 현재 policy 자체의 version이며, 잠재적으로 안전하지 않은 이전 policy로 rollback하는 일을 막는 데 사용됩니다.
Rule 문법과 평가 순서
158-180IPE policy의 다음 부분은 rule입니다. Rule은 property라고 부르는 `key=value` pair로 구성됩니다. 모든 IPE rule에는 일치했을 때 수행할 동작을 정하는 `action`과 rule을 평가할 시점을 정하는 `op`가 필요합니다.
순서가 중요합니다. Rule은 `op`로 시작하고 `action`으로 끝나야 하며 최소 rule은 다음과 같습니다.
op=EXECUTE action=ALLOW
이 예는 모든 실행을 허용합니다. 추가 property는 평가 대상 file의 불변 보안 속성을 검사합니다. 이 property들은 kernel 안에서 무결성 검증 수준을 제공하는 시스템을 기술하며, IPE는 그 값으로 resource의 신뢰 여부를 결정합니다.
Rule은 위에서 아래로 평가하므로 revoke 또는 deny rule은 `action=ALLOW` rule보다 먼저 평가되도록 file 앞쪽에 두어야 합니다. `#`부터 newline까지는 comment로 무시됩니다.
DEFAULT statement
181-194IPE 평가의 기본 동작은 `DEFAULT` statement로 policy에 표현할 수 있습니다. Global 수준 또는 operation별 수준으로 지정할 수 있습니다.
# Global
DEFAULT action=ALLOW
# Operation Specific
DEFAULT op=EXECUTE action=ALLOW
알려진 모든 IPE operation에는 default가 있어야 합니다. 새 operation을 도입한 kernel에서도 오래된 policy의 호환성을 유지하려면 global default를 `ALLOW`로 지정한 뒤 operation별 default로 덮어쓰십시오.
Boot policy
195-217Configurable policy 기반 LSM이 시작 시 policy를 읽고 parsing하여 강제할 때는 다음 문제가 있습니다.
| 문제 | 이유 |
|---|---|
| Userspace file 직접 읽기 | Kernel은 userspace file을 읽어서는 안 되므로 policy file 직접 읽기가 금지됩니다. |
| Kernel command line 크기 | 문자 수 제한이 있으므로 한 kernel module이 전체 공간을 독점해서는 안 됩니다. |
| Bootloader 다양성 | Memory block 전달 방식은 여러 bootloader를 지원하기 위한 유지 비용이 큽니다. |
IPE는 이를 `boot policy`로 해결합니다. Boot policy는 kernel에 compile되는 최소 policy로, userspace가 command를 받을 준비가 될 때까지 시스템을 올린 뒤 securityfs를 통해 더 복잡한 policy를 배포하게 합니다.
`SECURITY_IPE_BOOT_POLICY` config option에 적용할 plain-text IPE policy path를 지정하면 그 policy가 kernel에 compile됩니다. 지정하지 않으면 securityfs로 policy를 배포하고 활성화할 때까지 IPE가 비활성 상태입니다.
Policy 서명
218-240Policy는 userspace에서 securityfs를 통해 배포할 수 있습니다. 공격자가 무제한 root 권한을 얻어 `allow all` policy를 배포하지 못하도록 PKCS#7 message format으로 서명해 policy 권한을 통제합니다.
Policy는 `SYSTEM_TRUSTED_KEYRING`으로 chain되는 certificate로 서명해야 합니다. `CONFIG_IPE_POLICY_SIG_SECONDARY_KEYRING` 또는 `CONFIG_IPE_POLICY_SIG_PLATFORM_KEYRING`을 켰다면 각각 secondary 또는 platform keyring으로 chain되는 certificate도 사용할 수 있습니다.
OpenSSL로 policy를 서명하는 예는 다음과 같습니다.
openssl smime -sign \
-in "$MY_POLICY" \
-signer "$MY_CERTIFICATE" \
-inkey "$MY_PRIVATE_KEY" \
-noattr \
-nodetach \
-nosmimecap \
-outform der \
-out "$MY_POLICY.p7b"
new_policy 배포
241-253Policy는 securityfs의 `new_policy` node에 file을 써서 배포합니다.
cat "$MY_POLICY.p7b" > /sys/kernel/security/ipe/new_policy
성공하면 `/sys/kernel/security/ipe/policies/` 아래에 배포한 `policy_name`과 같은 subdirectory가 생깁니다. 위 예에서는 `/sys/kernel/security/ipe/policies/Ex_Policy`이며 그 안에는 `pkcs7`, `policy`, `name`, `version`, `active`, `update`, `delete` 일곱 file이 있습니다.
Policy directory file
254-283| File | Access | 동작 |
|---|---|---|
| pkcs7 | Read-only | Kernel에 제공한 raw PKCS#7 policy data를 반환합니다. 서명되지 않은 boot policy이면 `ENOENT`를 반환합니다. |
| policy | Read-only | Plain-text policy인 PKCS#7 내부 content를 반환합니다. |
| active | Read/write | `"1"`을 쓰면 active policy가 됩니다. 다른 policy는 inactive가 되며 version은 현재 실행 version 이상이어야 합니다. |
| update | Write-only | PKCS#7 signed policy를 받아 기존 policy를 update합니다. `policy_name`이 같고 version이 현재 실행 version보다 커야 합니다. |
| delete | Write-only | `1`을 쓰면 policy와 securityfs node를 제거합니다. 현재 active policy는 삭제할 수 없어 operation not permitted error를 반환합니다. |
`update` 또는 `new_policy`에 쓸 때 policy syntax error이면 bad message가, 같은 `policy_name`의 policy가 이미 배포되어 있으면 file exists error가 발생할 수 있습니다.
활성화와 삭제
284-312Policy를 배포하는 것만으로 IPE가 그 policy를 강제하지는 않습니다. IPE는 active로 표시한 policy만 강제하며 한 번에 하나만 active일 수 있습니다.
배포에 성공한 `Ex_Policy`를 활성화하려면 다음과 같이 `active` file에 `1`을 씁니다.
echo 1 > "/sys/kernel/security/ipe/policies/Ex_Policy/active"
이 시점부터 시스템은 `Ex_Policy`를 강제합니다.
Policy를 삭제하려면 해당 `delete` securityfs node에 `1`을 씁니다.
echo 1 > "/sys/kernel/security/ipe/policies/$policy_name/delete"
삭제 대상 policy는 inactive여야 합니다. SELinux, AppArmor, Smack 같은 전통적 MAC system이 활성화되어 있다면 IPE securityfs node에 쓰는 모든 작업에 `CAP_MAC_ADMIN`이 필요합니다.
Permissive와 enforced mode
313-329IPE는 SELinux permissive mode와 비슷한 permissive mode와 enforced mode를 지원합니다. Permissive mode에서도 모든 event를 검사하고 policy 위반을 기록하지만 실제로 차단하지 않으므로 강제하기 전에 policy를 시험할 수 있습니다.
기본값은 enforce입니다. Kernel command line의 `ipe.enforce=(0|1)` 또는 securityfs node `/sys/kernel/security/ipe/enforce`로 바꿀 수 있습니다. 전통적 MAC system이 활성화되어 있으면 이 node에 쓰는 데 `CAP_MAC_ADMIN`이 필요합니다.
1420 AUDIT_IPE_ACCESS
330-376IPE가 접근 제어 결정을 내렸을 때 다음과 같은 record가 생성됩니다.
type=1420 audit(1653364370.067:61): ipe_op=EXECUTE ipe_hook=MMAP enforcing=1 pid=2241 comm="ld-linux.so" path="/deny/lib/libc.so.6" dev="sda2" ino=14549020 rule="DEFAULT action=DENY"
type=1300 audit(1653364370.067:61): SYSCALL arch=c000003e syscall=9 success=no exit=-13 a0=7f1105a28000 a1=195000 a2=5 a3=812 items=0 ppid=2219 pid=2241 auid=0 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts0 ses=2 comm="ld-linux.so" exe="/tmp/ipe-test/lib/ld-linux.so" subj=unconfined key=(null)
type=1327 audit(1653364370.067:61): 707974686F6E3300746573742F6D61696E2E7079002D6E00
type=1420 audit(1653364735.161:64): ipe_op=EXECUTE ipe_hook=MMAP enforcing=1 pid=2472 comm="mmap_test" path=? dev=? ino=? rule="DEFAULT action=DENY"
type=1300 audit(1653364735.161:64): SYSCALL arch=c000003e syscall=9 success=no exit=-13 a0=0 a1=1000 a2=4 a3=21 items=0 ppid=2219 pid=2472 auid=0 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts0 ses=2 comm="mmap_test" exe="/root/overlake_test/upstream_test/vol_fsverity/bin/mmap_test" subj=unconfined key=(null)
type=1327 audit(1653364735.161:64): 707974686F6E3300746573742F6D61696E2E7079002D6E00
IPE 전용 record 1420은 항상 `AUDITSYSCALL` record와 함께 발생합니다. IPE가 permissive인지 enforced인지는 `AUDITSYSCALL` record의 `success` property와 exit code로 판단할 수 있습니다.
| Field | Value type | Optional | 값 설명 |
|---|---|---|---|
| ipe_op | string | 아니요 | 로그와 연관된 IPE 작업 이름 |
| ipe_hook | string | 아니요 | IPE 이벤트를 일으킨 LSM hook 이름 |
| enforcing | integer | 아니요 | 현재 IPE 강제 상태. 1은 enforcing, 0은 permissive mode |
| pid | integer | 아니요 | IPE 이벤트를 일으킨 process의 pid |
| comm | string | 아니요 | IPE 이벤트를 일으킨 process의 command-line program 이름 |
| path | string | 예 | 평가한 file의 absolute path |
| ino | integer | 예 | 평가한 file의 inode number |
| dev | string | 예 | 평가한 file의 device 이름(예: vda) |
| rule | string | 아니요 | 일치한 policy rule |
1421 AUDIT_IPE_CONFIG_CHANGE
377-420Active policy가 바뀌면 다음과 같은 configuration change event가 발생합니다.
type=1421 audit(1653425583.136:54): old_active_pol_name="Allow_All" old_active_pol_version=0.0.0 old_policy_digest=sha256:E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855 new_active_pol_name="boot_verified" new_active_pol_version=0.0.0 new_policy_digest=sha256:820EEA5B40CA42B51F68962354BA083122A20BB846F26765076DD8EED7B8F4DB auid=4294967295 ses=4294967295 lsm=ipe res=1
type=1300 audit(1653425583.136:54): SYSCALL arch=c000003e syscall=1 success=yes exit=2 a0=3 a1=5596fcae1fb0 a2=2 a3=2 items=0 ppid=184 pid=229 auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts0 ses=4294967295 comm="python3" exe="/usr/bin/python3.10" key=(null)
type=1327 audit(1653425583.136:54): PROCTITLE proctitle=707974686F6E3300746573742F6D61696E2E7079002D66002E2
이 event는 이전 policy와 새 policy의 이름, version, hash digest를 함께 기록합니다. IPE는 한 번에 하나의 policy만 active로 둘 수 있고 모든 접근 결정은 현재 active policy를 기준으로 평가합니다.
새 policy를 배포하는 일반 절차는 먼저 kernel에 policy를 load한 다음 active policy를 그 policy로 전환하는 것입니다. 이 record는 `write` syscall의 `AUDITSYSCALL` record와 항상 함께 발생합니다.
| Field | Value type | Optional | 값 설명 |
|---|---|---|---|
| old_active_pol_name | string | 예 | 이전 active policy 이름 |
| old_active_pol_version | string | 예 | 이전 active policy version |
| old_policy_digest | string | 예 | 이전 active policy hash |
| new_active_pol_name | string | 아니요 | 현재 active policy 이름 |
| new_active_pol_version | string | 아니요 | 현재 active policy version |
| new_policy_digest | string | 아니요 | 현재 active policy hash |
| auid | integer | 아니요 | login user ID |
| ses | integer | 아니요 | login session ID |
| lsm | string | 아니요 | event와 연관된 LSM 이름 |
| res | integer | 아니요 | 감사한 작업의 결과(success/fail) |
1422 AUDIT_IPE_POLICY_LOAD
421-485새 policy를 kernel에 load하면 다음 event가 policy name, version, hash와 함께 기록됩니다.
type=1422 audit(1653425529.927:53): policy_name="boot_verified" policy_version=0.0.0 policy_digest=sha256:820EEA5B40CA42B51F68962354BA083122A20BB846F26765076DD8EED7B8F4DB auid=4294967295 ses=4294967295 lsm=ipe res=1 errno=0
type=1300 audit(1653425529.927:53): arch=c000003e syscall=1 success=yes exit=2567 a0=3 a1=5596fcae1fb0 a2=a07 a3=2 items=0 ppid=184 pid=229 auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts0 ses=4294967295 comm="python3" exe="/usr/bin/python3.10" key=(null)
type=1327 audit(1653425529.927:53): PROCTITLE proctitle=707974686F6E3300746573742F6D61696E2E7079002D66002E2E
이 record는 `write` syscall의 `AUDITSYSCALL` record와 항상 함께 발생합니다.
| Field | Value type | Optional | 값 설명 |
|---|---|---|---|
| policy_name | string | 예 | `policy_name` |
| policy_version | string | 예 | `policy_version` |
| policy_digest | string | 예 | policy hash |
| auid | integer | 아니요 | login user ID |
| ses | integer | 아니요 | login session ID |
| lsm | string | 아니요 | event와 연관된 LSM 이름 |
| res | integer | 아니요 | 감사한 작업의 결과(success/fail) |
| errno | integer | 아니요 | policy load 작업의 error code(아래 표 참조) |
Policy를 load하거나 update할 때 `errno` field에는 다음 error code가 나타날 수 있습니다.
| Error code | 설명 |
|---|---|
| 0 | 성공 |
| -EPERM | 권한 부족 |
| -EEXIST | 같은 이름의 policy가 이미 배포됨 |
| -EBADMSG | policy가 유효하지 않음 |
| -ENOMEM | 메모리 부족(OOM) |
| -ERANGE | policy version number overflow |
| -EINVAL | policy version parsing error |
| -ENOKEY | IPE policy 서명에 사용한 key를 keyring에서 찾지 못함 |
| -EKEYREJECTED | policy signature verification 실패 |
| -ESTALE | 더 오래된 version으로 IPE policy를 update하려고 함 |
| -ENOENT | update 도중 policy가 삭제됨 |
1404 AUDIT_MAC_STATUS와 성공 감사
486-539IPE enforcing 상태를 전환하면 다음 event가 발생합니다.
type=1404 audit(1653425689.008:55): enforcing=0 old_enforcing=1 auid=4294967295 ses=4294967295 enabled=1 old-enabled=1 lsm=ipe res=1
type=1300 audit(1653425689.008:55): arch=c000003e syscall=1 success=yes exit=2 a0=1 a1=55c1065e5c60 a2=2 a3=0 items=0 ppid=405 pid=441 auid=0 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=)
type=1327 audit(1653425689.008:55): proctitle="-bash"
type=1404 audit(1653425689.008:55): enforcing=1 old_enforcing=0 auid=4294967295 ses=4294967295 enabled=1 old-enabled=1 lsm=ipe res=1
type=1300 audit(1653425689.008:55): arch=c000003e syscall=1 success=yes exit=2 a0=1 a1=55c1065e5c60 a2=2 a3=0 items=0 ppid=405 pid=441 auid=0 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=)
type=1327 audit(1653425689.008:55): proctitle="-bash"
이 record는 `write` syscall의 `AUDITSYSCALL` record와 항상 함께 발생합니다.
| Field | Value type | Optional | 값 설명 |
|---|---|---|---|
| enforcing | integer | 아니요 | 전환할 IPE 상태. 1은 enforcing, 0은 permissive mode |
| old_enforcing | integer | 아니요 | 전환 전 IPE 상태. 1은 enforcing, 0은 permissive mode |
| auid | integer | 아니요 | login user ID |
| ses | integer | 아니요 | login session ID |
| enabled | integer | 아니요 | 새 TTY audit enabled 설정 |
| old-enabled | integer | 아니요 | 이전 TTY audit enabled 설정 |
| lsm | string | 아니요 | event와 연관된 LSM 이름 |
| res | integer | 아니요 | 감사한 작업의 결과(success/fail) |
IPE는 success auditing을 지원합니다. 활성화하면 IPE policy를 통과해 차단되지 않은 모든 event가 audit event를 생성합니다. 기본값은 비활성이며 kernel command line의 `ipe.success_audit=(0|1)` 또는 securityfs file `/sys/kernel/security/ipe/success_audit`로 켤 수 있습니다.
IPE가 시스템의 모든 userspace binary를 검사하므로 매우 많은 로그가 생성되지만 policy debugging에는 유용합니다. 전통적 MAC system이 활성화되어 있으면 securityfs node에 쓰는 데 `CAP_MAC_ADMIN`이 필요합니다.
Property 개요
540-550IPE property는 policy에 쓰는 `key=value` pair입니다. Policy parser에 내장된 두 property는 `op`와 `action`입니다. 나머지는 평가 대상 file의 불변 보안 속성을 제한하는 데 사용합니다.
현재 지원하는 보안 property는 `boot_verified`, `dmverity_signature`, `dmverity_roothash`, `fsverity_signature`, `fsverity_digest`입니다.
op
551-592`op`는 rule을 적용할 operation을 나타내며 모든 rule의 첫 token이어야 합니다.
| Operation | 적용 대상 |
|---|---|
| EXECUTE | 실행되거나 executable로 load되는 모든 file |
| FIRMWARE | `firmware_class` interface를 통해 load되는 firmware. Preallocated buffer와 firmware file 자체를 모두 포함합니다. |
| KMODULE | `modprobe` 또는 `insmod`를 통한 kernel module load |
| KEXEC_IMAGE | `kexec`를 통한 kernel image load |
| KEXEC_INITRAMFS | `kexec --initrd`를 통한 initrd image load |
| POLICY | Kernel-space가 시작한 read를 통한 policy load. 예: `$securityfs/ima/policy`에 IMA policy file path를 써서 load하는 작업 |
| X509_CERT | Kconfig `CONFIG_IMA_X509_PATH`와 `CONFIG_EVM_X509_PATH`를 통한 IMA certificate load |
action
593-608`action`은 rule이 일치할 때 IPE가 수행할 일을 정하며 모든 rule의 마지막 clause여야 합니다.
| Action | 동작 |
|---|---|
| ALLOW | 더 이상 rule을 실행하지 않고 resource 접근을 명시적으로 허용합니다. |
| DENY | 더 이상 rule을 실행하지 않고 resource 접근을 명시적으로 금지합니다. |
boot_verified
609-630`boot_verified`는 initramfs의 file을 허가하는 데 사용할 수 있으며 형식은 다음과 같습니다.
boot_verified=(TRUE|FALSE)
경고: 이 property는 initramfs(rootfs)의 file을 신뢰하므로 초기 boot 단계에서만 사용해야 합니다. 실제 rootfs를 initramfs 위에 mount하기 전에 initramfs script는 보통 `switch_root(8)`로 initramfs의 모든 file과 directory를 재귀적으로 제거합니다.
실제 rootfs가 넘겨받은 뒤에는 initramfs가 비어 접근할 수 없으므로, 그 시점 이후에는 이 property에 의존하지 않는 다른 policy로 전환하는 것이 좋습니다. 그래야 시스템 전체 동작 중 신뢰 policy가 계속 적절하고 효과적으로 유지됩니다.
dmverity_roothash
631-656`dmverity_roothash`는 root hash로 식별한 특정 dm-verity volume을 허가하거나 revoke하는 데 사용합니다. `DM_VERITY` module에 의존하고 `IPE_PROP_DM_VERITY` config option이 제어하며, `SECURITY_IPE`와 `DM_VERITY`를 모두 켜면 자동 선택됩니다.
형식은 다음과 같습니다.
dmverity_roothash=DigestName:HexadecimalString
| 지원 DigestName |
|---|
| blake2b-512 |
| blake2s-256 |
| sha256 |
| sha384 |
| sha512 |
| sha3-224 |
| sha3-256 |
| sha3-384 |
| sha3-512 |
| sm3 |
| rmd160 |
dmverity_signature
657-671`dmverity_signature`은 dm-verity configuration이 지정한 system trusted keyring 또는 secondary keyring으로 검증된 signed roothash를 가진 모든 dm-verity volume을 허가하는 데 사용합니다.
`DM_VERITY_VERIFY_ROOTHASH_SIG` config option에 의존하고 `IPE_PROP_DM_VERITY_SIGNATURE`가 제어합니다. `SECURITY_IPE`, `DM_VERITY`, `DM_VERITY_VERIFY_ROOTHASH_SIG`를 모두 켜면 자동 선택됩니다.
dmverity_signature=(TRUE|FALSE)
fsverity_digest
672-688`fsverity_digest`는 fs-verity digest로 식별한 특정 fs-verity enabled file을 허가하는 데 사용합니다. `FS_VERITY`에 의존하고 `IPE_PROP_FS_VERITY`가 제어하며, `SECURITY_IPE`와 `FS_VERITY`를 모두 켜면 자동 선택됩니다.
fsverity_digest=DigestName:HexadecimalString
지원하는 `DigestName`은 `sha256`과 `sha512`입니다.
fsverity_signature
689-702`fsverity_signature`은 fs-verity built-in signature mechanism으로 검증된 모든 fs-verity enabled file을 허가합니다. Signature verification은 `.fs-verity` keyring에 저장된 key를 사용합니다.
`FS_VERITY_BUILTIN_SIGNATURES`에 의존하고 `IPE_PROP_FS_VERITY`가 제어합니다. `SECURITY_IPE`, `FS_VERITY`, `FS_VERITY_BUILTIN_SIGNATURES`를 모두 켜면 자동 선택됩니다.
fsverity_signature=(TRUE|FALSE)
예제: 모두 허용
703-713모든 operation을 허용하는 policy입니다.
policy_name=Allow_All policy_version=0.0.0
DEFAULT action=ALLOW
예제: initramfs만 허용
714-723기본적으로 거부하고 initramfs에서 온 executable만 허용합니다.
policy_name=Allow_Initramfs policy_version=0.0.0
DEFAULT action=DENY
op=EXECUTE boot_verified=TRUE action=ALLOW
예제: 서명된 dm-verity와 initramfs
724-734Initramfs와 유효한 signature가 있는 모든 dm-verity volume의 실행을 허용합니다.
policy_name=Allow_Signed_DMV_And_Initramfs policy_version=0.0.0
DEFAULT action=DENY
op=EXECUTE boot_verified=TRUE action=ALLOW
op=EXECUTE dmverity_signature=TRUE action=ALLOW
예제: 특정 dm-verity volume 금지
735-747특정 dm-verity roothash의 실행을 먼저 거부하고, initramfs와 서명된 다른 dm-verity volume을 허용합니다. Rule이 위에서 아래로 평가되므로 deny rule이 앞에 있습니다.
policy_name=Deny_DMV_By_Roothash policy_version=0.0.0
DEFAULT action=DENY
op=EXECUTE dmverity_roothash=sha256:cd2c5bae7c6c579edaae4353049d58eb5f2e8be0244bf05345bc8e5ed257baff action=DENY
op=EXECUTE boot_verified=TRUE action=ALLOW
op=EXECUTE dmverity_signature=TRUE action=ALLOW
예제: 특정 dm-verity volume만 허용
748-757기본적으로 거부하고 지정한 dm-verity roothash만 허용합니다.
policy_name=Allow_DMV_By_Roothash policy_version=0.0.0
DEFAULT action=DENY
op=EXECUTE dmverity_roothash=sha256:401fcec5944823ae12f62726e8184407a5fa9599783f030dec146938 action=ALLOW
예제: 유효한 fs-verity signature
758-767기본적으로 거부하고 유효한 built-in signature가 있는 fs-verity file을 허용합니다.
policy_name=Allow_Signed_And_Validated_FSVerity policy_version=0.0.0
DEFAULT action=DENY
op=EXECUTE fsverity_signature=TRUE action=ALLOW
예제: 특정 fs-verity digest
768-777기본적으로 거부하고 지정한 fs-verity digest의 file 실행만 허용합니다.
policy_name=ALLOW_FSV_By_Digest policy_version=0.0.0
DEFAULT action=DENY
op=EXECUTE fsverity_digest=sha256:fd88f2b8824e197f850bf4c5109bea5cf0ee38104f710843bb72da796ba5af9e action=ALLOW
추가 정보와 FAQ
778-803질문: 신뢰 기반 접근 제어 수준을 제공하는 다른 LSM과 IPE의 차이는 무엇입니까?
답변: 비슷한 기능을 제공하는 다른 LSM에는 IMA와 LoadPin이 있습니다. IMA와 IPE는 기능적으로 매우 비슷하지만 중요한 차이는 policy입니다.
LoadPin과 IPE는 차이가 큽니다. LoadPin은 IPE의 kernel read operation만 다루지만 IPE는 kernel read뿐 아니라 실행도 제어할 수 있습니다. 신뢰 모델도 다릅니다. LoadPin은 initial superblock에 신뢰의 뿌리를 두지만 IPE의 신뢰는 `SYSTEM_TRUSTED_KEYS`를 통해 kernel 자체에서 시작합니다.
참고 문헌
804-824- digest_cache LSM 제안
https://lore.kernel.org/lkml/20240415142436.2545003-1-roberto.sassu@huaweicloud.com/ - Interpreter 문제 해결 논의
https://lore.kernel.org/lkml/20220321161557.495388-1-mic@digikod.net/ - switch_root(8)
https://man7.org/linux/man-pages/man8/switch_root.8.html
`devdoc` 각주는 이 주제의 자세한 설명으로 `security/ipe` 설계 문서를 가리킵니다.
`dmveritydigests` 목록은 Linux crypto API가 허용하는 값을 바탕으로 합니다. IPE 자체는 digest algorithm을 제한하지 않으므로 목록이 최신이 아닐 수 있습니다.
`fsveritydigest` 목록은 kernel fs-verity 지원이 허용하는 값을 바탕으로 합니다. IPE 자체는 digest algorithm을 제한하지 않으므로 목록이 최신이 아닐 수 있습니다.
불변 속성 기반 접근 제어
ipe.rst:1-139IPE의 신뢰 모델, 적합한 사용 사례, 알려진 제한과 위협 범위를 설명합니다.