mbox series

[v9,00/25] security: Move IMA and EVM to the LSM infrastructure

Message ID 20240115181809.885385-1-roberto.sassu@huaweicloud.com
Headers show
Series security: Move IMA and EVM to the LSM infrastructure | expand

Message

Roberto Sassu Jan. 15, 2024, 6:17 p.m. UTC
From: Roberto Sassu <roberto.sassu@huawei.com>

IMA and EVM are not effectively LSMs, especially due to the fact that in
the past they could not provide a security blob while there is another LSM
active.

That changed in the recent years, the LSM stacking feature now makes it
possible to stack together multiple LSMs, and allows them to provide a
security blob for most kernel objects. While the LSM stacking feature has
some limitations being worked out, it is already suitable to make IMA and
EVM as LSMs.

The main purpose of this patch set is to remove IMA and EVM function calls,
hardcoded in the LSM infrastructure and other places in the kernel, and to
register them as LSM hook implementations, so that those functions are
called by the LSM infrastructure like other regular LSMs.

This patch set introduces two new LSMs 'ima' and 'evm', so that functions
can be registered to their respective LSM, and removes the 'integrity' LSM.
integrity_kernel_module_request() was moved to IMA, since deadlock could
occur only there. integrity_inode_free() was replaced with ima_inode_free()
(EVM does not need to free memory).

In order to make 'ima' and 'evm' independent LSMs, it was necessary to
split integrity metadata used by both IMA and EVM, and to let them manage
their own. The special case of the IMA_NEW_FILE flag, managed by IMA and
used by EVM, was handled by introducing a new flag in EVM, EVM_NEW_FILE,
managed by two additional LSM hooks, evm_post_path_mknod() and
evm_file_release(), equivalent to their counterparts ima_post_path_mknod()
and ima_file_free().

In addition to splitting metadata, it was decided to embed the
evm_iint_inode structure into the inode security blob, since it is small
and because anyway it cannot rely on IMA anymore allocating it (since it
uses a different structure).

On the other hand, to avoid memory pressure concerns, only a pointer to the
ima_iint_cache structure is stored in the inode security blob, and the
structure is allocated on demand, like before.

Another follow-up change was removing the iint parameter from
evm_verifyxattr(), that IMA used to pass integrity metadata to EVM. After
splitting metadata, and aligning EVM_NEW_FILE with IMA_NEW_FILE, this
parameter was not necessary anymore.

The last part was to ensure that the order of IMA and EVM functions is
respected after they become LSMs. Since the order of lsm_info structures in
the .lsm_info.init section depends on the order object files containing
those structures are passed to the linker of the kernel image, and since
IMA is before EVM in the Makefile, that is sufficient to assert that IMA
functions are executed before EVM ones.

The patch set is organized as follows.

Patches 1-9 make IMA and EVM functions suitable to be registered to the LSM
infrastructure, by aligning function parameters.

Patches 10-18 add new LSM hooks in the same places where IMA and EVM
functions are called, if there is no LSM hook already.

Patch 19 moves integrity_kernel_module_request() to IMA, as a prerequisite
for removing the 'integrity' LSM.

Patches 20-22 introduce the new standalone LSMs 'ima' and 'evm', and move
hardcoded calls to IMA, EVM and integrity functions to those LSMs.

Patches 23-24 remove the dependency on the 'integrity' LSM by splitting
integrity metadata, so that the 'ima' and 'evm' LSMs can use their own.
They also duplicate iint_lockdep_annotate() in ima_main.c, since the mutex
field was moved from integrity_iint_cache to ima_iint_cache.

Patch 25 finally removes the 'integrity' LSM, since 'ima' and 'evm' are now
self-contained and independent. 

The patch set applies on top of lsm/dev, commit f1bb47a31dff ("lsm: new
security_file_ioctl_compat() hook"). The linux-integrity/next-integrity at
commit c00f94b3a5be ("overlay: disable EVM") was merged.

Changelog:

v8:
 - Restore dynamic allocation of IMA integrity metadata, and store only the
   pointer in the inode security blob
 - Select SECURITY_PATH both in IMA and EVM
 - Rename evm_file_free() to evm_file_release()
 - Unconditionally register evm_post_path_mknod()
 - Introduce the new ima_iint.c file for the management of IMA integrity
   metadata
 - Introduce ima_inode_set_iint()/ima_inode_get_iint() in ima.h to
   respectively store/retrieve the IMA integrity metadata pointer
 - Replace ima_iint_inode() with ima_inode_get() and ima_iint_find(), with
   same behavior of integrity_inode_get() and integrity_iint_find()
 - Initialize the ima_iint_cache in ima_iintcache_init() and call it from
   init_ima_lsm()
 - Move integrity_kernel_module_request() to IMA in a separate patch
   (suggested by Mimi)
 - Compile ima_kernel_module_request() if CONFIG_INTEGRITY_ASYMMETRIC_KEYS
   is enabled
 - Remove ima_inode_alloc_security() and ima_inode_free_security(), since
   the IMA integrity metadata is not fully embedded in the inode security
   blob
 - Fixed the missed initialization of ima_iint_cache in
   process_measurement() and __ima_inode_hash()
 - Add a sentence in 'evm: Move to LSM infrastructure' to mention about
   moving evm_inode_remove_acl(), evm_inode_post_remove_acl() and
   evm_inode_post_set_acl() to evm_main.c
 - Add a sentence in 'ima: Move IMA-Appraisal to LSM infrastructure' to
   mention about moving ima_inode_remove_acl() to ima_appraise.c

v7:
 - Use return instead of goto in __vfs_removexattr_locked() (suggested by
   Casey)
 - Clarify in security/integrity/Makefile that the order of 'ima' and 'evm'
   LSMs depends on the order in which IMA and EVM are compiled
 - Move integrity_iint_cache flags to ima.h and evm.h in security/ and
   duplicate IMA_NEW_FILE to EVM_NEW_FILE
 - Rename evm_inode_get_iint() to evm_iint_inode() and ima_inode_get_iint()
   to ima_iint_inode(), check if inode->i_security is NULL, and just return
   the pointer from the inode security blob
 - Restore the non-NULL checks after ima_iint_inode() and evm_iint_inode()
   (suggested by Casey)
 - Introduce evm_file_free() to clear EVM_NEW_FILE
 - Remove comment about LSM_ORDER_LAST not guaranteeing the order of 'ima'
   and 'evm' LSMs
 - Lock iint->mutex before reading IMA_COLLECTED flag in __ima_inode_hash()
   and restored ima_policy_flag check
 - Remove patch about the hardcoded ordering of 'ima' and 'evm' LSMs in
   security.c
 - Add missing ima_inode_free_security() to free iint->ima_hash
 - Add the cases for LSM_ID_IMA and LSM_ID_EVM in lsm_list_modules_test.c
 - Mention about the change in IMA and EVM post functions for private
   inodes

v6:
 - See v7

v5:
 - Rename security_file_pre_free() to security_file_release() and the LSM
   hook file_pre_free_security to file_release (suggested by Paul)
 - Move integrity_kernel_module_request() to ima_main.c (renamed to
   ima_kernel_module_request())
 - Split the integrity_iint_cache structure into ima_iint_cache and
   evm_iint_cache, so that IMA and EVM can use disjoint metadata and
   reserve space with the LSM infrastructure
 - Reserve space for the entire ima_iint_cache and evm_iint_cache
   structures, not just the pointer (suggested by Paul)
 - Introduce ima_inode_get_iint() and evm_inode_get_iint() to retrieve
   respectively the ima_iint_cache and evm_iint_cache structure from the
   security blob
 - Remove the various non-NULL checks for the ima_iint_cache and
   evm_iint_cache structures, since the LSM infrastructure ensure that they
   always exist
 - Remove the iint parameter from evm_verifyxattr() since IMA and EVM
   use disjoint integrity metaddata
 - Introduce the evm_post_path_mknod() to set the IMA_NEW_FILE flag
 - Register the inode_alloc_security LSM hook in IMA and EVM to
   initialize the respective integrity metadata structures
 - Remove the 'integrity' LSM completely and instead make 'ima' and 'evm'
   proper standalone LSMs
 - Add the inode parameter to ima_get_verity_digest(), since the inode
   field is not present in ima_iint_cache
 - Move iint_lockdep_annotate() to ima_main.c (renamed to
   ima_iint_lockdep_annotate())
 - Remove ima_get_lsm_id() and evm_get_lsm_id(), since IMA and EVM directly
   register the needed LSM hooks
 - Enforce 'ima' and 'evm' LSM ordering at LSM infrastructure level

v4:
 - Improve short and long description of
   security_inode_post_create_tmpfile(), security_inode_post_set_acl(),
   security_inode_post_remove_acl() and security_file_post_open()
   (suggested by Mimi)
 - Improve commit message of 'ima: Move to LSM infrastructure' (suggested
   by Mimi)

v3:
 - Drop 'ima: Align ima_post_path_mknod() definition with LSM
   infrastructure' and 'ima: Align ima_post_create_tmpfile() definition
   with LSM infrastructure', define the new LSM hooks with the same
   IMA parameters instead (suggested by Mimi)
 - Do IS_PRIVATE() check in security_path_post_mknod() and
   security_inode_post_create_tmpfile() on the new inode rather than the
   parent directory (in the post method it is available)
 - Don't export ima_file_check() (suggested by Stefan)
 - Remove redundant check of file mode in ima_post_path_mknod() (suggested
   by Mimi)
 - Mention that ima_post_path_mknod() is now conditionally invoked when
   CONFIG_SECURITY_PATH=y (suggested by Mimi)
 - Mention when a LSM hook will be introduced in the IMA/EVM alignment
   patches (suggested by Mimi)
 - Simplify the commit messages when introducing a new LSM hook
 - Still keep the 'extern' in the function declaration, until the
   declaration is removed (suggested by Mimi)
 - Improve documentation of security_file_pre_free()
 - Register 'ima' and 'evm' as standalone LSMs (suggested by Paul)
 - Initialize the 'ima' and 'evm' LSMs from 'integrity', to keep the
   original ordering of IMA and EVM functions as when they were hardcoded
 - Return the IMA and EVM LSM IDs to 'integrity' for registration of the
   integrity-specific hooks
 - Reserve an xattr slot from the 'evm' LSM instead of 'integrity'
 - Pass the LSM ID to init_ima_appraise_lsm()

v2:
 - Add description for newly introduced LSM hooks (suggested by Casey)
 - Clarify in the description of security_file_pre_free() that actions can
   be performed while the file is still open

v1:
 - Drop 'evm: Complete description of evm_inode_setattr()', 'fs: Fix
   description of vfs_tmpfile()' and 'security: Introduce LSM_ORDER_LAST',
   they were sent separately (suggested by Christian Brauner)
 - Replace dentry with file descriptor parameter for
   security_inode_post_create_tmpfile()
 - Introduce mode_stripped and pass it as mode argument to
   security_path_mknod() and security_path_post_mknod()
 - Use goto in do_mknodat() and __vfs_removexattr_locked() (suggested by
   Mimi)
 - Replace __lsm_ro_after_init with __ro_after_init
 - Modify short description of security_inode_post_create_tmpfile() and
   security_inode_post_set_acl() (suggested by Stefan)
 - Move security_inode_post_setattr() just after security_inode_setattr()
   (suggested by Mimi)
 - Modify short description of security_key_post_create_or_update()
   (suggested by Mimi)
 - Add back exported functions ima_file_check() and
   evm_inode_init_security() respectively to ima.h and evm.h (reported by
   kernel robot)
 - Remove extern from prototype declarations and fix style issues
 - Remove unnecessary include of linux/lsm_hooks.h in ima_main.c and
   ima_appraise.c

Roberto Sassu (25):
  ima: Align ima_inode_post_setattr() definition with LSM infrastructure
  ima: Align ima_file_mprotect() definition with LSM infrastructure
  ima: Align ima_inode_setxattr() definition with LSM infrastructure
  ima: Align ima_inode_removexattr() definition with LSM infrastructure
  ima: Align ima_post_read_file() definition with LSM infrastructure
  evm: Align evm_inode_post_setattr() definition with LSM infrastructure
  evm: Align evm_inode_setxattr() definition with LSM infrastructure
  evm: Align evm_inode_post_setxattr() definition with LSM
    infrastructure
  security: Align inode_setattr hook definition with EVM
  security: Introduce inode_post_setattr hook
  security: Introduce inode_post_removexattr hook
  security: Introduce file_post_open hook
  security: Introduce file_release hook
  security: Introduce path_post_mknod hook
  security: Introduce inode_post_create_tmpfile hook
  security: Introduce inode_post_set_acl hook
  security: Introduce inode_post_remove_acl hook
  security: Introduce key_post_create_or_update hook
  integrity: Move integrity_kernel_module_request() to IMA
  ima: Move to LSM infrastructure
  ima: Move IMA-Appraisal to LSM infrastructure
  evm: Move to LSM infrastructure
  evm: Make it independent from 'integrity' LSM
  ima: Make it independent from 'integrity' LSM
  integrity: Remove LSM

 fs/attr.c                                     |   5 +-
 fs/file_table.c                               |   3 +-
 fs/namei.c                                    |  12 +-
 fs/nfsd/vfs.c                                 |   3 +-
 fs/open.c                                     |   1 -
 fs/posix_acl.c                                |   5 +-
 fs/xattr.c                                    |   9 +-
 include/linux/evm.h                           | 117 +-------
 include/linux/ima.h                           | 142 ----------
 include/linux/integrity.h                     |  27 --
 include/linux/lsm_hook_defs.h                 |  20 +-
 include/linux/security.h                      |  59 ++++
 include/uapi/linux/lsm.h                      |   2 +
 security/integrity/Makefile                   |   1 +
 security/integrity/digsig_asymmetric.c        |  23 --
 security/integrity/evm/Kconfig                |   1 +
 security/integrity/evm/evm.h                  |  19 ++
 security/integrity/evm/evm_crypto.c           |   4 +-
 security/integrity/evm/evm_main.c             | 195 ++++++++++---
 security/integrity/iint.c                     | 197 +------------
 security/integrity/ima/Kconfig                |   1 +
 security/integrity/ima/Makefile               |   2 +-
 security/integrity/ima/ima.h                  | 148 ++++++++--
 security/integrity/ima/ima_api.c              |  23 +-
 security/integrity/ima/ima_appraise.c         |  66 +++--
 security/integrity/ima/ima_iint.c             | 142 ++++++++++
 security/integrity/ima/ima_init.c             |   2 +-
 security/integrity/ima/ima_main.c             | 144 +++++++---
 security/integrity/ima/ima_policy.c           |   2 +-
 security/integrity/integrity.h                |  80 +-----
 security/keys/key.c                           |  10 +-
 security/security.c                           | 263 +++++++++++-------
 security/selinux/hooks.c                      |   3 +-
 security/smack/smack_lsm.c                    |   4 +-
 .../selftests/lsm/lsm_list_modules_test.c     |   6 +
 35 files changed, 902 insertions(+), 839 deletions(-)
 create mode 100644 security/integrity/ima/ima_iint.c

Comments

Roberto Sassu Jan. 16, 2024, 8:47 a.m. UTC | #1
On Mon, 2024-01-15 at 19:15 +0000, Al Viro wrote:
> On Mon, Jan 15, 2024 at 07:17:57PM +0100, Roberto Sassu wrote:
> > From: Roberto Sassu <roberto.sassu@huawei.com>
> > 
> > In preparation for moving IMA and EVM to the LSM infrastructure, introduce
> > the file_release hook.
> > 
> > IMA calculates at file close the new digest of the file content and writes
> > it to security.ima, so that appraisal at next file access succeeds.
> > 
> > An LSM could implement an exclusive access scheme for files, only allowing
> > access to files that have no references.
> 
> Elaborate that last part, please.

Apologies, I didn't understand that either. Casey?

Thanks

Roberto
Al Viro Jan. 16, 2024, 5:33 p.m. UTC | #2
On Tue, Jan 16, 2024 at 08:51:11AM -0800, Casey Schaufler wrote:
> On 1/16/2024 12:47 AM, Roberto Sassu wrote:
> > On Mon, 2024-01-15 at 19:15 +0000, Al Viro wrote:
> >> On Mon, Jan 15, 2024 at 07:17:57PM +0100, Roberto Sassu wrote:
> >>> From: Roberto Sassu <roberto.sassu@huawei.com>
> >>>
> >>> In preparation for moving IMA and EVM to the LSM infrastructure, introduce
> >>> the file_release hook.
> >>>
> >>> IMA calculates at file close the new digest of the file content and writes
> >>> it to security.ima, so that appraisal at next file access succeeds.
> >>>
> >>> An LSM could implement an exclusive access scheme for files, only allowing
> >>> access to files that have no references.
> >> Elaborate that last part, please.
> > Apologies, I didn't understand that either. Casey?
> 
> Just a hypothetical notion that if an LSM wanted to implement an
> exclusive access scheme it might find the proposed hook helpful.
> I don't have any plan to create such a scheme, nor do I think that
> a file_release hook would be the only thing you'd need.

Exclusive access to what?  "No more than one opened file with this
inode at a time"?  It won't serialize IO operations, obviously...
Details, please.
Casey Schaufler Jan. 16, 2024, 6:18 p.m. UTC | #3
On 1/16/2024 9:33 AM, Al Viro wrote:
> On Tue, Jan 16, 2024 at 08:51:11AM -0800, Casey Schaufler wrote:
>> On 1/16/2024 12:47 AM, Roberto Sassu wrote:
>>> On Mon, 2024-01-15 at 19:15 +0000, Al Viro wrote:
>>>> On Mon, Jan 15, 2024 at 07:17:57PM +0100, Roberto Sassu wrote:
>>>>> From: Roberto Sassu <roberto.sassu@huawei.com>
>>>>>
>>>>> In preparation for moving IMA and EVM to the LSM infrastructure, introduce
>>>>> the file_release hook.
>>>>>
>>>>> IMA calculates at file close the new digest of the file content and writes
>>>>> it to security.ima, so that appraisal at next file access succeeds.
>>>>>
>>>>> An LSM could implement an exclusive access scheme for files, only allowing
>>>>> access to files that have no references.
>>>> Elaborate that last part, please.
>>> Apologies, I didn't understand that either. Casey?
>> Just a hypothetical notion that if an LSM wanted to implement an
>> exclusive access scheme it might find the proposed hook helpful.
>> I don't have any plan to create such a scheme, nor do I think that
>> a file_release hook would be the only thing you'd need.
> Exclusive access to what?  "No more than one opened file with this
> inode at a time"?  It won't serialize IO operations, obviously...
> Details, please.

Once a file is opened it can't be opened again until it is closed.
That's the simple description, which ignores all sorts of cases.
I wouldn't want my system to behave that way, but I have heard
arguments that multiple concurrent opens can be a security issue.
In the context of my review of the code in question I included
the comment solely for the purpose of acknowledging the potential
for additional uses of the proposed hook. It's entirely possible
someone (not me!) would use the hook in this or some other "clever"
way.
Casey Schaufler Jan. 16, 2024, 7:39 p.m. UTC | #4
On 1/15/2024 10:18 AM, Roberto Sassu wrote:
> From: Roberto Sassu <roberto.sassu@huawei.com>
>
> Define a new structure for EVM-specific metadata, called evm_iint_cache,
> and embed it in the inode security blob. Introduce evm_iint_inode() to
> retrieve metadata, and register evm_inode_alloc_security() for the
> inode_alloc_security LSM hook, to initialize the structure (before
> splitting metadata, this task was done by iint_init_always()).
>
> Keep the non-NULL checks after calling evm_iint_inode() except in
> evm_inode_alloc_security(), to take into account inodes for which
> security_inode_alloc() was not called. When using shared metadata,
> obtaining a NULL pointer from integrity_iint_find() meant that the file
> wasn't in the IMA policy. Now, because IMA and EVM use disjoint metadata,
> the EVM status has to be stored for every inode regardless of the IMA
> policy.
>
> Given that from now on EVM relies on its own metadata, remove the iint
> parameter from evm_verifyxattr(). Also, directly retrieve the iint in
> evm_verify_hmac(), called by both evm_verifyxattr() and
> evm_verify_current_integrity(), since now there is no performance penalty
> in retrieving EVM metadata (constant time).
>
> Replicate the management of the IMA_NEW_FILE flag, by introducing
> evm_post_path_mknod() and evm_file_release() to respectively set and clear
> the newly introduced flag EVM_NEW_FILE, at the same time IMA does. Like for
> IMA, select CONFIG_SECURITY_PATH when EVM is enabled, to ensure that files
> are marked as new.
>
> Unlike ima_post_path_mknod(), evm_post_path_mknod() cannot check if a file
> must be appraised. Thus, it marks all affected files. Also, it does not
> clear EVM_NEW_FILE depending on i_version, but that is not a problem
> because IMA_NEW_FILE is always cleared when set in ima_check_last_writer().
>
> Move the EVM-specific flag EVM_IMMUTABLE_DIGSIG to
> security/integrity/evm/evm.h, since that definition is now unnecessary in
> the common integrity layer.
>
> Finally, switch to the LSM reservation mechanism for the EVM xattr, and
> consequently decrement by one the number of xattrs to allocate in
> security_inode_init_security().
>
> Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>

Reviewed-by: Casey Schaufler <casey@schaufler-ca.com>

> ---
>  include/linux/evm.h                   |  8 +--
>  security/integrity/evm/Kconfig        |  1 +
>  security/integrity/evm/evm.h          | 19 +++++++
>  security/integrity/evm/evm_crypto.c   |  4 +-
>  security/integrity/evm/evm_main.c     | 76 ++++++++++++++++++++-------
>  security/integrity/ima/ima_appraise.c |  2 +-
>  security/integrity/integrity.h        |  1 -
>  security/security.c                   |  4 +-
>  8 files changed, 83 insertions(+), 32 deletions(-)
>
> diff --git a/include/linux/evm.h b/include/linux/evm.h
> index cb481eccc967..d48d6da32315 100644
> --- a/include/linux/evm.h
> +++ b/include/linux/evm.h
> @@ -12,15 +12,12 @@
>  #include <linux/integrity.h>
>  #include <linux/xattr.h>
>  
> -struct integrity_iint_cache;
> -
>  #ifdef CONFIG_EVM
>  extern int evm_set_key(void *key, size_t keylen);
>  extern enum integrity_status evm_verifyxattr(struct dentry *dentry,
>  					     const char *xattr_name,
>  					     void *xattr_value,
> -					     size_t xattr_value_len,
> -					     struct integrity_iint_cache *iint);
> +					     size_t xattr_value_len);
>  int evm_inode_init_security(struct inode *inode, struct inode *dir,
>  			    const struct qstr *qstr, struct xattr *xattrs,
>  			    int *xattr_count);
> @@ -48,8 +45,7 @@ static inline int evm_set_key(void *key, size_t keylen)
>  static inline enum integrity_status evm_verifyxattr(struct dentry *dentry,
>  						    const char *xattr_name,
>  						    void *xattr_value,
> -						    size_t xattr_value_len,
> -					struct integrity_iint_cache *iint)
> +						    size_t xattr_value_len)
>  {
>  	return INTEGRITY_UNKNOWN;
>  }
> diff --git a/security/integrity/evm/Kconfig b/security/integrity/evm/Kconfig
> index fba9ee359bc9..861b3bacab82 100644
> --- a/security/integrity/evm/Kconfig
> +++ b/security/integrity/evm/Kconfig
> @@ -6,6 +6,7 @@ config EVM
>  	select CRYPTO_HMAC
>  	select CRYPTO_SHA1
>  	select CRYPTO_HASH_INFO
> +	select SECURITY_PATH
>  	default n
>  	help
>  	  EVM protects a file's security extended attributes against
> diff --git a/security/integrity/evm/evm.h b/security/integrity/evm/evm.h
> index 53bd7fec93fa..eb1a2c343bd7 100644
> --- a/security/integrity/evm/evm.h
> +++ b/security/integrity/evm/evm.h
> @@ -32,6 +32,25 @@ struct xattr_list {
>  	bool enabled;
>  };
>  
> +#define EVM_NEW_FILE			0x00000001
> +#define EVM_IMMUTABLE_DIGSIG		0x00000002
> +
> +/* EVM integrity metadata associated with an inode */
> +struct evm_iint_cache {
> +	unsigned long flags;
> +	enum integrity_status evm_status:4;
> +};
> +
> +extern struct lsm_blob_sizes evm_blob_sizes;
> +
> +static inline struct evm_iint_cache *evm_iint_inode(const struct inode *inode)
> +{
> +	if (unlikely(!inode->i_security))
> +		return NULL;
> +
> +	return inode->i_security + evm_blob_sizes.lbs_inode;
> +}
> +
>  extern int evm_initialized;
>  
>  #define EVM_ATTR_FSUUID		0x0001
> diff --git a/security/integrity/evm/evm_crypto.c b/security/integrity/evm/evm_crypto.c
> index b1ffd4cc0b44..7552d49d0725 100644
> --- a/security/integrity/evm/evm_crypto.c
> +++ b/security/integrity/evm/evm_crypto.c
> @@ -322,10 +322,10 @@ int evm_calc_hash(struct dentry *dentry, const char *req_xattr_name,
>  static int evm_is_immutable(struct dentry *dentry, struct inode *inode)
>  {
>  	const struct evm_ima_xattr_data *xattr_data = NULL;
> -	struct integrity_iint_cache *iint;
> +	struct evm_iint_cache *iint;
>  	int rc = 0;
>  
> -	iint = integrity_iint_find(inode);
> +	iint = evm_iint_inode(inode);
>  	if (iint && (iint->flags & EVM_IMMUTABLE_DIGSIG))
>  		return 1;
>  
> diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c
> index f65dbf3e9256..14c8f38e61d6 100644
> --- a/security/integrity/evm/evm_main.c
> +++ b/security/integrity/evm/evm_main.c
> @@ -178,14 +178,14 @@ static int is_unsupported_fs(struct dentry *dentry)
>  static enum integrity_status evm_verify_hmac(struct dentry *dentry,
>  					     const char *xattr_name,
>  					     char *xattr_value,
> -					     size_t xattr_value_len,
> -					     struct integrity_iint_cache *iint)
> +					     size_t xattr_value_len)
>  {
>  	struct evm_ima_xattr_data *xattr_data = NULL;
>  	struct signature_v2_hdr *hdr;
>  	enum integrity_status evm_status = INTEGRITY_PASS;
>  	struct evm_digest digest;
> -	struct inode *inode;
> +	struct inode *inode = d_backing_inode(dentry);
> +	struct evm_iint_cache *iint = evm_iint_inode(inode);
>  	int rc, xattr_len, evm_immutable = 0;
>  
>  	if (iint && (iint->evm_status == INTEGRITY_PASS ||
> @@ -254,8 +254,6 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry,
>  					(const char *)xattr_data, xattr_len,
>  					digest.digest, digest.hdr.length);
>  		if (!rc) {
> -			inode = d_backing_inode(dentry);
> -
>  			if (xattr_data->type == EVM_XATTR_PORTABLE_DIGSIG) {
>  				if (iint)
>  					iint->flags |= EVM_IMMUTABLE_DIGSIG;
> @@ -403,7 +401,6 @@ int evm_read_protected_xattrs(struct dentry *dentry, u8 *buffer,
>   * @xattr_name: requested xattr
>   * @xattr_value: requested xattr value
>   * @xattr_value_len: requested xattr value length
> - * @iint: inode integrity metadata
>   *
>   * Calculate the HMAC for the given dentry and verify it against the stored
>   * security.evm xattr. For performance, use the xattr value and length
> @@ -416,8 +413,7 @@ int evm_read_protected_xattrs(struct dentry *dentry, u8 *buffer,
>   */
>  enum integrity_status evm_verifyxattr(struct dentry *dentry,
>  				      const char *xattr_name,
> -				      void *xattr_value, size_t xattr_value_len,
> -				      struct integrity_iint_cache *iint)
> +				      void *xattr_value, size_t xattr_value_len)
>  {
>  	if (!evm_key_loaded() || !evm_protected_xattr(xattr_name))
>  		return INTEGRITY_UNKNOWN;
> @@ -425,13 +421,8 @@ enum integrity_status evm_verifyxattr(struct dentry *dentry,
>  	if (is_unsupported_fs(dentry))
>  		return INTEGRITY_UNKNOWN;
>  
> -	if (!iint) {
> -		iint = integrity_iint_find(d_backing_inode(dentry));
> -		if (!iint)
> -			return INTEGRITY_UNKNOWN;
> -	}
>  	return evm_verify_hmac(dentry, xattr_name, xattr_value,
> -				 xattr_value_len, iint);
> +				 xattr_value_len);
>  }
>  EXPORT_SYMBOL_GPL(evm_verifyxattr);
>  
> @@ -448,7 +439,7 @@ static enum integrity_status evm_verify_current_integrity(struct dentry *dentry)
>  
>  	if (!evm_key_loaded() || !S_ISREG(inode->i_mode) || evm_fixmode)
>  		return INTEGRITY_PASS;
> -	return evm_verify_hmac(dentry, NULL, NULL, 0, NULL);
> +	return evm_verify_hmac(dentry, NULL, NULL, 0);
>  }
>  
>  /*
> @@ -526,14 +517,14 @@ static int evm_protect_xattr(struct mnt_idmap *idmap,
>  
>  	evm_status = evm_verify_current_integrity(dentry);
>  	if (evm_status == INTEGRITY_NOXATTRS) {
> -		struct integrity_iint_cache *iint;
> +		struct evm_iint_cache *iint;
>  
>  		/* Exception if the HMAC is not going to be calculated. */
>  		if (evm_hmac_disabled())
>  			return 0;
>  
> -		iint = integrity_iint_find(d_backing_inode(dentry));
> -		if (iint && (iint->flags & IMA_NEW_FILE))
> +		iint = evm_iint_inode(d_backing_inode(dentry));
> +		if (iint && (iint->flags & EVM_NEW_FILE))
>  			return 0;
>  
>  		/* exception for pseudo filesystems */
> @@ -735,9 +726,9 @@ static int evm_inode_remove_acl(struct mnt_idmap *idmap, struct dentry *dentry,
>  
>  static void evm_reset_status(struct inode *inode)
>  {
> -	struct integrity_iint_cache *iint;
> +	struct evm_iint_cache *iint;
>  
> -	iint = integrity_iint_find(inode);
> +	iint = evm_iint_inode(inode);
>  	if (iint)
>  		iint->evm_status = INTEGRITY_UNKNOWN;
>  }
> @@ -1019,6 +1010,42 @@ int evm_inode_init_security(struct inode *inode, struct inode *dir,
>  }
>  EXPORT_SYMBOL_GPL(evm_inode_init_security);
>  
> +static int evm_inode_alloc_security(struct inode *inode)
> +{
> +	struct evm_iint_cache *iint = evm_iint_inode(inode);
> +
> +	/* Called by security_inode_alloc(), it cannot be NULL. */
> +	iint->flags = 0UL;
> +	iint->evm_status = INTEGRITY_UNKNOWN;
> +
> +	return 0;
> +}
> +
> +static void evm_file_release(struct file *file)
> +{
> +	struct inode *inode = file_inode(file);
> +	struct evm_iint_cache *iint = evm_iint_inode(inode);
> +	fmode_t mode = file->f_mode;
> +
> +	if (!S_ISREG(inode->i_mode) || !(mode & FMODE_WRITE))
> +		return;
> +
> +	if (iint && atomic_read(&inode->i_writecount) == 1)
> +		iint->flags &= ~EVM_NEW_FILE;
> +}
> +
> +static void evm_post_path_mknod(struct mnt_idmap *idmap, struct dentry *dentry)
> +{
> +	struct inode *inode = d_backing_inode(dentry);
> +	struct evm_iint_cache *iint = evm_iint_inode(inode);
> +
> +	if (!S_ISREG(inode->i_mode))
> +		return;
> +
> +	if (iint)
> +		iint->flags |= EVM_NEW_FILE;
> +}
> +
>  #ifdef CONFIG_EVM_LOAD_X509
>  void __init evm_load_x509(void)
>  {
> @@ -1071,6 +1098,9 @@ static struct security_hook_list evm_hooks[] __ro_after_init = {
>  	LSM_HOOK_INIT(inode_removexattr, evm_inode_removexattr),
>  	LSM_HOOK_INIT(inode_post_removexattr, evm_inode_post_removexattr),
>  	LSM_HOOK_INIT(inode_init_security, evm_inode_init_security),
> +	LSM_HOOK_INIT(inode_alloc_security, evm_inode_alloc_security),
> +	LSM_HOOK_INIT(file_release, evm_file_release),
> +	LSM_HOOK_INIT(path_post_mknod, evm_post_path_mknod),
>  };
>  
>  static const struct lsm_id evm_lsmid = {
> @@ -1084,10 +1114,16 @@ static int __init init_evm_lsm(void)
>  	return 0;
>  }
>  
> +struct lsm_blob_sizes evm_blob_sizes __ro_after_init = {
> +	.lbs_inode = sizeof(struct evm_iint_cache),
> +	.lbs_xattr_count = 1,
> +};
> +
>  DEFINE_LSM(evm) = {
>  	.name = "evm",
>  	.init = init_evm_lsm,
>  	.order = LSM_ORDER_LAST,
> +	.blobs = &evm_blob_sizes,
>  };
>  
>  late_initcall(init_evm);
> diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c
> index 076451109637..1dd6ee72a20a 100644
> --- a/security/integrity/ima/ima_appraise.c
> +++ b/security/integrity/ima/ima_appraise.c
> @@ -520,7 +520,7 @@ int ima_appraise_measurement(enum ima_hooks func,
>  	}
>  
>  	status = evm_verifyxattr(dentry, XATTR_NAME_IMA, xattr_value,
> -				 rc < 0 ? 0 : rc, iint);
> +				 rc < 0 ? 0 : rc);
>  	switch (status) {
>  	case INTEGRITY_PASS:
>  	case INTEGRITY_PASS_IMMUTABLE:
> diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h
> index 59eaddd84434..7a97c269a072 100644
> --- a/security/integrity/integrity.h
> +++ b/security/integrity/integrity.h
> @@ -37,7 +37,6 @@
>  #define IMA_DIGSIG_REQUIRED	0x01000000
>  #define IMA_PERMIT_DIRECTIO	0x02000000
>  #define IMA_NEW_FILE		0x04000000
> -#define EVM_IMMUTABLE_DIGSIG	0x08000000
>  #define IMA_FAIL_UNVERIFIABLE_SIGS	0x10000000
>  #define IMA_MODSIG_ALLOWED	0x20000000
>  #define IMA_CHECK_BLACKLIST	0x40000000
> diff --git a/security/security.c b/security/security.c
> index a44740640a9a..f811cc376a7a 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -1716,8 +1716,8 @@ int security_inode_init_security(struct inode *inode, struct inode *dir,
>  		return 0;
>  
>  	if (initxattrs) {
> -		/* Allocate +1 for EVM and +1 as terminator. */
> -		new_xattrs = kcalloc(blob_sizes.lbs_xattr_count + 2,
> +		/* Allocate +1 as terminator. */
> +		new_xattrs = kcalloc(blob_sizes.lbs_xattr_count + 1,
>  				     sizeof(*new_xattrs), GFP_NOFS);
>  		if (!new_xattrs)
>  			return -ENOMEM;
Casey Schaufler Jan. 16, 2024, 7:41 p.m. UTC | #5
On 1/15/2024 10:18 AM, Roberto Sassu wrote:
> From: Roberto Sassu <roberto.sassu@huawei.com>
>
> Since now IMA and EVM use their own integrity metadata, it is safe to
> remove the 'integrity' LSM, with its management of integrity metadata.
>
> Keep the iint.c file only for loading IMA and EVM keys at boot, and for
> creating the integrity directory in securityfs (we need to keep it for
> retrocompatibility reasons).
>
> Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>

Reviewed-by: Casey Schaufler <casey@schaufler-ca.com>

> ---
>  include/linux/integrity.h      |  14 ---
>  security/integrity/iint.c      | 197 +--------------------------------
>  security/integrity/integrity.h |  25 -----
>  security/security.c            |   2 -
>  4 files changed, 2 insertions(+), 236 deletions(-)
>
> diff --git a/include/linux/integrity.h b/include/linux/integrity.h
> index ef0f63ef5ebc..459b79683783 100644
> --- a/include/linux/integrity.h
> +++ b/include/linux/integrity.h
> @@ -19,24 +19,10 @@ enum integrity_status {
>  	INTEGRITY_UNKNOWN,
>  };
>  
> -/* List of EVM protected security xattrs */
>  #ifdef CONFIG_INTEGRITY
> -extern struct integrity_iint_cache *integrity_inode_get(struct inode *inode);
> -extern void integrity_inode_free(struct inode *inode);
>  extern void __init integrity_load_keys(void);
>  
>  #else
> -static inline struct integrity_iint_cache *
> -				integrity_inode_get(struct inode *inode)
> -{
> -	return NULL;
> -}
> -
> -static inline void integrity_inode_free(struct inode *inode)
> -{
> -	return;
> -}
> -
>  static inline void integrity_load_keys(void)
>  {
>  }
> diff --git a/security/integrity/iint.c b/security/integrity/iint.c
> index d4419a2a1e24..068ac6c2ae1e 100644
> --- a/security/integrity/iint.c
> +++ b/security/integrity/iint.c
> @@ -6,207 +6,14 @@
>   * Mimi Zohar <zohar@us.ibm.com>
>   *
>   * File: integrity_iint.c
> - *	- implements the integrity hooks: integrity_inode_alloc,
> - *	  integrity_inode_free
> - *	- cache integrity information associated with an inode
> - *	  using a rbtree tree.
> + *	- initialize the integrity directory in securityfs
> + *	- load IMA and EVM keys
>   */
> -#include <linux/slab.h>
> -#include <linux/init.h>
> -#include <linux/spinlock.h>
> -#include <linux/rbtree.h>
> -#include <linux/file.h>
> -#include <linux/uaccess.h>
>  #include <linux/security.h>
> -#include <linux/lsm_hooks.h>
>  #include "integrity.h"
>  
> -static struct rb_root integrity_iint_tree = RB_ROOT;
> -static DEFINE_RWLOCK(integrity_iint_lock);
> -static struct kmem_cache *iint_cache __ro_after_init;
> -
>  struct dentry *integrity_dir;
>  
> -/*
> - * __integrity_iint_find - return the iint associated with an inode
> - */
> -static struct integrity_iint_cache *__integrity_iint_find(struct inode *inode)
> -{
> -	struct integrity_iint_cache *iint;
> -	struct rb_node *n = integrity_iint_tree.rb_node;
> -
> -	while (n) {
> -		iint = rb_entry(n, struct integrity_iint_cache, rb_node);
> -
> -		if (inode < iint->inode)
> -			n = n->rb_left;
> -		else if (inode > iint->inode)
> -			n = n->rb_right;
> -		else
> -			return iint;
> -	}
> -
> -	return NULL;
> -}
> -
> -/*
> - * integrity_iint_find - return the iint associated with an inode
> - */
> -struct integrity_iint_cache *integrity_iint_find(struct inode *inode)
> -{
> -	struct integrity_iint_cache *iint;
> -
> -	if (!IS_IMA(inode))
> -		return NULL;
> -
> -	read_lock(&integrity_iint_lock);
> -	iint = __integrity_iint_find(inode);
> -	read_unlock(&integrity_iint_lock);
> -
> -	return iint;
> -}
> -
> -#define IMA_MAX_NESTING (FILESYSTEM_MAX_STACK_DEPTH+1)
> -
> -/*
> - * It is not clear that IMA should be nested at all, but as long is it measures
> - * files both on overlayfs and on underlying fs, we need to annotate the iint
> - * mutex to avoid lockdep false positives related to IMA + overlayfs.
> - * See ovl_lockdep_annotate_inode_mutex_key() for more details.
> - */
> -static inline void iint_lockdep_annotate(struct integrity_iint_cache *iint,
> -					 struct inode *inode)
> -{
> -#ifdef CONFIG_LOCKDEP
> -	static struct lock_class_key iint_mutex_key[IMA_MAX_NESTING];
> -
> -	int depth = inode->i_sb->s_stack_depth;
> -
> -	if (WARN_ON_ONCE(depth < 0 || depth >= IMA_MAX_NESTING))
> -		depth = 0;
> -
> -	lockdep_set_class(&iint->mutex, &iint_mutex_key[depth]);
> -#endif
> -}
> -
> -static void iint_init_always(struct integrity_iint_cache *iint,
> -			     struct inode *inode)
> -{
> -	iint->ima_hash = NULL;
> -	iint->version = 0;
> -	iint->flags = 0UL;
> -	iint->atomic_flags = 0UL;
> -	iint->ima_file_status = INTEGRITY_UNKNOWN;
> -	iint->ima_mmap_status = INTEGRITY_UNKNOWN;
> -	iint->ima_bprm_status = INTEGRITY_UNKNOWN;
> -	iint->ima_read_status = INTEGRITY_UNKNOWN;
> -	iint->ima_creds_status = INTEGRITY_UNKNOWN;
> -	iint->evm_status = INTEGRITY_UNKNOWN;
> -	iint->measured_pcrs = 0;
> -	mutex_init(&iint->mutex);
> -	iint_lockdep_annotate(iint, inode);
> -}
> -
> -static void iint_free(struct integrity_iint_cache *iint)
> -{
> -	kfree(iint->ima_hash);
> -	mutex_destroy(&iint->mutex);
> -	kmem_cache_free(iint_cache, iint);
> -}
> -
> -/**
> - * integrity_inode_get - find or allocate an iint associated with an inode
> - * @inode: pointer to the inode
> - * @return: allocated iint
> - *
> - * Caller must lock i_mutex
> - */
> -struct integrity_iint_cache *integrity_inode_get(struct inode *inode)
> -{
> -	struct rb_node **p;
> -	struct rb_node *node, *parent = NULL;
> -	struct integrity_iint_cache *iint, *test_iint;
> -
> -	iint = integrity_iint_find(inode);
> -	if (iint)
> -		return iint;
> -
> -	iint = kmem_cache_alloc(iint_cache, GFP_NOFS);
> -	if (!iint)
> -		return NULL;
> -
> -	iint_init_always(iint, inode);
> -
> -	write_lock(&integrity_iint_lock);
> -
> -	p = &integrity_iint_tree.rb_node;
> -	while (*p) {
> -		parent = *p;
> -		test_iint = rb_entry(parent, struct integrity_iint_cache,
> -				     rb_node);
> -		if (inode < test_iint->inode) {
> -			p = &(*p)->rb_left;
> -		} else if (inode > test_iint->inode) {
> -			p = &(*p)->rb_right;
> -		} else {
> -			write_unlock(&integrity_iint_lock);
> -			kmem_cache_free(iint_cache, iint);
> -			return test_iint;
> -		}
> -	}
> -
> -	iint->inode = inode;
> -	node = &iint->rb_node;
> -	inode->i_flags |= S_IMA;
> -	rb_link_node(node, parent, p);
> -	rb_insert_color(node, &integrity_iint_tree);
> -
> -	write_unlock(&integrity_iint_lock);
> -	return iint;
> -}
> -
> -/**
> - * integrity_inode_free - called on security_inode_free
> - * @inode: pointer to the inode
> - *
> - * Free the integrity information(iint) associated with an inode.
> - */
> -void integrity_inode_free(struct inode *inode)
> -{
> -	struct integrity_iint_cache *iint;
> -
> -	if (!IS_IMA(inode))
> -		return;
> -
> -	write_lock(&integrity_iint_lock);
> -	iint = __integrity_iint_find(inode);
> -	rb_erase(&iint->rb_node, &integrity_iint_tree);
> -	write_unlock(&integrity_iint_lock);
> -
> -	iint_free(iint);
> -}
> -
> -static void iint_init_once(void *foo)
> -{
> -	struct integrity_iint_cache *iint = (struct integrity_iint_cache *) foo;
> -
> -	memset(iint, 0, sizeof(*iint));
> -}
> -
> -static int __init integrity_iintcache_init(void)
> -{
> -	iint_cache =
> -	    kmem_cache_create("iint_cache", sizeof(struct integrity_iint_cache),
> -			      0, SLAB_PANIC, iint_init_once);
> -	return 0;
> -}
> -DEFINE_LSM(integrity) = {
> -	.name = "integrity",
> -	.init = integrity_iintcache_init,
> -	.order = LSM_ORDER_LAST,
> -};
> -
> -
>  /*
>   * integrity_kernel_read - read data from the file
>   *
> diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h
> index 671fc50255f9..50d6f798e613 100644
> --- a/security/integrity/integrity.h
> +++ b/security/integrity/integrity.h
> @@ -102,31 +102,6 @@ struct ima_file_id {
>  	__u8 hash[HASH_MAX_DIGESTSIZE];
>  } __packed;
>  
> -/* 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 measured_pcrs;
> -	unsigned long atomic_flags;
> -	unsigned long real_ino;
> -	dev_t real_dev;
> -	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;
> -};
> -
> -/* rbtree tree calls to lookup, insert, delete
> - * integrity data associated with an inode.
> - */
> -struct integrity_iint_cache *integrity_iint_find(struct inode *inode);
> -
>  int integrity_kernel_read(struct file *file, loff_t offset,
>  			  void *addr, unsigned long count);
>  
> diff --git a/security/security.c b/security/security.c
> index f811cc376a7a..df87c0a7eaac 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -19,7 +19,6 @@
>  #include <linux/kernel.h>
>  #include <linux/kernel_read_file.h>
>  #include <linux/lsm_hooks.h>
> -#include <linux/integrity.h>
>  #include <linux/fsnotify.h>
>  #include <linux/mman.h>
>  #include <linux/mount.h>
> @@ -1597,7 +1596,6 @@ static void inode_free_by_rcu(struct rcu_head *head)
>   */
>  void security_inode_free(struct inode *inode)
>  {
> -	integrity_inode_free(inode);
>  	call_void_hook(inode_free_security, inode);
>  	/*
>  	 * The inode may still be referenced in a path walk and
Paul Moore Feb. 8, 2024, 3:18 a.m. UTC | #6
On Jan 15, 2024 Roberto Sassu <roberto.sassu@huaweicloud.com> wrote:
> 
> IMA and EVM are not effectively LSMs, especially due to the fact that in
> the past they could not provide a security blob while there is another LSM
> active.
> 
> That changed in the recent years, the LSM stacking feature now makes it
> possible to stack together multiple LSMs, and allows them to provide a
> security blob for most kernel objects. While the LSM stacking feature has
> some limitations being worked out, it is already suitable to make IMA and
> EVM as LSMs.
> 
> The main purpose of this patch set is to remove IMA and EVM function calls,
> hardcoded in the LSM infrastructure and other places in the kernel, and to
> register them as LSM hook implementations, so that those functions are
> called by the LSM infrastructure like other regular LSMs.

Thanks Roberto, this is looking good.  I appreciate all the work you've
put into making this happen; when I first mentioned this idea I figured
it would be something that would happen much farther into the future, I
wasn't expecting to see you pick this up and put in the work to make it
happen - thank you.

I had some pretty minor comments but I think the only thing I saw that
I think needs a change/addition is a comment in the Makefile regarding
the IMA/EVM ordering; take a look and let me know what you think.

There are also a few patches in the patchset that don't have an
ACK/review tag from Mimi, although now that you are co-maininting IMA/EVM
with Mimi I don't know if that matters.  If the two of you can let me
know how you want me to handle LSM patches that are IMA/EVM related I
would appreciate it (two ACKs, one or other, something else?).

Once you add a Makefile commane and we sort out the IMA/EVM approval
process I think we're good to get this into linux-next.  A while back
Mimi and I had a chat offline and if I recall everything correctly she
preferred that I take this patchset via the LSM tree.  I don't have a
problem with that, and to be honest I would probably prefer
that too, but I wanted to check with everyone that is still the case.
Just in case, I've added my ACKs/reviews to this patchset in case this
needs to be merged via the integrity tree.

--
paul-moore.com
Roberto Sassu Feb. 8, 2024, 8:05 a.m. UTC | #7
On Wed, 2024-02-07 at 22:18 -0500, Paul Moore wrote:
> On Jan 15, 2024 Roberto Sassu <roberto.sassu@huaweicloud.com> wrote:
> > 
> > IMA and EVM are not effectively LSMs, especially due to the fact that in
> > the past they could not provide a security blob while there is another LSM
> > active.
> > 
> > That changed in the recent years, the LSM stacking feature now makes it
> > possible to stack together multiple LSMs, and allows them to provide a
> > security blob for most kernel objects. While the LSM stacking feature has
> > some limitations being worked out, it is already suitable to make IMA and
> > EVM as LSMs.
> > 
> > The main purpose of this patch set is to remove IMA and EVM function calls,
> > hardcoded in the LSM infrastructure and other places in the kernel, and to
> > register them as LSM hook implementations, so that those functions are
> > called by the LSM infrastructure like other regular LSMs.
> 
> Thanks Roberto, this is looking good.  I appreciate all the work you've
> put into making this happen; when I first mentioned this idea I figured
> it would be something that would happen much farther into the future, I
> wasn't expecting to see you pick this up and put in the work to make it
> happen - thank you.

Thanks! I also appreciate a lot your guidance and suggestions.

> I had some pretty minor comments but I think the only thing I saw that
> I think needs a change/addition is a comment in the Makefile regarding
> the IMA/EVM ordering; take a look and let me know what you think.

Oh, I remember well, it is there but difficult to spot...

--- a/security/integrity/Makefile
+++ b/security/integrity/Makefile
@@ -18,5 +18,6 @@ integrity-$(CONFIG_LOAD_IPL_KEYS) += platform_certs/load_ipl_s390.o
 integrity-$(CONFIG_LOAD_PPC_KEYS) += platform_certs/efi_parser.o \
                                      platform_certs/load_powerpc.o \
                                      platform_certs/keyring_handler.o
+# The relative order of the 'ima' and 'evm' LSMs depends on the order below.
 obj-$(CONFIG_IMA)			+= ima/
 obj-$(CONFIG_EVM)			+= evm/

> There are also a few patches in the patchset that don't have an
> ACK/review tag from Mimi, although now that you are co-maininting IMA/EVM
> with Mimi I don't know if that matters.  If the two of you can let me
> know how you want me to handle LSM patches that are IMA/EVM related I
> would appreciate it (two ACKs, one or other, something else?).

Ok, we will come back to you about this.

> Once you add a Makefile commane and we sort out the IMA/EVM approval
> process I think we're good to get this into linux-next.  A while back
> Mimi and I had a chat offline and if I recall everything correctly she
> preferred that I take this patchset via the LSM tree.  I don't have a
> problem with that, and to be honest I would probably prefer
> that too, but I wanted to check with everyone that is still the case.
> Just in case, I've added my ACKs/reviews to this patchset in case this
> needs to be merged via the integrity tree.

Ok, given that there is the comment in the Makefile, the last thing to
do from your side is to remove the vague comment in the file_release
patch.

Other than that, I think Mimi wanted to give a last look. If that is
ok, then the patches should be ready for your repo and linux-next.

Thanks

Roberto
Paul Moore Feb. 8, 2024, 2:16 p.m. UTC | #8
On Thu, Feb 8, 2024 at 3:06 AM Roberto Sassu
<roberto.sassu@huaweicloud.com> wrote:
> On Wed, 2024-02-07 at 22:18 -0500, Paul Moore wrote:

...

> > I had some pretty minor comments but I think the only thing I saw that
> > I think needs a change/addition is a comment in the Makefile regarding
> > the IMA/EVM ordering; take a look and let me know what you think.
>
> Oh, I remember well, it is there but difficult to spot...
>
> --- a/security/integrity/Makefile
> +++ b/security/integrity/Makefile
> @@ -18,5 +18,6 @@ integrity-$(CONFIG_LOAD_IPL_KEYS) += platform_certs/load_ipl_s390.o
>  integrity-$(CONFIG_LOAD_PPC_KEYS) += platform_certs/efi_parser.o \
>                                       platform_certs/load_powerpc.o \
>                                       platform_certs/keyring_handler.o
> +# The relative order of the 'ima' and 'evm' LSMs depends on the order below.
>  obj-$(CONFIG_IMA)                      += ima/
>  obj-$(CONFIG_EVM)                      += evm/

Great, thanks for that.  Not sure how I missed that ... ?

> > Once you add a Makefile commane and we sort out the IMA/EVM approval
> > process I think we're good to get this into linux-next.  A while back
> > Mimi and I had a chat offline and if I recall everything correctly she
> > preferred that I take this patchset via the LSM tree.  I don't have a
> > problem with that, and to be honest I would probably prefer
> > that too, but I wanted to check with everyone that is still the case.
> > Just in case, I've added my ACKs/reviews to this patchset in case this
> > needs to be merged via the integrity tree.
>
> Ok, given that there is the comment in the Makefile, the last thing to
> do from your side is to remove the vague comment in the file_release
> patch.
>
> Other than that, I think Mimi wanted to give a last look. If that is
> ok, then the patches should be ready for your repo and linux-next.

If Mimi is okay with the patchset as-is, and both of you would prefer
this to in via the LSM tree, don't worry about the file_release
comment, I'll just remove that when merging.
Christian Brauner Feb. 9, 2024, 9:53 a.m. UTC | #9
On Mon, Jan 15, 2024 at 07:17:59PM +0100, Roberto Sassu wrote:
> From: Roberto Sassu <roberto.sassu@huawei.com>
> 
> In preparation for moving IMA and EVM to the LSM infrastructure, introduce
> the inode_post_create_tmpfile hook.
> 
> As temp files can be made persistent, treat new temp files like other new
> files, so that the file hash is calculated and stored in the security
> xattr.
> 
> LSMs could also take some action after temp files have been created.
> 
> The new hook cannot return an error and cannot cause the operation to be
> canceled.
> 
> Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
> Acked-by: Casey Schaufler <casey@schaufler-ca.com>
> Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
> ---
>  fs/namei.c                    |  1 +

Acked-by: Christian Brauner <brauner@kernel.org>
Christian Brauner Feb. 9, 2024, 9:56 a.m. UTC | #10
On Mon, Jan 15, 2024 at 07:17:56PM +0100, Roberto Sassu wrote:
> From: Roberto Sassu <roberto.sassu@huawei.com>
> 
> In preparation to move IMA and EVM to the LSM infrastructure, introduce the
> file_post_open hook. Also, export security_file_post_open() for NFS.
> 
> Based on policy, IMA calculates the digest of the file content and
> extends the TPM with the digest, verifies the file's integrity based on
> the digest, and/or includes the file digest in the audit log.
> 
> LSMs could similarly take action depending on the file content and the
> access mask requested with open().
> 
> The new hook returns a value and can cause the open to be aborted.
> 
> Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
> Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
> Acked-by: Casey Schaufler <casey@schaufler-ca.com>
> Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
> ---
>  fs/namei.c                    |  2 ++

Acked-by: Christian Brauner <brauner@kernel.org>
Christian Brauner Feb. 9, 2024, 10:12 a.m. UTC | #11
On Mon, Jan 15, 2024 at 07:17:56PM +0100, Roberto Sassu wrote:
> From: Roberto Sassu <roberto.sassu@huawei.com>
> 
> In preparation to move IMA and EVM to the LSM infrastructure, introduce the
> file_post_open hook. Also, export security_file_post_open() for NFS.
> 
> Based on policy, IMA calculates the digest of the file content and
> extends the TPM with the digest, verifies the file's integrity based on
> the digest, and/or includes the file digest in the audit log.
> 
> LSMs could similarly take action depending on the file content and the
> access mask requested with open().
> 
> The new hook returns a value and can cause the open to be aborted.
> 
> Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
> Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
> Acked-by: Casey Schaufler <casey@schaufler-ca.com>
> Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
> ---
>  fs/namei.c                    |  2 ++
>  fs/nfsd/vfs.c                 |  6 ++++++
>  include/linux/lsm_hook_defs.h |  1 +
>  include/linux/security.h      |  6 ++++++
>  security/security.c           | 17 +++++++++++++++++
>  5 files changed, 32 insertions(+)
> 
> diff --git a/fs/namei.c b/fs/namei.c
> index 71c13b2990b4..fb93d3e13df6 100644
> --- a/fs/namei.c
> +++ b/fs/namei.c
> @@ -3620,6 +3620,8 @@ static int do_open(struct nameidata *nd,
>  	error = may_open(idmap, &nd->path, acc_mode, open_flag);
>  	if (!error && !(file->f_mode & FMODE_OPENED))
>  		error = vfs_open(&nd->path, file);
> +	if (!error)
> +		error = security_file_post_open(file, op->acc_mode);

What does it do for O_CREAT? IOW, we managed to create that thing and we
managed to open that thing. Can security_file_post_open() and
ima_file_check() fail afterwards even for newly created files?
Roberto Sassu Feb. 9, 2024, 12:02 p.m. UTC | #12
On Fri, 2024-02-09 at 12:34 +0100, Christian Brauner wrote:
> On Fri, Feb 09, 2024 at 11:46:16AM +0100, Roberto Sassu wrote:
> > On Fri, 2024-02-09 at 11:12 +0100, Christian Brauner wrote:
> > > On Mon, Jan 15, 2024 at 07:17:56PM +0100, Roberto Sassu wrote:
> > > > From: Roberto Sassu <roberto.sassu@huawei.com>
> > > > 
> > > > In preparation to move IMA and EVM to the LSM infrastructure, introduce the
> > > > file_post_open hook. Also, export security_file_post_open() for NFS.
> > > > 
> > > > Based on policy, IMA calculates the digest of the file content and
> > > > extends the TPM with the digest, verifies the file's integrity based on
> > > > the digest, and/or includes the file digest in the audit log.
> > > > 
> > > > LSMs could similarly take action depending on the file content and the
> > > > access mask requested with open().
> > > > 
> > > > The new hook returns a value and can cause the open to be aborted.
> > > > 
> > > > Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
> > > > Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
> > > > Acked-by: Casey Schaufler <casey@schaufler-ca.com>
> > > > Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
> > > > ---
> > > >  fs/namei.c                    |  2 ++
> > > >  fs/nfsd/vfs.c                 |  6 ++++++
> > > >  include/linux/lsm_hook_defs.h |  1 +
> > > >  include/linux/security.h      |  6 ++++++
> > > >  security/security.c           | 17 +++++++++++++++++
> > > >  5 files changed, 32 insertions(+)
> > > > 
> > > > diff --git a/fs/namei.c b/fs/namei.c
> > > > index 71c13b2990b4..fb93d3e13df6 100644
> > > > --- a/fs/namei.c
> > > > +++ b/fs/namei.c
> > > > @@ -3620,6 +3620,8 @@ static int do_open(struct nameidata *nd,
> > > >  	error = may_open(idmap, &nd->path, acc_mode, open_flag);
> > > >  	if (!error && !(file->f_mode & FMODE_OPENED))
> > > >  		error = vfs_open(&nd->path, file);
> > > > +	if (!error)
> > > > +		error = security_file_post_open(file, op->acc_mode);
> > > 
> > > What does it do for O_CREAT? IOW, we managed to create that thing and we
> > > managed to open that thing. Can security_file_post_open() and
> > > ima_file_check() fail afterwards even for newly created files?
> > 
> > $ strace touch test-file
> > ...
> > openat(AT_FDCWD, "test-file", O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK, 0666) = -1 EPERM (Operation not permitted)
> 
> Ah, meh. I was hoping IMA just wouldn't care about this case.

Actually it doesn't. I added code to artifically create the situation
(to see what happens if a new LSM does that).

Roberto
Stefan Berger Feb. 12, 2024, 5:21 p.m. UTC | #13
On 1/15/24 13:17, Roberto Sassu wrote:
> From: Roberto Sassu <roberto.sassu@huawei.com>
> 
> In preparation for moving IMA and EVM to the LSM infrastructure, introduce
> the file_release hook.
> 
> IMA calculates at file close the new digest of the file content and writes
> it to security.ima, so that appraisal at next file access succeeds.
> 
> An LSM could implement an exclusive access scheme for files, only allowing
> access to files that have no references.
> 
> The new hook cannot return an error and cannot cause the operation to be
> reverted.
> 
> Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>

Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>

> ---
>   fs/file_table.c               |  1 +
>   include/linux/lsm_hook_defs.h |  1 +
>   include/linux/security.h      |  4 ++++
>   security/security.c           | 11 +++++++++++
>   4 files changed, 17 insertions(+)
> 
> diff --git a/fs/file_table.c b/fs/file_table.c
> index de4a2915bfd4..c72dc75f2bd3 100644
> --- a/fs/file_table.c
> +++ b/fs/file_table.c
> @@ -385,6 +385,7 @@ static void __fput(struct file *file)
>   	eventpoll_release(file);
>   	locks_remove_file(file);
>   
> +	security_file_release(file);
>   	ima_file_free(file);
>   	if (unlikely(file->f_flags & FASYNC)) {
>   		if (file->f_op->fasync)
> diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
> index c3fecc7dcb0b..229f84ce12ae 100644
> --- a/include/linux/lsm_hook_defs.h
> +++ b/include/linux/lsm_hook_defs.h
> @@ -173,6 +173,7 @@ LSM_HOOK(int, 0, kernfs_init_security, struct kernfs_node *kn_dir,
>   	 struct kernfs_node *kn)
>   LSM_HOOK(int, 0, file_permission, struct file *file, int mask)
>   LSM_HOOK(int, 0, file_alloc_security, struct file *file)
> +LSM_HOOK(void, LSM_RET_VOID, file_release, struct file *file)
>   LSM_HOOK(void, LSM_RET_VOID, file_free_security, struct file *file)
>   LSM_HOOK(int, 0, file_ioctl, struct file *file, unsigned int cmd,
>   	 unsigned long arg)
> diff --git a/include/linux/security.h b/include/linux/security.h
> index 97f2212c13b6..2997348afcb7 100644
> --- a/include/linux/security.h
> +++ b/include/linux/security.h
> @@ -395,6 +395,7 @@ int security_kernfs_init_security(struct kernfs_node *kn_dir,
>   				  struct kernfs_node *kn);
>   int security_file_permission(struct file *file, int mask);
>   int security_file_alloc(struct file *file);
> +void security_file_release(struct file *file);
>   void security_file_free(struct file *file);
>   int security_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
>   int security_file_ioctl_compat(struct file *file, unsigned int cmd,
> @@ -1008,6 +1009,9 @@ static inline int security_file_alloc(struct file *file)
>   	return 0;
>   }
>   
> +static inline void security_file_release(struct file *file)
> +{ }
> +
>   static inline void security_file_free(struct file *file)
>   { }
>   
> diff --git a/security/security.c b/security/security.c
> index f3d92bffd02f..7d10724872f8 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -2724,6 +2724,17 @@ int security_file_alloc(struct file *file)
>   	return rc;
>   }
>   
> +/**
> + * security_file_release() - Perform actions before releasing the file ref
> + * @file: the file
> + *
> + * Perform actions before releasing the last reference to a file.
> + */
> +void security_file_release(struct file *file)
> +{
> +	call_void_hook(file_release, file);
> +}
> +
>   /**
>    * security_file_free() - Free a file's LSM blob
>    * @file: the file
Stefan Berger Feb. 12, 2024, 5:26 p.m. UTC | #14
On 1/15/24 13:17, Roberto Sassu wrote:
> From: Roberto Sassu <roberto.sassu@huawei.com>
> 
> In preparation for moving IMA and EVM to the LSM infrastructure, introduce
> the inode_post_create_tmpfile hook.
> 
> As temp files can be made persistent, treat new temp files like other new
> files, so that the file hash is calculated and stored in the security
> xattr.
> 
> LSMs could also take some action after temp files have been created.
> 
> The new hook cannot return an error and cannot cause the operation to be
> canceled.
> 
> Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
> Acked-by: Casey Schaufler <casey@schaufler-ca.com>
> Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>

Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>

> ---
>   fs/namei.c                    |  1 +
>   include/linux/lsm_hook_defs.h |  2 ++
>   include/linux/security.h      |  6 ++++++
>   security/security.c           | 15 +++++++++++++++
>   4 files changed, 24 insertions(+)
> 
> diff --git a/fs/namei.c b/fs/namei.c
> index b7f433720b1e..adb3ab27951a 100644
> --- a/fs/namei.c
> +++ b/fs/namei.c
> @@ -3686,6 +3686,7 @@ static int vfs_tmpfile(struct mnt_idmap *idmap,
>   		inode->i_state |= I_LINKABLE;
>   		spin_unlock(&inode->i_lock);
>   	}
> +	security_inode_post_create_tmpfile(idmap, inode);
>   	ima_post_create_tmpfile(idmap, inode);
>   	return 0;
>   }
> diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
> index e08b9091350d..5f90914d23e0 100644
> --- a/include/linux/lsm_hook_defs.h
> +++ b/include/linux/lsm_hook_defs.h
> @@ -121,6 +121,8 @@ LSM_HOOK(int, 0, inode_init_security_anon, struct inode *inode,
>   	 const struct qstr *name, const struct inode *context_inode)
>   LSM_HOOK(int, 0, inode_create, struct inode *dir, struct dentry *dentry,
>   	 umode_t mode)
> +LSM_HOOK(void, LSM_RET_VOID, inode_post_create_tmpfile, struct mnt_idmap *idmap,
> +	 struct inode *inode)
>   LSM_HOOK(int, 0, inode_link, struct dentry *old_dentry, struct inode *dir,
>   	 struct dentry *new_dentry)
>   LSM_HOOK(int, 0, inode_unlink, struct inode *dir, struct dentry *dentry)
> diff --git a/include/linux/security.h b/include/linux/security.h
> index 977dd9f7f51a..1cb604282617 100644
> --- a/include/linux/security.h
> +++ b/include/linux/security.h
> @@ -344,6 +344,8 @@ int security_inode_init_security_anon(struct inode *inode,
>   				      const struct qstr *name,
>   				      const struct inode *context_inode);
>   int security_inode_create(struct inode *dir, struct dentry *dentry, umode_t mode);
> +void security_inode_post_create_tmpfile(struct mnt_idmap *idmap,
> +					struct inode *inode);
>   int security_inode_link(struct dentry *old_dentry, struct inode *dir,
>   			 struct dentry *new_dentry);
>   int security_inode_unlink(struct inode *dir, struct dentry *dentry);
> @@ -811,6 +813,10 @@ static inline int security_inode_create(struct inode *dir,
>   	return 0;
>   }
>   
> +static inline void
> +security_inode_post_create_tmpfile(struct mnt_idmap *idmap, struct inode *inode)
> +{ }
> +
>   static inline int security_inode_link(struct dentry *old_dentry,
>   				       struct inode *dir,
>   				       struct dentry *new_dentry)
> diff --git a/security/security.c b/security/security.c
> index 750bfe2768d5..5bc7edc22923 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -2013,6 +2013,21 @@ int security_inode_create(struct inode *dir, struct dentry *dentry,
>   }
>   EXPORT_SYMBOL_GPL(security_inode_create);
>   
> +/**
> + * security_inode_post_create_tmpfile() - Update inode security of new tmpfile
> + * @idmap: idmap of the mount
> + * @inode: inode of the new tmpfile
> + *
> + * Update inode security data after a tmpfile has been created.
> + */
> +void security_inode_post_create_tmpfile(struct mnt_idmap *idmap,
> +					struct inode *inode)
> +{
> +	if (unlikely(IS_PRIVATE(inode)))
> +		return;
> +	call_void_hook(inode_post_create_tmpfile, idmap, inode);
> +}
> +
>   /**
>    * security_inode_link() - Check if creating a hard link is allowed
>    * @old_dentry: existing file
Stefan Berger Feb. 12, 2024, 5:37 p.m. UTC | #15
On 1/15/24 13:18, Roberto Sassu wrote:
> From: Roberto Sassu <roberto.sassu@huawei.com>
> 
> In preparation for removing the 'integrity' LSM, move
> integrity_kernel_module_request() to IMA, and rename it to
> ima_kernel_module_request().
> 
> Compile it conditionally if CONFIG_INTEGRITY_ASYMMETRIC_KEYS is enabled,
> and call it from security.c (removed afterwards with the move of IMA to the
> LSM infrastructure).
> 
> Adding this hook cannot be avoided, since IMA has no control on the flags
> passed to crypto_alloc_sig() in public_key_verify_signature(), and thus
> cannot pass CRYPTO_NOLOAD, which solved the problem for EVM hashing with
> commit e2861fa71641 ("evm: Don't deadlock if a crypto algorithm is
> unavailable").
> 
> EVM alone does not need to implement this hook, first because there is no
> mutex to deadlock, and second because even if it had it, there should be a
> recursive call. However, since verification from EVM can be initiated only
> by setting inode metadata, deadlock would occur if modprobe would do the
> same while loading a kernel module (which is unlikely).
> 
> Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
> ---
>   include/linux/ima.h                    | 10 +++++++++
>   include/linux/integrity.h              | 13 ------------
>   security/integrity/digsig_asymmetric.c | 23 --------------------
>   security/integrity/ima/ima_main.c      | 29 ++++++++++++++++++++++++++
>   security/security.c                    |  2 +-
>   5 files changed, 40 insertions(+), 37 deletions(-)
> 
> diff --git a/include/linux/ima.h b/include/linux/ima.h
> index 31ef6c3c3207..0f9af283cbc8 100644
> --- a/include/linux/ima.h
> +++ b/include/linux/ima.h
> @@ -256,4 +256,14 @@ static inline bool ima_appraise_signature(enum kernel_read_file_id func)
>   	return false;
>   }
>   #endif /* CONFIG_IMA_APPRAISE && CONFIG_INTEGRITY_TRUSTED_KEYRING */
> +
> +#if defined(CONFIG_IMA) && defined(CONFIG_INTEGRITY_ASYMMETRIC_KEYS)
> +extern int ima_kernel_module_request(char *kmod_name);
> +#else
> +static inline int ima_kernel_module_request(char *kmod_name)
> +{
> +	return 0;
> +}
> +
> +#endif
>   #endif /* _LINUX_IMA_H */
> diff --git a/include/linux/integrity.h b/include/linux/integrity.h
> index 2ea0f2f65ab6..ef0f63ef5ebc 100644
> --- a/include/linux/integrity.h
> +++ b/include/linux/integrity.h
> @@ -42,17 +42,4 @@ static inline void integrity_load_keys(void)
>   }
>   #endif /* CONFIG_INTEGRITY */
>   
> -#ifdef CONFIG_INTEGRITY_ASYMMETRIC_KEYS
> -
> -extern int integrity_kernel_module_request(char *kmod_name);
> -
> -#else
> -
> -static inline int integrity_kernel_module_request(char *kmod_name)
> -{
> -	return 0;
> -}
> -
> -#endif /* CONFIG_INTEGRITY_ASYMMETRIC_KEYS */
> -
>   #endif /* _LINUX_INTEGRITY_H */
> diff --git a/security/integrity/digsig_asymmetric.c b/security/integrity/digsig_asymmetric.c
> index 895f4b9ce8c6..de603cf42ac7 100644
> --- a/security/integrity/digsig_asymmetric.c
> +++ b/security/integrity/digsig_asymmetric.c
> @@ -132,26 +132,3 @@ int asymmetric_verify(struct key *keyring, const char *sig,
>   	pr_debug("%s() = %d\n", __func__, ret);
>   	return ret;
>   }
> -
> -/**
> - * integrity_kernel_module_request - prevent crypto-pkcs1pad(rsa,*) requests
> - * @kmod_name: kernel module name
> - *
> - * We have situation, when public_key_verify_signature() in case of RSA
> - * algorithm use alg_name to store internal information in order to
> - * construct an algorithm on the fly, but crypto_larval_lookup() will try
> - * to use alg_name in order to load kernel module with same name.
> - * Since we don't have any real "crypto-pkcs1pad(rsa,*)" kernel modules,
> - * we are safe to fail such module request from crypto_larval_lookup().
> - *
> - * In this way we prevent modprobe execution during digsig verification
> - * and avoid possible deadlock if modprobe and/or it's dependencies
> - * also signed with digsig.
> - */
> -int integrity_kernel_module_request(char *kmod_name)
> -{
> -	if (strncmp(kmod_name, "crypto-pkcs1pad(rsa,", 20) == 0)
> -		return -EINVAL;
> -
> -	return 0;
> -}
> diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
> index 02021ee467d3..908fa026ec58 100644
> --- a/security/integrity/ima/ima_main.c
> +++ b/security/integrity/ima/ima_main.c
> @@ -1091,6 +1091,35 @@ int ima_measure_critical_data(const char *event_label,
>   }
>   EXPORT_SYMBOL_GPL(ima_measure_critical_data);
>   
> +#ifdef CONFIG_INTEGRITY_ASYMMETRIC_KEYS
> +
> +/**
> + * ima_kernel_module_request - Prevent crypto-pkcs1pad(rsa,*) requests
> + * @kmod_name: kernel module name
> + *
> + * We have situation, when public_key_verify_signature() in case of RSA > + * algorithm use alg_name to store internal information in order to
> + * construct an algorithm on the fly, but crypto_larval_lookup() will try
> + * to use alg_name in order to load kernel module with same name.
> + * Since we don't have any real "crypto-pkcs1pad(rsa,*)" kernel modules,
> + * we are safe to fail such module request from crypto_larval_lookup().
> + *
> + * In this way we prevent modprobe execution during digsig verification
> + * and avoid possible deadlock if modprobe and/or it's dependencies
> + * also signed with digsig.

This text needs to some reformulation at some point..

> + *
> + * Return: Zero if it is safe to load the kernel module, -EINVAL otherwise.
> + */
> +int ima_kernel_module_request(char *kmod_name)
> +{
> +	if (strncmp(kmod_name, "crypto-pkcs1pad(rsa,", 20) == 0)
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
> +#endif /* CONFIG_INTEGRITY_ASYMMETRIC_KEYS */
> +
>   static int __init init_ima(void)
>   {
>   	int error;
> diff --git a/security/security.c b/security/security.c
> index d2a1226e6e69..6c6571a141a1 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -3255,7 +3255,7 @@ int security_kernel_module_request(char *kmod_name)
>   	ret = call_int_hook(kernel_module_request, 0, kmod_name);
>   	if (ret)
>   		return ret;
> -	return integrity_kernel_module_request(kmod_name);
> +	return ima_kernel_module_request(kmod_name);
>   }
>   
>   /**

Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
Paul Moore Feb. 12, 2024, 5:56 p.m. UTC | #16
On Mon, Feb 12, 2024 at 12:48 PM Stefan Berger <stefanb@linux.ibm.com> wrote:
> On 1/15/24 13:18, Roberto Sassu wrote:

...

> > +/**
> > + * ima_kernel_module_request - Prevent crypto-pkcs1pad(rsa,*) requests
> > + * @kmod_name: kernel module name
> > + *
> > + * We have situation, when public_key_verify_signature() in case of RSA > + * algorithm use alg_name to store internal information in order to
> > + * construct an algorithm on the fly, but crypto_larval_lookup() will try
> > + * to use alg_name in order to load kernel module with same name.
> > + * Since we don't have any real "crypto-pkcs1pad(rsa,*)" kernel modules,
> > + * we are safe to fail such module request from crypto_larval_lookup().
> > + *
> > + * In this way we prevent modprobe execution during digsig verification
> > + * and avoid possible deadlock if modprobe and/or it's dependencies
> > + * also signed with digsig.
>
> This text needs to some reformulation at some point..

There is no time like the present.  If you have a suggestion I would
love to hear it and I'm sure Roberto would too.
Stefan Berger Feb. 12, 2024, 7:13 p.m. UTC | #17
On 1/15/24 13:18, Roberto Sassu wrote:
> From: Roberto Sassu <roberto.sassu@huawei.com>
> 
> Define a new structure for EVM-specific metadata, called evm_iint_cache,
> and embed it in the inode security blob. Introduce evm_iint_inode() to
> retrieve metadata, and register evm_inode_alloc_security() for the
> inode_alloc_security LSM hook, to initialize the structure (before
> splitting metadata, this task was done by iint_init_always()).
> 
> Keep the non-NULL checks after calling evm_iint_inode() except in
> evm_inode_alloc_security(), to take into account inodes for which
> security_inode_alloc() was not called. When using shared metadata,
> obtaining a NULL pointer from integrity_iint_find() meant that the file
> wasn't in the IMA policy. Now, because IMA and EVM use disjoint metadata,
> the EVM status has to be stored for every inode regardless of the IMA
> policy.
> 
> Given that from now on EVM relies on its own metadata, remove the iint
> parameter from evm_verifyxattr(). Also, directly retrieve the iint in
> evm_verify_hmac(), called by both evm_verifyxattr() and
> evm_verify_current_integrity(), since now there is no performance penalty
> in retrieving EVM metadata (constant time).
> 
> Replicate the management of the IMA_NEW_FILE flag, by introducing
> evm_post_path_mknod() and evm_file_release() to respectively set and clear
> the newly introduced flag EVM_NEW_FILE, at the same time IMA does. Like for
> IMA, select CONFIG_SECURITY_PATH when EVM is enabled, to ensure that files
> are marked as new.
> 
> Unlike ima_post_path_mknod(), evm_post_path_mknod() cannot check if a file
> must be appraised. Thus, it marks all affected files. Also, it does not
> clear EVM_NEW_FILE depending on i_version, but that is not a problem
> because IMA_NEW_FILE is always cleared when set in ima_check_last_writer().
> 
> Move the EVM-specific flag EVM_IMMUTABLE_DIGSIG to
> security/integrity/evm/evm.h, since that definition is now unnecessary in
> the common integrity layer.
> 
> Finally, switch to the LSM reservation mechanism for the EVM xattr, and
> consequently decrement by one the number of xattrs to allocate in
> security_inode_init_security().
> 
> Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>

Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
Stefan Berger Feb. 12, 2024, 7:50 p.m. UTC | #18
On 1/15/24 13:18, Roberto Sassu wrote:
> From: Roberto Sassu <roberto.sassu@huawei.com>
> 
> Since now IMA and EVM use their own integrity metadata, it is safe to
> remove the 'integrity' LSM, with its management of integrity metadata.
> 
> Keep the iint.c file only for loading IMA and EVM keys at boot, and for
> creating the integrity directory in securityfs (we need to keep it for
> retrocompatibility reasons).
> 
> Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>

Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
Stefan Berger Feb. 12, 2024, 8:28 p.m. UTC | #19
On 2/12/24 12:56, Paul Moore wrote:
> On Mon, Feb 12, 2024 at 12:48 PM Stefan Berger <stefanb@linux.ibm.com> wrote:
>> On 1/15/24 13:18, Roberto Sassu wrote:
> 
> ...
> 
>>> +/**
>>> + * ima_kernel_module_request - Prevent crypto-pkcs1pad(rsa,*) requests
>>> + * @kmod_name: kernel module name
>>> + *
>>> + * We have situation, when public_key_verify_signature() in case of RSA > + * algorithm use alg_name to store internal information in order to
>>> + * construct an algorithm on the fly, but crypto_larval_lookup() will try
>>> + * to use alg_name in order to load kernel module with same name.
>>> + * Since we don't have any real "crypto-pkcs1pad(rsa,*)" kernel modules,
>>> + * we are safe to fail such module request from crypto_larval_lookup().
>>> + *
>>> + * In this way we prevent modprobe execution during digsig verification
>>> + * and avoid possible deadlock if modprobe and/or it's dependencies
>>> + * also signed with digsig.
>>
>> This text needs to some reformulation at some point..
> 
> There is no time like the present.  If you have a suggestion I would
> love to hear it and I'm sure Roberto would too.
> 

My interpretation of the issue after possibly lossy decoding of the 
above sentences:

Avoid a deadlock by rejecting a virtual kernel module with the name 
"crypto-pkcs1pad(rsa,*)". This module may be requested by 
crypto_larval_lookup() while trying to verify an RSA signature in 
public_key_verify_signature(). Since the loading of the RSA module may 
itself cause the request for an RSA signature verification it will 
otherwise lead to a deadlock.
Mimi Zohar Feb. 12, 2024, 9 p.m. UTC | #20
Hi Roberto,


> diff --git a/security/security.c b/security/security.c
> index d9d2636104db..f3d92bffd02f 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -2972,6 +2972,23 @@ int security_file_open(struct file *file)
>  	return fsnotify_perm(file, MAY_OPEN);  <===  Conflict

Replace with "return fsnotify_open_perm(file);"

>  }
>  

The patch set doesn't apply cleaning to 6.8-rcX without this change.  Unless
there are other issues, I can make the change.

thanks,

Mimi
Paul Moore Feb. 12, 2024, 9:16 p.m. UTC | #21
On Mon, Feb 12, 2024 at 4:06 PM Mimi Zohar <zohar@linux.ibm.com> wrote:
>
> Hi Roberto,
>
>
> > diff --git a/security/security.c b/security/security.c
> > index d9d2636104db..f3d92bffd02f 100644
> > --- a/security/security.c
> > +++ b/security/security.c
> > @@ -2972,6 +2972,23 @@ int security_file_open(struct file *file)
> >       return fsnotify_perm(file, MAY_OPEN);  <===  Conflict
>
> Replace with "return fsnotify_open_perm(file);"
>
> >  }
> >
>
> The patch set doesn't apply cleaning to 6.8-rcX without this change.  Unless
> there are other issues, I can make the change.

I take it this means you want to pull this via the IMA/EVM tree?
Roberto Sassu Feb. 13, 2024, 8:57 a.m. UTC | #22
On Mon, 2024-02-12 at 15:28 -0500, Stefan Berger wrote:
> 
> On 2/12/24 12:56, Paul Moore wrote:
> > On Mon, Feb 12, 2024 at 12:48 PM Stefan Berger <stefanb@linux.ibm.com> wrote:
> > > On 1/15/24 13:18, Roberto Sassu wrote:
> > 
> > ...
> > 
> > > > +/**
> > > > + * ima_kernel_module_request - Prevent crypto-pkcs1pad(rsa,*) requests
> > > > + * @kmod_name: kernel module name
> > > > + *
> > > > + * We have situation, when public_key_verify_signature() in case of RSA > + * algorithm use alg_name to store internal information in order to
> > > > + * construct an algorithm on the fly, but crypto_larval_lookup() will try
> > > > + * to use alg_name in order to load kernel module with same name.
> > > > + * Since we don't have any real "crypto-pkcs1pad(rsa,*)" kernel modules,
> > > > + * we are safe to fail such module request from crypto_larval_lookup().
> > > > + *
> > > > + * In this way we prevent modprobe execution during digsig verification
> > > > + * and avoid possible deadlock if modprobe and/or it's dependencies
> > > > + * also signed with digsig.
> > > 
> > > This text needs to some reformulation at some point..
> > 
> > There is no time like the present.  If you have a suggestion I would
> > love to hear it and I'm sure Roberto would too.
> > 
> 
> My interpretation of the issue after possibly lossy decoding of the 
> above sentences:
> 
> Avoid a deadlock by rejecting a virtual kernel module with the name 
> "crypto-pkcs1pad(rsa,*)". This module may be requested by 
> crypto_larval_lookup() while trying to verify an RSA signature in 
> public_key_verify_signature(). Since the loading of the RSA module may 
> itself cause the request for an RSA signature verification it will 
> otherwise lead to a deadlock.

I can be even more precise I guess (I actually reproduced it).

Avoid a verification loop where verifying the signature of the modprobe
binary requires executing modprobe itself. Since the modprobe iint-
>mutex is already held when the signature verification is performed, a
deadlock occurs as soon as modprobe is executed within the critical
region, since the same lock cannot be taken again.

This happens when public_key_verify_signature(), in case of RSA
algorithm, use alg_name to store internal information in order to
construct an algorithm on the fly, but crypto_larval_lookup() will try
to use alg_name in order to load a kernel module with same name.

Since we don't have any real "crypto-pkcs1pad(rsa,*)" kernel modules,
we are safe to fail such module request from crypto_larval_lookup(),
and avoid the verification loop.

Roberto
Roberto Sassu Feb. 13, 2024, 12:58 p.m. UTC | #23
On Mon, 2024-02-12 at 16:16 -0500, Paul Moore wrote:
> On Mon, Feb 12, 2024 at 4:06 PM Mimi Zohar <zohar@linux.ibm.com> wrote:
> > 
> > Hi Roberto,
> > 
> > 
> > > diff --git a/security/security.c b/security/security.c
> > > index d9d2636104db..f3d92bffd02f 100644
> > > --- a/security/security.c
> > > +++ b/security/security.c
> > > @@ -2972,6 +2972,23 @@ int security_file_open(struct file *file)
> > >       return fsnotify_perm(file, MAY_OPEN);  <===  Conflict
> > 
> > Replace with "return fsnotify_open_perm(file);"
> > 
> > >  }
> > > 
> > 
> > The patch set doesn't apply cleaning to 6.8-rcX without this change.  Unless
> > there are other issues, I can make the change.
> 
> I take it this means you want to pull this via the IMA/EVM tree?

Not sure about that, but I have enough changes to do to make a v10.

Roberto
Paul Moore Feb. 13, 2024, 3:33 p.m. UTC | #24
On Tue, Feb 13, 2024 at 7:59 AM Roberto Sassu
<roberto.sassu@huaweicloud.com> wrote:
> On Mon, 2024-02-12 at 16:16 -0500, Paul Moore wrote:
> > On Mon, Feb 12, 2024 at 4:06 PM Mimi Zohar <zohar@linux.ibm.com> wrote:
> > >
> > > Hi Roberto,
> > >
> > >
> > > > diff --git a/security/security.c b/security/security.c
> > > > index d9d2636104db..f3d92bffd02f 100644
> > > > --- a/security/security.c
> > > > +++ b/security/security.c
> > > > @@ -2972,6 +2972,23 @@ int security_file_open(struct file *file)
> > > >       return fsnotify_perm(file, MAY_OPEN);  <===  Conflict
> > >
> > > Replace with "return fsnotify_open_perm(file);"
> > >
> > > >  }
> > > >
> > >
> > > The patch set doesn't apply cleaning to 6.8-rcX without this change.  Unless
> > > there are other issues, I can make the change.
> >
> > I take it this means you want to pull this via the IMA/EVM tree?
>
> Not sure about that, but I have enough changes to do to make a v10.

Sorry, I should have been more clear, the point I was trying to
resolve was who was going to take this patchset (eventually).  There
are other patches destined for the LSM tree that touch the LSM hooks
in a way which will cause conflicts with this patchset, and if
you/Mimi are going to take this via the IMA/EVM tree - which is fine
with me - I need to take that into account when merging things in the
LSM tree during this cycle.  It's not a big deal either way, it would
just be nice to get an answer on that within the next week.
Stefan Berger Feb. 13, 2024, 4:31 p.m. UTC | #25
On 2/13/24 03:57, Roberto Sassu wrote:
> On Mon, 2024-02-12 at 15:28 -0500, Stefan Berger wrote:
>>
>> On 2/12/24 12:56, Paul Moore wrote:
>>> On Mon, Feb 12, 2024 at 12:48 PM Stefan Berger <stefanb@linux.ibm.com> wrote:
>>>> On 1/15/24 13:18, Roberto Sassu wrote:
>>>
>>> ...
>>>
>>>>> +/**
>>>>> + * ima_kernel_module_request - Prevent crypto-pkcs1pad(rsa,*) requests
>>>>> + * @kmod_name: kernel module name
>>>>> + *
>>>>> + * We have situation, when public_key_verify_signature() in case of RSA > + * algorithm use alg_name to store internal information in order to
>>>>> + * construct an algorithm on the fly, but crypto_larval_lookup() will try
>>>>> + * to use alg_name in order to load kernel module with same name.
>>>>> + * Since we don't have any real "crypto-pkcs1pad(rsa,*)" kernel modules,
>>>>> + * we are safe to fail such module request from crypto_larval_lookup().
>>>>> + *
>>>>> + * In this way we prevent modprobe execution during digsig verification
>>>>> + * and avoid possible deadlock if modprobe and/or it's dependencies
>>>>> + * also signed with digsig.
>>>>
>>>> This text needs to some reformulation at some point..
>>>
>>> There is no time like the present.  If you have a suggestion I would
>>> love to hear it and I'm sure Roberto would too.
>>>
>>
>> My interpretation of the issue after possibly lossy decoding of the
>> above sentences:
>>
>> Avoid a deadlock by rejecting a virtual kernel module with the name
>> "crypto-pkcs1pad(rsa,*)". This module may be requested by
>> crypto_larval_lookup() while trying to verify an RSA signature in
>> public_key_verify_signature(). Since the loading of the RSA module may
>> itself cause the request for an RSA signature verification it will
>> otherwise lead to a deadlock.
> 
> I can be even more precise I guess (I actually reproduced it). >
> Avoid a verification loop where verifying the signature of the modprobe
> binary requires executing modprobe itself. Since the modprobe iint-
>> mutex is already held when the signature verification is performed, a
> deadlock occurs as soon as modprobe is executed within the critical
> region, since the same lock cannot be taken again.

When ecdsa is used for signing files it could get stuck as well and 
would need this patch:

diff --git a/security/integrity/ima/ima_main.c 
b/security/integrity/ima/ima_main.c
index 45f1a102c599..2e71dc977d43 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -1110,7 +1110,9 @@ EXPORT_SYMBOL_GPL(ima_measure_critical_data);
   */
  static int ima_kernel_module_request(char *kmod_name)
  {
-       if (strncmp(kmod_name, "crypto-pkcs1pad(rsa,", 20) == 0)
+       if (strncmp(kmod_name, "crypto-pkcs1pad(rsa,", 20) == 0 ||
+           strncmp(kmod_name, "crypto-ecdsa-nist-p", 19) == 0 ||
+           strcmp(kmod_name, "cryptomgr") == 0)
                 return -EINVAL;

         return 0;

Rejecting cryptomgr seems necessary in the ecdsa case though I am not 
sure what the side effects of rejecting it all the time could be.

    Stefan

> 
> This happens when public_key_verify_signature(), in case of RSA
> algorithm, use alg_name to store internal information in order to
> construct an algorithm on the fly, but crypto_larval_lookup() will try
> to use alg_name in order to load a kernel module with same name.
> 
> Since we don't have any real "crypto-pkcs1pad(rsa,*)" kernel modules,
> we are safe to fail such module request from crypto_larval_lookup(),
> and avoid the verification loop.
> 
> Roberto
> 
>
Mimi Zohar Feb. 14, 2024, 8:07 p.m. UTC | #26
On Tue, 2024-02-13 at 10:33 -0500, Paul Moore wrote:
> On Tue, Feb 13, 2024 at 7:59 AM Roberto Sassu
> <roberto.sassu@huaweicloud.com> wrote:
> > On Mon, 2024-02-12 at 16:16 -0500, Paul Moore wrote:
> > > On Mon, Feb 12, 2024 at 4:06 PM Mimi Zohar <zohar@linux.ibm.com> wrote:
> > > > Hi Roberto,
> > > > 
> > > > 
> > > > > diff --git a/security/security.c b/security/security.c
> > > > > index d9d2636104db..f3d92bffd02f 100644
> > > > > --- a/security/security.c
> > > > > +++ b/security/security.c
> > > > > @@ -2972,6 +2972,23 @@ int security_file_open(struct file *file)
> > > > >       return fsnotify_perm(file, MAY_OPEN);  <===  Conflict
> > > > 
> > > > Replace with "return fsnotify_open_perm(file);"
> > > > 
> > > > >  }
> > > > > 
> > > > 
> > > > The patch set doesn't apply cleaning to 6.8-rcX without this
> > > > change.  Unless
> > > > there are other issues, I can make the change.
> > > 
> > > I take it this means you want to pull this via the IMA/EVM tree?
> > 
> > Not sure about that, but I have enough changes to do to make a v10.

@Roberto:  please add my "Reviewed-by" to the remaining patches.

> 
> Sorry, I should have been more clear, the point I was trying to
> resolve was who was going to take this patchset (eventually).  There
> are other patches destined for the LSM tree that touch the LSM hooks
> in a way which will cause conflicts with this patchset, and if
> you/Mimi are going to take this via the IMA/EVM tree - which is fine
> with me - I need to take that into account when merging things in the
> LSM tree during this cycle.  It's not a big deal either way, it would
> just be nice to get an answer on that within the next week.

Similarly there are other changes for IMA and EVM.  If you're willing to create
a topic branch for just the v10 patch set that can be merged into your tree and
into my tree, I'm fine with your upstreaming v10. (I'll wait to send my pull
request after yours.)  Roberto will add my Ack's to the integrity, IMA, and EVM
related patches.  However if you're not willing to create a topic branch, I'll
upstream the v10 patch set.

thanks,

Mimi
Paul Moore Feb. 14, 2024, 9:21 p.m. UTC | #27
On Wed, Feb 14, 2024 at 3:07 PM Mimi Zohar <zohar@linux.ibm.com> wrote:
> On Tue, 2024-02-13 at 10:33 -0500, Paul Moore wrote:
> > On Tue, Feb 13, 2024 at 7:59 AM Roberto Sassu
> > <roberto.sassu@huaweicloud.com> wrote:
> > > On Mon, 2024-02-12 at 16:16 -0500, Paul Moore wrote:
> > > > On Mon, Feb 12, 2024 at 4:06 PM Mimi Zohar <zohar@linux.ibm.com> wrote:
> > > > > Hi Roberto,
> > > > >
> > > > >
> > > > > > diff --git a/security/security.c b/security/security.c
> > > > > > index d9d2636104db..f3d92bffd02f 100644
> > > > > > --- a/security/security.c
> > > > > > +++ b/security/security.c
> > > > > > @@ -2972,6 +2972,23 @@ int security_file_open(struct file *file)
> > > > > >       return fsnotify_perm(file, MAY_OPEN);  <===  Conflict
> > > > >
> > > > > Replace with "return fsnotify_open_perm(file);"
> > > > >
> > > > > >  }
> > > > > >
> > > > >
> > > > > The patch set doesn't apply cleaning to 6.8-rcX without this
> > > > > change.  Unless
> > > > > there are other issues, I can make the change.
> > > >
> > > > I take it this means you want to pull this via the IMA/EVM tree?
> > >
> > > Not sure about that, but I have enough changes to do to make a v10.
>
> @Roberto:  please add my "Reviewed-by" to the remaining patches.
>
> >
> > Sorry, I should have been more clear, the point I was trying to
> > resolve was who was going to take this patchset (eventually).  There
> > are other patches destined for the LSM tree that touch the LSM hooks
> > in a way which will cause conflicts with this patchset, and if
> > you/Mimi are going to take this via the IMA/EVM tree - which is fine
> > with me - I need to take that into account when merging things in the
> > LSM tree during this cycle.  It's not a big deal either way, it would
> > just be nice to get an answer on that within the next week.
>
> Similarly there are other changes for IMA and EVM.  If you're willing to create
> a topic branch for just the v10 patch set that can be merged into your tree and
> into my tree, I'm fine with your upstreaming v10. (I'll wait to send my pull
> request after yours.)  Roberto will add my Ack's to the integrity, IMA, and EVM
> related patches.  However if you're not willing to create a topic branch, I'll
> upstream the v10 patch set.

I'm not a big fan of sharing topic branches across different subsystem
trees, I'd much rather just agree that one tree or another takes the
patchset and the others plan accordingly.  Based on our previous
discussions I was under the impression that you wanted me to merge
this patchset into lsm/dev, but it looks like that is no longer the
case - which is okay by me.

Assuming Roberto gets a v10 out soon, do you expect to merge the v10
patchset and send it up during the upcoming merge window (for v6.9),
or are you expecting to wait until after the upcoming merge window
closes and target v6.10?  Once again, either is fine, I'm just trying
to coordinate this with other patches.
Mimi Zohar Feb. 15, 2024, 8:16 a.m. UTC | #28
On Wed, 2024-02-14 at 16:21 -0500, Paul Moore wrote:
> On Wed, Feb 14, 2024 at 3:07 PM Mimi Zohar <zohar@linux.ibm.com> wrote:
> > On Tue, 2024-02-13 at 10:33 -0500, Paul Moore wrote:
> > > On Tue, Feb 13, 2024 at 7:59 AM Roberto Sassu
> > > <roberto.sassu@huaweicloud.com> wrote:
> > > > On Mon, 2024-02-12 at 16:16 -0500, Paul Moore wrote:
> > > > > On Mon, Feb 12, 2024 at 4:06 PM Mimi Zohar <zohar@linux.ibm.com>
> > > > > wrote:
> > > > > > Hi Roberto,
> > > > > > 
> > > > > > 
> > > > > > > diff --git a/security/security.c b/security/security.c
> > > > > > > index d9d2636104db..f3d92bffd02f 100644
> > > > > > > --- a/security/security.c
> > > > > > > +++ b/security/security.c
> > > > > > > @@ -2972,6 +2972,23 @@ int security_file_open(struct file *file)
> > > > > > >       return fsnotify_perm(file, MAY_OPEN);  <===  Conflict
> > > > > > 
> > > > > > Replace with "return fsnotify_open_perm(file);"
> > > > > > 
> > > > > > >  }
> > > > > > > 
> > > > > > 
> > > > > > The patch set doesn't apply cleaning to 6.8-rcX without this
> > > > > > change.  Unless
> > > > > > there are other issues, I can make the change.
> > > > > 
> > > > > I take it this means you want to pull this via the IMA/EVM tree?
> > > > 
> > > > Not sure about that, but I have enough changes to do to make a v10.
> > 
> > @Roberto:  please add my "Reviewed-by" to the remaining patches.
> > 
> > > Sorry, I should have been more clear, the point I was trying to
> > > resolve was who was going to take this patchset (eventually).  There
> > > are other patches destined for the LSM tree that touch the LSM hooks
> > > in a way which will cause conflicts with this patchset, and if
> > > you/Mimi are going to take this via the IMA/EVM tree - which is fine
> > > with me - I need to take that into account when merging things in the
> > > LSM tree during this cycle.  It's not a big deal either way, it would
> > > just be nice to get an answer on that within the next week.
> > 
> > Similarly there are other changes for IMA and EVM.  If you're willing to
> > create
> > a topic branch for just the v10 patch set that can be merged into your tree
> > and
> > into my tree, I'm fine with your upstreaming v10. (I'll wait to send my pull
> > request after yours.)  Roberto will add my Ack's to the integrity, IMA, and
> > EVM
> > related patches.  However if you're not willing to create a topic branch,
> > I'll
> > upstream the v10 patch set.
> 
> I'm not a big fan of sharing topic branches across different subsystem
> trees, I'd much rather just agree that one tree or another takes the
> patchset and the others plan accordingly.

Just curious why not?

> Based on our previous
> discussions I was under the impression that you wanted me to merge
> this patchset into lsm/dev, but it looks like that is no longer the
> case - which is okay by me.

Paul, I don't recall saying that.  Please go ahead and upstream it.  Roberto can
add my acks accordingly.

Mimi

> Assuming Roberto gets a v10 out soon, do you expect to merge the v10
> patchset and send it up during the upcoming merge window (for v6.9),
> or are you expecting to wait until after the upcoming merge window
> closes and target v6.10?  Once again, either is fine, I'm just trying
> to coordinate this with other patches.
Paul Moore Feb. 15, 2024, 3:02 p.m. UTC | #29
On Thu, Feb 15, 2024 at 3:18 AM Mimi Zohar <zohar@linux.ibm.com> wrote:
> On Wed, 2024-02-14 at 16:21 -0500, Paul Moore wrote:
> > I'm not a big fan of sharing topic branches across different subsystem
> > trees, I'd much rather just agree that one tree or another takes the
> > patchset and the others plan accordingly.
>
> Just curious why not?

I don't like the idea of cross-tree dependencies, I realize the term
"dependency" isn't a great fit for a shared topic branch - no one
needs to feel the need to explain how pulls and merges work - but it's
the conceptual idea of there being a dependency across different trees
that bothers me.  I also tend to dislike the idea that a new feature
*absolutely* *must* *be* *in* *a* *certain* *release* to the point
that we need to subvert our normal processes to make it happen.

Further, I believe that shared topic branches also discourages
cooperation and collaboration.  With a topic branch, anyone who wants
to build on top of it simply merges the topic branch and off they go;
without a shared topic branch there needs to be a discussion about
which other patches are affected, which trees are involved, who is
going to carry the patches, when are they going up to Linus, etc.  As
someone who feels strongly that we need more collaboration across
kernel subsystems, I'm always going to pick the option that involves
developers talking with other developers outside their immediate
subsystem.

Hopefully that makes sense.

> > Based on our previous
> > discussions I was under the impression that you wanted me to merge
> > this patchset into lsm/dev, but it looks like that is no longer the
> > case - which is okay by me.
>
> Paul, I don't recall saying that.  Please go ahead and upstream it.  Roberto can
> add my acks accordingly.

I believe it was during an off-list chat when we were discussing an
earlier revision of the patchset, however, as I said earlier I'm not
bothered by who merges the patches, as long as they eventually end up
in Linus' tree I'm happy :)  I *really* want to stress that last bit,
if you and Roberto have stuff queued for the IMA/EVM tree that depends
on this patchset, please go ahead and merge it; you've got my ACKs on
the patches that need them, and I believe I've reviewed most of the
other patches that don't require my ACK.  While there are a some LSM
related patches that would sit on top of this patchset, there is
nothing that is so critical that it must go in now.

If I don't hear anything back from you, I'll go ahead and merge these
into lsm/dev later tonight (probably in about ~12 hours from this
email as I have some personal commitments early this evening) just so
we can get them into linux-next as soon as possible.