The most essential part of IPE is its customizable policy which allows users to specify the rules that the LSM should enforce for different operations. This policy is designed to be both forward compatible and backwards compatible. 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 roll-back 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 that rule should be evaluated. Thus, a minimal rule is:
This example will allow any execution. Additional properties are used to restrict attributes about the files being evaluated. These properties are intended to be deterministic attributes that are resident in the kernel.
Order does not matter for the rule's properties - they can be listed in any order, however it is encouraged to have the "op" property be first, and the "action" property be last for readability. 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 as rule with "action=ALLOW" is hit.
Any unrecognized syntax in the policy will result in a fatal error to parse the policy. 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,
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 operation must be set for all understood
operations within IPE. For policies to remain completely forwards
compatible, it is recommended that users add a
and override the defaults on a per-operation basis.
Early user-mode protection
With configurable policy-based LSMs, there's several issues with enforcing the configurable policies at startup, around reading and parsing the policy:
- The kernel should not read files from userland, so directly reading the policy file is prohibited.
- The kernel command line has a character limit, and one kernel module should not reserve the entire character limit for its own configuration.
- 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, compiled into the kernel. This
policy is intended to get the system to a state where userland is setup
and ready to receive commands, at which point a more complex policy ("user policies")
can be deployed via securityfs. The boot policy can be specified via the
SECURITY_IPE_BOOT_POLICY, 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
through securityfs, and activated through sysfs.
IPE, similar to SELinux, supports two modes of operation: permissive and enforce. Permissive mode performs the same checks as enforce mode, and logs policy violations, but will not enforce the policy. This allows users to test policies before enforcing them.
The default mode is enforce, and can be changed via the kernel command line
ipe.enforce=(0|1), or the securityfs node,
/sys/kernel/security/ipe/enforce. The ability to switch modes can be compiled
out of the LSM via setting the Kconfig
CONFIG_SECURITY_IPE_PERMISSIVE_SWITCH to N.