| 1 | |
| 2 |
|
| 3 | Integrity Policy Enforcement (IPE) - Kernel Documentation
|
| 4 | =========================================================
|
| 5 |
|
| 6 | .. NOTE::
|
| 7 |
|
| 8 | This is documentation targeted at developers, instead of administrators.
|
| 9 | If you're looking for documentation on the usage of IPE, please see
|
| 10 | :doc:`IPE admin guide </admin-guide/LSM/ipe>`.
|
| 11 |
|
| 12 | Historical Motivation
|
| 13 | ---------------------
|
| 14 |
|
| 15 | The original issue that prompted IPE's implementation was the creation
|
| 16 | of a locked-down system. This system would be born-secure, and have
|
| 17 | strong integrity guarantees over both the executable code, and specific
|
| 18 | *data files* on the system, that were critical to its function. These
|
| 19 | specific data files would not be readable unless they passed integrity
|
| 20 | policy. A mandatory access control system would be present, and
|
| 21 | as a result, xattrs would have to be protected. This led to a selection
|
| 22 | of what would provide the integrity claims. At the time, there were two
|
| 23 | main mechanisms considered that could guarantee integrity for the system
|
| 24 | with these requirements:
|
| 25 |
|
| 26 | 1. IMA + EVM Signatures
|
| 27 | 2. DM-Verity
|
| 28 |
|
| 29 | Both options were carefully considered, however the choice to use DM-Verity
|
| 30 | over IMA+EVM as the *integrity mechanism* in the original use case of IPE
|
| 31 | was due to three main reasons:
|
| 32 |
|
| 33 | 1. Protection of additional attack vectors:
|
| 34 |
|
| 35 | * With IMA+EVM, without an encryption solution, the system is vulnerable
|
| 36 | to offline attack against the aforementioned specific data files.
|
| 37 |
|
| 38 | Unlike executables, read operations (like those on the protected data
|
| 39 | files), cannot be enforced to be globally integrity verified. This means
|
| 40 | there must be some form of selector to determine whether a read should
|
| 41 | enforce the integrity policy, or it should not.
|
| 42 |
|
| 43 | At the time, this was done with mandatory access control labels. An IMA
|
| 44 | policy would indicate what labels required integrity verification, which
|
| 45 | presented an issue: EVM would protect the label, but if an attacker could
|
| 46 | modify filesystem offline, the attacker could wipe all the xattrs -
|
| 47 | including the SELinux labels that would be used to determine whether the
|
| 48 | file should be subject to integrity policy.
|
| 49 |
|
| 50 | With DM-Verity, as the xattrs are saved as part of the Merkel tree, if
|
| 51 | offline mount occurs against the filesystem protected by dm-verity, the
|
| 52 | checksum no longer matches and the file fails to be read.
|
| 53 |
|
| 54 | * As userspace binaries are paged in Linux, dm-verity also offers the
|
| 55 | additional protection against a hostile block device. In such an attack,
|
| 56 | the block device reports the appropriate content for the IMA hash
|
| 57 | initially, passing the required integrity check. Then, on the page fault
|
| 58 | that accesses the real data, will report the attacker's payload. Since
|
| 59 | dm-verity will check the data when the page fault occurs (and the disk
|
| 60 | access), this attack is mitigated.
|
| 61 |
|
| 62 | 2. Performance:
|
| 63 |
|
| 64 | * dm-verity provides integrity verification on demand as blocks are
|
| 65 | read versus requiring the entire file being read into memory for
|
| 66 | validation.
|
| 67 |
|
| 68 | 3. Simplicity of signing:
|
| 69 |
|
| 70 | * No need for two signatures (IMA, then EVM): one signature covers
|
| 71 | an entire block device.
|
| 72 | * Signatures can be stored externally to the filesystem metadata.
|
| 73 | * The signature supports an x.509-based signing infrastructure.
|
| 74 |
|
| 75 | The next step was to choose a *policy* to enforce the integrity mechanism.
|
| 76 | The minimum requirements for the policy were:
|
| 77 |
|
| 78 | 1. The policy itself must be integrity verified (preventing trivial
|
| 79 | attack against it).
|
| 80 | 2. The policy itself must be resistant to rollback attacks.
|
| 81 | 3. The policy enforcement must have a permissive-like mode.
|
| 82 | 4. The policy must be able to be updated, in its entirety, without
|
| 83 | a reboot.
|
| 84 | 5. Policy updates must be atomic.
|
| 85 | 6. The policy must support *revocations* of previously authored
|
| 86 | components.
|
| 87 | 7. The policy must be auditable, at any point-of-time.
|
| 88 |
|
| 89 | IMA, as the only integrity policy mechanism at the time, was
|
| 90 | considered against these list of requirements, and did not fulfill
|
| 91 | all of the minimum requirements. Extending IMA to cover these
|
| 92 | requirements was considered, but ultimately discarded for a
|
| 93 | two reasons:
|
| 94 |
|
| 95 | 1. Regression risk; many of these changes would result in
|
| 96 | dramatic code changes to IMA, which is already present in the
|
| 97 | kernel, and therefore might impact users.
|
| 98 |
|
| 99 | 2. IMA was used in the system for measurement and attestation;
|
| 100 | separation of measurement policy from local integrity policy
|
| 101 | enforcement was considered favorable.
|
| 102 |
|
| 103 | Due to these reasons, it was decided that a new LSM should be created,
|
| 104 | whose responsibility would be only the local integrity policy enforcement.
|
| 105 |
|
| 106 | Role and Scope
|
| 107 | --------------
|
| 108 |
|
| 109 | IPE, as its name implies, is fundamentally an integrity policy enforcement
|
| 110 | solution; IPE does not mandate how integrity is provided, but instead
|
| 111 | leaves that decision to the system administrator to set the security bar,
|
| 112 | via the mechanisms that they select that suit their individual needs.
|
| 113 | There are several different integrity solutions that provide a different
|
| 114 | level of security guarantees; and IPE allows sysadmins to express policy for
|
| 115 | theoretically all of them.
|
| 116 |
|
| 117 | IPE does not have an inherent mechanism to ensure integrity on its own.
|
| 118 | Instead, there are more effective layers available for building systems that
|
| 119 | can guarantee integrity. It's important to note that the mechanism for proving
|
| 120 | integrity is independent of the policy for enforcing that integrity claim.
|
| 121 |
|
| 122 | Therefore, IPE was designed around:
|
| 123 |
|
| 124 | 1. Easy integrations with integrity providers.
|
| 125 | 2. Ease of use for platform administrators/sysadmins.
|
| 126 |
|
| 127 | Design Rationale:
|
| 128 | -----------------
|
| 129 |
|
| 130 | IPE was designed after evaluating existing integrity policy solutions
|
| 131 | in other operating systems and environments. In this survey of other
|
| 132 | implementations, there were a few pitfalls identified:
|
| 133 |
|
| 134 | 1. Policies were not readable by humans, usually requiring a binary
|
| 135 | intermediary format.
|
| 136 | 2. A single, non-customizable action was implicitly taken as a default.
|
| 137 | 3. Debugging the policy required manual steps to determine what rule was violated.
|
| 138 | 4. Authoring a policy required an in-depth knowledge of the larger system,
|
| 139 | or operating system.
|
| 140 |
|
| 141 | IPE attempts to avoid all of these pitfalls.
|
| 142 |
|
| 143 | Policy
|
| 144 | ~~~~~~
|
| 145 |
|
| 146 | Plain Text
|
| 147 | ^^^^^^^^^^
|
| 148 |
|
| 149 | IPE's policy is plain-text. This introduces slightly larger policy files than
|
| 150 | other LSMs, but solves two major problems that occurs with some integrity policy
|
| 151 | solutions on other platforms.
|
| 152 |
|
| 153 | The first issue is one of code maintenance and duplication. To author policies,
|
| 154 | the policy has to be some form of string representation (be it structured,
|
| 155 | through XML, JSON, YAML, etcetera), to allow the policy author to understand
|
| 156 | what is being written. In a hypothetical binary policy design, a serializer
|
| 157 | is necessary to write the policy from the human readable form, to the binary
|
| 158 | form, and a deserializer is needed to interpret the binary form into a data
|
| 159 | structure in the kernel.
|
| 160 |
|
| 161 | Eventually, another deserializer will be needed to transform the binary from
|
| 162 | back into the human-readable form with as much information preserved. This is because a
|
| 163 | user of this access control system will have to keep a lookup table of a checksum
|
| 164 | and the original file itself to try to understand what policies have been deployed
|
| 165 | on this system and what policies have not. For a single user, this may be alright,
|
| 166 | as old policies can be discarded almost immediately after the update takes hold.
|
| 167 | For users that manage computer fleets in the thousands, if not hundreds of thousands,
|
| 168 | with multiple different operating systems, and multiple different operational needs,
|
| 169 | this quickly becomes an issue, as stale policies from years ago may be present,
|
| 170 | quickly resulting in the need to recover the policy or fund extensive infrastructure
|
| 171 | to track what each policy contains.
|
| 172 |
|
| 173 | With now three separate serializer/deserializers, maintenance becomes costly. If the
|
| 174 | policy avoids the binary format, there is only one required serializer: from the
|
| 175 | human-readable form to the data structure in kernel, saving on code maintenance,
|
| 176 | and retaining operability.
|
| 177 |
|
| 178 | The second issue with a binary format is one of transparency. As IPE controls
|
| 179 | access based on the trust of the system's resources, it's policy must also be
|
| 180 | trusted to be changed. This is done through signatures, resulting in needing
|
| 181 | signing as a process. Signing, as a process, is typically done with a
|
| 182 | high security bar, as anything signed can be used to attack integrity
|
| 183 | enforcement systems. It is also important that, when signing something, that
|
| 184 | the signer is aware of what they are signing. A binary policy can cause
|
| 185 | obfuscation of that fact; what signers see is an opaque binary blob. A
|
| 186 | plain-text policy, on the other hand, the signers see the actual policy
|
| 187 | submitted for signing.
|
| 188 |
|
| 189 | Boot Policy
|
| 190 | ~~~~~~~~~~~
|
| 191 |
|
| 192 | IPE, if configured appropriately, is able to enforce a policy as soon as a
|
| 193 | kernel is booted and usermode starts. That implies some level of storage
|
| 194 | of the policy to apply the minute usermode starts. Generally, that storage
|
| 195 | can be handled in one of three ways:
|
| 196 |
|
| 197 | 1. The policy file(s) live on disk and the kernel loads the policy prior
|
| 198 | to a code path that would result in an enforcement decision.
|
| 199 | 2. The policy file(s) are passed by the bootloader to the kernel, who
|
| 200 | parses the policy.
|
| 201 | 3. There is a policy file that is compiled into the kernel that is
|
| 202 | parsed and enforced on initialization.
|
| 203 |
|
| 204 | The first option has problems: the kernel reading files from userspace
|
| 205 | is typically discouraged and very uncommon in the kernel.
|
| 206 |
|
| 207 | The second option also has problems: Linux supports a variety of bootloaders
|
| 208 | across its entire ecosystem - every bootloader would have to support this
|
| 209 | new methodology or there must be an independent source. It would likely
|
| 210 | result in more drastic changes to the kernel startup than necessary.
|
| 211 |
|
| 212 | The third option is the best but it's important to be aware that the policy
|
| 213 | will take disk space against the kernel it's compiled in. It's important to
|
| 214 | keep this policy generalized enough that userspace can load a new, more
|
| 215 | complicated policy, but restrictive enough that it will not overauthorize
|
| 216 | and cause security issues.
|
| 217 |
|
| 218 | The initramfs provides a way that this bootup path can be established. The
|
| 219 | kernel starts with a minimal policy, that trusts the initramfs only. Inside
|
| 220 | the initramfs, when the real rootfs is mounted, but not yet transferred to,
|
| 221 | it deploys and activates a policy that trusts the new root filesystem.
|
| 222 | This prevents overauthorization at any step, and keeps the kernel policy
|
| 223 | to a minimal size.
|
| 224 |
|
| 225 | Startup
|
| 226 | ^^^^^^^
|
| 227 |
|
| 228 | Not every system, however starts with an initramfs, so the startup policy
|
| 229 | compiled into the kernel will need some flexibility to express how trust
|
| 230 | is established for the next phase of the bootup. To this end, if we just
|
| 231 | make the compiled-in policy a full IPE policy, it allows system builders
|
| 232 | to express the first stage bootup requirements appropriately.
|
| 233 |
|
| 234 | Updatable, Rebootless Policy
|
| 235 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| 236 |
|
| 237 | As requirements change over time (vulnerabilities are found in previously
|
| 238 | trusted applications, keys roll, etcetera), updating a kernel to meet
|
| 239 | those security goals is not always a suitable option, as updates are not
|
| 240 | always risk-free, and blocking a security update leaves systems vulnerable.
|
| 241 | This means IPE requires a policy that can be completely updated (allowing
|
| 242 | revocations of existing policy) from a source external to the kernel (allowing
|
| 243 | policies to be updated without updating the kernel).
|
| 244 |
|
| 245 | Additionally, since the kernel is stateless between invocations, and reading
|
| 246 | policy files off the disk from kernel space is a bad idea(tm), then the
|
| 247 | policy updates have to be done rebootlessly.
|
| 248 |
|
| 249 | To allow an update from an external source, it could be potentially malicious,
|
| 250 | so this policy needs to have a way to be identified as trusted. This is
|
| 251 | done via a signature chained to a trust source in the kernel. Arbitrarily,
|
| 252 | this is the ``SYSTEM_TRUSTED_KEYRING``, a keyring that is initially
|
| 253 | populated at kernel compile-time, as this matches the expectation that the
|
| 254 | author of the compiled-in policy described above is the same entity that can
|
| 255 | deploy policy updates.
|
| 256 |
|
| 257 | Anti-Rollback / Anti-Replay
|
| 258 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| 259 |
|
| 260 | Over time, vulnerabilities are found and trusted resources may not be
|
| 261 | trusted anymore. IPE's policy has no exception to this. There can be
|
| 262 | instances where a mistaken policy author deploys an insecure policy,
|
| 263 | before correcting it with a secure policy.
|
| 264 |
|
| 265 | Assuming that as soon as the insecure policy is signed, and an attacker
|
| 266 | acquires the insecure policy, IPE needs a way to prevent rollback
|
| 267 | from the secure policy update to the insecure policy update.
|
| 268 |
|
| 269 | Initially, IPE's policy can have a policy_version that states the
|
| 270 | minimum required version across all policies that can be active on
|
| 271 | the system. This will prevent rollback while the system is live.
|
| 272 |
|
| 273 | .. WARNING::
|
| 274 |
|
| 275 | However, since the kernel is stateless across boots, this policy
|
| 276 | version will be reset to 0.0.0 on the next boot. System builders
|
| 277 | need to be aware of this, and ensure the new secure policies are
|
| 278 | deployed ASAP after a boot to ensure that the window of
|
| 279 | opportunity is minimal for an attacker to deploy the insecure policy.
|
| 280 |
|
| 281 | Implicit Actions:
|
| 282 | ~~~~~~~~~~~~~~~~~
|
| 283 |
|
| 284 | The issue of implicit actions only becomes visible when you consider
|
| 285 | a mixed level of security bars across multiple operations in a system.
|
| 286 | For example, consider a system that has strong integrity guarantees
|
| 287 | over both the executable code, and specific *data files* on the system,
|
| 288 | that were critical to its function. In this system, three types of policies
|
| 289 | are possible:
|
| 290 |
|
| 291 | 1. A policy in which failure to match any rules in the policy results
|
| 292 | in the action being denied.
|
| 293 | 2. A policy in which failure to match any rules in the policy results
|
| 294 | in the action being allowed.
|
| 295 | 3. A policy in which the action taken when no rules are matched is
|
| 296 | specified by the policy author.
|
| 297 |
|
| 298 | The first option could make a policy like this::
|
| 299 |
|
| 300 | op=EXECUTE integrity_verified=YES action=ALLOW
|
| 301 |
|
| 302 | In the example system, this works well for the executables, as all
|
| 303 | executables should have integrity guarantees, without exception. The
|
| 304 | issue becomes with the second requirement about specific data files.
|
| 305 | This would result in a policy like this (assuming each line is
|
| 306 | evaluated in order)::
|
| 307 |
|
| 308 | op=EXECUTE integrity_verified=YES action=ALLOW
|
| 309 |
|
| 310 | op=READ integrity_verified=NO label=critical_t action=DENY
|
| 311 | op=READ action=ALLOW
|
| 312 |
|
| 313 | This is somewhat clear if you read the docs, understand the policy
|
| 314 | is executed in order and that the default is a denial; however, the
|
| 315 | last line effectively changes that default to an ALLOW. This is
|
| 316 | required, because in a realistic system, there are some unverified
|
| 317 | reads (imagine appending to a log file).
|
| 318 |
|
| 319 | The second option, matching no rules results in an allow, is clearer
|
| 320 | for the specific data files::
|
| 321 |
|
| 322 | op=READ integrity_verified=NO label=critical_t action=DENY
|
| 323 |
|
| 324 | And, like the first option, falls short with the execution scenario,
|
| 325 | effectively needing to override the default::
|
| 326 |
|
| 327 | op=EXECUTE integrity_verified=YES action=ALLOW
|
| 328 | op=EXECUTE action=DENY
|
| 329 |
|
| 330 | op=READ integrity_verified=NO label=critical_t action=DENY
|
| 331 |
|
| 332 | This leaves the third option. Instead of making users be clever
|
| 333 | and override the default with an empty rule, force the end-user
|
| 334 | to consider what the appropriate default should be for their
|
| 335 | scenario and explicitly state it::
|
| 336 |
|
| 337 | DEFAULT op=EXECUTE action=DENY
|
| 338 | op=EXECUTE integrity_verified=YES action=ALLOW
|
| 339 |
|
| 340 | DEFAULT op=READ action=ALLOW
|
| 341 | op=READ integrity_verified=NO label=critical_t action=DENY
|
| 342 |
|
| 343 | Policy Debugging:
|
| 344 | ~~~~~~~~~~~~~~~~~
|
| 345 |
|
| 346 | When developing a policy, it is useful to know what line of the policy
|
| 347 | is being violated to reduce debugging costs; narrowing the scope of the
|
| 348 | investigation to the exact line that resulted in the action. Some integrity
|
| 349 | policy systems do not provide this information, instead providing the
|
| 350 | information that was used in the evaluation. This then requires a correlation
|
| 351 | with the policy to evaluate what went wrong.
|
| 352 |
|
| 353 | Instead, IPE just emits the rule that was matched. This limits the scope
|
| 354 | of the investigation to the exact policy line (in the case of a specific
|
| 355 | rule), or the section (in the case of a DEFAULT). This decreases iteration
|
| 356 | and investigation times when policy failures are observed while evaluating
|
| 357 | policies.
|
| 358 |
|
| 359 | IPE's policy engine is also designed in a way that it makes it obvious to
|
| 360 | a human of how to investigate a policy failure. Each line is evaluated in
|
| 361 | the sequence that is written, so the algorithm is very simple to follow
|
| 362 | for humans to recreate the steps and could have caused the failure. In other
|
| 363 | surveyed systems, optimizations occur (sorting rules, for instance) when loading
|
| 364 | the policy. In those systems, it requires multiple steps to debug, and the
|
| 365 | algorithm may not always be clear to the end-user without reading the code first.
|
| 366 |
|
| 367 | Simplified Policy:
|
| 368 | ~~~~~~~~~~~~~~~~~~
|
| 369 |
|
| 370 | Finally, IPE's policy is designed for sysadmins, not kernel developers. Instead
|
| 371 | of covering individual LSM hooks (or syscalls), IPE covers operations. This means
|
| 372 | instead of sysadmins needing to know that the syscalls ``mmap``, ``mprotect``,
|
| 373 | ``execve``, and ``uselib`` must have rules protecting them, they must simply know
|
| 374 | that they want to restrict code execution. This limits the amount of bypasses that
|
| 375 | could occur due to a lack of knowledge of the underlying system; whereas the
|
| 376 | maintainers of IPE, being kernel developers can make the correct choice to determine
|
| 377 | whether something maps to these operations, and under what conditions.
|
| 378 |
|
| 379 | Implementation Notes
|
| 380 | --------------------
|
| 381 |
|
| 382 | Anonymous Memory
|
| 383 | ~~~~~~~~~~~~~~~~
|
| 384 |
|
| 385 | Anonymous memory isn't treated any differently from any other access in IPE.
|
| 386 | When anonymous memory is mapped with ``+X``, it still comes into the ``file_mmap``
|
| 387 | or ``file_mprotect`` hook, but with a ``NULL`` file object. This is submitted to
|
| 388 | the evaluation, like any other file. However, all current trust properties will
|
| 389 | evaluate to false, as they are all file-based and the operation is not
|
| 390 | associated with a file.
|
| 391 |
|
| 392 | .. WARNING::
|
| 393 |
|
| 394 | This also occurs with the ``kernel_load_data`` hook, when the kernel is
|
| 395 | loading data from a userspace buffer that is not backed by a file. In this
|
| 396 | scenario all current trust properties will also evaluate to false.
|
| 397 |
|
| 398 | Securityfs Interface
|
| 399 | ~~~~~~~~~~~~~~~~~~~~
|
| 400 |
|
| 401 | The per-policy securityfs tree is somewhat unique. For example, for
|
| 402 | a standard securityfs policy tree::
|
| 403 |
|
| 404 | MyPolicy
|
| 405 | |- active
|
| 406 | |- delete
|
| 407 | |- name
|
| 408 | |- pkcs7
|
| 409 | |- policy
|
| 410 | |- update
|
| 411 | |- version
|
| 412 |
|
| 413 | The policy is stored in the ``->i_private`` data of the MyPolicy inode.
|
| 414 |
|
| 415 | Tests
|
| 416 | -----
|
| 417 |
|
| 418 | IPE has KUnit Tests for the policy parser. Recommended kunitconfig::
|
| 419 |
|
| 420 | CONFIG_KUNIT=y
|
| 421 | CONFIG_SECURITY=y
|
| 422 | CONFIG_SECURITYFS=y
|
| 423 | CONFIG_PKCS7_MESSAGE_PARSER=y
|
| 424 | CONFIG_SYSTEM_DATA_VERIFICATION=y
|
| 425 | CONFIG_FS_VERITY=y
|
| 426 | CONFIG_FS_VERITY_BUILTIN_SIGNATURES=y
|
| 427 | CONFIG_BLOCK=y
|
| 428 | CONFIG_MD=y
|
| 429 | CONFIG_BLK_DEV_DM=y
|
| 430 | CONFIG_DM_VERITY=y
|
| 431 | CONFIG_DM_VERITY_VERIFY_ROOTHASH_SIG=y
|
| 432 | CONFIG_NET=y
|
| 433 | CONFIG_AUDIT=y
|
| 434 | CONFIG_AUDITSYSCALL=y
|
| 435 | CONFIG_BLK_DEV_INITRD=y
|
| 436 |
|
| 437 | CONFIG_SECURITY_IPE=y
|
| 438 | CONFIG_IPE_PROP_DM_VERITY=y
|
| 439 | CONFIG_IPE_PROP_DM_VERITY_SIGNATURE=y
|
| 440 | CONFIG_IPE_PROP_FS_VERITY=y
|
| 441 | CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG=y
|
| 442 | CONFIG_SECURITY_IPE_KUNIT_TEST=y
|
| 443 |
|
| 444 | In addition, IPE has a python based integration
|
| 445 | `test suite <https://github.com/microsoft/ipe/tree/test-suite>`_ that
|
| 446 | can test both user interfaces and enforcement functionalities.
|