An exec rule that names a profile which is not loaded denies the exec. The only way policy can say "use something else instead" today is the composite mode letters:
/usr/bin/stg Pix -> stg, # if stg is missing, run under the parent /usr/bin/stg PUx -> stg, # if stg is missing, run unconfined However, ix and ux are not always adapted: ix gives the child whatever the parent has and ux gives it everything. Neither can be fitted to what the child actually does, so the choice is between denying and over-granting. Two cases want a real answer. Policy that ships in parts needs a rule to stay useful while its target is still missing (a helper packaged separately, a profile staged for a later release, and apparmor.d, whose deployment is inherently partial). And a profile that spawns a helper usually has a sensible category profile to name instead, say network-helper: not necessarily stricter than ix, but fitted to the job rather than inherited from the parent. This series lets the rule name it. Both forms of exec rule take a list, whether or not they name a target: /usr/bin/stg Px -> stg fallback=(generic-helper), /usr/bin/foo Px fallback=(restricted-helper), This is the profile-side equivalent of identity delegation, and complements it. At exec the kernel tries, in order, the rule's own target (the -> target if present, or the profile the executable's path attaches to) and then each fallback in the order written. The first that resolves wins. When the list is exhausted, the rule behaves exactly as an unresolved target does without one: the ix or ux composite if the mode letters ask for it, otherwise -EACCES with info="profile transition not found". The list is walked afresh on every exec, so loading the primary target later makes it win immediately. The alternatives are appended to the rule's existing transition table entry, which becomes a \0-separated list. A list is told from a plain name by a second terminator, decided per entry rather than per table, so policy built before this series keeps loading unchanged. The implicit form needs a transition type of its own, and AA_X_TYPE_MASK had one value spare: AA_X_NAME | AA_X_TABLE, previously unused, now means resolve by attachment and walk the entry only if that finds nothing. The kernel advertises domain/exec_fallback, allowing the parser to use this feature in policies if supported by the kernel, or degrade loading gracefully. - Patch 1 moves per-element target resolution into one place. - Patch 2 makes a table entry able to hold a list. - Patch 3 walks it. - Patch 4 adds the implicit form and advertises the feature The parser side has been posted upstream separately. Based on apparmor-next (4ec11f14d1d6). Maxime Bélair (4): apparmor: split exec target resolution by kind apparmor: allow multi-entry transition tables apparmor: try exec fallback targets in order apparmor: resolve fallbacks after attachment security/apparmor/apparmorfs.c | 1 + security/apparmor/domain.c | 274 +++++++++++++++++----- security/apparmor/include/domain.h | 3 - security/apparmor/include/file.h | 4 + security/apparmor/include/policy_unpack.h | 1 + security/apparmor/policy_unpack.c | 86 +++++-- security/apparmor/policy_unpack_test.c | 144 ++++++++++++ 7 files changed, 423 insertions(+), 90 deletions(-) -- 2.51.0
