lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Wed, 5 Jan 2022 10:21:38 -0500
From:   Stefan Berger <stefanb@...ux.ibm.com>
To:     Stefan Berger <stefanb@...ux.vnet.ibm.com>,
        linux-integrity@...r.kernel.org
Cc:     zohar@...ux.ibm.com, serge@...lyn.com,
        christian.brauner@...ntu.com, containers@...ts.linux.dev,
        dmitry.kasatkin@...il.com, ebiederm@...ssion.com,
        krzysztof.struczynski@...wei.com, roberto.sassu@...wei.com,
        mpeters@...hat.com, lhinds@...hat.com, lsturman@...hat.com,
        puiterwi@...hat.com, jejb@...ux.ibm.com, jamjoom@...ibm.com,
        linux-kernel@...r.kernel.org, paul@...l-moore.com, rgb@...hat.com,
        linux-security-module@...r.kernel.org, jmorris@...ei.org
Subject: Re: [PATCH v8 16/19] ima: Enable re-auditing of modified files


On 1/4/22 12:04, Stefan Berger wrote:
> From: Stefan Berger <stefanb@...ux.ibm.com>
>
> Walk the list of ns_status associated with an iint if the file has
> changed and reset the IMA_AUDITED flag, which is part of the
> IMA_DONE_MASK. This causes a new audit message to be emitted when the
> file is again accessed on either the host or in an IMA namespace.
>
> Signed-off-by: Stefan Berger <stefanb@...ux.ibm.com>
> ---
>   security/integrity/ima/ima_main.c | 33 ++++++++++++++++++++++++++++++-
>   1 file changed, 32 insertions(+), 1 deletion(-)
>
> diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
> index 99dc984b49c9..bc3ab08f39c6 100644
> --- a/security/integrity/ima/ima_main.c
> +++ b/security/integrity/ima/ima_main.c
> @@ -153,6 +153,35 @@ static void ima_rdwr_violation_check(struct ima_namespace *ns,
>   				  "invalid_pcr", "open_writers");
>   }
>   
> +#ifdef CONFIG_IMA_NS
> +
> +static void mask_iint_ns_status_flags(struct integrity_iint_cache *iint,
> +				      unsigned long mask)
> +{
> +	struct ns_status *status;
> +	unsigned long flags;
> +
> +	read_lock(&iint->ns_list_lock);
> +	list_for_each_entry(status, &iint->ns_list, ns_next) {
> +		flags = iint_flags(iint, status) & mask;
> +		set_iint_flags(iint, status, flags);
> +	}
> +	read_unlock(&iint->ns_list_lock);
> +}
> +
> +#else
> +
> +static void mask_iint_ns_status_flags(struct integrity_iint_cache *iint,
> +				      unsigned long mask)
> +{
> +	unsigned long flags;
> +
> +	flags = iint_flags(iint, NULL) & mask;
> +	set_iint_flags(iint, NULL, flags);
> +}
> +
> +#endif
> +

The above two cases are due to this here:

diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h
index 547425c20e11..201a9d46d6e1 100644
--- a/security/integrity/integrity.h
+++ b/security/integrity/integrity.h
@@ -138,6 +138,10 @@ struct integrity_iint_cache {
  	enum integrity_status ima_creds_status:4;
  	enum integrity_status evm_status:4;
  	struct ima_digest_data *ima_hash;
+#ifdef CONFIG_IMA_NS
+	rwlock_t ns_list_lock;
+	struct list_head ns_list;
+#endif
  };

Ideally namespaced and non-namespaced code cases would share the code and to be able to share it the above #ifdef CONFIG_IMA_NS  in integrity.hshouldn't be there but we would have the lock and list in IMA namespacing and non-namespacing case. The above two code cases shown above are just the beginning and as more variables are moved from the iint into the ns_status these types of 'two cases of code' would show up in more places. So I think we should prevent this already now.

To be able to share the code we need an ns_status on a list in the non-namespacing case as well. In the non-namespacing case it would always be a single ns_status on the list. What is worth a decision is how to get the ns_status on the list. One idea would be to conditionally embed it into the integrity_iint_cache like this:

/* integrity data associated with an inode */
struct integrity_iint_cache {
         struct rb_node rb_node; /* rooted in integrity_iint_tree */
         struct mutex mutex;     /* protects: version, flags, digest */
         struct inode *inode;    /* back pointer to inode in question */
         u64 version;            /* track inode changes */
         unsigned long flags;
         unsigned long atomic_flags;
         enum integrity_status ima_file_status:4;
         enum integrity_status ima_mmap_status:4;
         enum integrity_status ima_bprm_status:4;
         enum integrity_status ima_read_status:4;
         enum integrity_status ima_creds_status:4;
         enum integrity_status evm_status:4;
         struct ima_digest_data *ima_hash;
         rwlock_t ns_list_lock;
         struct list_head ns_list;
#ifndef CONFIG_IMA_NS
	struct ns_status status;
#endif
};

This would prevent a 2nd cache just for allocation of ns_status in the 
non-namespacing case and getting the  embedded ns_status onto the list 
would also be like this:

     INIT_LIST_HEAD(&iint->ns_list);

#ifndef CONFIG_IMA_NS

     INIT_LIST_HEAD(&iint->status.ns_next);

     list_add_tail(&iint->status.ns_next, &iint->ns_list);

#endif

The other option is to allocated the ns_status via a minimal 
implementation of ima_ns_status.c for the non-namespaced case using 
kmalloc's from a cache for ns_status structures.


Also, the new 'rwlock_t ns_list_lock' in the iint would really only be 
necessary for locking in the namespacing case. However, to be able to 
share the code we would need to keep this lock around for the 
non-namespacing case as well so that we can call read_lock() in both 
cases. An option would be to introduce a macro for the locking that is a 
no-op in the non-namespacing case and does the actual locking in the 
namespacing case. I am not sure what would be better. I would prefer to 
explicitly see the read_lock()...



>   static void ima_check_last_writer(struct integrity_iint_cache *iint,
>   				  struct inode *inode, struct file *file)
>   {
> @@ -169,8 +198,10 @@ static void ima_check_last_writer(struct integrity_iint_cache *iint,
>   		if (!IS_I_VERSION(inode) ||
>   		    !inode_eq_iversion(inode, iint->version) ||
>   		    (iint->flags & IMA_NEW_FILE)) {
> -			iint->flags &= ~(IMA_DONE_MASK | IMA_NEW_FILE);
> +			mask_iint_ns_status_flags(iint,
> +					~(IMA_DONE_MASK | IMA_NEW_FILE));
>   			iint->measured_pcrs = 0;
> +
>   			if (update)
>   				ima_update_xattr(iint, file);
>   		}

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ