* Re: [PATCH v20 03/23] LSM: Use lsmblob in security_audit_rule_match
From: Paul Moore @ 2020-09-04 18:53 UTC (permalink / raw)
To: Casey Schaufler
Cc: casey.schaufler, James Morris, linux-security-module, selinux,
linux-audit, keescook, john.johansen, penguin-kernel,
Stephen Smalley
In-Reply-To: <20200826145247.10029-4-casey@schaufler-ca.com>
On Wed, Aug 26, 2020 at 11:04 AM Casey Schaufler <casey@schaufler-ca.com> wrote:
>
> Change the secid parameter of security_audit_rule_match
> to a lsmblob structure pointer. Pass the entry from the
> lsmblob structure for the approprite slot to the LSM hook.
>
> Change the users of security_audit_rule_match to use the
> lsmblob instead of a u32. The scaffolding function lsmblob_init()
> fills the blob with the value of the old secid, ensuring that
> it is available to the appropriate module hook. The sources of
> the secid, security_task_getsecid() and security_inode_getsecid(),
> will be converted to use the blob structure later in the series.
> At the point the use of lsmblob_init() is dropped.
>
> Reviewed-by: Kees Cook <keescook@chromium.org>
> Reviewed-by: John Johansen <john.johansen@canonical.com>
> Acked-by: Stephen Smalley <sds@tycho.nsa.gov>
> Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
> ---
> include/linux/security.h | 7 ++++---
> kernel/auditfilter.c | 6 ++++--
> kernel/auditsc.c | 14 ++++++++++----
> security/integrity/ima/ima.h | 4 ++--
> security/integrity/ima/ima_policy.c | 7 +++++--
> security/security.c | 10 ++++++++--
> 6 files changed, 33 insertions(+), 15 deletions(-)
Acked-by: Paul Moore <paul@paul-moore.com>
--
paul moore
www.paul-moore.com
^ permalink raw reply
* [RFC PATCH] sched: only issue an audit on privileged operation
From: Christian Göttsche @ 2020-09-04 16:00 UTC (permalink / raw)
To: linux-kernel
Cc: selinux, linux-security-module, Ingo Molnar, Peter Zijlstra,
Juri Lelli, Vincent Guittot, Dietmar Eggemann, Steven Rostedt,
Ben Segall, Mel Gorman
sched_setattr(2) does via kernel/sched/core.c:__sched_setscheduler()
issue a CAP_SYS_NICE audit event unconditionally, even when the requested
operation does not require that capability / is un-privileged.
Perform privilged/unprivileged catigorization first and perform a
capable test only if needed.
Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
---
kernel/sched/core.c | 65 ++++++++++++++++++++++++++++++++-------------
1 file changed, 47 insertions(+), 18 deletions(-)
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 8471a0f7eb32..954f968d2466 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -5249,13 +5249,19 @@ static int __sched_setscheduler(struct task_struct *p,
return -EINVAL;
/*
- * Allow unprivileged RT tasks to decrease priority:
+ * Allow unprivileged RT tasks to decrease priority.
+ * Only issue a capable test if needed to avoid audit
+ * event on non-privileged operations:
*/
- if (user && !capable(CAP_SYS_NICE)) {
+ if (user) {
if (fair_policy(policy)) {
if (attr->sched_nice < task_nice(p) &&
- !can_nice(p, attr->sched_nice))
- return -EPERM;
+ !can_nice(p, attr->sched_nice)) {
+ if (capable(CAP_SYS_NICE))
+ goto sys_nice_capable;
+ else
+ return -EPERM;
+ }
}
if (rt_policy(policy)) {
@@ -5263,13 +5269,21 @@ static int __sched_setscheduler(struct task_struct *p,
task_rlimit(p, RLIMIT_RTPRIO);
/* Can't set/change the rt policy: */
- if (policy != p->policy && !rlim_rtprio)
- return -EPERM;
+ if (policy != p->policy && !rlim_rtprio) {
+ if (capable(CAP_SYS_NICE))
+ goto sys_nice_capable;
+ else
+ return -EPERM;
+ }
/* Can't increase priority: */
if (attr->sched_priority > p->rt_priority &&
- attr->sched_priority > rlim_rtprio)
- return -EPERM;
+ attr->sched_priority > rlim_rtprio) {
+ if (capable(CAP_SYS_NICE))
+ goto sys_nice_capable;
+ else
+ return -EPERM;
+ }
}
/*
@@ -5278,28 +5292,43 @@ static int __sched_setscheduler(struct task_struct *p,
* unprivileged DL tasks to increase their relative deadline
* or reduce their runtime (both ways reducing utilization)
*/
- if (dl_policy(policy))
- return -EPERM;
+ if (dl_policy(policy)) {
+ if (capable(CAP_SYS_NICE))
+ goto sys_nice_capable;
+ else
+ return -EPERM;
+ }
/*
* Treat SCHED_IDLE as nice 20. Only allow a switch to
* SCHED_NORMAL if the RLIMIT_NICE would normally permit it.
*/
if (task_has_idle_policy(p) && !idle_policy(policy)) {
- if (!can_nice(p, task_nice(p)))
- return -EPERM;
+ if (!can_nice(p, task_nice(p))) {
+ if (capable(CAP_SYS_NICE))
+ goto sys_nice_capable;
+ else
+ return -EPERM;
+ }
}
/* Can't change other user's priorities: */
- if (!check_same_owner(p))
- return -EPERM;
+ if (!check_same_owner(p)) {
+ if (capable(CAP_SYS_NICE))
+ goto sys_nice_capable;
+ else
+ return -EPERM;
+ }
/* Normal users shall not reset the sched_reset_on_fork flag: */
- if (p->sched_reset_on_fork && !reset_on_fork)
- return -EPERM;
- }
+ if (p->sched_reset_on_fork && !reset_on_fork) {
+ if (capable(CAP_SYS_NICE))
+ goto sys_nice_capable;
+ else
+ return -EPERM;
+ }
- if (user) {
+sys_nice_capable:
if (attr->sched_flags & SCHED_FLAG_SUGOV)
return -EINVAL;
--
2.28.0
^ permalink raw reply related
* Re: [RFC PATCH 00/30] ima: Introduce IMA namespace
From: Dr. Greg @ 2020-09-04 14:06 UTC (permalink / raw)
To: Mimi Zohar
Cc: Krzysztof Struczynski, James Bottomley,
linux-integrity@vger.kernel.org, linux-kernel@vger.kernel.org,
containers@lists.linux-foundation.org,
linux-security-module@vger.kernel.org, stefanb@linux.vnet.ibm.com,
sunyuqiong1988@gmail.com, mkayaalp@cs.binghamton.edu,
dmitry.kasatkin@gmail.com, serge@hallyn.com, jmorris@namei.org,
christian@brauner.io, Silviu Vlasceanu, Roberto Sassu, nick.dusek
In-Reply-To: <5331e60b5a1afb55e2bc778db1b95998466b687d.camel@linux.ibm.com>
On Wed, Sep 02, 2020 at 02:53:17PM -0400, Mimi Zohar wrote:
Good morning, I hope the week is ending well for everyone.
> On Fri, 2020-08-21 at 15:13 +0000, Krzysztof Struczynski wrote:
> > > From: James Bottomley [mailto:James.Bottomley@HansenPartnership.com]
> > > On Tue, 2020-08-18 at 17:20 +0200, krzysztof.struczynski@huawei.com
> > > wrote:
> > > > The measurement list remains global, with the assumption that there
> > > > is only one TPM in the system. Each IMA namespace has a unique ID,
> > > > that allows to track measurements per IMA namespace. Processes in one
> > > > namespace, have access only to the measurements from that namespace.
> > > > The exception is made for the initial IMA namespace, whose processes
> > > > have access to all entries.
> > >
> > > So I think this can work in the use case where the system owner is
> > > responsible for doing the logging and attestation and the tenants just
> > > trust the owner without requiring an attestation. However, in a multi-
> > > tenant system you need a way for the attestation to be per-container
> > > (because the combined list of who executed what would be a security
> > > leak between tenants). Since we can't virtualise the PCRs without
> > > introducing a vtpm this is going to require a vtpm infrastructure like
> > > that used for virtual machines and then we can do IMA logging per
> > > container.
> >
> > I agree and wonder if we should decouple the attestation trust model,
> > which depends on the specific use case (e.g. multi/single tenant,
> > public/private cloud), from the IMA logic of linking the measurements to
> > the container. Indeed, attestation from within the container might require
> > anchoring to a vTPM/vPCR and the current measurement tagging mechanism can
> > support several ways of anchoring them to a (virtual) root of trust.
> >
> > > I don't think the above has to be in your first patch set, we just have
> > > to have an idea of how it could be done to show that nothing in this
> > > patch set precludes a follow on from doing this.
> >
> > Given that virtualizing trust anchors seems like a separate problem in
> > which industry consensus is not easy to reach for all use cases, an
> > anchoring mechanism should probably be a separate IMA feature.
> Other trust anchors for "trusted keys" has been discussed, but I wasn't
> aware of any discussion about other trust anchors for the IMA
> measurement list. The IMA measurement list is very much tied to a TPM.
>
> Including container measurements in the host measurement list, will
> unnecessarily cause the host measurement list to grow. The decision of
> what should and shouldn't be included in the host measurement list
> shouldn't be defined by the container.
We have been shipping, and more importantly maintaining in the wild,
systems with a namespaced IMA implementation for 4+ years now. We
presented the foundations for all of this at the 2015 Linux Security
Summit in Seattle.
For the purposes of further conversation, I should clarify and
indicate that we have been shipping and maintaining what a namespaced
IMA implementation turns into when all of the engineering challenges
have been addressed with respect to workability issues, particularly
in regards to keeping the resultant system from being too fragile to
be effectively deployed and maintained.
If practical experience is worth anything, I don't believe that
namespacing the current IMA implementation is the optimum path
forward. With respect to developing operationally relevant trusted
platforms, the objective needs to be modeling the behavior of
namespaces spawned from a known root behavior.
The current IMA implementation provides a great deal of relevant
infrastructure, but as these conversations have suggested, namespacing
the current implementation is problematic given how entangled it has
become with existing kernel infrastructure. What is needed is
something far simpler that delegates, on the basis of a namespace,
security policy to something other then the kernel, consistent with
what we have learned about policy over the last 29+ years of Linux
development.
With respect to roots of trust, I don't think TPM's/fTPM's, virtual or
otherwise, are going to be the relevant technology moving forward,
although they will be part of the picture.
Mimi has another post down thread that I will provide some more direct
reflections on all of this for whatever value they may have.
> Mimi
Have a good day.
Dr. Greg
As always,
Dr. Greg Wettstein, Ph.D, Worker Autonomously self-defensive
Enjellic Systems Development, LLC IOT platforms and edge devices.
4206 N. 19th Ave.
Fargo, ND 58102
PH: 701-281-1686 EMAIL: dg@enjellic.com
------------------------------------------------------------------------------
"I had far rather walk, as I do, in daily terror of eternity, than feel
that this was only a children's game in which all of the contestants
would get equally worthless prizes in the end."
-- T. S. Elliot
^ permalink raw reply
* Re: [PATCH v20 05/12] LSM: Infrastructure management of the superblock
From: Stephen Smalley @ 2020-09-04 14:06 UTC (permalink / raw)
To: Mickaël Salaün
Cc: Stephen Smalley, Casey Schaufler, Kees Cook, John Johansen,
linux-kernel, Al Viro, Andy Lutomirski, Anton Ivanov,
Arnd Bergmann, James Morris, Jann Horn, Jeff Dike,
Jonathan Corbet, Michael Kerrisk, Richard Weinberger,
Serge E . Hallyn, Shuah Khan, Vincent Dagonneau, kernel-hardening,
linux-api, linux-arch, linux-doc, Linux FS Devel, linux-kselftest,
LSM List, X86 ML
In-Reply-To: <CAEjxPJ7POnxKy=5w-iQkKhjftxf2-=UuvA6D8EmhUPJyS1F6qg@mail.gmail.com>
On Thu, Aug 13, 2020 at 2:39 PM Stephen Smalley
<stephen.smalley.work@gmail.com> wrote:
>
> On Thu, Aug 13, 2020 at 10:17 AM Mickaël Salaün <mic@digikod.net> wrote:
> >
> >
> > On 12/08/2020 21:16, Stephen Smalley wrote:
> > > On 8/2/20 5:58 PM, Mickaël Salaün wrote:
> > >> From: Casey Schaufler <casey@schaufler-ca.com>
> > >>
> > >> Move management of the superblock->sb_security blob out
> > >> of the individual security modules and into the security
> > >> infrastructure. Instead of allocating the blobs from within
> > >> the modules the modules tell the infrastructure how much
> > >> space is required, and the space is allocated there.
> > >>
> > >> Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
> > >> Reviewed-by: Kees Cook <keescook@chromium.org>
> > >> Reviewed-by: John Johansen <john.johansen@canonical.com>
> > >> Reviewed-by: Stephen Smalley <sds@tycho.nsa.gov>
> > >> Reviewed-by: Mickaël Salaün <mic@digikod.net>
> > >> Link:
> > >> https://lore.kernel.org/r/20190829232935.7099-2-casey@schaufler-ca.com
> > >> ---
> > >>
> > >> Changes since v17:
> > >> * Rebase the original LSM stacking patch from v5.3 to v5.7: I fixed some
> > >> diff conflicts caused by code moves and function renames in
> > >> selinux/include/objsec.h and selinux/hooks.c . I checked that it
> > >> builds but I didn't test the changes for SELinux nor SMACK.
> > >
> > > You shouldn't retain Signed-off-by and Reviewed-by lines from an earlier
> > > patch if you made non-trivial changes to it (even more so if you didn't
> > > test them).
> >
> > I think I made trivial changes according to the original patch. But
> > without reply from other people with Signed-off-by or Reviewed-by
> > (Casey, Kees, John), I'll remove them. I guess you don't want your
> > Reviewed-by to be kept, so I'll remove it, except if you want to review
> > this patch (or the modified part).
>
> At the very least your Reviewed-by line is wrong - yours should be
> Signed-off-by because the patch went through you and you modified it.
> I'll try to take a look as time permits but FYI you should this
> address (already updated in MAINTAINERS) going forward.
I finally got around to reviewing your updated patch. You can drop
the old line and add:
Reviewed-by: Stephen Smalley <stephen.smalley.work@gmail.com>
^ permalink raw reply
* Re: [RFC PATCH] certs: Add EFI_CERT_X509_GUID support for dbx entries]
From: Jarkko Sakkinen @ 2020-09-04 12:59 UTC (permalink / raw)
To: Eric Snowberg
Cc: dhowells, dwmw2, jmorris, serge, zohar, erichte, nayna, mpe,
keyrings, linux-kernel, linux-security-module
In-Reply-To: <20200901165143.10295-1-eric.snowberg@oracle.com>
On Tue, Sep 01, 2020 at 12:51:43PM -0400, Eric Snowberg wrote:
> The Secure Boot Forbidden Signature Database, dbx, contains a list of now
> revoked signatures and keys previously approved to boot with UEFI Secure
> Boot enabled. The dbx is capable of containing any number of
> EFI_CERT_X509_SHA256_GUID, EFI_CERT_SHA256_GUID, and EFI_CERT_X509_GUID
> entries.
>
> Currently when EFI_CERT_X509_GUID are contained in the dbx, the entries are
> skipped.
>
> This change adds support for EFI_CERT_X509_GUID dbx entries. When a
> EFI_CERT_X509_GUID is found, it is added as an asymmetrical key to the
> .blacklist keyring. Anytime the .platform keyring is used, the keys in
> the .blacklist keyring are referenced, if a matching key is found, the
> key will be rejected.
>
> Signed-off-by: Eric Snowberg <eric.snowberg@oracle.com>
In the last paragraph, please use imperative form: "Add support for ...".
> ---
> certs/blacklist.c | 36 +++++++++++++++++++
> certs/system_keyring.c | 6 ++++
> include/keys/system_keyring.h | 11 ++++++
> .../platform_certs/keyring_handler.c | 11 ++++++
> 4 files changed, 64 insertions(+)
>
> diff --git a/certs/blacklist.c b/certs/blacklist.c
> index 6514f9ebc943..17ebf50cf0ae 100644
> --- a/certs/blacklist.c
> +++ b/certs/blacklist.c
> @@ -15,6 +15,7 @@
> #include <linux/err.h>
> #include <linux/seq_file.h>
> #include <keys/system_keyring.h>
> +#include <crypto/pkcs7.h>
> #include "blacklist.h"
>
> static struct key *blacklist_keyring;
> @@ -100,6 +101,41 @@ int mark_hash_blacklisted(const char *hash)
> return 0;
> }
>
> +int mark_key_revocationlisted(const char *data, size_t size)
> +{
> + key_ref_t key;
> +
> + key = key_create_or_update(make_key_ref(blacklist_keyring, true),
> + "asymmetric",
> + NULL,
> + data,
> + size,
> + ((KEY_POS_ALL & ~KEY_POS_SETATTR) |
> + KEY_USR_VIEW),
> + KEY_ALLOC_NOT_IN_QUOTA |
> + KEY_ALLOC_BUILT_IN);
> +
> + if (IS_ERR(key)) {
> + pr_err("Problem with revocation key (%ld)\n", PTR_ERR(key));
> + return PTR_ERR(key);
> + }
> +
> + return 0;
> +}
> +
> +int is_key_revocationlisted(struct pkcs7_message *pkcs7)
> +{
> + int ret;
> +
> + ret = pkcs7_validate_trust(pkcs7, blacklist_keyring);
> +
> + if (ret == 0)
> + return -EKEYREJECTED;
> +
> + return -ENOKEY;
> +}
> +EXPORT_SYMBOL_GPL(is_key_revocationlisted);
> +
> /**
> * is_hash_blacklisted - Determine if a hash is blacklisted
> * @hash: The hash to be checked as a binary blob
> diff --git a/certs/system_keyring.c b/certs/system_keyring.c
> index 798291177186..f8ea96219155 100644
> --- a/certs/system_keyring.c
> +++ b/certs/system_keyring.c
> @@ -241,6 +241,12 @@ int verify_pkcs7_message_sig(const void *data, size_t len,
> pr_devel("PKCS#7 platform keyring is not available\n");
> goto error;
> }
> +
> + ret = is_key_revocationlisted(pkcs7);
> + if (ret != -ENOKEY) {
> + pr_devel("PKCS#7 platform key revocationlisted\n");
> + goto error;
> + }
> }
> ret = pkcs7_validate_trust(pkcs7, trusted_keys);
> if (ret < 0) {
> diff --git a/include/keys/system_keyring.h b/include/keys/system_keyring.h
> index fb8b07daa9d1..b6991cfe1b6d 100644
> --- a/include/keys/system_keyring.h
> +++ b/include/keys/system_keyring.h
> @@ -31,11 +31,14 @@ extern int restrict_link_by_builtin_and_secondary_trusted(
> #define restrict_link_by_builtin_and_secondary_trusted restrict_link_by_builtin_trusted
> #endif
>
> +extern struct pkcs7_message *pkcs7;
> #ifdef CONFIG_SYSTEM_BLACKLIST_KEYRING
> extern int mark_hash_blacklisted(const char *hash);
> +extern int mark_key_revocationlisted(const char *data, size_t size);
> extern int is_hash_blacklisted(const u8 *hash, size_t hash_len,
> const char *type);
> extern int is_binary_blacklisted(const u8 *hash, size_t hash_len);
> +extern int is_key_revocationlisted(struct pkcs7_message *pkcs7);
> #else
> static inline int is_hash_blacklisted(const u8 *hash, size_t hash_len,
> const char *type)
> @@ -47,6 +50,14 @@ static inline int is_binary_blacklisted(const u8 *hash, size_t hash_len)
> {
> return 0;
> }
> +static inline int mark_key_revocationlisted(const char *data, size_t size)
> +{
> + return 0;
> +}
> +static inline int is_key_revocationlisted(struct pkcs7_message *pkcs7)
> +{
> + return -ENOKEY;
> +}
> #endif
>
> #ifdef CONFIG_IMA_BLACKLIST_KEYRING
> diff --git a/security/integrity/platform_certs/keyring_handler.c b/security/integrity/platform_certs/keyring_handler.c
> index c5ba695c10e3..cc5a43804bc4 100644
> --- a/security/integrity/platform_certs/keyring_handler.c
> +++ b/security/integrity/platform_certs/keyring_handler.c
> @@ -55,6 +55,15 @@ static __init void uefi_blacklist_binary(const char *source,
> uefi_blacklist_hash(source, data, len, "bin:", 4);
> }
>
> +/*
> + * Revocationlist the X509 cert
> + */
> +static __init void uefi_revocationlist_x509(const char *source,
> + const void *data, size_t len)
> +{
> + mark_key_revocationlisted(data, len);
> +}
> +
> /*
> * Return the appropriate handler for particular signature list types found in
> * the UEFI db and MokListRT tables.
> @@ -76,5 +85,7 @@ __init efi_element_handler_t get_handler_for_dbx(const efi_guid_t *sig_type)
> return uefi_blacklist_x509_tbs;
> if (efi_guidcmp(*sig_type, efi_cert_sha256_guid) == 0)
> return uefi_blacklist_binary;
> + if (efi_guidcmp(*sig_type, efi_cert_x509_guid) == 0)
> + return uefi_revocationlist_x509;
> return 0;
> }
> --
> 2.18.1
>
I did not find anything wrong with the code change.
/Jarkko
^ permalink raw reply
* Re: [PATCH v33 11/21] x86/sgx: Linux Enclave Driver
From: Jarkko Sakkinen @ 2020-09-04 12:01 UTC (permalink / raw)
To: Haitao Huang
Cc: Sean Christopherson, x86, linux-sgx, linux-kernel,
linux-security-module, Jethro Beekman, Chunyang Hui, Jordan Hand,
Nathaniel McCallum, Seth Moore, Suresh Siddha, akpm,
andriy.shevchenko, asapek, bp, cedric.xing, chenalexchen,
conradparker, cyhanish, dave.hansen, josh, kai.huang, kai.svahn,
kmoy, ludloff, luto, nhorman, puiterwijk, rientjes, tglx,
yaozhangx
In-Reply-To: <op.0qaqw6rvwjvjmi@hhuan26-mobl1.amr.corp.intel.com>
On Tue, Sep 01, 2020 at 10:06:32PM -0500, Haitao Huang wrote:
> On Fri, 03 Jul 2020 22:31:10 -0500, Jarkko Sakkinen
> <jarkko.sakkinen@linux.intel.com> wrote:
>
> > On Wed, Jul 01, 2020 at 08:59:02PM -0700, Sean Christopherson wrote:
> > > On Thu, Jun 18, 2020 at 01:08:33AM +0300, Jarkko Sakkinen wrote:
> > > > +static int sgx_validate_secs(const struct sgx_secs *secs,
> > > > + unsigned long ssaframesize)
> > > > +{
> > > > + if (secs->size < (2 * PAGE_SIZE) || !is_power_of_2(secs->size))
> > > > + return -EINVAL;
> > > > +
> > > > + if (secs->base & (secs->size - 1))
> > > > + return -EINVAL;
> > > > +
> > > > + if (secs->miscselect & sgx_misc_reserved_mask ||
> > > > + secs->attributes & sgx_attributes_reserved_mask ||
> > > > + secs->xfrm & sgx_xfrm_reserved_mask)
> > > > + return -EINVAL;
> > > > +
> > > > + if (secs->attributes & SGX_ATTR_MODE64BIT) {
> > > > + if (secs->size > sgx_encl_size_max_64)
> > > > + return -EINVAL;
> > > > + } else if (secs->size > sgx_encl_size_max_32)
> > > > + return -EINVAL;
> > >
> > > These should be >=, not >, the SDM uses one of those fancy ≥ ligatures.
> > >
> > > Internal versions use more obvious pseudocode, e.g.:
> > >
> > > if ((DS:TMP_SECS.ATTRIBUTES.MODE64BIT = 1) AND
> > > (DS:TMP_SECS.SIZE AND (~((1 << CPUID.18.0:EDX[15:8]) – 1)))
> > > {
> > > #GP(0);
> >
> > Updated as:
> >
> > static int sgx_validate_secs(const struct sgx_secs *secs)
> > {
> > u64 max_size = (secs->attributes & SGX_ATTR_MODE64BIT) ?
> > sgx_encl_size_max_64 : sgx_encl_size_max_32;
> >
> > if (secs->size < (2 * PAGE_SIZE) || !is_power_of_2(secs->size))
> > return -EINVAL;
> >
> > if (secs->base & (secs->size - 1))
> > return -EINVAL;
> >
> > if (secs->miscselect & sgx_misc_reserved_mask ||
> > secs->attributes & sgx_attributes_reserved_mask ||
> > secs->xfrm & sgx_xfrm_reserved_mask)
> > return -EINVAL;
> >
> > if (secs->size >= max_size)
> > return -EINVAL;
> >
>
> This should be > not >=. Issue raised and fixed by Fábio Silva for ported
> patches for OOT SGX support:
> https://github.com/intel/SGXDataCenterAttestationPrimitives/pull/123
>
> I tested and verified with Intel arch, the comparison indeed should be >.
>
> Thanks
> Haitao
Thans a lot!
I added this changelog entry to the v37 log:
* Fixed off-by-one error in a size calculation:
https://github.com/intel/SGXDataCenterAttestationPrimitives/commit/e44cc238becf584cc079aef40b557c6af9a03f38
Given the Boris' earlier feedback I xref every changelog
entry in v37 changelog. Then it is also less time consuming
to spot if something is missing.
/Jarkko
^ permalink raw reply
* [PATCH v2 10/12] ima: Allow imasig requirement to be satisfied by EVM portable signatures
From: Roberto Sassu @ 2020-09-04 9:26 UTC (permalink / raw)
To: zohar, mjg59
Cc: linux-integrity, linux-security-module, linux-kernel,
silviu.vlasceanu, Roberto Sassu
In-Reply-To: <20200904092339.19598-1-roberto.sassu@huawei.com>
System administrators can require that all accessed files have a signature
by specifying appraise_type=imasig in a policy rule.
Currently, IMA signatures satisfy this requirement. Appended signatures may
also satisfy this requirement, but are not applicable as IMA signatures.
IMA/appended signatures ensure data source authentication for file content
and prevent any change. EVM signatures instead ensure data source
authentication for file metadata. Given that the digest or signature of the
file content must be included in the metadata, EVM signatures provide the
same file data guarantees of IMA signatures, as well as providing file
metadata guarantees.
This patch lets systems protected with EVM signatures pass appraisal
verification if the appraise_type=imasig requirement is specified in the
policy. This facilitates deployment in the scenarios where only EVM
signatures are available.
The patch makes the following changes:
file xattr types:
security.ima: IMA_XATTR_DIGEST/IMA_XATTR_DIGEST_NG
security.evm: EVM_XATTR_PORTABLE_DIGSIG
execve(), mmap(), open() behavior (with appraise_type=imasig):
before: denied (file without IMA signature, imasig requirement not met)
after: allowed (file with EVM portable signature, imasig requirement met)
open(O_WRONLY) behavior (without appraise_type=imasig):
before: allowed (file without IMA signature, not immutable)
after: denied (file with EVM portable signature, immutable)
In addition, similarly to IMA signatures, this patch temporarily allows
new files without or with incomplete metadata to be opened so that content
can be written.
Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
---
security/integrity/ima/ima_appraise.c | 22 +++++++++++++++-------
1 file changed, 15 insertions(+), 7 deletions(-)
diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c
index 4d682bc3a77f..95c7a1fc0d01 100644
--- a/security/integrity/ima/ima_appraise.c
+++ b/security/integrity/ima/ima_appraise.c
@@ -225,12 +225,16 @@ static int xattr_verify(enum ima_hooks func, struct integrity_iint_cache *iint,
hash_start = 1;
fallthrough;
case IMA_XATTR_DIGEST:
- if (iint->flags & IMA_DIGSIG_REQUIRED) {
- *cause = "IMA-signature-required";
- *status = INTEGRITY_FAIL;
- break;
+ if (*status != INTEGRITY_PASS_IMMUTABLE) {
+ if (iint->flags & IMA_DIGSIG_REQUIRED) {
+ *cause = "IMA-signature-required";
+ *status = INTEGRITY_FAIL;
+ break;
+ }
+ clear_bit(IMA_DIGSIG, &iint->atomic_flags);
+ } else {
+ set_bit(IMA_DIGSIG, &iint->atomic_flags);
}
- clear_bit(IMA_DIGSIG, &iint->atomic_flags);
if (xattr_len - sizeof(xattr_value->type) - hash_start >=
iint->ima_hash->length)
/*
@@ -400,6 +404,7 @@ int ima_appraise_measurement(enum ima_hooks func,
cause = "missing-HMAC";
goto out;
case INTEGRITY_FAIL_IMMUTABLE:
+ set_bit(IMA_DIGSIG, &iint->atomic_flags);
fallthrough;
case INTEGRITY_FAIL: /* Invalid HMAC/signature. */
cause = "invalid-HMAC";
@@ -444,9 +449,12 @@ int ima_appraise_measurement(enum ima_hooks func,
status = INTEGRITY_PASS;
}
- /* Permit new files with file signatures, but without data. */
+ /*
+ * Permit new files with file/EVM portable signatures, but
+ * without data.
+ */
if (inode->i_size == 0 && iint->flags & IMA_NEW_FILE &&
- xattr_value && xattr_value->type == EVM_IMA_XATTR_DIGSIG) {
+ test_bit(IMA_DIGSIG, &iint->atomic_flags)) {
status = INTEGRITY_PASS;
}
--
2.27.GIT
^ permalink raw reply related
* [PATCH v2 12/12] ima: Don't remove security.ima if file must not be appraised
From: Roberto Sassu @ 2020-09-04 9:26 UTC (permalink / raw)
To: zohar, mjg59
Cc: linux-integrity, linux-security-module, linux-kernel,
silviu.vlasceanu, Roberto Sassu
In-Reply-To: <20200904092339.19598-1-roberto.sassu@huawei.com>
Files might come from a remote source and might have xattrs, including
security.ima. It should not be IMA task to decide whether security.ima
should be kept or not. This patch removes the removexattr() system
call in ima_inode_post_setattr().
Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
---
security/integrity/ima/ima_appraise.c | 2 --
1 file changed, 2 deletions(-)
diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c
index 95c7a1fc0d01..2dbf0417f9e6 100644
--- a/security/integrity/ima/ima_appraise.c
+++ b/security/integrity/ima/ima_appraise.c
@@ -513,8 +513,6 @@ void ima_inode_post_setattr(struct dentry *dentry)
return;
action = ima_must_appraise(inode, MAY_ACCESS, POST_SETATTR);
- if (!action)
- __vfs_removexattr(dentry, XATTR_NAME_IMA);
iint = integrity_iint_find(inode);
if (iint) {
set_bit(IMA_CHANGE_ATTR, &iint->atomic_flags);
--
2.27.GIT
^ permalink raw reply related
* [PATCH v2 11/12] ima: Introduce template field evmsig and write to field sig as fallback
From: Roberto Sassu @ 2020-09-04 9:26 UTC (permalink / raw)
To: zohar, mjg59
Cc: linux-integrity, linux-security-module, linux-kernel,
silviu.vlasceanu, Roberto Sassu
In-Reply-To: <20200904092339.19598-1-roberto.sassu@huawei.com>
With the patch to accept EVM portable signatures when the
appraise_type=imasig requirement is specified in the policy, appraisal can
be successfully done even if the file does not have an IMA signature.
However, remote attestation would not see that a different signature type
was used, as only IMA signatures can be included in the measurement list.
This patch solves the issue by introducing the new template field 'evmsig'
to show EVM portable signatures and by including its value in the existing
field 'sig' if the IMA signature is not found.
Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
Suggested-by: Mimi Zohar <zohar@linux.ibm.com>
---
Documentation/security/IMA-templates.rst | 4 ++-
security/integrity/ima/ima_template.c | 2 ++
security/integrity/ima/ima_template_lib.c | 39 ++++++++++++++++++++++-
security/integrity/ima/ima_template_lib.h | 2 ++
4 files changed, 45 insertions(+), 2 deletions(-)
diff --git a/Documentation/security/IMA-templates.rst b/Documentation/security/IMA-templates.rst
index c5a8432972ef..9f3e86ab028a 100644
--- a/Documentation/security/IMA-templates.rst
+++ b/Documentation/security/IMA-templates.rst
@@ -70,9 +70,11 @@ descriptors by adding their identifier to the format string
prefix is shown only if the hash algorithm is not SHA1 or MD5);
- 'd-modsig': the digest of the event without the appended modsig;
- 'n-ng': the name of the event, without size limitations;
- - 'sig': the file signature;
+ - 'sig': the file signature, or the EVM portable signature if the file
+ signature is not found;
- 'modsig' the appended file signature;
- 'buf': the buffer data that was used to generate the hash without size limitations;
+ - 'evmsig': the EVM portable signature;
Below, there is the list of defined template descriptors:
diff --git a/security/integrity/ima/ima_template.c b/security/integrity/ima/ima_template.c
index 1e89e2d3851f..02afc4116606 100644
--- a/security/integrity/ima/ima_template.c
+++ b/security/integrity/ima/ima_template.c
@@ -45,6 +45,8 @@ static const struct ima_template_field supported_fields[] = {
.field_show = ima_show_template_digest_ng},
{.field_id = "modsig", .field_init = ima_eventmodsig_init,
.field_show = ima_show_template_sig},
+ {.field_id = "evmsig", .field_init = ima_eventevmsig_init,
+ .field_show = ima_show_template_sig},
};
/*
diff --git a/security/integrity/ima/ima_template_lib.c b/security/integrity/ima/ima_template_lib.c
index c022ee9e2a4e..2c596c2a89cc 100644
--- a/security/integrity/ima/ima_template_lib.c
+++ b/security/integrity/ima/ima_template_lib.c
@@ -10,6 +10,7 @@
*/
#include "ima_template_lib.h"
+#include <linux/xattr.h>
static bool ima_template_hash_algo_allowed(u8 algo)
{
@@ -438,7 +439,7 @@ int ima_eventsig_init(struct ima_event_data *event_data,
struct evm_ima_xattr_data *xattr_value = event_data->xattr_value;
if ((!xattr_value) || (xattr_value->type != EVM_IMA_XATTR_DIGSIG))
- return 0;
+ return ima_eventevmsig_init(event_data, field_data);
return ima_write_template_field_data(xattr_value, event_data->xattr_len,
DATA_FMT_HEX, field_data);
@@ -484,3 +485,39 @@ int ima_eventmodsig_init(struct ima_event_data *event_data,
return ima_write_template_field_data(data, data_len, DATA_FMT_HEX,
field_data);
}
+
+/*
+ * ima_eventevmsig_init - include the EVM portable signature as part of the
+ * template data
+ */
+int ima_eventevmsig_init(struct ima_event_data *event_data,
+ struct ima_field_data *field_data)
+{
+ struct evm_ima_xattr_data *xattr_data = NULL;
+ int rc = 0;
+
+ if (!event_data->file)
+ return 0;
+
+ if (!(file_inode(event_data->file)->i_opflags & IOP_XATTR))
+ return 0;
+
+ rc = vfs_getxattr_alloc(file_dentry(event_data->file), XATTR_NAME_EVM,
+ (char **)&xattr_data, 0, GFP_NOFS);
+ if (rc <= 0) {
+ if (!rc || rc == -ENODATA)
+ return 0;
+
+ return rc;
+ }
+
+ if (xattr_data->type != EVM_XATTR_PORTABLE_DIGSIG) {
+ kfree(xattr_data);
+ return 0;
+ }
+
+ rc = ima_write_template_field_data((char *)xattr_data, rc, DATA_FMT_HEX,
+ field_data);
+ kfree(xattr_data);
+ return rc;
+}
diff --git a/security/integrity/ima/ima_template_lib.h b/security/integrity/ima/ima_template_lib.h
index 6b3b880637a0..f4b2a2056d1d 100644
--- a/security/integrity/ima/ima_template_lib.h
+++ b/security/integrity/ima/ima_template_lib.h
@@ -46,4 +46,6 @@ int ima_eventbuf_init(struct ima_event_data *event_data,
struct ima_field_data *field_data);
int ima_eventmodsig_init(struct ima_event_data *event_data,
struct ima_field_data *field_data);
+int ima_eventevmsig_init(struct ima_event_data *event_data,
+ struct ima_field_data *field_data);
#endif /* __LINUX_IMA_TEMPLATE_LIB_H */
--
2.27.GIT
^ permalink raw reply related
* [PATCH v2 05/12] evm: Load EVM key in ima_load_x509() to avoid appraisal
From: Roberto Sassu @ 2020-09-04 9:26 UTC (permalink / raw)
To: zohar, mjg59
Cc: linux-integrity, linux-security-module, linux-kernel,
silviu.vlasceanu, Roberto Sassu
In-Reply-To: <20200904092339.19598-1-roberto.sassu@huawei.com>
Public keys do not need to be appraised by IMA as the restriction on the
IMA/EVM keyrings ensures that a key is loaded only if it is signed with a
key in the primary or secondary keyring.
However, when evm_load_x509() is loaded, appraisal is already enabled and
a valid IMA signature must be added to the EVM key to pass verification.
Since the restriction is applied on both IMA and EVM keyrings, it is safe
to disable appraisal also when the EVM key is loaded. This patch calls
evm_load_x509() inside ima_load_x509() if CONFIG_IMA_LOAD_X509 is defined.
Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
---
security/integrity/iint.c | 2 ++
security/integrity/ima/ima_init.c | 4 ++++
2 files changed, 6 insertions(+)
diff --git a/security/integrity/iint.c b/security/integrity/iint.c
index 1d20003243c3..7d08c31c612f 100644
--- a/security/integrity/iint.c
+++ b/security/integrity/iint.c
@@ -200,7 +200,9 @@ int integrity_kernel_read(struct file *file, loff_t offset,
void __init integrity_load_keys(void)
{
ima_load_x509();
+#ifndef CONFIG_IMA_LOAD_X509
evm_load_x509();
+#endif
}
static int __init integrity_fs_init(void)
diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c
index 4902fe7bd570..9d29a1680da8 100644
--- a/security/integrity/ima/ima_init.c
+++ b/security/integrity/ima/ima_init.c
@@ -106,6 +106,10 @@ void __init ima_load_x509(void)
ima_policy_flag &= ~unset_flags;
integrity_load_x509(INTEGRITY_KEYRING_IMA, CONFIG_IMA_X509_PATH);
+
+ /* load also EVM key to avoid appraisal */
+ evm_load_x509();
+
ima_policy_flag |= unset_flags;
}
#endif
--
2.27.GIT
^ permalink raw reply related
* [PATCH v2 08/12] evm: Allow xattr/attr operations for portable signatures if check fails
From: Roberto Sassu @ 2020-09-04 9:26 UTC (permalink / raw)
To: zohar, mjg59
Cc: linux-integrity, linux-security-module, linux-kernel,
silviu.vlasceanu, Roberto Sassu
In-Reply-To: <20200904092339.19598-1-roberto.sassu@huawei.com>
If files with portable signatures are copied from one location to another
or are extracted from an archive, verification can temporarily fail until
all xattrs/attrs are set in the destination. Only portable signatures may
be moved or copied from one file to another, as they don't depend on
system-specific information such as the inode generation. Instead portable
signatures must include security.ima.
Unlike other security.evm types, EVM portable signatures are also
immutable. Thus, it wouldn't be a problem to allow xattr/attr operations
when verification fails, as portable signatures will never be replaced with
an HMAC on possibly corrupted xattrs/attrs.
This patch first introduces a new integrity status called
INTEGRITY_FAIL_IMMUTABLE, that allows callers of
evm_verify_current_integrity() to detect that a portable signature didn't
pass verification and then adds an exception in evm_protect_xattr() and
evm_inode_setattr() for this status and returns 0 instead of -EPERM.
Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
---
include/linux/integrity.h | 1 +
security/integrity/evm/evm_main.c | 31 +++++++++++++++++++++------
security/integrity/ima/ima_appraise.c | 2 ++
3 files changed, 27 insertions(+), 7 deletions(-)
diff --git a/include/linux/integrity.h b/include/linux/integrity.h
index 2271939c5c31..2ea0f2f65ab6 100644
--- a/include/linux/integrity.h
+++ b/include/linux/integrity.h
@@ -13,6 +13,7 @@ enum integrity_status {
INTEGRITY_PASS = 0,
INTEGRITY_PASS_IMMUTABLE,
INTEGRITY_FAIL,
+ INTEGRITY_FAIL_IMMUTABLE,
INTEGRITY_NOLABEL,
INTEGRITY_NOXATTRS,
INTEGRITY_UNKNOWN,
diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c
index 05be1ad3e6f3..a5dab1ac9374 100644
--- a/security/integrity/evm/evm_main.c
+++ b/security/integrity/evm/evm_main.c
@@ -27,7 +27,8 @@
int evm_initialized;
static const char * const integrity_status_msg[] = {
- "pass", "pass_immutable", "fail", "no_label", "no_xattrs", "unknown"
+ "pass", "pass_immutable", "fail", "fail_immutable", "no_label",
+ "no_xattrs", "unknown"
};
int evm_hmac_attrs;
@@ -134,7 +135,7 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry,
enum integrity_status evm_status = INTEGRITY_PASS;
struct evm_digest digest;
struct inode *inode;
- int rc, xattr_len;
+ int rc, xattr_len, evm_immutable = 0;
if (iint && (iint->evm_status == INTEGRITY_PASS ||
iint->evm_status == INTEGRITY_PASS_IMMUTABLE))
@@ -179,8 +180,10 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry,
if (rc)
rc = -EINVAL;
break;
- case EVM_IMA_XATTR_DIGSIG:
case EVM_XATTR_PORTABLE_DIGSIG:
+ evm_immutable = 1;
+ fallthrough;
+ case EVM_IMA_XATTR_DIGSIG:
/* accept xattr with non-empty signature field */
if (xattr_len <= sizeof(struct signature_v2_hdr)) {
evm_status = INTEGRITY_FAIL;
@@ -217,9 +220,12 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry,
break;
}
- if (rc)
- evm_status = (rc == -ENODATA) ?
- INTEGRITY_NOXATTRS : INTEGRITY_FAIL;
+ if (rc) {
+ evm_status = INTEGRITY_NOXATTRS;
+ if (rc != -ENODATA)
+ evm_status = evm_immutable ?
+ INTEGRITY_FAIL_IMMUTABLE : INTEGRITY_FAIL;
+ }
out:
if (iint) {
/*
@@ -358,6 +364,12 @@ static int evm_protect_xattr(struct dentry *dentry, const char *xattr_name,
-EPERM, 0);
}
out:
+ /* Writing other xattrs is safe for portable signatures, as portable
+ * signatures are immutable and can never be updated.
+ */
+ if (evm_status == INTEGRITY_FAIL_IMMUTABLE)
+ return 0;
+
if (evm_status != INTEGRITY_PASS)
integrity_audit_msg(AUDIT_INTEGRITY_METADATA, d_backing_inode(dentry),
dentry->d_name.name, "appraise_metadata",
@@ -499,9 +511,14 @@ int evm_inode_setattr(struct dentry *dentry, struct iattr *attr)
if (!(ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID)))
return 0;
evm_status = evm_verify_current_integrity(dentry);
+ /* Writing attrs is safe for portable signatures, as portable signatures
+ * are immutable and can never be updated.
+ */
if ((evm_status == INTEGRITY_PASS) ||
- (evm_status == INTEGRITY_NOXATTRS))
+ (evm_status == INTEGRITY_NOXATTRS) ||
+ (evm_status == INTEGRITY_FAIL_IMMUTABLE))
return 0;
+
integrity_audit_msg(AUDIT_INTEGRITY_METADATA, d_backing_inode(dentry),
dentry->d_name.name, "appraise_metadata",
integrity_status_msg[evm_status], -EPERM, 0);
diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c
index b8848f53c8cc..4d682bc3a77f 100644
--- a/security/integrity/ima/ima_appraise.c
+++ b/security/integrity/ima/ima_appraise.c
@@ -399,6 +399,8 @@ int ima_appraise_measurement(enum ima_hooks func,
case INTEGRITY_NOLABEL: /* No security.evm xattr. */
cause = "missing-HMAC";
goto out;
+ case INTEGRITY_FAIL_IMMUTABLE:
+ fallthrough;
case INTEGRITY_FAIL: /* Invalid HMAC/signature. */
cause = "invalid-HMAC";
goto out;
--
2.27.GIT
^ permalink raw reply related
* [PATCH v2 07/12] evm: Introduce EVM_RESET_STATUS atomic flag
From: Roberto Sassu @ 2020-09-04 9:26 UTC (permalink / raw)
To: zohar, mjg59
Cc: linux-integrity, linux-security-module, linux-kernel,
silviu.vlasceanu, Roberto Sassu, stable
In-Reply-To: <20200904092339.19598-1-roberto.sassu@huawei.com>
When EVM_ALLOW_METADATA_WRITES is set, EVM allows any operation on
metadata. Its main purpose is to allow users to freely set metadata when
they are protected by a portable signature, until the HMAC key is loaded.
However, IMA is not notified about metadata changes and, after the first
successful appraisal, always allows access to the files without checking
metadata again.
This patch introduces the new atomic flag EVM_RESET_STATUS in
integrity_iint_cache that is set in the EVM post hooks and cleared in
evm_verify_hmac(). IMA checks the new flag in process_measurement() and if
it is set, it clears the appraisal flags.
Although the flag could be cleared also by evm_inode_setxattr() and
evm_inode_setattr() before IMA sees it, this does not happen if
EVM_ALLOW_METADATA_WRITES is set. Since the only remaining caller is
evm_verifyxattr(), this ensures that IMA always sees the flag set before it
is cleared.
This patch also adds a call to evm_reset_status() in
evm_inode_post_setattr() so that EVM won't return the cached status the
next time appraisal is performed.
Cc: stable@vger.kernel.org # 4.16.x
Fixes: ae1ba1676b88e ("EVM: Allow userland to permit modification of EVM-protected metadata")
Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
---
security/integrity/evm/evm_main.c | 17 +++++++++++++++--
security/integrity/ima/ima_main.c | 8 ++++++--
security/integrity/integrity.h | 1 +
3 files changed, 22 insertions(+), 4 deletions(-)
diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c
index 4e9f5e8b21d5..05be1ad3e6f3 100644
--- a/security/integrity/evm/evm_main.c
+++ b/security/integrity/evm/evm_main.c
@@ -221,8 +221,15 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry,
evm_status = (rc == -ENODATA) ?
INTEGRITY_NOXATTRS : INTEGRITY_FAIL;
out:
- if (iint)
+ if (iint) {
+ /*
+ * EVM_RESET_STATUS can be cleared only by evm_verifyxattr()
+ * when EVM_ALLOW_METADATA_WRITES is set. This guarantees that
+ * IMA sees the EVM_RESET_STATUS flag set before it is cleared.
+ */
+ clear_bit(EVM_RESET_STATUS, &iint->atomic_flags);
iint->evm_status = evm_status;
+ }
kfree(xattr_data);
return evm_status;
}
@@ -418,8 +425,12 @@ static void evm_reset_status(struct inode *inode)
struct integrity_iint_cache *iint;
iint = integrity_iint_find(inode);
- if (iint)
+ if (iint) {
+ if (evm_initialized & EVM_ALLOW_METADATA_WRITES)
+ set_bit(EVM_RESET_STATUS, &iint->atomic_flags);
+
iint->evm_status = INTEGRITY_UNKNOWN;
+ }
}
/**
@@ -513,6 +524,8 @@ void evm_inode_post_setattr(struct dentry *dentry, int ia_valid)
if (!evm_key_loaded())
return;
+ evm_reset_status(dentry->d_inode);
+
if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID))
evm_update_evmxattr(dentry, NULL, NULL, 0);
}
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index 8a91711ca79b..bb9976dc2b74 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -246,8 +246,12 @@ static int process_measurement(struct file *file, const struct cred *cred,
mutex_lock(&iint->mutex);
- if (test_and_clear_bit(IMA_CHANGE_ATTR, &iint->atomic_flags))
- /* reset appraisal flags if ima_inode_post_setattr was called */
+ if (test_and_clear_bit(IMA_CHANGE_ATTR, &iint->atomic_flags) ||
+ test_bit(EVM_RESET_STATUS, &iint->atomic_flags))
+ /*
+ * Reset appraisal flags if ima_inode_post_setattr was called or
+ * EVM reset its status and metadata modification was enabled.
+ */
iint->flags &= ~(IMA_APPRAISE | IMA_APPRAISED |
IMA_APPRAISE_SUBMASK | IMA_APPRAISED_SUBMASK |
IMA_ACTION_FLAGS);
diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h
index 413c803c5208..2adec51c0f6e 100644
--- a/security/integrity/integrity.h
+++ b/security/integrity/integrity.h
@@ -70,6 +70,7 @@
#define IMA_CHANGE_ATTR 2
#define IMA_DIGSIG 3
#define IMA_MUST_MEASURE 4
+#define EVM_RESET_STATUS 5
enum evm_ima_xattr_type {
IMA_XATTR_DIGEST = 0x01,
--
2.27.GIT
^ permalink raw reply related
* [PATCH v2 09/12] evm: Allow setxattr() and setattr() if metadata digest won't change
From: Roberto Sassu @ 2020-09-04 9:26 UTC (permalink / raw)
To: zohar, mjg59
Cc: linux-integrity, linux-security-module, linux-kernel,
silviu.vlasceanu, Roberto Sassu
In-Reply-To: <20200904092339.19598-1-roberto.sassu@huawei.com>
With the patch to allow xattr/attr operations if a portable signature
verification fails, cp and tar can copy all xattrs/attrs so that at the
end of the process verification succeeds.
However, it might happen that xattrs/attrs are already set to the correct
value (taken at signing time) and signature verification succeeds before
the copy is completed. For example, an archive might contains files owned
by root and the archive is extracted by root.
Then, since portable signatures are immutable, all subsequent operations
fail (e.g. fchown()), even if the operation is legitimate (does not alter
the current value).
This patch avoids this problem by reporting successful operation to user
space when that operation does not alter the current value of xattrs/attrs.
Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
---
security/integrity/evm/evm_main.c | 94 +++++++++++++++++++++++++++++++
1 file changed, 94 insertions(+)
diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c
index a5dab1ac9374..f43780ae8ae4 100644
--- a/security/integrity/evm/evm_main.c
+++ b/security/integrity/evm/evm_main.c
@@ -18,6 +18,7 @@
#include <linux/integrity.h>
#include <linux/evm.h>
#include <linux/magic.h>
+#include <linux/posix_acl_xattr.h>
#include <crypto/hash.h>
#include <crypto/hash_info.h>
@@ -314,6 +315,78 @@ static enum integrity_status evm_verify_current_integrity(struct dentry *dentry)
return evm_verify_hmac(dentry, NULL, NULL, 0, NULL);
}
+/*
+ * evm_xattr_acl_change - check if passed ACL changes the inode mode
+ * @dentry: pointer to the affected dentry
+ * @xattr_name: requested xattr
+ * @xattr_value: requested xattr value
+ * @xattr_value_len: requested xattr value length
+ *
+ * Check if passed ACL changes the inode mode, which is protected by EVM.
+ *
+ * Returns 1 if passed ACL causes inode mode change, 0 otherwise.
+ */
+static int evm_xattr_acl_change(struct dentry *dentry, const char *xattr_name,
+ const void *xattr_value, size_t xattr_value_len)
+{
+ umode_t mode;
+ struct posix_acl *acl = NULL, *acl_res;
+ struct inode *inode = d_backing_inode(dentry);
+ int rc;
+
+ /* UID/GID in ACL have been already converted from user to init ns */
+ acl = posix_acl_from_xattr(&init_user_ns, xattr_value, xattr_value_len);
+ if (!acl)
+ return 1;
+
+ acl_res = acl;
+ rc = posix_acl_update_mode(inode, &mode, &acl_res);
+
+ posix_acl_release(acl);
+
+ if (rc)
+ return 1;
+
+ if (acl_res && inode->i_mode != mode)
+ return 1;
+
+ return 0;
+}
+
+/*
+ * evm_xattr_change - check if passed xattr value differs from current value
+ * @dentry: pointer to the affected dentry
+ * @xattr_name: requested xattr
+ * @xattr_value: requested xattr value
+ * @xattr_value_len: requested xattr value length
+ *
+ * Check if passed xattr value differs from current value.
+ *
+ * Returns 1 if passed xattr value differs from current value, 0 otherwise.
+ */
+static int evm_xattr_change(struct dentry *dentry, const char *xattr_name,
+ const void *xattr_value, size_t xattr_value_len)
+{
+ char *xattr_data = NULL;
+ int rc = 0;
+
+ if (posix_xattr_acl(xattr_name))
+ return evm_xattr_acl_change(dentry, xattr_name, xattr_value,
+ xattr_value_len);
+
+ rc = vfs_getxattr_alloc(dentry, xattr_name, &xattr_data, 0, GFP_NOFS);
+ if (rc < 0)
+ return 1;
+
+ if (rc == xattr_value_len)
+ rc = memcmp(xattr_value, xattr_data, rc);
+ else
+ rc = 1;
+
+ kfree(xattr_data);
+ return rc;
+}
+
/*
* evm_protect_xattr - protect the EVM extended attribute
*
@@ -370,6 +443,10 @@ static int evm_protect_xattr(struct dentry *dentry, const char *xattr_name,
if (evm_status == INTEGRITY_FAIL_IMMUTABLE)
return 0;
+ if (evm_status == INTEGRITY_PASS_IMMUTABLE &&
+ !evm_xattr_change(dentry, xattr_name, xattr_value, xattr_value_len))
+ return 0;
+
if (evm_status != INTEGRITY_PASS)
integrity_audit_msg(AUDIT_INTEGRITY_METADATA, d_backing_inode(dentry),
dentry->d_name.name, "appraise_metadata",
@@ -490,6 +567,19 @@ void evm_inode_post_removexattr(struct dentry *dentry, const char *xattr_name)
evm_update_evmxattr(dentry, xattr_name, NULL, 0);
}
+static int evm_attr_change(struct dentry *dentry, struct iattr *attr)
+{
+ struct inode *inode = d_backing_inode(dentry);
+ unsigned int ia_valid = attr->ia_valid;
+
+ if ((!(ia_valid & ATTR_UID) || uid_eq(attr->ia_uid, inode->i_uid)) &&
+ (!(ia_valid & ATTR_GID) || gid_eq(attr->ia_gid, inode->i_gid)) &&
+ (!(ia_valid & ATTR_MODE) || attr->ia_mode == inode->i_mode))
+ return 0;
+
+ return 1;
+}
+
/**
* evm_inode_setattr - prevent updating an invalid EVM extended attribute
* @dentry: pointer to the affected dentry
@@ -519,6 +609,10 @@ int evm_inode_setattr(struct dentry *dentry, struct iattr *attr)
(evm_status == INTEGRITY_FAIL_IMMUTABLE))
return 0;
+ if (evm_status == INTEGRITY_PASS_IMMUTABLE &&
+ !evm_attr_change(dentry, attr))
+ return 0;
+
integrity_audit_msg(AUDIT_INTEGRITY_METADATA, d_backing_inode(dentry),
dentry->d_name.name, "appraise_metadata",
integrity_status_msg[evm_status], -EPERM, 0);
--
2.27.GIT
^ permalink raw reply related
* [PATCH v2 06/12] evm: Refuse EVM_ALLOW_METADATA_WRITES only if the HMAC key is loaded
From: Roberto Sassu @ 2020-09-04 9:26 UTC (permalink / raw)
To: zohar, mjg59
Cc: linux-integrity, linux-security-module, linux-kernel,
silviu.vlasceanu, Roberto Sassu, stable
In-Reply-To: <20200904092339.19598-1-roberto.sassu@huawei.com>
EVM_ALLOW_METADATA_WRITES is an EVM initialization flag that can be set to
temporarily disable metadata verification until all xattrs/attrs necessary
to verify an EVM portable signature are copied to the file. This flag is
cleared when EVM is initialized with an HMAC key, to avoid that the HMAC is
calculated on unverified xattrs/attrs.
Currently EVM unnecessarily denies setting this flag if EVM is initialized
with public key, which is not a concern as it cannot be used to trust
xattrs/attrs updates. This patch removes this limitation.
Cc: stable@vger.kernel.org # 4.16.x
Fixes: ae1ba1676b88e ("EVM: Allow userland to permit modification of EVM-protected metadata")
Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
---
Documentation/ABI/testing/evm | 6 ++++--
security/integrity/evm/evm_secfs.c | 2 +-
2 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/Documentation/ABI/testing/evm b/Documentation/ABI/testing/evm
index 201d10319fa1..cbb50ab09c78 100644
--- a/Documentation/ABI/testing/evm
+++ b/Documentation/ABI/testing/evm
@@ -42,8 +42,10 @@ Description:
modification of EVM-protected metadata and
disable all further modification of policy
- Note that once a key has been loaded, it will no longer be
- possible to enable metadata modification.
+ Note that once HMAC validation and creation is enabled,
+ it will no longer be possible to enable metadata modification
+ and if metadata modification is already enabled, it will be
+ disabled.
Until key loading has been signaled EVM can not create
or validate the 'security.evm' xattr, but returns
diff --git a/security/integrity/evm/evm_secfs.c b/security/integrity/evm/evm_secfs.c
index cfc3075769bb..92fe26ace797 100644
--- a/security/integrity/evm/evm_secfs.c
+++ b/security/integrity/evm/evm_secfs.c
@@ -84,7 +84,7 @@ static ssize_t evm_write_key(struct file *file, const char __user *buf,
* keys are loaded.
*/
if ((i & EVM_ALLOW_METADATA_WRITES) &&
- ((evm_initialized & EVM_KEY_MASK) != 0) &&
+ ((evm_initialized & EVM_INIT_HMAC) != 0) &&
!(evm_initialized & EVM_ALLOW_METADATA_WRITES))
return -EPERM;
--
2.27.GIT
^ permalink raw reply related
* [PATCH v2 02/12] ima: Remove semicolon at the end of ima_get_binary_runtime_size()
From: Roberto Sassu @ 2020-09-04 9:23 UTC (permalink / raw)
To: zohar, mjg59
Cc: linux-integrity, linux-security-module, linux-kernel,
silviu.vlasceanu, Roberto Sassu, stable
In-Reply-To: <20200904092339.19598-1-roberto.sassu@huawei.com>
This patch removes the unnecessary semicolon at the end of
ima_get_binary_runtime_size().
Cc: stable@vger.kernel.org
Fixes: d158847ae89a2 ("ima: maintain memory size needed for serializing the measurement list")
Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
---
security/integrity/ima/ima_queue.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/security/integrity/ima/ima_queue.c b/security/integrity/ima/ima_queue.c
index fb4ec270f620..c096ef8945c7 100644
--- a/security/integrity/ima/ima_queue.c
+++ b/security/integrity/ima/ima_queue.c
@@ -133,7 +133,7 @@ unsigned long ima_get_binary_runtime_size(void)
return ULONG_MAX;
else
return binary_runtime_size + sizeof(struct ima_kexec_hdr);
-};
+}
static int ima_pcr_extend(struct tpm_digest *digests_arg, int pcr)
{
--
2.27.GIT
^ permalink raw reply related
* [PATCH v2 03/12] evm: Check size of security.evm before using it
From: Roberto Sassu @ 2020-09-04 9:23 UTC (permalink / raw)
To: zohar, mjg59
Cc: linux-integrity, linux-security-module, linux-kernel,
silviu.vlasceanu, Roberto Sassu, stable
In-Reply-To: <20200904092339.19598-1-roberto.sassu@huawei.com>
This patch checks the size for the EVM_IMA_XATTR_DIGSIG and
EVM_XATTR_PORTABLE_DIGSIG types to ensure that the algorithm is read from
the buffer returned by vfs_getxattr_alloc().
Cc: stable@vger.kernel.org # 4.19.x
Fixes: 5feeb61183dde ("evm: Allow non-SHA1 digital signatures")
Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
---
security/integrity/evm/evm_main.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c
index 0d36259b690d..e4b47759ba1c 100644
--- a/security/integrity/evm/evm_main.c
+++ b/security/integrity/evm/evm_main.c
@@ -181,6 +181,12 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry,
break;
case EVM_IMA_XATTR_DIGSIG:
case EVM_XATTR_PORTABLE_DIGSIG:
+ /* accept xattr with non-empty signature field */
+ if (xattr_len <= sizeof(struct signature_v2_hdr)) {
+ evm_status = INTEGRITY_FAIL;
+ goto out;
+ }
+
hdr = (struct signature_v2_hdr *)xattr_data;
digest.hdr.algo = hdr->hash_algo;
rc = evm_calc_hash(dentry, xattr_name, xattr_value,
--
2.27.GIT
^ permalink raw reply related
* [PATCH v2 04/12] evm: Execute evm_inode_init_security() only when the HMAC key is loaded
From: Roberto Sassu @ 2020-09-04 9:23 UTC (permalink / raw)
To: zohar, mjg59
Cc: linux-integrity, linux-security-module, linux-kernel,
silviu.vlasceanu, Roberto Sassu, stable
In-Reply-To: <20200904092339.19598-1-roberto.sassu@huawei.com>
evm_inode_init_security() requires the HMAC key to calculate the HMAC on
initial xattrs provided by LSMs. Unfortunately, with the evm_key_loaded()
check, the function continues even if the HMAC key is not loaded
(evm_key_loaded() returns true also if EVM has been initialized only with a
public key). If the HMAC key is not loaded, evm_inode_init_security()
returns an error later when it calls evm_init_hmac().
Thus, this patch replaces the evm_key_loaded() check with a check of the
EVM_INIT_HMAC flag in evm_initialized, so that evm_inode_init_security()
returns 0 instead of an error.
Cc: stable@vger.kernel.org # 4.5.x
Fixes: 26ddabfe96b ("evm: enable EVM when X509 certificate is loaded")
Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
---
security/integrity/evm/evm_main.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c
index e4b47759ba1c..4e9f5e8b21d5 100644
--- a/security/integrity/evm/evm_main.c
+++ b/security/integrity/evm/evm_main.c
@@ -527,7 +527,8 @@ int evm_inode_init_security(struct inode *inode,
struct evm_xattr *xattr_data;
int rc;
- if (!evm_key_loaded() || !evm_protected_xattr(lsm_xattr->name))
+ if (!(evm_initialized & EVM_INIT_HMAC) ||
+ !evm_protected_xattr(lsm_xattr->name))
return 0;
xattr_data = kzalloc(sizeof(*xattr_data), GFP_NOFS);
--
2.27.GIT
^ permalink raw reply related
* [PATCH v2 01/12] ima: Don't ignore errors from crypto_shash_update()
From: Roberto Sassu @ 2020-09-04 9:23 UTC (permalink / raw)
To: zohar, mjg59
Cc: linux-integrity, linux-security-module, linux-kernel,
silviu.vlasceanu, Roberto Sassu, stable
In-Reply-To: <20200904092339.19598-1-roberto.sassu@huawei.com>
Errors returned by crypto_shash_update() are not checked in
ima_calc_boot_aggregate_tfm() and thus can be overwritten at the next
iteration of the loop. This patch adds a check after calling
crypto_shash_update() and returns immediately if the result is not zero.
Cc: stable@vger.kernel.org
Fixes: 3323eec921efd ("integrity: IMA as an integrity service provider")
Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
---
security/integrity/ima/ima_crypto.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c
index 011c3c76af86..21989fa0c107 100644
--- a/security/integrity/ima/ima_crypto.c
+++ b/security/integrity/ima/ima_crypto.c
@@ -829,6 +829,8 @@ static int ima_calc_boot_aggregate_tfm(char *digest, u16 alg_id,
/* now accumulate with current aggregate */
rc = crypto_shash_update(shash, d.digest,
crypto_shash_digestsize(tfm));
+ if (rc != 0)
+ return rc;
}
/*
* Extend cumulative digest over TPM registers 8-9, which contain
--
2.27.GIT
^ permalink raw reply related
* [PATCH v2 00/12] IMA/EVM fixes
From: Roberto Sassu @ 2020-09-04 9:23 UTC (permalink / raw)
To: zohar, mjg59
Cc: linux-integrity, linux-security-module, linux-kernel,
silviu.vlasceanu, Roberto Sassu
This patch set includes various fixes for IMA and EVM.
Patches 1-3 are trivial fixes. The remaining improve support and usability
of EVM portable signatures. In particular patch 4 allows EVM to be used
without an HMAC key. Patch 5 avoids appraisal verification of public keys
(they are already verified by the key subsystem).
Patches 6-7 allow metadata verification to be turned off when the HMAC key
is not already loaded and to use this mode in a safe way (by ensuring that
IMA revalidates metadata when there is a change).
Patches 8-9 make portable signatures more usable if metadata verification
cannot be turned off (because the HMAC key is loaded) by accepting any
metadata modification until signature verification succeeds (useful when
xattrs/attrs are copied in a sequence from a source) and by allowing
operations that don't change metadata.
Patch 10 makes it possible to use portable signatures when the IMA policy
requires file signatures and patch 11 shows portable signatures when the
ima-sig measurement list template is selected.
Lastly, patch 12 avoids undesired removal of security.ima when a file is
not selected by the IMA policy.
Roberto Sassu (12):
ima: Don't ignore errors from crypto_shash_update()
ima: Remove semicolon at the end of ima_get_binary_runtime_size()
evm: Check size of security.evm before using it
evm: Execute evm_inode_init_security() only when the HMAC key is
loaded
evm: Load EVM key in ima_load_x509() to avoid appraisal
evm: Refuse EVM_ALLOW_METADATA_WRITES only if the HMAC key is loaded
evm: Introduce EVM_RESET_STATUS atomic flag
evm: Allow xattr/attr operations for portable signatures if check
fails
evm: Allow setxattr() and setattr() if metadata digest won't change
ima: Allow imasig requirement to be satisfied by EVM portable
signatures
ima: Introduce template field evmsig and write to field sig as
fallback
ima: Don't remove security.ima if file must not be appraised
Documentation/ABI/testing/evm | 6 +-
Documentation/security/IMA-templates.rst | 4 +-
include/linux/integrity.h | 1 +
security/integrity/evm/evm_main.c | 151 ++++++++++++++++++++--
security/integrity/evm/evm_secfs.c | 2 +-
security/integrity/iint.c | 2 +
security/integrity/ima/ima_appraise.c | 26 ++--
security/integrity/ima/ima_crypto.c | 2 +
security/integrity/ima/ima_init.c | 4 +
security/integrity/ima/ima_main.c | 8 +-
security/integrity/ima/ima_queue.c | 2 +-
security/integrity/ima/ima_template.c | 2 +
security/integrity/ima/ima_template_lib.c | 39 +++++-
security/integrity/ima/ima_template_lib.h | 2 +
security/integrity/integrity.h | 1 +
15 files changed, 225 insertions(+), 27 deletions(-)
--
2.27.GIT
^ permalink raw reply
* Re: [PATCH v20 20/23] Audit: Add new record for multiple process LSM attributes
From: Paul Moore @ 2020-09-03 21:49 UTC (permalink / raw)
To: James Morris
Cc: Casey Schaufler, casey.schaufler, linux-security-module, selinux,
linux-audit, keescook, john.johansen, penguin-kernel,
Stephen Smalley
In-Reply-To: <alpine.LRH.2.21.2009040231550.1484@namei.org>
On Thu, Sep 3, 2020 at 12:32 PM James Morris <jmorris@namei.org> wrote:
> On Wed, 26 Aug 2020, Casey Schaufler wrote:
>
> > Create a new audit record type to contain the subject information
> > when there are multiple security modules that require such data.
> > This record is linked with the same timestamp and serial number.
> > The record is produced only in cases where there is more than one
> > security module with a process "context".
> >
> > Before this change the only audit events that required multiple
> > records were syscall events. Several non-syscall events include
> > subject contexts, so the use of audit_context data has been expanded
> > as necessary.
> >
> > Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
> > Cc: linux-audit@redhat.com
>
> Paul, can you review/ack the audit changes?
I did a previous version at some point in the past, I'll take a look
at v20 tomorrow or this weekend.
--
paul moore
www.paul-moore.com
^ permalink raw reply
* Re: [PATCH v20 20/23] Audit: Add new record for multiple process LSM attributes
From: John Johansen @ 2020-09-03 17:00 UTC (permalink / raw)
To: James Morris, Casey Schaufler
Cc: casey.schaufler, linux-security-module, selinux, linux-audit,
keescook, penguin-kernel, paul, sds
In-Reply-To: <alpine.LRH.2.21.2009040231550.1484@namei.org>
On 9/3/20 9:32 AM, James Morris wrote:
> On Wed, 26 Aug 2020, Casey Schaufler wrote:
>
>> Create a new audit record type to contain the subject information
>> when there are multiple security modules that require such data.
>> This record is linked with the same timestamp and serial number.
>> The record is produced only in cases where there is more than one
>> security module with a process "context".
>>
>> Before this change the only audit events that required multiple
>> records were syscall events. Several non-syscall events include
>> subject contexts, so the use of audit_context data has been expanded
>> as necessary.
>>
>> Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
>> Cc: linux-audit@redhat.com
>
> Paul, can you review/ack the audit changes?
>
I am working on reviewing them as well, but I can't/won't ack them.
>> ---
>> drivers/android/binder.c | 2 +-
>> include/linux/audit.h | 13 +++-
>> include/linux/security.h | 18 ++++-
>> include/net/netlabel.h | 2 +-
>> include/net/scm.h | 3 +-
>> include/net/xfrm.h | 4 +-
>> include/uapi/linux/audit.h | 1 +
>> kernel/audit.c | 89 ++++++++++++++++++-------
>> kernel/auditfilter.c | 2 +-
>> kernel/auditsc.c | 87 ++++++++++++++++++++++--
>> net/ipv4/ip_sockglue.c | 2 +-
>> net/netfilter/nf_conntrack_netlink.c | 4 +-
>> net/netfilter/nf_conntrack_standalone.c | 2 +-
>> net/netfilter/nfnetlink_queue.c | 2 +-
>> net/netlabel/netlabel_unlabeled.c | 16 ++---
>> net/netlabel/netlabel_user.c | 12 ++--
>> net/netlabel/netlabel_user.h | 6 +-
>> security/integrity/integrity_audit.c | 2 +-
>> security/security.c | 73 +++++++++++++++-----
>> security/smack/smackfs.c | 3 +-
>> 20 files changed, 259 insertions(+), 84 deletions(-)
>>
>> diff --git a/drivers/android/binder.c b/drivers/android/binder.c
>> index 0bde1b96680e..93781dad0c28 100644
>> --- a/drivers/android/binder.c
>> +++ b/drivers/android/binder.c
>> @@ -3113,7 +3113,7 @@ static void binder_transaction(struct binder_proc *proc,
>> size_t added_size;
>>
>> security_task_getsecid(proc->tsk, &blob);
>> - ret = security_secid_to_secctx(&blob, &lsmctx);
>> + ret = security_secid_to_secctx(&blob, &lsmctx, LSMBLOB_DISPLAY);
>> if (ret) {
>> return_error = BR_FAILED_REPLY;
>> return_error_param = ret;
>> diff --git a/include/linux/audit.h b/include/linux/audit.h
>> index ba1cd38d601b..fe027df0d9a8 100644
>> --- a/include/linux/audit.h
>> +++ b/include/linux/audit.h
>> @@ -186,7 +186,9 @@ extern void audit_log_path_denied(int type,
>> const char *operation);
>> extern void audit_log_lost(const char *message);
>>
>> -extern int audit_log_task_context(struct audit_buffer *ab);
>> +extern void audit_log_lsm(struct lsmblob *blob, bool exiting);
>> +extern int audit_log_task_context(struct audit_buffer *ab,
>> + struct lsmblob *blob);
>> extern void audit_log_task_info(struct audit_buffer *ab);
>>
>> extern int audit_update_lsm_rules(void);
>> @@ -246,7 +248,10 @@ static inline void audit_log_key(struct audit_buffer *ab, char *key)
>> { }
>> static inline void audit_log_path_denied(int type, const char *operation)
>> { }
>> -static inline int audit_log_task_context(struct audit_buffer *ab)
>> +static inline void audit_log_lsm(struct lsmblob *blob, bool exiting)
>> +{ }
>> +static inline int audit_log_task_context(struct audit_buffer *ab,
>> + struct lsmblob *blob);
>> {
>> return 0;
>> }
>> @@ -305,6 +310,7 @@ extern void audit_seccomp(unsigned long syscall, long signr, int code);
>> extern void audit_seccomp_actions_logged(const char *names,
>> const char *old_names, int res);
>> extern void __audit_ptrace(struct task_struct *t);
>> +extern void audit_stamp_context(struct audit_context *ctx);
>>
>> static inline void audit_set_context(struct task_struct *task, struct audit_context *ctx)
>> {
>> @@ -682,6 +688,9 @@ static inline void audit_ntp_log(const struct audit_ntp_data *ad)
>> static inline void audit_ptrace(struct task_struct *t)
>> { }
>>
>> +static inline void audit_stamp_context(struct audit_context *ctx)
>> +{ }
>> +
>> static inline void audit_log_nfcfg(const char *name, u8 af,
>> unsigned int nentries,
>> enum audit_nfcfgop op, gfp_t gfp)
>> diff --git a/include/linux/security.h b/include/linux/security.h
>> index 40260bfc3a0d..3cbe24be1563 100644
>> --- a/include/linux/security.h
>> +++ b/include/linux/security.h
>> @@ -180,6 +180,8 @@ struct lsmblob {
>> #define LSMBLOB_INVALID -1 /* Not a valid LSM slot number */
>> #define LSMBLOB_NEEDED -2 /* Slot requested on initialization */
>> #define LSMBLOB_NOT_NEEDED -3 /* Slot not requested */
>> +#define LSMBLOB_DISPLAY -4 /* Use the "display" slot */
>> +#define LSMBLOB_FIRST -5 /* Use the default "display" slot */
>>
>> /**
>> * lsmblob_init - initialize an lsmblob structure.
>> @@ -242,6 +244,17 @@ static inline u32 lsmblob_value(const struct lsmblob *blob)
>> return 0;
>> }
>>
>> +const char *security_lsm_slot_name(int slot);
>> +
>> +static inline bool lsm_multiple_contexts(void)
>> +{
>> +#ifdef CONFIG_SECURITY
>> + return security_lsm_slot_name(1) != NULL;
>> +#else
>> + return false;
>> +#endif
>> +}
>> +
>> /* These functions are in security/commoncap.c */
>> extern int cap_capable(const struct cred *cred, struct user_namespace *ns,
>> int cap, unsigned int opts);
>> @@ -554,7 +567,8 @@ int security_setprocattr(const char *lsm, const char *name, void *value,
>> size_t size);
>> int security_netlink_send(struct sock *sk, struct sk_buff *skb);
>> int security_ismaclabel(const char *name);
>> -int security_secid_to_secctx(struct lsmblob *blob, struct lsmcontext *cp);
>> +int security_secid_to_secctx(struct lsmblob *blob, struct lsmcontext *cp,
>> + int display);
>> int security_secctx_to_secid(const char *secdata, u32 seclen,
>> struct lsmblob *blob);
>> void security_release_secctx(struct lsmcontext *cp);
>> @@ -1372,7 +1386,7 @@ static inline int security_ismaclabel(const char *name)
>> }
>>
>> static inline int security_secid_to_secctx(struct lsmblob *blob,
>> - struct lsmcontext *cp)
>> + struct lsmcontext *cp, int display)
>> {
>> return -EOPNOTSUPP;
>> }
>> diff --git a/include/net/netlabel.h b/include/net/netlabel.h
>> index 73fc25b4042b..216cb1ffc8f0 100644
>> --- a/include/net/netlabel.h
>> +++ b/include/net/netlabel.h
>> @@ -97,7 +97,7 @@ struct calipso_doi;
>>
>> /* NetLabel audit information */
>> struct netlbl_audit {
>> - u32 secid;
>> + struct lsmblob lsmdata;
>> kuid_t loginuid;
>> unsigned int sessionid;
>> };
>> diff --git a/include/net/scm.h b/include/net/scm.h
>> index 4a6ad8caf423..8b5a4737e1b8 100644
>> --- a/include/net/scm.h
>> +++ b/include/net/scm.h
>> @@ -96,7 +96,8 @@ static inline void scm_passec(struct socket *sock, struct msghdr *msg, struct sc
>> int err;
>>
>> if (test_bit(SOCK_PASSSEC, &sock->flags)) {
>> - err = security_secid_to_secctx(&scm->lsmblob, &context);
>> + err = security_secid_to_secctx(&scm->lsmblob, &context,
>> + LSMBLOB_DISPLAY);
>>
>> if (!err) {
>> put_cmsg(msg, SOL_SOCKET, SCM_SECURITY,
>> diff --git a/include/net/xfrm.h b/include/net/xfrm.h
>> index 2737d24ec244..9e8cac6228b4 100644
>> --- a/include/net/xfrm.h
>> +++ b/include/net/xfrm.h
>> @@ -675,11 +675,13 @@ static inline struct audit_buffer *xfrm_audit_start(const char *op)
>>
>> if (audit_enabled == AUDIT_OFF)
>> return NULL;
>> + audit_stamp_context(audit_context());
>> audit_buf = audit_log_start(audit_context(), GFP_ATOMIC,
>> AUDIT_MAC_IPSEC_EVENT);
>> if (audit_buf == NULL)
>> return NULL;
>> audit_log_format(audit_buf, "op=%s", op);
>> + audit_log_lsm(NULL, false);
>> return audit_buf;
>> }
>>
>> @@ -693,7 +695,7 @@ static inline void xfrm_audit_helper_usrinfo(bool task_valid,
>> AUDIT_SID_UNSET;
>>
>> audit_log_format(audit_buf, " auid=%u ses=%u", auid, ses);
>> - audit_log_task_context(audit_buf);
>> + audit_log_task_context(audit_buf, NULL);
>> }
>>
>> void xfrm_audit_policy_add(struct xfrm_policy *xp, int result, bool task_valid);
>> diff --git a/include/uapi/linux/audit.h b/include/uapi/linux/audit.h
>> index cd2d8279a5e4..2a63720e56f6 100644
>> --- a/include/uapi/linux/audit.h
>> +++ b/include/uapi/linux/audit.h
>> @@ -139,6 +139,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_MAC_TASK_CONTEXTS 1420 /* Multiple LSM contexts */
>>
>> #define AUDIT_FIRST_KERN_ANOM_MSG 1700
>> #define AUDIT_LAST_KERN_ANOM_MSG 1799
>> diff --git a/kernel/audit.c b/kernel/audit.c
>> index 594b42fc88ff..0e7831c9f321 100644
>> --- a/kernel/audit.c
>> +++ b/kernel/audit.c
>> @@ -394,10 +394,11 @@ static int audit_log_config_change(char *function_name, u32 new, u32 old,
>> return rc;
>> audit_log_format(ab, "op=set %s=%u old=%u ", function_name, new, old);
>> audit_log_session_info(ab);
>> - rc = audit_log_task_context(ab);
>> + rc = audit_log_task_context(ab, NULL);
>> if (rc)
>> allow_changes = 0; /* Something weird, deny request */
>> audit_log_format(ab, " res=%d", allow_changes);
>> + audit_log_lsm(NULL, false);
>> audit_log_end(ab);
>> return rc;
>> }
>> @@ -1070,13 +1071,31 @@ static void audit_log_common_recv_msg(struct audit_context *context,
>> return;
>> audit_log_format(*ab, "pid=%d uid=%u ", pid, uid);
>> audit_log_session_info(*ab);
>> - audit_log_task_context(*ab);
>> + audit_log_task_context(*ab, NULL);
>> }
>>
>> static inline void audit_log_user_recv_msg(struct audit_buffer **ab,
>> u16 msg_type)
>> {
>> - audit_log_common_recv_msg(NULL, ab, msg_type);
>> + struct audit_context *context;
>> +
>> + if (!lsm_multiple_contexts()) {
>> + audit_log_common_recv_msg(NULL, ab, msg_type);
>> + return;
>> + }
>> +
>> + context = audit_context();
>> + if (context) {
>> + if (!context->in_syscall)
>> + audit_stamp_context(context);
>> + audit_log_common_recv_msg(context, ab, msg_type);
>> + return;
>> + }
>> +
>> + audit_alloc(current);
>> + context = audit_context();
>> +
>> + audit_log_common_recv_msg(context, ab, msg_type);
>> }
>>
>> int is_audit_feature_set(int i)
>> @@ -1372,6 +1391,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
>> audit_log_n_untrustedstring(ab, str, data_len);
>> }
>> audit_log_end(ab);
>> + audit_log_lsm(NULL, false);
>> }
>> break;
>> case AUDIT_ADD_RULE:
>> @@ -1444,7 +1464,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
>>
>> if (lsmblob_is_set(&audit_sig_lsm)) {
>> err = security_secid_to_secctx(&audit_sig_lsm,
>> - &context);
>> + &context, LSMBLOB_FIRST);
>> if (err)
>> return err;
>> }
>> @@ -1572,7 +1592,7 @@ static void audit_log_multicast(int group, const char *op, int err)
>> tty ? tty_name(tty) : "(none)",
>> audit_get_sessionid(current));
>> audit_put_tty(tty);
>> - audit_log_task_context(ab); /* subj= */
>> + audit_log_task_context(ab, NULL); /* subj= */
>> audit_log_format(ab, " comm=");
>> audit_log_untrustedstring(ab, get_task_comm(comm, current));
>> audit_log_d_path_exe(ab, current->mm); /* exe= */
>> @@ -1869,6 +1889,10 @@ struct audit_buffer *audit_log_start(struct audit_context *ctx, gfp_t gfp_mask,
>> }
>>
>> audit_get_stamp(ab->ctx, &t, &serial);
>> + if (type == AUDIT_MAC_TASK_CONTEXTS && ab->ctx->serial == 0) {
>> + audit_stamp_context(ab->ctx);
>> + audit_get_stamp(ab->ctx, &t, &serial);
>> + }
>> audit_log_format(ab, "audit(%llu.%03lu:%u): ",
>> (unsigned long long)t.tv_sec, t.tv_nsec/1000000, serial);
>>
>> @@ -2126,30 +2150,47 @@ void audit_log_key(struct audit_buffer *ab, char *key)
>> audit_log_format(ab, "(null)");
>> }
>>
>> -int audit_log_task_context(struct audit_buffer *ab)
>> +int audit_log_task_context(struct audit_buffer *ab, struct lsmblob *blob)
>> {
>> + int i;
>> int error;
>> - struct lsmblob blob;
>> - struct lsmcontext context;
>> + struct lsmblob localblob;
>> + struct lsmcontext lsmdata;
>>
>> - security_task_getsecid(current, &blob);
>> - if (!lsmblob_is_set(&blob))
>> + /*
>> + * If there is more than one security module that has a
>> + * subject "context" it's necessary to put the subject data
>> + * into a separate record to maintain compatibility.
>> + */
>> + if (lsm_multiple_contexts()) {
>> + audit_log_format(ab, " subj=?");
>> return 0;
>> + }
>>
>> - error = security_secid_to_secctx(&blob, &context);
>> - if (error) {
>> - if (error != -EINVAL)
>> - goto error_path;
>> - return 0;
>> + if (blob == NULL) {
>> + security_task_getsecid(current, &localblob);
>> + if (!lsmblob_is_set(&localblob)) {
>> + audit_log_format(ab, " subj=?");
>> + return 0;
>> + }
>> + blob = &localblob;
>> }
>>
>> - audit_log_format(ab, " subj=%s", context.context);
>> - security_release_secctx(&context);
>> - return 0;
>> + for (i = 0; i < LSMBLOB_ENTRIES; i++) {
>> + if (blob->secid[i] == 0)
>> + continue;
>> + error = security_secid_to_secctx(blob, &lsmdata, i);
>> + if (error && error != -EINVAL) {
>> + audit_panic("error in audit_log_task_context");
>> + return error;
>> + }
>>
>> -error_path:
>> - audit_panic("error in audit_log_task_context");
>> - return error;
>> + audit_log_format(ab, " subj=%s", lsmdata.context);
>> + security_release_secctx(&lsmdata);
>> + break;
>> + }
>> +
>> + return 0;
>> }
>> EXPORT_SYMBOL(audit_log_task_context);
>>
>> @@ -2221,7 +2262,7 @@ void audit_log_task_info(struct audit_buffer *ab)
>> audit_log_format(ab, " comm=");
>> audit_log_untrustedstring(ab, get_task_comm(comm, current));
>> audit_log_d_path_exe(ab, current->mm);
>> - audit_log_task_context(ab);
>> + audit_log_task_context(ab, NULL);
>> }
>> EXPORT_SYMBOL(audit_log_task_info);
>>
>> @@ -2279,6 +2320,7 @@ static void audit_log_set_loginuid(kuid_t koldloginuid, kuid_t kloginuid,
>> if (!audit_enabled)
>> return;
>>
>> + audit_stamp_context(audit_context());
>> ab = audit_log_start(audit_context(), GFP_KERNEL, AUDIT_LOGIN);
>> if (!ab)
>> return;
>> @@ -2289,11 +2331,12 @@ static void audit_log_set_loginuid(kuid_t koldloginuid, kuid_t kloginuid,
>> tty = audit_get_tty();
>>
>> audit_log_format(ab, "pid=%d uid=%u", task_tgid_nr(current), uid);
>> - audit_log_task_context(ab);
>> + audit_log_task_context(ab, NULL);
>> audit_log_format(ab, " old-auid=%u auid=%u tty=%s old-ses=%u ses=%u res=%d",
>> oldloginuid, loginuid, tty ? tty_name(tty) : "(none)",
>> oldsessionid, sessionid, !rc);
>> audit_put_tty(tty);
>> + audit_log_lsm(NULL, true);
>> audit_log_end(ab);
>> }
>>
>> diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
>> index 31732023b689..6c03e463668e 100644
>> --- a/kernel/auditfilter.c
>> +++ b/kernel/auditfilter.c
>> @@ -1107,7 +1107,7 @@ static void audit_log_rule_change(char *action, struct audit_krule *rule, int re
>> if (!ab)
>> return;
>> audit_log_session_info(ab);
>> - audit_log_task_context(ab);
>> + audit_log_task_context(ab, NULL);
>> audit_log_format(ab, " op=%s", action);
>> audit_log_key(ab, rule->filterkey);
>> audit_log_format(ab, " list=%d res=%d", rule->listnr, res);
>> diff --git a/kernel/auditsc.c b/kernel/auditsc.c
>> index 4af5861bcb9a..cf5dbd0e3a3d 100644
>> --- a/kernel/auditsc.c
>> +++ b/kernel/auditsc.c
>> @@ -473,7 +473,7 @@ static int audit_filter_rules(struct task_struct *tsk,
>> {
>> const struct cred *cred;
>> int i, need_sid = 1;
>> - struct lsmblob blob;
>> + struct lsmblob blob = { };
>> unsigned int sessionid;
>>
>> cred = rcu_dereference_check(tsk->cred, tsk == current || task_creation);
>> @@ -962,10 +962,12 @@ int audit_alloc(struct task_struct *tsk)
>> return 0; /* Return if not auditing. */
>>
>> state = audit_filter_task(tsk, &key);
>> - if (state == AUDIT_DISABLED) {
>> + if (!lsm_multiple_contexts() && state == AUDIT_DISABLED) {
>> clear_tsk_thread_flag(tsk, TIF_SYSCALL_AUDIT);
>> return 0;
>> }
>> + if (state == AUDIT_DISABLED)
>> + clear_tsk_thread_flag(tsk, TIF_SYSCALL_AUDIT);
>>
>> if (!(context = audit_alloc_context(state))) {
>> kfree(key);
>> @@ -1009,7 +1011,7 @@ static int audit_log_pid_context(struct audit_context *context, pid_t pid,
>> from_kuid(&init_user_ns, auid),
>> from_kuid(&init_user_ns, uid), sessionid);
>> if (lsmblob_is_set(blob)) {
>> - if (security_secid_to_secctx(blob, &lsmctx)) {
>> + if (security_secid_to_secctx(blob, &lsmctx, LSMBLOB_FIRST)) {
>> audit_log_format(ab, " obj=(none)");
>> rc = 1;
>> } else {
>> @@ -1254,7 +1256,8 @@ static void show_special(struct audit_context *context, int *call_panic)
>> struct lsmblob blob;
>>
>> lsmblob_init(&blob, osid);
>> - if (security_secid_to_secctx(&blob, &lsmcxt)) {
>> + if (security_secid_to_secctx(&blob, &lsmcxt,
>> + LSMBLOB_FIRST)) {
>> audit_log_format(ab, " osid=%u", osid);
>> *call_panic = 1;
>> } else {
>> @@ -1406,7 +1409,7 @@ static void audit_log_name(struct audit_context *context, struct audit_names *n,
>> struct lsmcontext lsmctx;
>>
>> lsmblob_init(&blob, n->osid);
>> - if (security_secid_to_secctx(&blob, &lsmctx)) {
>> + if (security_secid_to_secctx(&blob, &lsmctx, LSMBLOB_FIRST)) {
>> audit_log_format(ab, " osid=%u", n->osid);
>> if (call_panic)
>> *call_panic = 2;
>> @@ -1483,6 +1486,52 @@ static void audit_log_proctitle(void)
>> audit_log_end(ab);
>> }
>>
>> +void audit_log_lsm(struct lsmblob *blob, bool exiting)
>> +{
>> + struct audit_context *context = audit_context();
>> + struct lsmcontext lsmdata;
>> + struct audit_buffer *ab;
>> + struct lsmblob localblob;
>> + bool sep = false;
>> + int error;
>> + int i;
>> +
>> + if (!lsm_multiple_contexts())
>> + return;
>> +
>> + if (context && context->in_syscall && !exiting)
>> + return;
>> +
>> + ab = audit_log_start(context, GFP_ATOMIC, AUDIT_MAC_TASK_CONTEXTS);
>> + if (!ab)
>> + return; /* audit_panic or being filtered */
>> +
>> + if (blob == NULL) {
>> + security_task_getsecid(current, &localblob);
>> + if (!lsmblob_is_set(&localblob))
>> + return;
>> + blob = &localblob;
>> + }
>> +
>> + for (i = 0; i < LSMBLOB_ENTRIES; i++) {
>> + if (blob->secid[i] == 0)
>> + continue;
>> + error = security_secid_to_secctx(blob, &lsmdata, i);
>> + if (error && error != -EINVAL) {
>> + audit_panic("error in audit_log_lsm");
>> + return;
>> + }
>> +
>> + audit_log_format(ab, "%ssubj_%s=%s", sep ? " " : "",
>> + security_lsm_slot_name(i), lsmdata.context);
>> + sep = true;
>> +
>> + security_release_secctx(&lsmdata);
>> + }
>> +
>> + audit_log_end(ab);
>> +}
>> +
>> static void audit_log_exit(void)
>> {
>> int i, call_panic = 0;
>> @@ -1606,6 +1655,7 @@ static void audit_log_exit(void)
>> }
>>
>> audit_log_proctitle();
>> + audit_log_lsm(NULL, true);
>>
>> /* Send end of event record to help user space know we are finished */
>> ab = audit_log_start(context, GFP_KERNEL, AUDIT_EOE);
>> @@ -2217,6 +2267,21 @@ void __audit_inode_child(struct inode *parent,
>> }
>> EXPORT_SYMBOL_GPL(__audit_inode_child);
>>
>> +/**
>> + * audit_stamp_context - set the timestamp+serial in an audit context
>> + * @ctx: audit_context to set
>> + */
>> +void audit_stamp_context(struct audit_context *ctx)
>> +{
>> + /* ctx will be NULL unless lsm_multiple_contexts() is true */
>> + if (!ctx)
>> + return;
>> +
>> + ktime_get_coarse_real_ts64(&ctx->ctime);
>> + ctx->serial = audit_serial();
>> + ctx->current_state = AUDIT_BUILD_CONTEXT;
>> +}
>> +
>> /**
>> * auditsc_get_stamp - get local copies of audit_context values
>> * @ctx: audit_context for the task
>> @@ -2228,6 +2293,12 @@ EXPORT_SYMBOL_GPL(__audit_inode_child);
>> int auditsc_get_stamp(struct audit_context *ctx,
>> struct timespec64 *t, unsigned int *serial)
>> {
>> + if (ctx->serial && !ctx->in_syscall) {
>> + t->tv_sec = ctx->ctime.tv_sec;
>> + t->tv_nsec = ctx->ctime.tv_nsec;
>> + *serial = ctx->serial;
>> + return 1;
>> + }
>> if (!ctx->in_syscall)
>> return 0;
>> if (!ctx->serial)
>> @@ -2622,7 +2693,7 @@ void __audit_log_nfcfg(const char *name, u8 af, unsigned int nentries,
>> name, af, nentries, audit_nfcfgs[op].s);
>>
>> audit_log_format(ab, " pid=%u", task_pid_nr(current));
>> - audit_log_task_context(ab); /* subj= */
>> + audit_log_task_context(ab, NULL); /* subj= */
>> audit_log_format(ab, " comm=");
>> audit_log_untrustedstring(ab, get_task_comm(comm, current));
>> audit_log_end(ab);
>> @@ -2645,7 +2716,7 @@ static void audit_log_task(struct audit_buffer *ab)
>> from_kuid(&init_user_ns, uid),
>> from_kgid(&init_user_ns, gid),
>> sessionid);
>> - audit_log_task_context(ab);
>> + audit_log_task_context(ab, NULL);
>> audit_log_format(ab, " pid=%d comm=", task_tgid_nr(current));
>> audit_log_untrustedstring(ab, get_task_comm(comm, current));
>> audit_log_d_path_exe(ab, current->mm);
>> @@ -2668,11 +2739,13 @@ void audit_core_dumps(long signr)
>> if (signr == SIGQUIT) /* don't care for those */
>> return;
>>
>> + audit_stamp_context(audit_context());
>> ab = audit_log_start(audit_context(), GFP_KERNEL, AUDIT_ANOM_ABEND);
>> if (unlikely(!ab))
>> return;
>> audit_log_task(ab);
>> audit_log_format(ab, " sig=%ld res=1", signr);
>> + audit_log_lsm(NULL, true);
>> audit_log_end(ab);
>> }
>>
>> diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
>> index 58bf1f3532ae..16fa8f1fb4e0 100644
>> --- a/net/ipv4/ip_sockglue.c
>> +++ b/net/ipv4/ip_sockglue.c
>> @@ -138,7 +138,7 @@ static void ip_cmsg_recv_security(struct msghdr *msg, struct sk_buff *skb)
>> if (err)
>> return;
>>
>> - err = security_secid_to_secctx(&lb, &context);
>> + err = security_secid_to_secctx(&lb, &context, LSMBLOB_DISPLAY);
>> if (err)
>> return;
>>
>> diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
>> index e38b5182e301..3c90b9a488d5 100644
>> --- a/net/netfilter/nf_conntrack_netlink.c
>> +++ b/net/netfilter/nf_conntrack_netlink.c
>> @@ -339,7 +339,7 @@ static int ctnetlink_dump_secctx(struct sk_buff *skb, const struct nf_conn *ct)
>> * security_secid_to_secctx() will know which security module
>> * to use to create the secctx. */
>> lsmblob_init(&blob, ct->secmark);
>> - ret = security_secid_to_secctx(&blob, &context);
>> + ret = security_secid_to_secctx(&blob, &context, LSMBLOB_DISPLAY);
>> if (ret)
>> return 0;
>>
>> @@ -655,7 +655,7 @@ static inline int ctnetlink_secctx_size(const struct nf_conn *ct)
>> struct lsmblob blob;
>> struct lsmcontext context;
>>
>> - ret = security_secid_to_secctx(&blob, &context);
>> + ret = security_secid_to_secctx(&blob, &context, LSMBLOB_DISPLAY);
>> if (ret)
>> return 0;
>>
>> diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c
>> index 71bec249d23b..ca01bf2b73c2 100644
>> --- a/net/netfilter/nf_conntrack_standalone.c
>> +++ b/net/netfilter/nf_conntrack_standalone.c
>> @@ -177,7 +177,7 @@ static void ct_show_secctx(struct seq_file *s, const struct nf_conn *ct)
>> struct lsmcontext context;
>>
>> lsmblob_init(&blob, ct->secmark);
>> - ret = security_secid_to_secctx(&blob, &context);
>> + ret = security_secid_to_secctx(&blob, &context, LSMBLOB_DISPLAY);
>> if (ret)
>> return;
>>
>> diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
>> index c830401f7792..9c557f9091ab 100644
>> --- a/net/netfilter/nfnetlink_queue.c
>> +++ b/net/netfilter/nfnetlink_queue.c
>> @@ -316,7 +316,7 @@ static u32 nfqnl_get_sk_secctx(struct sk_buff *skb, struct lsmcontext *context)
>> * blob. security_secid_to_secctx() will know which security
>> * module to use to create the secctx. */
>> lsmblob_init(&blob, skb->secmark);
>> - security_secid_to_secctx(&blob, context);
>> + security_secid_to_secctx(&blob, context, LSMBLOB_DISPLAY);
>> }
>>
>> read_unlock_bh(&skb->sk->sk_callback_lock);
>> diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c
>> index c14a485ff045..99579fa49293 100644
>> --- a/net/netlabel/netlabel_unlabeled.c
>> +++ b/net/netlabel/netlabel_unlabeled.c
>> @@ -437,7 +437,8 @@ int netlbl_unlhsh_add(struct net *net,
>> unlhsh_add_return:
>> rcu_read_unlock();
>> if (audit_buf != NULL) {
>> - if (security_secid_to_secctx(lsmblob, &context) == 0) {
>> + if (security_secid_to_secctx(lsmblob, &context,
>> + LSMBLOB_FIRST) == 0) {
>> audit_log_format(audit_buf, " sec_obj=%s",
>> context.context);
>> security_release_secctx(&context);
>> @@ -492,7 +493,8 @@ static int netlbl_unlhsh_remove_addr4(struct net *net,
>> if (dev != NULL)
>> dev_put(dev);
>> if (entry != NULL &&
>> - security_secid_to_secctx(&entry->lsmblob, &context) == 0) {
>> + security_secid_to_secctx(&entry->lsmblob, &context,
>> + LSMBLOB_FIRST) == 0) {
>> audit_log_format(audit_buf, " sec_obj=%s",
>> context.context);
>> security_release_secctx(&context);
>> @@ -552,7 +554,8 @@ static int netlbl_unlhsh_remove_addr6(struct net *net,
>> if (dev != NULL)
>> dev_put(dev);
>> if (entry != NULL &&
>> - security_secid_to_secctx(&entry->lsmblob, &context) == 0) {
>> + security_secid_to_secctx(&entry->lsmblob, &context,
>> + LSMBLOB_FIRST) == 0) {
>> audit_log_format(audit_buf, " sec_obj=%s",
>> context.context);
>> security_release_secctx(&context);
>> @@ -1122,7 +1125,7 @@ static int netlbl_unlabel_staticlist_gen(u32 cmd,
>> lsmb = (struct lsmblob *)&addr6->lsmblob;
>> }
>>
>> - ret_val = security_secid_to_secctx(lsmb, &context);
>> + ret_val = security_secid_to_secctx(lsmb, &context, LSMBLOB_FIRST);
>> if (ret_val != 0)
>> goto list_cb_failure;
>> ret_val = nla_put(cb_arg->skb,
>> @@ -1521,14 +1524,11 @@ int __init netlbl_unlabel_defconf(void)
>> int ret_val;
>> struct netlbl_dom_map *entry;
>> struct netlbl_audit audit_info;
>> - struct lsmblob blob;
>>
>> /* Only the kernel is allowed to call this function and the only time
>> * it is called is at bootup before the audit subsystem is reporting
>> * messages so don't worry to much about these values. */
>> - security_task_getsecid(current, &blob);
>> - /* scaffolding until audit_info.secid is converted */
>> - audit_info.secid = blob.secid[0];
>> + security_task_getsecid(current, &audit_info.lsmdata);
>> audit_info.loginuid = GLOBAL_ROOT_UID;
>> audit_info.sessionid = 0;
>>
>> diff --git a/net/netlabel/netlabel_user.c b/net/netlabel/netlabel_user.c
>> index 951ba0639d20..4e9064754b5f 100644
>> --- a/net/netlabel/netlabel_user.c
>> +++ b/net/netlabel/netlabel_user.c
>> @@ -84,12 +84,12 @@ struct audit_buffer *netlbl_audit_start_common(int type,
>> struct netlbl_audit *audit_info)
>> {
>> struct audit_buffer *audit_buf;
>> - struct lsmcontext context;
>> - struct lsmblob blob;
>>
>> if (audit_enabled == AUDIT_OFF)
>> return NULL;
>>
>> + audit_stamp_context(audit_context());
>> +
>> audit_buf = audit_log_start(audit_context(), GFP_ATOMIC, type);
>> if (audit_buf == NULL)
>> return NULL;
>> @@ -98,12 +98,8 @@ struct audit_buffer *netlbl_audit_start_common(int type,
>> from_kuid(&init_user_ns, audit_info->loginuid),
>> audit_info->sessionid);
>>
>> - lsmblob_init(&blob, audit_info->secid);
>> - if (audit_info->secid != 0 &&
>> - security_secid_to_secctx(&blob, &context) == 0) {
>> - audit_log_format(audit_buf, " subj=%s", context.context);
>> - security_release_secctx(&context);
>> - }
>> + audit_log_task_context(audit_buf, &audit_info->lsmdata);
>> + audit_log_lsm(&audit_info->lsmdata, false);
>>
>> return audit_buf;
>> }
>> diff --git a/net/netlabel/netlabel_user.h b/net/netlabel/netlabel_user.h
>> index 438b5db6c714..bd4335443b87 100644
>> --- a/net/netlabel/netlabel_user.h
>> +++ b/net/netlabel/netlabel_user.h
>> @@ -34,11 +34,7 @@
>> static inline void netlbl_netlink_auditinfo(struct sk_buff *skb,
>> struct netlbl_audit *audit_info)
>> {
>> - struct lsmblob blob;
>> -
>> - security_task_getsecid(current, &blob);
>> - /* scaffolding until secid is converted */
>> - audit_info->secid = blob.secid[0];
>> + security_task_getsecid(current, &audit_info->lsmdata);
>> audit_info->loginuid = audit_get_loginuid(current);
>> audit_info->sessionid = audit_get_sessionid(current);
>> }
>> diff --git a/security/integrity/integrity_audit.c b/security/integrity/integrity_audit.c
>> index f25e7df099c8..418f7e45753d 100644
>> --- a/security/integrity/integrity_audit.c
>> +++ b/security/integrity/integrity_audit.c
>> @@ -50,7 +50,7 @@ void integrity_audit_message(int audit_msgno, struct inode *inode,
>> from_kuid(&init_user_ns, current_cred()->uid),
>> from_kuid(&init_user_ns, audit_get_loginuid(current)),
>> audit_get_sessionid(current));
>> - audit_log_task_context(ab);
>> + audit_log_task_context(ab, NULL);
>> audit_log_format(ab, " op=%s cause=%s comm=", op, cause);
>> audit_log_untrustedstring(ab, get_task_comm(name, current));
>> if (fname) {
>> diff --git a/security/security.c b/security/security.c
>> index 95b48721fb17..4752291376bf 100644
>> --- a/security/security.c
>> +++ b/security/security.c
>> @@ -480,7 +480,31 @@ static int lsm_append(const char *new, char **result)
>> * Pointers to the LSM id structures for local use.
>> */
>> static int lsm_slot __lsm_ro_after_init;
>> -static struct lsm_id *lsm_slotlist[LSMBLOB_ENTRIES];
>> +static struct lsm_id *lsm_slotlist[LSMBLOB_ENTRIES] __lsm_ro_after_init;
>> +
>> +/**
>> + * security_lsm_slot_name - Get the name of the security module in a slot
>> + * @slot: index into the "display" slot list.
>> + *
>> + * Provide the name of the security module associated with
>> + * a display slot.
>> + *
>> + * If @slot is LSMBLOB_INVALID return the value
>> + * for slot 0 if it has been set, otherwise NULL.
>> + *
>> + * Returns a pointer to the name string or NULL.
>> + */
>> +const char *security_lsm_slot_name(int slot)
>> +{
>> + if (slot == LSMBLOB_INVALID)
>> + slot = 0;
>> + else if (slot >= LSMBLOB_ENTRIES || slot < 0)
>> + return NULL;
>> +
>> + if (lsm_slotlist[slot] == NULL)
>> + return NULL;
>> + return lsm_slotlist[slot]->lsm;
>> +}
>>
>> /**
>> * security_add_hooks - Add a modules hooks to the hook lists.
>> @@ -2175,7 +2199,7 @@ int security_setprocattr(const char *lsm, const char *name, void *value,
>> hlist_for_each_entry(hp, &security_hook_heads.setprocattr,
>> list) {
>> rc = hp->hook.setprocattr(name, value, size);
>> - if (rc < 0)
>> + if (rc < 0 && rc != -EINVAL)
>> return rc;
>> }
>>
>> @@ -2220,13 +2244,32 @@ int security_ismaclabel(const char *name)
>> }
>> EXPORT_SYMBOL(security_ismaclabel);
>>
>> -int security_secid_to_secctx(struct lsmblob *blob, struct lsmcontext *cp)
>> +int security_secid_to_secctx(struct lsmblob *blob, struct lsmcontext *cp,
>> + int display)
>> {
>> struct security_hook_list *hp;
>> - int display = lsm_task_display(current);
>>
>> memset(cp, 0, sizeof(*cp));
>>
>> + /*
>> + * display either is the slot number use for formatting
>> + * or an instruction on which relative slot to use.
>> + */
>> + if (display == LSMBLOB_DISPLAY)
>> + display = lsm_task_display(current);
>> + else if (display == LSMBLOB_FIRST)
>> + display = LSMBLOB_INVALID;
>> + else if (display < 0) {
>> + WARN_ONCE(true,
>> + "LSM: %s unknown display\n", __func__);
>> + display = LSMBLOB_INVALID;
>> + } else if (display >= lsm_slot) {
>> + WARN_ONCE(true,
>> + "LSM: %s invalid display\n", __func__);
>> + display = LSMBLOB_INVALID;
>> + }
>> +
>> +
>> hlist_for_each_entry(hp, &security_hook_heads.secid_to_secctx, list) {
>> if (WARN_ON(hp->lsmid->slot < 0 || hp->lsmid->slot >= lsm_slot))
>> continue;
>> @@ -2256,7 +2299,7 @@ int security_secctx_to_secid(const char *secdata, u32 seclen,
>> return hp->hook.secctx_to_secid(secdata, seclen,
>> &blob->secid[hp->lsmid->slot]);
>> }
>> - return 0;
>> + return -EOPNOTSUPP;
>> }
>> EXPORT_SYMBOL(security_secctx_to_secid);
>>
>> @@ -2757,23 +2800,17 @@ int security_key_getsecurity(struct key *key, char **_buffer)
>> int security_audit_rule_init(u32 field, u32 op, char *rulestr, void **lsmrule)
>> {
>> struct security_hook_list *hp;
>> - bool one_is_good = false;
>> - int rc = 0;
>> - int trc;
>> + int display = lsm_task_display(current);
>>
>> hlist_for_each_entry(hp, &security_hook_heads.audit_rule_init, list) {
>> if (WARN_ON(hp->lsmid->slot < 0 || hp->lsmid->slot >= lsm_slot))
>> continue;
>> - trc = hp->hook.audit_rule_init(field, op, rulestr,
>> - &lsmrule[hp->lsmid->slot]);
>> - if (trc == 0)
>> - one_is_good = true;
>> - else
>> - rc = trc;
>> + if (display != LSMBLOB_INVALID && display != hp->lsmid->slot)
>> + continue;
>> + return hp->hook.audit_rule_init(field, op, rulestr,
>> + &lsmrule[hp->lsmid->slot]);
>> }
>> - if (one_is_good)
>> - return 0;
>> - return rc;
>> + return 0;
>> }
>>
>> int security_audit_rule_known(struct audit_krule *krule)
>> @@ -2805,6 +2842,8 @@ int security_audit_rule_match(struct lsmblob *blob, u32 field, u32 op,
>> continue;
>> if (lsmrule[hp->lsmid->slot] == NULL)
>> continue;
>> + if (lsmrule[hp->lsmid->slot] == NULL)
>> + continue;
>> rc = hp->hook.audit_rule_match(blob->secid[hp->lsmid->slot],
>> field, op,
>> &lsmrule[hp->lsmid->slot]);
>> diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
>> index dcabf6bd8faa..15fa4b7eb2e6 100644
>> --- a/security/smack/smackfs.c
>> +++ b/security/smack/smackfs.c
>> @@ -185,7 +185,8 @@ static void smk_netlabel_audit_set(struct netlbl_audit *nap)
>>
>> nap->loginuid = audit_get_loginuid(current);
>> nap->sessionid = audit_get_sessionid(current);
>> - nap->secid = skp->smk_secid;
>> + lsmblob_init(&nap->lsmdata, 0);
>> + nap->lsmdata.secid[smack_lsmid.slot] = skp->smk_secid;
>> }
>>
>> /*
>>
>
^ permalink raw reply
* Re: [PATCH v20 20/23] Audit: Add new record for multiple process LSM attributes
From: James Morris @ 2020-09-03 16:32 UTC (permalink / raw)
To: Casey Schaufler
Cc: casey.schaufler, linux-security-module, selinux, linux-audit,
keescook, john.johansen, penguin-kernel, paul, sds
In-Reply-To: <20200826145247.10029-21-casey@schaufler-ca.com>
On Wed, 26 Aug 2020, Casey Schaufler wrote:
> Create a new audit record type to contain the subject information
> when there are multiple security modules that require such data.
> This record is linked with the same timestamp and serial number.
> The record is produced only in cases where there is more than one
> security module with a process "context".
>
> Before this change the only audit events that required multiple
> records were syscall events. Several non-syscall events include
> subject contexts, so the use of audit_context data has been expanded
> as necessary.
>
> Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
> Cc: linux-audit@redhat.com
Paul, can you review/ack the audit changes?
> ---
> drivers/android/binder.c | 2 +-
> include/linux/audit.h | 13 +++-
> include/linux/security.h | 18 ++++-
> include/net/netlabel.h | 2 +-
> include/net/scm.h | 3 +-
> include/net/xfrm.h | 4 +-
> include/uapi/linux/audit.h | 1 +
> kernel/audit.c | 89 ++++++++++++++++++-------
> kernel/auditfilter.c | 2 +-
> kernel/auditsc.c | 87 ++++++++++++++++++++++--
> net/ipv4/ip_sockglue.c | 2 +-
> net/netfilter/nf_conntrack_netlink.c | 4 +-
> net/netfilter/nf_conntrack_standalone.c | 2 +-
> net/netfilter/nfnetlink_queue.c | 2 +-
> net/netlabel/netlabel_unlabeled.c | 16 ++---
> net/netlabel/netlabel_user.c | 12 ++--
> net/netlabel/netlabel_user.h | 6 +-
> security/integrity/integrity_audit.c | 2 +-
> security/security.c | 73 +++++++++++++++-----
> security/smack/smackfs.c | 3 +-
> 20 files changed, 259 insertions(+), 84 deletions(-)
>
> diff --git a/drivers/android/binder.c b/drivers/android/binder.c
> index 0bde1b96680e..93781dad0c28 100644
> --- a/drivers/android/binder.c
> +++ b/drivers/android/binder.c
> @@ -3113,7 +3113,7 @@ static void binder_transaction(struct binder_proc *proc,
> size_t added_size;
>
> security_task_getsecid(proc->tsk, &blob);
> - ret = security_secid_to_secctx(&blob, &lsmctx);
> + ret = security_secid_to_secctx(&blob, &lsmctx, LSMBLOB_DISPLAY);
> if (ret) {
> return_error = BR_FAILED_REPLY;
> return_error_param = ret;
> diff --git a/include/linux/audit.h b/include/linux/audit.h
> index ba1cd38d601b..fe027df0d9a8 100644
> --- a/include/linux/audit.h
> +++ b/include/linux/audit.h
> @@ -186,7 +186,9 @@ extern void audit_log_path_denied(int type,
> const char *operation);
> extern void audit_log_lost(const char *message);
>
> -extern int audit_log_task_context(struct audit_buffer *ab);
> +extern void audit_log_lsm(struct lsmblob *blob, bool exiting);
> +extern int audit_log_task_context(struct audit_buffer *ab,
> + struct lsmblob *blob);
> extern void audit_log_task_info(struct audit_buffer *ab);
>
> extern int audit_update_lsm_rules(void);
> @@ -246,7 +248,10 @@ static inline void audit_log_key(struct audit_buffer *ab, char *key)
> { }
> static inline void audit_log_path_denied(int type, const char *operation)
> { }
> -static inline int audit_log_task_context(struct audit_buffer *ab)
> +static inline void audit_log_lsm(struct lsmblob *blob, bool exiting)
> +{ }
> +static inline int audit_log_task_context(struct audit_buffer *ab,
> + struct lsmblob *blob);
> {
> return 0;
> }
> @@ -305,6 +310,7 @@ extern void audit_seccomp(unsigned long syscall, long signr, int code);
> extern void audit_seccomp_actions_logged(const char *names,
> const char *old_names, int res);
> extern void __audit_ptrace(struct task_struct *t);
> +extern void audit_stamp_context(struct audit_context *ctx);
>
> static inline void audit_set_context(struct task_struct *task, struct audit_context *ctx)
> {
> @@ -682,6 +688,9 @@ static inline void audit_ntp_log(const struct audit_ntp_data *ad)
> static inline void audit_ptrace(struct task_struct *t)
> { }
>
> +static inline void audit_stamp_context(struct audit_context *ctx)
> +{ }
> +
> static inline void audit_log_nfcfg(const char *name, u8 af,
> unsigned int nentries,
> enum audit_nfcfgop op, gfp_t gfp)
> diff --git a/include/linux/security.h b/include/linux/security.h
> index 40260bfc3a0d..3cbe24be1563 100644
> --- a/include/linux/security.h
> +++ b/include/linux/security.h
> @@ -180,6 +180,8 @@ struct lsmblob {
> #define LSMBLOB_INVALID -1 /* Not a valid LSM slot number */
> #define LSMBLOB_NEEDED -2 /* Slot requested on initialization */
> #define LSMBLOB_NOT_NEEDED -3 /* Slot not requested */
> +#define LSMBLOB_DISPLAY -4 /* Use the "display" slot */
> +#define LSMBLOB_FIRST -5 /* Use the default "display" slot */
>
> /**
> * lsmblob_init - initialize an lsmblob structure.
> @@ -242,6 +244,17 @@ static inline u32 lsmblob_value(const struct lsmblob *blob)
> return 0;
> }
>
> +const char *security_lsm_slot_name(int slot);
> +
> +static inline bool lsm_multiple_contexts(void)
> +{
> +#ifdef CONFIG_SECURITY
> + return security_lsm_slot_name(1) != NULL;
> +#else
> + return false;
> +#endif
> +}
> +
> /* These functions are in security/commoncap.c */
> extern int cap_capable(const struct cred *cred, struct user_namespace *ns,
> int cap, unsigned int opts);
> @@ -554,7 +567,8 @@ int security_setprocattr(const char *lsm, const char *name, void *value,
> size_t size);
> int security_netlink_send(struct sock *sk, struct sk_buff *skb);
> int security_ismaclabel(const char *name);
> -int security_secid_to_secctx(struct lsmblob *blob, struct lsmcontext *cp);
> +int security_secid_to_secctx(struct lsmblob *blob, struct lsmcontext *cp,
> + int display);
> int security_secctx_to_secid(const char *secdata, u32 seclen,
> struct lsmblob *blob);
> void security_release_secctx(struct lsmcontext *cp);
> @@ -1372,7 +1386,7 @@ static inline int security_ismaclabel(const char *name)
> }
>
> static inline int security_secid_to_secctx(struct lsmblob *blob,
> - struct lsmcontext *cp)
> + struct lsmcontext *cp, int display)
> {
> return -EOPNOTSUPP;
> }
> diff --git a/include/net/netlabel.h b/include/net/netlabel.h
> index 73fc25b4042b..216cb1ffc8f0 100644
> --- a/include/net/netlabel.h
> +++ b/include/net/netlabel.h
> @@ -97,7 +97,7 @@ struct calipso_doi;
>
> /* NetLabel audit information */
> struct netlbl_audit {
> - u32 secid;
> + struct lsmblob lsmdata;
> kuid_t loginuid;
> unsigned int sessionid;
> };
> diff --git a/include/net/scm.h b/include/net/scm.h
> index 4a6ad8caf423..8b5a4737e1b8 100644
> --- a/include/net/scm.h
> +++ b/include/net/scm.h
> @@ -96,7 +96,8 @@ static inline void scm_passec(struct socket *sock, struct msghdr *msg, struct sc
> int err;
>
> if (test_bit(SOCK_PASSSEC, &sock->flags)) {
> - err = security_secid_to_secctx(&scm->lsmblob, &context);
> + err = security_secid_to_secctx(&scm->lsmblob, &context,
> + LSMBLOB_DISPLAY);
>
> if (!err) {
> put_cmsg(msg, SOL_SOCKET, SCM_SECURITY,
> diff --git a/include/net/xfrm.h b/include/net/xfrm.h
> index 2737d24ec244..9e8cac6228b4 100644
> --- a/include/net/xfrm.h
> +++ b/include/net/xfrm.h
> @@ -675,11 +675,13 @@ static inline struct audit_buffer *xfrm_audit_start(const char *op)
>
> if (audit_enabled == AUDIT_OFF)
> return NULL;
> + audit_stamp_context(audit_context());
> audit_buf = audit_log_start(audit_context(), GFP_ATOMIC,
> AUDIT_MAC_IPSEC_EVENT);
> if (audit_buf == NULL)
> return NULL;
> audit_log_format(audit_buf, "op=%s", op);
> + audit_log_lsm(NULL, false);
> return audit_buf;
> }
>
> @@ -693,7 +695,7 @@ static inline void xfrm_audit_helper_usrinfo(bool task_valid,
> AUDIT_SID_UNSET;
>
> audit_log_format(audit_buf, " auid=%u ses=%u", auid, ses);
> - audit_log_task_context(audit_buf);
> + audit_log_task_context(audit_buf, NULL);
> }
>
> void xfrm_audit_policy_add(struct xfrm_policy *xp, int result, bool task_valid);
> diff --git a/include/uapi/linux/audit.h b/include/uapi/linux/audit.h
> index cd2d8279a5e4..2a63720e56f6 100644
> --- a/include/uapi/linux/audit.h
> +++ b/include/uapi/linux/audit.h
> @@ -139,6 +139,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_MAC_TASK_CONTEXTS 1420 /* Multiple LSM contexts */
>
> #define AUDIT_FIRST_KERN_ANOM_MSG 1700
> #define AUDIT_LAST_KERN_ANOM_MSG 1799
> diff --git a/kernel/audit.c b/kernel/audit.c
> index 594b42fc88ff..0e7831c9f321 100644
> --- a/kernel/audit.c
> +++ b/kernel/audit.c
> @@ -394,10 +394,11 @@ static int audit_log_config_change(char *function_name, u32 new, u32 old,
> return rc;
> audit_log_format(ab, "op=set %s=%u old=%u ", function_name, new, old);
> audit_log_session_info(ab);
> - rc = audit_log_task_context(ab);
> + rc = audit_log_task_context(ab, NULL);
> if (rc)
> allow_changes = 0; /* Something weird, deny request */
> audit_log_format(ab, " res=%d", allow_changes);
> + audit_log_lsm(NULL, false);
> audit_log_end(ab);
> return rc;
> }
> @@ -1070,13 +1071,31 @@ static void audit_log_common_recv_msg(struct audit_context *context,
> return;
> audit_log_format(*ab, "pid=%d uid=%u ", pid, uid);
> audit_log_session_info(*ab);
> - audit_log_task_context(*ab);
> + audit_log_task_context(*ab, NULL);
> }
>
> static inline void audit_log_user_recv_msg(struct audit_buffer **ab,
> u16 msg_type)
> {
> - audit_log_common_recv_msg(NULL, ab, msg_type);
> + struct audit_context *context;
> +
> + if (!lsm_multiple_contexts()) {
> + audit_log_common_recv_msg(NULL, ab, msg_type);
> + return;
> + }
> +
> + context = audit_context();
> + if (context) {
> + if (!context->in_syscall)
> + audit_stamp_context(context);
> + audit_log_common_recv_msg(context, ab, msg_type);
> + return;
> + }
> +
> + audit_alloc(current);
> + context = audit_context();
> +
> + audit_log_common_recv_msg(context, ab, msg_type);
> }
>
> int is_audit_feature_set(int i)
> @@ -1372,6 +1391,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
> audit_log_n_untrustedstring(ab, str, data_len);
> }
> audit_log_end(ab);
> + audit_log_lsm(NULL, false);
> }
> break;
> case AUDIT_ADD_RULE:
> @@ -1444,7 +1464,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
>
> if (lsmblob_is_set(&audit_sig_lsm)) {
> err = security_secid_to_secctx(&audit_sig_lsm,
> - &context);
> + &context, LSMBLOB_FIRST);
> if (err)
> return err;
> }
> @@ -1572,7 +1592,7 @@ static void audit_log_multicast(int group, const char *op, int err)
> tty ? tty_name(tty) : "(none)",
> audit_get_sessionid(current));
> audit_put_tty(tty);
> - audit_log_task_context(ab); /* subj= */
> + audit_log_task_context(ab, NULL); /* subj= */
> audit_log_format(ab, " comm=");
> audit_log_untrustedstring(ab, get_task_comm(comm, current));
> audit_log_d_path_exe(ab, current->mm); /* exe= */
> @@ -1869,6 +1889,10 @@ struct audit_buffer *audit_log_start(struct audit_context *ctx, gfp_t gfp_mask,
> }
>
> audit_get_stamp(ab->ctx, &t, &serial);
> + if (type == AUDIT_MAC_TASK_CONTEXTS && ab->ctx->serial == 0) {
> + audit_stamp_context(ab->ctx);
> + audit_get_stamp(ab->ctx, &t, &serial);
> + }
> audit_log_format(ab, "audit(%llu.%03lu:%u): ",
> (unsigned long long)t.tv_sec, t.tv_nsec/1000000, serial);
>
> @@ -2126,30 +2150,47 @@ void audit_log_key(struct audit_buffer *ab, char *key)
> audit_log_format(ab, "(null)");
> }
>
> -int audit_log_task_context(struct audit_buffer *ab)
> +int audit_log_task_context(struct audit_buffer *ab, struct lsmblob *blob)
> {
> + int i;
> int error;
> - struct lsmblob blob;
> - struct lsmcontext context;
> + struct lsmblob localblob;
> + struct lsmcontext lsmdata;
>
> - security_task_getsecid(current, &blob);
> - if (!lsmblob_is_set(&blob))
> + /*
> + * If there is more than one security module that has a
> + * subject "context" it's necessary to put the subject data
> + * into a separate record to maintain compatibility.
> + */
> + if (lsm_multiple_contexts()) {
> + audit_log_format(ab, " subj=?");
> return 0;
> + }
>
> - error = security_secid_to_secctx(&blob, &context);
> - if (error) {
> - if (error != -EINVAL)
> - goto error_path;
> - return 0;
> + if (blob == NULL) {
> + security_task_getsecid(current, &localblob);
> + if (!lsmblob_is_set(&localblob)) {
> + audit_log_format(ab, " subj=?");
> + return 0;
> + }
> + blob = &localblob;
> }
>
> - audit_log_format(ab, " subj=%s", context.context);
> - security_release_secctx(&context);
> - return 0;
> + for (i = 0; i < LSMBLOB_ENTRIES; i++) {
> + if (blob->secid[i] == 0)
> + continue;
> + error = security_secid_to_secctx(blob, &lsmdata, i);
> + if (error && error != -EINVAL) {
> + audit_panic("error in audit_log_task_context");
> + return error;
> + }
>
> -error_path:
> - audit_panic("error in audit_log_task_context");
> - return error;
> + audit_log_format(ab, " subj=%s", lsmdata.context);
> + security_release_secctx(&lsmdata);
> + break;
> + }
> +
> + return 0;
> }
> EXPORT_SYMBOL(audit_log_task_context);
>
> @@ -2221,7 +2262,7 @@ void audit_log_task_info(struct audit_buffer *ab)
> audit_log_format(ab, " comm=");
> audit_log_untrustedstring(ab, get_task_comm(comm, current));
> audit_log_d_path_exe(ab, current->mm);
> - audit_log_task_context(ab);
> + audit_log_task_context(ab, NULL);
> }
> EXPORT_SYMBOL(audit_log_task_info);
>
> @@ -2279,6 +2320,7 @@ static void audit_log_set_loginuid(kuid_t koldloginuid, kuid_t kloginuid,
> if (!audit_enabled)
> return;
>
> + audit_stamp_context(audit_context());
> ab = audit_log_start(audit_context(), GFP_KERNEL, AUDIT_LOGIN);
> if (!ab)
> return;
> @@ -2289,11 +2331,12 @@ static void audit_log_set_loginuid(kuid_t koldloginuid, kuid_t kloginuid,
> tty = audit_get_tty();
>
> audit_log_format(ab, "pid=%d uid=%u", task_tgid_nr(current), uid);
> - audit_log_task_context(ab);
> + audit_log_task_context(ab, NULL);
> audit_log_format(ab, " old-auid=%u auid=%u tty=%s old-ses=%u ses=%u res=%d",
> oldloginuid, loginuid, tty ? tty_name(tty) : "(none)",
> oldsessionid, sessionid, !rc);
> audit_put_tty(tty);
> + audit_log_lsm(NULL, true);
> audit_log_end(ab);
> }
>
> diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
> index 31732023b689..6c03e463668e 100644
> --- a/kernel/auditfilter.c
> +++ b/kernel/auditfilter.c
> @@ -1107,7 +1107,7 @@ static void audit_log_rule_change(char *action, struct audit_krule *rule, int re
> if (!ab)
> return;
> audit_log_session_info(ab);
> - audit_log_task_context(ab);
> + audit_log_task_context(ab, NULL);
> audit_log_format(ab, " op=%s", action);
> audit_log_key(ab, rule->filterkey);
> audit_log_format(ab, " list=%d res=%d", rule->listnr, res);
> diff --git a/kernel/auditsc.c b/kernel/auditsc.c
> index 4af5861bcb9a..cf5dbd0e3a3d 100644
> --- a/kernel/auditsc.c
> +++ b/kernel/auditsc.c
> @@ -473,7 +473,7 @@ static int audit_filter_rules(struct task_struct *tsk,
> {
> const struct cred *cred;
> int i, need_sid = 1;
> - struct lsmblob blob;
> + struct lsmblob blob = { };
> unsigned int sessionid;
>
> cred = rcu_dereference_check(tsk->cred, tsk == current || task_creation);
> @@ -962,10 +962,12 @@ int audit_alloc(struct task_struct *tsk)
> return 0; /* Return if not auditing. */
>
> state = audit_filter_task(tsk, &key);
> - if (state == AUDIT_DISABLED) {
> + if (!lsm_multiple_contexts() && state == AUDIT_DISABLED) {
> clear_tsk_thread_flag(tsk, TIF_SYSCALL_AUDIT);
> return 0;
> }
> + if (state == AUDIT_DISABLED)
> + clear_tsk_thread_flag(tsk, TIF_SYSCALL_AUDIT);
>
> if (!(context = audit_alloc_context(state))) {
> kfree(key);
> @@ -1009,7 +1011,7 @@ static int audit_log_pid_context(struct audit_context *context, pid_t pid,
> from_kuid(&init_user_ns, auid),
> from_kuid(&init_user_ns, uid), sessionid);
> if (lsmblob_is_set(blob)) {
> - if (security_secid_to_secctx(blob, &lsmctx)) {
> + if (security_secid_to_secctx(blob, &lsmctx, LSMBLOB_FIRST)) {
> audit_log_format(ab, " obj=(none)");
> rc = 1;
> } else {
> @@ -1254,7 +1256,8 @@ static void show_special(struct audit_context *context, int *call_panic)
> struct lsmblob blob;
>
> lsmblob_init(&blob, osid);
> - if (security_secid_to_secctx(&blob, &lsmcxt)) {
> + if (security_secid_to_secctx(&blob, &lsmcxt,
> + LSMBLOB_FIRST)) {
> audit_log_format(ab, " osid=%u", osid);
> *call_panic = 1;
> } else {
> @@ -1406,7 +1409,7 @@ static void audit_log_name(struct audit_context *context, struct audit_names *n,
> struct lsmcontext lsmctx;
>
> lsmblob_init(&blob, n->osid);
> - if (security_secid_to_secctx(&blob, &lsmctx)) {
> + if (security_secid_to_secctx(&blob, &lsmctx, LSMBLOB_FIRST)) {
> audit_log_format(ab, " osid=%u", n->osid);
> if (call_panic)
> *call_panic = 2;
> @@ -1483,6 +1486,52 @@ static void audit_log_proctitle(void)
> audit_log_end(ab);
> }
>
> +void audit_log_lsm(struct lsmblob *blob, bool exiting)
> +{
> + struct audit_context *context = audit_context();
> + struct lsmcontext lsmdata;
> + struct audit_buffer *ab;
> + struct lsmblob localblob;
> + bool sep = false;
> + int error;
> + int i;
> +
> + if (!lsm_multiple_contexts())
> + return;
> +
> + if (context && context->in_syscall && !exiting)
> + return;
> +
> + ab = audit_log_start(context, GFP_ATOMIC, AUDIT_MAC_TASK_CONTEXTS);
> + if (!ab)
> + return; /* audit_panic or being filtered */
> +
> + if (blob == NULL) {
> + security_task_getsecid(current, &localblob);
> + if (!lsmblob_is_set(&localblob))
> + return;
> + blob = &localblob;
> + }
> +
> + for (i = 0; i < LSMBLOB_ENTRIES; i++) {
> + if (blob->secid[i] == 0)
> + continue;
> + error = security_secid_to_secctx(blob, &lsmdata, i);
> + if (error && error != -EINVAL) {
> + audit_panic("error in audit_log_lsm");
> + return;
> + }
> +
> + audit_log_format(ab, "%ssubj_%s=%s", sep ? " " : "",
> + security_lsm_slot_name(i), lsmdata.context);
> + sep = true;
> +
> + security_release_secctx(&lsmdata);
> + }
> +
> + audit_log_end(ab);
> +}
> +
> static void audit_log_exit(void)
> {
> int i, call_panic = 0;
> @@ -1606,6 +1655,7 @@ static void audit_log_exit(void)
> }
>
> audit_log_proctitle();
> + audit_log_lsm(NULL, true);
>
> /* Send end of event record to help user space know we are finished */
> ab = audit_log_start(context, GFP_KERNEL, AUDIT_EOE);
> @@ -2217,6 +2267,21 @@ void __audit_inode_child(struct inode *parent,
> }
> EXPORT_SYMBOL_GPL(__audit_inode_child);
>
> +/**
> + * audit_stamp_context - set the timestamp+serial in an audit context
> + * @ctx: audit_context to set
> + */
> +void audit_stamp_context(struct audit_context *ctx)
> +{
> + /* ctx will be NULL unless lsm_multiple_contexts() is true */
> + if (!ctx)
> + return;
> +
> + ktime_get_coarse_real_ts64(&ctx->ctime);
> + ctx->serial = audit_serial();
> + ctx->current_state = AUDIT_BUILD_CONTEXT;
> +}
> +
> /**
> * auditsc_get_stamp - get local copies of audit_context values
> * @ctx: audit_context for the task
> @@ -2228,6 +2293,12 @@ EXPORT_SYMBOL_GPL(__audit_inode_child);
> int auditsc_get_stamp(struct audit_context *ctx,
> struct timespec64 *t, unsigned int *serial)
> {
> + if (ctx->serial && !ctx->in_syscall) {
> + t->tv_sec = ctx->ctime.tv_sec;
> + t->tv_nsec = ctx->ctime.tv_nsec;
> + *serial = ctx->serial;
> + return 1;
> + }
> if (!ctx->in_syscall)
> return 0;
> if (!ctx->serial)
> @@ -2622,7 +2693,7 @@ void __audit_log_nfcfg(const char *name, u8 af, unsigned int nentries,
> name, af, nentries, audit_nfcfgs[op].s);
>
> audit_log_format(ab, " pid=%u", task_pid_nr(current));
> - audit_log_task_context(ab); /* subj= */
> + audit_log_task_context(ab, NULL); /* subj= */
> audit_log_format(ab, " comm=");
> audit_log_untrustedstring(ab, get_task_comm(comm, current));
> audit_log_end(ab);
> @@ -2645,7 +2716,7 @@ static void audit_log_task(struct audit_buffer *ab)
> from_kuid(&init_user_ns, uid),
> from_kgid(&init_user_ns, gid),
> sessionid);
> - audit_log_task_context(ab);
> + audit_log_task_context(ab, NULL);
> audit_log_format(ab, " pid=%d comm=", task_tgid_nr(current));
> audit_log_untrustedstring(ab, get_task_comm(comm, current));
> audit_log_d_path_exe(ab, current->mm);
> @@ -2668,11 +2739,13 @@ void audit_core_dumps(long signr)
> if (signr == SIGQUIT) /* don't care for those */
> return;
>
> + audit_stamp_context(audit_context());
> ab = audit_log_start(audit_context(), GFP_KERNEL, AUDIT_ANOM_ABEND);
> if (unlikely(!ab))
> return;
> audit_log_task(ab);
> audit_log_format(ab, " sig=%ld res=1", signr);
> + audit_log_lsm(NULL, true);
> audit_log_end(ab);
> }
>
> diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
> index 58bf1f3532ae..16fa8f1fb4e0 100644
> --- a/net/ipv4/ip_sockglue.c
> +++ b/net/ipv4/ip_sockglue.c
> @@ -138,7 +138,7 @@ static void ip_cmsg_recv_security(struct msghdr *msg, struct sk_buff *skb)
> if (err)
> return;
>
> - err = security_secid_to_secctx(&lb, &context);
> + err = security_secid_to_secctx(&lb, &context, LSMBLOB_DISPLAY);
> if (err)
> return;
>
> diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
> index e38b5182e301..3c90b9a488d5 100644
> --- a/net/netfilter/nf_conntrack_netlink.c
> +++ b/net/netfilter/nf_conntrack_netlink.c
> @@ -339,7 +339,7 @@ static int ctnetlink_dump_secctx(struct sk_buff *skb, const struct nf_conn *ct)
> * security_secid_to_secctx() will know which security module
> * to use to create the secctx. */
> lsmblob_init(&blob, ct->secmark);
> - ret = security_secid_to_secctx(&blob, &context);
> + ret = security_secid_to_secctx(&blob, &context, LSMBLOB_DISPLAY);
> if (ret)
> return 0;
>
> @@ -655,7 +655,7 @@ static inline int ctnetlink_secctx_size(const struct nf_conn *ct)
> struct lsmblob blob;
> struct lsmcontext context;
>
> - ret = security_secid_to_secctx(&blob, &context);
> + ret = security_secid_to_secctx(&blob, &context, LSMBLOB_DISPLAY);
> if (ret)
> return 0;
>
> diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c
> index 71bec249d23b..ca01bf2b73c2 100644
> --- a/net/netfilter/nf_conntrack_standalone.c
> +++ b/net/netfilter/nf_conntrack_standalone.c
> @@ -177,7 +177,7 @@ static void ct_show_secctx(struct seq_file *s, const struct nf_conn *ct)
> struct lsmcontext context;
>
> lsmblob_init(&blob, ct->secmark);
> - ret = security_secid_to_secctx(&blob, &context);
> + ret = security_secid_to_secctx(&blob, &context, LSMBLOB_DISPLAY);
> if (ret)
> return;
>
> diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
> index c830401f7792..9c557f9091ab 100644
> --- a/net/netfilter/nfnetlink_queue.c
> +++ b/net/netfilter/nfnetlink_queue.c
> @@ -316,7 +316,7 @@ static u32 nfqnl_get_sk_secctx(struct sk_buff *skb, struct lsmcontext *context)
> * blob. security_secid_to_secctx() will know which security
> * module to use to create the secctx. */
> lsmblob_init(&blob, skb->secmark);
> - security_secid_to_secctx(&blob, context);
> + security_secid_to_secctx(&blob, context, LSMBLOB_DISPLAY);
> }
>
> read_unlock_bh(&skb->sk->sk_callback_lock);
> diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c
> index c14a485ff045..99579fa49293 100644
> --- a/net/netlabel/netlabel_unlabeled.c
> +++ b/net/netlabel/netlabel_unlabeled.c
> @@ -437,7 +437,8 @@ int netlbl_unlhsh_add(struct net *net,
> unlhsh_add_return:
> rcu_read_unlock();
> if (audit_buf != NULL) {
> - if (security_secid_to_secctx(lsmblob, &context) == 0) {
> + if (security_secid_to_secctx(lsmblob, &context,
> + LSMBLOB_FIRST) == 0) {
> audit_log_format(audit_buf, " sec_obj=%s",
> context.context);
> security_release_secctx(&context);
> @@ -492,7 +493,8 @@ static int netlbl_unlhsh_remove_addr4(struct net *net,
> if (dev != NULL)
> dev_put(dev);
> if (entry != NULL &&
> - security_secid_to_secctx(&entry->lsmblob, &context) == 0) {
> + security_secid_to_secctx(&entry->lsmblob, &context,
> + LSMBLOB_FIRST) == 0) {
> audit_log_format(audit_buf, " sec_obj=%s",
> context.context);
> security_release_secctx(&context);
> @@ -552,7 +554,8 @@ static int netlbl_unlhsh_remove_addr6(struct net *net,
> if (dev != NULL)
> dev_put(dev);
> if (entry != NULL &&
> - security_secid_to_secctx(&entry->lsmblob, &context) == 0) {
> + security_secid_to_secctx(&entry->lsmblob, &context,
> + LSMBLOB_FIRST) == 0) {
> audit_log_format(audit_buf, " sec_obj=%s",
> context.context);
> security_release_secctx(&context);
> @@ -1122,7 +1125,7 @@ static int netlbl_unlabel_staticlist_gen(u32 cmd,
> lsmb = (struct lsmblob *)&addr6->lsmblob;
> }
>
> - ret_val = security_secid_to_secctx(lsmb, &context);
> + ret_val = security_secid_to_secctx(lsmb, &context, LSMBLOB_FIRST);
> if (ret_val != 0)
> goto list_cb_failure;
> ret_val = nla_put(cb_arg->skb,
> @@ -1521,14 +1524,11 @@ int __init netlbl_unlabel_defconf(void)
> int ret_val;
> struct netlbl_dom_map *entry;
> struct netlbl_audit audit_info;
> - struct lsmblob blob;
>
> /* Only the kernel is allowed to call this function and the only time
> * it is called is at bootup before the audit subsystem is reporting
> * messages so don't worry to much about these values. */
> - security_task_getsecid(current, &blob);
> - /* scaffolding until audit_info.secid is converted */
> - audit_info.secid = blob.secid[0];
> + security_task_getsecid(current, &audit_info.lsmdata);
> audit_info.loginuid = GLOBAL_ROOT_UID;
> audit_info.sessionid = 0;
>
> diff --git a/net/netlabel/netlabel_user.c b/net/netlabel/netlabel_user.c
> index 951ba0639d20..4e9064754b5f 100644
> --- a/net/netlabel/netlabel_user.c
> +++ b/net/netlabel/netlabel_user.c
> @@ -84,12 +84,12 @@ struct audit_buffer *netlbl_audit_start_common(int type,
> struct netlbl_audit *audit_info)
> {
> struct audit_buffer *audit_buf;
> - struct lsmcontext context;
> - struct lsmblob blob;
>
> if (audit_enabled == AUDIT_OFF)
> return NULL;
>
> + audit_stamp_context(audit_context());
> +
> audit_buf = audit_log_start(audit_context(), GFP_ATOMIC, type);
> if (audit_buf == NULL)
> return NULL;
> @@ -98,12 +98,8 @@ struct audit_buffer *netlbl_audit_start_common(int type,
> from_kuid(&init_user_ns, audit_info->loginuid),
> audit_info->sessionid);
>
> - lsmblob_init(&blob, audit_info->secid);
> - if (audit_info->secid != 0 &&
> - security_secid_to_secctx(&blob, &context) == 0) {
> - audit_log_format(audit_buf, " subj=%s", context.context);
> - security_release_secctx(&context);
> - }
> + audit_log_task_context(audit_buf, &audit_info->lsmdata);
> + audit_log_lsm(&audit_info->lsmdata, false);
>
> return audit_buf;
> }
> diff --git a/net/netlabel/netlabel_user.h b/net/netlabel/netlabel_user.h
> index 438b5db6c714..bd4335443b87 100644
> --- a/net/netlabel/netlabel_user.h
> +++ b/net/netlabel/netlabel_user.h
> @@ -34,11 +34,7 @@
> static inline void netlbl_netlink_auditinfo(struct sk_buff *skb,
> struct netlbl_audit *audit_info)
> {
> - struct lsmblob blob;
> -
> - security_task_getsecid(current, &blob);
> - /* scaffolding until secid is converted */
> - audit_info->secid = blob.secid[0];
> + security_task_getsecid(current, &audit_info->lsmdata);
> audit_info->loginuid = audit_get_loginuid(current);
> audit_info->sessionid = audit_get_sessionid(current);
> }
> diff --git a/security/integrity/integrity_audit.c b/security/integrity/integrity_audit.c
> index f25e7df099c8..418f7e45753d 100644
> --- a/security/integrity/integrity_audit.c
> +++ b/security/integrity/integrity_audit.c
> @@ -50,7 +50,7 @@ void integrity_audit_message(int audit_msgno, struct inode *inode,
> from_kuid(&init_user_ns, current_cred()->uid),
> from_kuid(&init_user_ns, audit_get_loginuid(current)),
> audit_get_sessionid(current));
> - audit_log_task_context(ab);
> + audit_log_task_context(ab, NULL);
> audit_log_format(ab, " op=%s cause=%s comm=", op, cause);
> audit_log_untrustedstring(ab, get_task_comm(name, current));
> if (fname) {
> diff --git a/security/security.c b/security/security.c
> index 95b48721fb17..4752291376bf 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -480,7 +480,31 @@ static int lsm_append(const char *new, char **result)
> * Pointers to the LSM id structures for local use.
> */
> static int lsm_slot __lsm_ro_after_init;
> -static struct lsm_id *lsm_slotlist[LSMBLOB_ENTRIES];
> +static struct lsm_id *lsm_slotlist[LSMBLOB_ENTRIES] __lsm_ro_after_init;
> +
> +/**
> + * security_lsm_slot_name - Get the name of the security module in a slot
> + * @slot: index into the "display" slot list.
> + *
> + * Provide the name of the security module associated with
> + * a display slot.
> + *
> + * If @slot is LSMBLOB_INVALID return the value
> + * for slot 0 if it has been set, otherwise NULL.
> + *
> + * Returns a pointer to the name string or NULL.
> + */
> +const char *security_lsm_slot_name(int slot)
> +{
> + if (slot == LSMBLOB_INVALID)
> + slot = 0;
> + else if (slot >= LSMBLOB_ENTRIES || slot < 0)
> + return NULL;
> +
> + if (lsm_slotlist[slot] == NULL)
> + return NULL;
> + return lsm_slotlist[slot]->lsm;
> +}
>
> /**
> * security_add_hooks - Add a modules hooks to the hook lists.
> @@ -2175,7 +2199,7 @@ int security_setprocattr(const char *lsm, const char *name, void *value,
> hlist_for_each_entry(hp, &security_hook_heads.setprocattr,
> list) {
> rc = hp->hook.setprocattr(name, value, size);
> - if (rc < 0)
> + if (rc < 0 && rc != -EINVAL)
> return rc;
> }
>
> @@ -2220,13 +2244,32 @@ int security_ismaclabel(const char *name)
> }
> EXPORT_SYMBOL(security_ismaclabel);
>
> -int security_secid_to_secctx(struct lsmblob *blob, struct lsmcontext *cp)
> +int security_secid_to_secctx(struct lsmblob *blob, struct lsmcontext *cp,
> + int display)
> {
> struct security_hook_list *hp;
> - int display = lsm_task_display(current);
>
> memset(cp, 0, sizeof(*cp));
>
> + /*
> + * display either is the slot number use for formatting
> + * or an instruction on which relative slot to use.
> + */
> + if (display == LSMBLOB_DISPLAY)
> + display = lsm_task_display(current);
> + else if (display == LSMBLOB_FIRST)
> + display = LSMBLOB_INVALID;
> + else if (display < 0) {
> + WARN_ONCE(true,
> + "LSM: %s unknown display\n", __func__);
> + display = LSMBLOB_INVALID;
> + } else if (display >= lsm_slot) {
> + WARN_ONCE(true,
> + "LSM: %s invalid display\n", __func__);
> + display = LSMBLOB_INVALID;
> + }
> +
> +
> hlist_for_each_entry(hp, &security_hook_heads.secid_to_secctx, list) {
> if (WARN_ON(hp->lsmid->slot < 0 || hp->lsmid->slot >= lsm_slot))
> continue;
> @@ -2256,7 +2299,7 @@ int security_secctx_to_secid(const char *secdata, u32 seclen,
> return hp->hook.secctx_to_secid(secdata, seclen,
> &blob->secid[hp->lsmid->slot]);
> }
> - return 0;
> + return -EOPNOTSUPP;
> }
> EXPORT_SYMBOL(security_secctx_to_secid);
>
> @@ -2757,23 +2800,17 @@ int security_key_getsecurity(struct key *key, char **_buffer)
> int security_audit_rule_init(u32 field, u32 op, char *rulestr, void **lsmrule)
> {
> struct security_hook_list *hp;
> - bool one_is_good = false;
> - int rc = 0;
> - int trc;
> + int display = lsm_task_display(current);
>
> hlist_for_each_entry(hp, &security_hook_heads.audit_rule_init, list) {
> if (WARN_ON(hp->lsmid->slot < 0 || hp->lsmid->slot >= lsm_slot))
> continue;
> - trc = hp->hook.audit_rule_init(field, op, rulestr,
> - &lsmrule[hp->lsmid->slot]);
> - if (trc == 0)
> - one_is_good = true;
> - else
> - rc = trc;
> + if (display != LSMBLOB_INVALID && display != hp->lsmid->slot)
> + continue;
> + return hp->hook.audit_rule_init(field, op, rulestr,
> + &lsmrule[hp->lsmid->slot]);
> }
> - if (one_is_good)
> - return 0;
> - return rc;
> + return 0;
> }
>
> int security_audit_rule_known(struct audit_krule *krule)
> @@ -2805,6 +2842,8 @@ int security_audit_rule_match(struct lsmblob *blob, u32 field, u32 op,
> continue;
> if (lsmrule[hp->lsmid->slot] == NULL)
> continue;
> + if (lsmrule[hp->lsmid->slot] == NULL)
> + continue;
> rc = hp->hook.audit_rule_match(blob->secid[hp->lsmid->slot],
> field, op,
> &lsmrule[hp->lsmid->slot]);
> diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
> index dcabf6bd8faa..15fa4b7eb2e6 100644
> --- a/security/smack/smackfs.c
> +++ b/security/smack/smackfs.c
> @@ -185,7 +185,8 @@ static void smk_netlabel_audit_set(struct netlbl_audit *nap)
>
> nap->loginuid = audit_get_loginuid(current);
> nap->sessionid = audit_get_sessionid(current);
> - nap->secid = skp->smk_secid;
> + lsmblob_init(&nap->lsmdata, 0);
> + nap->lsmdata.secid[smack_lsmid.slot] = skp->smk_secid;
> }
>
> /*
>
--
James Morris
<jmorris@namei.org>
^ permalink raw reply
* Re: [PATCH v20 05/23] net: Prepare UDS for security module stacking
From: James Morris @ 2020-09-03 16:28 UTC (permalink / raw)
To: Casey Schaufler
Cc: casey.schaufler, linux-security-module, selinux, linux-audit,
keescook, john.johansen, penguin-kernel, paul, sds
In-Reply-To: <20200826145247.10029-6-casey@schaufler-ca.com>
On Wed, 26 Aug 2020, Casey Schaufler wrote:
> Change the data used in UDS SO_PEERSEC processing from a
> secid to a more general struct lsmblob. Update the
> security_socket_getpeersec_dgram() interface to use the
> lsmblob. There is a small amount of scaffolding code
> that will come out when the security_secid_to_secctx()
> code is brought in line with the lsmblob.
>
> Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
This needs some review by networking folk, and/or LSM maintainers. You
should probably cc netdev on anything touching the networking code.
> ---
> include/linux/security.h | 7 +++++--
> include/net/af_unix.h | 2 +-
> include/net/scm.h | 8 +++++---
> net/ipv4/ip_sockglue.c | 8 +++++---
> net/unix/af_unix.c | 6 +++---
> security/security.c | 18 +++++++++++++++---
> 6 files changed, 34 insertions(+), 15 deletions(-)
>
> diff --git a/include/linux/security.h b/include/linux/security.h
> index e2ef982b3dd7..ae623b89cdf4 100644
> --- a/include/linux/security.h
> +++ b/include/linux/security.h
> @@ -1398,7 +1398,8 @@ int security_socket_shutdown(struct socket *sock, int how);
> int security_sock_rcv_skb(struct sock *sk, struct sk_buff *skb);
> int security_socket_getpeersec_stream(struct socket *sock, char __user *optval,
> int __user *optlen, unsigned len);
> -int security_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb, u32 *secid);
> +int security_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb,
> + struct lsmblob *blob);
> int security_sk_alloc(struct sock *sk, int family, gfp_t priority);
> void security_sk_free(struct sock *sk);
> void security_sk_clone(const struct sock *sk, struct sock *newsk);
> @@ -1536,7 +1537,9 @@ static inline int security_socket_getpeersec_stream(struct socket *sock, char __
> return -ENOPROTOOPT;
> }
>
> -static inline int security_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb, u32 *secid)
> +static inline int security_socket_getpeersec_dgram(struct socket *sock,
> + struct sk_buff *skb,
> + struct lsmblob *blob)
> {
> return -ENOPROTOOPT;
> }
> diff --git a/include/net/af_unix.h b/include/net/af_unix.h
> index f42fdddecd41..a86da0cb5ec1 100644
> --- a/include/net/af_unix.h
> +++ b/include/net/af_unix.h
> @@ -36,7 +36,7 @@ struct unix_skb_parms {
> kgid_t gid;
> struct scm_fp_list *fp; /* Passed files */
> #ifdef CONFIG_SECURITY_NETWORK
> - u32 secid; /* Security ID */
> + struct lsmblob lsmblob; /* Security LSM data */
> #endif
> u32 consumed;
> } __randomize_layout;
> diff --git a/include/net/scm.h b/include/net/scm.h
> index 1ce365f4c256..e2e71c4bf9d0 100644
> --- a/include/net/scm.h
> +++ b/include/net/scm.h
> @@ -33,7 +33,7 @@ struct scm_cookie {
> struct scm_fp_list *fp; /* Passed files */
> struct scm_creds creds; /* Skb credentials */
> #ifdef CONFIG_SECURITY_NETWORK
> - u32 secid; /* Passed security ID */
> + struct lsmblob lsmblob; /* Passed LSM data */
> #endif
> };
>
> @@ -46,7 +46,7 @@ struct scm_fp_list *scm_fp_dup(struct scm_fp_list *fpl);
> #ifdef CONFIG_SECURITY_NETWORK
> static __inline__ void unix_get_peersec_dgram(struct socket *sock, struct scm_cookie *scm)
> {
> - security_socket_getpeersec_dgram(sock, NULL, &scm->secid);
> + security_socket_getpeersec_dgram(sock, NULL, &scm->lsmblob);
> }
> #else
> static __inline__ void unix_get_peersec_dgram(struct socket *sock, struct scm_cookie *scm)
> @@ -97,7 +97,9 @@ static inline void scm_passec(struct socket *sock, struct msghdr *msg, struct sc
> int err;
>
> if (test_bit(SOCK_PASSSEC, &sock->flags)) {
> - err = security_secid_to_secctx(scm->secid, &secdata, &seclen);
> + /* Scaffolding - it has to be element 0 for now */
> + err = security_secid_to_secctx(scm->lsmblob.secid[0],
> + &secdata, &seclen);
>
> if (!err) {
> put_cmsg(msg, SOL_SOCKET, SCM_SECURITY, seclen, secdata);
> diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
> index d2c223554ff7..551dfbc717e9 100644
> --- a/net/ipv4/ip_sockglue.c
> +++ b/net/ipv4/ip_sockglue.c
> @@ -130,15 +130,17 @@ static void ip_cmsg_recv_checksum(struct msghdr *msg, struct sk_buff *skb,
>
> static void ip_cmsg_recv_security(struct msghdr *msg, struct sk_buff *skb)
> {
> + struct lsmblob lb;
> char *secdata;
> - u32 seclen, secid;
> + u32 seclen;
> int err;
>
> - err = security_socket_getpeersec_dgram(NULL, skb, &secid);
> + err = security_socket_getpeersec_dgram(NULL, skb, &lb);
> if (err)
> return;
>
> - err = security_secid_to_secctx(secid, &secdata, &seclen);
> + /* Scaffolding - it has to be element 0 */
> + err = security_secid_to_secctx(lb.secid[0], &secdata, &seclen);
> if (err)
> return;
>
> diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
> index 181ea6fb56a6..c15668b80d1d 100644
> --- a/net/unix/af_unix.c
> +++ b/net/unix/af_unix.c
> @@ -138,17 +138,17 @@ static struct hlist_head *unix_sockets_unbound(void *addr)
> #ifdef CONFIG_SECURITY_NETWORK
> static void unix_get_secdata(struct scm_cookie *scm, struct sk_buff *skb)
> {
> - UNIXCB(skb).secid = scm->secid;
> + UNIXCB(skb).lsmblob = scm->lsmblob;
> }
>
> static inline void unix_set_secdata(struct scm_cookie *scm, struct sk_buff *skb)
> {
> - scm->secid = UNIXCB(skb).secid;
> + scm->lsmblob = UNIXCB(skb).lsmblob;
> }
>
> static inline bool unix_secdata_eq(struct scm_cookie *scm, struct sk_buff *skb)
> {
> - return (scm->secid == UNIXCB(skb).secid);
> + return lsmblob_equal(&scm->lsmblob, &(UNIXCB(skb).lsmblob));
> }
> #else
> static inline void unix_get_secdata(struct scm_cookie *scm, struct sk_buff *skb)
> diff --git a/security/security.c b/security/security.c
> index d6d882b1f7d5..c42873876954 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -2219,10 +2219,22 @@ int security_socket_getpeersec_stream(struct socket *sock, char __user *optval,
> optval, optlen, len);
> }
>
> -int security_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb, u32 *secid)
> +int security_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb,
> + struct lsmblob *blob)
> {
> - return call_int_hook(socket_getpeersec_dgram, -ENOPROTOOPT, sock,
> - skb, secid);
> + struct security_hook_list *hp;
> + int rc = -ENOPROTOOPT;
> +
> + hlist_for_each_entry(hp, &security_hook_heads.socket_getpeersec_dgram,
> + list) {
> + if (WARN_ON(hp->lsmid->slot < 0 || hp->lsmid->slot >= lsm_slot))
> + continue;
> + rc = hp->hook.socket_getpeersec_dgram(sock, skb,
> + &blob->secid[hp->lsmid->slot]);
> + if (rc != 0)
> + break;
> + }
> + return rc;
> }
> EXPORT_SYMBOL(security_socket_getpeersec_dgram);
>
>
--
James Morris
<jmorris@namei.org>
^ permalink raw reply
* [PATCH v6 7/8] X.509: support OSCCA sm2-with-sm3 certificate verification
From: Tianjia Zhang @ 2020-09-03 13:12 UTC (permalink / raw)
To: Herbert Xu, David S. Miller, David Howells, Maxime Coquelin,
Alexandre Torgue, James Morris, Serge E. Hallyn, Stephan Mueller,
Marcelo Henrique Cerri, Steven Rostedt (VMware), Masahiro Yamada,
Brendan Higgins, Andrew Morton, Johannes Weiner, Waiman Long,
Mimi Zohar, Lakshmi Ramasubramanian, Colin Ian King,
Tushar Sugandhi, Vitaly Chikunov, Gilad Ben-Yossef,
Pascal van Leeuwen, linux-crypto, linux-kernel, keyrings,
linux-stm32, linux-arm-kernel, linux-security-module
Cc: Xufeng Zhang, Jia Zhang, Tianjia Zhang
In-Reply-To: <20200903131242.128665-1-tianjia.zhang@linux.alibaba.com>
The digital certificate format based on SM2 crypto algorithm as
specified in GM/T 0015-2012. It was published by State Encryption
Management Bureau, China.
The method of generating Other User Information is defined as
ZA=H256(ENTLA || IDA || a || b || xG || yG || xA || yA), it also
specified in https://tools.ietf.org/html/draft-shen-sm2-ecdsa-02.
The x509 certificate supports sm2-with-sm3 type certificate
verification. Because certificate verification requires ZA
in addition to tbs data, ZA also depends on elliptic curve
parameters and public key data, so you need to access tbs in sig
and calculate ZA. Finally calculate the digest of the
signature and complete the verification work. The calculation
process of ZA is declared in specifications GM/T 0009-2012
and GM/T 0003.2-2012.
Signed-off-by: Tianjia Zhang <tianjia.zhang@linux.alibaba.com>
Tested-by: Xufeng Zhang <yunbo.xufeng@linux.alibaba.com>
---
crypto/asymmetric_keys/Makefile | 1 +
crypto/asymmetric_keys/public_key.c | 6 +++
crypto/asymmetric_keys/public_key_sm2.c | 61 ++++++++++++++++++++++++
crypto/asymmetric_keys/x509_public_key.c | 3 ++
include/crypto/public_key.h | 15 ++++++
5 files changed, 86 insertions(+)
create mode 100644 crypto/asymmetric_keys/public_key_sm2.c
diff --git a/crypto/asymmetric_keys/Makefile b/crypto/asymmetric_keys/Makefile
index 28b91adba2ae..1a99ea5acb6b 100644
--- a/crypto/asymmetric_keys/Makefile
+++ b/crypto/asymmetric_keys/Makefile
@@ -11,6 +11,7 @@ asymmetric_keys-y := \
signature.o
obj-$(CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE) += public_key.o
+obj-$(CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE) += public_key_sm2.o
obj-$(CONFIG_ASYMMETRIC_TPM_KEY_SUBTYPE) += asym_tpm.o
#
diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c
index d8410ffd7f12..1d0492098bbd 100644
--- a/crypto/asymmetric_keys/public_key.c
+++ b/crypto/asymmetric_keys/public_key.c
@@ -299,6 +299,12 @@ int public_key_verify_signature(const struct public_key *pkey,
if (ret)
goto error_free_key;
+ if (strcmp(sig->pkey_algo, "sm2") == 0 && sig->data_size) {
+ ret = cert_sig_digest_update(sig, tfm);
+ if (ret)
+ goto error_free_key;
+ }
+
sg_init_table(src_sg, 2);
sg_set_buf(&src_sg[0], sig->s, sig->s_size);
sg_set_buf(&src_sg[1], sig->digest, sig->digest_size);
diff --git a/crypto/asymmetric_keys/public_key_sm2.c b/crypto/asymmetric_keys/public_key_sm2.c
new file mode 100644
index 000000000000..7325cf21dbb4
--- /dev/null
+++ b/crypto/asymmetric_keys/public_key_sm2.c
@@ -0,0 +1,61 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * asymmetric public-key algorithm for SM2-with-SM3 certificate
+ * as specified by OSCCA GM/T 0003.1-2012 -- 0003.5-2012 SM2 and
+ * described at https://tools.ietf.org/html/draft-shen-sm2-ecdsa-02
+ *
+ * Copyright (c) 2020, Alibaba Group.
+ * Authors: Tianjia Zhang <tianjia.zhang@linux.alibaba.com>
+ */
+
+#include <crypto/sm3_base.h>
+#include <crypto/sm2.h>
+#include <crypto/public_key.h>
+
+#if IS_REACHABLE(CONFIG_CRYPTO_SM2)
+
+int cert_sig_digest_update(const struct public_key_signature *sig,
+ struct crypto_akcipher *tfm_pkey)
+{
+ struct crypto_shash *tfm;
+ struct shash_desc *desc;
+ size_t desc_size;
+ unsigned char dgst[SM3_DIGEST_SIZE];
+ int ret;
+
+ BUG_ON(!sig->data);
+
+ ret = sm2_compute_z_digest(tfm_pkey, SM2_DEFAULT_USERID,
+ SM2_DEFAULT_USERID_LEN, dgst);
+ if (ret)
+ return ret;
+
+ tfm = crypto_alloc_shash(sig->hash_algo, 0, 0);
+ if (IS_ERR(tfm))
+ return PTR_ERR(tfm);
+
+ desc_size = crypto_shash_descsize(tfm) + sizeof(*desc);
+ desc = kzalloc(desc_size, GFP_KERNEL);
+ if (!desc)
+ goto error_free_tfm;
+
+ desc->tfm = tfm;
+
+ ret = crypto_shash_init(desc);
+ if (ret < 0)
+ goto error_free_desc;
+
+ ret = crypto_shash_update(desc, dgst, SM3_DIGEST_SIZE);
+ if (ret < 0)
+ goto error_free_desc;
+
+ ret = crypto_shash_finup(desc, sig->data, sig->data_size, sig->digest);
+
+error_free_desc:
+ kfree(desc);
+error_free_tfm:
+ crypto_free_shash(tfm);
+ return ret;
+}
+
+#endif /* ! IS_REACHABLE(CONFIG_CRYPTO_SM2) */
diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c
index d964cc82b69c..ae450eb8be14 100644
--- a/crypto/asymmetric_keys/x509_public_key.c
+++ b/crypto/asymmetric_keys/x509_public_key.c
@@ -30,6 +30,9 @@ int x509_get_sig_params(struct x509_certificate *cert)
pr_devel("==>%s()\n", __func__);
+ sig->data = cert->tbs;
+ sig->data_size = cert->tbs_size;
+
if (!cert->pub->pkey_algo)
cert->unsupported_key = true;
diff --git a/include/crypto/public_key.h b/include/crypto/public_key.h
index 11f535cfb810..02a6dbe5c366 100644
--- a/include/crypto/public_key.h
+++ b/include/crypto/public_key.h
@@ -12,6 +12,7 @@
#include <linux/keyctl.h>
#include <linux/oid_registry.h>
+#include <crypto/akcipher.h>
/*
* Cryptographic data for the public-key subtype of the asymmetric key type.
@@ -44,6 +45,8 @@ struct public_key_signature {
const char *pkey_algo;
const char *hash_algo;
const char *encoding;
+ const void *data;
+ unsigned int data_size;
};
extern void public_key_signature_free(struct public_key_signature *sig);
@@ -81,4 +84,16 @@ extern int verify_signature(const struct key *,
int public_key_verify_signature(const struct public_key *pkey,
const struct public_key_signature *sig);
+#if IS_REACHABLE(CONFIG_CRYPTO_SM2)
+int cert_sig_digest_update(const struct public_key_signature *sig,
+ struct crypto_akcipher *tfm_pkey);
+#else
+static inline
+int cert_sig_digest_update(const struct public_key_signature *sig,
+ struct crypto_akcipher *tfm_pkey)
+{
+ return -ENOTSUPP;
+}
+#endif
+
#endif /* _LINUX_PUBLIC_KEY_H */
--
2.19.1.3.ge56e4f7
^ permalink raw reply related
* [PATCH v6 1/8] crypto: sm3 - export crypto_sm3_final function
From: Tianjia Zhang @ 2020-09-03 13:12 UTC (permalink / raw)
To: Herbert Xu, David S. Miller, David Howells, Maxime Coquelin,
Alexandre Torgue, James Morris, Serge E. Hallyn, Stephan Mueller,
Marcelo Henrique Cerri, Steven Rostedt (VMware), Masahiro Yamada,
Brendan Higgins, Andrew Morton, Johannes Weiner, Waiman Long,
Mimi Zohar, Lakshmi Ramasubramanian, Colin Ian King,
Tushar Sugandhi, Vitaly Chikunov, Gilad Ben-Yossef,
Pascal van Leeuwen, linux-crypto, linux-kernel, keyrings,
linux-stm32, linux-arm-kernel, linux-security-module
Cc: Xufeng Zhang, Jia Zhang, Tianjia Zhang
In-Reply-To: <20200903131242.128665-1-tianjia.zhang@linux.alibaba.com>
Both crypto_sm3_update and crypto_sm3_finup have been
exported, exporting crypto_sm3_final, to avoid having to
use crypto_sm3_finup(desc, NULL, 0, dgst) to calculate
the hash in some cases.
Signed-off-by: Tianjia Zhang <tianjia.zhang@linux.alibaba.com>
Tested-by: Xufeng Zhang <yunbo.xufeng@linux.alibaba.com>
---
crypto/sm3_generic.c | 7 ++++---
include/crypto/sm3.h | 2 ++
2 files changed, 6 insertions(+), 3 deletions(-)
diff --git a/crypto/sm3_generic.c b/crypto/sm3_generic.c
index 3468975215ca..193c4584bd00 100644
--- a/crypto/sm3_generic.c
+++ b/crypto/sm3_generic.c
@@ -149,17 +149,18 @@ int crypto_sm3_update(struct shash_desc *desc, const u8 *data,
}
EXPORT_SYMBOL(crypto_sm3_update);
-static int sm3_final(struct shash_desc *desc, u8 *out)
+int crypto_sm3_final(struct shash_desc *desc, u8 *out)
{
sm3_base_do_finalize(desc, sm3_generic_block_fn);
return sm3_base_finish(desc, out);
}
+EXPORT_SYMBOL(crypto_sm3_final);
int crypto_sm3_finup(struct shash_desc *desc, const u8 *data,
unsigned int len, u8 *hash)
{
sm3_base_do_update(desc, data, len, sm3_generic_block_fn);
- return sm3_final(desc, hash);
+ return crypto_sm3_final(desc, hash);
}
EXPORT_SYMBOL(crypto_sm3_finup);
@@ -167,7 +168,7 @@ static struct shash_alg sm3_alg = {
.digestsize = SM3_DIGEST_SIZE,
.init = sm3_base_init,
.update = crypto_sm3_update,
- .final = sm3_final,
+ .final = crypto_sm3_final,
.finup = crypto_sm3_finup,
.descsize = sizeof(struct sm3_state),
.base = {
diff --git a/include/crypto/sm3.h b/include/crypto/sm3.h
index 1438942dc773..42ea21289ba9 100644
--- a/include/crypto/sm3.h
+++ b/include/crypto/sm3.h
@@ -35,6 +35,8 @@ struct shash_desc;
extern int crypto_sm3_update(struct shash_desc *desc, const u8 *data,
unsigned int len);
+extern int crypto_sm3_final(struct shash_desc *desc, u8 *out);
+
extern int crypto_sm3_finup(struct shash_desc *desc, const u8 *data,
unsigned int len, u8 *hash);
#endif
--
2.19.1.3.ge56e4f7
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox