Re: [RFC PATCH v9 07/16] uapi|audit|ipe: add ipe auditing support

From: Roberto Sassu
Date: Tue Jan 31 2023 - 07:58:54 EST


On Mon, 2023-01-30 at 14:57 -0800, Fan Wu wrote:
> From: Deven Bowers <deven.desai@xxxxxxxxxxxxxxxxxxx>
>
> Users of IPE require a way to identify when and why an operation fails,
> allowing them to both respond to violations of policy and be notified
> of potentially malicious actions on their systens with respect to IPE
> itself.
>
> The new 1420 audit, AUDIT_IPE_ACCESS indicates the result of a policy
> evaulation of a resource. The other two events, AUDIT_MAC_POLICY_LOAD,
> and AUDIT_MAC_CONFIG_CHANGE represent a new policy was loaded into the
> kernel and the currently active policy changed, respectively.
>
> This patch also adds support for success auditing, allowing users to
> identify how a resource passed policy. It is recommended to use this
> option with caution, as it is quite noisy.

Not sure if this comment makes sense. When a new function is
introduced, like ipe_update_policy(), I like to see it in only one
patch, not with subsequent changes, unless it is really necessary.

If it is possible, I would always introduce the dependencies before and
then the new function.

Roberto

> This patch adds the following audit records:
>
> audit: AUDIT1420 path="/tmp/tmpwxmam366/deny/bin/hello" dev="tmpfs"
> ino=72 rule="DEFAULT op=EXECUTE action=DENY"
>
> The above audit record shows IPE blocked a file
> /tmp/tmpwxmam366/deny/bin/hello in the temp file system.
>
> audit: AUDIT1420 path="/tmp/tmpxkvb3d9x/deny/bin/hello" dev="tmpfs"
> ino=157 rule="DEFAULT action=DENY"
>
> The above audit record shows IPE blocked a file
> /tmp/tmpxkvb3d9x/deny/bin/hello in the temp file system via another
> rule.
>
> audit: MAC_POLICY_LOAD policy_name="dmverity_roothash"
> policy_version=0.0.0 sha256=DC67AC19E05894EFB3170A8E55DE529794E248C2
> auid=4294967295 ses=4294967295 lsm=ipe res=1
>
> The above audit record shows IPE loaded a new policy named
> "dmverity_roothash" with the sha256 hash of the policy.
>
> audit: MAC_CONFIG_CHANGE old_active_pol_name="Allow_All"
> old_active_pol_version=0.0.0
> old_sha256=DA39A3EE5E6B4B0D3255BFEF95601890AFD80709
> new_active_pol_name="dmverity_roothash" new_active_pol_version=0.0.0
> new_sha256=DC67AC19E05894EFB3170A8E55DE529794E248C2
> auid=4294967295 ses=4294967295 lsm=ipe res=1
>
> The above audit record shows IPE's active policy switched from
> "Allow_All" to "dmverity_roothash".
>
> These result in the following events (the audit records are always
> prior to a SYSCALL record):
>
> audit: AUDIT1420 path="/tmp/tmpwxmam366/deny/bin/hello" dev="tmpfs"
> ino=72 rule="DEFAULT op=EXECUTE action=DENY"
> audit[476]: SYSCALL arch=c000003e syscall=59 success=no exit=-13
> a0=7f7d01b5e890 a1=7f7d01f80e80 a2=7ffde535f230 a3=0 items=0 ppid=229
> pid=476 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)
> audit: PROCTITLE
> proctitle=707974686F6E3300746573742F6D61696E2E7079002D66002E2E
>
> The above events shows IPE blocked the hello file which python was
> trying to execute.
>
> audit: AUDIT1420 path="/tmp/tmpxkvb3d9x/deny/bin/hello" dev="tmpfs"
> ino=157 rule="DEFAULT action=DENY"
> audit[1195]: SYSCALL arch=c000003e syscall=9 success=no
> exit=-13 a0=0 a1=18020 a2=6 a3=2 items=0 ppid=997 pid=1195
> auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0
> tty=pts0 ses=4294967295 comm="mmap_test"
> exe="/tmp/ipe-test/bin/mmap_test" key=(null)
> audit: PROCTITLE
> proctitle=2F746D702F6970652D746573742F62696E2F6D6D61705F746573
>
> The above events shows IPE blocked the hello file which
> /tmp/ipe-test/bin/mmap_test was trying to mmap.
>
> audit: MAC_POLICY_LOAD policy_name="dmverity_roothash"
> policy_version=0.0.0 sha256=DC67AC19E05894EFB3170A8E55DE529794E248C2
> auid=4294967295 ses=4294967295 lsm=ipe res=1
> audit[229]: SYSCALL 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 sg
> id=0 fsgid=0 tty=pts0 ses=4294967295 comm="python3"
> exe="/usr/bin/python3.10" key=(null)
> audit: PROCTITLE
> proctitle=707974686F6E3300746573742F6D61696E2E7079002D66002E2E
>
> The above events shows IPE loaded a new policy "dmverity_roothash"
> because python used write system call.
>
> audit: MAC_CONFIG_CHANGE old_active_pol_name="Allow_All"
> old_active_pol_version=0.0.0
> old_sha256=DA39A3EE5E6B4B0D3255BFEF95601890AFD80709
> new_active_pol_name="dmverity_roothash" new_active_pol_version=0.0.0
> new_sha256=DC67AC19E05894EFB3170A8E55DE529794E248C2
> auid=4294967295 ses=4294967295 lsm=ipe res=1
> audit[229]: 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)
> audit: PROCTITLE
> proctitle=707974686F6E3300746573742F6D61696E2E7079002D66002E2
> The above events shows IPE switched to a new active policy
> "dmverity_roothash" because python used write system call.
>
> Signed-off-by: Deven Bowers <deven.desai@xxxxxxxxxxxxxxxxxxx>
> Signed-off-by: Fan Wu <wufan@xxxxxxxxxxxxxxxxxxx>
> ---
>
> v2:
> + Split evaluation loop, access control hooks,
> and evaluation loop from policy parser and userspace
> interface to pass mailing list character limit
>
> v3:
> + Move ipe_load_properties to patch 04.
> + Remove useless 0-initializations
> + Prefix extern variables with ipe_
> + Remove kernel module parameters, as these are
> exposed through sysctls.
> + Add more prose to the IPE base config option
> help text.
> + Use GFP_KERNEL for audit_log_start.
> + Remove unnecessary caching system.
> + Remove comments from headers
> + Use rcu_access_pointer for rcu-pointer null check
> + Remove usage of reqprot; use prot only.
> + Move policy load and activation audit event to 03/12
>
> v4:
> + Remove sysctls in favor of securityfs nodes
> + Re-add kernel module parameters, as these are now
> exposed through securityfs.
> + Refactor property audit loop to a separate function.
>
> v5:
> + fix minor grammatical errors
> + do not group rule by curly-brace in audit record,
> reconstruct the exact rule.
>
> v6:
> + No changes
>
> v7:
> + Further split lsm creation, the audit system, the evaluation loop,
> and access control hooks into separate patches.
> + Further split audit system patch into two separate patches; one
> for include/uapi, and the usage of the new defines.
> + Split out the permissive functionality into another separate patch,
> for easier review.
> + Correct misuse of audit_log_n_untrusted string to audit_log_format
> + Use get_task_comm instead of comm directly.
> + Quote certain audit values
> + Remove unnecessary help text on choice options - these were
> previously
> idented at the wrong level
> + Correct a stale string constant (ctx_ns_enforce to ctx_enforce)
>
> v8:
>
> + Change dependency for CONFIG_AUDIT to CONFIG_AUDITSYSCALL
> + Drop ctx_* prefix
> + Reuse, where appropriate, the audit fields from the field
> dictionary. This transforms:
> ctx_pathname -> path
> ctx_ino -> ino
> ctx_dev -> dev
>
> + Add audit records and event examples to commit description.
> + Remove new_audit_ctx, replace with audit_log_start. All data that
> would provided by new_audit_ctx is already present in the syscall
> audit record, that is always emitted on these actions. The audit
> records should be correlated as such.
> + Change audit types:
> + AUDIT_TRUST_RESULT -> AUDIT_IPE_ACCESS
> + This prevents overloading of the AVC type.
> + AUDIT_TRUST_POLICY_ACTIVATE -> AUDIT_MAC_CONFIG_CHANGE
> + AUDIT_TRUST_POLICY_LOAD -> AUDIT_MAC_POLICY_LOAD
> + There were no significant difference in meaning between
> these types.
>
> + Remove enforcing parameter passed from the context structure
> for AUDIT_IPE_ACCESS.
> + This field can be inferred from the SYSCALL audit event,
> based on the success field.
>
> + Remove all fields already captured in the syscall record. "hook",
> an IPE specific field, can be determined via the syscall field in
> the syscall record itself, so it has been removed.
> + ino, path, and dev in IPE's record refer to the subject of the
> syscall, while the syscall record refers to the calling process.
>
> + remove IPE prefix from policy load/policy activation events
> + fix a bug wherein a policy change audit record was not fired when
> updating a policy
>
> v9:
> + Merge the AUDIT_IPE_ACCESS definition with the audit support commit
> + Change the audit format of policy load and siwtch
> + Remove the ipe audit kernel switch
> ---
> include/uapi/linux/audit.h | 1 +
> security/ipe/Kconfig | 2 +-
> security/ipe/Makefile | 1 +
> security/ipe/audit.c | 196 +++++++++++++++++++++++++++++++++++++
> security/ipe/audit.h | 18 ++++
> security/ipe/eval.c | 26 ++++-
> security/ipe/eval.h | 8 ++
> security/ipe/fs.c | 68 +++++++++++++
> security/ipe/policy.c | 5 +
> 9 files changed, 321 insertions(+), 4 deletions(-)
> create mode 100644 security/ipe/audit.c
> create mode 100644 security/ipe/audit.h
>
> diff --git a/include/uapi/linux/audit.h b/include/uapi/linux/audit.h
> index d676ed2b246e..ee3b3db95076 100644
> --- a/include/uapi/linux/audit.h
> +++ b/include/uapi/linux/audit.h
> @@ -143,6 +143,7 @@
> #define AUDIT_MAC_UNLBL_STCDEL 1417 /* NetLabel: del a static label */
> #define AUDIT_MAC_CALIPSO_ADD 1418 /* NetLabel: add CALIPSO DOI entry */
> #define AUDIT_MAC_CALIPSO_DEL 1419 /* NetLabel: del CALIPSO DOI entry */
> +#define AUDIT_IPE_ACCESS 1420 /* IPE Denial or Grant */
>
> #define AUDIT_FIRST_KERN_ANOM_MSG 1700
> #define AUDIT_LAST_KERN_ANOM_MSG 1799
> diff --git a/security/ipe/Kconfig b/security/ipe/Kconfig
> index e4875fb04883..ac4d558e69d5 100644
> --- a/security/ipe/Kconfig
> +++ b/security/ipe/Kconfig
> @@ -5,7 +5,7 @@
>
> menuconfig SECURITY_IPE
> bool "Integrity Policy Enforcement (IPE)"
> - depends on SECURITY && SECURITYFS
> + depends on SECURITY && SECURITYFS && AUDIT && AUDITSYSCALL
> select PKCS7_MESSAGE_PARSER
> select SYSTEM_DATA_VERIFICATION
> help
> diff --git a/security/ipe/Makefile b/security/ipe/Makefile
> index 8602d71250b4..89a76ad72301 100644
> --- a/security/ipe/Makefile
> +++ b/security/ipe/Makefile
> @@ -13,3 +13,4 @@ obj-$(CONFIG_SECURITY_IPE) += \
> policy.o \
> policy_fs.o \
> policy_parser.o \
> + audit.o \
> diff --git a/security/ipe/audit.c b/security/ipe/audit.c
> new file mode 100644
> index 000000000000..295e9f9f5146
> --- /dev/null
> +++ b/security/ipe/audit.c
> @@ -0,0 +1,196 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) Microsoft Corporation. All rights reserved.
> + */
> +
> +#include "ipe.h"
> +#include "eval.h"
> +#include "hooks.h"
> +#include "policy.h"
> +#include "audit.h"
> +#include "digest.h"
> +
> +#include <linux/slab.h>
> +#include <linux/audit.h>
> +#include <linux/types.h>
> +#include <crypto/hash.h>
> +
> +#define ACTSTR(x) ((x) == ipe_action_allow ? "ALLOW" : "DENY")
> +
> +#define IPE_AUDIT_HASH_ALG "sha256"
> +
> +#define AUDIT_POLICY_LOAD_FMT "policy_name=\"%s\" policy_version=%hu.%hu.%hu "\
> + IPE_AUDIT_HASH_ALG "="
> +#define AUDIT_OLD_ACTIVE_POLICY_FMT "old_active_pol_name=\"%s\" "\
> + "old_active_pol_version=%hu.%hu.%hu "\
> + "old_" IPE_AUDIT_HASH_ALG "="
> +#define AUDIT_NEW_ACTIVE_POLICY_FMT "new_active_pol_name=\"%s\" "\
> + "new_active_pol_version=%hu.%hu.%hu "\
> + "new_" IPE_AUDIT_HASH_ALG "="
> +
> +static const char *const audit_op_names[ipe_op_max] = {
> + "EXECUTE",
> + "FIRMWARE",
> + "KMODULE",
> + "KEXEC_IMAGE",
> + "KEXEC_INITRAMFS",
> + "IMA_POLICY",
> + "IMA_X509_CERT",
> +};
> +
> +static const char *const audit_prop_names[ipe_prop_max] = {
> + "boot_verified=FALSE",
> + "boot_verified=TRUE",
> +};
> +
> +/**
> + * audit_rule - audit an IPE policy rule approximation.
> + * @ab: Supplies a poniter to the audit_buffer to append to.
> + * @r: Supplies a pointer to the ipe_rule to approximate a string form for.
> + */
> +static void audit_rule(struct audit_buffer *ab, const struct ipe_rule *r)
> +{
> + const struct ipe_prop *ptr;
> +
> + audit_log_format(ab, "rule=\"op=%s ", audit_op_names[r->op]);
> +
> + list_for_each_entry(ptr, &r->props, next) {
> + audit_log_format(ab, "%s", audit_prop_names[ptr->type]);
> + audit_log_format(ab, " ");
> + }
> +
> + audit_log_format(ab, "action=%s\"", ACTSTR(r->action));
> +}
> +
> +/**
> + * ipe_audit_match - audit a match for IPE policy.
> + * @ctx: Supplies a poniter to the evaluation context that was used in the
> + * evaluation.
> + * @match_type: Supplies the scope of the match: rule, operation default,
> + * global default.
> + * @act: Supplies the IPE's evaluation decision, deny or allow.
> + * @r: Supplies a pointer to the rule that was matched, if possible.
> + * @enforce: Supplies the enforcement/permissive state at the point
> + * the enforcement decision was made.
> + */
> +void ipe_audit_match(const struct ipe_eval_ctx *const ctx,
> + enum ipe_match match_type,
> + enum ipe_action_type act, const struct ipe_rule *const r)
> +{
> + struct inode *inode;
> + struct audit_buffer *ab;
> + const char *op = audit_op_names[ctx->op];
> +
> + if (act != ipe_action_deny && !READ_ONCE(success_audit))
> + return;
> +
> + ab = audit_log_start(audit_context(), GFP_KERNEL, AUDIT_IPE_ACCESS);
> + if (!ab)
> + return;
> +
> + if (ctx->file) {
> + audit_log_d_path(ab, "path=", &ctx->file->f_path);
> + inode = file_inode(ctx->file);
> + if (inode) {
> + audit_log_format(ab, " dev=");
> + audit_log_untrustedstring(ab, inode->i_sb->s_id);
> + audit_log_format(ab, " ino=%lu ", inode->i_ino);
> + }
> + }
> +
> + if (match_type == ipe_match_rule)
> + audit_rule(ab, r);
> + else if (match_type == ipe_match_table)
> + audit_log_format(ab, "rule=\"DEFAULT op=%s action=%s\"", op,
> + ACTSTR(act));
> + else
> + audit_log_format(ab, "rule=\"DEFAULT action=%s\"",
> + ACTSTR(act));
> +
> + audit_log_end(ab);
> +}
> +
> +/**
> + * audit_policy - Audit a policy's name, version and thumbprint to @ab.
> + * @ab: Supplies a pointer to the audit buffer to append to.
> + * @p: Supplies a pointer to the policy to audit.
> + */
> +static void audit_policy(struct audit_buffer *ab,
> + const char *audit_format,
> + const struct ipe_policy *const p)
> +{
> + u8 *digest = NULL;
> + struct crypto_shash *tfm;
> + SHASH_DESC_ON_STACK(desc, tfm);
> +
> + tfm = crypto_alloc_shash(IPE_AUDIT_HASH_ALG, 0, 0);
> + if (IS_ERR(tfm))
> + return;
> +
> + desc->tfm = tfm;
> +
> + digest = kzalloc(crypto_shash_digestsize(tfm), GFP_KERNEL);
> + if (!digest)
> + goto out;
> +
> + if (crypto_shash_init(desc))
> + goto out;
> +
> + if (crypto_shash_update(desc, p->pkcs7, p->pkcs7len))
> + goto out;
> +
> + if (crypto_shash_final(desc, digest))
> + goto out;
> +
> + audit_log_format(ab, audit_format, p->parsed->name,
> + p->parsed->version.major, p->parsed->version.minor,
> + p->parsed->version.rev);
> + audit_log_n_hex(ab, digest, crypto_shash_digestsize(tfm));
> +
> +out:
> + kfree(digest);
> + crypto_free_shash(tfm);
> +}
> +
> +/**
> + * ipe_audit_policy_activation - Audit a policy being made the active policy.
> + * @p: Supplies a pointer to the policy to audit.
> + */
> +void ipe_audit_policy_activation(const struct ipe_policy *const op,
> + const struct ipe_policy *const np)
> +{
> + struct audit_buffer *ab;
> +
> + ab = audit_log_start(audit_context(), GFP_KERNEL, AUDIT_MAC_CONFIG_CHANGE);
> + if (!ab)
> + return;
> +
> + audit_policy(ab, AUDIT_OLD_ACTIVE_POLICY_FMT, op);
> + audit_log_format(ab, " ");
> + audit_policy(ab, AUDIT_NEW_ACTIVE_POLICY_FMT, np);
> + audit_log_format(ab, " auid=%u ses=%u lsm=ipe res=1",
> + from_kuid(&init_user_ns, audit_get_loginuid(current)),
> + audit_get_sessionid(current));
> +
> + audit_log_end(ab);
> +}
> +
> +/**
> + * ipe_audit_policy_load - Audit a policy being loaded into the kernel.
> + * @p: Supplies a pointer to the policy to audit.
> + */
> +void ipe_audit_policy_load(const struct ipe_policy *const p)
> +{
> + struct audit_buffer *ab;
> +
> + ab = audit_log_start(audit_context(), GFP_KERNEL, AUDIT_MAC_POLICY_LOAD);
> + if (!ab)
> + return;
> +
> + audit_policy(ab, AUDIT_POLICY_LOAD_FMT, p);
> + audit_log_format(ab, " auid=%u ses=%u lsm=ipe res=1",
> + from_kuid(&init_user_ns, audit_get_loginuid(current)),
> + audit_get_sessionid(current));
> +
> + audit_log_end(ab);
> +}
> diff --git a/security/ipe/audit.h b/security/ipe/audit.h
> new file mode 100644
> index 000000000000..2e9b99737f97
> --- /dev/null
> +++ b/security/ipe/audit.h
> @@ -0,0 +1,18 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (C) Microsoft Corporation. All rights reserved.
> + */
> +
> +#ifndef IPE_AUDIT_H
> +#define IPE_AUDIT_H
> +
> +#include "policy.h"
> +
> +void ipe_audit_match(const struct ipe_eval_ctx *const ctx,
> + enum ipe_match match_type,
> + enum ipe_action_type act, const struct ipe_rule *const r);
> +void ipe_audit_policy_load(const struct ipe_policy *const p);
> +void ipe_audit_policy_activation(const struct ipe_policy *const op,
> + const struct ipe_policy *const np);
> +
> +#endif /* IPE_AUDIT_H */
> diff --git a/security/ipe/eval.c b/security/ipe/eval.c
> index 48b5104a3463..d713808cad9c 100644
> --- a/security/ipe/eval.c
> +++ b/security/ipe/eval.c
> @@ -7,6 +7,7 @@
> #include "eval.h"
> #include "hooks.h"
> #include "policy.h"
> +#include "audit.h"
>
> #include <linux/fs.h>
> #include <linux/types.h>
> @@ -15,8 +16,10 @@
> #include <linux/sched.h>
> #include <linux/rcupdate.h>
> #include <linux/spinlock.h>
> +#include <linux/moduleparam.h>
>
> struct ipe_policy __rcu *ipe_active_policy;
> +bool success_audit;
>
> static struct super_block *pinned_sb;
> static DEFINE_SPINLOCK(pin_lock);
> @@ -117,6 +120,7 @@ int ipe_evaluate_event(const struct ipe_eval_ctx *const ctx)
> int rc = 0;
> bool match = false;
> enum ipe_action_type action;
> + enum ipe_match match_type;
> struct ipe_policy *pol = NULL;
> const struct ipe_rule *rule = NULL;
> const struct ipe_op_table *rules = NULL;
> @@ -131,6 +135,7 @@ int ipe_evaluate_event(const struct ipe_eval_ctx *const ctx)
>
> if (ctx->op == ipe_op_max) {
> action = pol->parsed->global_default_action;
> + match_type = ipe_match_global;
> goto eval;
> }
>
> @@ -146,14 +151,20 @@ int ipe_evaluate_event(const struct ipe_eval_ctx *const ctx)
> break;
> }
>
> - if (match)
> + if (match) {
> action = rule->action;
> - else if (rules->default_action != ipe_action_max)
> + match_type = ipe_match_rule;
> + } else if (rules->default_action != ipe_action_max) {
> action = rules->default_action;
> - else
> + match_type = ipe_match_table;
> + } else {
> action = pol->parsed->global_default_action;
> + match_type = ipe_match_global;
> + }
>
> eval:
> + ipe_audit_match(ctx, match_type, action, rule);
> +
> if (action == ipe_action_deny)
> rc = -EACCES;
>
> @@ -178,3 +189,12 @@ void ipe_invalidate_pinned_sb(const struct super_block *mnt_sb)
>
> spin_unlock(&pin_lock);
> }
> +
> +/* Set the right module name */
> +#ifdef KBUILD_MODNAME
> +#undef KBUILD_MODNAME
> +#define KBUILD_MODNAME "ipe"
> +#endif
> +
> +module_param(success_audit, bool, 0400);
> +MODULE_PARM_DESC(success_audit, "Start IPE with success auditing enabled");
> diff --git a/security/ipe/eval.h b/security/ipe/eval.h
> index 887797438b9b..b83730d0b5ae 100644
> --- a/security/ipe/eval.h
> +++ b/security/ipe/eval.h
> @@ -13,6 +13,7 @@
> #include "policy.h"
>
> extern struct ipe_policy __rcu *ipe_active_policy;
> +extern bool success_audit;
>
> struct ipe_eval_ctx {
> enum ipe_op_type op;
> @@ -21,6 +22,13 @@ struct ipe_eval_ctx {
> bool from_init_sb;
> };
>
> +enum ipe_match {
> + ipe_match_rule = 0,
> + ipe_match_table,
> + ipe_match_global,
> + ipe_match_max
> +};
> +
> void build_eval_ctx(struct ipe_eval_ctx *ctx, const struct file *file, enum ipe_op_type op);
> int ipe_evaluate_event(const struct ipe_eval_ctx *const ctx);
> void ipe_invalidate_pinned_sb(const struct super_block *mnt_sb);
> diff --git a/security/ipe/fs.c b/security/ipe/fs.c
> index 9f6a4867bec2..c99616f36f32 100644
> --- a/security/ipe/fs.c
> +++ b/security/ipe/fs.c
> @@ -4,7 +4,9 @@
> */
> #include "ipe.h"
> #include "fs.h"
> +#include "eval.h"
> #include "policy.h"
> +#include "audit.h"
>
> #include <linux/dcache.h>
> #include <linux/security.h>
> @@ -12,6 +14,57 @@
> static struct dentry *np __ro_after_init;
> static struct dentry *root __ro_after_init;
> struct dentry *policy_root __ro_after_init;
> +static struct dentry *audit_node __ro_after_init;
> +
> +/**
> + * setaudit - Write handler for the securityfs node, "ipe/success_audit"
> + * @f: Supplies a file structure representing the securityfs node.
> + * @data: Supplies a buffer passed to the write syscall.
> + * @len: Supplies the length of @data.
> + * @offset: unused.
> + *
> + * Return:
> + * * >0 - Success, Length of buffer written
> + * * <0 - Error
> + */
> +static ssize_t setaudit(struct file *f, const char __user *data,
> + size_t len, loff_t *offset)
> +{
> + int rc = 0;
> + bool value;
> +
> + if (!file_ns_capable(f, &init_user_ns, CAP_MAC_ADMIN))
> + return -EPERM;
> +
> + rc = kstrtobool_from_user(data, len, &value);
> + if (rc)
> + return rc;
> +
> + WRITE_ONCE(success_audit, value);
> +
> + return len;
> +}
> +
> +/**
> + * getaudit - Read handler for the securityfs node, "ipe/success_audit"
> + * @f: Supplies a file structure representing the securityfs node.
> + * @data: Supplies a buffer passed to the read syscall
> + * @len: Supplies the length of @data
> + * @offset: unused.
> + *
> + * Return:
> + * * >0 - Success, Length of buffer written
> + * * <0 - Error
> + */
> +static ssize_t getaudit(struct file *f, char __user *data,
> + size_t len, loff_t *offset)
> +{
> + const char *result;
> +
> + result = ((READ_ONCE(success_audit)) ? "1" : "0");
> +
> + return simple_read_from_buffer(data, len, offset, result, 1);
> +}
>
> /**
> * new_policy - Write handler for the securityfs node, "ipe/new_policy".
> @@ -50,6 +103,8 @@ static ssize_t new_policy(struct file *f, const char __user *data,
> if (rc)
> goto err;
>
> + ipe_audit_policy_load(p);
> +
> err:
> return (rc < 0) ? rc : len;
> }
> @@ -58,6 +113,11 @@ static const struct file_operations np_fops = {
> .write = new_policy,
> };
>
> +static const struct file_operations audit_fops = {
> + .write = setaudit,
> + .read = getaudit,
> +};
> +
> /**
> * ipe_init_securityfs - Initialize IPE's securityfs tree at fsinit.
> *
> @@ -84,6 +144,13 @@ static int __init ipe_init_securityfs(void)
> goto err;
> }
>
> + audit_node = securityfs_create_file("success_audit", 0600, root,
> + NULL, &audit_fops);
> + if (IS_ERR(audit_node)) {
> + rc = PTR_ERR(audit_node);
> + goto err;
> + }
> +
> policy_root = securityfs_create_dir("policies", root);
> if (IS_ERR(policy_root)) {
> rc = PTR_ERR(policy_root);
> @@ -94,6 +161,7 @@ static int __init ipe_init_securityfs(void)
> err:
> securityfs_remove(np);
> securityfs_remove(root);
> + securityfs_remove(audit_node);
> securityfs_remove(policy_root);
> return rc;
> }
> diff --git a/security/ipe/policy.c b/security/ipe/policy.c
> index a5e9c6e5691b..703b3fd9cf4c 100644
> --- a/security/ipe/policy.c
> +++ b/security/ipe/policy.c
> @@ -9,6 +9,7 @@
> #include "policy.h"
> #include "policy_parser.h"
> #include "digest.h"
> +#include "audit.h"
>
> #include <linux/verification.h>
>
> @@ -124,6 +125,9 @@ struct ipe_policy *ipe_update_policy(struct ipe_policy __rcu **addr,
> swap(new->policyfs, old->policyfs);
> ipe_free_policy(old);
>
> + if (!rc)
> + ipe_audit_policy_load(new);
> +
> goto out;
> err:
> ipe_free_policy(new);
> @@ -230,6 +234,7 @@ int ipe_set_active_pol(const struct ipe_policy *p)
> spin_unlock(&ipe_policy_lock);
> synchronize_rcu();
>
> + ipe_audit_policy_activation(ap, p);
> out:
> return rc;
> }