All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v5 00/23] security: Move IMA and EVM to the LSM infrastructure
@ 2023-11-07 13:39 Roberto Sassu
  2023-11-07 13:39 ` [PATCH v5 01/23] ima: Align ima_inode_post_setattr() definition with " Roberto Sassu
                   ` (23 more replies)
  0 siblings, 24 replies; 96+ messages in thread
From: Roberto Sassu @ 2023-11-07 13:39 UTC (permalink / raw)
  To: viro, brauner, chuck.lever, jlayton, neilb, kolga, Dai.Ngo, tom,
	paul, jmorris, serge, zohar, dmitry.kasatkin, dhowells, jarkko,
	stephen.smalley.work, eparis, casey, mic
  Cc: linux-fsdevel, linux-kernel, linux-nfs, linux-security-module,
	linux-integrity, keyrings, selinux, Roberto Sassu

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.

In short, while this patch set is big, it does not make any functional
change to IMA and EVM. IMA and EVM functions are called by the LSM
infrastructure in the same places as before (except ima_post_path_mknod()),
rather being hardcoded calls, and the inode metadata pointer is directly
stored in the inode security blob rather than in a separate rbtree.

To avoid functional changes, it was necessary to keep the 'integrity' LSM
in addition to the newly introduced 'ima' and 'evm' LSMs, despite there is
no LSM ID assigned to it. There are two reasons: first, IMA and EVM still
share the same inode metadata, and thus cannot directly reserve space in
the security blob for it; second, someone needs to initialize 'ima' and
'evm' exactly in this order, as the LSM infrastructure cannot guarantee
that.

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.

Patches 19-22 do the bulk of the work, introduce the new LSMs 'ima' and
'evm', and move hardcoded calls to IMA, EVM and integrity functions to
those LSMs. In addition, they reserve one slot for the 'evm' LSM to supply
an xattr with the inode_init_security hook.

Finally, patch 23 removes the rbtree used to bind integrity metadata to the
inodes, and instead reserves a space in the inode security blob to store
the pointer to that metadata. This also brings performance improvements due
to retrieving metadata in constant time, as opposed to logarithmic.

The patch set applies on top of lsm/dev-staging, commit ba7ce019d3e9 ("lsm:
convert security_setselfattr() to use memdup_user()"). No need to merge
linux-integrity/next-integrity-testing.

Changelog:

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 (23):
  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_pre_free_security 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
  ima: Move to LSM infrastructure
  ima: Move IMA-Appraisal to LSM infrastructure
  evm: Move to LSM infrastructure
  integrity: Move integrity functions to the LSM infrastructure
  integrity: Switch from rbtree to LSM-managed blob for
    integrity_iint_cache

 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                   | 103 ----------
 include/linux/ima.h                   | 142 --------------
 include/linux/integrity.h             |  26 ---
 include/linux/lsm_hook_defs.h         |  20 +-
 include/linux/security.h              |  59 ++++++
 include/uapi/linux/lsm.h              |   2 +
 security/integrity/evm/evm_main.c     | 138 ++++++++++++--
 security/integrity/iint.c             | 113 +++++------
 security/integrity/ima/ima.h          |  11 ++
 security/integrity/ima/ima_appraise.c |  37 +++-
 security/integrity/ima/ima_main.c     |  96 ++++++++--
 security/integrity/integrity.h        |  58 +++++-
 security/keys/key.c                   |  10 +-
 security/security.c                   | 261 ++++++++++++++++----------
 security/selinux/hooks.c              |   3 +-
 security/smack/smack_lsm.c            |   4 +-
 23 files changed, 614 insertions(+), 507 deletions(-)

-- 
2.34.1


^ permalink raw reply	[flat|nested] 96+ messages in thread

* [PATCH v5 01/23] ima: Align ima_inode_post_setattr() definition with LSM infrastructure
  2023-11-07 13:39 [PATCH v5 00/23] security: Move IMA and EVM to the LSM infrastructure Roberto Sassu
@ 2023-11-07 13:39 ` Roberto Sassu
  2023-11-07 17:21   ` Casey Schaufler
  2023-11-07 13:39 ` [PATCH v5 02/23] ima: Align ima_file_mprotect() " Roberto Sassu
                   ` (22 subsequent siblings)
  23 siblings, 1 reply; 96+ messages in thread
From: Roberto Sassu @ 2023-11-07 13:39 UTC (permalink / raw)
  To: viro, brauner, chuck.lever, jlayton, neilb, kolga, Dai.Ngo, tom,
	paul, jmorris, serge, zohar, dmitry.kasatkin, dhowells, jarkko,
	stephen.smalley.work, eparis, casey, mic
  Cc: linux-fsdevel, linux-kernel, linux-nfs, linux-security-module,
	linux-integrity, keyrings, selinux, Roberto Sassu, Stefan Berger

From: Roberto Sassu <roberto.sassu@huawei.com>

Change ima_inode_post_setattr() definition, so that it can be registered as
implementation of the inode_post_setattr hook (to be introduced).

Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
---
 fs/attr.c                             | 2 +-
 include/linux/ima.h                   | 4 ++--
 security/integrity/ima/ima_appraise.c | 3 ++-
 3 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/fs/attr.c b/fs/attr.c
index bdf5deb06ea9..9bddc0a6352c 100644
--- a/fs/attr.c
+++ b/fs/attr.c
@@ -502,7 +502,7 @@ int notify_change(struct mnt_idmap *idmap, struct dentry *dentry,
 
 	if (!error) {
 		fsnotify_change(dentry, ia_valid);
-		ima_inode_post_setattr(idmap, dentry);
+		ima_inode_post_setattr(idmap, dentry, ia_valid);
 		evm_inode_post_setattr(dentry, ia_valid);
 	}
 
diff --git a/include/linux/ima.h b/include/linux/ima.h
index 86b57757c7b1..910a2f11a906 100644
--- a/include/linux/ima.h
+++ b/include/linux/ima.h
@@ -186,7 +186,7 @@ static inline void ima_post_key_create_or_update(struct key *keyring,
 #ifdef CONFIG_IMA_APPRAISE
 extern bool is_ima_appraise_enabled(void);
 extern void ima_inode_post_setattr(struct mnt_idmap *idmap,
-				   struct dentry *dentry);
+				   struct dentry *dentry, int ia_valid);
 extern int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name,
 		       const void *xattr_value, size_t xattr_value_len);
 extern int ima_inode_set_acl(struct mnt_idmap *idmap,
@@ -206,7 +206,7 @@ static inline bool is_ima_appraise_enabled(void)
 }
 
 static inline void ima_inode_post_setattr(struct mnt_idmap *idmap,
-					  struct dentry *dentry)
+					  struct dentry *dentry, int ia_valid)
 {
 	return;
 }
diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c
index 870dde67707b..36c2938a5c69 100644
--- a/security/integrity/ima/ima_appraise.c
+++ b/security/integrity/ima/ima_appraise.c
@@ -629,6 +629,7 @@ void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file)
  * ima_inode_post_setattr - reflect file metadata changes
  * @idmap:  idmap of the mount the inode was found from
  * @dentry: pointer to the affected dentry
+ * @ia_valid: for the UID and GID status
  *
  * Changes to a dentry's metadata might result in needing to appraise.
  *
@@ -636,7 +637,7 @@ void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file)
  * to lock the inode's i_mutex.
  */
 void ima_inode_post_setattr(struct mnt_idmap *idmap,
-			    struct dentry *dentry)
+			    struct dentry *dentry, int ia_valid)
 {
 	struct inode *inode = d_backing_inode(dentry);
 	struct integrity_iint_cache *iint;
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 96+ messages in thread

* [PATCH v5 02/23] ima: Align ima_file_mprotect() definition with LSM infrastructure
  2023-11-07 13:39 [PATCH v5 00/23] security: Move IMA and EVM to the LSM infrastructure Roberto Sassu
  2023-11-07 13:39 ` [PATCH v5 01/23] ima: Align ima_inode_post_setattr() definition with " Roberto Sassu
@ 2023-11-07 13:39 ` Roberto Sassu
  2023-11-07 17:22   ` Casey Schaufler
  2023-11-07 13:39 ` [PATCH v5 03/23] ima: Align ima_inode_setxattr() " Roberto Sassu
                   ` (21 subsequent siblings)
  23 siblings, 1 reply; 96+ messages in thread
From: Roberto Sassu @ 2023-11-07 13:39 UTC (permalink / raw)
  To: viro, brauner, chuck.lever, jlayton, neilb, kolga, Dai.Ngo, tom,
	paul, jmorris, serge, zohar, dmitry.kasatkin, dhowells, jarkko,
	stephen.smalley.work, eparis, casey, mic
  Cc: linux-fsdevel, linux-kernel, linux-nfs, linux-security-module,
	linux-integrity, keyrings, selinux, Roberto Sassu, Stefan Berger

From: Roberto Sassu <roberto.sassu@huawei.com>

Change ima_file_mprotect() definition, so that it can be registered
as implementation of the file_mprotect hook.

Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
---
 include/linux/ima.h               | 5 +++--
 security/integrity/ima/ima_main.c | 6 ++++--
 security/security.c               | 2 +-
 3 files changed, 8 insertions(+), 5 deletions(-)

diff --git a/include/linux/ima.h b/include/linux/ima.h
index 910a2f11a906..b66353f679e8 100644
--- a/include/linux/ima.h
+++ b/include/linux/ima.h
@@ -23,7 +23,8 @@ extern void ima_post_create_tmpfile(struct mnt_idmap *idmap,
 extern void ima_file_free(struct file *file);
 extern int ima_file_mmap(struct file *file, unsigned long reqprot,
 			 unsigned long prot, unsigned long flags);
-extern int ima_file_mprotect(struct vm_area_struct *vma, unsigned long prot);
+extern int ima_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot,
+			     unsigned long prot);
 extern int ima_load_data(enum kernel_load_data_id id, bool contents);
 extern int ima_post_load_data(char *buf, loff_t size,
 			      enum kernel_load_data_id id, char *description);
@@ -84,7 +85,7 @@ static inline int ima_file_mmap(struct file *file, unsigned long reqprot,
 }
 
 static inline int ima_file_mprotect(struct vm_area_struct *vma,
-				    unsigned long prot)
+				    unsigned long reqprot, unsigned long prot)
 {
 	return 0;
 }
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index cc1217ac2c6f..b3f5e8401056 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -455,7 +455,8 @@ int ima_file_mmap(struct file *file, unsigned long reqprot,
 /**
  * ima_file_mprotect - based on policy, limit mprotect change
  * @vma: vm_area_struct protection is set to
- * @prot: contains the protection that will be applied by the kernel.
+ * @reqprot: protection requested by the application
+ * @prot: protection that will be applied by the kernel
  *
  * Files can be mmap'ed read/write and later changed to execute to circumvent
  * IMA's mmap appraisal policy rules.  Due to locking issues (mmap semaphore
@@ -465,7 +466,8 @@ int ima_file_mmap(struct file *file, unsigned long reqprot,
  *
  * On mprotect change success, return 0.  On failure, return -EACESS.
  */
-int ima_file_mprotect(struct vm_area_struct *vma, unsigned long prot)
+int ima_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot,
+		      unsigned long prot)
 {
 	struct ima_template_desc *template = NULL;
 	struct file *file;
diff --git a/security/security.c b/security/security.c
index d7b15ea67c3f..c87ba1bbd7dc 100644
--- a/security/security.c
+++ b/security/security.c
@@ -2819,7 +2819,7 @@ int security_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot,
 	ret = call_int_hook(file_mprotect, 0, vma, reqprot, prot);
 	if (ret)
 		return ret;
-	return ima_file_mprotect(vma, prot);
+	return ima_file_mprotect(vma, reqprot, prot);
 }
 
 /**
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 96+ messages in thread

* [PATCH v5 03/23] ima: Align ima_inode_setxattr() definition with LSM infrastructure
  2023-11-07 13:39 [PATCH v5 00/23] security: Move IMA and EVM to the LSM infrastructure Roberto Sassu
  2023-11-07 13:39 ` [PATCH v5 01/23] ima: Align ima_inode_post_setattr() definition with " Roberto Sassu
  2023-11-07 13:39 ` [PATCH v5 02/23] ima: Align ima_file_mprotect() " Roberto Sassu
@ 2023-11-07 13:39 ` Roberto Sassu
  2023-11-07 17:23   ` Casey Schaufler
  2023-11-07 13:39 ` [PATCH v5 04/23] ima: Align ima_inode_removexattr() " Roberto Sassu
                   ` (20 subsequent siblings)
  23 siblings, 1 reply; 96+ messages in thread
From: Roberto Sassu @ 2023-11-07 13:39 UTC (permalink / raw)
  To: viro, brauner, chuck.lever, jlayton, neilb, kolga, Dai.Ngo, tom,
	paul, jmorris, serge, zohar, dmitry.kasatkin, dhowells, jarkko,
	stephen.smalley.work, eparis, casey, mic
  Cc: linux-fsdevel, linux-kernel, linux-nfs, linux-security-module,
	linux-integrity, keyrings, selinux, Roberto Sassu, Stefan Berger

From: Roberto Sassu <roberto.sassu@huawei.com>

Change ima_inode_setxattr() definition, so that it can be registered as
implementation of the inode_setxattr hook.

Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
---
 include/linux/ima.h                   | 11 +++++++----
 security/integrity/ima/ima_appraise.c |  5 +++--
 security/security.c                   |  2 +-
 3 files changed, 11 insertions(+), 7 deletions(-)

diff --git a/include/linux/ima.h b/include/linux/ima.h
index b66353f679e8..077324309c11 100644
--- a/include/linux/ima.h
+++ b/include/linux/ima.h
@@ -188,8 +188,9 @@ static inline void ima_post_key_create_or_update(struct key *keyring,
 extern bool is_ima_appraise_enabled(void);
 extern void ima_inode_post_setattr(struct mnt_idmap *idmap,
 				   struct dentry *dentry, int ia_valid);
-extern int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name,
-		       const void *xattr_value, size_t xattr_value_len);
+extern int ima_inode_setxattr(struct mnt_idmap *idmap, struct dentry *dentry,
+			      const char *xattr_name, const void *xattr_value,
+			      size_t xattr_value_len, int flags);
 extern int ima_inode_set_acl(struct mnt_idmap *idmap,
 			     struct dentry *dentry, const char *acl_name,
 			     struct posix_acl *kacl);
@@ -212,10 +213,12 @@ static inline void ima_inode_post_setattr(struct mnt_idmap *idmap,
 	return;
 }
 
-static inline int ima_inode_setxattr(struct dentry *dentry,
+static inline int ima_inode_setxattr(struct mnt_idmap *idmap,
+				     struct dentry *dentry,
 				     const char *xattr_name,
 				     const void *xattr_value,
-				     size_t xattr_value_len)
+				     size_t xattr_value_len,
+				     int flags)
 {
 	return 0;
 }
diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c
index 36c2938a5c69..cb2d0d11aa77 100644
--- a/security/integrity/ima/ima_appraise.c
+++ b/security/integrity/ima/ima_appraise.c
@@ -750,8 +750,9 @@ static int validate_hash_algo(struct dentry *dentry,
 	return -EACCES;
 }
 
-int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name,
-		       const void *xattr_value, size_t xattr_value_len)
+int ima_inode_setxattr(struct mnt_idmap *idmap, struct dentry *dentry,
+		       const char *xattr_name, const void *xattr_value,
+		       size_t xattr_value_len, int flags)
 {
 	const struct evm_ima_xattr_data *xvalue = xattr_value;
 	int digsig = 0;
diff --git a/security/security.c b/security/security.c
index c87ba1bbd7dc..ec5c8065ea36 100644
--- a/security/security.c
+++ b/security/security.c
@@ -2269,7 +2269,7 @@ int security_inode_setxattr(struct mnt_idmap *idmap,
 		ret = cap_inode_setxattr(dentry, name, value, size, flags);
 	if (ret)
 		return ret;
-	ret = ima_inode_setxattr(dentry, name, value, size);
+	ret = ima_inode_setxattr(idmap, dentry, name, value, size, flags);
 	if (ret)
 		return ret;
 	return evm_inode_setxattr(idmap, dentry, name, value, size);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 96+ messages in thread

* [PATCH v5 04/23] ima: Align ima_inode_removexattr() definition with LSM infrastructure
  2023-11-07 13:39 [PATCH v5 00/23] security: Move IMA and EVM to the LSM infrastructure Roberto Sassu
                   ` (2 preceding siblings ...)
  2023-11-07 13:39 ` [PATCH v5 03/23] ima: Align ima_inode_setxattr() " Roberto Sassu
@ 2023-11-07 13:39 ` Roberto Sassu
  2023-11-07 17:24   ` Casey Schaufler
  2023-11-07 13:39 ` [PATCH v5 05/23] ima: Align ima_post_read_file() " Roberto Sassu
                   ` (19 subsequent siblings)
  23 siblings, 1 reply; 96+ messages in thread
From: Roberto Sassu @ 2023-11-07 13:39 UTC (permalink / raw)
  To: viro, brauner, chuck.lever, jlayton, neilb, kolga, Dai.Ngo, tom,
	paul, jmorris, serge, zohar, dmitry.kasatkin, dhowells, jarkko,
	stephen.smalley.work, eparis, casey, mic
  Cc: linux-fsdevel, linux-kernel, linux-nfs, linux-security-module,
	linux-integrity, keyrings, selinux, Roberto Sassu, Stefan Berger

From: Roberto Sassu <roberto.sassu@huawei.com>

Change ima_inode_removexattr() definition, so that it can be registered as
implementation of the inode_removexattr hook.

Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
---
 include/linux/ima.h                   | 7 +++++--
 security/integrity/ima/ima_appraise.c | 3 ++-
 security/security.c                   | 2 +-
 3 files changed, 8 insertions(+), 4 deletions(-)

diff --git a/include/linux/ima.h b/include/linux/ima.h
index 077324309c11..678a03fddd7e 100644
--- a/include/linux/ima.h
+++ b/include/linux/ima.h
@@ -200,7 +200,9 @@ static inline int ima_inode_remove_acl(struct mnt_idmap *idmap,
 {
 	return ima_inode_set_acl(idmap, dentry, acl_name, NULL);
 }
-extern int ima_inode_removexattr(struct dentry *dentry, const char *xattr_name);
+
+extern int ima_inode_removexattr(struct mnt_idmap *idmap, struct dentry *dentry,
+				 const char *xattr_name);
 #else
 static inline bool is_ima_appraise_enabled(void)
 {
@@ -231,7 +233,8 @@ static inline int ima_inode_set_acl(struct mnt_idmap *idmap,
 	return 0;
 }
 
-static inline int ima_inode_removexattr(struct dentry *dentry,
+static inline int ima_inode_removexattr(struct mnt_idmap *idmap,
+					struct dentry *dentry,
 					const char *xattr_name)
 {
 	return 0;
diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c
index cb2d0d11aa77..36abc84ba299 100644
--- a/security/integrity/ima/ima_appraise.c
+++ b/security/integrity/ima/ima_appraise.c
@@ -790,7 +790,8 @@ int ima_inode_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
 	return 0;
 }
 
-int ima_inode_removexattr(struct dentry *dentry, const char *xattr_name)
+int ima_inode_removexattr(struct mnt_idmap *idmap, struct dentry *dentry,
+			  const char *xattr_name)
 {
 	int result;
 
diff --git a/security/security.c b/security/security.c
index ec5c8065ea36..358ec01a5492 100644
--- a/security/security.c
+++ b/security/security.c
@@ -2430,7 +2430,7 @@ int security_inode_removexattr(struct mnt_idmap *idmap,
 		ret = cap_inode_removexattr(idmap, dentry, name);
 	if (ret)
 		return ret;
-	ret = ima_inode_removexattr(dentry, name);
+	ret = ima_inode_removexattr(idmap, dentry, name);
 	if (ret)
 		return ret;
 	return evm_inode_removexattr(idmap, dentry, name);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 96+ messages in thread

* [PATCH v5 05/23] ima: Align ima_post_read_file() definition with LSM infrastructure
  2023-11-07 13:39 [PATCH v5 00/23] security: Move IMA and EVM to the LSM infrastructure Roberto Sassu
                   ` (3 preceding siblings ...)
  2023-11-07 13:39 ` [PATCH v5 04/23] ima: Align ima_inode_removexattr() " Roberto Sassu
@ 2023-11-07 13:39 ` Roberto Sassu
  2023-11-07 17:25   ` Casey Schaufler
  2023-11-07 13:39 ` [PATCH v5 06/23] evm: Align evm_inode_post_setattr() " Roberto Sassu
                   ` (18 subsequent siblings)
  23 siblings, 1 reply; 96+ messages in thread
From: Roberto Sassu @ 2023-11-07 13:39 UTC (permalink / raw)
  To: viro, brauner, chuck.lever, jlayton, neilb, kolga, Dai.Ngo, tom,
	paul, jmorris, serge, zohar, dmitry.kasatkin, dhowells, jarkko,
	stephen.smalley.work, eparis, casey, mic
  Cc: linux-fsdevel, linux-kernel, linux-nfs, linux-security-module,
	linux-integrity, keyrings, selinux, Roberto Sassu, Stefan Berger

From: Roberto Sassu <roberto.sassu@huawei.com>

Change ima_post_read_file() definition, by making "void *buf" a
"char *buf", so that it can be registered as implementation of the
post_read_file hook.

Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
---
 include/linux/ima.h               | 4 ++--
 security/integrity/ima/ima_main.c | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/include/linux/ima.h b/include/linux/ima.h
index 678a03fddd7e..31ef6c3c3207 100644
--- a/include/linux/ima.h
+++ b/include/linux/ima.h
@@ -30,7 +30,7 @@ extern int ima_post_load_data(char *buf, loff_t size,
 			      enum kernel_load_data_id id, char *description);
 extern int ima_read_file(struct file *file, enum kernel_read_file_id id,
 			 bool contents);
-extern int ima_post_read_file(struct file *file, void *buf, loff_t size,
+extern int ima_post_read_file(struct file *file, char *buf, loff_t size,
 			      enum kernel_read_file_id id);
 extern void ima_post_path_mknod(struct mnt_idmap *idmap,
 				struct dentry *dentry);
@@ -108,7 +108,7 @@ static inline int ima_read_file(struct file *file, enum kernel_read_file_id id,
 	return 0;
 }
 
-static inline int ima_post_read_file(struct file *file, void *buf, loff_t size,
+static inline int ima_post_read_file(struct file *file, char *buf, loff_t size,
 				     enum kernel_read_file_id id)
 {
 	return 0;
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index b3f5e8401056..02021ee467d3 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -803,7 +803,7 @@ const int read_idmap[READING_MAX_ID] = {
  * On success return 0.  On integrity appraisal error, assuming the file
  * is in policy and IMA-appraisal is in enforcing mode, return -EACCES.
  */
-int ima_post_read_file(struct file *file, void *buf, loff_t size,
+int ima_post_read_file(struct file *file, char *buf, loff_t size,
 		       enum kernel_read_file_id read_id)
 {
 	enum ima_hooks func;
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 96+ messages in thread

* [PATCH v5 06/23] evm: Align evm_inode_post_setattr() definition with LSM infrastructure
  2023-11-07 13:39 [PATCH v5 00/23] security: Move IMA and EVM to the LSM infrastructure Roberto Sassu
                   ` (4 preceding siblings ...)
  2023-11-07 13:39 ` [PATCH v5 05/23] ima: Align ima_post_read_file() " Roberto Sassu
@ 2023-11-07 13:39 ` Roberto Sassu
  2023-11-07 17:26   ` Casey Schaufler
  2023-11-07 13:39 ` [PATCH v5 07/23] evm: Align evm_inode_setxattr() " Roberto Sassu
                   ` (17 subsequent siblings)
  23 siblings, 1 reply; 96+ messages in thread
From: Roberto Sassu @ 2023-11-07 13:39 UTC (permalink / raw)
  To: viro, brauner, chuck.lever, jlayton, neilb, kolga, Dai.Ngo, tom,
	paul, jmorris, serge, zohar, dmitry.kasatkin, dhowells, jarkko,
	stephen.smalley.work, eparis, casey, mic
  Cc: linux-fsdevel, linux-kernel, linux-nfs, linux-security-module,
	linux-integrity, keyrings, selinux, Roberto Sassu, Stefan Berger

From: Roberto Sassu <roberto.sassu@huawei.com>

Change evm_inode_post_setattr() definition, so that it can be registered as
implementation of the inode_post_setattr hook (to be introduced).

Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
---
 fs/attr.c                         | 2 +-
 include/linux/evm.h               | 6 ++++--
 security/integrity/evm/evm_main.c | 4 +++-
 3 files changed, 8 insertions(+), 4 deletions(-)

diff --git a/fs/attr.c b/fs/attr.c
index 9bddc0a6352c..498e673bdf06 100644
--- a/fs/attr.c
+++ b/fs/attr.c
@@ -503,7 +503,7 @@ int notify_change(struct mnt_idmap *idmap, struct dentry *dentry,
 	if (!error) {
 		fsnotify_change(dentry, ia_valid);
 		ima_inode_post_setattr(idmap, dentry, ia_valid);
-		evm_inode_post_setattr(dentry, ia_valid);
+		evm_inode_post_setattr(idmap, dentry, ia_valid);
 	}
 
 	return error;
diff --git a/include/linux/evm.h b/include/linux/evm.h
index 01fc495a83e2..cf976d8dbd7a 100644
--- a/include/linux/evm.h
+++ b/include/linux/evm.h
@@ -23,7 +23,8 @@ extern enum integrity_status evm_verifyxattr(struct dentry *dentry,
 					     struct integrity_iint_cache *iint);
 extern int evm_inode_setattr(struct mnt_idmap *idmap,
 			     struct dentry *dentry, struct iattr *attr);
-extern void evm_inode_post_setattr(struct dentry *dentry, int ia_valid);
+extern void evm_inode_post_setattr(struct mnt_idmap *idmap,
+				   struct dentry *dentry, int ia_valid);
 extern int evm_inode_setxattr(struct mnt_idmap *idmap,
 			      struct dentry *dentry, const char *name,
 			      const void *value, size_t size);
@@ -97,7 +98,8 @@ static inline int evm_inode_setattr(struct mnt_idmap *idmap,
 	return 0;
 }
 
-static inline void evm_inode_post_setattr(struct dentry *dentry, int ia_valid)
+static inline void evm_inode_post_setattr(struct mnt_idmap *idmap,
+					  struct dentry *dentry, int ia_valid)
 {
 	return;
 }
diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c
index 894570fe39bc..d452d469c503 100644
--- a/security/integrity/evm/evm_main.c
+++ b/security/integrity/evm/evm_main.c
@@ -840,6 +840,7 @@ int evm_inode_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
 
 /**
  * evm_inode_post_setattr - update 'security.evm' after modifying metadata
+ * @idmap: idmap of the idmapped mount
  * @dentry: pointer to the affected dentry
  * @ia_valid: for the UID and GID status
  *
@@ -849,7 +850,8 @@ int evm_inode_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
  * This function is called from notify_change(), which expects the caller
  * to lock the inode's i_mutex.
  */
-void evm_inode_post_setattr(struct dentry *dentry, int ia_valid)
+void evm_inode_post_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
+			    int ia_valid)
 {
 	if (!evm_revalidate_status(NULL))
 		return;
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 96+ messages in thread

* [PATCH v5 07/23] evm: Align evm_inode_setxattr() definition with LSM infrastructure
  2023-11-07 13:39 [PATCH v5 00/23] security: Move IMA and EVM to the LSM infrastructure Roberto Sassu
                   ` (5 preceding siblings ...)
  2023-11-07 13:39 ` [PATCH v5 06/23] evm: Align evm_inode_post_setattr() " Roberto Sassu
@ 2023-11-07 13:39 ` Roberto Sassu
  2023-11-07 17:27   ` Casey Schaufler
  2023-11-07 13:39 ` [PATCH v5 08/23] evm: Align evm_inode_post_setxattr() " Roberto Sassu
                   ` (16 subsequent siblings)
  23 siblings, 1 reply; 96+ messages in thread
From: Roberto Sassu @ 2023-11-07 13:39 UTC (permalink / raw)
  To: viro, brauner, chuck.lever, jlayton, neilb, kolga, Dai.Ngo, tom,
	paul, jmorris, serge, zohar, dmitry.kasatkin, dhowells, jarkko,
	stephen.smalley.work, eparis, casey, mic
  Cc: linux-fsdevel, linux-kernel, linux-nfs, linux-security-module,
	linux-integrity, keyrings, selinux, Roberto Sassu, Stefan Berger

From: Roberto Sassu <roberto.sassu@huawei.com>

Change evm_inode_setxattr() definition, so that it can be registered as
implementation of the inode_setxattr hook.

Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
---
 include/linux/evm.h               | 4 ++--
 security/integrity/evm/evm_main.c | 3 ++-
 security/security.c               | 2 +-
 3 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/include/linux/evm.h b/include/linux/evm.h
index cf976d8dbd7a..7c6a74dbc093 100644
--- a/include/linux/evm.h
+++ b/include/linux/evm.h
@@ -27,7 +27,7 @@ extern void evm_inode_post_setattr(struct mnt_idmap *idmap,
 				   struct dentry *dentry, int ia_valid);
 extern int evm_inode_setxattr(struct mnt_idmap *idmap,
 			      struct dentry *dentry, const char *name,
-			      const void *value, size_t size);
+			      const void *value, size_t size, int flags);
 extern void evm_inode_post_setxattr(struct dentry *dentry,
 				    const char *xattr_name,
 				    const void *xattr_value,
@@ -106,7 +106,7 @@ static inline void evm_inode_post_setattr(struct mnt_idmap *idmap,
 
 static inline int evm_inode_setxattr(struct mnt_idmap *idmap,
 				     struct dentry *dentry, const char *name,
-				     const void *value, size_t size)
+				     const void *value, size_t size, int flags)
 {
 	return 0;
 }
diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c
index d452d469c503..7fc083d53fdf 100644
--- a/security/integrity/evm/evm_main.c
+++ b/security/integrity/evm/evm_main.c
@@ -558,6 +558,7 @@ static int evm_protect_xattr(struct mnt_idmap *idmap,
  * @xattr_name: pointer to the affected extended attribute name
  * @xattr_value: pointer to the new extended attribute value
  * @xattr_value_len: pointer to the new extended attribute value length
+ * @flags: flags to pass into filesystem operations
  *
  * Before allowing the 'security.evm' protected xattr to be updated,
  * verify the existing value is valid.  As only the kernel should have
@@ -567,7 +568,7 @@ static int evm_protect_xattr(struct mnt_idmap *idmap,
  */
 int evm_inode_setxattr(struct mnt_idmap *idmap, struct dentry *dentry,
 		       const char *xattr_name, const void *xattr_value,
-		       size_t xattr_value_len)
+		       size_t xattr_value_len, int flags)
 {
 	const struct evm_ima_xattr_data *xattr_data = xattr_value;
 
diff --git a/security/security.c b/security/security.c
index 358ec01a5492..ae3625198c9f 100644
--- a/security/security.c
+++ b/security/security.c
@@ -2272,7 +2272,7 @@ int security_inode_setxattr(struct mnt_idmap *idmap,
 	ret = ima_inode_setxattr(idmap, dentry, name, value, size, flags);
 	if (ret)
 		return ret;
-	return evm_inode_setxattr(idmap, dentry, name, value, size);
+	return evm_inode_setxattr(idmap, dentry, name, value, size, flags);
 }
 
 /**
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 96+ messages in thread

* [PATCH v5 08/23] evm: Align evm_inode_post_setxattr() definition with LSM infrastructure
  2023-11-07 13:39 [PATCH v5 00/23] security: Move IMA and EVM to the LSM infrastructure Roberto Sassu
                   ` (6 preceding siblings ...)
  2023-11-07 13:39 ` [PATCH v5 07/23] evm: Align evm_inode_setxattr() " Roberto Sassu
@ 2023-11-07 13:39 ` Roberto Sassu
  2023-11-07 17:28   ` Casey Schaufler
  2023-11-07 13:39 ` [PATCH v5 09/23] security: Align inode_setattr hook definition with EVM Roberto Sassu
                   ` (15 subsequent siblings)
  23 siblings, 1 reply; 96+ messages in thread
From: Roberto Sassu @ 2023-11-07 13:39 UTC (permalink / raw)
  To: viro, brauner, chuck.lever, jlayton, neilb, kolga, Dai.Ngo, tom,
	paul, jmorris, serge, zohar, dmitry.kasatkin, dhowells, jarkko,
	stephen.smalley.work, eparis, casey, mic
  Cc: linux-fsdevel, linux-kernel, linux-nfs, linux-security-module,
	linux-integrity, keyrings, selinux, Roberto Sassu, Stefan Berger

From: Roberto Sassu <roberto.sassu@huawei.com>

Change evm_inode_post_setxattr() definition, so that it can be registered
as implementation of the inode_post_setxattr hook.

Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
---
 include/linux/evm.h               | 8 +++++---
 security/integrity/evm/evm_main.c | 4 +++-
 security/security.c               | 2 +-
 3 files changed, 9 insertions(+), 5 deletions(-)

diff --git a/include/linux/evm.h b/include/linux/evm.h
index 7c6a74dbc093..437d4076a3b3 100644
--- a/include/linux/evm.h
+++ b/include/linux/evm.h
@@ -31,7 +31,8 @@ extern int evm_inode_setxattr(struct mnt_idmap *idmap,
 extern void evm_inode_post_setxattr(struct dentry *dentry,
 				    const char *xattr_name,
 				    const void *xattr_value,
-				    size_t xattr_value_len);
+				    size_t xattr_value_len,
+				    int flags);
 extern int evm_inode_removexattr(struct mnt_idmap *idmap,
 				 struct dentry *dentry, const char *xattr_name);
 extern void evm_inode_post_removexattr(struct dentry *dentry,
@@ -55,7 +56,7 @@ static inline void evm_inode_post_set_acl(struct dentry *dentry,
 					  const char *acl_name,
 					  struct posix_acl *kacl)
 {
-	return evm_inode_post_setxattr(dentry, acl_name, NULL, 0);
+	return evm_inode_post_setxattr(dentry, acl_name, NULL, 0, 0);
 }
 
 int evm_inode_init_security(struct inode *inode, struct inode *dir,
@@ -114,7 +115,8 @@ static inline int evm_inode_setxattr(struct mnt_idmap *idmap,
 static inline void evm_inode_post_setxattr(struct dentry *dentry,
 					   const char *xattr_name,
 					   const void *xattr_value,
-					   size_t xattr_value_len)
+					   size_t xattr_value_len,
+					   int flags)
 {
 	return;
 }
diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c
index 7fc083d53fdf..ea84a6f835ff 100644
--- a/security/integrity/evm/evm_main.c
+++ b/security/integrity/evm/evm_main.c
@@ -730,6 +730,7 @@ bool evm_revalidate_status(const char *xattr_name)
  * @xattr_name: pointer to the affected extended attribute name
  * @xattr_value: pointer to the new extended attribute value
  * @xattr_value_len: pointer to the new extended attribute value length
+ * @flags: flags to pass into filesystem operations
  *
  * Update the HMAC stored in 'security.evm' to reflect the change.
  *
@@ -738,7 +739,8 @@ bool evm_revalidate_status(const char *xattr_name)
  * i_mutex lock.
  */
 void evm_inode_post_setxattr(struct dentry *dentry, const char *xattr_name,
-			     const void *xattr_value, size_t xattr_value_len)
+			     const void *xattr_value, size_t xattr_value_len,
+			     int flags)
 {
 	if (!evm_revalidate_status(xattr_name))
 		return;
diff --git a/security/security.c b/security/security.c
index ae3625198c9f..53793f3cb36a 100644
--- a/security/security.c
+++ b/security/security.c
@@ -2367,7 +2367,7 @@ void security_inode_post_setxattr(struct dentry *dentry, const char *name,
 	if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
 		return;
 	call_void_hook(inode_post_setxattr, dentry, name, value, size, flags);
-	evm_inode_post_setxattr(dentry, name, value, size);
+	evm_inode_post_setxattr(dentry, name, value, size, flags);
 }
 
 /**
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 96+ messages in thread

* [PATCH v5 09/23] security: Align inode_setattr hook definition with EVM
  2023-11-07 13:39 [PATCH v5 00/23] security: Move IMA and EVM to the LSM infrastructure Roberto Sassu
                   ` (7 preceding siblings ...)
  2023-11-07 13:39 ` [PATCH v5 08/23] evm: Align evm_inode_post_setxattr() " Roberto Sassu
@ 2023-11-07 13:39 ` Roberto Sassu
  2023-11-07 13:39 ` [PATCH v5 10/23] security: Introduce inode_post_setattr hook Roberto Sassu
                   ` (14 subsequent siblings)
  23 siblings, 0 replies; 96+ messages in thread
From: Roberto Sassu @ 2023-11-07 13:39 UTC (permalink / raw)
  To: viro, brauner, chuck.lever, jlayton, neilb, kolga, Dai.Ngo, tom,
	paul, jmorris, serge, zohar, dmitry.kasatkin, dhowells, jarkko,
	stephen.smalley.work, eparis, casey, mic
  Cc: linux-fsdevel, linux-kernel, linux-nfs, linux-security-module,
	linux-integrity, keyrings, selinux, Roberto Sassu, Stefan Berger

From: Roberto Sassu <roberto.sassu@huawei.com>

Add the idmap parameter to the definition, so that evm_inode_setattr() can
be registered as this hook implementation.

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>
---
 include/linux/lsm_hook_defs.h | 3 ++-
 security/security.c           | 2 +-
 security/selinux/hooks.c      | 3 ++-
 security/smack/smack_lsm.c    | 4 +++-
 4 files changed, 8 insertions(+), 4 deletions(-)

diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
index 6ea529e4d9be..f5db5e993cd8 100644
--- a/include/linux/lsm_hook_defs.h
+++ b/include/linux/lsm_hook_defs.h
@@ -135,7 +135,8 @@ LSM_HOOK(int, 0, inode_readlink, struct dentry *dentry)
 LSM_HOOK(int, 0, inode_follow_link, struct dentry *dentry, struct inode *inode,
 	 bool rcu)
 LSM_HOOK(int, 0, inode_permission, struct inode *inode, int mask)
-LSM_HOOK(int, 0, inode_setattr, struct dentry *dentry, struct iattr *attr)
+LSM_HOOK(int, 0, inode_setattr, struct mnt_idmap *idmap, struct dentry *dentry,
+	 struct iattr *attr)
 LSM_HOOK(int, 0, inode_getattr, const struct path *path)
 LSM_HOOK(int, 0, inode_setxattr, struct mnt_idmap *idmap,
 	 struct dentry *dentry, const char *name, const void *value,
diff --git a/security/security.c b/security/security.c
index 53793f3cb36a..7935d11d58b5 100644
--- a/security/security.c
+++ b/security/security.c
@@ -2215,7 +2215,7 @@ int security_inode_setattr(struct mnt_idmap *idmap,
 
 	if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
 		return 0;
-	ret = call_int_hook(inode_setattr, 0, dentry, attr);
+	ret = call_int_hook(inode_setattr, 0, idmap, dentry, attr);
 	if (ret)
 		return ret;
 	return evm_inode_setattr(idmap, dentry, attr);
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 942f2b8c4ebb..c0807055513a 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -3128,7 +3128,8 @@ static int selinux_inode_permission(struct inode *inode, int mask)
 	return rc;
 }
 
-static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
+static int selinux_inode_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
+				 struct iattr *iattr)
 {
 	const struct cred *cred = current_cred();
 	struct inode *inode = d_backing_inode(dentry);
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 99664c8cf867..9ebb4ec49f35 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -1232,12 +1232,14 @@ static int smack_inode_permission(struct inode *inode, int mask)
 
 /**
  * smack_inode_setattr - Smack check for setting attributes
+ * @idmap: idmap of the mount
  * @dentry: the object
  * @iattr: for the force flag
  *
  * Returns 0 if access is permitted, an error code otherwise
  */
-static int smack_inode_setattr(struct dentry *dentry, struct iattr *iattr)
+static int smack_inode_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
+			       struct iattr *iattr)
 {
 	struct smk_audit_info ad;
 	int rc;
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 96+ messages in thread

* [PATCH v5 10/23] security: Introduce inode_post_setattr hook
  2023-11-07 13:39 [PATCH v5 00/23] security: Move IMA and EVM to the LSM infrastructure Roberto Sassu
                   ` (8 preceding siblings ...)
  2023-11-07 13:39 ` [PATCH v5 09/23] security: Align inode_setattr hook definition with EVM Roberto Sassu
@ 2023-11-07 13:39 ` Roberto Sassu
  2023-11-07 17:30   ` Casey Schaufler
  2023-11-16  4:33   ` Paul Moore
  2023-11-07 13:40 ` [PATCH v5 11/23] security: Introduce inode_post_removexattr hook Roberto Sassu
                   ` (13 subsequent siblings)
  23 siblings, 2 replies; 96+ messages in thread
From: Roberto Sassu @ 2023-11-07 13:39 UTC (permalink / raw)
  To: viro, brauner, chuck.lever, jlayton, neilb, kolga, Dai.Ngo, tom,
	paul, jmorris, serge, zohar, dmitry.kasatkin, dhowells, jarkko,
	stephen.smalley.work, eparis, casey, mic
  Cc: linux-fsdevel, linux-kernel, linux-nfs, linux-security-module,
	linux-integrity, keyrings, selinux, Roberto Sassu, Stefan Berger

From: Roberto Sassu <roberto.sassu@huawei.com>

In preparation for moving IMA and EVM to the LSM infrastructure, introduce
the inode_post_setattr hook.

At inode_setattr hook, EVM verifies the file's existing HMAC value. At
inode_post_setattr, EVM re-calculates the file's HMAC based on the modified
file attributes and other file metadata.

Other LSMs could similarly take some action after successful file attribute
change.

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>
Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
---
 fs/attr.c                     |  1 +
 include/linux/lsm_hook_defs.h |  2 ++
 include/linux/security.h      |  7 +++++++
 security/security.c           | 16 ++++++++++++++++
 4 files changed, 26 insertions(+)

diff --git a/fs/attr.c b/fs/attr.c
index 498e673bdf06..221d2bb0a906 100644
--- a/fs/attr.c
+++ b/fs/attr.c
@@ -502,6 +502,7 @@ int notify_change(struct mnt_idmap *idmap, struct dentry *dentry,
 
 	if (!error) {
 		fsnotify_change(dentry, ia_valid);
+		security_inode_post_setattr(idmap, dentry, ia_valid);
 		ima_inode_post_setattr(idmap, dentry, ia_valid);
 		evm_inode_post_setattr(idmap, dentry, ia_valid);
 	}
diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
index f5db5e993cd8..67410e085205 100644
--- a/include/linux/lsm_hook_defs.h
+++ b/include/linux/lsm_hook_defs.h
@@ -137,6 +137,8 @@ LSM_HOOK(int, 0, inode_follow_link, struct dentry *dentry, struct inode *inode,
 LSM_HOOK(int, 0, inode_permission, struct inode *inode, int mask)
 LSM_HOOK(int, 0, inode_setattr, struct mnt_idmap *idmap, struct dentry *dentry,
 	 struct iattr *attr)
+LSM_HOOK(void, LSM_RET_VOID, inode_post_setattr, struct mnt_idmap *idmap,
+	 struct dentry *dentry, int ia_valid)
 LSM_HOOK(int, 0, inode_getattr, const struct path *path)
 LSM_HOOK(int, 0, inode_setxattr, struct mnt_idmap *idmap,
 	 struct dentry *dentry, const char *name, const void *value,
diff --git a/include/linux/security.h b/include/linux/security.h
index 750130a7b9dd..664df46b22a9 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -361,6 +361,8 @@ int security_inode_follow_link(struct dentry *dentry, struct inode *inode,
 int security_inode_permission(struct inode *inode, int mask);
 int security_inode_setattr(struct mnt_idmap *idmap,
 			   struct dentry *dentry, struct iattr *attr);
+void security_inode_post_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
+				 int ia_valid);
 int security_inode_getattr(const struct path *path);
 int security_inode_setxattr(struct mnt_idmap *idmap,
 			    struct dentry *dentry, const char *name,
@@ -877,6 +879,11 @@ static inline int security_inode_setattr(struct mnt_idmap *idmap,
 	return 0;
 }
 
+static inline void
+security_inode_post_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
+			    int ia_valid)
+{ }
+
 static inline int security_inode_getattr(const struct path *path)
 {
 	return 0;
diff --git a/security/security.c b/security/security.c
index 7935d11d58b5..ce3bc7642e18 100644
--- a/security/security.c
+++ b/security/security.c
@@ -2222,6 +2222,22 @@ int security_inode_setattr(struct mnt_idmap *idmap,
 }
 EXPORT_SYMBOL_GPL(security_inode_setattr);
 
+/**
+ * security_inode_post_setattr() - Update the inode after a setattr operation
+ * @idmap: idmap of the mount
+ * @dentry: file
+ * @ia_valid: file attributes set
+ *
+ * Update inode security field after successful setting file attributes.
+ */
+void security_inode_post_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
+				 int ia_valid)
+{
+	if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
+		return;
+	call_void_hook(inode_post_setattr, idmap, dentry, ia_valid);
+}
+
 /**
  * security_inode_getattr() - Check if getting file attributes is allowed
  * @path: file
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 96+ messages in thread

* [PATCH v5 11/23] security: Introduce inode_post_removexattr hook
  2023-11-07 13:39 [PATCH v5 00/23] security: Move IMA and EVM to the LSM infrastructure Roberto Sassu
                   ` (9 preceding siblings ...)
  2023-11-07 13:39 ` [PATCH v5 10/23] security: Introduce inode_post_setattr hook Roberto Sassu
@ 2023-11-07 13:40 ` Roberto Sassu
  2023-11-07 17:33   ` Casey Schaufler
  2023-11-16  4:33   ` Paul Moore
  2023-11-07 13:40 ` [PATCH v5 12/23] security: Introduce file_post_open hook Roberto Sassu
                   ` (12 subsequent siblings)
  23 siblings, 2 replies; 96+ messages in thread
From: Roberto Sassu @ 2023-11-07 13:40 UTC (permalink / raw)
  To: viro, brauner, chuck.lever, jlayton, neilb, kolga, Dai.Ngo, tom,
	paul, jmorris, serge, zohar, dmitry.kasatkin, dhowells, jarkko,
	stephen.smalley.work, eparis, casey, mic
  Cc: linux-fsdevel, linux-kernel, linux-nfs, linux-security-module,
	linux-integrity, keyrings, selinux, Roberto Sassu, Stefan Berger

From: Roberto Sassu <roberto.sassu@huawei.com>

In preparation for moving IMA and EVM to the LSM infrastructure, introduce
the inode_post_removexattr hook.

At inode_removexattr hook, EVM verifies the file's existing HMAC value. At
inode_post_removexattr, EVM re-calculates the file's HMAC with the passed
xattr removed and other file metadata.

Other LSMs could similarly take some action after successful xattr removal.

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>
Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
---
 fs/xattr.c                    |  9 +++++----
 include/linux/lsm_hook_defs.h |  2 ++
 include/linux/security.h      |  5 +++++
 security/security.c           | 14 ++++++++++++++
 4 files changed, 26 insertions(+), 4 deletions(-)

diff --git a/fs/xattr.c b/fs/xattr.c
index 09d927603433..84a4aa566c02 100644
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -552,11 +552,12 @@ __vfs_removexattr_locked(struct mnt_idmap *idmap,
 		goto out;
 
 	error = __vfs_removexattr(idmap, dentry, name);
+	if (error)
+		goto out;
 
-	if (!error) {
-		fsnotify_xattr(dentry);
-		evm_inode_post_removexattr(dentry, name);
-	}
+	fsnotify_xattr(dentry);
+	security_inode_post_removexattr(dentry, name);
+	evm_inode_post_removexattr(dentry, name);
 
 out:
 	return error;
diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
index 67410e085205..88452e45025c 100644
--- a/include/linux/lsm_hook_defs.h
+++ b/include/linux/lsm_hook_defs.h
@@ -149,6 +149,8 @@ LSM_HOOK(int, 0, inode_getxattr, struct dentry *dentry, const char *name)
 LSM_HOOK(int, 0, inode_listxattr, struct dentry *dentry)
 LSM_HOOK(int, 0, inode_removexattr, struct mnt_idmap *idmap,
 	 struct dentry *dentry, const char *name)
+LSM_HOOK(void, LSM_RET_VOID, inode_post_removexattr, struct dentry *dentry,
+	 const char *name)
 LSM_HOOK(int, 0, inode_set_acl, struct mnt_idmap *idmap,
 	 struct dentry *dentry, const char *acl_name, struct posix_acl *kacl)
 LSM_HOOK(int, 0, inode_get_acl, struct mnt_idmap *idmap,
diff --git a/include/linux/security.h b/include/linux/security.h
index 664df46b22a9..922ea7709bae 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -380,6 +380,7 @@ int security_inode_getxattr(struct dentry *dentry, const char *name);
 int security_inode_listxattr(struct dentry *dentry);
 int security_inode_removexattr(struct mnt_idmap *idmap,
 			       struct dentry *dentry, const char *name);
+void security_inode_post_removexattr(struct dentry *dentry, const char *name);
 int security_inode_need_killpriv(struct dentry *dentry);
 int security_inode_killpriv(struct mnt_idmap *idmap, struct dentry *dentry);
 int security_inode_getsecurity(struct mnt_idmap *idmap,
@@ -940,6 +941,10 @@ static inline int security_inode_removexattr(struct mnt_idmap *idmap,
 	return cap_inode_removexattr(idmap, dentry, name);
 }
 
+static inline void security_inode_post_removexattr(struct dentry *dentry,
+						   const char *name)
+{ }
+
 static inline int security_inode_need_killpriv(struct dentry *dentry)
 {
 	return cap_inode_need_killpriv(dentry);
diff --git a/security/security.c b/security/security.c
index ce3bc7642e18..8aa6e9f316dd 100644
--- a/security/security.c
+++ b/security/security.c
@@ -2452,6 +2452,20 @@ int security_inode_removexattr(struct mnt_idmap *idmap,
 	return evm_inode_removexattr(idmap, dentry, name);
 }
 
+/**
+ * security_inode_post_removexattr() - Update the inode after a removexattr op
+ * @dentry: file
+ * @name: xattr name
+ *
+ * Update the inode after a successful removexattr operation.
+ */
+void security_inode_post_removexattr(struct dentry *dentry, const char *name)
+{
+	if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
+		return;
+	call_void_hook(inode_post_removexattr, dentry, name);
+}
+
 /**
  * security_inode_need_killpriv() - Check if security_inode_killpriv() required
  * @dentry: associated dentry
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 96+ messages in thread

* [PATCH v5 12/23] security: Introduce file_post_open hook
  2023-11-07 13:39 [PATCH v5 00/23] security: Move IMA and EVM to the LSM infrastructure Roberto Sassu
                   ` (10 preceding siblings ...)
  2023-11-07 13:40 ` [PATCH v5 11/23] security: Introduce inode_post_removexattr hook Roberto Sassu
@ 2023-11-07 13:40 ` Roberto Sassu
  2023-11-07 17:35   ` Casey Schaufler
  2023-11-07 13:40 ` [PATCH v5 13/23] security: Introduce file_pre_free_security hook Roberto Sassu
                   ` (11 subsequent siblings)
  23 siblings, 1 reply; 96+ messages in thread
From: Roberto Sassu @ 2023-11-07 13:40 UTC (permalink / raw)
  To: viro, brauner, chuck.lever, jlayton, neilb, kolga, Dai.Ngo, tom,
	paul, jmorris, serge, zohar, dmitry.kasatkin, dhowells, jarkko,
	stephen.smalley.work, eparis, casey, mic
  Cc: linux-fsdevel, linux-kernel, linux-nfs, linux-security-module,
	linux-integrity, keyrings, selinux, Roberto Sassu, Stefan Berger

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>
---
 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);
 	if (!error)
 		error = ima_file_check(file, op->acc_mode);
 	if (!error && do_truncate)
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index fbbea7498f02..b0c3f07a8bba 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -877,6 +877,12 @@ __nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type,
 		goto out;
 	}
 
+	host_err = security_file_post_open(file, may_flags);
+	if (host_err) {
+		fput(file);
+		goto out;
+	}
+
 	host_err = ima_file_check(file, may_flags);
 	if (host_err) {
 		fput(file);
diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
index 88452e45025c..4f6861fecacd 100644
--- a/include/linux/lsm_hook_defs.h
+++ b/include/linux/lsm_hook_defs.h
@@ -189,6 +189,7 @@ LSM_HOOK(int, 0, file_send_sigiotask, struct task_struct *tsk,
 	 struct fown_struct *fown, int sig)
 LSM_HOOK(int, 0, file_receive, struct file *file)
 LSM_HOOK(int, 0, file_open, struct file *file)
+LSM_HOOK(int, 0, file_post_open, struct file *file, int mask)
 LSM_HOOK(int, 0, file_truncate, struct file *file)
 LSM_HOOK(int, 0, task_alloc, struct task_struct *task,
 	 unsigned long clone_flags)
diff --git a/include/linux/security.h b/include/linux/security.h
index 922ea7709bae..c360458920b1 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -409,6 +409,7 @@ int security_file_send_sigiotask(struct task_struct *tsk,
 				 struct fown_struct *fown, int sig);
 int security_file_receive(struct file *file);
 int security_file_open(struct file *file);
+int security_file_post_open(struct file *file, int mask);
 int security_file_truncate(struct file *file);
 int security_task_alloc(struct task_struct *task, unsigned long clone_flags);
 void security_task_free(struct task_struct *task);
@@ -1065,6 +1066,11 @@ static inline int security_file_open(struct file *file)
 	return 0;
 }
 
+static inline int security_file_post_open(struct file *file, int mask)
+{
+	return 0;
+}
+
 static inline int security_file_truncate(struct file *file)
 {
 	return 0;
diff --git a/security/security.c b/security/security.c
index 8aa6e9f316dd..fe6a160afc35 100644
--- a/security/security.c
+++ b/security/security.c
@@ -2954,6 +2954,23 @@ int security_file_open(struct file *file)
 	return fsnotify_perm(file, MAY_OPEN);
 }
 
+/**
+ * security_file_post_open() - Evaluate a file after it has been opened
+ * @file: the file
+ * @mask: access mask
+ *
+ * Evaluate an opened file and the access mask requested with open(). The hook
+ * is useful for LSMs that require the file content to be available in order to
+ * make decisions.
+ *
+ * Return: Returns 0 if permission is granted.
+ */
+int security_file_post_open(struct file *file, int mask)
+{
+	return call_int_hook(file_post_open, 0, file, mask);
+}
+EXPORT_SYMBOL_GPL(security_file_post_open);
+
 /**
  * security_file_truncate() - Check if truncating a file is allowed
  * @file: file
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 96+ messages in thread

* [PATCH v5 13/23] security: Introduce file_pre_free_security hook
  2023-11-07 13:39 [PATCH v5 00/23] security: Move IMA and EVM to the LSM infrastructure Roberto Sassu
                   ` (11 preceding siblings ...)
  2023-11-07 13:40 ` [PATCH v5 12/23] security: Introduce file_post_open hook Roberto Sassu
@ 2023-11-07 13:40 ` Roberto Sassu
  2023-11-07 17:39   ` Casey Schaufler
  2023-11-16  4:33   ` Paul Moore
  2023-11-07 13:40 ` [PATCH v5 14/23] security: Introduce path_post_mknod hook Roberto Sassu
                   ` (10 subsequent siblings)
  23 siblings, 2 replies; 96+ messages in thread
From: Roberto Sassu @ 2023-11-07 13:40 UTC (permalink / raw)
  To: viro, brauner, chuck.lever, jlayton, neilb, kolga, Dai.Ngo, tom,
	paul, jmorris, serge, zohar, dmitry.kasatkin, dhowells, jarkko,
	stephen.smalley.work, eparis, casey, mic
  Cc: linux-fsdevel, linux-kernel, linux-nfs, linux-security-module,
	linux-integrity, keyrings, selinux, Roberto Sassu

From: Roberto Sassu <roberto.sassu@huawei.com>

In preparation for moving IMA and EVM to the LSM infrastructure, introduce
the file_pre_free_security 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.

LSMs could also take some action before the last reference of a file is
released.

The new hook cannot return an error and cannot cause the operation to be
reverted.

Signed-off-by: Roberto Sassu <roberto.sassu@huawei.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..64ed74555e64 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_pre_free(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 4f6861fecacd..5d0a09ead7ac 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_pre_free_security, 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 c360458920b1..a570213693d9 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_pre_free(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_mmap_file(struct file *file, unsigned long prot,
@@ -1006,6 +1007,9 @@ static inline int security_file_alloc(struct file *file)
 	return 0;
 }
 
+static inline void security_file_pre_free(struct file *file)
+{ }
+
 static inline void security_file_free(struct file *file)
 { }
 
diff --git a/security/security.c b/security/security.c
index fe6a160afc35..331a3e5efb62 100644
--- a/security/security.c
+++ b/security/security.c
@@ -2724,6 +2724,17 @@ int security_file_alloc(struct file *file)
 	return rc;
 }
 
+/**
+ * security_file_pre_free() - Perform actions before releasing the file ref
+ * @file: the file
+ *
+ * Perform actions before releasing the last reference to a file.
+ */
+void security_file_pre_free(struct file *file)
+{
+	call_void_hook(file_pre_free_security, file);
+}
+
 /**
  * security_file_free() - Free a file's LSM blob
  * @file: the file
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 96+ messages in thread

* [PATCH v5 14/23] security: Introduce path_post_mknod hook
  2023-11-07 13:39 [PATCH v5 00/23] security: Move IMA and EVM to the LSM infrastructure Roberto Sassu
                   ` (12 preceding siblings ...)
  2023-11-07 13:40 ` [PATCH v5 13/23] security: Introduce file_pre_free_security hook Roberto Sassu
@ 2023-11-07 13:40 ` Roberto Sassu
  2023-11-07 17:41   ` Casey Schaufler
  2023-11-07 13:40 ` [PATCH v5 15/23] security: Introduce inode_post_create_tmpfile hook Roberto Sassu
                   ` (9 subsequent siblings)
  23 siblings, 1 reply; 96+ messages in thread
From: Roberto Sassu @ 2023-11-07 13:40 UTC (permalink / raw)
  To: viro, brauner, chuck.lever, jlayton, neilb, kolga, Dai.Ngo, tom,
	paul, jmorris, serge, zohar, dmitry.kasatkin, dhowells, jarkko,
	stephen.smalley.work, eparis, casey, mic
  Cc: linux-fsdevel, linux-kernel, linux-nfs, linux-security-module,
	linux-integrity, keyrings, selinux, Roberto Sassu

From: Roberto Sassu <roberto.sassu@huawei.com>

In preparation for moving IMA and EVM to the LSM infrastructure, introduce
the path_post_mknod hook.

IMA-appraisal requires all existing files in policy to have a file
hash/signature stored in security.ima. An exception is made for empty files
created by mknod, by tagging them as new files.

LSMs could also take some action after files are created.

The new hook cannot return an error and cannot cause the operation to be
reverted.

Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
---
 fs/namei.c                    |  5 +++++
 include/linux/lsm_hook_defs.h |  2 ++
 include/linux/security.h      |  5 +++++
 security/security.c           | 14 ++++++++++++++
 4 files changed, 26 insertions(+)

diff --git a/fs/namei.c b/fs/namei.c
index fb93d3e13df6..b7f433720b1e 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -4047,6 +4047,11 @@ static int do_mknodat(int dfd, struct filename *name, umode_t mode,
 					  dentry, mode, 0);
 			break;
 	}
+
+	if (error)
+		goto out2;
+
+	security_path_post_mknod(idmap, dentry);
 out2:
 	done_path_create(&path, dentry);
 	if (retry_estale(error, lookup_flags)) {
diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
index 5d0a09ead7ac..e491951399f7 100644
--- a/include/linux/lsm_hook_defs.h
+++ b/include/linux/lsm_hook_defs.h
@@ -94,6 +94,8 @@ LSM_HOOK(int, 0, path_mkdir, const struct path *dir, struct dentry *dentry,
 LSM_HOOK(int, 0, path_rmdir, const struct path *dir, struct dentry *dentry)
 LSM_HOOK(int, 0, path_mknod, const struct path *dir, struct dentry *dentry,
 	 umode_t mode, unsigned int dev)
+LSM_HOOK(void, LSM_RET_VOID, path_post_mknod, struct mnt_idmap *idmap,
+	 struct dentry *dentry)
 LSM_HOOK(int, 0, path_truncate, const struct path *path)
 LSM_HOOK(int, 0, path_symlink, const struct path *dir, struct dentry *dentry,
 	 const char *old_name)
diff --git a/include/linux/security.h b/include/linux/security.h
index a570213693d9..68cbdc84506e 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -1884,6 +1884,7 @@ int security_path_mkdir(const struct path *dir, struct dentry *dentry, umode_t m
 int security_path_rmdir(const struct path *dir, struct dentry *dentry);
 int security_path_mknod(const struct path *dir, struct dentry *dentry, umode_t mode,
 			unsigned int dev);
+void security_path_post_mknod(struct mnt_idmap *idmap, struct dentry *dentry);
 int security_path_truncate(const struct path *path);
 int security_path_symlink(const struct path *dir, struct dentry *dentry,
 			  const char *old_name);
@@ -1918,6 +1919,10 @@ static inline int security_path_mknod(const struct path *dir, struct dentry *den
 	return 0;
 }
 
+static inline void security_path_post_mknod(struct mnt_idmap *idmap,
+					    struct dentry *dentry)
+{ }
+
 static inline int security_path_truncate(const struct path *path)
 {
 	return 0;
diff --git a/security/security.c b/security/security.c
index 331a3e5efb62..5eaf5f2aa5ea 100644
--- a/security/security.c
+++ b/security/security.c
@@ -1800,6 +1800,20 @@ int security_path_mknod(const struct path *dir, struct dentry *dentry,
 }
 EXPORT_SYMBOL(security_path_mknod);
 
+/**
+ * security_path_post_mknod() - Update inode security field after file creation
+ * @idmap: idmap of the mount
+ * @dentry: new file
+ *
+ * Update inode security field after a file has been created.
+ */
+void security_path_post_mknod(struct mnt_idmap *idmap, struct dentry *dentry)
+{
+	if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
+		return;
+	call_void_hook(path_post_mknod, idmap, dentry);
+}
+
 /**
  * security_path_mkdir() - Check if creating a new directory is allowed
  * @dir: parent directory
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 96+ messages in thread

* [PATCH v5 15/23] security: Introduce inode_post_create_tmpfile hook
  2023-11-07 13:39 [PATCH v5 00/23] security: Move IMA and EVM to the LSM infrastructure Roberto Sassu
                   ` (13 preceding siblings ...)
  2023-11-07 13:40 ` [PATCH v5 14/23] security: Introduce path_post_mknod hook Roberto Sassu
@ 2023-11-07 13:40 ` Roberto Sassu
  2023-11-07 17:42   ` Casey Schaufler
  2023-11-16  4:33   ` Paul Moore
  2023-11-07 13:40 ` [PATCH v5 16/23] security: Introduce inode_post_set_acl hook Roberto Sassu
                   ` (8 subsequent siblings)
  23 siblings, 2 replies; 96+ messages in thread
From: Roberto Sassu @ 2023-11-07 13:40 UTC (permalink / raw)
  To: viro, brauner, chuck.lever, jlayton, neilb, kolga, Dai.Ngo, tom,
	paul, jmorris, serge, zohar, dmitry.kasatkin, dhowells, jarkko,
	stephen.smalley.work, eparis, casey, mic
  Cc: linux-fsdevel, linux-kernel, linux-nfs, linux-security-module,
	linux-integrity, keyrings, selinux, Roberto Sassu

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>
---
 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 e491951399f7..ec5319ec2e85 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 68cbdc84506e..0c85f0337a9e 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);
@@ -809,6 +811,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 5eaf5f2aa5ea..ca650c285fd9 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
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 96+ messages in thread

* [PATCH v5 16/23] security: Introduce inode_post_set_acl hook
  2023-11-07 13:39 [PATCH v5 00/23] security: Move IMA and EVM to the LSM infrastructure Roberto Sassu
                   ` (14 preceding siblings ...)
  2023-11-07 13:40 ` [PATCH v5 15/23] security: Introduce inode_post_create_tmpfile hook Roberto Sassu
@ 2023-11-07 13:40 ` Roberto Sassu
  2023-11-07 17:44   ` Casey Schaufler
  2023-11-16  4:33   ` Paul Moore
  2023-11-07 13:40 ` [PATCH v5 17/23] security: Introduce inode_post_remove_acl hook Roberto Sassu
                   ` (7 subsequent siblings)
  23 siblings, 2 replies; 96+ messages in thread
From: Roberto Sassu @ 2023-11-07 13:40 UTC (permalink / raw)
  To: viro, brauner, chuck.lever, jlayton, neilb, kolga, Dai.Ngo, tom,
	paul, jmorris, serge, zohar, dmitry.kasatkin, dhowells, jarkko,
	stephen.smalley.work, eparis, casey, mic
  Cc: linux-fsdevel, linux-kernel, linux-nfs, linux-security-module,
	linux-integrity, keyrings, selinux, Roberto Sassu, Stefan Berger

From: Roberto Sassu <roberto.sassu@huawei.com>

In preparation for moving IMA and EVM to the LSM infrastructure, introduce
the inode_post_set_acl hook.

At inode_set_acl hook, EVM verifies the file's existing HMAC value. At
inode_post_set_acl, EVM re-calculates the file's HMAC based on the modified
POSIX ACL and other file metadata.

Other LSMs could similarly take some action after successful POSIX ACL
change.

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/posix_acl.c                |  1 +
 include/linux/lsm_hook_defs.h |  2 ++
 include/linux/security.h      |  7 +++++++
 security/security.c           | 17 +++++++++++++++++
 4 files changed, 27 insertions(+)

diff --git a/fs/posix_acl.c b/fs/posix_acl.c
index a05fe94970ce..58e3c1e2fbbc 100644
--- a/fs/posix_acl.c
+++ b/fs/posix_acl.c
@@ -1137,6 +1137,7 @@ int vfs_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
 		error = -EIO;
 	if (!error) {
 		fsnotify_xattr(dentry);
+		security_inode_post_set_acl(dentry, acl_name, kacl);
 		evm_inode_post_set_acl(dentry, acl_name, kacl);
 	}
 
diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
index ec5319ec2e85..6a671616196f 100644
--- a/include/linux/lsm_hook_defs.h
+++ b/include/linux/lsm_hook_defs.h
@@ -157,6 +157,8 @@ LSM_HOOK(void, LSM_RET_VOID, inode_post_removexattr, struct dentry *dentry,
 	 const char *name)
 LSM_HOOK(int, 0, inode_set_acl, struct mnt_idmap *idmap,
 	 struct dentry *dentry, const char *acl_name, struct posix_acl *kacl)
+LSM_HOOK(void, LSM_RET_VOID, inode_post_set_acl, struct dentry *dentry,
+	 const char *acl_name, struct posix_acl *kacl)
 LSM_HOOK(int, 0, inode_get_acl, struct mnt_idmap *idmap,
 	 struct dentry *dentry, const char *acl_name)
 LSM_HOOK(int, 0, inode_remove_acl, struct mnt_idmap *idmap,
diff --git a/include/linux/security.h b/include/linux/security.h
index 0c85f0337a9e..d71d0b08e9fe 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -372,6 +372,8 @@ int security_inode_setxattr(struct mnt_idmap *idmap,
 int security_inode_set_acl(struct mnt_idmap *idmap,
 			   struct dentry *dentry, const char *acl_name,
 			   struct posix_acl *kacl);
+void security_inode_post_set_acl(struct dentry *dentry, const char *acl_name,
+				 struct posix_acl *kacl);
 int security_inode_get_acl(struct mnt_idmap *idmap,
 			   struct dentry *dentry, const char *acl_name);
 int security_inode_remove_acl(struct mnt_idmap *idmap,
@@ -913,6 +915,11 @@ static inline int security_inode_set_acl(struct mnt_idmap *idmap,
 	return 0;
 }
 
+static inline void security_inode_post_set_acl(struct dentry *dentry,
+					       const char *acl_name,
+					       struct posix_acl *kacl)
+{ }
+
 static inline int security_inode_get_acl(struct mnt_idmap *idmap,
 					 struct dentry *dentry,
 					 const char *acl_name)
diff --git a/security/security.c b/security/security.c
index ca650c285fd9..d2dbea54a63a 100644
--- a/security/security.c
+++ b/security/security.c
@@ -2350,6 +2350,23 @@ int security_inode_set_acl(struct mnt_idmap *idmap,
 	return evm_inode_set_acl(idmap, dentry, acl_name, kacl);
 }
 
+/**
+ * security_inode_post_set_acl() - Update inode security from posix acls set
+ * @dentry: file
+ * @acl_name: acl name
+ * @kacl: acl struct
+ *
+ * Update inode security data after successfully setting posix acls on @dentry.
+ * The posix acls in @kacl are identified by @acl_name.
+ */
+void security_inode_post_set_acl(struct dentry *dentry, const char *acl_name,
+				 struct posix_acl *kacl)
+{
+	if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
+		return;
+	call_void_hook(inode_post_set_acl, dentry, acl_name, kacl);
+}
+
 /**
  * security_inode_get_acl() - Check if reading posix acls is allowed
  * @idmap: idmap of the mount
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 96+ messages in thread

* [PATCH v5 17/23] security: Introduce inode_post_remove_acl hook
  2023-11-07 13:39 [PATCH v5 00/23] security: Move IMA and EVM to the LSM infrastructure Roberto Sassu
                   ` (15 preceding siblings ...)
  2023-11-07 13:40 ` [PATCH v5 16/23] security: Introduce inode_post_set_acl hook Roberto Sassu
@ 2023-11-07 13:40 ` Roberto Sassu
  2023-11-07 17:45   ` Casey Schaufler
  2023-11-16  4:33   ` Paul Moore
  2023-11-07 13:40 ` [PATCH v5 18/23] security: Introduce key_post_create_or_update hook Roberto Sassu
                   ` (6 subsequent siblings)
  23 siblings, 2 replies; 96+ messages in thread
From: Roberto Sassu @ 2023-11-07 13:40 UTC (permalink / raw)
  To: viro, brauner, chuck.lever, jlayton, neilb, kolga, Dai.Ngo, tom,
	paul, jmorris, serge, zohar, dmitry.kasatkin, dhowells, jarkko,
	stephen.smalley.work, eparis, casey, mic
  Cc: linux-fsdevel, linux-kernel, linux-nfs, linux-security-module,
	linux-integrity, keyrings, selinux, Roberto Sassu, Stefan Berger

From: Roberto Sassu <roberto.sassu@huawei.com>

In preparation for moving IMA and EVM to the LSM infrastructure, introduce
the inode_post_remove_acl hook.

At inode_remove_acl hook, EVM verifies the file's existing HMAC value. At
inode_post_remove_acl, EVM re-calculates the file's HMAC with the passed
POSIX ACL removed and other file metadata.

Other LSMs could similarly take some action after successful POSIX ACL
removal.

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/posix_acl.c                |  1 +
 include/linux/lsm_hook_defs.h |  2 ++
 include/linux/security.h      |  8 ++++++++
 security/security.c           | 17 +++++++++++++++++
 4 files changed, 28 insertions(+)

diff --git a/fs/posix_acl.c b/fs/posix_acl.c
index 58e3c1e2fbbc..e3fbe1a9f3f5 100644
--- a/fs/posix_acl.c
+++ b/fs/posix_acl.c
@@ -1246,6 +1246,7 @@ int vfs_remove_acl(struct mnt_idmap *idmap, struct dentry *dentry,
 		error = -EIO;
 	if (!error) {
 		fsnotify_xattr(dentry);
+		security_inode_post_remove_acl(idmap, dentry, acl_name);
 		evm_inode_post_remove_acl(idmap, dentry, acl_name);
 	}
 
diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
index 6a671616196f..2bf128f7cbae 100644
--- a/include/linux/lsm_hook_defs.h
+++ b/include/linux/lsm_hook_defs.h
@@ -163,6 +163,8 @@ LSM_HOOK(int, 0, inode_get_acl, struct mnt_idmap *idmap,
 	 struct dentry *dentry, const char *acl_name)
 LSM_HOOK(int, 0, inode_remove_acl, struct mnt_idmap *idmap,
 	 struct dentry *dentry, const char *acl_name)
+LSM_HOOK(void, LSM_RET_VOID, inode_post_remove_acl, struct mnt_idmap *idmap,
+	 struct dentry *dentry, const char *acl_name)
 LSM_HOOK(int, 0, inode_need_killpriv, struct dentry *dentry)
 LSM_HOOK(int, 0, inode_killpriv, struct mnt_idmap *idmap,
 	 struct dentry *dentry)
diff --git a/include/linux/security.h b/include/linux/security.h
index d71d0b08e9fe..7cd7126f6545 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -378,6 +378,9 @@ int security_inode_get_acl(struct mnt_idmap *idmap,
 			   struct dentry *dentry, const char *acl_name);
 int security_inode_remove_acl(struct mnt_idmap *idmap,
 			      struct dentry *dentry, const char *acl_name);
+void security_inode_post_remove_acl(struct mnt_idmap *idmap,
+				    struct dentry *dentry,
+				    const char *acl_name);
 void security_inode_post_setxattr(struct dentry *dentry, const char *name,
 				  const void *value, size_t size, int flags);
 int security_inode_getxattr(struct dentry *dentry, const char *name);
@@ -934,6 +937,11 @@ static inline int security_inode_remove_acl(struct mnt_idmap *idmap,
 	return 0;
 }
 
+static inline void security_inode_post_remove_acl(struct mnt_idmap *idmap,
+						  struct dentry *dentry,
+						  const char *acl_name)
+{ }
+
 static inline void security_inode_post_setxattr(struct dentry *dentry,
 		const char *name, const void *value, size_t size, int flags)
 { }
diff --git a/security/security.c b/security/security.c
index d2dbea54a63a..6eb7c9cff1e5 100644
--- a/security/security.c
+++ b/security/security.c
@@ -2413,6 +2413,23 @@ int security_inode_remove_acl(struct mnt_idmap *idmap,
 	return evm_inode_remove_acl(idmap, dentry, acl_name);
 }
 
+/**
+ * security_inode_post_remove_acl() - Update inode security after rm posix acls
+ * @idmap: idmap of the mount
+ * @dentry: file
+ * @acl_name: acl name
+ *
+ * Update inode security data after successfully removing posix acls on
+ * @dentry in @idmap. The posix acls are identified by @acl_name.
+ */
+void security_inode_post_remove_acl(struct mnt_idmap *idmap,
+				    struct dentry *dentry, const char *acl_name)
+{
+	if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
+		return;
+	call_void_hook(inode_post_remove_acl, idmap, dentry, acl_name);
+}
+
 /**
  * security_inode_post_setxattr() - Update the inode after a setxattr operation
  * @dentry: file
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 96+ messages in thread

* [PATCH v5 18/23] security: Introduce key_post_create_or_update hook
  2023-11-07 13:39 [PATCH v5 00/23] security: Move IMA and EVM to the LSM infrastructure Roberto Sassu
                   ` (16 preceding siblings ...)
  2023-11-07 13:40 ` [PATCH v5 17/23] security: Introduce inode_post_remove_acl hook Roberto Sassu
@ 2023-11-07 13:40 ` Roberto Sassu
  2023-11-07 17:47   ` Casey Schaufler
  2023-11-07 13:40 ` [PATCH v5 19/23] ima: Move to LSM infrastructure Roberto Sassu
                   ` (5 subsequent siblings)
  23 siblings, 1 reply; 96+ messages in thread
From: Roberto Sassu @ 2023-11-07 13:40 UTC (permalink / raw)
  To: viro, brauner, chuck.lever, jlayton, neilb, kolga, Dai.Ngo, tom,
	paul, jmorris, serge, zohar, dmitry.kasatkin, dhowells, jarkko,
	stephen.smalley.work, eparis, casey, mic
  Cc: linux-fsdevel, linux-kernel, linux-nfs, linux-security-module,
	linux-integrity, keyrings, selinux, Roberto Sassu, Stefan Berger

From: Roberto Sassu <roberto.sassu@huawei.com>

In preparation for moving IMA and EVM to the LSM infrastructure, introduce
the key_post_create_or_update hook.

Depending on policy, IMA measures the key content after creation or update,
so that remote verifiers are aware of the operation.

Other LSMs could similarly take some action after successful key creation
or update.

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>
---
 include/linux/lsm_hook_defs.h |  3 +++
 include/linux/security.h      | 11 +++++++++++
 security/keys/key.c           |  7 ++++++-
 security/security.c           | 19 +++++++++++++++++++
 4 files changed, 39 insertions(+), 1 deletion(-)

diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
index 2bf128f7cbae..ec5d160c32ba 100644
--- a/include/linux/lsm_hook_defs.h
+++ b/include/linux/lsm_hook_defs.h
@@ -403,6 +403,9 @@ LSM_HOOK(void, LSM_RET_VOID, key_free, struct key *key)
 LSM_HOOK(int, 0, key_permission, key_ref_t key_ref, const struct cred *cred,
 	 enum key_need_perm need_perm)
 LSM_HOOK(int, 0, key_getsecurity, struct key *key, char **buffer)
+LSM_HOOK(void, LSM_RET_VOID, key_post_create_or_update, struct key *keyring,
+	 struct key *key, const void *payload, size_t payload_len,
+	 unsigned long flags, bool create)
 #endif /* CONFIG_KEYS */
 
 #ifdef CONFIG_AUDIT
diff --git a/include/linux/security.h b/include/linux/security.h
index 7cd7126f6545..1cd84970ab4c 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -1995,6 +1995,9 @@ void security_key_free(struct key *key);
 int security_key_permission(key_ref_t key_ref, const struct cred *cred,
 			    enum key_need_perm need_perm);
 int security_key_getsecurity(struct key *key, char **_buffer);
+void security_key_post_create_or_update(struct key *keyring, struct key *key,
+					const void *payload, size_t payload_len,
+					unsigned long flags, bool create);
 
 #else
 
@@ -2022,6 +2025,14 @@ static inline int security_key_getsecurity(struct key *key, char **_buffer)
 	return 0;
 }
 
+static inline void security_key_post_create_or_update(struct key *keyring,
+						      struct key *key,
+						      const void *payload,
+						      size_t payload_len,
+						      unsigned long flags,
+						      bool create)
+{ }
+
 #endif
 #endif /* CONFIG_KEYS */
 
diff --git a/security/keys/key.c b/security/keys/key.c
index 0260a1902922..f75fe66c2f03 100644
--- a/security/keys/key.c
+++ b/security/keys/key.c
@@ -935,6 +935,8 @@ static key_ref_t __key_create_or_update(key_ref_t keyring_ref,
 		goto error_link_end;
 	}
 
+	security_key_post_create_or_update(keyring, key, payload, plen, flags,
+					   true);
 	ima_post_key_create_or_update(keyring, key, payload, plen,
 				      flags, true);
 
@@ -968,10 +970,13 @@ static key_ref_t __key_create_or_update(key_ref_t keyring_ref,
 
 	key_ref = __key_update(key_ref, &prep);
 
-	if (!IS_ERR(key_ref))
+	if (!IS_ERR(key_ref)) {
+		security_key_post_create_or_update(keyring, key, payload, plen,
+						   flags, false);
 		ima_post_key_create_or_update(keyring, key,
 					      payload, plen,
 					      flags, false);
+	}
 
 	goto error_free_prep;
 }
diff --git a/security/security.c b/security/security.c
index 6eb7c9cff1e5..859189722ab8 100644
--- a/security/security.c
+++ b/security/security.c
@@ -5406,6 +5406,25 @@ int security_key_getsecurity(struct key *key, char **buffer)
 	*buffer = NULL;
 	return call_int_hook(key_getsecurity, 0, key, buffer);
 }
+
+/**
+ * security_key_post_create_or_update() - Notification of key create or update
+ * @keyring: keyring to which the key is linked to
+ * @key: created or updated key
+ * @payload: data used to instantiate or update the key
+ * @payload_len: length of payload
+ * @flags: key flags
+ * @create: flag indicating whether the key was created or updated
+ *
+ * Notify the caller of a key creation or update.
+ */
+void security_key_post_create_or_update(struct key *keyring, struct key *key,
+					const void *payload, size_t payload_len,
+					unsigned long flags, bool create)
+{
+	call_void_hook(key_post_create_or_update, keyring, key, payload,
+		       payload_len, flags, create);
+}
 #endif	/* CONFIG_KEYS */
 
 #ifdef CONFIG_AUDIT
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 96+ messages in thread

* [PATCH v5 19/23] ima: Move to LSM infrastructure
  2023-11-07 13:39 [PATCH v5 00/23] security: Move IMA and EVM to the LSM infrastructure Roberto Sassu
                   ` (17 preceding siblings ...)
  2023-11-07 13:40 ` [PATCH v5 18/23] security: Introduce key_post_create_or_update hook Roberto Sassu
@ 2023-11-07 13:40 ` Roberto Sassu
  2023-11-07 17:52   ` Casey Schaufler
  2023-11-07 13:40 ` [PATCH v5 20/23] ima: Move IMA-Appraisal " Roberto Sassu
                   ` (4 subsequent siblings)
  23 siblings, 1 reply; 96+ messages in thread
From: Roberto Sassu @ 2023-11-07 13:40 UTC (permalink / raw)
  To: viro, brauner, chuck.lever, jlayton, neilb, kolga, Dai.Ngo, tom,
	paul, jmorris, serge, zohar, dmitry.kasatkin, dhowells, jarkko,
	stephen.smalley.work, eparis, casey, mic
  Cc: linux-fsdevel, linux-kernel, linux-nfs, linux-security-module,
	linux-integrity, keyrings, selinux, Roberto Sassu

From: Roberto Sassu <roberto.sassu@huawei.com>

Move hardcoded IMA function calls (not appraisal-specific functions) from
various places in the kernel to the LSM infrastructure, by introducing a
new LSM named 'ima' (at the end of the LSM list and always enabled like
'integrity').

Make moved functions as static (except ima_post_key_create_or_update(),
which is not in ima_main.c), and register them as implementation of the
respective hooks in the new function init_ima_lsm(). Conditionally register
ima_post_path_mknod() if CONFIG_SECURITY_PATH is enabled, otherwise the
path_post_mknod hook won't be available.

Call init_ima_lsm() from integrity_lsm_init() (renamed from
integrity_iintcache_init()), the init method of the 'integrity' LSM, to
make sure that the integrity subsystem is ready at the time IMA hooks are
registered, and to keep the original ordering of IMA and EVM functions as
when they were hardcoded.

Finally, introduce ima_get_lsm_id() to pass the IMA LSM ID back to the
'integrity' LSM for registration of the integrity-specific hooks.

Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
Acked-by: Chuck Lever <chuck.lever@oracle.com>
---
 fs/file_table.c                   |  2 -
 fs/namei.c                        |  6 --
 fs/nfsd/vfs.c                     |  7 ---
 fs/open.c                         |  1 -
 include/linux/ima.h               | 94 -------------------------------
 include/uapi/linux/lsm.h          |  1 +
 security/integrity/iint.c         | 11 +++-
 security/integrity/ima/ima.h      |  6 ++
 security/integrity/ima/ima_main.c | 93 +++++++++++++++++++++++-------
 security/integrity/integrity.h    | 16 ++++++
 security/keys/key.c               |  9 +--
 security/security.c               | 56 ++++--------------
 12 files changed, 116 insertions(+), 186 deletions(-)

diff --git a/fs/file_table.c b/fs/file_table.c
index 64ed74555e64..e64b0057fa72 100644
--- a/fs/file_table.c
+++ b/fs/file_table.c
@@ -26,7 +26,6 @@
 #include <linux/percpu_counter.h>
 #include <linux/percpu.h>
 #include <linux/task_work.h>
-#include <linux/ima.h>
 #include <linux/swap.h>
 #include <linux/kmemleak.h>
 
@@ -386,7 +385,6 @@ static void __fput(struct file *file)
 	locks_remove_file(file);
 
 	security_file_pre_free(file);
-	ima_file_free(file);
 	if (unlikely(file->f_flags & FASYNC)) {
 		if (file->f_op->fasync)
 			file->f_op->fasync(-1, file, 0);
diff --git a/fs/namei.c b/fs/namei.c
index adb3ab27951a..37cc0988308f 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -27,7 +27,6 @@
 #include <linux/fsnotify.h>
 #include <linux/personality.h>
 #include <linux/security.h>
-#include <linux/ima.h>
 #include <linux/syscalls.h>
 #include <linux/mount.h>
 #include <linux/audit.h>
@@ -3622,8 +3621,6 @@ static int do_open(struct nameidata *nd,
 		error = vfs_open(&nd->path, file);
 	if (!error)
 		error = security_file_post_open(file, op->acc_mode);
-	if (!error)
-		error = ima_file_check(file, op->acc_mode);
 	if (!error && do_truncate)
 		error = handle_truncate(idmap, file);
 	if (unlikely(error > 0)) {
@@ -3687,7 +3684,6 @@ static int vfs_tmpfile(struct mnt_idmap *idmap,
 		spin_unlock(&inode->i_lock);
 	}
 	security_inode_post_create_tmpfile(idmap, inode);
-	ima_post_create_tmpfile(idmap, inode);
 	return 0;
 }
 
@@ -4036,8 +4032,6 @@ static int do_mknodat(int dfd, struct filename *name, umode_t mode,
 		case 0: case S_IFREG:
 			error = vfs_create(idmap, path.dentry->d_inode,
 					   dentry, mode, true);
-			if (!error)
-				ima_post_path_mknod(idmap, dentry);
 			break;
 		case S_IFCHR: case S_IFBLK:
 			error = vfs_mknod(idmap, path.dentry->d_inode,
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index b0c3f07a8bba..e491392a1243 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -25,7 +25,6 @@
 #include <linux/posix_acl_xattr.h>
 #include <linux/xattr.h>
 #include <linux/jhash.h>
-#include <linux/ima.h>
 #include <linux/pagemap.h>
 #include <linux/slab.h>
 #include <linux/uaccess.h>
@@ -883,12 +882,6 @@ __nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type,
 		goto out;
 	}
 
-	host_err = ima_file_check(file, may_flags);
-	if (host_err) {
-		fput(file);
-		goto out;
-	}
-
 	if (may_flags & NFSD_MAY_64BIT_COOKIE)
 		file->f_mode |= FMODE_64BITHASH;
 	else
diff --git a/fs/open.c b/fs/open.c
index 02dc608d40d8..c8bb9bd5259f 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -29,7 +29,6 @@
 #include <linux/audit.h>
 #include <linux/falloc.h>
 #include <linux/fs_struct.h>
-#include <linux/ima.h>
 #include <linux/dnotify.h>
 #include <linux/compat.h>
 #include <linux/mnt_idmapping.h>
diff --git a/include/linux/ima.h b/include/linux/ima.h
index 31ef6c3c3207..23ae24b60ecf 100644
--- a/include/linux/ima.h
+++ b/include/linux/ima.h
@@ -16,24 +16,6 @@ struct linux_binprm;
 
 #ifdef CONFIG_IMA
 extern enum hash_algo ima_get_current_hash_algo(void);
-extern int ima_bprm_check(struct linux_binprm *bprm);
-extern int ima_file_check(struct file *file, int mask);
-extern void ima_post_create_tmpfile(struct mnt_idmap *idmap,
-				    struct inode *inode);
-extern void ima_file_free(struct file *file);
-extern int ima_file_mmap(struct file *file, unsigned long reqprot,
-			 unsigned long prot, unsigned long flags);
-extern int ima_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot,
-			     unsigned long prot);
-extern int ima_load_data(enum kernel_load_data_id id, bool contents);
-extern int ima_post_load_data(char *buf, loff_t size,
-			      enum kernel_load_data_id id, char *description);
-extern int ima_read_file(struct file *file, enum kernel_read_file_id id,
-			 bool contents);
-extern int ima_post_read_file(struct file *file, char *buf, loff_t size,
-			      enum kernel_read_file_id id);
-extern void ima_post_path_mknod(struct mnt_idmap *idmap,
-				struct dentry *dentry);
 extern int ima_file_hash(struct file *file, char *buf, size_t buf_size);
 extern int ima_inode_hash(struct inode *inode, char *buf, size_t buf_size);
 extern void ima_kexec_cmdline(int kernel_fd, const void *buf, int size);
@@ -58,68 +40,6 @@ static inline enum hash_algo ima_get_current_hash_algo(void)
 	return HASH_ALGO__LAST;
 }
 
-static inline int ima_bprm_check(struct linux_binprm *bprm)
-{
-	return 0;
-}
-
-static inline int ima_file_check(struct file *file, int mask)
-{
-	return 0;
-}
-
-static inline void ima_post_create_tmpfile(struct mnt_idmap *idmap,
-					   struct inode *inode)
-{
-}
-
-static inline void ima_file_free(struct file *file)
-{
-	return;
-}
-
-static inline int ima_file_mmap(struct file *file, unsigned long reqprot,
-				unsigned long prot, unsigned long flags)
-{
-	return 0;
-}
-
-static inline int ima_file_mprotect(struct vm_area_struct *vma,
-				    unsigned long reqprot, unsigned long prot)
-{
-	return 0;
-}
-
-static inline int ima_load_data(enum kernel_load_data_id id, bool contents)
-{
-	return 0;
-}
-
-static inline int ima_post_load_data(char *buf, loff_t size,
-				     enum kernel_load_data_id id,
-				     char *description)
-{
-	return 0;
-}
-
-static inline int ima_read_file(struct file *file, enum kernel_read_file_id id,
-				bool contents)
-{
-	return 0;
-}
-
-static inline int ima_post_read_file(struct file *file, char *buf, loff_t size,
-				     enum kernel_read_file_id id)
-{
-	return 0;
-}
-
-static inline void ima_post_path_mknod(struct mnt_idmap *idmap,
-				       struct dentry *dentry)
-{
-	return;
-}
-
 static inline int ima_file_hash(struct file *file, char *buf, size_t buf_size)
 {
 	return -EOPNOTSUPP;
@@ -170,20 +90,6 @@ static inline void ima_add_kexec_buffer(struct kimage *image)
 {}
 #endif
 
-#ifdef CONFIG_IMA_MEASURE_ASYMMETRIC_KEYS
-extern void ima_post_key_create_or_update(struct key *keyring,
-					  struct key *key,
-					  const void *payload, size_t plen,
-					  unsigned long flags, bool create);
-#else
-static inline void ima_post_key_create_or_update(struct key *keyring,
-						 struct key *key,
-						 const void *payload,
-						 size_t plen,
-						 unsigned long flags,
-						 bool create) {}
-#endif  /* CONFIG_IMA_MEASURE_ASYMMETRIC_KEYS */
-
 #ifdef CONFIG_IMA_APPRAISE
 extern bool is_ima_appraise_enabled(void);
 extern void ima_inode_post_setattr(struct mnt_idmap *idmap,
diff --git a/include/uapi/linux/lsm.h b/include/uapi/linux/lsm.h
index f0386880a78e..ee7d034255a9 100644
--- a/include/uapi/linux/lsm.h
+++ b/include/uapi/linux/lsm.h
@@ -61,6 +61,7 @@ struct lsm_ctx {
 #define LSM_ID_LOCKDOWN		108
 #define LSM_ID_BPF		109
 #define LSM_ID_LANDLOCK		110
+#define LSM_ID_IMA		111
 
 /*
  * LSM_ATTR_XXX definitions identify different LSM attributes
diff --git a/security/integrity/iint.c b/security/integrity/iint.c
index d4419a2a1e24..87f2c0d69f78 100644
--- a/security/integrity/iint.c
+++ b/security/integrity/iint.c
@@ -193,20 +193,25 @@ static void iint_init_once(void *foo)
 	memset(iint, 0, sizeof(*iint));
 }
 
-static int __init integrity_iintcache_init(void)
+static int __init integrity_lsm_init(void)
 {
 	iint_cache =
 	    kmem_cache_create("iint_cache", sizeof(struct integrity_iint_cache),
 			      0, SLAB_PANIC, iint_init_once);
+	init_ima_lsm();
 	return 0;
 }
+
+/*
+ * Keep it until IMA and EVM can use disjoint integrity metadata, and their
+ * initialization order can be swapped without change in their behavior.
+ */
 DEFINE_LSM(integrity) = {
 	.name = "integrity",
-	.init = integrity_iintcache_init,
+	.init = integrity_lsm_init,
 	.order = LSM_ORDER_LAST,
 };
 
-
 /*
  * integrity_kernel_read - read data from the file
  *
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index c29db699c996..c0412100023e 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -127,6 +127,12 @@ void ima_load_kexec_buffer(void);
 static inline void ima_load_kexec_buffer(void) {}
 #endif /* CONFIG_HAVE_IMA_KEXEC */
 
+#ifdef CONFIG_IMA_MEASURE_ASYMMETRIC_KEYS
+void ima_post_key_create_or_update(struct key *keyring, struct key *key,
+				   const void *payload, size_t plen,
+				   unsigned long flags, bool create);
+#endif
+
 /*
  * The default binary_runtime_measurements list format is defined as the
  * platform native format.  The canonical format is defined as little-endian.
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index 02021ee467d3..f923ff5c6524 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -189,7 +189,7 @@ static void ima_check_last_writer(struct integrity_iint_cache *iint,
  *
  * Flag files that changed, based on i_version
  */
-void ima_file_free(struct file *file)
+static void ima_file_free(struct file *file)
 {
 	struct inode *inode = file_inode(file);
 	struct integrity_iint_cache *iint;
@@ -427,8 +427,8 @@ static int process_measurement(struct file *file, const struct cred *cred,
  * On success return 0.  On integrity appraisal error, assuming the file
  * is in policy and IMA-appraisal is in enforcing mode, return -EACCES.
  */
-int ima_file_mmap(struct file *file, unsigned long reqprot,
-		  unsigned long prot, unsigned long flags)
+static int ima_file_mmap(struct file *file, unsigned long reqprot,
+			 unsigned long prot, unsigned long flags)
 {
 	u32 secid;
 	int ret;
@@ -466,8 +466,8 @@ int ima_file_mmap(struct file *file, unsigned long reqprot,
  *
  * On mprotect change success, return 0.  On failure, return -EACESS.
  */
-int ima_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot,
-		      unsigned long prot)
+static int ima_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot,
+			     unsigned long prot)
 {
 	struct ima_template_desc *template = NULL;
 	struct file *file;
@@ -525,7 +525,7 @@ int ima_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot,
  * On success return 0.  On integrity appraisal error, assuming the file
  * is in policy and IMA-appraisal is in enforcing mode, return -EACCES.
  */
-int ima_bprm_check(struct linux_binprm *bprm)
+static int ima_bprm_check(struct linux_binprm *bprm)
 {
 	int ret;
 	u32 secid;
@@ -551,7 +551,7 @@ int ima_bprm_check(struct linux_binprm *bprm)
  * On success return 0.  On integrity appraisal error, assuming the file
  * is in policy and IMA-appraisal is in enforcing mode, return -EACCES.
  */
-int ima_file_check(struct file *file, int mask)
+static int ima_file_check(struct file *file, int mask)
 {
 	u32 secid;
 
@@ -560,7 +560,6 @@ int ima_file_check(struct file *file, int mask)
 				   mask & (MAY_READ | MAY_WRITE | MAY_EXEC |
 					   MAY_APPEND), FILE_CHECK);
 }
-EXPORT_SYMBOL_GPL(ima_file_check);
 
 static int __ima_inode_hash(struct inode *inode, struct file *file, char *buf,
 			    size_t buf_size)
@@ -685,8 +684,9 @@ EXPORT_SYMBOL_GPL(ima_inode_hash);
  * Skip calling process_measurement(), but indicate which newly, created
  * tmpfiles are in policy.
  */
-void ima_post_create_tmpfile(struct mnt_idmap *idmap,
-			     struct inode *inode)
+static void ima_post_create_tmpfile(struct mnt_idmap *idmap,
+				    struct inode *inode)
+
 {
 	struct integrity_iint_cache *iint;
 	int must_appraise;
@@ -717,8 +717,8 @@ void ima_post_create_tmpfile(struct mnt_idmap *idmap,
  * Mark files created via the mknodat syscall as new, so that the
  * file data can be written later.
  */
-void ima_post_path_mknod(struct mnt_idmap *idmap,
-			 struct dentry *dentry)
+static void __maybe_unused
+ima_post_path_mknod(struct mnt_idmap *idmap, struct dentry *dentry)
 {
 	struct integrity_iint_cache *iint;
 	struct inode *inode = dentry->d_inode;
@@ -753,8 +753,8 @@ void ima_post_path_mknod(struct mnt_idmap *idmap,
  *
  * For permission return 0, otherwise return -EACCES.
  */
-int ima_read_file(struct file *file, enum kernel_read_file_id read_id,
-		  bool contents)
+static int ima_read_file(struct file *file, enum kernel_read_file_id read_id,
+			 bool contents)
 {
 	enum ima_hooks func;
 	u32 secid;
@@ -803,8 +803,8 @@ const int read_idmap[READING_MAX_ID] = {
  * On success return 0.  On integrity appraisal error, assuming the file
  * is in policy and IMA-appraisal is in enforcing mode, return -EACCES.
  */
-int ima_post_read_file(struct file *file, char *buf, loff_t size,
-		       enum kernel_read_file_id read_id)
+static int ima_post_read_file(struct file *file, char *buf, loff_t size,
+			      enum kernel_read_file_id read_id)
 {
 	enum ima_hooks func;
 	u32 secid;
@@ -837,7 +837,7 @@ int ima_post_read_file(struct file *file, char *buf, loff_t size,
  *
  * For permission return 0, otherwise return -EACCES.
  */
-int ima_load_data(enum kernel_load_data_id id, bool contents)
+static int ima_load_data(enum kernel_load_data_id id, bool contents)
 {
 	bool ima_enforce, sig_enforce;
 
@@ -891,9 +891,9 @@ int ima_load_data(enum kernel_load_data_id id, bool contents)
  * On success return 0.  On integrity appraisal error, assuming the file
  * is in policy and IMA-appraisal is in enforcing mode, return -EACCES.
  */
-int ima_post_load_data(char *buf, loff_t size,
-		       enum kernel_load_data_id load_id,
-		       char *description)
+static int ima_post_load_data(char *buf, loff_t size,
+			      enum kernel_load_data_id load_id,
+			      char *description)
 {
 	if (load_id == LOADING_FIRMWARE) {
 		if ((ima_appraise & IMA_APPRAISE_FIRMWARE) &&
@@ -1122,4 +1122,57 @@ static int __init init_ima(void)
 	return error;
 }
 
+static struct security_hook_list ima_hooks[] __ro_after_init = {
+	LSM_HOOK_INIT(bprm_check_security, ima_bprm_check),
+	LSM_HOOK_INIT(file_post_open, ima_file_check),
+	LSM_HOOK_INIT(inode_post_create_tmpfile, ima_post_create_tmpfile),
+	LSM_HOOK_INIT(file_pre_free_security, ima_file_free),
+	LSM_HOOK_INIT(mmap_file, ima_file_mmap),
+	LSM_HOOK_INIT(file_mprotect, ima_file_mprotect),
+	LSM_HOOK_INIT(kernel_load_data, ima_load_data),
+	LSM_HOOK_INIT(kernel_post_load_data, ima_post_load_data),
+	LSM_HOOK_INIT(kernel_read_file, ima_read_file),
+	LSM_HOOK_INIT(kernel_post_read_file, ima_post_read_file),
+#ifdef CONFIG_SECURITY_PATH
+	LSM_HOOK_INIT(path_post_mknod, ima_post_path_mknod),
+#endif
+#ifdef CONFIG_IMA_MEASURE_ASYMMETRIC_KEYS
+	LSM_HOOK_INIT(key_post_create_or_update, ima_post_key_create_or_update),
+#endif
+};
+
+static const struct lsm_id ima_lsmid = {
+	.name = "ima",
+	.id = LSM_ID_IMA,
+};
+
+/* Return the IMA LSM ID, if IMA is enabled or NULL if not. */
+const struct lsm_id *ima_get_lsm_id(void)
+{
+	return &ima_lsmid;
+}
+
+/*
+ * Since with the LSM_ORDER_LAST there is no guarantee about the ordering
+ * within the .lsm_info.init section, ensure that IMA hooks are before EVM
+ * ones, by letting the 'integrity' LSM call init_ima_lsm() to initialize the
+ * 'ima' and 'evm' LSMs in this sequence.
+ */
+void __init init_ima_lsm(void)
+{
+	security_add_hooks(ima_hooks, ARRAY_SIZE(ima_hooks), &ima_lsmid);
+}
+
+/* Introduce a dummy function as 'ima' init method (it cannot be NULL). */
+static int __init dummy_init_ima_lsm(void)
+{
+	return 0;
+}
+
+DEFINE_LSM(ima) = {
+	.name = "ima",
+	.init = dummy_init_ima_lsm,
+	.order = LSM_ORDER_LAST,
+};
+
 late_initcall(init_ima);	/* Start IMA after the TPM is available */
diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h
index 9561db7cf6b4..3098cae1c27c 100644
--- a/security/integrity/integrity.h
+++ b/security/integrity/integrity.h
@@ -18,6 +18,7 @@
 #include <crypto/hash.h>
 #include <linux/key.h>
 #include <linux/audit.h>
+#include <linux/lsm_hooks.h>
 
 /* iint action cache flags */
 #define IMA_MEASURE		0x00000001
@@ -193,6 +194,21 @@ extern struct dentry *integrity_dir;
 
 struct modsig;
 
+#ifdef CONFIG_IMA
+const struct lsm_id *ima_get_lsm_id(void);
+void __init init_ima_lsm(void);
+#else
+static inline const struct lsm_id *ima_get_lsm_id(void)
+{
+	return NULL;
+}
+
+static inline void __init init_ima_lsm(void)
+{
+}
+
+#endif
+
 #ifdef CONFIG_INTEGRITY_SIGNATURE
 
 int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
diff --git a/security/keys/key.c b/security/keys/key.c
index f75fe66c2f03..80fc2f203a0c 100644
--- a/security/keys/key.c
+++ b/security/keys/key.c
@@ -13,7 +13,6 @@
 #include <linux/security.h>
 #include <linux/workqueue.h>
 #include <linux/random.h>
-#include <linux/ima.h>
 #include <linux/err.h>
 #include "internal.h"
 
@@ -937,8 +936,6 @@ static key_ref_t __key_create_or_update(key_ref_t keyring_ref,
 
 	security_key_post_create_or_update(keyring, key, payload, plen, flags,
 					   true);
-	ima_post_key_create_or_update(keyring, key, payload, plen,
-				      flags, true);
 
 	key_ref = make_key_ref(key, is_key_possessed(keyring_ref));
 
@@ -970,13 +967,9 @@ static key_ref_t __key_create_or_update(key_ref_t keyring_ref,
 
 	key_ref = __key_update(key_ref, &prep);
 
-	if (!IS_ERR(key_ref)) {
+	if (!IS_ERR(key_ref))
 		security_key_post_create_or_update(keyring, key, payload, plen,
 						   flags, false);
-		ima_post_key_create_or_update(keyring, key,
-					      payload, plen,
-					      flags, false);
-	}
 
 	goto error_free_prep;
 }
diff --git a/security/security.c b/security/security.c
index 859189722ab8..b2fdcbaa4b30 100644
--- a/security/security.c
+++ b/security/security.c
@@ -50,7 +50,8 @@
 	(IS_ENABLED(CONFIG_SECURITY_SAFESETID) ? 1 : 0) + \
 	(IS_ENABLED(CONFIG_SECURITY_LOCKDOWN_LSM) ? 1 : 0) + \
 	(IS_ENABLED(CONFIG_BPF_LSM) ? 1 : 0) + \
-	(IS_ENABLED(CONFIG_SECURITY_LANDLOCK) ? 1 : 0))
+	(IS_ENABLED(CONFIG_SECURITY_LANDLOCK) ? 1 : 0) + \
+	(IS_ENABLED(CONFIG_IMA) ? 1 : 0))
 
 /*
  * These are descriptions of the reasons that can be passed to the
@@ -1182,12 +1183,7 @@ int security_bprm_creds_from_file(struct linux_binprm *bprm, const struct file *
  */
 int security_bprm_check(struct linux_binprm *bprm)
 {
-	int ret;
-
-	ret = call_int_hook(bprm_check_security, 0, bprm);
-	if (ret)
-		return ret;
-	return ima_bprm_check(bprm);
+	return call_int_hook(bprm_check_security, 0, bprm);
 }
 
 /**
@@ -2883,13 +2879,8 @@ static inline unsigned long mmap_prot(struct file *file, unsigned long prot)
 int security_mmap_file(struct file *file, unsigned long prot,
 		       unsigned long flags)
 {
-	unsigned long prot_adj = mmap_prot(file, prot);
-	int ret;
-
-	ret = call_int_hook(mmap_file, 0, file, prot, prot_adj, flags);
-	if (ret)
-		return ret;
-	return ima_file_mmap(file, prot, prot_adj, flags);
+	return call_int_hook(mmap_file, 0, file, prot, mmap_prot(file, prot),
+			     flags);
 }
 
 /**
@@ -2918,12 +2909,7 @@ int security_mmap_addr(unsigned long addr)
 int security_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot,
 			   unsigned long prot)
 {
-	int ret;
-
-	ret = call_int_hook(file_mprotect, 0, vma, reqprot, prot);
-	if (ret)
-		return ret;
-	return ima_file_mprotect(vma, reqprot, prot);
+	return call_int_hook(file_mprotect, 0, vma, reqprot, prot);
 }
 
 /**
@@ -3253,12 +3239,7 @@ int security_kernel_module_request(char *kmod_name)
 int security_kernel_read_file(struct file *file, enum kernel_read_file_id id,
 			      bool contents)
 {
-	int ret;
-
-	ret = call_int_hook(kernel_read_file, 0, file, id, contents);
-	if (ret)
-		return ret;
-	return ima_read_file(file, id, contents);
+	return call_int_hook(kernel_read_file, 0, file, id, contents);
 }
 EXPORT_SYMBOL_GPL(security_kernel_read_file);
 
@@ -3278,12 +3259,7 @@ EXPORT_SYMBOL_GPL(security_kernel_read_file);
 int security_kernel_post_read_file(struct file *file, char *buf, loff_t size,
 				   enum kernel_read_file_id id)
 {
-	int ret;
-
-	ret = call_int_hook(kernel_post_read_file, 0, file, buf, size, id);
-	if (ret)
-		return ret;
-	return ima_post_read_file(file, buf, size, id);
+	return call_int_hook(kernel_post_read_file, 0, file, buf, size, id);
 }
 EXPORT_SYMBOL_GPL(security_kernel_post_read_file);
 
@@ -3298,12 +3274,7 @@ EXPORT_SYMBOL_GPL(security_kernel_post_read_file);
  */
 int security_kernel_load_data(enum kernel_load_data_id id, bool contents)
 {
-	int ret;
-
-	ret = call_int_hook(kernel_load_data, 0, id, contents);
-	if (ret)
-		return ret;
-	return ima_load_data(id, contents);
+	return call_int_hook(kernel_load_data, 0, id, contents);
 }
 EXPORT_SYMBOL_GPL(security_kernel_load_data);
 
@@ -3325,13 +3296,8 @@ int security_kernel_post_load_data(char *buf, loff_t size,
 				   enum kernel_load_data_id id,
 				   char *description)
 {
-	int ret;
-
-	ret = call_int_hook(kernel_post_load_data, 0, buf, size, id,
-			    description);
-	if (ret)
-		return ret;
-	return ima_post_load_data(buf, size, id, description);
+	return call_int_hook(kernel_post_load_data, 0, buf, size, id,
+			     description);
 }
 EXPORT_SYMBOL_GPL(security_kernel_post_load_data);
 
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 96+ messages in thread

* [PATCH v5 20/23] ima: Move IMA-Appraisal to LSM infrastructure
  2023-11-07 13:39 [PATCH v5 00/23] security: Move IMA and EVM to the LSM infrastructure Roberto Sassu
                   ` (18 preceding siblings ...)
  2023-11-07 13:40 ` [PATCH v5 19/23] ima: Move to LSM infrastructure Roberto Sassu
@ 2023-11-07 13:40 ` Roberto Sassu
  2023-11-07 18:43   ` Casey Schaufler
  2023-11-07 13:40 ` [PATCH v5 21/23] evm: Move " Roberto Sassu
                   ` (3 subsequent siblings)
  23 siblings, 1 reply; 96+ messages in thread
From: Roberto Sassu @ 2023-11-07 13:40 UTC (permalink / raw)
  To: viro, brauner, chuck.lever, jlayton, neilb, kolga, Dai.Ngo, tom,
	paul, jmorris, serge, zohar, dmitry.kasatkin, dhowells, jarkko,
	stephen.smalley.work, eparis, casey, mic
  Cc: linux-fsdevel, linux-kernel, linux-nfs, linux-security-module,
	linux-integrity, keyrings, selinux, Roberto Sassu, Stefan Berger

From: Roberto Sassu <roberto.sassu@huawei.com>

Do the registration of IMA-Appraisal only functions separately from the
rest of IMA functions, as appraisal is a separate feature not necessarily
enabled in the kernel configuration.

Reuse the same approach as for other IMA functions, move hardcoded calls
from various places in the kernel to the LSM infrastructure. Declare the
functions as static and register them as hook implementations in
init_ima_appraise_lsm(), called by init_ima_lsm().

Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
---
 fs/attr.c                             |  2 -
 include/linux/ima.h                   | 55 ---------------------------
 security/integrity/ima/ima.h          |  5 +++
 security/integrity/ima/ima_appraise.c | 38 +++++++++++++-----
 security/integrity/ima/ima_main.c     |  1 +
 security/security.c                   | 13 -------
 6 files changed, 35 insertions(+), 79 deletions(-)

diff --git a/fs/attr.c b/fs/attr.c
index 221d2bb0a906..38841f3ebbcb 100644
--- a/fs/attr.c
+++ b/fs/attr.c
@@ -17,7 +17,6 @@
 #include <linux/filelock.h>
 #include <linux/security.h>
 #include <linux/evm.h>
-#include <linux/ima.h>
 
 #include "internal.h"
 
@@ -503,7 +502,6 @@ int notify_change(struct mnt_idmap *idmap, struct dentry *dentry,
 	if (!error) {
 		fsnotify_change(dentry, ia_valid);
 		security_inode_post_setattr(idmap, dentry, ia_valid);
-		ima_inode_post_setattr(idmap, dentry, ia_valid);
 		evm_inode_post_setattr(idmap, dentry, ia_valid);
 	}
 
diff --git a/include/linux/ima.h b/include/linux/ima.h
index 23ae24b60ecf..0bae61a15b60 100644
--- a/include/linux/ima.h
+++ b/include/linux/ima.h
@@ -92,66 +92,11 @@ static inline void ima_add_kexec_buffer(struct kimage *image)
 
 #ifdef CONFIG_IMA_APPRAISE
 extern bool is_ima_appraise_enabled(void);
-extern void ima_inode_post_setattr(struct mnt_idmap *idmap,
-				   struct dentry *dentry, int ia_valid);
-extern int ima_inode_setxattr(struct mnt_idmap *idmap, struct dentry *dentry,
-			      const char *xattr_name, const void *xattr_value,
-			      size_t xattr_value_len, int flags);
-extern int ima_inode_set_acl(struct mnt_idmap *idmap,
-			     struct dentry *dentry, const char *acl_name,
-			     struct posix_acl *kacl);
-static inline int ima_inode_remove_acl(struct mnt_idmap *idmap,
-				       struct dentry *dentry,
-				       const char *acl_name)
-{
-	return ima_inode_set_acl(idmap, dentry, acl_name, NULL);
-}
-
-extern int ima_inode_removexattr(struct mnt_idmap *idmap, struct dentry *dentry,
-				 const char *xattr_name);
 #else
 static inline bool is_ima_appraise_enabled(void)
 {
 	return 0;
 }
-
-static inline void ima_inode_post_setattr(struct mnt_idmap *idmap,
-					  struct dentry *dentry, int ia_valid)
-{
-	return;
-}
-
-static inline int ima_inode_setxattr(struct mnt_idmap *idmap,
-				     struct dentry *dentry,
-				     const char *xattr_name,
-				     const void *xattr_value,
-				     size_t xattr_value_len,
-				     int flags)
-{
-	return 0;
-}
-
-static inline int ima_inode_set_acl(struct mnt_idmap *idmap,
-				    struct dentry *dentry, const char *acl_name,
-				    struct posix_acl *kacl)
-{
-
-	return 0;
-}
-
-static inline int ima_inode_removexattr(struct mnt_idmap *idmap,
-					struct dentry *dentry,
-					const char *xattr_name)
-{
-	return 0;
-}
-
-static inline int ima_inode_remove_acl(struct mnt_idmap *idmap,
-				       struct dentry *dentry,
-				       const char *acl_name)
-{
-	return 0;
-}
 #endif /* CONFIG_IMA_APPRAISE */
 
 #if defined(CONFIG_IMA_APPRAISE) && defined(CONFIG_INTEGRITY_TRUSTED_KEYRING)
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index c0412100023e..a27fc10f84f7 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -334,6 +334,7 @@ enum hash_algo ima_get_hash_algo(const struct evm_ima_xattr_data *xattr_value,
 				 int xattr_len);
 int ima_read_xattr(struct dentry *dentry,
 		   struct evm_ima_xattr_data **xattr_value, int xattr_len);
+void __init init_ima_appraise_lsm(const struct lsm_id *lsmid);
 
 #else
 static inline int ima_check_blacklist(struct integrity_iint_cache *iint,
@@ -385,6 +386,10 @@ static inline int ima_read_xattr(struct dentry *dentry,
 	return 0;
 }
 
+static inline void __init init_ima_appraise_lsm(const struct lsm_id *lsmid)
+{
+}
+
 #endif /* CONFIG_IMA_APPRAISE */
 
 #ifdef CONFIG_IMA_APPRAISE_MODSIG
diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c
index 36abc84ba299..076451109637 100644
--- a/security/integrity/ima/ima_appraise.c
+++ b/security/integrity/ima/ima_appraise.c
@@ -636,8 +636,8 @@ void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file)
  * This function is called from notify_change(), which expects the caller
  * to lock the inode's i_mutex.
  */
-void ima_inode_post_setattr(struct mnt_idmap *idmap,
-			    struct dentry *dentry, int ia_valid)
+static void ima_inode_post_setattr(struct mnt_idmap *idmap,
+				   struct dentry *dentry, int ia_valid)
 {
 	struct inode *inode = d_backing_inode(dentry);
 	struct integrity_iint_cache *iint;
@@ -750,9 +750,9 @@ static int validate_hash_algo(struct dentry *dentry,
 	return -EACCES;
 }
 
-int ima_inode_setxattr(struct mnt_idmap *idmap, struct dentry *dentry,
-		       const char *xattr_name, const void *xattr_value,
-		       size_t xattr_value_len, int flags)
+static int ima_inode_setxattr(struct mnt_idmap *idmap, struct dentry *dentry,
+			      const char *xattr_name, const void *xattr_value,
+			      size_t xattr_value_len, int flags)
 {
 	const struct evm_ima_xattr_data *xvalue = xattr_value;
 	int digsig = 0;
@@ -781,8 +781,8 @@ int ima_inode_setxattr(struct mnt_idmap *idmap, struct dentry *dentry,
 	return result;
 }
 
-int ima_inode_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
-		      const char *acl_name, struct posix_acl *kacl)
+static int ima_inode_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
+			     const char *acl_name, struct posix_acl *kacl)
 {
 	if (evm_revalidate_status(acl_name))
 		ima_reset_appraise_flags(d_backing_inode(dentry), 0);
@@ -790,8 +790,8 @@ int ima_inode_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
 	return 0;
 }
 
-int ima_inode_removexattr(struct mnt_idmap *idmap, struct dentry *dentry,
-			  const char *xattr_name)
+static int ima_inode_removexattr(struct mnt_idmap *idmap, struct dentry *dentry,
+				 const char *xattr_name)
 {
 	int result;
 
@@ -803,3 +803,23 @@ int ima_inode_removexattr(struct mnt_idmap *idmap, struct dentry *dentry,
 	}
 	return result;
 }
+
+static int ima_inode_remove_acl(struct mnt_idmap *idmap, struct dentry *dentry,
+				const char *acl_name)
+{
+	return ima_inode_set_acl(idmap, dentry, acl_name, NULL);
+}
+
+static struct security_hook_list ima_appraise_hooks[] __ro_after_init = {
+	LSM_HOOK_INIT(inode_post_setattr, ima_inode_post_setattr),
+	LSM_HOOK_INIT(inode_setxattr, ima_inode_setxattr),
+	LSM_HOOK_INIT(inode_set_acl, ima_inode_set_acl),
+	LSM_HOOK_INIT(inode_removexattr, ima_inode_removexattr),
+	LSM_HOOK_INIT(inode_remove_acl, ima_inode_remove_acl),
+};
+
+void __init init_ima_appraise_lsm(const struct lsm_id *lsmid)
+{
+	security_add_hooks(ima_appraise_hooks, ARRAY_SIZE(ima_appraise_hooks),
+			   lsmid);
+}
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index f923ff5c6524..9aabbc37916c 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -1161,6 +1161,7 @@ const struct lsm_id *ima_get_lsm_id(void)
 void __init init_ima_lsm(void)
 {
 	security_add_hooks(ima_hooks, ARRAY_SIZE(ima_hooks), &ima_lsmid);
+	init_ima_appraise_lsm(&ima_lsmid);
 }
 
 /* Introduce a dummy function as 'ima' init method (it cannot be NULL). */
diff --git a/security/security.c b/security/security.c
index b2fdcbaa4b30..456f3fe74116 100644
--- a/security/security.c
+++ b/security/security.c
@@ -20,7 +20,6 @@
 #include <linux/kernel_read_file.h>
 #include <linux/lsm_hooks.h>
 #include <linux/integrity.h>
-#include <linux/ima.h>
 #include <linux/evm.h>
 #include <linux/fsnotify.h>
 #include <linux/mman.h>
@@ -2308,9 +2307,6 @@ int security_inode_setxattr(struct mnt_idmap *idmap,
 
 	if (ret == 1)
 		ret = cap_inode_setxattr(dentry, name, value, size, flags);
-	if (ret)
-		return ret;
-	ret = ima_inode_setxattr(idmap, dentry, name, value, size, flags);
 	if (ret)
 		return ret;
 	return evm_inode_setxattr(idmap, dentry, name, value, size, flags);
@@ -2338,9 +2334,6 @@ int security_inode_set_acl(struct mnt_idmap *idmap,
 		return 0;
 	ret = call_int_hook(inode_set_acl, 0, idmap, dentry, acl_name,
 			    kacl);
-	if (ret)
-		return ret;
-	ret = ima_inode_set_acl(idmap, dentry, acl_name, kacl);
 	if (ret)
 		return ret;
 	return evm_inode_set_acl(idmap, dentry, acl_name, kacl);
@@ -2401,9 +2394,6 @@ int security_inode_remove_acl(struct mnt_idmap *idmap,
 	if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
 		return 0;
 	ret = call_int_hook(inode_remove_acl, 0, idmap, dentry, acl_name);
-	if (ret)
-		return ret;
-	ret = ima_inode_remove_acl(idmap, dentry, acl_name);
 	if (ret)
 		return ret;
 	return evm_inode_remove_acl(idmap, dentry, acl_name);
@@ -2503,9 +2493,6 @@ int security_inode_removexattr(struct mnt_idmap *idmap,
 	ret = call_int_hook(inode_removexattr, 1, idmap, dentry, name);
 	if (ret == 1)
 		ret = cap_inode_removexattr(idmap, dentry, name);
-	if (ret)
-		return ret;
-	ret = ima_inode_removexattr(idmap, dentry, name);
 	if (ret)
 		return ret;
 	return evm_inode_removexattr(idmap, dentry, name);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 96+ messages in thread

* [PATCH v5 21/23] evm: Move to LSM infrastructure
  2023-11-07 13:39 [PATCH v5 00/23] security: Move IMA and EVM to the LSM infrastructure Roberto Sassu
                   ` (19 preceding siblings ...)
  2023-11-07 13:40 ` [PATCH v5 20/23] ima: Move IMA-Appraisal " Roberto Sassu
@ 2023-11-07 13:40 ` Roberto Sassu
  2023-11-07 18:45   ` Casey Schaufler
  2023-11-07 13:40 ` [PATCH v5 22/23] integrity: Move integrity functions to the " Roberto Sassu
                   ` (2 subsequent siblings)
  23 siblings, 1 reply; 96+ messages in thread
From: Roberto Sassu @ 2023-11-07 13:40 UTC (permalink / raw)
  To: viro, brauner, chuck.lever, jlayton, neilb, kolga, Dai.Ngo, tom,
	paul, jmorris, serge, zohar, dmitry.kasatkin, dhowells, jarkko,
	stephen.smalley.work, eparis, casey, mic
  Cc: linux-fsdevel, linux-kernel, linux-nfs, linux-security-module,
	linux-integrity, keyrings, selinux, Roberto Sassu

From: Roberto Sassu <roberto.sassu@huawei.com>

As for IMA, move hardcoded EVM function calls from various places in the
kernel to the LSM infrastructure, by introducing a new LSM named 'evm'
(at the end of the LSM list and always enabled, like 'ima' and
'integrity').

Make EVM functions as static (except for evm_inode_init_security(), which
is exported), and register them as hook implementations in init_evm_lsm(),
called by integrity_lsm_init() to keep the original ordering of IMA and EVM
functions.

Introduce evm_get_lsm_id() to pass the EVM LSM ID back to the 'integrity'
LSM for registration of the integrity-specific hooks.

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>
---
 fs/attr.c                         |   2 -
 fs/posix_acl.c                    |   3 -
 fs/xattr.c                        |   2 -
 include/linux/evm.h               | 107 -----------------------
 include/uapi/linux/lsm.h          |   1 +
 security/integrity/evm/evm_main.c | 137 ++++++++++++++++++++++++++----
 security/integrity/iint.c         |   1 +
 security/integrity/integrity.h    |  15 ++++
 security/security.c               |  45 +++-------
 9 files changed, 150 insertions(+), 163 deletions(-)

diff --git a/fs/attr.c b/fs/attr.c
index 38841f3ebbcb..b51bd7c9b4a7 100644
--- a/fs/attr.c
+++ b/fs/attr.c
@@ -16,7 +16,6 @@
 #include <linux/fcntl.h>
 #include <linux/filelock.h>
 #include <linux/security.h>
-#include <linux/evm.h>
 
 #include "internal.h"
 
@@ -502,7 +501,6 @@ int notify_change(struct mnt_idmap *idmap, struct dentry *dentry,
 	if (!error) {
 		fsnotify_change(dentry, ia_valid);
 		security_inode_post_setattr(idmap, dentry, ia_valid);
-		evm_inode_post_setattr(idmap, dentry, ia_valid);
 	}
 
 	return error;
diff --git a/fs/posix_acl.c b/fs/posix_acl.c
index e3fbe1a9f3f5..ae67479cd2b6 100644
--- a/fs/posix_acl.c
+++ b/fs/posix_acl.c
@@ -26,7 +26,6 @@
 #include <linux/mnt_idmapping.h>
 #include <linux/iversion.h>
 #include <linux/security.h>
-#include <linux/evm.h>
 #include <linux/fsnotify.h>
 #include <linux/filelock.h>
 
@@ -1138,7 +1137,6 @@ int vfs_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
 	if (!error) {
 		fsnotify_xattr(dentry);
 		security_inode_post_set_acl(dentry, acl_name, kacl);
-		evm_inode_post_set_acl(dentry, acl_name, kacl);
 	}
 
 out_inode_unlock:
@@ -1247,7 +1245,6 @@ int vfs_remove_acl(struct mnt_idmap *idmap, struct dentry *dentry,
 	if (!error) {
 		fsnotify_xattr(dentry);
 		security_inode_post_remove_acl(idmap, dentry, acl_name);
-		evm_inode_post_remove_acl(idmap, dentry, acl_name);
 	}
 
 out_inode_unlock:
diff --git a/fs/xattr.c b/fs/xattr.c
index 84a4aa566c02..2660bc7effdc 100644
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -16,7 +16,6 @@
 #include <linux/mount.h>
 #include <linux/namei.h>
 #include <linux/security.h>
-#include <linux/evm.h>
 #include <linux/syscalls.h>
 #include <linux/export.h>
 #include <linux/fsnotify.h>
@@ -557,7 +556,6 @@ __vfs_removexattr_locked(struct mnt_idmap *idmap,
 
 	fsnotify_xattr(dentry);
 	security_inode_post_removexattr(dentry, name);
-	evm_inode_post_removexattr(dentry, name);
 
 out:
 	return error;
diff --git a/include/linux/evm.h b/include/linux/evm.h
index 437d4076a3b3..cb481eccc967 100644
--- a/include/linux/evm.h
+++ b/include/linux/evm.h
@@ -21,44 +21,6 @@ extern enum integrity_status evm_verifyxattr(struct dentry *dentry,
 					     void *xattr_value,
 					     size_t xattr_value_len,
 					     struct integrity_iint_cache *iint);
-extern int evm_inode_setattr(struct mnt_idmap *idmap,
-			     struct dentry *dentry, struct iattr *attr);
-extern void evm_inode_post_setattr(struct mnt_idmap *idmap,
-				   struct dentry *dentry, int ia_valid);
-extern int evm_inode_setxattr(struct mnt_idmap *idmap,
-			      struct dentry *dentry, const char *name,
-			      const void *value, size_t size, int flags);
-extern void evm_inode_post_setxattr(struct dentry *dentry,
-				    const char *xattr_name,
-				    const void *xattr_value,
-				    size_t xattr_value_len,
-				    int flags);
-extern int evm_inode_removexattr(struct mnt_idmap *idmap,
-				 struct dentry *dentry, const char *xattr_name);
-extern void evm_inode_post_removexattr(struct dentry *dentry,
-				       const char *xattr_name);
-static inline void evm_inode_post_remove_acl(struct mnt_idmap *idmap,
-					     struct dentry *dentry,
-					     const char *acl_name)
-{
-	evm_inode_post_removexattr(dentry, acl_name);
-}
-extern int evm_inode_set_acl(struct mnt_idmap *idmap,
-			     struct dentry *dentry, const char *acl_name,
-			     struct posix_acl *kacl);
-static inline int evm_inode_remove_acl(struct mnt_idmap *idmap,
-				       struct dentry *dentry,
-				       const char *acl_name)
-{
-	return evm_inode_set_acl(idmap, dentry, acl_name, NULL);
-}
-static inline void evm_inode_post_set_acl(struct dentry *dentry,
-					  const char *acl_name,
-					  struct posix_acl *kacl)
-{
-	return evm_inode_post_setxattr(dentry, acl_name, NULL, 0, 0);
-}
-
 int evm_inode_init_security(struct inode *inode, struct inode *dir,
 			    const struct qstr *qstr, struct xattr *xattrs,
 			    int *xattr_count);
@@ -93,75 +55,6 @@ static inline enum integrity_status evm_verifyxattr(struct dentry *dentry,
 }
 #endif
 
-static inline int evm_inode_setattr(struct mnt_idmap *idmap,
-				    struct dentry *dentry, struct iattr *attr)
-{
-	return 0;
-}
-
-static inline void evm_inode_post_setattr(struct mnt_idmap *idmap,
-					  struct dentry *dentry, int ia_valid)
-{
-	return;
-}
-
-static inline int evm_inode_setxattr(struct mnt_idmap *idmap,
-				     struct dentry *dentry, const char *name,
-				     const void *value, size_t size, int flags)
-{
-	return 0;
-}
-
-static inline void evm_inode_post_setxattr(struct dentry *dentry,
-					   const char *xattr_name,
-					   const void *xattr_value,
-					   size_t xattr_value_len,
-					   int flags)
-{
-	return;
-}
-
-static inline int evm_inode_removexattr(struct mnt_idmap *idmap,
-					struct dentry *dentry,
-					const char *xattr_name)
-{
-	return 0;
-}
-
-static inline void evm_inode_post_removexattr(struct dentry *dentry,
-					      const char *xattr_name)
-{
-	return;
-}
-
-static inline void evm_inode_post_remove_acl(struct mnt_idmap *idmap,
-					     struct dentry *dentry,
-					     const char *acl_name)
-{
-	return;
-}
-
-static inline int evm_inode_set_acl(struct mnt_idmap *idmap,
-				    struct dentry *dentry, const char *acl_name,
-				    struct posix_acl *kacl)
-{
-	return 0;
-}
-
-static inline int evm_inode_remove_acl(struct mnt_idmap *idmap,
-				       struct dentry *dentry,
-				       const char *acl_name)
-{
-	return 0;
-}
-
-static inline void evm_inode_post_set_acl(struct dentry *dentry,
-					  const char *acl_name,
-					  struct posix_acl *kacl)
-{
-	return;
-}
-
 static inline int evm_inode_init_security(struct inode *inode, struct inode *dir,
 					  const struct qstr *qstr,
 					  struct xattr *xattrs,
diff --git a/include/uapi/linux/lsm.h b/include/uapi/linux/lsm.h
index ee7d034255a9..825339bcd580 100644
--- a/include/uapi/linux/lsm.h
+++ b/include/uapi/linux/lsm.h
@@ -62,6 +62,7 @@ struct lsm_ctx {
 #define LSM_ID_BPF		109
 #define LSM_ID_LANDLOCK		110
 #define LSM_ID_IMA		111
+#define LSM_ID_EVM		112
 
 /*
  * LSM_ATTR_XXX definitions identify different LSM attributes
diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c
index ea84a6f835ff..21560874e5fc 100644
--- a/security/integrity/evm/evm_main.c
+++ b/security/integrity/evm/evm_main.c
@@ -566,9 +566,9 @@ static int evm_protect_xattr(struct mnt_idmap *idmap,
  * userspace from writing HMAC value.  Writing 'security.evm' requires
  * requires CAP_SYS_ADMIN privileges.
  */
-int evm_inode_setxattr(struct mnt_idmap *idmap, struct dentry *dentry,
-		       const char *xattr_name, const void *xattr_value,
-		       size_t xattr_value_len, int flags)
+static int evm_inode_setxattr(struct mnt_idmap *idmap, struct dentry *dentry,
+			      const char *xattr_name, const void *xattr_value,
+			      size_t xattr_value_len, int flags)
 {
 	const struct evm_ima_xattr_data *xattr_data = xattr_value;
 
@@ -598,8 +598,8 @@ int evm_inode_setxattr(struct mnt_idmap *idmap, struct dentry *dentry,
  * Removing 'security.evm' requires CAP_SYS_ADMIN privileges and that
  * the current value is valid.
  */
-int evm_inode_removexattr(struct mnt_idmap *idmap,
-			  struct dentry *dentry, const char *xattr_name)
+static int evm_inode_removexattr(struct mnt_idmap *idmap, struct dentry *dentry,
+				 const char *xattr_name)
 {
 	/* Policy permits modification of the protected xattrs even though
 	 * there's no HMAC key loaded
@@ -649,9 +649,11 @@ static inline int evm_inode_set_acl_change(struct mnt_idmap *idmap,
  * Prevent modifying posix acls causing the EVM HMAC to be re-calculated
  * and 'security.evm' xattr updated, unless the existing 'security.evm' is
  * valid.
+ *
+ * Return: zero on success, -EPERM on failure.
  */
-int evm_inode_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
-		      const char *acl_name, struct posix_acl *kacl)
+static int evm_inode_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
+			     const char *acl_name, struct posix_acl *kacl)
 {
 	enum integrity_status evm_status;
 
@@ -690,6 +692,24 @@ int evm_inode_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
 	return -EPERM;
 }
 
+/**
+ * evm_inode_remove_acl - Protect the EVM extended attribute from posix acls
+ * @idmap: idmap of the mount
+ * @dentry: pointer to the affected dentry
+ * @acl_name: name of the posix acl
+ *
+ * Prevent removing posix acls causing the EVM HMAC to be re-calculated
+ * and 'security.evm' xattr updated, unless the existing 'security.evm' is
+ * valid.
+ *
+ * Return: zero on success, -EPERM on failure.
+ */
+static int evm_inode_remove_acl(struct mnt_idmap *idmap, struct dentry *dentry,
+				const char *acl_name)
+{
+	return evm_inode_set_acl(idmap, dentry, acl_name, NULL);
+}
+
 static void evm_reset_status(struct inode *inode)
 {
 	struct integrity_iint_cache *iint;
@@ -738,9 +758,11 @@ bool evm_revalidate_status(const char *xattr_name)
  * __vfs_setxattr_noperm().  The caller of which has taken the inode's
  * i_mutex lock.
  */
-void evm_inode_post_setxattr(struct dentry *dentry, const char *xattr_name,
-			     const void *xattr_value, size_t xattr_value_len,
-			     int flags)
+static void evm_inode_post_setxattr(struct dentry *dentry,
+				    const char *xattr_name,
+				    const void *xattr_value,
+				    size_t xattr_value_len,
+				    int flags)
 {
 	if (!evm_revalidate_status(xattr_name))
 		return;
@@ -756,6 +778,21 @@ void evm_inode_post_setxattr(struct dentry *dentry, const char *xattr_name,
 	evm_update_evmxattr(dentry, xattr_name, xattr_value, xattr_value_len);
 }
 
+/**
+ * evm_inode_post_set_acl - Update the EVM extended attribute from posix acls
+ * @dentry: pointer to the affected dentry
+ * @acl_name: name of the posix acl
+ * @kacl: pointer to the posix acls
+ *
+ * Update the 'security.evm' xattr with the EVM HMAC re-calculated after setting
+ * posix acls.
+ */
+static void evm_inode_post_set_acl(struct dentry *dentry, const char *acl_name,
+				   struct posix_acl *kacl)
+{
+	return evm_inode_post_setxattr(dentry, acl_name, NULL, 0, 0);
+}
+
 /**
  * evm_inode_post_removexattr - update 'security.evm' after removing the xattr
  * @dentry: pointer to the affected dentry
@@ -766,7 +803,8 @@ void evm_inode_post_setxattr(struct dentry *dentry, const char *xattr_name,
  * No need to take the i_mutex lock here, as this function is called from
  * vfs_removexattr() which takes the i_mutex.
  */
-void evm_inode_post_removexattr(struct dentry *dentry, const char *xattr_name)
+static void evm_inode_post_removexattr(struct dentry *dentry,
+				       const char *xattr_name)
 {
 	if (!evm_revalidate_status(xattr_name))
 		return;
@@ -782,6 +820,22 @@ void evm_inode_post_removexattr(struct dentry *dentry, const char *xattr_name)
 	evm_update_evmxattr(dentry, xattr_name, NULL, 0);
 }
 
+/**
+ * evm_inode_post_remove_acl - Update the EVM extended attribute from posix acls
+ * @idmap: idmap of the mount
+ * @dentry: pointer to the affected dentry
+ * @acl_name: name of the posix acl
+ *
+ * Update the 'security.evm' xattr with the EVM HMAC re-calculated after
+ * removing posix acls.
+ */
+static inline void evm_inode_post_remove_acl(struct mnt_idmap *idmap,
+					     struct dentry *dentry,
+					     const char *acl_name)
+{
+	evm_inode_post_removexattr(dentry, acl_name);
+}
+
 static int evm_attr_change(struct mnt_idmap *idmap,
 			   struct dentry *dentry, struct iattr *attr)
 {
@@ -805,8 +859,8 @@ static int evm_attr_change(struct mnt_idmap *idmap,
  * Permit update of file attributes when files have a valid EVM signature,
  * except in the case of them having an immutable portable signature.
  */
-int evm_inode_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
-		      struct iattr *attr)
+static int evm_inode_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
+			     struct iattr *attr)
 {
 	unsigned int ia_valid = attr->ia_valid;
 	enum integrity_status evm_status;
@@ -853,8 +907,8 @@ int evm_inode_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
  * This function is called from notify_change(), which expects the caller
  * to lock the inode's i_mutex.
  */
-void evm_inode_post_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
-			    int ia_valid)
+static void evm_inode_post_setattr(struct mnt_idmap *idmap,
+				   struct dentry *dentry, int ia_valid)
 {
 	if (!evm_revalidate_status(NULL))
 		return;
@@ -964,4 +1018,57 @@ static int __init init_evm(void)
 	return error;
 }
 
+static struct security_hook_list evm_hooks[] __ro_after_init = {
+	LSM_HOOK_INIT(inode_setattr, evm_inode_setattr),
+	LSM_HOOK_INIT(inode_post_setattr, evm_inode_post_setattr),
+	LSM_HOOK_INIT(inode_setxattr, evm_inode_setxattr),
+	LSM_HOOK_INIT(inode_set_acl, evm_inode_set_acl),
+	LSM_HOOK_INIT(inode_post_set_acl, evm_inode_post_set_acl),
+	LSM_HOOK_INIT(inode_remove_acl, evm_inode_remove_acl),
+	LSM_HOOK_INIT(inode_post_remove_acl, evm_inode_post_remove_acl),
+	LSM_HOOK_INIT(inode_post_setxattr, evm_inode_post_setxattr),
+	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),
+};
+
+static const struct lsm_id evm_lsmid = {
+	.name = "evm",
+	.id = LSM_ID_EVM,
+};
+
+/* Return the EVM LSM ID, if EVM is enabled or NULL if not. */
+const struct lsm_id *evm_get_lsm_id(void)
+{
+	return &evm_lsmid;
+}
+
+/*
+ * Since with the LSM_ORDER_LAST there is no guarantee about the ordering
+ * within the .lsm_info.init section, ensure that IMA hooks are before EVM
+ * ones, by letting the 'integrity' LSM call init_evm_lsm() to initialize the
+ * 'ima' and 'evm' LSMs in this sequence.
+ */
+void __init init_evm_lsm(void)
+{
+	security_add_hooks(evm_hooks, ARRAY_SIZE(evm_hooks), &evm_lsmid);
+}
+
+static struct lsm_blob_sizes evm_blob_sizes __ro_after_init = {
+	.lbs_xattr_count = 1,
+};
+
+/* Introduce a dummy function as 'evm' init method (it cannot be NULL). */
+static int __init dummy_init_evm_lsm(void)
+{
+	return 0;
+}
+
+DEFINE_LSM(evm) = {
+	.name = "evm",
+	.init = dummy_init_evm_lsm,
+	.order = LSM_ORDER_LAST,
+	.blobs = &evm_blob_sizes,
+};
+
 late_initcall(init_evm);
diff --git a/security/integrity/iint.c b/security/integrity/iint.c
index 87f2c0d69f78..0b0ac71142e8 100644
--- a/security/integrity/iint.c
+++ b/security/integrity/iint.c
@@ -199,6 +199,7 @@ static int __init integrity_lsm_init(void)
 	    kmem_cache_create("iint_cache", sizeof(struct integrity_iint_cache),
 			      0, SLAB_PANIC, iint_init_once);
 	init_ima_lsm();
+	init_evm_lsm();
 	return 0;
 }
 
diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h
index 3098cae1c27c..7534ec06324e 100644
--- a/security/integrity/integrity.h
+++ b/security/integrity/integrity.h
@@ -209,6 +209,21 @@ static inline void __init init_ima_lsm(void)
 
 #endif
 
+#ifdef CONFIG_EVM
+const struct lsm_id *evm_get_lsm_id(void);
+void __init init_evm_lsm(void);
+#else
+static inline const struct lsm_id *evm_get_lsm_id(void)
+{
+	return NULL;
+}
+
+static inline void __init init_evm_lsm(void)
+{
+}
+
+#endif
+
 #ifdef CONFIG_INTEGRITY_SIGNATURE
 
 int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
diff --git a/security/security.c b/security/security.c
index 456f3fe74116..9703549b6ddc 100644
--- a/security/security.c
+++ b/security/security.c
@@ -20,13 +20,13 @@
 #include <linux/kernel_read_file.h>
 #include <linux/lsm_hooks.h>
 #include <linux/integrity.h>
-#include <linux/evm.h>
 #include <linux/fsnotify.h>
 #include <linux/mman.h>
 #include <linux/mount.h>
 #include <linux/personality.h>
 #include <linux/backing-dev.h>
 #include <linux/string.h>
+#include <linux/xattr.h>
 #include <linux/msg.h>
 #include <net/flow.h>
 
@@ -50,7 +50,8 @@
 	(IS_ENABLED(CONFIG_SECURITY_LOCKDOWN_LSM) ? 1 : 0) + \
 	(IS_ENABLED(CONFIG_BPF_LSM) ? 1 : 0) + \
 	(IS_ENABLED(CONFIG_SECURITY_LANDLOCK) ? 1 : 0) + \
-	(IS_ENABLED(CONFIG_IMA) ? 1 : 0))
+	(IS_ENABLED(CONFIG_IMA) ? 1 : 0) + \
+	(IS_ENABLED(CONFIG_EVM) ? 1 : 0))
 
 /*
  * These are descriptions of the reasons that can be passed to the
@@ -1715,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;
@@ -1740,10 +1741,6 @@ int security_inode_init_security(struct inode *inode, struct inode *dir,
 	if (!xattr_count)
 		goto out;
 
-	ret = evm_inode_init_security(inode, dir, qstr, new_xattrs,
-				      &xattr_count);
-	if (ret)
-		goto out;
 	ret = initxattrs(inode, new_xattrs, fs_data);
 out:
 	for (; xattr_count > 0; xattr_count--)
@@ -2235,14 +2232,9 @@ int security_inode_permission(struct inode *inode, int mask)
 int security_inode_setattr(struct mnt_idmap *idmap,
 			   struct dentry *dentry, struct iattr *attr)
 {
-	int ret;
-
 	if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
 		return 0;
-	ret = call_int_hook(inode_setattr, 0, idmap, dentry, attr);
-	if (ret)
-		return ret;
-	return evm_inode_setattr(idmap, dentry, attr);
+	return call_int_hook(inode_setattr, 0, idmap, dentry, attr);
 }
 EXPORT_SYMBOL_GPL(security_inode_setattr);
 
@@ -2307,9 +2299,7 @@ int security_inode_setxattr(struct mnt_idmap *idmap,
 
 	if (ret == 1)
 		ret = cap_inode_setxattr(dentry, name, value, size, flags);
-	if (ret)
-		return ret;
-	return evm_inode_setxattr(idmap, dentry, name, value, size, flags);
+	return ret;
 }
 
 /**
@@ -2328,15 +2318,10 @@ int security_inode_set_acl(struct mnt_idmap *idmap,
 			   struct dentry *dentry, const char *acl_name,
 			   struct posix_acl *kacl)
 {
-	int ret;
-
 	if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
 		return 0;
-	ret = call_int_hook(inode_set_acl, 0, idmap, dentry, acl_name,
-			    kacl);
-	if (ret)
-		return ret;
-	return evm_inode_set_acl(idmap, dentry, acl_name, kacl);
+	return call_int_hook(inode_set_acl, 0, idmap, dentry, acl_name,
+			     kacl);
 }
 
 /**
@@ -2389,14 +2374,9 @@ int security_inode_get_acl(struct mnt_idmap *idmap,
 int security_inode_remove_acl(struct mnt_idmap *idmap,
 			      struct dentry *dentry, const char *acl_name)
 {
-	int ret;
-
 	if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
 		return 0;
-	ret = call_int_hook(inode_remove_acl, 0, idmap, dentry, acl_name);
-	if (ret)
-		return ret;
-	return evm_inode_remove_acl(idmap, dentry, acl_name);
+	return call_int_hook(inode_remove_acl, 0, idmap, dentry, acl_name);
 }
 
 /**
@@ -2432,7 +2412,6 @@ void security_inode_post_setxattr(struct dentry *dentry, const char *name,
 	if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
 		return;
 	call_void_hook(inode_post_setxattr, dentry, name, value, size, flags);
-	evm_inode_post_setxattr(dentry, name, value, size, flags);
 }
 
 /**
@@ -2493,9 +2472,7 @@ int security_inode_removexattr(struct mnt_idmap *idmap,
 	ret = call_int_hook(inode_removexattr, 1, idmap, dentry, name);
 	if (ret == 1)
 		ret = cap_inode_removexattr(idmap, dentry, name);
-	if (ret)
-		return ret;
-	return evm_inode_removexattr(idmap, dentry, name);
+	return ret;
 }
 
 /**
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 96+ messages in thread

* [PATCH v5 22/23] integrity: Move integrity functions to the LSM infrastructure
  2023-11-07 13:39 [PATCH v5 00/23] security: Move IMA and EVM to the LSM infrastructure Roberto Sassu
                   ` (20 preceding siblings ...)
  2023-11-07 13:40 ` [PATCH v5 21/23] evm: Move " Roberto Sassu
@ 2023-11-07 13:40 ` Roberto Sassu
  2023-11-07 18:46   ` Casey Schaufler
  2023-11-16  4:33   ` Paul Moore
  2023-11-07 13:40 ` [PATCH v5 23/23] integrity: Switch from rbtree to LSM-managed blob for integrity_iint_cache Roberto Sassu
  2023-11-07 14:05 ` [PATCH v5 00/23] security: Move IMA and EVM to the LSM infrastructure Roberto Sassu
  23 siblings, 2 replies; 96+ messages in thread
From: Roberto Sassu @ 2023-11-07 13:40 UTC (permalink / raw)
  To: viro, brauner, chuck.lever, jlayton, neilb, kolga, Dai.Ngo, tom,
	paul, jmorris, serge, zohar, dmitry.kasatkin, dhowells, jarkko,
	stephen.smalley.work, eparis, casey, mic
  Cc: linux-fsdevel, linux-kernel, linux-nfs, linux-security-module,
	linux-integrity, keyrings, selinux, Roberto Sassu

From: Roberto Sassu <roberto.sassu@huawei.com>

Remove hardcoded calls to integrity functions from the LSM infrastructure
and, instead, register them in integrity_lsm_init() with the IMA or EVM
LSM ID (the first non-NULL returned by ima_get_lsm_id() and
evm_get_lsm_id()).

Also move the global declaration of integrity_inode_get() to
security/integrity/integrity.h, so that the function can be still called by
IMA.

Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
---
 include/linux/integrity.h      | 26 --------------------------
 security/integrity/iint.c      | 30 +++++++++++++++++++++++++++++-
 security/integrity/integrity.h |  7 +++++++
 security/security.c            |  9 +--------
 4 files changed, 37 insertions(+), 35 deletions(-)

diff --git a/include/linux/integrity.h b/include/linux/integrity.h
index 2ea0f2f65ab6..afaae7ad26f4 100644
--- a/include/linux/integrity.h
+++ b/include/linux/integrity.h
@@ -21,38 +21,12 @@ enum integrity_status {
 
 /* 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)
 {
 }
 #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/iint.c b/security/integrity/iint.c
index 0b0ac71142e8..882fde2a2607 100644
--- a/security/integrity/iint.c
+++ b/security/integrity/iint.c
@@ -171,7 +171,7 @@ struct integrity_iint_cache *integrity_inode_get(struct inode *inode)
  *
  * Free the integrity information(iint) associated with an inode.
  */
-void integrity_inode_free(struct inode *inode)
+static void integrity_inode_free(struct inode *inode)
 {
 	struct integrity_iint_cache *iint;
 
@@ -193,11 +193,39 @@ static void iint_init_once(void *foo)
 	memset(iint, 0, sizeof(*iint));
 }
 
+static struct security_hook_list integrity_hooks[] __ro_after_init = {
+	LSM_HOOK_INIT(inode_free_security, integrity_inode_free),
+#ifdef CONFIG_INTEGRITY_ASYMMETRIC_KEYS
+	LSM_HOOK_INIT(kernel_module_request, integrity_kernel_module_request),
+#endif
+};
+
+/*
+ * Perform the initialization of the 'integrity', 'ima' and 'evm' LSMs to
+ * ensure that the management of integrity metadata is working at the time
+ * IMA and EVM hooks are registered to the LSM infrastructure, and to keep
+ * the original ordering of IMA and EVM functions as when they were hardcoded.
+ */
 static int __init integrity_lsm_init(void)
 {
+	const struct lsm_id *lsmid;
+
 	iint_cache =
 	    kmem_cache_create("iint_cache", sizeof(struct integrity_iint_cache),
 			      0, SLAB_PANIC, iint_init_once);
+	/*
+	 * Obtain either the IMA or EVM LSM ID to register integrity-specific
+	 * hooks under that LSM, since there is no LSM ID assigned to the
+	 * 'integrity' LSM.
+	 */
+	lsmid = ima_get_lsm_id();
+	if (!lsmid)
+		lsmid = evm_get_lsm_id();
+	/* No point in continuing, since both IMA and EVM are disabled. */
+	if (!lsmid)
+		return 0;
+
+	security_add_hooks(integrity_hooks, ARRAY_SIZE(integrity_hooks), lsmid);
 	init_ima_lsm();
 	init_evm_lsm();
 	return 0;
diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h
index 7534ec06324e..e4df82d6f6e7 100644
--- a/security/integrity/integrity.h
+++ b/security/integrity/integrity.h
@@ -180,6 +180,7 @@ struct integrity_iint_cache {
  * integrity data associated with an inode.
  */
 struct integrity_iint_cache *integrity_iint_find(struct inode *inode);
+struct integrity_iint_cache *integrity_inode_get(struct inode *inode);
 
 int integrity_kernel_read(struct file *file, loff_t offset,
 			  void *addr, unsigned long count);
@@ -266,12 +267,18 @@ static inline int __init integrity_load_cert(const unsigned int id,
 #ifdef CONFIG_INTEGRITY_ASYMMETRIC_KEYS
 int asymmetric_verify(struct key *keyring, const char *sig,
 		      int siglen, const char *data, int datalen);
+int integrity_kernel_module_request(char *kmod_name);
 #else
 static inline int asymmetric_verify(struct key *keyring, const char *sig,
 				    int siglen, const char *data, int datalen)
 {
 	return -EOPNOTSUPP;
 }
+
+static inline int integrity_kernel_module_request(char *kmod_name)
+{
+	return 0;
+}
 #endif
 
 #ifdef CONFIG_IMA_APPRAISE_MODSIG
diff --git a/security/security.c b/security/security.c
index 9703549b6ddc..0d9eaa4cd260 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
@@ -3182,12 +3180,7 @@ int security_kernel_create_files_as(struct cred *new, struct inode *inode)
  */
 int security_kernel_module_request(char *kmod_name)
 {
-	int ret;
-
-	ret = call_int_hook(kernel_module_request, 0, kmod_name);
-	if (ret)
-		return ret;
-	return integrity_kernel_module_request(kmod_name);
+	return call_int_hook(kernel_module_request, 0, kmod_name);
 }
 
 /**
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 96+ messages in thread

* [PATCH v5 23/23] integrity: Switch from rbtree to LSM-managed blob for integrity_iint_cache
  2023-11-07 13:39 [PATCH v5 00/23] security: Move IMA and EVM to the LSM infrastructure Roberto Sassu
                   ` (21 preceding siblings ...)
  2023-11-07 13:40 ` [PATCH v5 22/23] integrity: Move integrity functions to the " Roberto Sassu
@ 2023-11-07 13:40 ` Roberto Sassu
  2023-11-17 20:57   ` Paul Moore
  2023-11-07 14:05 ` [PATCH v5 00/23] security: Move IMA and EVM to the LSM infrastructure Roberto Sassu
  23 siblings, 1 reply; 96+ messages in thread
From: Roberto Sassu @ 2023-11-07 13:40 UTC (permalink / raw)
  To: viro, brauner, chuck.lever, jlayton, neilb, kolga, Dai.Ngo, tom,
	paul, jmorris, serge, zohar, dmitry.kasatkin, dhowells, jarkko,
	stephen.smalley.work, eparis, casey, mic
  Cc: linux-fsdevel, linux-kernel, linux-nfs, linux-security-module,
	linux-integrity, keyrings, selinux, Roberto Sassu

From: Roberto Sassu <roberto.sassu@huawei.com>

Before the security field of kernel objects could be shared among LSMs with
the LSM stacking feature, IMA and EVM had to rely on an alternative storage
of inode metadata. The association between inode metadata and inode is
maintained through an rbtree.

Because of this alternative storage mechanism, there was no need to use
disjoint inode metadata, so IMA and EVM today still share them.

With the reservation mechanism offered by the LSM infrastructure, the
rbtree is no longer necessary, as each LSM could reserve a space in the
security blob for each inode. However, since IMA and EVM share the
inode metadata, they cannot directly reserve the space for them.

Instead, request from the 'integrity' LSM a space in the security blob for
the pointer of inode metadata (integrity_iint_cache structure). The other
reason for keeping the 'integrity' LSM is to preserve the original ordering
of IMA and EVM functions as when they were hardcoded.

Prefer reserving space for a pointer to allocating the integrity_iint_cache
structure directly, as IMA would require it only for a subset of inodes.
Always allocating it would cause a waste of memory.

Introduce two primitives for getting and setting the pointer of
integrity_iint_cache in the security blob, respectively
integrity_inode_get_iint() and integrity_inode_set_iint(). This would make
the code more understandable, as they directly replace rbtree operations.

Locking is not needed, as access to inode metadata is not shared, it is per
inode.

Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
Reviewed-by: Casey Schaufler <casey@schaufler-ca.com>
---
 security/integrity/iint.c      | 71 +++++-----------------------------
 security/integrity/integrity.h | 20 +++++++++-
 2 files changed, 29 insertions(+), 62 deletions(-)

diff --git a/security/integrity/iint.c b/security/integrity/iint.c
index 882fde2a2607..a5edd3c70784 100644
--- a/security/integrity/iint.c
+++ b/security/integrity/iint.c
@@ -14,56 +14,25 @@
 #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;
+	return integrity_inode_get_iint(inode);
 }
 
 #define IMA_MAX_NESTING (FILESYSTEM_MAX_STACK_DEPTH+1)
@@ -123,9 +92,7 @@ static void iint_free(struct integrity_iint_cache *iint)
  */
 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;
+	struct integrity_iint_cache *iint;
 
 	iint = integrity_iint_find(inode);
 	if (iint)
@@ -137,31 +104,10 @@ struct integrity_iint_cache *integrity_inode_get(struct inode *inode)
 
 	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);
+	integrity_inode_set_iint(inode, iint);
 
-	write_unlock(&integrity_iint_lock);
 	return iint;
 }
 
@@ -178,10 +124,8 @@ static void integrity_inode_free(struct inode *inode)
 	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 = integrity_iint_find(inode);
+	integrity_inode_set_iint(inode, NULL);
 
 	iint_free(iint);
 }
@@ -231,6 +175,10 @@ static int __init integrity_lsm_init(void)
 	return 0;
 }
 
+struct lsm_blob_sizes integrity_blob_sizes __ro_after_init = {
+	.lbs_inode = sizeof(struct integrity_iint_cache *),
+};
+
 /*
  * Keep it until IMA and EVM can use disjoint integrity metadata, and their
  * initialization order can be swapped without change in their behavior.
@@ -239,6 +187,7 @@ DEFINE_LSM(integrity) = {
 	.name = "integrity",
 	.init = integrity_lsm_init,
 	.order = LSM_ORDER_LAST,
+	.blobs = &integrity_blob_sizes,
 };
 
 /*
diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h
index e4df82d6f6e7..ef2689b5264d 100644
--- a/security/integrity/integrity.h
+++ b/security/integrity/integrity.h
@@ -158,7 +158,6 @@ struct ima_file_id {
 
 /* 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 */
@@ -192,6 +191,25 @@ int integrity_kernel_read(struct file *file, loff_t offset,
 #define INTEGRITY_KEYRING_MAX		4
 
 extern struct dentry *integrity_dir;
+extern struct lsm_blob_sizes integrity_blob_sizes;
+
+static inline struct integrity_iint_cache *
+integrity_inode_get_iint(const struct inode *inode)
+{
+	struct integrity_iint_cache **iint_sec;
+
+	iint_sec = inode->i_security + integrity_blob_sizes.lbs_inode;
+	return *iint_sec;
+}
+
+static inline void integrity_inode_set_iint(const struct inode *inode,
+					    struct integrity_iint_cache *iint)
+{
+	struct integrity_iint_cache **iint_sec;
+
+	iint_sec = inode->i_security + integrity_blob_sizes.lbs_inode;
+	*iint_sec = iint;
+}
 
 struct modsig;
 
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 96+ messages in thread

* Re: [PATCH v5 00/23] security: Move IMA and EVM to the LSM infrastructure
  2023-11-07 13:39 [PATCH v5 00/23] security: Move IMA and EVM to the LSM infrastructure Roberto Sassu
                   ` (22 preceding siblings ...)
  2023-11-07 13:40 ` [PATCH v5 23/23] integrity: Switch from rbtree to LSM-managed blob for integrity_iint_cache Roberto Sassu
@ 2023-11-07 14:05 ` Roberto Sassu
  2023-11-07 19:37   ` Mimi Zohar
  2023-11-08  3:14   ` Paul Moore
  23 siblings, 2 replies; 96+ messages in thread
From: Roberto Sassu @ 2023-11-07 14:05 UTC (permalink / raw)
  To: viro, brauner, chuck.lever, jlayton, neilb, kolga, Dai.Ngo, tom,
	paul, jmorris, serge, zohar, dmitry.kasatkin, dhowells, jarkko,
	stephen.smalley.work, eparis, casey, mic
  Cc: linux-fsdevel, linux-kernel, linux-nfs, linux-security-module,
	linux-integrity, keyrings, selinux, Roberto Sassu

On Tue, 2023-11-07 at 14:39 +0100, Roberto Sassu wrote:
> From: Roberto Sassu <roberto.sassu@huawei.com>

Hi everyone

I kindly ask your support to add the missing reviewed-by/acked-by. I
summarize what is missing below:

- @Mimi: patches 1, 2, 4, 5, 6, 19, 21, 22, 23 (IMA/EVM-specific
         patches)
- @Al/@Christian: patches 10-17 (VFS-specific patches)
- @Paul: patches 10-23 (VFS-specific patches/new LSM hooks/new LSMs)
- @David Howells/@Jarkko: patch 18 (new LSM hook in the key subsystem)
- @Chuck Lever: patch 12 (new LSM hook in nfsd/vfs.c)

Paul, as I mentioned I currently based the patch set on lsm/dev-
staging, which include the following dependencies:

8f79e425c140 lsm: don't yet account for IMA in LSM_CONFIG_COUNT calculation
3c91a124f23d lsm: drop LSM_ID_IMA

I know you wanted to wait until at least rc1 to make lsm/dev. I will
help for rebasing my patch set, if needed.

Chuck, Mimi, there were two conflicts during the latest rebase:

d59b3515ab021 - nfsd: Handle EOPENSTALE correctly in the filecache
68279f9c9f59 - treewide: mark stuff as __ro_after_init

The first one required to change from 'goto out_nfserr' to 'goto out'
in the error path of patch 12.

The second one was automatically solved by kdiff3. It was because of
this change:

--- a/security/integrity/iint.c
+++ b/security/integrity/iint.c
@@ -23,7 +23,7 @@
 
 static struct rb_root integrity_iint_tree = RB_ROOT;
 static DEFINE_RWLOCK(integrity_iint_lock);
-static struct kmem_cache *iint_cache __read_mostly;
+static struct kmem_cache *iint_cache __ro_after_init;

I'm running the IMA tests for every patch set version. So far, no
issues detected:

https://github.com/robertosassu/ima-evm-utils/actions/runs/6774439916

Please let me know if I can help with the process.

Thanks

Roberto

> 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.
> 
> In short, while this patch set is big, it does not make any functional
> change to IMA and EVM. IMA and EVM functions are called by the LSM
> infrastructure in the same places as before (except ima_post_path_mknod()),
> rather being hardcoded calls, and the inode metadata pointer is directly
> stored in the inode security blob rather than in a separate rbtree.
> 
> To avoid functional changes, it was necessary to keep the 'integrity' LSM
> in addition to the newly introduced 'ima' and 'evm' LSMs, despite there is
> no LSM ID assigned to it. There are two reasons: first, IMA and EVM still
> share the same inode metadata, and thus cannot directly reserve space in
> the security blob for it; second, someone needs to initialize 'ima' and
> 'evm' exactly in this order, as the LSM infrastructure cannot guarantee
> that.
> 
> 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.
> 
> Patches 19-22 do the bulk of the work, introduce the new LSMs 'ima' and
> 'evm', and move hardcoded calls to IMA, EVM and integrity functions to
> those LSMs. In addition, they reserve one slot for the 'evm' LSM to supply
> an xattr with the inode_init_security hook.
> 
> Finally, patch 23 removes the rbtree used to bind integrity metadata to the
> inodes, and instead reserves a space in the inode security blob to store
> the pointer to that metadata. This also brings performance improvements due
> to retrieving metadata in constant time, as opposed to logarithmic.
> 
> The patch set applies on top of lsm/dev-staging, commit ba7ce019d3e9 ("lsm:
> convert security_setselfattr() to use memdup_user()"). No need to merge
> linux-integrity/next-integrity-testing.
> 
> Changelog:
> 
> 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 (23):
>   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_pre_free_security 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
>   ima: Move to LSM infrastructure
>   ima: Move IMA-Appraisal to LSM infrastructure
>   evm: Move to LSM infrastructure
>   integrity: Move integrity functions to the LSM infrastructure
>   integrity: Switch from rbtree to LSM-managed blob for
>     integrity_iint_cache
> 
>  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                   | 103 ----------
>  include/linux/ima.h                   | 142 --------------
>  include/linux/integrity.h             |  26 ---
>  include/linux/lsm_hook_defs.h         |  20 +-
>  include/linux/security.h              |  59 ++++++
>  include/uapi/linux/lsm.h              |   2 +
>  security/integrity/evm/evm_main.c     | 138 ++++++++++++--
>  security/integrity/iint.c             | 113 +++++------
>  security/integrity/ima/ima.h          |  11 ++
>  security/integrity/ima/ima_appraise.c |  37 +++-
>  security/integrity/ima/ima_main.c     |  96 ++++++++--
>  security/integrity/integrity.h        |  58 +++++-
>  security/keys/key.c                   |  10 +-
>  security/security.c                   | 261 ++++++++++++++++----------
>  security/selinux/hooks.c              |   3 +-
>  security/smack/smack_lsm.c            |   4 +-
>  23 files changed, 614 insertions(+), 507 deletions(-)
> 


^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v5 01/23] ima: Align ima_inode_post_setattr() definition with LSM infrastructure
  2023-11-07 13:39 ` [PATCH v5 01/23] ima: Align ima_inode_post_setattr() definition with " Roberto Sassu
@ 2023-11-07 17:21   ` Casey Schaufler
  0 siblings, 0 replies; 96+ messages in thread
From: Casey Schaufler @ 2023-11-07 17:21 UTC (permalink / raw)
  To: Roberto Sassu, viro, brauner, chuck.lever, jlayton, neilb, kolga,
	Dai.Ngo, tom, paul, jmorris, serge, zohar, dmitry.kasatkin,
	dhowells, jarkko, stephen.smalley.work, eparis, mic
  Cc: linux-fsdevel, linux-kernel, linux-nfs, linux-security-module,
	linux-integrity, keyrings, selinux, Roberto Sassu, Stefan Berger,
	Casey Schaufler

On 11/7/2023 5:39 AM, Roberto Sassu wrote:
> From: Roberto Sassu <roberto.sassu@huawei.com>
>
> Change ima_inode_post_setattr() definition, so that it can be registered as
> implementation of the inode_post_setattr hook (to be introduced).
>
> Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
> Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>

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

> ---
>  fs/attr.c                             | 2 +-
>  include/linux/ima.h                   | 4 ++--
>  security/integrity/ima/ima_appraise.c | 3 ++-
>  3 files changed, 5 insertions(+), 4 deletions(-)
>
> diff --git a/fs/attr.c b/fs/attr.c
> index bdf5deb06ea9..9bddc0a6352c 100644
> --- a/fs/attr.c
> +++ b/fs/attr.c
> @@ -502,7 +502,7 @@ int notify_change(struct mnt_idmap *idmap, struct dentry *dentry,
>  
>  	if (!error) {
>  		fsnotify_change(dentry, ia_valid);
> -		ima_inode_post_setattr(idmap, dentry);
> +		ima_inode_post_setattr(idmap, dentry, ia_valid);
>  		evm_inode_post_setattr(dentry, ia_valid);
>  	}
>  
> diff --git a/include/linux/ima.h b/include/linux/ima.h
> index 86b57757c7b1..910a2f11a906 100644
> --- a/include/linux/ima.h
> +++ b/include/linux/ima.h
> @@ -186,7 +186,7 @@ static inline void ima_post_key_create_or_update(struct key *keyring,
>  #ifdef CONFIG_IMA_APPRAISE
>  extern bool is_ima_appraise_enabled(void);
>  extern void ima_inode_post_setattr(struct mnt_idmap *idmap,
> -				   struct dentry *dentry);
> +				   struct dentry *dentry, int ia_valid);
>  extern int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name,
>  		       const void *xattr_value, size_t xattr_value_len);
>  extern int ima_inode_set_acl(struct mnt_idmap *idmap,
> @@ -206,7 +206,7 @@ static inline bool is_ima_appraise_enabled(void)
>  }
>  
>  static inline void ima_inode_post_setattr(struct mnt_idmap *idmap,
> -					  struct dentry *dentry)
> +					  struct dentry *dentry, int ia_valid)
>  {
>  	return;
>  }
> diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c
> index 870dde67707b..36c2938a5c69 100644
> --- a/security/integrity/ima/ima_appraise.c
> +++ b/security/integrity/ima/ima_appraise.c
> @@ -629,6 +629,7 @@ void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file)
>   * ima_inode_post_setattr - reflect file metadata changes
>   * @idmap:  idmap of the mount the inode was found from
>   * @dentry: pointer to the affected dentry
> + * @ia_valid: for the UID and GID status
>   *
>   * Changes to a dentry's metadata might result in needing to appraise.
>   *
> @@ -636,7 +637,7 @@ void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file)
>   * to lock the inode's i_mutex.
>   */
>  void ima_inode_post_setattr(struct mnt_idmap *idmap,
> -			    struct dentry *dentry)
> +			    struct dentry *dentry, int ia_valid)
>  {
>  	struct inode *inode = d_backing_inode(dentry);
>  	struct integrity_iint_cache *iint;

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v5 02/23] ima: Align ima_file_mprotect() definition with LSM infrastructure
  2023-11-07 13:39 ` [PATCH v5 02/23] ima: Align ima_file_mprotect() " Roberto Sassu
@ 2023-11-07 17:22   ` Casey Schaufler
  0 siblings, 0 replies; 96+ messages in thread
From: Casey Schaufler @ 2023-11-07 17:22 UTC (permalink / raw)
  To: Roberto Sassu, viro, brauner, chuck.lever, jlayton, neilb, kolga,
	Dai.Ngo, tom, paul, jmorris, serge, zohar, dmitry.kasatkin,
	dhowells, jarkko, stephen.smalley.work, eparis, mic
  Cc: linux-fsdevel, linux-kernel, linux-nfs, linux-security-module,
	linux-integrity, keyrings, selinux, Roberto Sassu, Stefan Berger,
	Casey Schaufler

On 11/7/2023 5:39 AM, Roberto Sassu wrote:
> From: Roberto Sassu <roberto.sassu@huawei.com>
>
> Change ima_file_mprotect() definition, so that it can be registered
> as implementation of the file_mprotect hook.
>
> Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
> Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>

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

> ---
>  include/linux/ima.h               | 5 +++--
>  security/integrity/ima/ima_main.c | 6 ++++--
>  security/security.c               | 2 +-
>  3 files changed, 8 insertions(+), 5 deletions(-)
>
> diff --git a/include/linux/ima.h b/include/linux/ima.h
> index 910a2f11a906..b66353f679e8 100644
> --- a/include/linux/ima.h
> +++ b/include/linux/ima.h
> @@ -23,7 +23,8 @@ extern void ima_post_create_tmpfile(struct mnt_idmap *idmap,
>  extern void ima_file_free(struct file *file);
>  extern int ima_file_mmap(struct file *file, unsigned long reqprot,
>  			 unsigned long prot, unsigned long flags);
> -extern int ima_file_mprotect(struct vm_area_struct *vma, unsigned long prot);
> +extern int ima_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot,
> +			     unsigned long prot);
>  extern int ima_load_data(enum kernel_load_data_id id, bool contents);
>  extern int ima_post_load_data(char *buf, loff_t size,
>  			      enum kernel_load_data_id id, char *description);
> @@ -84,7 +85,7 @@ static inline int ima_file_mmap(struct file *file, unsigned long reqprot,
>  }
>  
>  static inline int ima_file_mprotect(struct vm_area_struct *vma,
> -				    unsigned long prot)
> +				    unsigned long reqprot, unsigned long prot)
>  {
>  	return 0;
>  }
> diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
> index cc1217ac2c6f..b3f5e8401056 100644
> --- a/security/integrity/ima/ima_main.c
> +++ b/security/integrity/ima/ima_main.c
> @@ -455,7 +455,8 @@ int ima_file_mmap(struct file *file, unsigned long reqprot,
>  /**
>   * ima_file_mprotect - based on policy, limit mprotect change
>   * @vma: vm_area_struct protection is set to
> - * @prot: contains the protection that will be applied by the kernel.
> + * @reqprot: protection requested by the application
> + * @prot: protection that will be applied by the kernel
>   *
>   * Files can be mmap'ed read/write and later changed to execute to circumvent
>   * IMA's mmap appraisal policy rules.  Due to locking issues (mmap semaphore
> @@ -465,7 +466,8 @@ int ima_file_mmap(struct file *file, unsigned long reqprot,
>   *
>   * On mprotect change success, return 0.  On failure, return -EACESS.
>   */
> -int ima_file_mprotect(struct vm_area_struct *vma, unsigned long prot)
> +int ima_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot,
> +		      unsigned long prot)
>  {
>  	struct ima_template_desc *template = NULL;
>  	struct file *file;
> diff --git a/security/security.c b/security/security.c
> index d7b15ea67c3f..c87ba1bbd7dc 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -2819,7 +2819,7 @@ int security_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot,
>  	ret = call_int_hook(file_mprotect, 0, vma, reqprot, prot);
>  	if (ret)
>  		return ret;
> -	return ima_file_mprotect(vma, prot);
> +	return ima_file_mprotect(vma, reqprot, prot);
>  }
>  
>  /**

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v5 03/23] ima: Align ima_inode_setxattr() definition with LSM infrastructure
  2023-11-07 13:39 ` [PATCH v5 03/23] ima: Align ima_inode_setxattr() " Roberto Sassu
@ 2023-11-07 17:23   ` Casey Schaufler
  0 siblings, 0 replies; 96+ messages in thread
From: Casey Schaufler @ 2023-11-07 17:23 UTC (permalink / raw)
  To: Roberto Sassu, viro, brauner, chuck.lever, jlayton, neilb, kolga,
	Dai.Ngo, tom, paul, jmorris, serge, zohar, dmitry.kasatkin,
	dhowells, jarkko, stephen.smalley.work, eparis, mic
  Cc: linux-fsdevel, linux-kernel, linux-nfs, linux-security-module,
	linux-integrity, keyrings, selinux, Roberto Sassu, Stefan Berger,
	Casey Schaufler

On 11/7/2023 5:39 AM, Roberto Sassu wrote:
> From: Roberto Sassu <roberto.sassu@huawei.com>
>
> Change ima_inode_setxattr() definition, so that it can be registered as
> implementation of the inode_setxattr hook.
>
> Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
> Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
> Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>

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


> ---
>  include/linux/ima.h                   | 11 +++++++----
>  security/integrity/ima/ima_appraise.c |  5 +++--
>  security/security.c                   |  2 +-
>  3 files changed, 11 insertions(+), 7 deletions(-)
>
> diff --git a/include/linux/ima.h b/include/linux/ima.h
> index b66353f679e8..077324309c11 100644
> --- a/include/linux/ima.h
> +++ b/include/linux/ima.h
> @@ -188,8 +188,9 @@ static inline void ima_post_key_create_or_update(struct key *keyring,
>  extern bool is_ima_appraise_enabled(void);
>  extern void ima_inode_post_setattr(struct mnt_idmap *idmap,
>  				   struct dentry *dentry, int ia_valid);
> -extern int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name,
> -		       const void *xattr_value, size_t xattr_value_len);
> +extern int ima_inode_setxattr(struct mnt_idmap *idmap, struct dentry *dentry,
> +			      const char *xattr_name, const void *xattr_value,
> +			      size_t xattr_value_len, int flags);
>  extern int ima_inode_set_acl(struct mnt_idmap *idmap,
>  			     struct dentry *dentry, const char *acl_name,
>  			     struct posix_acl *kacl);
> @@ -212,10 +213,12 @@ static inline void ima_inode_post_setattr(struct mnt_idmap *idmap,
>  	return;
>  }
>  
> -static inline int ima_inode_setxattr(struct dentry *dentry,
> +static inline int ima_inode_setxattr(struct mnt_idmap *idmap,
> +				     struct dentry *dentry,
>  				     const char *xattr_name,
>  				     const void *xattr_value,
> -				     size_t xattr_value_len)
> +				     size_t xattr_value_len,
> +				     int flags)
>  {
>  	return 0;
>  }
> diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c
> index 36c2938a5c69..cb2d0d11aa77 100644
> --- a/security/integrity/ima/ima_appraise.c
> +++ b/security/integrity/ima/ima_appraise.c
> @@ -750,8 +750,9 @@ static int validate_hash_algo(struct dentry *dentry,
>  	return -EACCES;
>  }
>  
> -int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name,
> -		       const void *xattr_value, size_t xattr_value_len)
> +int ima_inode_setxattr(struct mnt_idmap *idmap, struct dentry *dentry,
> +		       const char *xattr_name, const void *xattr_value,
> +		       size_t xattr_value_len, int flags)
>  {
>  	const struct evm_ima_xattr_data *xvalue = xattr_value;
>  	int digsig = 0;
> diff --git a/security/security.c b/security/security.c
> index c87ba1bbd7dc..ec5c8065ea36 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -2269,7 +2269,7 @@ int security_inode_setxattr(struct mnt_idmap *idmap,
>  		ret = cap_inode_setxattr(dentry, name, value, size, flags);
>  	if (ret)
>  		return ret;
> -	ret = ima_inode_setxattr(dentry, name, value, size);
> +	ret = ima_inode_setxattr(idmap, dentry, name, value, size, flags);
>  	if (ret)
>  		return ret;
>  	return evm_inode_setxattr(idmap, dentry, name, value, size);

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v5 04/23] ima: Align ima_inode_removexattr() definition with LSM infrastructure
  2023-11-07 13:39 ` [PATCH v5 04/23] ima: Align ima_inode_removexattr() " Roberto Sassu
@ 2023-11-07 17:24   ` Casey Schaufler
  0 siblings, 0 replies; 96+ messages in thread
From: Casey Schaufler @ 2023-11-07 17:24 UTC (permalink / raw)
  To: Roberto Sassu, viro, brauner, chuck.lever, jlayton, neilb, kolga,
	Dai.Ngo, tom, paul, jmorris, serge, zohar, dmitry.kasatkin,
	dhowells, jarkko, stephen.smalley.work, eparis, mic
  Cc: linux-fsdevel, linux-kernel, linux-nfs, linux-security-module,
	linux-integrity, keyrings, selinux, Roberto Sassu, Stefan Berger,
	Casey Schaufler

On 11/7/2023 5:39 AM, Roberto Sassu wrote:
> From: Roberto Sassu <roberto.sassu@huawei.com>
>
> Change ima_inode_removexattr() definition, so that it can be registered as
> implementation of the inode_removexattr hook.
>
> Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
> Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>

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


> ---
>  include/linux/ima.h                   | 7 +++++--
>  security/integrity/ima/ima_appraise.c | 3 ++-
>  security/security.c                   | 2 +-
>  3 files changed, 8 insertions(+), 4 deletions(-)
>
> diff --git a/include/linux/ima.h b/include/linux/ima.h
> index 077324309c11..678a03fddd7e 100644
> --- a/include/linux/ima.h
> +++ b/include/linux/ima.h
> @@ -200,7 +200,9 @@ static inline int ima_inode_remove_acl(struct mnt_idmap *idmap,
>  {
>  	return ima_inode_set_acl(idmap, dentry, acl_name, NULL);
>  }
> -extern int ima_inode_removexattr(struct dentry *dentry, const char *xattr_name);
> +
> +extern int ima_inode_removexattr(struct mnt_idmap *idmap, struct dentry *dentry,
> +				 const char *xattr_name);
>  #else
>  static inline bool is_ima_appraise_enabled(void)
>  {
> @@ -231,7 +233,8 @@ static inline int ima_inode_set_acl(struct mnt_idmap *idmap,
>  	return 0;
>  }
>  
> -static inline int ima_inode_removexattr(struct dentry *dentry,
> +static inline int ima_inode_removexattr(struct mnt_idmap *idmap,
> +					struct dentry *dentry,
>  					const char *xattr_name)
>  {
>  	return 0;
> diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c
> index cb2d0d11aa77..36abc84ba299 100644
> --- a/security/integrity/ima/ima_appraise.c
> +++ b/security/integrity/ima/ima_appraise.c
> @@ -790,7 +790,8 @@ int ima_inode_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
>  	return 0;
>  }
>  
> -int ima_inode_removexattr(struct dentry *dentry, const char *xattr_name)
> +int ima_inode_removexattr(struct mnt_idmap *idmap, struct dentry *dentry,
> +			  const char *xattr_name)
>  {
>  	int result;
>  
> diff --git a/security/security.c b/security/security.c
> index ec5c8065ea36..358ec01a5492 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -2430,7 +2430,7 @@ int security_inode_removexattr(struct mnt_idmap *idmap,
>  		ret = cap_inode_removexattr(idmap, dentry, name);
>  	if (ret)
>  		return ret;
> -	ret = ima_inode_removexattr(dentry, name);
> +	ret = ima_inode_removexattr(idmap, dentry, name);
>  	if (ret)
>  		return ret;
>  	return evm_inode_removexattr(idmap, dentry, name);

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v5 05/23] ima: Align ima_post_read_file() definition with LSM infrastructure
  2023-11-07 13:39 ` [PATCH v5 05/23] ima: Align ima_post_read_file() " Roberto Sassu
@ 2023-11-07 17:25   ` Casey Schaufler
  0 siblings, 0 replies; 96+ messages in thread
From: Casey Schaufler @ 2023-11-07 17:25 UTC (permalink / raw)
  To: Roberto Sassu, viro, brauner, chuck.lever, jlayton, neilb, kolga,
	Dai.Ngo, tom, paul, jmorris, serge, zohar, dmitry.kasatkin,
	dhowells, jarkko, stephen.smalley.work, eparis, mic
  Cc: linux-fsdevel, linux-kernel, linux-nfs, linux-security-module,
	linux-integrity, keyrings, selinux, Roberto Sassu, Stefan Berger,
	Casey Schaufler

On 11/7/2023 5:39 AM, Roberto Sassu wrote:
> From: Roberto Sassu <roberto.sassu@huawei.com>
>
> Change ima_post_read_file() definition, by making "void *buf" a
> "char *buf", so that it can be registered as implementation of the
> post_read_file hook.
>
> Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
> Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>

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


> ---
>  include/linux/ima.h               | 4 ++--
>  security/integrity/ima/ima_main.c | 2 +-
>  2 files changed, 3 insertions(+), 3 deletions(-)
>
> diff --git a/include/linux/ima.h b/include/linux/ima.h
> index 678a03fddd7e..31ef6c3c3207 100644
> --- a/include/linux/ima.h
> +++ b/include/linux/ima.h
> @@ -30,7 +30,7 @@ extern int ima_post_load_data(char *buf, loff_t size,
>  			      enum kernel_load_data_id id, char *description);
>  extern int ima_read_file(struct file *file, enum kernel_read_file_id id,
>  			 bool contents);
> -extern int ima_post_read_file(struct file *file, void *buf, loff_t size,
> +extern int ima_post_read_file(struct file *file, char *buf, loff_t size,
>  			      enum kernel_read_file_id id);
>  extern void ima_post_path_mknod(struct mnt_idmap *idmap,
>  				struct dentry *dentry);
> @@ -108,7 +108,7 @@ static inline int ima_read_file(struct file *file, enum kernel_read_file_id id,
>  	return 0;
>  }
>  
> -static inline int ima_post_read_file(struct file *file, void *buf, loff_t size,
> +static inline int ima_post_read_file(struct file *file, char *buf, loff_t size,
>  				     enum kernel_read_file_id id)
>  {
>  	return 0;
> diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
> index b3f5e8401056..02021ee467d3 100644
> --- a/security/integrity/ima/ima_main.c
> +++ b/security/integrity/ima/ima_main.c
> @@ -803,7 +803,7 @@ const int read_idmap[READING_MAX_ID] = {
>   * On success return 0.  On integrity appraisal error, assuming the file
>   * is in policy and IMA-appraisal is in enforcing mode, return -EACCES.
>   */
> -int ima_post_read_file(struct file *file, void *buf, loff_t size,
> +int ima_post_read_file(struct file *file, char *buf, loff_t size,
>  		       enum kernel_read_file_id read_id)
>  {
>  	enum ima_hooks func;

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v5 06/23] evm: Align evm_inode_post_setattr() definition with LSM infrastructure
  2023-11-07 13:39 ` [PATCH v5 06/23] evm: Align evm_inode_post_setattr() " Roberto Sassu
@ 2023-11-07 17:26   ` Casey Schaufler
  0 siblings, 0 replies; 96+ messages in thread
From: Casey Schaufler @ 2023-11-07 17:26 UTC (permalink / raw)
  To: Roberto Sassu, viro, brauner, chuck.lever, jlayton, neilb, kolga,
	Dai.Ngo, tom, paul, jmorris, serge, zohar, dmitry.kasatkin,
	dhowells, jarkko, stephen.smalley.work, eparis, mic
  Cc: linux-fsdevel, linux-kernel, linux-nfs, linux-security-module,
	linux-integrity, keyrings, selinux, Roberto Sassu, Stefan Berger,
	Casey Schaufler

On 11/7/2023 5:39 AM, Roberto Sassu wrote:
> From: Roberto Sassu <roberto.sassu@huawei.com>
>
> Change evm_inode_post_setattr() definition, so that it can be registered as
> implementation of the inode_post_setattr hook (to be introduced).
>
> Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
> Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>

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


> ---
>  fs/attr.c                         | 2 +-
>  include/linux/evm.h               | 6 ++++--
>  security/integrity/evm/evm_main.c | 4 +++-
>  3 files changed, 8 insertions(+), 4 deletions(-)
>
> diff --git a/fs/attr.c b/fs/attr.c
> index 9bddc0a6352c..498e673bdf06 100644
> --- a/fs/attr.c
> +++ b/fs/attr.c
> @@ -503,7 +503,7 @@ int notify_change(struct mnt_idmap *idmap, struct dentry *dentry,
>  	if (!error) {
>  		fsnotify_change(dentry, ia_valid);
>  		ima_inode_post_setattr(idmap, dentry, ia_valid);
> -		evm_inode_post_setattr(dentry, ia_valid);
> +		evm_inode_post_setattr(idmap, dentry, ia_valid);
>  	}
>  
>  	return error;
> diff --git a/include/linux/evm.h b/include/linux/evm.h
> index 01fc495a83e2..cf976d8dbd7a 100644
> --- a/include/linux/evm.h
> +++ b/include/linux/evm.h
> @@ -23,7 +23,8 @@ extern enum integrity_status evm_verifyxattr(struct dentry *dentry,
>  					     struct integrity_iint_cache *iint);
>  extern int evm_inode_setattr(struct mnt_idmap *idmap,
>  			     struct dentry *dentry, struct iattr *attr);
> -extern void evm_inode_post_setattr(struct dentry *dentry, int ia_valid);
> +extern void evm_inode_post_setattr(struct mnt_idmap *idmap,
> +				   struct dentry *dentry, int ia_valid);
>  extern int evm_inode_setxattr(struct mnt_idmap *idmap,
>  			      struct dentry *dentry, const char *name,
>  			      const void *value, size_t size);
> @@ -97,7 +98,8 @@ static inline int evm_inode_setattr(struct mnt_idmap *idmap,
>  	return 0;
>  }
>  
> -static inline void evm_inode_post_setattr(struct dentry *dentry, int ia_valid)
> +static inline void evm_inode_post_setattr(struct mnt_idmap *idmap,
> +					  struct dentry *dentry, int ia_valid)
>  {
>  	return;
>  }
> diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c
> index 894570fe39bc..d452d469c503 100644
> --- a/security/integrity/evm/evm_main.c
> +++ b/security/integrity/evm/evm_main.c
> @@ -840,6 +840,7 @@ int evm_inode_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
>  
>  /**
>   * evm_inode_post_setattr - update 'security.evm' after modifying metadata
> + * @idmap: idmap of the idmapped mount
>   * @dentry: pointer to the affected dentry
>   * @ia_valid: for the UID and GID status
>   *
> @@ -849,7 +850,8 @@ int evm_inode_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
>   * This function is called from notify_change(), which expects the caller
>   * to lock the inode's i_mutex.
>   */
> -void evm_inode_post_setattr(struct dentry *dentry, int ia_valid)
> +void evm_inode_post_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
> +			    int ia_valid)
>  {
>  	if (!evm_revalidate_status(NULL))
>  		return;

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v5 07/23] evm: Align evm_inode_setxattr() definition with LSM infrastructure
  2023-11-07 13:39 ` [PATCH v5 07/23] evm: Align evm_inode_setxattr() " Roberto Sassu
@ 2023-11-07 17:27   ` Casey Schaufler
  0 siblings, 0 replies; 96+ messages in thread
From: Casey Schaufler @ 2023-11-07 17:27 UTC (permalink / raw)
  To: Roberto Sassu, viro, brauner, chuck.lever, jlayton, neilb, kolga,
	Dai.Ngo, tom, paul, jmorris, serge, zohar, dmitry.kasatkin,
	dhowells, jarkko, stephen.smalley.work, eparis, mic
  Cc: linux-fsdevel, linux-kernel, linux-nfs, linux-security-module,
	linux-integrity, keyrings, selinux, Roberto Sassu, Stefan Berger,
	Casey Schaufler

On 11/7/2023 5:39 AM, Roberto Sassu wrote:
> From: Roberto Sassu <roberto.sassu@huawei.com>
>
> Change evm_inode_setxattr() definition, so that it can be registered as
> implementation of the inode_setxattr hook.
>
> Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
> Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
> Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>

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


> ---
>  include/linux/evm.h               | 4 ++--
>  security/integrity/evm/evm_main.c | 3 ++-
>  security/security.c               | 2 +-
>  3 files changed, 5 insertions(+), 4 deletions(-)
>
> diff --git a/include/linux/evm.h b/include/linux/evm.h
> index cf976d8dbd7a..7c6a74dbc093 100644
> --- a/include/linux/evm.h
> +++ b/include/linux/evm.h
> @@ -27,7 +27,7 @@ extern void evm_inode_post_setattr(struct mnt_idmap *idmap,
>  				   struct dentry *dentry, int ia_valid);
>  extern int evm_inode_setxattr(struct mnt_idmap *idmap,
>  			      struct dentry *dentry, const char *name,
> -			      const void *value, size_t size);
> +			      const void *value, size_t size, int flags);
>  extern void evm_inode_post_setxattr(struct dentry *dentry,
>  				    const char *xattr_name,
>  				    const void *xattr_value,
> @@ -106,7 +106,7 @@ static inline void evm_inode_post_setattr(struct mnt_idmap *idmap,
>  
>  static inline int evm_inode_setxattr(struct mnt_idmap *idmap,
>  				     struct dentry *dentry, const char *name,
> -				     const void *value, size_t size)
> +				     const void *value, size_t size, int flags)
>  {
>  	return 0;
>  }
> diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c
> index d452d469c503..7fc083d53fdf 100644
> --- a/security/integrity/evm/evm_main.c
> +++ b/security/integrity/evm/evm_main.c
> @@ -558,6 +558,7 @@ static int evm_protect_xattr(struct mnt_idmap *idmap,
>   * @xattr_name: pointer to the affected extended attribute name
>   * @xattr_value: pointer to the new extended attribute value
>   * @xattr_value_len: pointer to the new extended attribute value length
> + * @flags: flags to pass into filesystem operations
>   *
>   * Before allowing the 'security.evm' protected xattr to be updated,
>   * verify the existing value is valid.  As only the kernel should have
> @@ -567,7 +568,7 @@ static int evm_protect_xattr(struct mnt_idmap *idmap,
>   */
>  int evm_inode_setxattr(struct mnt_idmap *idmap, struct dentry *dentry,
>  		       const char *xattr_name, const void *xattr_value,
> -		       size_t xattr_value_len)
> +		       size_t xattr_value_len, int flags)
>  {
>  	const struct evm_ima_xattr_data *xattr_data = xattr_value;
>  
> diff --git a/security/security.c b/security/security.c
> index 358ec01a5492..ae3625198c9f 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -2272,7 +2272,7 @@ int security_inode_setxattr(struct mnt_idmap *idmap,
>  	ret = ima_inode_setxattr(idmap, dentry, name, value, size, flags);
>  	if (ret)
>  		return ret;
> -	return evm_inode_setxattr(idmap, dentry, name, value, size);
> +	return evm_inode_setxattr(idmap, dentry, name, value, size, flags);
>  }
>  
>  /**

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v5 08/23] evm: Align evm_inode_post_setxattr() definition with LSM infrastructure
  2023-11-07 13:39 ` [PATCH v5 08/23] evm: Align evm_inode_post_setxattr() " Roberto Sassu
@ 2023-11-07 17:28   ` Casey Schaufler
  0 siblings, 0 replies; 96+ messages in thread
From: Casey Schaufler @ 2023-11-07 17:28 UTC (permalink / raw)
  To: Roberto Sassu, viro, brauner, chuck.lever, jlayton, neilb, kolga,
	Dai.Ngo, tom, paul, jmorris, serge, zohar, dmitry.kasatkin,
	dhowells, jarkko, stephen.smalley.work, eparis, mic
  Cc: linux-fsdevel, linux-kernel, linux-nfs, linux-security-module,
	linux-integrity, keyrings, selinux, Roberto Sassu, Stefan Berger,
	Casey Schaufler

On 11/7/2023 5:39 AM, Roberto Sassu wrote:
> From: Roberto Sassu <roberto.sassu@huawei.com>
>
> Change evm_inode_post_setxattr() definition, so that it can be registered
> as implementation of the inode_post_setxattr hook.
>
> Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
> Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
> Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>

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


> ---
>  include/linux/evm.h               | 8 +++++---
>  security/integrity/evm/evm_main.c | 4 +++-
>  security/security.c               | 2 +-
>  3 files changed, 9 insertions(+), 5 deletions(-)
>
> diff --git a/include/linux/evm.h b/include/linux/evm.h
> index 7c6a74dbc093..437d4076a3b3 100644
> --- a/include/linux/evm.h
> +++ b/include/linux/evm.h
> @@ -31,7 +31,8 @@ extern int evm_inode_setxattr(struct mnt_idmap *idmap,
>  extern void evm_inode_post_setxattr(struct dentry *dentry,
>  				    const char *xattr_name,
>  				    const void *xattr_value,
> -				    size_t xattr_value_len);
> +				    size_t xattr_value_len,
> +				    int flags);
>  extern int evm_inode_removexattr(struct mnt_idmap *idmap,
>  				 struct dentry *dentry, const char *xattr_name);
>  extern void evm_inode_post_removexattr(struct dentry *dentry,
> @@ -55,7 +56,7 @@ static inline void evm_inode_post_set_acl(struct dentry *dentry,
>  					  const char *acl_name,
>  					  struct posix_acl *kacl)
>  {
> -	return evm_inode_post_setxattr(dentry, acl_name, NULL, 0);
> +	return evm_inode_post_setxattr(dentry, acl_name, NULL, 0, 0);
>  }
>  
>  int evm_inode_init_security(struct inode *inode, struct inode *dir,
> @@ -114,7 +115,8 @@ static inline int evm_inode_setxattr(struct mnt_idmap *idmap,
>  static inline void evm_inode_post_setxattr(struct dentry *dentry,
>  					   const char *xattr_name,
>  					   const void *xattr_value,
> -					   size_t xattr_value_len)
> +					   size_t xattr_value_len,
> +					   int flags)
>  {
>  	return;
>  }
> diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c
> index 7fc083d53fdf..ea84a6f835ff 100644
> --- a/security/integrity/evm/evm_main.c
> +++ b/security/integrity/evm/evm_main.c
> @@ -730,6 +730,7 @@ bool evm_revalidate_status(const char *xattr_name)
>   * @xattr_name: pointer to the affected extended attribute name
>   * @xattr_value: pointer to the new extended attribute value
>   * @xattr_value_len: pointer to the new extended attribute value length
> + * @flags: flags to pass into filesystem operations
>   *
>   * Update the HMAC stored in 'security.evm' to reflect the change.
>   *
> @@ -738,7 +739,8 @@ bool evm_revalidate_status(const char *xattr_name)
>   * i_mutex lock.
>   */
>  void evm_inode_post_setxattr(struct dentry *dentry, const char *xattr_name,
> -			     const void *xattr_value, size_t xattr_value_len)
> +			     const void *xattr_value, size_t xattr_value_len,
> +			     int flags)
>  {
>  	if (!evm_revalidate_status(xattr_name))
>  		return;
> diff --git a/security/security.c b/security/security.c
> index ae3625198c9f..53793f3cb36a 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -2367,7 +2367,7 @@ void security_inode_post_setxattr(struct dentry *dentry, const char *name,
>  	if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
>  		return;
>  	call_void_hook(inode_post_setxattr, dentry, name, value, size, flags);
> -	evm_inode_post_setxattr(dentry, name, value, size);
> +	evm_inode_post_setxattr(dentry, name, value, size, flags);
>  }
>  
>  /**

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v5 10/23] security: Introduce inode_post_setattr hook
  2023-11-07 13:39 ` [PATCH v5 10/23] security: Introduce inode_post_setattr hook Roberto Sassu
@ 2023-11-07 17:30   ` Casey Schaufler
  2023-11-16  4:33   ` Paul Moore
  1 sibling, 0 replies; 96+ messages in thread
From: Casey Schaufler @ 2023-11-07 17:30 UTC (permalink / raw)
  To: Roberto Sassu, viro, brauner, chuck.lever, jlayton, neilb, kolga,
	Dai.Ngo, tom, paul, jmorris, serge, zohar, dmitry.kasatkin,
	dhowells, jarkko, stephen.smalley.work, eparis, mic
  Cc: linux-fsdevel, linux-kernel, linux-nfs, linux-security-module,
	linux-integrity, keyrings, selinux, Roberto Sassu, Stefan Berger,
	Casey Schaufler

On 11/7/2023 5:39 AM, 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_setattr hook.
>
> At inode_setattr hook, EVM verifies the file's existing HMAC value. At
> inode_post_setattr, EVM re-calculates the file's HMAC based on the modified
> file attributes and other file metadata.
>
> Other LSMs could similarly take some action after successful file attribute
> change.
>
> 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>
> Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>

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


> ---
>  fs/attr.c                     |  1 +
>  include/linux/lsm_hook_defs.h |  2 ++
>  include/linux/security.h      |  7 +++++++
>  security/security.c           | 16 ++++++++++++++++
>  4 files changed, 26 insertions(+)
>
> diff --git a/fs/attr.c b/fs/attr.c
> index 498e673bdf06..221d2bb0a906 100644
> --- a/fs/attr.c
> +++ b/fs/attr.c
> @@ -502,6 +502,7 @@ int notify_change(struct mnt_idmap *idmap, struct dentry *dentry,
>  
>  	if (!error) {
>  		fsnotify_change(dentry, ia_valid);
> +		security_inode_post_setattr(idmap, dentry, ia_valid);
>  		ima_inode_post_setattr(idmap, dentry, ia_valid);
>  		evm_inode_post_setattr(idmap, dentry, ia_valid);
>  	}
> diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
> index f5db5e993cd8..67410e085205 100644
> --- a/include/linux/lsm_hook_defs.h
> +++ b/include/linux/lsm_hook_defs.h
> @@ -137,6 +137,8 @@ LSM_HOOK(int, 0, inode_follow_link, struct dentry *dentry, struct inode *inode,
>  LSM_HOOK(int, 0, inode_permission, struct inode *inode, int mask)
>  LSM_HOOK(int, 0, inode_setattr, struct mnt_idmap *idmap, struct dentry *dentry,
>  	 struct iattr *attr)
> +LSM_HOOK(void, LSM_RET_VOID, inode_post_setattr, struct mnt_idmap *idmap,
> +	 struct dentry *dentry, int ia_valid)
>  LSM_HOOK(int, 0, inode_getattr, const struct path *path)
>  LSM_HOOK(int, 0, inode_setxattr, struct mnt_idmap *idmap,
>  	 struct dentry *dentry, const char *name, const void *value,
> diff --git a/include/linux/security.h b/include/linux/security.h
> index 750130a7b9dd..664df46b22a9 100644
> --- a/include/linux/security.h
> +++ b/include/linux/security.h
> @@ -361,6 +361,8 @@ int security_inode_follow_link(struct dentry *dentry, struct inode *inode,
>  int security_inode_permission(struct inode *inode, int mask);
>  int security_inode_setattr(struct mnt_idmap *idmap,
>  			   struct dentry *dentry, struct iattr *attr);
> +void security_inode_post_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
> +				 int ia_valid);
>  int security_inode_getattr(const struct path *path);
>  int security_inode_setxattr(struct mnt_idmap *idmap,
>  			    struct dentry *dentry, const char *name,
> @@ -877,6 +879,11 @@ static inline int security_inode_setattr(struct mnt_idmap *idmap,
>  	return 0;
>  }
>  
> +static inline void
> +security_inode_post_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
> +			    int ia_valid)
> +{ }
> +
>  static inline int security_inode_getattr(const struct path *path)
>  {
>  	return 0;
> diff --git a/security/security.c b/security/security.c
> index 7935d11d58b5..ce3bc7642e18 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -2222,6 +2222,22 @@ int security_inode_setattr(struct mnt_idmap *idmap,
>  }
>  EXPORT_SYMBOL_GPL(security_inode_setattr);
>  
> +/**
> + * security_inode_post_setattr() - Update the inode after a setattr operation
> + * @idmap: idmap of the mount
> + * @dentry: file
> + * @ia_valid: file attributes set
> + *
> + * Update inode security field after successful setting file attributes.
> + */
> +void security_inode_post_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
> +				 int ia_valid)
> +{
> +	if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
> +		return;
> +	call_void_hook(inode_post_setattr, idmap, dentry, ia_valid);
> +}
> +
>  /**
>   * security_inode_getattr() - Check if getting file attributes is allowed
>   * @path: file

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v5 11/23] security: Introduce inode_post_removexattr hook
  2023-11-07 13:40 ` [PATCH v5 11/23] security: Introduce inode_post_removexattr hook Roberto Sassu
@ 2023-11-07 17:33   ` Casey Schaufler
  2023-11-07 17:45     ` Roberto Sassu
  2023-11-20 17:31     ` Roberto Sassu
  2023-11-16  4:33   ` Paul Moore
  1 sibling, 2 replies; 96+ messages in thread
From: Casey Schaufler @ 2023-11-07 17:33 UTC (permalink / raw)
  To: Roberto Sassu, viro, brauner, chuck.lever, jlayton, neilb, kolga,
	Dai.Ngo, tom, paul, jmorris, serge, zohar, dmitry.kasatkin,
	dhowells, jarkko, stephen.smalley.work, eparis, mic
  Cc: linux-fsdevel, linux-kernel, linux-nfs, linux-security-module,
	linux-integrity, keyrings, selinux, Roberto Sassu, Stefan Berger,
	Casey Schaufler

On 11/7/2023 5:40 AM, 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_removexattr hook.
>
> At inode_removexattr hook, EVM verifies the file's existing HMAC value. At
> inode_post_removexattr, EVM re-calculates the file's HMAC with the passed
> xattr removed and other file metadata.
>
> Other LSMs could similarly take some action after successful xattr removal.
>
> 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>
> Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
> ---
>  fs/xattr.c                    |  9 +++++----
>  include/linux/lsm_hook_defs.h |  2 ++
>  include/linux/security.h      |  5 +++++
>  security/security.c           | 14 ++++++++++++++
>  4 files changed, 26 insertions(+), 4 deletions(-)
>
> diff --git a/fs/xattr.c b/fs/xattr.c
> index 09d927603433..84a4aa566c02 100644
> --- a/fs/xattr.c
> +++ b/fs/xattr.c
> @@ -552,11 +552,12 @@ __vfs_removexattr_locked(struct mnt_idmap *idmap,
>  		goto out;
>  
>  	error = __vfs_removexattr(idmap, dentry, name);
> +	if (error)
> +		goto out;

Shouldn't this be simply "return error" rather than a goto to nothing
but "return error"?

>  
> -	if (!error) {
> -		fsnotify_xattr(dentry);
> -		evm_inode_post_removexattr(dentry, name);
> -	}
> +	fsnotify_xattr(dentry);
> +	security_inode_post_removexattr(dentry, name);
> +	evm_inode_post_removexattr(dentry, name);
>  
>  out:
>  	return error;
> diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
> index 67410e085205..88452e45025c 100644
> --- a/include/linux/lsm_hook_defs.h
> +++ b/include/linux/lsm_hook_defs.h
> @@ -149,6 +149,8 @@ LSM_HOOK(int, 0, inode_getxattr, struct dentry *dentry, const char *name)
>  LSM_HOOK(int, 0, inode_listxattr, struct dentry *dentry)
>  LSM_HOOK(int, 0, inode_removexattr, struct mnt_idmap *idmap,
>  	 struct dentry *dentry, const char *name)
> +LSM_HOOK(void, LSM_RET_VOID, inode_post_removexattr, struct dentry *dentry,
> +	 const char *name)
>  LSM_HOOK(int, 0, inode_set_acl, struct mnt_idmap *idmap,
>  	 struct dentry *dentry, const char *acl_name, struct posix_acl *kacl)
>  LSM_HOOK(int, 0, inode_get_acl, struct mnt_idmap *idmap,
> diff --git a/include/linux/security.h b/include/linux/security.h
> index 664df46b22a9..922ea7709bae 100644
> --- a/include/linux/security.h
> +++ b/include/linux/security.h
> @@ -380,6 +380,7 @@ int security_inode_getxattr(struct dentry *dentry, const char *name);
>  int security_inode_listxattr(struct dentry *dentry);
>  int security_inode_removexattr(struct mnt_idmap *idmap,
>  			       struct dentry *dentry, const char *name);
> +void security_inode_post_removexattr(struct dentry *dentry, const char *name);
>  int security_inode_need_killpriv(struct dentry *dentry);
>  int security_inode_killpriv(struct mnt_idmap *idmap, struct dentry *dentry);
>  int security_inode_getsecurity(struct mnt_idmap *idmap,
> @@ -940,6 +941,10 @@ static inline int security_inode_removexattr(struct mnt_idmap *idmap,
>  	return cap_inode_removexattr(idmap, dentry, name);
>  }
>  
> +static inline void security_inode_post_removexattr(struct dentry *dentry,
> +						   const char *name)
> +{ }
> +
>  static inline int security_inode_need_killpriv(struct dentry *dentry)
>  {
>  	return cap_inode_need_killpriv(dentry);
> diff --git a/security/security.c b/security/security.c
> index ce3bc7642e18..8aa6e9f316dd 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -2452,6 +2452,20 @@ int security_inode_removexattr(struct mnt_idmap *idmap,
>  	return evm_inode_removexattr(idmap, dentry, name);
>  }
>  
> +/**
> + * security_inode_post_removexattr() - Update the inode after a removexattr op
> + * @dentry: file
> + * @name: xattr name
> + *
> + * Update the inode after a successful removexattr operation.
> + */
> +void security_inode_post_removexattr(struct dentry *dentry, const char *name)
> +{
> +	if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
> +		return;
> +	call_void_hook(inode_post_removexattr, dentry, name);
> +}
> +
>  /**
>   * security_inode_need_killpriv() - Check if security_inode_killpriv() required
>   * @dentry: associated dentry

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v5 12/23] security: Introduce file_post_open hook
  2023-11-07 13:40 ` [PATCH v5 12/23] security: Introduce file_post_open hook Roberto Sassu
@ 2023-11-07 17:35   ` Casey Schaufler
  0 siblings, 0 replies; 96+ messages in thread
From: Casey Schaufler @ 2023-11-07 17:35 UTC (permalink / raw)
  To: Roberto Sassu, viro, brauner, chuck.lever, jlayton, neilb, kolga,
	Dai.Ngo, tom, paul, jmorris, serge, zohar, dmitry.kasatkin,
	dhowells, jarkko, stephen.smalley.work, eparis, mic
  Cc: linux-fsdevel, linux-kernel, linux-nfs, linux-security-module,
	linux-integrity, keyrings, selinux, Roberto Sassu, Stefan Berger,
	Casey Schaufler

On 11/7/2023 5:40 AM, 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>


> ---
>  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);
>  	if (!error)
>  		error = ima_file_check(file, op->acc_mode);
>  	if (!error && do_truncate)
> diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
> index fbbea7498f02..b0c3f07a8bba 100644
> --- a/fs/nfsd/vfs.c
> +++ b/fs/nfsd/vfs.c
> @@ -877,6 +877,12 @@ __nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type,
>  		goto out;
>  	}
>  
> +	host_err = security_file_post_open(file, may_flags);
> +	if (host_err) {
> +		fput(file);
> +		goto out;
> +	}
> +
>  	host_err = ima_file_check(file, may_flags);
>  	if (host_err) {
>  		fput(file);
> diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
> index 88452e45025c..4f6861fecacd 100644
> --- a/include/linux/lsm_hook_defs.h
> +++ b/include/linux/lsm_hook_defs.h
> @@ -189,6 +189,7 @@ LSM_HOOK(int, 0, file_send_sigiotask, struct task_struct *tsk,
>  	 struct fown_struct *fown, int sig)
>  LSM_HOOK(int, 0, file_receive, struct file *file)
>  LSM_HOOK(int, 0, file_open, struct file *file)
> +LSM_HOOK(int, 0, file_post_open, struct file *file, int mask)
>  LSM_HOOK(int, 0, file_truncate, struct file *file)
>  LSM_HOOK(int, 0, task_alloc, struct task_struct *task,
>  	 unsigned long clone_flags)
> diff --git a/include/linux/security.h b/include/linux/security.h
> index 922ea7709bae..c360458920b1 100644
> --- a/include/linux/security.h
> +++ b/include/linux/security.h
> @@ -409,6 +409,7 @@ int security_file_send_sigiotask(struct task_struct *tsk,
>  				 struct fown_struct *fown, int sig);
>  int security_file_receive(struct file *file);
>  int security_file_open(struct file *file);
> +int security_file_post_open(struct file *file, int mask);
>  int security_file_truncate(struct file *file);
>  int security_task_alloc(struct task_struct *task, unsigned long clone_flags);
>  void security_task_free(struct task_struct *task);
> @@ -1065,6 +1066,11 @@ static inline int security_file_open(struct file *file)
>  	return 0;
>  }
>  
> +static inline int security_file_post_open(struct file *file, int mask)
> +{
> +	return 0;
> +}
> +
>  static inline int security_file_truncate(struct file *file)
>  {
>  	return 0;
> diff --git a/security/security.c b/security/security.c
> index 8aa6e9f316dd..fe6a160afc35 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -2954,6 +2954,23 @@ int security_file_open(struct file *file)
>  	return fsnotify_perm(file, MAY_OPEN);
>  }
>  
> +/**
> + * security_file_post_open() - Evaluate a file after it has been opened
> + * @file: the file
> + * @mask: access mask
> + *
> + * Evaluate an opened file and the access mask requested with open(). The hook
> + * is useful for LSMs that require the file content to be available in order to
> + * make decisions.
> + *
> + * Return: Returns 0 if permission is granted.
> + */
> +int security_file_post_open(struct file *file, int mask)
> +{
> +	return call_int_hook(file_post_open, 0, file, mask);
> +}
> +EXPORT_SYMBOL_GPL(security_file_post_open);
> +
>  /**
>   * security_file_truncate() - Check if truncating a file is allowed
>   * @file: file

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v5 13/23] security: Introduce file_pre_free_security hook
  2023-11-07 13:40 ` [PATCH v5 13/23] security: Introduce file_pre_free_security hook Roberto Sassu
@ 2023-11-07 17:39   ` Casey Schaufler
  2023-11-16  4:33   ` Paul Moore
  1 sibling, 0 replies; 96+ messages in thread
From: Casey Schaufler @ 2023-11-07 17:39 UTC (permalink / raw)
  To: Roberto Sassu, viro, brauner, chuck.lever, jlayton, neilb, kolga,
	Dai.Ngo, tom, paul, jmorris, serge, zohar, dmitry.kasatkin,
	dhowells, jarkko, stephen.smalley.work, eparis, mic
  Cc: linux-fsdevel, linux-kernel, linux-nfs, linux-security-module,
	linux-integrity, keyrings, selinux, Roberto Sassu,
	Casey Schaufler

On 11/7/2023 5:40 AM, Roberto Sassu wrote:
> From: Roberto Sassu <roberto.sassu@huawei.com>
>
> In preparation for moving IMA and EVM to the LSM infrastructure, introduce
> the file_pre_free_security 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.
>
> LSMs could also take some action before the last reference of a file is
> released.
>
> The new hook cannot return an error and cannot cause the operation to be
> reverted.
>
> Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>

Acked-by: Casey Schaufler <casey@schaufler-ca.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..64ed74555e64 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_pre_free(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 4f6861fecacd..5d0a09ead7ac 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_pre_free_security, 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 c360458920b1..a570213693d9 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_pre_free(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_mmap_file(struct file *file, unsigned long prot,
> @@ -1006,6 +1007,9 @@ static inline int security_file_alloc(struct file *file)
>  	return 0;
>  }
>  
> +static inline void security_file_pre_free(struct file *file)
> +{ }
> +
>  static inline void security_file_free(struct file *file)
>  { }
>  
> diff --git a/security/security.c b/security/security.c
> index fe6a160afc35..331a3e5efb62 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -2724,6 +2724,17 @@ int security_file_alloc(struct file *file)
>  	return rc;
>  }
>  
> +/**
> + * security_file_pre_free() - Perform actions before releasing the file ref
> + * @file: the file
> + *
> + * Perform actions before releasing the last reference to a file.
> + */
> +void security_file_pre_free(struct file *file)
> +{
> +	call_void_hook(file_pre_free_security, file);
> +}
> +
>  /**
>   * security_file_free() - Free a file's LSM blob
>   * @file: the file

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v5 14/23] security: Introduce path_post_mknod hook
  2023-11-07 13:40 ` [PATCH v5 14/23] security: Introduce path_post_mknod hook Roberto Sassu
@ 2023-11-07 17:41   ` Casey Schaufler
  0 siblings, 0 replies; 96+ messages in thread
From: Casey Schaufler @ 2023-11-07 17:41 UTC (permalink / raw)
  To: Roberto Sassu, viro, brauner, chuck.lever, jlayton, neilb, kolga,
	Dai.Ngo, tom, paul, jmorris, serge, zohar, dmitry.kasatkin,
	dhowells, jarkko, stephen.smalley.work, eparis, mic
  Cc: linux-fsdevel, linux-kernel, linux-nfs, linux-security-module,
	linux-integrity, keyrings, selinux, Roberto Sassu,
	Casey Schaufler

On 11/7/2023 5:40 AM, Roberto Sassu wrote:
> From: Roberto Sassu <roberto.sassu@huawei.com>
>
> In preparation for moving IMA and EVM to the LSM infrastructure, introduce
> the path_post_mknod hook.
>
> IMA-appraisal requires all existing files in policy to have a file
> hash/signature stored in security.ima. An exception is made for empty files
> created by mknod, by tagging them as new files.
>
> LSMs could also take some action after files are created.
>
> The new hook cannot return an error and cannot cause the operation to be
> reverted.
>
> Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>

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


> ---
>  fs/namei.c                    |  5 +++++
>  include/linux/lsm_hook_defs.h |  2 ++
>  include/linux/security.h      |  5 +++++
>  security/security.c           | 14 ++++++++++++++
>  4 files changed, 26 insertions(+)
>
> diff --git a/fs/namei.c b/fs/namei.c
> index fb93d3e13df6..b7f433720b1e 100644
> --- a/fs/namei.c
> +++ b/fs/namei.c
> @@ -4047,6 +4047,11 @@ static int do_mknodat(int dfd, struct filename *name, umode_t mode,
>  					  dentry, mode, 0);
>  			break;
>  	}
> +
> +	if (error)
> +		goto out2;
> +
> +	security_path_post_mknod(idmap, dentry);
>  out2:
>  	done_path_create(&path, dentry);
>  	if (retry_estale(error, lookup_flags)) {
> diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
> index 5d0a09ead7ac..e491951399f7 100644
> --- a/include/linux/lsm_hook_defs.h
> +++ b/include/linux/lsm_hook_defs.h
> @@ -94,6 +94,8 @@ LSM_HOOK(int, 0, path_mkdir, const struct path *dir, struct dentry *dentry,
>  LSM_HOOK(int, 0, path_rmdir, const struct path *dir, struct dentry *dentry)
>  LSM_HOOK(int, 0, path_mknod, const struct path *dir, struct dentry *dentry,
>  	 umode_t mode, unsigned int dev)
> +LSM_HOOK(void, LSM_RET_VOID, path_post_mknod, struct mnt_idmap *idmap,
> +	 struct dentry *dentry)
>  LSM_HOOK(int, 0, path_truncate, const struct path *path)
>  LSM_HOOK(int, 0, path_symlink, const struct path *dir, struct dentry *dentry,
>  	 const char *old_name)
> diff --git a/include/linux/security.h b/include/linux/security.h
> index a570213693d9..68cbdc84506e 100644
> --- a/include/linux/security.h
> +++ b/include/linux/security.h
> @@ -1884,6 +1884,7 @@ int security_path_mkdir(const struct path *dir, struct dentry *dentry, umode_t m
>  int security_path_rmdir(const struct path *dir, struct dentry *dentry);
>  int security_path_mknod(const struct path *dir, struct dentry *dentry, umode_t mode,
>  			unsigned int dev);
> +void security_path_post_mknod(struct mnt_idmap *idmap, struct dentry *dentry);
>  int security_path_truncate(const struct path *path);
>  int security_path_symlink(const struct path *dir, struct dentry *dentry,
>  			  const char *old_name);
> @@ -1918,6 +1919,10 @@ static inline int security_path_mknod(const struct path *dir, struct dentry *den
>  	return 0;
>  }
>  
> +static inline void security_path_post_mknod(struct mnt_idmap *idmap,
> +					    struct dentry *dentry)
> +{ }
> +
>  static inline int security_path_truncate(const struct path *path)
>  {
>  	return 0;
> diff --git a/security/security.c b/security/security.c
> index 331a3e5efb62..5eaf5f2aa5ea 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -1800,6 +1800,20 @@ int security_path_mknod(const struct path *dir, struct dentry *dentry,
>  }
>  EXPORT_SYMBOL(security_path_mknod);
>  
> +/**
> + * security_path_post_mknod() - Update inode security field after file creation
> + * @idmap: idmap of the mount
> + * @dentry: new file
> + *
> + * Update inode security field after a file has been created.
> + */
> +void security_path_post_mknod(struct mnt_idmap *idmap, struct dentry *dentry)
> +{
> +	if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
> +		return;
> +	call_void_hook(path_post_mknod, idmap, dentry);
> +}
> +
>  /**
>   * security_path_mkdir() - Check if creating a new directory is allowed
>   * @dir: parent directory

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v5 15/23] security: Introduce inode_post_create_tmpfile hook
  2023-11-07 13:40 ` [PATCH v5 15/23] security: Introduce inode_post_create_tmpfile hook Roberto Sassu
@ 2023-11-07 17:42   ` Casey Schaufler
  2023-11-16  4:33   ` Paul Moore
  1 sibling, 0 replies; 96+ messages in thread
From: Casey Schaufler @ 2023-11-07 17:42 UTC (permalink / raw)
  To: Roberto Sassu, viro, brauner, chuck.lever, jlayton, neilb, kolga,
	Dai.Ngo, tom, paul, jmorris, serge, zohar, dmitry.kasatkin,
	dhowells, jarkko, stephen.smalley.work, eparis, mic
  Cc: linux-fsdevel, linux-kernel, linux-nfs, linux-security-module,
	linux-integrity, keyrings, selinux, Roberto Sassu,
	Casey Schaufler

On 11/7/2023 5:40 AM, 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>


> ---
>  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 e491951399f7..ec5319ec2e85 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 68cbdc84506e..0c85f0337a9e 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);
> @@ -809,6 +811,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 5eaf5f2aa5ea..ca650c285fd9 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

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v5 16/23] security: Introduce inode_post_set_acl hook
  2023-11-07 13:40 ` [PATCH v5 16/23] security: Introduce inode_post_set_acl hook Roberto Sassu
@ 2023-11-07 17:44   ` Casey Schaufler
  2023-11-16  4:33   ` Paul Moore
  1 sibling, 0 replies; 96+ messages in thread
From: Casey Schaufler @ 2023-11-07 17:44 UTC (permalink / raw)
  To: Roberto Sassu, viro, brauner, chuck.lever, jlayton, neilb, kolga,
	Dai.Ngo, tom, paul, jmorris, serge, zohar, dmitry.kasatkin,
	dhowells, jarkko, stephen.smalley.work, eparis, mic
  Cc: linux-fsdevel, linux-kernel, linux-nfs, linux-security-module,
	linux-integrity, keyrings, selinux, Roberto Sassu, Stefan Berger,
	Casey Schaufler

On 11/7/2023 5:40 AM, 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_set_acl hook.
>
> At inode_set_acl hook, EVM verifies the file's existing HMAC value. At
> inode_post_set_acl, EVM re-calculates the file's HMAC based on the modified
> POSIX ACL and other file metadata.
>
> Other LSMs could similarly take some action after successful POSIX ACL
> change.
>
> 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>

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


> ---
>  fs/posix_acl.c                |  1 +
>  include/linux/lsm_hook_defs.h |  2 ++
>  include/linux/security.h      |  7 +++++++
>  security/security.c           | 17 +++++++++++++++++
>  4 files changed, 27 insertions(+)
>
> diff --git a/fs/posix_acl.c b/fs/posix_acl.c
> index a05fe94970ce..58e3c1e2fbbc 100644
> --- a/fs/posix_acl.c
> +++ b/fs/posix_acl.c
> @@ -1137,6 +1137,7 @@ int vfs_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
>  		error = -EIO;
>  	if (!error) {
>  		fsnotify_xattr(dentry);
> +		security_inode_post_set_acl(dentry, acl_name, kacl);
>  		evm_inode_post_set_acl(dentry, acl_name, kacl);
>  	}
>  
> diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
> index ec5319ec2e85..6a671616196f 100644
> --- a/include/linux/lsm_hook_defs.h
> +++ b/include/linux/lsm_hook_defs.h
> @@ -157,6 +157,8 @@ LSM_HOOK(void, LSM_RET_VOID, inode_post_removexattr, struct dentry *dentry,
>  	 const char *name)
>  LSM_HOOK(int, 0, inode_set_acl, struct mnt_idmap *idmap,
>  	 struct dentry *dentry, const char *acl_name, struct posix_acl *kacl)
> +LSM_HOOK(void, LSM_RET_VOID, inode_post_set_acl, struct dentry *dentry,
> +	 const char *acl_name, struct posix_acl *kacl)
>  LSM_HOOK(int, 0, inode_get_acl, struct mnt_idmap *idmap,
>  	 struct dentry *dentry, const char *acl_name)
>  LSM_HOOK(int, 0, inode_remove_acl, struct mnt_idmap *idmap,
> diff --git a/include/linux/security.h b/include/linux/security.h
> index 0c85f0337a9e..d71d0b08e9fe 100644
> --- a/include/linux/security.h
> +++ b/include/linux/security.h
> @@ -372,6 +372,8 @@ int security_inode_setxattr(struct mnt_idmap *idmap,
>  int security_inode_set_acl(struct mnt_idmap *idmap,
>  			   struct dentry *dentry, const char *acl_name,
>  			   struct posix_acl *kacl);
> +void security_inode_post_set_acl(struct dentry *dentry, const char *acl_name,
> +				 struct posix_acl *kacl);
>  int security_inode_get_acl(struct mnt_idmap *idmap,
>  			   struct dentry *dentry, const char *acl_name);
>  int security_inode_remove_acl(struct mnt_idmap *idmap,
> @@ -913,6 +915,11 @@ static inline int security_inode_set_acl(struct mnt_idmap *idmap,
>  	return 0;
>  }
>  
> +static inline void security_inode_post_set_acl(struct dentry *dentry,
> +					       const char *acl_name,
> +					       struct posix_acl *kacl)
> +{ }
> +
>  static inline int security_inode_get_acl(struct mnt_idmap *idmap,
>  					 struct dentry *dentry,
>  					 const char *acl_name)
> diff --git a/security/security.c b/security/security.c
> index ca650c285fd9..d2dbea54a63a 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -2350,6 +2350,23 @@ int security_inode_set_acl(struct mnt_idmap *idmap,
>  	return evm_inode_set_acl(idmap, dentry, acl_name, kacl);
>  }
>  
> +/**
> + * security_inode_post_set_acl() - Update inode security from posix acls set
> + * @dentry: file
> + * @acl_name: acl name
> + * @kacl: acl struct
> + *
> + * Update inode security data after successfully setting posix acls on @dentry.
> + * The posix acls in @kacl are identified by @acl_name.
> + */
> +void security_inode_post_set_acl(struct dentry *dentry, const char *acl_name,
> +				 struct posix_acl *kacl)
> +{
> +	if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
> +		return;
> +	call_void_hook(inode_post_set_acl, dentry, acl_name, kacl);
> +}
> +
>  /**
>   * security_inode_get_acl() - Check if reading posix acls is allowed
>   * @idmap: idmap of the mount

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v5 17/23] security: Introduce inode_post_remove_acl hook
  2023-11-07 13:40 ` [PATCH v5 17/23] security: Introduce inode_post_remove_acl hook Roberto Sassu
@ 2023-11-07 17:45   ` Casey Schaufler
  2023-11-16  4:33   ` Paul Moore
  1 sibling, 0 replies; 96+ messages in thread
From: Casey Schaufler @ 2023-11-07 17:45 UTC (permalink / raw)
  To: Roberto Sassu, viro, brauner, chuck.lever, jlayton, neilb, kolga,
	Dai.Ngo, tom, paul, jmorris, serge, zohar, dmitry.kasatkin,
	dhowells, jarkko, stephen.smalley.work, eparis, mic
  Cc: linux-fsdevel, linux-kernel, linux-nfs, linux-security-module,
	linux-integrity, keyrings, selinux, Roberto Sassu, Stefan Berger,
	Casey Schaufler

On 11/7/2023 5:40 AM, 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_remove_acl hook.
>
> At inode_remove_acl hook, EVM verifies the file's existing HMAC value. At
> inode_post_remove_acl, EVM re-calculates the file's HMAC with the passed
> POSIX ACL removed and other file metadata.
>
> Other LSMs could similarly take some action after successful POSIX ACL
> removal.
>
> 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>

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


> ---
>  fs/posix_acl.c                |  1 +
>  include/linux/lsm_hook_defs.h |  2 ++
>  include/linux/security.h      |  8 ++++++++
>  security/security.c           | 17 +++++++++++++++++
>  4 files changed, 28 insertions(+)
>
> diff --git a/fs/posix_acl.c b/fs/posix_acl.c
> index 58e3c1e2fbbc..e3fbe1a9f3f5 100644
> --- a/fs/posix_acl.c
> +++ b/fs/posix_acl.c
> @@ -1246,6 +1246,7 @@ int vfs_remove_acl(struct mnt_idmap *idmap, struct dentry *dentry,
>  		error = -EIO;
>  	if (!error) {
>  		fsnotify_xattr(dentry);
> +		security_inode_post_remove_acl(idmap, dentry, acl_name);
>  		evm_inode_post_remove_acl(idmap, dentry, acl_name);
>  	}
>  
> diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
> index 6a671616196f..2bf128f7cbae 100644
> --- a/include/linux/lsm_hook_defs.h
> +++ b/include/linux/lsm_hook_defs.h
> @@ -163,6 +163,8 @@ LSM_HOOK(int, 0, inode_get_acl, struct mnt_idmap *idmap,
>  	 struct dentry *dentry, const char *acl_name)
>  LSM_HOOK(int, 0, inode_remove_acl, struct mnt_idmap *idmap,
>  	 struct dentry *dentry, const char *acl_name)
> +LSM_HOOK(void, LSM_RET_VOID, inode_post_remove_acl, struct mnt_idmap *idmap,
> +	 struct dentry *dentry, const char *acl_name)
>  LSM_HOOK(int, 0, inode_need_killpriv, struct dentry *dentry)
>  LSM_HOOK(int, 0, inode_killpriv, struct mnt_idmap *idmap,
>  	 struct dentry *dentry)
> diff --git a/include/linux/security.h b/include/linux/security.h
> index d71d0b08e9fe..7cd7126f6545 100644
> --- a/include/linux/security.h
> +++ b/include/linux/security.h
> @@ -378,6 +378,9 @@ int security_inode_get_acl(struct mnt_idmap *idmap,
>  			   struct dentry *dentry, const char *acl_name);
>  int security_inode_remove_acl(struct mnt_idmap *idmap,
>  			      struct dentry *dentry, const char *acl_name);
> +void security_inode_post_remove_acl(struct mnt_idmap *idmap,
> +				    struct dentry *dentry,
> +				    const char *acl_name);
>  void security_inode_post_setxattr(struct dentry *dentry, const char *name,
>  				  const void *value, size_t size, int flags);
>  int security_inode_getxattr(struct dentry *dentry, const char *name);
> @@ -934,6 +937,11 @@ static inline int security_inode_remove_acl(struct mnt_idmap *idmap,
>  	return 0;
>  }
>  
> +static inline void security_inode_post_remove_acl(struct mnt_idmap *idmap,
> +						  struct dentry *dentry,
> +						  const char *acl_name)
> +{ }
> +
>  static inline void security_inode_post_setxattr(struct dentry *dentry,
>  		const char *name, const void *value, size_t size, int flags)
>  { }
> diff --git a/security/security.c b/security/security.c
> index d2dbea54a63a..6eb7c9cff1e5 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -2413,6 +2413,23 @@ int security_inode_remove_acl(struct mnt_idmap *idmap,
>  	return evm_inode_remove_acl(idmap, dentry, acl_name);
>  }
>  
> +/**
> + * security_inode_post_remove_acl() - Update inode security after rm posix acls
> + * @idmap: idmap of the mount
> + * @dentry: file
> + * @acl_name: acl name
> + *
> + * Update inode security data after successfully removing posix acls on
> + * @dentry in @idmap. The posix acls are identified by @acl_name.
> + */
> +void security_inode_post_remove_acl(struct mnt_idmap *idmap,
> +				    struct dentry *dentry, const char *acl_name)
> +{
> +	if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
> +		return;
> +	call_void_hook(inode_post_remove_acl, idmap, dentry, acl_name);
> +}
> +
>  /**
>   * security_inode_post_setxattr() - Update the inode after a setxattr operation
>   * @dentry: file

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v5 11/23] security: Introduce inode_post_removexattr hook
  2023-11-07 17:33   ` Casey Schaufler
@ 2023-11-07 17:45     ` Roberto Sassu
  2023-11-20 17:31     ` Roberto Sassu
  1 sibling, 0 replies; 96+ messages in thread
From: Roberto Sassu @ 2023-11-07 17:45 UTC (permalink / raw)
  To: Casey Schaufler, viro, brauner, chuck.lever, jlayton, neilb,
	kolga, Dai.Ngo, tom, paul, jmorris, serge, zohar,
	dmitry.kasatkin, dhowells, jarkko, stephen.smalley.work, eparis,
	mic
  Cc: linux-fsdevel, linux-kernel, linux-nfs, linux-security-module,
	linux-integrity, keyrings, selinux, Roberto Sassu, Stefan Berger

On Tue, 2023-11-07 at 09:33 -0800, Casey Schaufler wrote:
> On 11/7/2023 5:40 AM, 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_removexattr hook.
> > 
> > At inode_removexattr hook, EVM verifies the file's existing HMAC value. At
> > inode_post_removexattr, EVM re-calculates the file's HMAC with the passed
> > xattr removed and other file metadata.
> > 
> > Other LSMs could similarly take some action after successful xattr removal.
> > 
> > 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>
> > Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
> > ---
> >  fs/xattr.c                    |  9 +++++----
> >  include/linux/lsm_hook_defs.h |  2 ++
> >  include/linux/security.h      |  5 +++++
> >  security/security.c           | 14 ++++++++++++++
> >  4 files changed, 26 insertions(+), 4 deletions(-)
> > 
> > diff --git a/fs/xattr.c b/fs/xattr.c
> > index 09d927603433..84a4aa566c02 100644
> > --- a/fs/xattr.c
> > +++ b/fs/xattr.c
> > @@ -552,11 +552,12 @@ __vfs_removexattr_locked(struct mnt_idmap *idmap,
> >  		goto out;
> >  
> >  	error = __vfs_removexattr(idmap, dentry, name);
> > +	if (error)
> > +		goto out;
> 
> Shouldn't this be simply "return error" rather than a goto to nothing
> but "return error"?

Ok, no problem. I can change that.

Thanks

Roberto

> >  
> > -	if (!error) {
> > -		fsnotify_xattr(dentry);
> > -		evm_inode_post_removexattr(dentry, name);
> > -	}
> > +	fsnotify_xattr(dentry);
> > +	security_inode_post_removexattr(dentry, name);
> > +	evm_inode_post_removexattr(dentry, name);
> >  
> >  out:
> >  	return error;
> > diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
> > index 67410e085205..88452e45025c 100644
> > --- a/include/linux/lsm_hook_defs.h
> > +++ b/include/linux/lsm_hook_defs.h
> > @@ -149,6 +149,8 @@ LSM_HOOK(int, 0, inode_getxattr, struct dentry *dentry, const char *name)
> >  LSM_HOOK(int, 0, inode_listxattr, struct dentry *dentry)
> >  LSM_HOOK(int, 0, inode_removexattr, struct mnt_idmap *idmap,
> >  	 struct dentry *dentry, const char *name)
> > +LSM_HOOK(void, LSM_RET_VOID, inode_post_removexattr, struct dentry *dentry,
> > +	 const char *name)
> >  LSM_HOOK(int, 0, inode_set_acl, struct mnt_idmap *idmap,
> >  	 struct dentry *dentry, const char *acl_name, struct posix_acl *kacl)
> >  LSM_HOOK(int, 0, inode_get_acl, struct mnt_idmap *idmap,
> > diff --git a/include/linux/security.h b/include/linux/security.h
> > index 664df46b22a9..922ea7709bae 100644
> > --- a/include/linux/security.h
> > +++ b/include/linux/security.h
> > @@ -380,6 +380,7 @@ int security_inode_getxattr(struct dentry *dentry, const char *name);
> >  int security_inode_listxattr(struct dentry *dentry);
> >  int security_inode_removexattr(struct mnt_idmap *idmap,
> >  			       struct dentry *dentry, const char *name);
> > +void security_inode_post_removexattr(struct dentry *dentry, const char *name);
> >  int security_inode_need_killpriv(struct dentry *dentry);
> >  int security_inode_killpriv(struct mnt_idmap *idmap, struct dentry *dentry);
> >  int security_inode_getsecurity(struct mnt_idmap *idmap,
> > @@ -940,6 +941,10 @@ static inline int security_inode_removexattr(struct mnt_idmap *idmap,
> >  	return cap_inode_removexattr(idmap, dentry, name);
> >  }
> >  
> > +static inline void security_inode_post_removexattr(struct dentry *dentry,
> > +						   const char *name)
> > +{ }
> > +
> >  static inline int security_inode_need_killpriv(struct dentry *dentry)
> >  {
> >  	return cap_inode_need_killpriv(dentry);
> > diff --git a/security/security.c b/security/security.c
> > index ce3bc7642e18..8aa6e9f316dd 100644
> > --- a/security/security.c
> > +++ b/security/security.c
> > @@ -2452,6 +2452,20 @@ int security_inode_removexattr(struct mnt_idmap *idmap,
> >  	return evm_inode_removexattr(idmap, dentry, name);
> >  }
> >  
> > +/**
> > + * security_inode_post_removexattr() - Update the inode after a removexattr op
> > + * @dentry: file
> > + * @name: xattr name
> > + *
> > + * Update the inode after a successful removexattr operation.
> > + */
> > +void security_inode_post_removexattr(struct dentry *dentry, const char *name)
> > +{
> > +	if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
> > +		return;
> > +	call_void_hook(inode_post_removexattr, dentry, name);
> > +}
> > +
> >  /**
> >   * security_inode_need_killpriv() - Check if security_inode_killpriv() required
> >   * @dentry: associated dentry


^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v5 18/23] security: Introduce key_post_create_or_update hook
  2023-11-07 13:40 ` [PATCH v5 18/23] security: Introduce key_post_create_or_update hook Roberto Sassu
@ 2023-11-07 17:47   ` Casey Schaufler
  0 siblings, 0 replies; 96+ messages in thread
From: Casey Schaufler @ 2023-11-07 17:47 UTC (permalink / raw)
  To: Roberto Sassu, viro, brauner, chuck.lever, jlayton, neilb, kolga,
	Dai.Ngo, tom, paul, jmorris, serge, zohar, dmitry.kasatkin,
	dhowells, jarkko, stephen.smalley.work, eparis, mic
  Cc: linux-fsdevel, linux-kernel, linux-nfs, linux-security-module,
	linux-integrity, keyrings, selinux, Roberto Sassu, Stefan Berger,
	Casey Schaufler

On 11/7/2023 5:40 AM, Roberto Sassu wrote:
> From: Roberto Sassu <roberto.sassu@huawei.com>
>
> In preparation for moving IMA and EVM to the LSM infrastructure, introduce
> the key_post_create_or_update hook.
>
> Depending on policy, IMA measures the key content after creation or update,
> so that remote verifiers are aware of the operation.
>
> Other LSMs could similarly take some action after successful key creation
> or update.
>
> 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>

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

> ---
>  include/linux/lsm_hook_defs.h |  3 +++
>  include/linux/security.h      | 11 +++++++++++
>  security/keys/key.c           |  7 ++++++-
>  security/security.c           | 19 +++++++++++++++++++
>  4 files changed, 39 insertions(+), 1 deletion(-)
>
> diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
> index 2bf128f7cbae..ec5d160c32ba 100644
> --- a/include/linux/lsm_hook_defs.h
> +++ b/include/linux/lsm_hook_defs.h
> @@ -403,6 +403,9 @@ LSM_HOOK(void, LSM_RET_VOID, key_free, struct key *key)
>  LSM_HOOK(int, 0, key_permission, key_ref_t key_ref, const struct cred *cred,
>  	 enum key_need_perm need_perm)
>  LSM_HOOK(int, 0, key_getsecurity, struct key *key, char **buffer)
> +LSM_HOOK(void, LSM_RET_VOID, key_post_create_or_update, struct key *keyring,
> +	 struct key *key, const void *payload, size_t payload_len,
> +	 unsigned long flags, bool create)
>  #endif /* CONFIG_KEYS */
>  
>  #ifdef CONFIG_AUDIT
> diff --git a/include/linux/security.h b/include/linux/security.h
> index 7cd7126f6545..1cd84970ab4c 100644
> --- a/include/linux/security.h
> +++ b/include/linux/security.h
> @@ -1995,6 +1995,9 @@ void security_key_free(struct key *key);
>  int security_key_permission(key_ref_t key_ref, const struct cred *cred,
>  			    enum key_need_perm need_perm);
>  int security_key_getsecurity(struct key *key, char **_buffer);
> +void security_key_post_create_or_update(struct key *keyring, struct key *key,
> +					const void *payload, size_t payload_len,
> +					unsigned long flags, bool create);
>  
>  #else
>  
> @@ -2022,6 +2025,14 @@ static inline int security_key_getsecurity(struct key *key, char **_buffer)
>  	return 0;
>  }
>  
> +static inline void security_key_post_create_or_update(struct key *keyring,
> +						      struct key *key,
> +						      const void *payload,
> +						      size_t payload_len,
> +						      unsigned long flags,
> +						      bool create)
> +{ }
> +
>  #endif
>  #endif /* CONFIG_KEYS */
>  
> diff --git a/security/keys/key.c b/security/keys/key.c
> index 0260a1902922..f75fe66c2f03 100644
> --- a/security/keys/key.c
> +++ b/security/keys/key.c
> @@ -935,6 +935,8 @@ static key_ref_t __key_create_or_update(key_ref_t keyring_ref,
>  		goto error_link_end;
>  	}
>  
> +	security_key_post_create_or_update(keyring, key, payload, plen, flags,
> +					   true);
>  	ima_post_key_create_or_update(keyring, key, payload, plen,
>  				      flags, true);
>  
> @@ -968,10 +970,13 @@ static key_ref_t __key_create_or_update(key_ref_t keyring_ref,
>  
>  	key_ref = __key_update(key_ref, &prep);
>  
> -	if (!IS_ERR(key_ref))
> +	if (!IS_ERR(key_ref)) {
> +		security_key_post_create_or_update(keyring, key, payload, plen,
> +						   flags, false);
>  		ima_post_key_create_or_update(keyring, key,
>  					      payload, plen,
>  					      flags, false);
> +	}
>  
>  	goto error_free_prep;
>  }
> diff --git a/security/security.c b/security/security.c
> index 6eb7c9cff1e5..859189722ab8 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -5406,6 +5406,25 @@ int security_key_getsecurity(struct key *key, char **buffer)
>  	*buffer = NULL;
>  	return call_int_hook(key_getsecurity, 0, key, buffer);
>  }
> +
> +/**
> + * security_key_post_create_or_update() - Notification of key create or update
> + * @keyring: keyring to which the key is linked to
> + * @key: created or updated key
> + * @payload: data used to instantiate or update the key
> + * @payload_len: length of payload
> + * @flags: key flags
> + * @create: flag indicating whether the key was created or updated
> + *
> + * Notify the caller of a key creation or update.
> + */
> +void security_key_post_create_or_update(struct key *keyring, struct key *key,
> +					const void *payload, size_t payload_len,
> +					unsigned long flags, bool create)
> +{
> +	call_void_hook(key_post_create_or_update, keyring, key, payload,
> +		       payload_len, flags, create);
> +}
>  #endif	/* CONFIG_KEYS */
>  
>  #ifdef CONFIG_AUDIT

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v5 19/23] ima: Move to LSM infrastructure
  2023-11-07 13:40 ` [PATCH v5 19/23] ima: Move to LSM infrastructure Roberto Sassu
@ 2023-11-07 17:52   ` Casey Schaufler
  0 siblings, 0 replies; 96+ messages in thread
From: Casey Schaufler @ 2023-11-07 17:52 UTC (permalink / raw)
  To: Roberto Sassu, viro, brauner, chuck.lever, jlayton, neilb, kolga,
	Dai.Ngo, tom, paul, jmorris, serge, zohar, dmitry.kasatkin,
	dhowells, jarkko, stephen.smalley.work, eparis, mic
  Cc: linux-fsdevel, linux-kernel, linux-nfs, linux-security-module,
	linux-integrity, keyrings, selinux, Roberto Sassu,
	Casey Schaufler

On 11/7/2023 5:40 AM, Roberto Sassu wrote:
> From: Roberto Sassu <roberto.sassu@huawei.com>
>
> Move hardcoded IMA function calls (not appraisal-specific functions) from
> various places in the kernel to the LSM infrastructure, by introducing a
> new LSM named 'ima' (at the end of the LSM list and always enabled like
> 'integrity').
>
> Make moved functions as static (except ima_post_key_create_or_update(),
> which is not in ima_main.c), and register them as implementation of the
> respective hooks in the new function init_ima_lsm(). Conditionally register
> ima_post_path_mknod() if CONFIG_SECURITY_PATH is enabled, otherwise the
> path_post_mknod hook won't be available.
>
> Call init_ima_lsm() from integrity_lsm_init() (renamed from
> integrity_iintcache_init()), the init method of the 'integrity' LSM, to
> make sure that the integrity subsystem is ready at the time IMA hooks are
> registered, and to keep the original ordering of IMA and EVM functions as
> when they were hardcoded.
>
> Finally, introduce ima_get_lsm_id() to pass the IMA LSM ID back to the
> 'integrity' LSM for registration of the integrity-specific hooks.
>
> Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
> Acked-by: Chuck Lever <chuck.lever@oracle.com>

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

> ---
>  fs/file_table.c                   |  2 -
>  fs/namei.c                        |  6 --
>  fs/nfsd/vfs.c                     |  7 ---
>  fs/open.c                         |  1 -
>  include/linux/ima.h               | 94 -------------------------------
>  include/uapi/linux/lsm.h          |  1 +
>  security/integrity/iint.c         | 11 +++-
>  security/integrity/ima/ima.h      |  6 ++
>  security/integrity/ima/ima_main.c | 93 +++++++++++++++++++++++-------
>  security/integrity/integrity.h    | 16 ++++++
>  security/keys/key.c               |  9 +--
>  security/security.c               | 56 ++++--------------
>  12 files changed, 116 insertions(+), 186 deletions(-)
>
> diff --git a/fs/file_table.c b/fs/file_table.c
> index 64ed74555e64..e64b0057fa72 100644
> --- a/fs/file_table.c
> +++ b/fs/file_table.c
> @@ -26,7 +26,6 @@
>  #include <linux/percpu_counter.h>
>  #include <linux/percpu.h>
>  #include <linux/task_work.h>
> -#include <linux/ima.h>
>  #include <linux/swap.h>
>  #include <linux/kmemleak.h>
>  
> @@ -386,7 +385,6 @@ static void __fput(struct file *file)
>  	locks_remove_file(file);
>  
>  	security_file_pre_free(file);
> -	ima_file_free(file);
>  	if (unlikely(file->f_flags & FASYNC)) {
>  		if (file->f_op->fasync)
>  			file->f_op->fasync(-1, file, 0);
> diff --git a/fs/namei.c b/fs/namei.c
> index adb3ab27951a..37cc0988308f 100644
> --- a/fs/namei.c
> +++ b/fs/namei.c
> @@ -27,7 +27,6 @@
>  #include <linux/fsnotify.h>
>  #include <linux/personality.h>
>  #include <linux/security.h>
> -#include <linux/ima.h>
>  #include <linux/syscalls.h>
>  #include <linux/mount.h>
>  #include <linux/audit.h>
> @@ -3622,8 +3621,6 @@ static int do_open(struct nameidata *nd,
>  		error = vfs_open(&nd->path, file);
>  	if (!error)
>  		error = security_file_post_open(file, op->acc_mode);
> -	if (!error)
> -		error = ima_file_check(file, op->acc_mode);
>  	if (!error && do_truncate)
>  		error = handle_truncate(idmap, file);
>  	if (unlikely(error > 0)) {
> @@ -3687,7 +3684,6 @@ static int vfs_tmpfile(struct mnt_idmap *idmap,
>  		spin_unlock(&inode->i_lock);
>  	}
>  	security_inode_post_create_tmpfile(idmap, inode);
> -	ima_post_create_tmpfile(idmap, inode);
>  	return 0;
>  }
>  
> @@ -4036,8 +4032,6 @@ static int do_mknodat(int dfd, struct filename *name, umode_t mode,
>  		case 0: case S_IFREG:
>  			error = vfs_create(idmap, path.dentry->d_inode,
>  					   dentry, mode, true);
> -			if (!error)
> -				ima_post_path_mknod(idmap, dentry);
>  			break;
>  		case S_IFCHR: case S_IFBLK:
>  			error = vfs_mknod(idmap, path.dentry->d_inode,
> diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
> index b0c3f07a8bba..e491392a1243 100644
> --- a/fs/nfsd/vfs.c
> +++ b/fs/nfsd/vfs.c
> @@ -25,7 +25,6 @@
>  #include <linux/posix_acl_xattr.h>
>  #include <linux/xattr.h>
>  #include <linux/jhash.h>
> -#include <linux/ima.h>
>  #include <linux/pagemap.h>
>  #include <linux/slab.h>
>  #include <linux/uaccess.h>
> @@ -883,12 +882,6 @@ __nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type,
>  		goto out;
>  	}
>  
> -	host_err = ima_file_check(file, may_flags);
> -	if (host_err) {
> -		fput(file);
> -		goto out;
> -	}
> -
>  	if (may_flags & NFSD_MAY_64BIT_COOKIE)
>  		file->f_mode |= FMODE_64BITHASH;
>  	else
> diff --git a/fs/open.c b/fs/open.c
> index 02dc608d40d8..c8bb9bd5259f 100644
> --- a/fs/open.c
> +++ b/fs/open.c
> @@ -29,7 +29,6 @@
>  #include <linux/audit.h>
>  #include <linux/falloc.h>
>  #include <linux/fs_struct.h>
> -#include <linux/ima.h>
>  #include <linux/dnotify.h>
>  #include <linux/compat.h>
>  #include <linux/mnt_idmapping.h>
> diff --git a/include/linux/ima.h b/include/linux/ima.h
> index 31ef6c3c3207..23ae24b60ecf 100644
> --- a/include/linux/ima.h
> +++ b/include/linux/ima.h
> @@ -16,24 +16,6 @@ struct linux_binprm;
>  
>  #ifdef CONFIG_IMA
>  extern enum hash_algo ima_get_current_hash_algo(void);
> -extern int ima_bprm_check(struct linux_binprm *bprm);
> -extern int ima_file_check(struct file *file, int mask);
> -extern void ima_post_create_tmpfile(struct mnt_idmap *idmap,
> -				    struct inode *inode);
> -extern void ima_file_free(struct file *file);
> -extern int ima_file_mmap(struct file *file, unsigned long reqprot,
> -			 unsigned long prot, unsigned long flags);
> -extern int ima_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot,
> -			     unsigned long prot);
> -extern int ima_load_data(enum kernel_load_data_id id, bool contents);
> -extern int ima_post_load_data(char *buf, loff_t size,
> -			      enum kernel_load_data_id id, char *description);
> -extern int ima_read_file(struct file *file, enum kernel_read_file_id id,
> -			 bool contents);
> -extern int ima_post_read_file(struct file *file, char *buf, loff_t size,
> -			      enum kernel_read_file_id id);
> -extern void ima_post_path_mknod(struct mnt_idmap *idmap,
> -				struct dentry *dentry);
>  extern int ima_file_hash(struct file *file, char *buf, size_t buf_size);
>  extern int ima_inode_hash(struct inode *inode, char *buf, size_t buf_size);
>  extern void ima_kexec_cmdline(int kernel_fd, const void *buf, int size);
> @@ -58,68 +40,6 @@ static inline enum hash_algo ima_get_current_hash_algo(void)
>  	return HASH_ALGO__LAST;
>  }
>  
> -static inline int ima_bprm_check(struct linux_binprm *bprm)
> -{
> -	return 0;
> -}
> -
> -static inline int ima_file_check(struct file *file, int mask)
> -{
> -	return 0;
> -}
> -
> -static inline void ima_post_create_tmpfile(struct mnt_idmap *idmap,
> -					   struct inode *inode)
> -{
> -}
> -
> -static inline void ima_file_free(struct file *file)
> -{
> -	return;
> -}
> -
> -static inline int ima_file_mmap(struct file *file, unsigned long reqprot,
> -				unsigned long prot, unsigned long flags)
> -{
> -	return 0;
> -}
> -
> -static inline int ima_file_mprotect(struct vm_area_struct *vma,
> -				    unsigned long reqprot, unsigned long prot)
> -{
> -	return 0;
> -}
> -
> -static inline int ima_load_data(enum kernel_load_data_id id, bool contents)
> -{
> -	return 0;
> -}
> -
> -static inline int ima_post_load_data(char *buf, loff_t size,
> -				     enum kernel_load_data_id id,
> -				     char *description)
> -{
> -	return 0;
> -}
> -
> -static inline int ima_read_file(struct file *file, enum kernel_read_file_id id,
> -				bool contents)
> -{
> -	return 0;
> -}
> -
> -static inline int ima_post_read_file(struct file *file, char *buf, loff_t size,
> -				     enum kernel_read_file_id id)
> -{
> -	return 0;
> -}
> -
> -static inline void ima_post_path_mknod(struct mnt_idmap *idmap,
> -				       struct dentry *dentry)
> -{
> -	return;
> -}
> -
>  static inline int ima_file_hash(struct file *file, char *buf, size_t buf_size)
>  {
>  	return -EOPNOTSUPP;
> @@ -170,20 +90,6 @@ static inline void ima_add_kexec_buffer(struct kimage *image)
>  {}
>  #endif
>  
> -#ifdef CONFIG_IMA_MEASURE_ASYMMETRIC_KEYS
> -extern void ima_post_key_create_or_update(struct key *keyring,
> -					  struct key *key,
> -					  const void *payload, size_t plen,
> -					  unsigned long flags, bool create);
> -#else
> -static inline void ima_post_key_create_or_update(struct key *keyring,
> -						 struct key *key,
> -						 const void *payload,
> -						 size_t plen,
> -						 unsigned long flags,
> -						 bool create) {}
> -#endif  /* CONFIG_IMA_MEASURE_ASYMMETRIC_KEYS */
> -
>  #ifdef CONFIG_IMA_APPRAISE
>  extern bool is_ima_appraise_enabled(void);
>  extern void ima_inode_post_setattr(struct mnt_idmap *idmap,
> diff --git a/include/uapi/linux/lsm.h b/include/uapi/linux/lsm.h
> index f0386880a78e..ee7d034255a9 100644
> --- a/include/uapi/linux/lsm.h
> +++ b/include/uapi/linux/lsm.h
> @@ -61,6 +61,7 @@ struct lsm_ctx {
>  #define LSM_ID_LOCKDOWN		108
>  #define LSM_ID_BPF		109
>  #define LSM_ID_LANDLOCK		110
> +#define LSM_ID_IMA		111
>  
>  /*
>   * LSM_ATTR_XXX definitions identify different LSM attributes
> diff --git a/security/integrity/iint.c b/security/integrity/iint.c
> index d4419a2a1e24..87f2c0d69f78 100644
> --- a/security/integrity/iint.c
> +++ b/security/integrity/iint.c
> @@ -193,20 +193,25 @@ static void iint_init_once(void *foo)
>  	memset(iint, 0, sizeof(*iint));
>  }
>  
> -static int __init integrity_iintcache_init(void)
> +static int __init integrity_lsm_init(void)
>  {
>  	iint_cache =
>  	    kmem_cache_create("iint_cache", sizeof(struct integrity_iint_cache),
>  			      0, SLAB_PANIC, iint_init_once);
> +	init_ima_lsm();
>  	return 0;
>  }
> +
> +/*
> + * Keep it until IMA and EVM can use disjoint integrity metadata, and their
> + * initialization order can be swapped without change in their behavior.
> + */
>  DEFINE_LSM(integrity) = {
>  	.name = "integrity",
> -	.init = integrity_iintcache_init,
> +	.init = integrity_lsm_init,
>  	.order = LSM_ORDER_LAST,
>  };
>  
> -
>  /*
>   * integrity_kernel_read - read data from the file
>   *
> diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
> index c29db699c996..c0412100023e 100644
> --- a/security/integrity/ima/ima.h
> +++ b/security/integrity/ima/ima.h
> @@ -127,6 +127,12 @@ void ima_load_kexec_buffer(void);
>  static inline void ima_load_kexec_buffer(void) {}
>  #endif /* CONFIG_HAVE_IMA_KEXEC */
>  
> +#ifdef CONFIG_IMA_MEASURE_ASYMMETRIC_KEYS
> +void ima_post_key_create_or_update(struct key *keyring, struct key *key,
> +				   const void *payload, size_t plen,
> +				   unsigned long flags, bool create);
> +#endif
> +
>  /*
>   * The default binary_runtime_measurements list format is defined as the
>   * platform native format.  The canonical format is defined as little-endian.
> diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
> index 02021ee467d3..f923ff5c6524 100644
> --- a/security/integrity/ima/ima_main.c
> +++ b/security/integrity/ima/ima_main.c
> @@ -189,7 +189,7 @@ static void ima_check_last_writer(struct integrity_iint_cache *iint,
>   *
>   * Flag files that changed, based on i_version
>   */
> -void ima_file_free(struct file *file)
> +static void ima_file_free(struct file *file)
>  {
>  	struct inode *inode = file_inode(file);
>  	struct integrity_iint_cache *iint;
> @@ -427,8 +427,8 @@ static int process_measurement(struct file *file, const struct cred *cred,
>   * On success return 0.  On integrity appraisal error, assuming the file
>   * is in policy and IMA-appraisal is in enforcing mode, return -EACCES.
>   */
> -int ima_file_mmap(struct file *file, unsigned long reqprot,
> -		  unsigned long prot, unsigned long flags)
> +static int ima_file_mmap(struct file *file, unsigned long reqprot,
> +			 unsigned long prot, unsigned long flags)
>  {
>  	u32 secid;
>  	int ret;
> @@ -466,8 +466,8 @@ int ima_file_mmap(struct file *file, unsigned long reqprot,
>   *
>   * On mprotect change success, return 0.  On failure, return -EACESS.
>   */
> -int ima_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot,
> -		      unsigned long prot)
> +static int ima_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot,
> +			     unsigned long prot)
>  {
>  	struct ima_template_desc *template = NULL;
>  	struct file *file;
> @@ -525,7 +525,7 @@ int ima_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot,
>   * On success return 0.  On integrity appraisal error, assuming the file
>   * is in policy and IMA-appraisal is in enforcing mode, return -EACCES.
>   */
> -int ima_bprm_check(struct linux_binprm *bprm)
> +static int ima_bprm_check(struct linux_binprm *bprm)
>  {
>  	int ret;
>  	u32 secid;
> @@ -551,7 +551,7 @@ int ima_bprm_check(struct linux_binprm *bprm)
>   * On success return 0.  On integrity appraisal error, assuming the file
>   * is in policy and IMA-appraisal is in enforcing mode, return -EACCES.
>   */
> -int ima_file_check(struct file *file, int mask)
> +static int ima_file_check(struct file *file, int mask)
>  {
>  	u32 secid;
>  
> @@ -560,7 +560,6 @@ int ima_file_check(struct file *file, int mask)
>  				   mask & (MAY_READ | MAY_WRITE | MAY_EXEC |
>  					   MAY_APPEND), FILE_CHECK);
>  }
> -EXPORT_SYMBOL_GPL(ima_file_check);
>  
>  static int __ima_inode_hash(struct inode *inode, struct file *file, char *buf,
>  			    size_t buf_size)
> @@ -685,8 +684,9 @@ EXPORT_SYMBOL_GPL(ima_inode_hash);
>   * Skip calling process_measurement(), but indicate which newly, created
>   * tmpfiles are in policy.
>   */
> -void ima_post_create_tmpfile(struct mnt_idmap *idmap,
> -			     struct inode *inode)
> +static void ima_post_create_tmpfile(struct mnt_idmap *idmap,
> +				    struct inode *inode)
> +
>  {
>  	struct integrity_iint_cache *iint;
>  	int must_appraise;
> @@ -717,8 +717,8 @@ void ima_post_create_tmpfile(struct mnt_idmap *idmap,
>   * Mark files created via the mknodat syscall as new, so that the
>   * file data can be written later.
>   */
> -void ima_post_path_mknod(struct mnt_idmap *idmap,
> -			 struct dentry *dentry)
> +static void __maybe_unused
> +ima_post_path_mknod(struct mnt_idmap *idmap, struct dentry *dentry)
>  {
>  	struct integrity_iint_cache *iint;
>  	struct inode *inode = dentry->d_inode;
> @@ -753,8 +753,8 @@ void ima_post_path_mknod(struct mnt_idmap *idmap,
>   *
>   * For permission return 0, otherwise return -EACCES.
>   */
> -int ima_read_file(struct file *file, enum kernel_read_file_id read_id,
> -		  bool contents)
> +static int ima_read_file(struct file *file, enum kernel_read_file_id read_id,
> +			 bool contents)
>  {
>  	enum ima_hooks func;
>  	u32 secid;
> @@ -803,8 +803,8 @@ const int read_idmap[READING_MAX_ID] = {
>   * On success return 0.  On integrity appraisal error, assuming the file
>   * is in policy and IMA-appraisal is in enforcing mode, return -EACCES.
>   */
> -int ima_post_read_file(struct file *file, char *buf, loff_t size,
> -		       enum kernel_read_file_id read_id)
> +static int ima_post_read_file(struct file *file, char *buf, loff_t size,
> +			      enum kernel_read_file_id read_id)
>  {
>  	enum ima_hooks func;
>  	u32 secid;
> @@ -837,7 +837,7 @@ int ima_post_read_file(struct file *file, char *buf, loff_t size,
>   *
>   * For permission return 0, otherwise return -EACCES.
>   */
> -int ima_load_data(enum kernel_load_data_id id, bool contents)
> +static int ima_load_data(enum kernel_load_data_id id, bool contents)
>  {
>  	bool ima_enforce, sig_enforce;
>  
> @@ -891,9 +891,9 @@ int ima_load_data(enum kernel_load_data_id id, bool contents)
>   * On success return 0.  On integrity appraisal error, assuming the file
>   * is in policy and IMA-appraisal is in enforcing mode, return -EACCES.
>   */
> -int ima_post_load_data(char *buf, loff_t size,
> -		       enum kernel_load_data_id load_id,
> -		       char *description)
> +static int ima_post_load_data(char *buf, loff_t size,
> +			      enum kernel_load_data_id load_id,
> +			      char *description)
>  {
>  	if (load_id == LOADING_FIRMWARE) {
>  		if ((ima_appraise & IMA_APPRAISE_FIRMWARE) &&
> @@ -1122,4 +1122,57 @@ static int __init init_ima(void)
>  	return error;
>  }
>  
> +static struct security_hook_list ima_hooks[] __ro_after_init = {
> +	LSM_HOOK_INIT(bprm_check_security, ima_bprm_check),
> +	LSM_HOOK_INIT(file_post_open, ima_file_check),
> +	LSM_HOOK_INIT(inode_post_create_tmpfile, ima_post_create_tmpfile),
> +	LSM_HOOK_INIT(file_pre_free_security, ima_file_free),
> +	LSM_HOOK_INIT(mmap_file, ima_file_mmap),
> +	LSM_HOOK_INIT(file_mprotect, ima_file_mprotect),
> +	LSM_HOOK_INIT(kernel_load_data, ima_load_data),
> +	LSM_HOOK_INIT(kernel_post_load_data, ima_post_load_data),
> +	LSM_HOOK_INIT(kernel_read_file, ima_read_file),
> +	LSM_HOOK_INIT(kernel_post_read_file, ima_post_read_file),
> +#ifdef CONFIG_SECURITY_PATH
> +	LSM_HOOK_INIT(path_post_mknod, ima_post_path_mknod),
> +#endif
> +#ifdef CONFIG_IMA_MEASURE_ASYMMETRIC_KEYS
> +	LSM_HOOK_INIT(key_post_create_or_update, ima_post_key_create_or_update),
> +#endif
> +};
> +
> +static const struct lsm_id ima_lsmid = {
> +	.name = "ima",
> +	.id = LSM_ID_IMA,
> +};
> +
> +/* Return the IMA LSM ID, if IMA is enabled or NULL if not. */
> +const struct lsm_id *ima_get_lsm_id(void)
> +{
> +	return &ima_lsmid;
> +}
> +
> +/*
> + * Since with the LSM_ORDER_LAST there is no guarantee about the ordering
> + * within the .lsm_info.init section, ensure that IMA hooks are before EVM
> + * ones, by letting the 'integrity' LSM call init_ima_lsm() to initialize the
> + * 'ima' and 'evm' LSMs in this sequence.
> + */
> +void __init init_ima_lsm(void)
> +{
> +	security_add_hooks(ima_hooks, ARRAY_SIZE(ima_hooks), &ima_lsmid);
> +}
> +
> +/* Introduce a dummy function as 'ima' init method (it cannot be NULL). */
> +static int __init dummy_init_ima_lsm(void)
> +{
> +	return 0;
> +}
> +
> +DEFINE_LSM(ima) = {
> +	.name = "ima",
> +	.init = dummy_init_ima_lsm,
> +	.order = LSM_ORDER_LAST,
> +};
> +
>  late_initcall(init_ima);	/* Start IMA after the TPM is available */
> diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h
> index 9561db7cf6b4..3098cae1c27c 100644
> --- a/security/integrity/integrity.h
> +++ b/security/integrity/integrity.h
> @@ -18,6 +18,7 @@
>  #include <crypto/hash.h>
>  #include <linux/key.h>
>  #include <linux/audit.h>
> +#include <linux/lsm_hooks.h>
>  
>  /* iint action cache flags */
>  #define IMA_MEASURE		0x00000001
> @@ -193,6 +194,21 @@ extern struct dentry *integrity_dir;
>  
>  struct modsig;
>  
> +#ifdef CONFIG_IMA
> +const struct lsm_id *ima_get_lsm_id(void);
> +void __init init_ima_lsm(void);
> +#else
> +static inline const struct lsm_id *ima_get_lsm_id(void)
> +{
> +	return NULL;
> +}
> +
> +static inline void __init init_ima_lsm(void)
> +{
> +}
> +
> +#endif
> +
>  #ifdef CONFIG_INTEGRITY_SIGNATURE
>  
>  int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
> diff --git a/security/keys/key.c b/security/keys/key.c
> index f75fe66c2f03..80fc2f203a0c 100644
> --- a/security/keys/key.c
> +++ b/security/keys/key.c
> @@ -13,7 +13,6 @@
>  #include <linux/security.h>
>  #include <linux/workqueue.h>
>  #include <linux/random.h>
> -#include <linux/ima.h>
>  #include <linux/err.h>
>  #include "internal.h"
>  
> @@ -937,8 +936,6 @@ static key_ref_t __key_create_or_update(key_ref_t keyring_ref,
>  
>  	security_key_post_create_or_update(keyring, key, payload, plen, flags,
>  					   true);
> -	ima_post_key_create_or_update(keyring, key, payload, plen,
> -				      flags, true);
>  
>  	key_ref = make_key_ref(key, is_key_possessed(keyring_ref));
>  
> @@ -970,13 +967,9 @@ static key_ref_t __key_create_or_update(key_ref_t keyring_ref,
>  
>  	key_ref = __key_update(key_ref, &prep);
>  
> -	if (!IS_ERR(key_ref)) {
> +	if (!IS_ERR(key_ref))
>  		security_key_post_create_or_update(keyring, key, payload, plen,
>  						   flags, false);
> -		ima_post_key_create_or_update(keyring, key,
> -					      payload, plen,
> -					      flags, false);
> -	}
>  
>  	goto error_free_prep;
>  }
> diff --git a/security/security.c b/security/security.c
> index 859189722ab8..b2fdcbaa4b30 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -50,7 +50,8 @@
>  	(IS_ENABLED(CONFIG_SECURITY_SAFESETID) ? 1 : 0) + \
>  	(IS_ENABLED(CONFIG_SECURITY_LOCKDOWN_LSM) ? 1 : 0) + \
>  	(IS_ENABLED(CONFIG_BPF_LSM) ? 1 : 0) + \
> -	(IS_ENABLED(CONFIG_SECURITY_LANDLOCK) ? 1 : 0))
> +	(IS_ENABLED(CONFIG_SECURITY_LANDLOCK) ? 1 : 0) + \
> +	(IS_ENABLED(CONFIG_IMA) ? 1 : 0))
>  
>  /*
>   * These are descriptions of the reasons that can be passed to the
> @@ -1182,12 +1183,7 @@ int security_bprm_creds_from_file(struct linux_binprm *bprm, const struct file *
>   */
>  int security_bprm_check(struct linux_binprm *bprm)
>  {
> -	int ret;
> -
> -	ret = call_int_hook(bprm_check_security, 0, bprm);
> -	if (ret)
> -		return ret;
> -	return ima_bprm_check(bprm);
> +	return call_int_hook(bprm_check_security, 0, bprm);
>  }
>  
>  /**
> @@ -2883,13 +2879,8 @@ static inline unsigned long mmap_prot(struct file *file, unsigned long prot)
>  int security_mmap_file(struct file *file, unsigned long prot,
>  		       unsigned long flags)
>  {
> -	unsigned long prot_adj = mmap_prot(file, prot);
> -	int ret;
> -
> -	ret = call_int_hook(mmap_file, 0, file, prot, prot_adj, flags);
> -	if (ret)
> -		return ret;
> -	return ima_file_mmap(file, prot, prot_adj, flags);
> +	return call_int_hook(mmap_file, 0, file, prot, mmap_prot(file, prot),
> +			     flags);
>  }
>  
>  /**
> @@ -2918,12 +2909,7 @@ int security_mmap_addr(unsigned long addr)
>  int security_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot,
>  			   unsigned long prot)
>  {
> -	int ret;
> -
> -	ret = call_int_hook(file_mprotect, 0, vma, reqprot, prot);
> -	if (ret)
> -		return ret;
> -	return ima_file_mprotect(vma, reqprot, prot);
> +	return call_int_hook(file_mprotect, 0, vma, reqprot, prot);
>  }
>  
>  /**
> @@ -3253,12 +3239,7 @@ int security_kernel_module_request(char *kmod_name)
>  int security_kernel_read_file(struct file *file, enum kernel_read_file_id id,
>  			      bool contents)
>  {
> -	int ret;
> -
> -	ret = call_int_hook(kernel_read_file, 0, file, id, contents);
> -	if (ret)
> -		return ret;
> -	return ima_read_file(file, id, contents);
> +	return call_int_hook(kernel_read_file, 0, file, id, contents);
>  }
>  EXPORT_SYMBOL_GPL(security_kernel_read_file);
>  
> @@ -3278,12 +3259,7 @@ EXPORT_SYMBOL_GPL(security_kernel_read_file);
>  int security_kernel_post_read_file(struct file *file, char *buf, loff_t size,
>  				   enum kernel_read_file_id id)
>  {
> -	int ret;
> -
> -	ret = call_int_hook(kernel_post_read_file, 0, file, buf, size, id);
> -	if (ret)
> -		return ret;
> -	return ima_post_read_file(file, buf, size, id);
> +	return call_int_hook(kernel_post_read_file, 0, file, buf, size, id);
>  }
>  EXPORT_SYMBOL_GPL(security_kernel_post_read_file);
>  
> @@ -3298,12 +3274,7 @@ EXPORT_SYMBOL_GPL(security_kernel_post_read_file);
>   */
>  int security_kernel_load_data(enum kernel_load_data_id id, bool contents)
>  {
> -	int ret;
> -
> -	ret = call_int_hook(kernel_load_data, 0, id, contents);
> -	if (ret)
> -		return ret;
> -	return ima_load_data(id, contents);
> +	return call_int_hook(kernel_load_data, 0, id, contents);
>  }
>  EXPORT_SYMBOL_GPL(security_kernel_load_data);
>  
> @@ -3325,13 +3296,8 @@ int security_kernel_post_load_data(char *buf, loff_t size,
>  				   enum kernel_load_data_id id,
>  				   char *description)
>  {
> -	int ret;
> -
> -	ret = call_int_hook(kernel_post_load_data, 0, buf, size, id,
> -			    description);
> -	if (ret)
> -		return ret;
> -	return ima_post_load_data(buf, size, id, description);
> +	return call_int_hook(kernel_post_load_data, 0, buf, size, id,
> +			     description);
>  }
>  EXPORT_SYMBOL_GPL(security_kernel_post_load_data);
>  

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v5 20/23] ima: Move IMA-Appraisal to LSM infrastructure
  2023-11-07 13:40 ` [PATCH v5 20/23] ima: Move IMA-Appraisal " Roberto Sassu
@ 2023-11-07 18:43   ` Casey Schaufler
  0 siblings, 0 replies; 96+ messages in thread
From: Casey Schaufler @ 2023-11-07 18:43 UTC (permalink / raw)
  To: Roberto Sassu, viro, brauner, chuck.lever, jlayton, neilb, kolga,
	Dai.Ngo, tom, paul, jmorris, serge, zohar, dmitry.kasatkin,
	dhowells, jarkko, stephen.smalley.work, eparis, mic
  Cc: linux-fsdevel, linux-kernel, linux-nfs, linux-security-module,
	linux-integrity, keyrings, selinux, Roberto Sassu, Stefan Berger,
	Casey Schaufler

On 11/7/2023 5:40 AM, Roberto Sassu wrote:
> From: Roberto Sassu <roberto.sassu@huawei.com>
>
> Do the registration of IMA-Appraisal only functions separately from the
> rest of IMA functions, as appraisal is a separate feature not necessarily
> enabled in the kernel configuration.
>
> Reuse the same approach as for other IMA functions, move hardcoded calls
> from various places in the kernel to the LSM infrastructure. Declare the
> functions as static and register them as hook implementations in
> init_ima_appraise_lsm(), called by init_ima_lsm().
>
> Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
> Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
> Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>

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


> ---
>  fs/attr.c                             |  2 -
>  include/linux/ima.h                   | 55 ---------------------------
>  security/integrity/ima/ima.h          |  5 +++
>  security/integrity/ima/ima_appraise.c | 38 +++++++++++++-----
>  security/integrity/ima/ima_main.c     |  1 +
>  security/security.c                   | 13 -------
>  6 files changed, 35 insertions(+), 79 deletions(-)
>
> diff --git a/fs/attr.c b/fs/attr.c
> index 221d2bb0a906..38841f3ebbcb 100644
> --- a/fs/attr.c
> +++ b/fs/attr.c
> @@ -17,7 +17,6 @@
>  #include <linux/filelock.h>
>  #include <linux/security.h>
>  #include <linux/evm.h>
> -#include <linux/ima.h>
>  
>  #include "internal.h"
>  
> @@ -503,7 +502,6 @@ int notify_change(struct mnt_idmap *idmap, struct dentry *dentry,
>  	if (!error) {
>  		fsnotify_change(dentry, ia_valid);
>  		security_inode_post_setattr(idmap, dentry, ia_valid);
> -		ima_inode_post_setattr(idmap, dentry, ia_valid);
>  		evm_inode_post_setattr(idmap, dentry, ia_valid);
>  	}
>  
> diff --git a/include/linux/ima.h b/include/linux/ima.h
> index 23ae24b60ecf..0bae61a15b60 100644
> --- a/include/linux/ima.h
> +++ b/include/linux/ima.h
> @@ -92,66 +92,11 @@ static inline void ima_add_kexec_buffer(struct kimage *image)
>  
>  #ifdef CONFIG_IMA_APPRAISE
>  extern bool is_ima_appraise_enabled(void);
> -extern void ima_inode_post_setattr(struct mnt_idmap *idmap,
> -				   struct dentry *dentry, int ia_valid);
> -extern int ima_inode_setxattr(struct mnt_idmap *idmap, struct dentry *dentry,
> -			      const char *xattr_name, const void *xattr_value,
> -			      size_t xattr_value_len, int flags);
> -extern int ima_inode_set_acl(struct mnt_idmap *idmap,
> -			     struct dentry *dentry, const char *acl_name,
> -			     struct posix_acl *kacl);
> -static inline int ima_inode_remove_acl(struct mnt_idmap *idmap,
> -				       struct dentry *dentry,
> -				       const char *acl_name)
> -{
> -	return ima_inode_set_acl(idmap, dentry, acl_name, NULL);
> -}
> -
> -extern int ima_inode_removexattr(struct mnt_idmap *idmap, struct dentry *dentry,
> -				 const char *xattr_name);
>  #else
>  static inline bool is_ima_appraise_enabled(void)
>  {
>  	return 0;
>  }
> -
> -static inline void ima_inode_post_setattr(struct mnt_idmap *idmap,
> -					  struct dentry *dentry, int ia_valid)
> -{
> -	return;
> -}
> -
> -static inline int ima_inode_setxattr(struct mnt_idmap *idmap,
> -				     struct dentry *dentry,
> -				     const char *xattr_name,
> -				     const void *xattr_value,
> -				     size_t xattr_value_len,
> -				     int flags)
> -{
> -	return 0;
> -}
> -
> -static inline int ima_inode_set_acl(struct mnt_idmap *idmap,
> -				    struct dentry *dentry, const char *acl_name,
> -				    struct posix_acl *kacl)
> -{
> -
> -	return 0;
> -}
> -
> -static inline int ima_inode_removexattr(struct mnt_idmap *idmap,
> -					struct dentry *dentry,
> -					const char *xattr_name)
> -{
> -	return 0;
> -}
> -
> -static inline int ima_inode_remove_acl(struct mnt_idmap *idmap,
> -				       struct dentry *dentry,
> -				       const char *acl_name)
> -{
> -	return 0;
> -}
>  #endif /* CONFIG_IMA_APPRAISE */
>  
>  #if defined(CONFIG_IMA_APPRAISE) && defined(CONFIG_INTEGRITY_TRUSTED_KEYRING)
> diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
> index c0412100023e..a27fc10f84f7 100644
> --- a/security/integrity/ima/ima.h
> +++ b/security/integrity/ima/ima.h
> @@ -334,6 +334,7 @@ enum hash_algo ima_get_hash_algo(const struct evm_ima_xattr_data *xattr_value,
>  				 int xattr_len);
>  int ima_read_xattr(struct dentry *dentry,
>  		   struct evm_ima_xattr_data **xattr_value, int xattr_len);
> +void __init init_ima_appraise_lsm(const struct lsm_id *lsmid);
>  
>  #else
>  static inline int ima_check_blacklist(struct integrity_iint_cache *iint,
> @@ -385,6 +386,10 @@ static inline int ima_read_xattr(struct dentry *dentry,
>  	return 0;
>  }
>  
> +static inline void __init init_ima_appraise_lsm(const struct lsm_id *lsmid)
> +{
> +}
> +
>  #endif /* CONFIG_IMA_APPRAISE */
>  
>  #ifdef CONFIG_IMA_APPRAISE_MODSIG
> diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c
> index 36abc84ba299..076451109637 100644
> --- a/security/integrity/ima/ima_appraise.c
> +++ b/security/integrity/ima/ima_appraise.c
> @@ -636,8 +636,8 @@ void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file)
>   * This function is called from notify_change(), which expects the caller
>   * to lock the inode's i_mutex.
>   */
> -void ima_inode_post_setattr(struct mnt_idmap *idmap,
> -			    struct dentry *dentry, int ia_valid)
> +static void ima_inode_post_setattr(struct mnt_idmap *idmap,
> +				   struct dentry *dentry, int ia_valid)
>  {
>  	struct inode *inode = d_backing_inode(dentry);
>  	struct integrity_iint_cache *iint;
> @@ -750,9 +750,9 @@ static int validate_hash_algo(struct dentry *dentry,
>  	return -EACCES;
>  }
>  
> -int ima_inode_setxattr(struct mnt_idmap *idmap, struct dentry *dentry,
> -		       const char *xattr_name, const void *xattr_value,
> -		       size_t xattr_value_len, int flags)
> +static int ima_inode_setxattr(struct mnt_idmap *idmap, struct dentry *dentry,
> +			      const char *xattr_name, const void *xattr_value,
> +			      size_t xattr_value_len, int flags)
>  {
>  	const struct evm_ima_xattr_data *xvalue = xattr_value;
>  	int digsig = 0;
> @@ -781,8 +781,8 @@ int ima_inode_setxattr(struct mnt_idmap *idmap, struct dentry *dentry,
>  	return result;
>  }
>  
> -int ima_inode_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
> -		      const char *acl_name, struct posix_acl *kacl)
> +static int ima_inode_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
> +			     const char *acl_name, struct posix_acl *kacl)
>  {
>  	if (evm_revalidate_status(acl_name))
>  		ima_reset_appraise_flags(d_backing_inode(dentry), 0);
> @@ -790,8 +790,8 @@ int ima_inode_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
>  	return 0;
>  }
>  
> -int ima_inode_removexattr(struct mnt_idmap *idmap, struct dentry *dentry,
> -			  const char *xattr_name)
> +static int ima_inode_removexattr(struct mnt_idmap *idmap, struct dentry *dentry,
> +				 const char *xattr_name)
>  {
>  	int result;
>  
> @@ -803,3 +803,23 @@ int ima_inode_removexattr(struct mnt_idmap *idmap, struct dentry *dentry,
>  	}
>  	return result;
>  }
> +
> +static int ima_inode_remove_acl(struct mnt_idmap *idmap, struct dentry *dentry,
> +				const char *acl_name)
> +{
> +	return ima_inode_set_acl(idmap, dentry, acl_name, NULL);
> +}
> +
> +static struct security_hook_list ima_appraise_hooks[] __ro_after_init = {
> +	LSM_HOOK_INIT(inode_post_setattr, ima_inode_post_setattr),
> +	LSM_HOOK_INIT(inode_setxattr, ima_inode_setxattr),
> +	LSM_HOOK_INIT(inode_set_acl, ima_inode_set_acl),
> +	LSM_HOOK_INIT(inode_removexattr, ima_inode_removexattr),
> +	LSM_HOOK_INIT(inode_remove_acl, ima_inode_remove_acl),
> +};
> +
> +void __init init_ima_appraise_lsm(const struct lsm_id *lsmid)
> +{
> +	security_add_hooks(ima_appraise_hooks, ARRAY_SIZE(ima_appraise_hooks),
> +			   lsmid);
> +}
> diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
> index f923ff5c6524..9aabbc37916c 100644
> --- a/security/integrity/ima/ima_main.c
> +++ b/security/integrity/ima/ima_main.c
> @@ -1161,6 +1161,7 @@ const struct lsm_id *ima_get_lsm_id(void)
>  void __init init_ima_lsm(void)
>  {
>  	security_add_hooks(ima_hooks, ARRAY_SIZE(ima_hooks), &ima_lsmid);
> +	init_ima_appraise_lsm(&ima_lsmid);
>  }
>  
>  /* Introduce a dummy function as 'ima' init method (it cannot be NULL). */
> diff --git a/security/security.c b/security/security.c
> index b2fdcbaa4b30..456f3fe74116 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -20,7 +20,6 @@
>  #include <linux/kernel_read_file.h>
>  #include <linux/lsm_hooks.h>
>  #include <linux/integrity.h>
> -#include <linux/ima.h>
>  #include <linux/evm.h>
>  #include <linux/fsnotify.h>
>  #include <linux/mman.h>
> @@ -2308,9 +2307,6 @@ int security_inode_setxattr(struct mnt_idmap *idmap,
>  
>  	if (ret == 1)
>  		ret = cap_inode_setxattr(dentry, name, value, size, flags);
> -	if (ret)
> -		return ret;
> -	ret = ima_inode_setxattr(idmap, dentry, name, value, size, flags);
>  	if (ret)
>  		return ret;
>  	return evm_inode_setxattr(idmap, dentry, name, value, size, flags);
> @@ -2338,9 +2334,6 @@ int security_inode_set_acl(struct mnt_idmap *idmap,
>  		return 0;
>  	ret = call_int_hook(inode_set_acl, 0, idmap, dentry, acl_name,
>  			    kacl);
> -	if (ret)
> -		return ret;
> -	ret = ima_inode_set_acl(idmap, dentry, acl_name, kacl);
>  	if (ret)
>  		return ret;
>  	return evm_inode_set_acl(idmap, dentry, acl_name, kacl);
> @@ -2401,9 +2394,6 @@ int security_inode_remove_acl(struct mnt_idmap *idmap,
>  	if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
>  		return 0;
>  	ret = call_int_hook(inode_remove_acl, 0, idmap, dentry, acl_name);
> -	if (ret)
> -		return ret;
> -	ret = ima_inode_remove_acl(idmap, dentry, acl_name);
>  	if (ret)
>  		return ret;
>  	return evm_inode_remove_acl(idmap, dentry, acl_name);
> @@ -2503,9 +2493,6 @@ int security_inode_removexattr(struct mnt_idmap *idmap,
>  	ret = call_int_hook(inode_removexattr, 1, idmap, dentry, name);
>  	if (ret == 1)
>  		ret = cap_inode_removexattr(idmap, dentry, name);
> -	if (ret)
> -		return ret;
> -	ret = ima_inode_removexattr(idmap, dentry, name);
>  	if (ret)
>  		return ret;
>  	return evm_inode_removexattr(idmap, dentry, name);

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v5 21/23] evm: Move to LSM infrastructure
  2023-11-07 13:40 ` [PATCH v5 21/23] evm: Move " Roberto Sassu
@ 2023-11-07 18:45   ` Casey Schaufler
  0 siblings, 0 replies; 96+ messages in thread
From: Casey Schaufler @ 2023-11-07 18:45 UTC (permalink / raw)
  To: Roberto Sassu, viro, brauner, chuck.lever, jlayton, neilb, kolga,
	Dai.Ngo, tom, paul, jmorris, serge, zohar, dmitry.kasatkin,
	dhowells, jarkko, stephen.smalley.work, eparis, mic
  Cc: linux-fsdevel, linux-kernel, linux-nfs, linux-security-module,
	linux-integrity, keyrings, selinux, Roberto Sassu,
	Casey Schaufler

On 11/7/2023 5:40 AM, Roberto Sassu wrote:
> From: Roberto Sassu <roberto.sassu@huawei.com>
>
> As for IMA, move hardcoded EVM function calls from various places in the
> kernel to the LSM infrastructure, by introducing a new LSM named 'evm'
> (at the end of the LSM list and always enabled, like 'ima' and
> 'integrity').
>
> Make EVM functions as static (except for evm_inode_init_security(), which
> is exported), and register them as hook implementations in init_evm_lsm(),
> called by integrity_lsm_init() to keep the original ordering of IMA and EVM
> functions.
>
> Introduce evm_get_lsm_id() to pass the EVM LSM ID back to the 'integrity'
> LSM for registration of the integrity-specific hooks.
>
> 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>

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

> ---
>  fs/attr.c                         |   2 -
>  fs/posix_acl.c                    |   3 -
>  fs/xattr.c                        |   2 -
>  include/linux/evm.h               | 107 -----------------------
>  include/uapi/linux/lsm.h          |   1 +
>  security/integrity/evm/evm_main.c | 137 ++++++++++++++++++++++++++----
>  security/integrity/iint.c         |   1 +
>  security/integrity/integrity.h    |  15 ++++
>  security/security.c               |  45 +++-------
>  9 files changed, 150 insertions(+), 163 deletions(-)
>
> diff --git a/fs/attr.c b/fs/attr.c
> index 38841f3ebbcb..b51bd7c9b4a7 100644
> --- a/fs/attr.c
> +++ b/fs/attr.c
> @@ -16,7 +16,6 @@
>  #include <linux/fcntl.h>
>  #include <linux/filelock.h>
>  #include <linux/security.h>
> -#include <linux/evm.h>
>  
>  #include "internal.h"
>  
> @@ -502,7 +501,6 @@ int notify_change(struct mnt_idmap *idmap, struct dentry *dentry,
>  	if (!error) {
>  		fsnotify_change(dentry, ia_valid);
>  		security_inode_post_setattr(idmap, dentry, ia_valid);
> -		evm_inode_post_setattr(idmap, dentry, ia_valid);
>  	}
>  
>  	return error;
> diff --git a/fs/posix_acl.c b/fs/posix_acl.c
> index e3fbe1a9f3f5..ae67479cd2b6 100644
> --- a/fs/posix_acl.c
> +++ b/fs/posix_acl.c
> @@ -26,7 +26,6 @@
>  #include <linux/mnt_idmapping.h>
>  #include <linux/iversion.h>
>  #include <linux/security.h>
> -#include <linux/evm.h>
>  #include <linux/fsnotify.h>
>  #include <linux/filelock.h>
>  
> @@ -1138,7 +1137,6 @@ int vfs_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
>  	if (!error) {
>  		fsnotify_xattr(dentry);
>  		security_inode_post_set_acl(dentry, acl_name, kacl);
> -		evm_inode_post_set_acl(dentry, acl_name, kacl);
>  	}
>  
>  out_inode_unlock:
> @@ -1247,7 +1245,6 @@ int vfs_remove_acl(struct mnt_idmap *idmap, struct dentry *dentry,
>  	if (!error) {
>  		fsnotify_xattr(dentry);
>  		security_inode_post_remove_acl(idmap, dentry, acl_name);
> -		evm_inode_post_remove_acl(idmap, dentry, acl_name);
>  	}
>  
>  out_inode_unlock:
> diff --git a/fs/xattr.c b/fs/xattr.c
> index 84a4aa566c02..2660bc7effdc 100644
> --- a/fs/xattr.c
> +++ b/fs/xattr.c
> @@ -16,7 +16,6 @@
>  #include <linux/mount.h>
>  #include <linux/namei.h>
>  #include <linux/security.h>
> -#include <linux/evm.h>
>  #include <linux/syscalls.h>
>  #include <linux/export.h>
>  #include <linux/fsnotify.h>
> @@ -557,7 +556,6 @@ __vfs_removexattr_locked(struct mnt_idmap *idmap,
>  
>  	fsnotify_xattr(dentry);
>  	security_inode_post_removexattr(dentry, name);
> -	evm_inode_post_removexattr(dentry, name);
>  
>  out:
>  	return error;
> diff --git a/include/linux/evm.h b/include/linux/evm.h
> index 437d4076a3b3..cb481eccc967 100644
> --- a/include/linux/evm.h
> +++ b/include/linux/evm.h
> @@ -21,44 +21,6 @@ extern enum integrity_status evm_verifyxattr(struct dentry *dentry,
>  					     void *xattr_value,
>  					     size_t xattr_value_len,
>  					     struct integrity_iint_cache *iint);
> -extern int evm_inode_setattr(struct mnt_idmap *idmap,
> -			     struct dentry *dentry, struct iattr *attr);
> -extern void evm_inode_post_setattr(struct mnt_idmap *idmap,
> -				   struct dentry *dentry, int ia_valid);
> -extern int evm_inode_setxattr(struct mnt_idmap *idmap,
> -			      struct dentry *dentry, const char *name,
> -			      const void *value, size_t size, int flags);
> -extern void evm_inode_post_setxattr(struct dentry *dentry,
> -				    const char *xattr_name,
> -				    const void *xattr_value,
> -				    size_t xattr_value_len,
> -				    int flags);
> -extern int evm_inode_removexattr(struct mnt_idmap *idmap,
> -				 struct dentry *dentry, const char *xattr_name);
> -extern void evm_inode_post_removexattr(struct dentry *dentry,
> -				       const char *xattr_name);
> -static inline void evm_inode_post_remove_acl(struct mnt_idmap *idmap,
> -					     struct dentry *dentry,
> -					     const char *acl_name)
> -{
> -	evm_inode_post_removexattr(dentry, acl_name);
> -}
> -extern int evm_inode_set_acl(struct mnt_idmap *idmap,
> -			     struct dentry *dentry, const char *acl_name,
> -			     struct posix_acl *kacl);
> -static inline int evm_inode_remove_acl(struct mnt_idmap *idmap,
> -				       struct dentry *dentry,
> -				       const char *acl_name)
> -{
> -	return evm_inode_set_acl(idmap, dentry, acl_name, NULL);
> -}
> -static inline void evm_inode_post_set_acl(struct dentry *dentry,
> -					  const char *acl_name,
> -					  struct posix_acl *kacl)
> -{
> -	return evm_inode_post_setxattr(dentry, acl_name, NULL, 0, 0);
> -}
> -
>  int evm_inode_init_security(struct inode *inode, struct inode *dir,
>  			    const struct qstr *qstr, struct xattr *xattrs,
>  			    int *xattr_count);
> @@ -93,75 +55,6 @@ static inline enum integrity_status evm_verifyxattr(struct dentry *dentry,
>  }
>  #endif
>  
> -static inline int evm_inode_setattr(struct mnt_idmap *idmap,
> -				    struct dentry *dentry, struct iattr *attr)
> -{
> -	return 0;
> -}
> -
> -static inline void evm_inode_post_setattr(struct mnt_idmap *idmap,
> -					  struct dentry *dentry, int ia_valid)
> -{
> -	return;
> -}
> -
> -static inline int evm_inode_setxattr(struct mnt_idmap *idmap,
> -				     struct dentry *dentry, const char *name,
> -				     const void *value, size_t size, int flags)
> -{
> -	return 0;
> -}
> -
> -static inline void evm_inode_post_setxattr(struct dentry *dentry,
> -					   const char *xattr_name,
> -					   const void *xattr_value,
> -					   size_t xattr_value_len,
> -					   int flags)
> -{
> -	return;
> -}
> -
> -static inline int evm_inode_removexattr(struct mnt_idmap *idmap,
> -					struct dentry *dentry,
> -					const char *xattr_name)
> -{
> -	return 0;
> -}
> -
> -static inline void evm_inode_post_removexattr(struct dentry *dentry,
> -					      const char *xattr_name)
> -{
> -	return;
> -}
> -
> -static inline void evm_inode_post_remove_acl(struct mnt_idmap *idmap,
> -					     struct dentry *dentry,
> -					     const char *acl_name)
> -{
> -	return;
> -}
> -
> -static inline int evm_inode_set_acl(struct mnt_idmap *idmap,
> -				    struct dentry *dentry, const char *acl_name,
> -				    struct posix_acl *kacl)
> -{
> -	return 0;
> -}
> -
> -static inline int evm_inode_remove_acl(struct mnt_idmap *idmap,
> -				       struct dentry *dentry,
> -				       const char *acl_name)
> -{
> -	return 0;
> -}
> -
> -static inline void evm_inode_post_set_acl(struct dentry *dentry,
> -					  const char *acl_name,
> -					  struct posix_acl *kacl)
> -{
> -	return;
> -}
> -
>  static inline int evm_inode_init_security(struct inode *inode, struct inode *dir,
>  					  const struct qstr *qstr,
>  					  struct xattr *xattrs,
> diff --git a/include/uapi/linux/lsm.h b/include/uapi/linux/lsm.h
> index ee7d034255a9..825339bcd580 100644
> --- a/include/uapi/linux/lsm.h
> +++ b/include/uapi/linux/lsm.h
> @@ -62,6 +62,7 @@ struct lsm_ctx {
>  #define LSM_ID_BPF		109
>  #define LSM_ID_LANDLOCK		110
>  #define LSM_ID_IMA		111
> +#define LSM_ID_EVM		112
>  
>  /*
>   * LSM_ATTR_XXX definitions identify different LSM attributes
> diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c
> index ea84a6f835ff..21560874e5fc 100644
> --- a/security/integrity/evm/evm_main.c
> +++ b/security/integrity/evm/evm_main.c
> @@ -566,9 +566,9 @@ static int evm_protect_xattr(struct mnt_idmap *idmap,
>   * userspace from writing HMAC value.  Writing 'security.evm' requires
>   * requires CAP_SYS_ADMIN privileges.
>   */
> -int evm_inode_setxattr(struct mnt_idmap *idmap, struct dentry *dentry,
> -		       const char *xattr_name, const void *xattr_value,
> -		       size_t xattr_value_len, int flags)
> +static int evm_inode_setxattr(struct mnt_idmap *idmap, struct dentry *dentry,
> +			      const char *xattr_name, const void *xattr_value,
> +			      size_t xattr_value_len, int flags)
>  {
>  	const struct evm_ima_xattr_data *xattr_data = xattr_value;
>  
> @@ -598,8 +598,8 @@ int evm_inode_setxattr(struct mnt_idmap *idmap, struct dentry *dentry,
>   * Removing 'security.evm' requires CAP_SYS_ADMIN privileges and that
>   * the current value is valid.
>   */
> -int evm_inode_removexattr(struct mnt_idmap *idmap,
> -			  struct dentry *dentry, const char *xattr_name)
> +static int evm_inode_removexattr(struct mnt_idmap *idmap, struct dentry *dentry,
> +				 const char *xattr_name)
>  {
>  	/* Policy permits modification of the protected xattrs even though
>  	 * there's no HMAC key loaded
> @@ -649,9 +649,11 @@ static inline int evm_inode_set_acl_change(struct mnt_idmap *idmap,
>   * Prevent modifying posix acls causing the EVM HMAC to be re-calculated
>   * and 'security.evm' xattr updated, unless the existing 'security.evm' is
>   * valid.
> + *
> + * Return: zero on success, -EPERM on failure.
>   */
> -int evm_inode_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
> -		      const char *acl_name, struct posix_acl *kacl)
> +static int evm_inode_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
> +			     const char *acl_name, struct posix_acl *kacl)
>  {
>  	enum integrity_status evm_status;
>  
> @@ -690,6 +692,24 @@ int evm_inode_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
>  	return -EPERM;
>  }
>  
> +/**
> + * evm_inode_remove_acl - Protect the EVM extended attribute from posix acls
> + * @idmap: idmap of the mount
> + * @dentry: pointer to the affected dentry
> + * @acl_name: name of the posix acl
> + *
> + * Prevent removing posix acls causing the EVM HMAC to be re-calculated
> + * and 'security.evm' xattr updated, unless the existing 'security.evm' is
> + * valid.
> + *
> + * Return: zero on success, -EPERM on failure.
> + */
> +static int evm_inode_remove_acl(struct mnt_idmap *idmap, struct dentry *dentry,
> +				const char *acl_name)
> +{
> +	return evm_inode_set_acl(idmap, dentry, acl_name, NULL);
> +}
> +
>  static void evm_reset_status(struct inode *inode)
>  {
>  	struct integrity_iint_cache *iint;
> @@ -738,9 +758,11 @@ bool evm_revalidate_status(const char *xattr_name)
>   * __vfs_setxattr_noperm().  The caller of which has taken the inode's
>   * i_mutex lock.
>   */
> -void evm_inode_post_setxattr(struct dentry *dentry, const char *xattr_name,
> -			     const void *xattr_value, size_t xattr_value_len,
> -			     int flags)
> +static void evm_inode_post_setxattr(struct dentry *dentry,
> +				    const char *xattr_name,
> +				    const void *xattr_value,
> +				    size_t xattr_value_len,
> +				    int flags)
>  {
>  	if (!evm_revalidate_status(xattr_name))
>  		return;
> @@ -756,6 +778,21 @@ void evm_inode_post_setxattr(struct dentry *dentry, const char *xattr_name,
>  	evm_update_evmxattr(dentry, xattr_name, xattr_value, xattr_value_len);
>  }
>  
> +/**
> + * evm_inode_post_set_acl - Update the EVM extended attribute from posix acls
> + * @dentry: pointer to the affected dentry
> + * @acl_name: name of the posix acl
> + * @kacl: pointer to the posix acls
> + *
> + * Update the 'security.evm' xattr with the EVM HMAC re-calculated after setting
> + * posix acls.
> + */
> +static void evm_inode_post_set_acl(struct dentry *dentry, const char *acl_name,
> +				   struct posix_acl *kacl)
> +{
> +	return evm_inode_post_setxattr(dentry, acl_name, NULL, 0, 0);
> +}
> +
>  /**
>   * evm_inode_post_removexattr - update 'security.evm' after removing the xattr
>   * @dentry: pointer to the affected dentry
> @@ -766,7 +803,8 @@ void evm_inode_post_setxattr(struct dentry *dentry, const char *xattr_name,
>   * No need to take the i_mutex lock here, as this function is called from
>   * vfs_removexattr() which takes the i_mutex.
>   */
> -void evm_inode_post_removexattr(struct dentry *dentry, const char *xattr_name)
> +static void evm_inode_post_removexattr(struct dentry *dentry,
> +				       const char *xattr_name)
>  {
>  	if (!evm_revalidate_status(xattr_name))
>  		return;
> @@ -782,6 +820,22 @@ void evm_inode_post_removexattr(struct dentry *dentry, const char *xattr_name)
>  	evm_update_evmxattr(dentry, xattr_name, NULL, 0);
>  }
>  
> +/**
> + * evm_inode_post_remove_acl - Update the EVM extended attribute from posix acls
> + * @idmap: idmap of the mount
> + * @dentry: pointer to the affected dentry
> + * @acl_name: name of the posix acl
> + *
> + * Update the 'security.evm' xattr with the EVM HMAC re-calculated after
> + * removing posix acls.
> + */
> +static inline void evm_inode_post_remove_acl(struct mnt_idmap *idmap,
> +					     struct dentry *dentry,
> +					     const char *acl_name)
> +{
> +	evm_inode_post_removexattr(dentry, acl_name);
> +}
> +
>  static int evm_attr_change(struct mnt_idmap *idmap,
>  			   struct dentry *dentry, struct iattr *attr)
>  {
> @@ -805,8 +859,8 @@ static int evm_attr_change(struct mnt_idmap *idmap,
>   * Permit update of file attributes when files have a valid EVM signature,
>   * except in the case of them having an immutable portable signature.
>   */
> -int evm_inode_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
> -		      struct iattr *attr)
> +static int evm_inode_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
> +			     struct iattr *attr)
>  {
>  	unsigned int ia_valid = attr->ia_valid;
>  	enum integrity_status evm_status;
> @@ -853,8 +907,8 @@ int evm_inode_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
>   * This function is called from notify_change(), which expects the caller
>   * to lock the inode's i_mutex.
>   */
> -void evm_inode_post_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
> -			    int ia_valid)
> +static void evm_inode_post_setattr(struct mnt_idmap *idmap,
> +				   struct dentry *dentry, int ia_valid)
>  {
>  	if (!evm_revalidate_status(NULL))
>  		return;
> @@ -964,4 +1018,57 @@ static int __init init_evm(void)
>  	return error;
>  }
>  
> +static struct security_hook_list evm_hooks[] __ro_after_init = {
> +	LSM_HOOK_INIT(inode_setattr, evm_inode_setattr),
> +	LSM_HOOK_INIT(inode_post_setattr, evm_inode_post_setattr),
> +	LSM_HOOK_INIT(inode_setxattr, evm_inode_setxattr),
> +	LSM_HOOK_INIT(inode_set_acl, evm_inode_set_acl),
> +	LSM_HOOK_INIT(inode_post_set_acl, evm_inode_post_set_acl),
> +	LSM_HOOK_INIT(inode_remove_acl, evm_inode_remove_acl),
> +	LSM_HOOK_INIT(inode_post_remove_acl, evm_inode_post_remove_acl),
> +	LSM_HOOK_INIT(inode_post_setxattr, evm_inode_post_setxattr),
> +	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),
> +};
> +
> +static const struct lsm_id evm_lsmid = {
> +	.name = "evm",
> +	.id = LSM_ID_EVM,
> +};
> +
> +/* Return the EVM LSM ID, if EVM is enabled or NULL if not. */
> +const struct lsm_id *evm_get_lsm_id(void)
> +{
> +	return &evm_lsmid;
> +}
> +
> +/*
> + * Since with the LSM_ORDER_LAST there is no guarantee about the ordering
> + * within the .lsm_info.init section, ensure that IMA hooks are before EVM
> + * ones, by letting the 'integrity' LSM call init_evm_lsm() to initialize the
> + * 'ima' and 'evm' LSMs in this sequence.
> + */
> +void __init init_evm_lsm(void)
> +{
> +	security_add_hooks(evm_hooks, ARRAY_SIZE(evm_hooks), &evm_lsmid);
> +}
> +
> +static struct lsm_blob_sizes evm_blob_sizes __ro_after_init = {
> +	.lbs_xattr_count = 1,
> +};
> +
> +/* Introduce a dummy function as 'evm' init method (it cannot be NULL). */
> +static int __init dummy_init_evm_lsm(void)
> +{
> +	return 0;
> +}
> +
> +DEFINE_LSM(evm) = {
> +	.name = "evm",
> +	.init = dummy_init_evm_lsm,
> +	.order = LSM_ORDER_LAST,
> +	.blobs = &evm_blob_sizes,
> +};
> +
>  late_initcall(init_evm);
> diff --git a/security/integrity/iint.c b/security/integrity/iint.c
> index 87f2c0d69f78..0b0ac71142e8 100644
> --- a/security/integrity/iint.c
> +++ b/security/integrity/iint.c
> @@ -199,6 +199,7 @@ static int __init integrity_lsm_init(void)
>  	    kmem_cache_create("iint_cache", sizeof(struct integrity_iint_cache),
>  			      0, SLAB_PANIC, iint_init_once);
>  	init_ima_lsm();
> +	init_evm_lsm();
>  	return 0;
>  }
>  
> diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h
> index 3098cae1c27c..7534ec06324e 100644
> --- a/security/integrity/integrity.h
> +++ b/security/integrity/integrity.h
> @@ -209,6 +209,21 @@ static inline void __init init_ima_lsm(void)
>  
>  #endif
>  
> +#ifdef CONFIG_EVM
> +const struct lsm_id *evm_get_lsm_id(void);
> +void __init init_evm_lsm(void);
> +#else
> +static inline const struct lsm_id *evm_get_lsm_id(void)
> +{
> +	return NULL;
> +}
> +
> +static inline void __init init_evm_lsm(void)
> +{
> +}
> +
> +#endif
> +
>  #ifdef CONFIG_INTEGRITY_SIGNATURE
>  
>  int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
> diff --git a/security/security.c b/security/security.c
> index 456f3fe74116..9703549b6ddc 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -20,13 +20,13 @@
>  #include <linux/kernel_read_file.h>
>  #include <linux/lsm_hooks.h>
>  #include <linux/integrity.h>
> -#include <linux/evm.h>
>  #include <linux/fsnotify.h>
>  #include <linux/mman.h>
>  #include <linux/mount.h>
>  #include <linux/personality.h>
>  #include <linux/backing-dev.h>
>  #include <linux/string.h>
> +#include <linux/xattr.h>
>  #include <linux/msg.h>
>  #include <net/flow.h>
>  
> @@ -50,7 +50,8 @@
>  	(IS_ENABLED(CONFIG_SECURITY_LOCKDOWN_LSM) ? 1 : 0) + \
>  	(IS_ENABLED(CONFIG_BPF_LSM) ? 1 : 0) + \
>  	(IS_ENABLED(CONFIG_SECURITY_LANDLOCK) ? 1 : 0) + \
> -	(IS_ENABLED(CONFIG_IMA) ? 1 : 0))
> +	(IS_ENABLED(CONFIG_IMA) ? 1 : 0) + \
> +	(IS_ENABLED(CONFIG_EVM) ? 1 : 0))
>  
>  /*
>   * These are descriptions of the reasons that can be passed to the
> @@ -1715,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;
> @@ -1740,10 +1741,6 @@ int security_inode_init_security(struct inode *inode, struct inode *dir,
>  	if (!xattr_count)
>  		goto out;
>  
> -	ret = evm_inode_init_security(inode, dir, qstr, new_xattrs,
> -				      &xattr_count);
> -	if (ret)
> -		goto out;
>  	ret = initxattrs(inode, new_xattrs, fs_data);
>  out:
>  	for (; xattr_count > 0; xattr_count--)
> @@ -2235,14 +2232,9 @@ int security_inode_permission(struct inode *inode, int mask)
>  int security_inode_setattr(struct mnt_idmap *idmap,
>  			   struct dentry *dentry, struct iattr *attr)
>  {
> -	int ret;
> -
>  	if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
>  		return 0;
> -	ret = call_int_hook(inode_setattr, 0, idmap, dentry, attr);
> -	if (ret)
> -		return ret;
> -	return evm_inode_setattr(idmap, dentry, attr);
> +	return call_int_hook(inode_setattr, 0, idmap, dentry, attr);
>  }
>  EXPORT_SYMBOL_GPL(security_inode_setattr);
>  
> @@ -2307,9 +2299,7 @@ int security_inode_setxattr(struct mnt_idmap *idmap,
>  
>  	if (ret == 1)
>  		ret = cap_inode_setxattr(dentry, name, value, size, flags);
> -	if (ret)
> -		return ret;
> -	return evm_inode_setxattr(idmap, dentry, name, value, size, flags);
> +	return ret;
>  }
>  
>  /**
> @@ -2328,15 +2318,10 @@ int security_inode_set_acl(struct mnt_idmap *idmap,
>  			   struct dentry *dentry, const char *acl_name,
>  			   struct posix_acl *kacl)
>  {
> -	int ret;
> -
>  	if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
>  		return 0;
> -	ret = call_int_hook(inode_set_acl, 0, idmap, dentry, acl_name,
> -			    kacl);
> -	if (ret)
> -		return ret;
> -	return evm_inode_set_acl(idmap, dentry, acl_name, kacl);
> +	return call_int_hook(inode_set_acl, 0, idmap, dentry, acl_name,
> +			     kacl);
>  }
>  
>  /**
> @@ -2389,14 +2374,9 @@ int security_inode_get_acl(struct mnt_idmap *idmap,
>  int security_inode_remove_acl(struct mnt_idmap *idmap,
>  			      struct dentry *dentry, const char *acl_name)
>  {
> -	int ret;
> -
>  	if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
>  		return 0;
> -	ret = call_int_hook(inode_remove_acl, 0, idmap, dentry, acl_name);
> -	if (ret)
> -		return ret;
> -	return evm_inode_remove_acl(idmap, dentry, acl_name);
> +	return call_int_hook(inode_remove_acl, 0, idmap, dentry, acl_name);
>  }
>  
>  /**
> @@ -2432,7 +2412,6 @@ void security_inode_post_setxattr(struct dentry *dentry, const char *name,
>  	if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
>  		return;
>  	call_void_hook(inode_post_setxattr, dentry, name, value, size, flags);
> -	evm_inode_post_setxattr(dentry, name, value, size, flags);
>  }
>  
>  /**
> @@ -2493,9 +2472,7 @@ int security_inode_removexattr(struct mnt_idmap *idmap,
>  	ret = call_int_hook(inode_removexattr, 1, idmap, dentry, name);
>  	if (ret == 1)
>  		ret = cap_inode_removexattr(idmap, dentry, name);
> -	if (ret)
> -		return ret;
> -	return evm_inode_removexattr(idmap, dentry, name);
> +	return ret;
>  }
>  
>  /**

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v5 22/23] integrity: Move integrity functions to the LSM infrastructure
  2023-11-07 13:40 ` [PATCH v5 22/23] integrity: Move integrity functions to the " Roberto Sassu
@ 2023-11-07 18:46   ` Casey Schaufler
  2023-11-16  4:33   ` Paul Moore
  1 sibling, 0 replies; 96+ messages in thread
From: Casey Schaufler @ 2023-11-07 18:46 UTC (permalink / raw)
  To: Roberto Sassu, viro, brauner, chuck.lever, jlayton, neilb, kolga,
	Dai.Ngo, tom, paul, jmorris, serge, zohar, dmitry.kasatkin,
	dhowells, jarkko, stephen.smalley.work, eparis, mic
  Cc: linux-fsdevel, linux-kernel, linux-nfs, linux-security-module,
	linux-integrity, keyrings, selinux, Roberto Sassu,
	Casey Schaufler

On 11/7/2023 5:40 AM, Roberto Sassu wrote:
> From: Roberto Sassu <roberto.sassu@huawei.com>
>
> Remove hardcoded calls to integrity functions from the LSM infrastructure
> and, instead, register them in integrity_lsm_init() with the IMA or EVM
> LSM ID (the first non-NULL returned by ima_get_lsm_id() and
> evm_get_lsm_id()).
>
> Also move the global declaration of integrity_inode_get() to
> security/integrity/integrity.h, so that the function can be still called by
> IMA.
>
> Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>

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


> ---
>  include/linux/integrity.h      | 26 --------------------------
>  security/integrity/iint.c      | 30 +++++++++++++++++++++++++++++-
>  security/integrity/integrity.h |  7 +++++++
>  security/security.c            |  9 +--------
>  4 files changed, 37 insertions(+), 35 deletions(-)
>
> diff --git a/include/linux/integrity.h b/include/linux/integrity.h
> index 2ea0f2f65ab6..afaae7ad26f4 100644
> --- a/include/linux/integrity.h
> +++ b/include/linux/integrity.h
> @@ -21,38 +21,12 @@ enum integrity_status {
>  
>  /* 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)
>  {
>  }
>  #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/iint.c b/security/integrity/iint.c
> index 0b0ac71142e8..882fde2a2607 100644
> --- a/security/integrity/iint.c
> +++ b/security/integrity/iint.c
> @@ -171,7 +171,7 @@ struct integrity_iint_cache *integrity_inode_get(struct inode *inode)
>   *
>   * Free the integrity information(iint) associated with an inode.
>   */
> -void integrity_inode_free(struct inode *inode)
> +static void integrity_inode_free(struct inode *inode)
>  {
>  	struct integrity_iint_cache *iint;
>  
> @@ -193,11 +193,39 @@ static void iint_init_once(void *foo)
>  	memset(iint, 0, sizeof(*iint));
>  }
>  
> +static struct security_hook_list integrity_hooks[] __ro_after_init = {
> +	LSM_HOOK_INIT(inode_free_security, integrity_inode_free),
> +#ifdef CONFIG_INTEGRITY_ASYMMETRIC_KEYS
> +	LSM_HOOK_INIT(kernel_module_request, integrity_kernel_module_request),
> +#endif
> +};
> +
> +/*
> + * Perform the initialization of the 'integrity', 'ima' and 'evm' LSMs to
> + * ensure that the management of integrity metadata is working at the time
> + * IMA and EVM hooks are registered to the LSM infrastructure, and to keep
> + * the original ordering of IMA and EVM functions as when they were hardcoded.
> + */
>  static int __init integrity_lsm_init(void)
>  {
> +	const struct lsm_id *lsmid;
> +
>  	iint_cache =
>  	    kmem_cache_create("iint_cache", sizeof(struct integrity_iint_cache),
>  			      0, SLAB_PANIC, iint_init_once);
> +	/*
> +	 * Obtain either the IMA or EVM LSM ID to register integrity-specific
> +	 * hooks under that LSM, since there is no LSM ID assigned to the
> +	 * 'integrity' LSM.
> +	 */
> +	lsmid = ima_get_lsm_id();
> +	if (!lsmid)
> +		lsmid = evm_get_lsm_id();
> +	/* No point in continuing, since both IMA and EVM are disabled. */
> +	if (!lsmid)
> +		return 0;
> +
> +	security_add_hooks(integrity_hooks, ARRAY_SIZE(integrity_hooks), lsmid);
>  	init_ima_lsm();
>  	init_evm_lsm();
>  	return 0;
> diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h
> index 7534ec06324e..e4df82d6f6e7 100644
> --- a/security/integrity/integrity.h
> +++ b/security/integrity/integrity.h
> @@ -180,6 +180,7 @@ struct integrity_iint_cache {
>   * integrity data associated with an inode.
>   */
>  struct integrity_iint_cache *integrity_iint_find(struct inode *inode);
> +struct integrity_iint_cache *integrity_inode_get(struct inode *inode);
>  
>  int integrity_kernel_read(struct file *file, loff_t offset,
>  			  void *addr, unsigned long count);
> @@ -266,12 +267,18 @@ static inline int __init integrity_load_cert(const unsigned int id,
>  #ifdef CONFIG_INTEGRITY_ASYMMETRIC_KEYS
>  int asymmetric_verify(struct key *keyring, const char *sig,
>  		      int siglen, const char *data, int datalen);
> +int integrity_kernel_module_request(char *kmod_name);
>  #else
>  static inline int asymmetric_verify(struct key *keyring, const char *sig,
>  				    int siglen, const char *data, int datalen)
>  {
>  	return -EOPNOTSUPP;
>  }
> +
> +static inline int integrity_kernel_module_request(char *kmod_name)
> +{
> +	return 0;
> +}
>  #endif
>  
>  #ifdef CONFIG_IMA_APPRAISE_MODSIG
> diff --git a/security/security.c b/security/security.c
> index 9703549b6ddc..0d9eaa4cd260 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
> @@ -3182,12 +3180,7 @@ int security_kernel_create_files_as(struct cred *new, struct inode *inode)
>   */
>  int security_kernel_module_request(char *kmod_name)
>  {
> -	int ret;
> -
> -	ret = call_int_hook(kernel_module_request, 0, kmod_name);
> -	if (ret)
> -		return ret;
> -	return integrity_kernel_module_request(kmod_name);
> +	return call_int_hook(kernel_module_request, 0, kmod_name);
>  }
>  
>  /**

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v5 00/23] security: Move IMA and EVM to the LSM infrastructure
  2023-11-07 14:05 ` [PATCH v5 00/23] security: Move IMA and EVM to the LSM infrastructure Roberto Sassu
@ 2023-11-07 19:37   ` Mimi Zohar
  2023-11-08  3:14   ` Paul Moore
  1 sibling, 0 replies; 96+ messages in thread
From: Mimi Zohar @ 2023-11-07 19:37 UTC (permalink / raw)
  To: Roberto Sassu, viro, brauner, chuck.lever, jlayton, neilb, kolga,
	Dai.Ngo, tom, paul, jmorris, serge, dmitry.kasatkin, dhowells,
	jarkko, stephen.smalley.work, eparis, casey, mic
  Cc: linux-fsdevel, linux-kernel, linux-nfs, linux-security-module,
	linux-integrity, keyrings, selinux, Roberto Sassu

On Tue, 2023-11-07 at 15:05 +0100, Roberto Sassu wrote:
> I kindly ask your support to add the missing reviewed-by/acked-by. I
> summarize what is missing below:
> 
> - @Mimi: patches 1, 2, 4, 5, 6, 19, 21, 22, 23 (IMA/EVM-specific
>          patches)

Thanks, Roberto.  I reviewed and commented on the entire patch set.
	Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>h


^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v5 00/23] security: Move IMA and EVM to the LSM infrastructure
  2023-11-07 14:05 ` [PATCH v5 00/23] security: Move IMA and EVM to the LSM infrastructure Roberto Sassu
  2023-11-07 19:37   ` Mimi Zohar
@ 2023-11-08  3:14   ` Paul Moore
  1 sibling, 0 replies; 96+ messages in thread
From: Paul Moore @ 2023-11-08  3:14 UTC (permalink / raw)
  To: Roberto Sassu
  Cc: viro, brauner, chuck.lever, jlayton, neilb, kolga, Dai.Ngo, tom,
	jmorris, serge, zohar, dmitry.kasatkin, dhowells, jarkko,
	stephen.smalley.work, eparis, casey, mic, linux-fsdevel,
	linux-kernel, linux-nfs, linux-security-module, linux-integrity,
	keyrings, selinux, Roberto Sassu

On Tue, Nov 7, 2023 at 9:06 AM Roberto Sassu
<roberto.sassu@huaweicloud.com> wrote:
> Hi everyone
>
> I kindly ask your support to add the missing reviewed-by/acked-by. I
> summarize what is missing below:
>
> - @Mimi: patches 1, 2, 4, 5, 6, 19, 21, 22, 23 (IMA/EVM-specific
>          patches)
> - @Al/@Christian: patches 10-17 (VFS-specific patches)
> - @Paul: patches 10-23 (VFS-specific patches/new LSM hooks/new LSMs)

This patchset is next in my review queue :)

> - @David Howells/@Jarkko: patch 18 (new LSM hook in the key subsystem)
> - @Chuck Lever: patch 12 (new LSM hook in nfsd/vfs.c)
>
> Paul, as I mentioned I currently based the patch set on lsm/dev-
> staging, which include the following dependencies:
>
> 8f79e425c140 lsm: don't yet account for IMA in LSM_CONFIG_COUNT calculation
> 3c91a124f23d lsm: drop LSM_ID_IMA
>
> I know you wanted to wait until at least rc1 to make lsm/dev. I will
> help for rebasing my patch set, if needed.

No, it should be fine for right now.  Thanks for your patience and
help with all of this.

-- 
paul-moore.com

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v5 10/23] security: Introduce inode_post_setattr hook
  2023-11-07 13:39 ` [PATCH v5 10/23] security: Introduce inode_post_setattr hook Roberto Sassu
  2023-11-07 17:30   ` Casey Schaufler
@ 2023-11-16  4:33   ` Paul Moore
  2023-11-16  9:43     ` Roberto Sassu
  1 sibling, 1 reply; 96+ messages in thread
From: Paul Moore @ 2023-11-16  4:33 UTC (permalink / raw)
  To: Roberto Sassu, viro, brauner, chuck.lever, jlayton, neilb, kolga,
	Dai.Ngo, tom, jmorris, serge, zohar, dmitry.kasatkin, dhowells,
	jarkko, stephen.smalley.work, eparis, casey, mic
  Cc: linux-fsdevel, linux-kernel, linux-nfs, linux-security-module,
	linux-integrity, keyrings, selinux, Roberto Sassu, Stefan Berger

On Nov  7, 2023 Roberto Sassu <roberto.sassu@huaweicloud.com> wrote:
> 
> In preparation for moving IMA and EVM to the LSM infrastructure, introduce
> the inode_post_setattr hook.
> 
> At inode_setattr hook, EVM verifies the file's existing HMAC value. At
> inode_post_setattr, EVM re-calculates the file's HMAC based on the modified
> file attributes and other file metadata.
> 
> Other LSMs could similarly take some action after successful file attribute
> change.
> 
> 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>
> Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
> Acked-by: Casey Schaufler <casey@schaufler-ca.com>
> ---
>  fs/attr.c                     |  1 +
>  include/linux/lsm_hook_defs.h |  2 ++
>  include/linux/security.h      |  7 +++++++
>  security/security.c           | 16 ++++++++++++++++
>  4 files changed, 26 insertions(+)

...

> diff --git a/security/security.c b/security/security.c
> index 7935d11d58b5..ce3bc7642e18 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -2222,6 +2222,22 @@ int security_inode_setattr(struct mnt_idmap *idmap,
>  }
>  EXPORT_SYMBOL_GPL(security_inode_setattr);
>  
> +/**
> + * security_inode_post_setattr() - Update the inode after a setattr operation
> + * @idmap: idmap of the mount
> + * @dentry: file
> + * @ia_valid: file attributes set
> + *
> + * Update inode security field after successful setting file attributes.
> + */
> +void security_inode_post_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
> +				 int ia_valid)
> +{
> +	if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
> +		return;

I may be missing it, but I don't see the S_PRIVATE flag check in the
existing IMA or EVM hooks so I'm curious as to why it is added here?
Please don't misunderstand me, I think it makes sense to return early
on private dentrys/inodes, but why aren't we doing that now?

> +	call_void_hook(inode_post_setattr, idmap, dentry, ia_valid);
> +}
> +
>  /**
>   * security_inode_getattr() - Check if getting file attributes is allowed
>   * @path: file
> -- 
> 2.34.1

--
paul-moore.com

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v5 11/23] security: Introduce inode_post_removexattr hook
  2023-11-07 13:40 ` [PATCH v5 11/23] security: Introduce inode_post_removexattr hook Roberto Sassu
  2023-11-07 17:33   ` Casey Schaufler
@ 2023-11-16  4:33   ` Paul Moore
  1 sibling, 0 replies; 96+ messages in thread
From: Paul Moore @ 2023-11-16  4:33 UTC (permalink / raw)
  To: Roberto Sassu, viro, brauner, chuck.lever, jlayton, neilb, kolga,
	Dai.Ngo, tom, jmorris, serge, zohar, dmitry.kasatkin, dhowells,
	jarkko, stephen.smalley.work, eparis, casey, mic
  Cc: linux-fsdevel, linux-kernel, linux-nfs, linux-security-module,
	linux-integrity, keyrings, selinux, Roberto Sassu, Stefan Berger

On Nov  7, 2023 Roberto Sassu <roberto.sassu@huaweicloud.com> wrote:
> 
> In preparation for moving IMA and EVM to the LSM infrastructure, introduce
> the inode_post_removexattr hook.
> 
> At inode_removexattr hook, EVM verifies the file's existing HMAC value. At
> inode_post_removexattr, EVM re-calculates the file's HMAC with the passed
> xattr removed and other file metadata.
> 
> Other LSMs could similarly take some action after successful xattr removal.
> 
> 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>
> Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
> ---
>  fs/xattr.c                    |  9 +++++----
>  include/linux/lsm_hook_defs.h |  2 ++
>  include/linux/security.h      |  5 +++++
>  security/security.c           | 14 ++++++++++++++
>  4 files changed, 26 insertions(+), 4 deletions(-)

...

> diff --git a/security/security.c b/security/security.c
> index ce3bc7642e18..8aa6e9f316dd 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -2452,6 +2452,20 @@ int security_inode_removexattr(struct mnt_idmap *idmap,
>  	return evm_inode_removexattr(idmap, dentry, name);
>  }
>  
> +/**
> + * security_inode_post_removexattr() - Update the inode after a removexattr op
> + * @dentry: file
> + * @name: xattr name
> + *
> + * Update the inode after a successful removexattr operation.
> + */
> +void security_inode_post_removexattr(struct dentry *dentry, const char *name)
> +{
> +	if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
> +		return;

Similar comment about the S_PRIVATE check as was in patch 10/23.

> +	call_void_hook(inode_post_removexattr, dentry, name);
> +}
> +
>  /**
>   * security_inode_need_killpriv() - Check if security_inode_killpriv() required
>   * @dentry: associated dentry
> -- 
> 2.34.1

--
paul-moore.com

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v5 13/23] security: Introduce file_pre_free_security hook
  2023-11-07 13:40 ` [PATCH v5 13/23] security: Introduce file_pre_free_security hook Roberto Sassu
  2023-11-07 17:39   ` Casey Schaufler
@ 2023-11-16  4:33   ` Paul Moore
  2023-11-16  9:46     ` Roberto Sassu
  1 sibling, 1 reply; 96+ messages in thread
From: Paul Moore @ 2023-11-16  4:33 UTC (permalink / raw)
  To: Roberto Sassu, viro, brauner, chuck.lever, jlayton, neilb, kolga,
	Dai.Ngo, tom, jmorris, serge, zohar, dmitry.kasatkin, dhowells,
	jarkko, stephen.smalley.work, eparis, casey, mic
  Cc: linux-fsdevel, linux-kernel, linux-nfs, linux-security-module,
	linux-integrity, keyrings, selinux, Roberto Sassu

On Nov  7, 2023 Roberto Sassu <roberto.sassu@huaweicloud.com> wrote:
> 
> In preparation for moving IMA and EVM to the LSM infrastructure, introduce
> the file_pre_free_security 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.
> 
> LSMs could also take some action before the last reference of a file is
> released.
> 
> The new hook cannot return an error and cannot cause the operation to be
> reverted.
> 
> 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/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..64ed74555e64 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_pre_free(file);

I worry that security_file_pre_free() is a misleading name as "free"
tends to imply memory management tasks, which isn't the main focus of
this hook.  What do you think of security_file_release() or
security_file_put() instead?

>  	ima_file_free(file);
>  	if (unlikely(file->f_flags & FASYNC)) {
>  		if (file->f_op->fasync)

--
paul-moore.com

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v5 15/23] security: Introduce inode_post_create_tmpfile  hook
  2023-11-07 13:40 ` [PATCH v5 15/23] security: Introduce inode_post_create_tmpfile hook Roberto Sassu
  2023-11-07 17:42   ` Casey Schaufler
@ 2023-11-16  4:33   ` Paul Moore
  1 sibling, 0 replies; 96+ messages in thread
From: Paul Moore @ 2023-11-16  4:33 UTC (permalink / raw)
  To: Roberto Sassu, viro, brauner, chuck.lever, jlayton, neilb, kolga,
	Dai.Ngo, tom, jmorris, serge, zohar, dmitry.kasatkin, dhowells,
	jarkko, stephen.smalley.work, eparis, casey, mic
  Cc: linux-fsdevel, linux-kernel, linux-nfs, linux-security-module,
	linux-integrity, keyrings, selinux, Roberto Sassu

On Nov  7, 2023 Roberto Sassu <roberto.sassu@huaweicloud.com> wrote:
> 
> 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 +
>  include/linux/lsm_hook_defs.h |  2 ++
>  include/linux/security.h      |  6 ++++++
>  security/security.c           | 15 +++++++++++++++
>  4 files changed, 24 insertions(+)

...

> diff --git a/security/security.c b/security/security.c
> index 5eaf5f2aa5ea..ca650c285fd9 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;

See my previous comments/questions about checking for S_PRIVATE here.

> +	call_void_hook(inode_post_create_tmpfile, idmap, inode);
> +}
> +
>  /**
>   * security_inode_link() - Check if creating a hard link is allowed
>   * @old_dentry: existing file
> -- 
> 2.34.1

--
paul-moore.com

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v5 16/23] security: Introduce inode_post_set_acl hook
  2023-11-07 13:40 ` [PATCH v5 16/23] security: Introduce inode_post_set_acl hook Roberto Sassu
  2023-11-07 17:44   ` Casey Schaufler
@ 2023-11-16  4:33   ` Paul Moore
  1 sibling, 0 replies; 96+ messages in thread
From: Paul Moore @ 2023-11-16  4:33 UTC (permalink / raw)
  To: Roberto Sassu, viro, brauner, chuck.lever, jlayton, neilb, kolga,
	Dai.Ngo, tom, jmorris, serge, zohar, dmitry.kasatkin, dhowells,
	jarkko, stephen.smalley.work, eparis, casey, mic
  Cc: linux-fsdevel, linux-kernel, linux-nfs, linux-security-module,
	linux-integrity, keyrings, selinux, Roberto Sassu, Stefan Berger

On Nov  7, 2023 Roberto Sassu <roberto.sassu@huaweicloud.com> wrote:
> 
> In preparation for moving IMA and EVM to the LSM infrastructure, introduce
> the inode_post_set_acl hook.
> 
> At inode_set_acl hook, EVM verifies the file's existing HMAC value. At
> inode_post_set_acl, EVM re-calculates the file's HMAC based on the modified
> POSIX ACL and other file metadata.
> 
> Other LSMs could similarly take some action after successful POSIX ACL
> change.
> 
> 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>
> Acked-by: Casey Schaufler <casey@schaufler-ca.com>
> Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
> ---
>  fs/posix_acl.c                |  1 +
>  include/linux/lsm_hook_defs.h |  2 ++
>  include/linux/security.h      |  7 +++++++
>  security/security.c           | 17 +++++++++++++++++
>  4 files changed, 27 insertions(+)

...

> diff --git a/security/security.c b/security/security.c
> index ca650c285fd9..d2dbea54a63a 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -2350,6 +2350,23 @@ int security_inode_set_acl(struct mnt_idmap *idmap,
>  	return evm_inode_set_acl(idmap, dentry, acl_name, kacl);
>  }
>  
> +/**
> + * security_inode_post_set_acl() - Update inode security from posix acls set
> + * @dentry: file
> + * @acl_name: acl name
> + * @kacl: acl struct
> + *
> + * Update inode security data after successfully setting posix acls on @dentry.
> + * The posix acls in @kacl are identified by @acl_name.
> + */
> +void security_inode_post_set_acl(struct dentry *dentry, const char *acl_name,
> +				 struct posix_acl *kacl)
> +{
> +	if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
> +		return;

Another case where the existing evm_inode_post_set_acl() hook doesn't
check S_PRIVATE but this hook does.

> +	call_void_hook(inode_post_set_acl, dentry, acl_name, kacl);
> +}
> +
>  /**
>   * security_inode_get_acl() - Check if reading posix acls is allowed
>   * @idmap: idmap of the mount
> -- 
> 2.34.1

--
paul-moore.com

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v5 17/23] security: Introduce inode_post_remove_acl hook
  2023-11-07 13:40 ` [PATCH v5 17/23] security: Introduce inode_post_remove_acl hook Roberto Sassu
  2023-11-07 17:45   ` Casey Schaufler
@ 2023-11-16  4:33   ` Paul Moore
  1 sibling, 0 replies; 96+ messages in thread
From: Paul Moore @ 2023-11-16  4:33 UTC (permalink / raw)
  To: Roberto Sassu, viro, brauner, chuck.lever, jlayton, neilb, kolga,
	Dai.Ngo, tom, jmorris, serge, zohar, dmitry.kasatkin, dhowells,
	jarkko, stephen.smalley.work, eparis, casey, mic
  Cc: linux-fsdevel, linux-kernel, linux-nfs, linux-security-module,
	linux-integrity, keyrings, selinux, Roberto Sassu, Stefan Berger

On Nov  7, 2023 Roberto Sassu <roberto.sassu@huaweicloud.com> wrote:
> 
> In preparation for moving IMA and EVM to the LSM infrastructure, introduce
> the inode_post_remove_acl hook.
> 
> At inode_remove_acl hook, EVM verifies the file's existing HMAC value. At
> inode_post_remove_acl, EVM re-calculates the file's HMAC with the passed
> POSIX ACL removed and other file metadata.
> 
> Other LSMs could similarly take some action after successful POSIX ACL
> removal.
> 
> 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>
> Acked-by: Casey Schaufler <casey@schaufler-ca.com>
> Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
> ---
>  fs/posix_acl.c                |  1 +
>  include/linux/lsm_hook_defs.h |  2 ++
>  include/linux/security.h      |  8 ++++++++
>  security/security.c           | 17 +++++++++++++++++
>  4 files changed, 28 insertions(+)

...

> diff --git a/security/security.c b/security/security.c
> index d2dbea54a63a..6eb7c9cff1e5 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -2413,6 +2413,23 @@ int security_inode_remove_acl(struct mnt_idmap *idmap,
>  	return evm_inode_remove_acl(idmap, dentry, acl_name);
>  }
>  
> +/**
> + * security_inode_post_remove_acl() - Update inode security after rm posix acls
> + * @idmap: idmap of the mount
> + * @dentry: file
> + * @acl_name: acl name
> + *
> + * Update inode security data after successfully removing posix acls on
> + * @dentry in @idmap. The posix acls are identified by @acl_name.
> + */
> +void security_inode_post_remove_acl(struct mnt_idmap *idmap,
> +				    struct dentry *dentry, const char *acl_name)
> +{
> +	if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
> +		return;

See previous comments regaring S_PRIVATE checks.

> +	call_void_hook(inode_post_remove_acl, idmap, dentry, acl_name);
> +}
> +
>  /**
>   * security_inode_post_setxattr() - Update the inode after a setxattr operation
>   * @dentry: file
> -- 
> 2.34.1

--
paul-moore.com

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v5 22/23] integrity: Move integrity functions to the LSM  infrastructure
  2023-11-07 13:40 ` [PATCH v5 22/23] integrity: Move integrity functions to the " Roberto Sassu
  2023-11-07 18:46   ` Casey Schaufler
@ 2023-11-16  4:33   ` Paul Moore
  2023-11-16 10:07     ` Roberto Sassu
  1 sibling, 1 reply; 96+ messages in thread
From: Paul Moore @ 2023-11-16  4:33 UTC (permalink / raw)
  To: Roberto Sassu, viro, brauner, chuck.lever, jlayton, neilb, kolga,
	Dai.Ngo, tom, jmorris, serge, zohar, dmitry.kasatkin, dhowells,
	jarkko, stephen.smalley.work, eparis, casey, mic
  Cc: linux-fsdevel, linux-kernel, linux-nfs, linux-security-module,
	linux-integrity, keyrings, selinux, Roberto Sassu

On Nov  7, 2023 Roberto Sassu <roberto.sassu@huaweicloud.com> wrote:
> 
> Remove hardcoded calls to integrity functions from the LSM infrastructure
> and, instead, register them in integrity_lsm_init() with the IMA or EVM
> LSM ID (the first non-NULL returned by ima_get_lsm_id() and
> evm_get_lsm_id()).
> 
> Also move the global declaration of integrity_inode_get() to
> security/integrity/integrity.h, so that the function can be still called by
> IMA.
> 
> Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
> Reviewed-by: Casey Schaufler <casey@schaufler-ca.com>
> Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
> ---
>  include/linux/integrity.h      | 26 --------------------------
>  security/integrity/iint.c      | 30 +++++++++++++++++++++++++++++-
>  security/integrity/integrity.h |  7 +++++++
>  security/security.c            |  9 +--------
>  4 files changed, 37 insertions(+), 35 deletions(-)

...

> diff --git a/security/integrity/iint.c b/security/integrity/iint.c
> index 0b0ac71142e8..882fde2a2607 100644
> --- a/security/integrity/iint.c
> +++ b/security/integrity/iint.c
> @@ -171,7 +171,7 @@ struct integrity_iint_cache *integrity_inode_get(struct inode *inode)
>   *
>   * Free the integrity information(iint) associated with an inode.
>   */
> -void integrity_inode_free(struct inode *inode)
> +static void integrity_inode_free(struct inode *inode)
>  {
>  	struct integrity_iint_cache *iint;
>  
> @@ -193,11 +193,39 @@ static void iint_init_once(void *foo)
>  	memset(iint, 0, sizeof(*iint));
>  }
>  
> +static struct security_hook_list integrity_hooks[] __ro_after_init = {
> +	LSM_HOOK_INIT(inode_free_security, integrity_inode_free),
> +#ifdef CONFIG_INTEGRITY_ASYMMETRIC_KEYS
> +	LSM_HOOK_INIT(kernel_module_request, integrity_kernel_module_request),
> +#endif
> +};
> +
> +/*
> + * Perform the initialization of the 'integrity', 'ima' and 'evm' LSMs to
> + * ensure that the management of integrity metadata is working at the time
> + * IMA and EVM hooks are registered to the LSM infrastructure, and to keep
> + * the original ordering of IMA and EVM functions as when they were hardcoded.
> + */
>  static int __init integrity_lsm_init(void)
>  {
> +	const struct lsm_id *lsmid;
> +
>  	iint_cache =
>  	    kmem_cache_create("iint_cache", sizeof(struct integrity_iint_cache),
>  			      0, SLAB_PANIC, iint_init_once);
> +	/*
> +	 * Obtain either the IMA or EVM LSM ID to register integrity-specific
> +	 * hooks under that LSM, since there is no LSM ID assigned to the
> +	 * 'integrity' LSM.
> +	 */
> +	lsmid = ima_get_lsm_id();
> +	if (!lsmid)
> +		lsmid = evm_get_lsm_id();
> +	/* No point in continuing, since both IMA and EVM are disabled. */
> +	if (!lsmid)
> +		return 0;
> +
> +	security_add_hooks(integrity_hooks, ARRAY_SIZE(integrity_hooks), lsmid);

Ooof.  I understand, or at least I think I understand, why the above
hack is needed, but I really don't like the idea of @integrity_hooks
jumping between IMA and EVM depending on how the kernel is configured.

Just to make sure I'm understanding things correctly, the "integrity"
LSM exists to ensure the proper hook ordering between IMA/EVM, shared
metadata management for IMA/EVM, and a little bit of a hack to solve
some kernel module loading issues with signatures.  Is that correct?

I see that patch 23/23 makes some nice improvements to the metadata
management, moving them into LSM security blobs, but it appears that
they are still shared, and thus the requirement is still there for
an "integrity" LSM to manage the shared blobs.

I'd like to hear everyone's honest opinion on this next question: do
we have any hope of separating IMA and EVM so they are independent
(ignore the ordering issues for a moment), or are we always going to
need to have the "integrity" LSM to manage shared resources, hooks,
etc.?

>  	init_ima_lsm();
>  	init_evm_lsm();
>  	return 0;

--
paul-moore.com

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v5 10/23] security: Introduce inode_post_setattr hook
  2023-11-16  4:33   ` Paul Moore
@ 2023-11-16  9:43     ` Roberto Sassu
  2023-11-16 18:46       ` Paul Moore
  0 siblings, 1 reply; 96+ messages in thread
From: Roberto Sassu @ 2023-11-16  9:43 UTC (permalink / raw)
  To: Paul Moore, viro, brauner, chuck.lever, jlayton, neilb, kolga,
	Dai.Ngo, tom, jmorris, serge, zohar, dmitry.kasatkin, dhowells,
	jarkko, stephen.smalley.work, eparis, casey, mic
  Cc: linux-fsdevel, linux-kernel, linux-nfs, linux-security-module,
	linux-integrity, keyrings, selinux, Roberto Sassu, Stefan Berger

On Wed, 2023-11-15 at 23:33 -0500, Paul Moore wrote:
> On Nov  7, 2023 Roberto Sassu <roberto.sassu@huaweicloud.com> wrote:
> > 
> > In preparation for moving IMA and EVM to the LSM infrastructure, introduce
> > the inode_post_setattr hook.
> > 
> > At inode_setattr hook, EVM verifies the file's existing HMAC value. At
> > inode_post_setattr, EVM re-calculates the file's HMAC based on the modified
> > file attributes and other file metadata.
> > 
> > Other LSMs could similarly take some action after successful file attribute
> > change.
> > 
> > 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>
> > Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
> > Acked-by: Casey Schaufler <casey@schaufler-ca.com>
> > ---
> >  fs/attr.c                     |  1 +
> >  include/linux/lsm_hook_defs.h |  2 ++
> >  include/linux/security.h      |  7 +++++++
> >  security/security.c           | 16 ++++++++++++++++
> >  4 files changed, 26 insertions(+)
> 
> ...
> 
> > diff --git a/security/security.c b/security/security.c
> > index 7935d11d58b5..ce3bc7642e18 100644
> > --- a/security/security.c
> > +++ b/security/security.c
> > @@ -2222,6 +2222,22 @@ int security_inode_setattr(struct mnt_idmap *idmap,
> >  }
> >  EXPORT_SYMBOL_GPL(security_inode_setattr);
> >  
> > +/**
> > + * security_inode_post_setattr() - Update the inode after a setattr operation
> > + * @idmap: idmap of the mount
> > + * @dentry: file
> > + * @ia_valid: file attributes set
> > + *
> > + * Update inode security field after successful setting file attributes.
> > + */
> > +void security_inode_post_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
> > +				 int ia_valid)
> > +{
> > +	if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
> > +		return;
> 
> I may be missing it, but I don't see the S_PRIVATE flag check in the
> existing IMA or EVM hooks so I'm curious as to why it is added here?
> Please don't misunderstand me, I think it makes sense to return early
> on private dentrys/inodes, but why aren't we doing that now?

My first motivation was that it is in the pre hooks, so it should be in
the post hook as well.

Thinking more about it, suppose that the post don't have the check,
private inodes would gain an HMAC without checking the validity of the
current HMAC first (done in the pre hooks), which would be even worse.

So, my idea about this is that at least we are consistent.

If IMA and EVM should look at private inodes is a different question,
which would require a discussion.

Thanks

Roberto

> > +	call_void_hook(inode_post_setattr, idmap, dentry, ia_valid);
> > +}
> > +
> >  /**
> >   * security_inode_getattr() - Check if getting file attributes is allowed
> >   * @path: file
> > -- 
> > 2.34.1
> 
> --
> paul-moore.com


^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v5 13/23] security: Introduce file_pre_free_security hook
  2023-11-16  4:33   ` Paul Moore
@ 2023-11-16  9:46     ` Roberto Sassu
  2023-11-16 18:41       ` Paul Moore
  0 siblings, 1 reply; 96+ messages in thread
From: Roberto Sassu @ 2023-11-16  9:46 UTC (permalink / raw)
  To: Paul Moore, viro, brauner, chuck.lever, jlayton, neilb, kolga,
	Dai.Ngo, tom, jmorris, serge, zohar, dmitry.kasatkin, dhowells,
	jarkko, stephen.smalley.work, eparis, casey, mic
  Cc: linux-fsdevel, linux-kernel, linux-nfs, linux-security-module,
	linux-integrity, keyrings, selinux, Roberto Sassu

On Wed, 2023-11-15 at 23:33 -0500, Paul Moore wrote:
> On Nov  7, 2023 Roberto Sassu <roberto.sassu@huaweicloud.com> wrote:
> > 
> > In preparation for moving IMA and EVM to the LSM infrastructure, introduce
> > the file_pre_free_security 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.
> > 
> > LSMs could also take some action before the last reference of a file is
> > released.
> > 
> > The new hook cannot return an error and cannot cause the operation to be
> > reverted.
> > 
> > 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/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..64ed74555e64 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_pre_free(file);
> 
> I worry that security_file_pre_free() is a misleading name as "free"
> tends to imply memory management tasks, which isn't the main focus of
> this hook.  What do you think of security_file_release() or
> security_file_put() instead?

security_file_release() would be fine for me.

Thanks

Roberto

> >  	ima_file_free(file);
> >  	if (unlikely(file->f_flags & FASYNC)) {
> >  		if (file->f_op->fasync)
> 
> --
> paul-moore.com


^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v5 22/23] integrity: Move integrity functions to the LSM infrastructure
  2023-11-16  4:33   ` Paul Moore
@ 2023-11-16 10:07     ` Roberto Sassu
  2023-11-17 21:22       ` Paul Moore
  0 siblings, 1 reply; 96+ messages in thread
From: Roberto Sassu @ 2023-11-16 10:07 UTC (permalink / raw)
  To: Paul Moore, viro, brauner, chuck.lever, jlayton, neilb, kolga,
	Dai.Ngo, tom, jmorris, serge, zohar, dmitry.kasatkin, dhowells,
	jarkko, stephen.smalley.work, eparis, casey, mic
  Cc: linux-fsdevel, linux-kernel, linux-nfs, linux-security-module,
	linux-integrity, keyrings, selinux, Roberto Sassu

On Wed, 2023-11-15 at 23:33 -0500, Paul Moore wrote:
> On Nov  7, 2023 Roberto Sassu <roberto.sassu@huaweicloud.com> wrote:
> > 
> > Remove hardcoded calls to integrity functions from the LSM infrastructure
> > and, instead, register them in integrity_lsm_init() with the IMA or EVM
> > LSM ID (the first non-NULL returned by ima_get_lsm_id() and
> > evm_get_lsm_id()).
> > 
> > Also move the global declaration of integrity_inode_get() to
> > security/integrity/integrity.h, so that the function can be still called by
> > IMA.
> > 
> > Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
> > Reviewed-by: Casey Schaufler <casey@schaufler-ca.com>
> > Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
> > ---
> >  include/linux/integrity.h      | 26 --------------------------
> >  security/integrity/iint.c      | 30 +++++++++++++++++++++++++++++-
> >  security/integrity/integrity.h |  7 +++++++
> >  security/security.c            |  9 +--------
> >  4 files changed, 37 insertions(+), 35 deletions(-)
> 
> ...
> 
> > diff --git a/security/integrity/iint.c b/security/integrity/iint.c
> > index 0b0ac71142e8..882fde2a2607 100644
> > --- a/security/integrity/iint.c
> > +++ b/security/integrity/iint.c
> > @@ -171,7 +171,7 @@ struct integrity_iint_cache *integrity_inode_get(struct inode *inode)
> >   *
> >   * Free the integrity information(iint) associated with an inode.
> >   */
> > -void integrity_inode_free(struct inode *inode)
> > +static void integrity_inode_free(struct inode *inode)
> >  {
> >  	struct integrity_iint_cache *iint;
> >  
> > @@ -193,11 +193,39 @@ static void iint_init_once(void *foo)
> >  	memset(iint, 0, sizeof(*iint));
> >  }
> >  
> > +static struct security_hook_list integrity_hooks[] __ro_after_init = {
> > +	LSM_HOOK_INIT(inode_free_security, integrity_inode_free),
> > +#ifdef CONFIG_INTEGRITY_ASYMMETRIC_KEYS
> > +	LSM_HOOK_INIT(kernel_module_request, integrity_kernel_module_request),
> > +#endif
> > +};
> > +
> > +/*
> > + * Perform the initialization of the 'integrity', 'ima' and 'evm' LSMs to
> > + * ensure that the management of integrity metadata is working at the time
> > + * IMA and EVM hooks are registered to the LSM infrastructure, and to keep
> > + * the original ordering of IMA and EVM functions as when they were hardcoded.
> > + */
> >  static int __init integrity_lsm_init(void)
> >  {
> > +	const struct lsm_id *lsmid;
> > +
> >  	iint_cache =
> >  	    kmem_cache_create("iint_cache", sizeof(struct integrity_iint_cache),
> >  			      0, SLAB_PANIC, iint_init_once);
> > +	/*
> > +	 * Obtain either the IMA or EVM LSM ID to register integrity-specific
> > +	 * hooks under that LSM, since there is no LSM ID assigned to the
> > +	 * 'integrity' LSM.
> > +	 */
> > +	lsmid = ima_get_lsm_id();
> > +	if (!lsmid)
> > +		lsmid = evm_get_lsm_id();
> > +	/* No point in continuing, since both IMA and EVM are disabled. */
> > +	if (!lsmid)
> > +		return 0;
> > +
> > +	security_add_hooks(integrity_hooks, ARRAY_SIZE(integrity_hooks), lsmid);
> 
> Ooof.  I understand, or at least I think I understand, why the above
> hack is needed, but I really don't like the idea of @integrity_hooks
> jumping between IMA and EVM depending on how the kernel is configured.
> 
> Just to make sure I'm understanding things correctly, the "integrity"
> LSM exists to ensure the proper hook ordering between IMA/EVM, shared
> metadata management for IMA/EVM, and a little bit of a hack to solve
> some kernel module loading issues with signatures.  Is that correct?
> 
> I see that patch 23/23 makes some nice improvements to the metadata
> management, moving them into LSM security blobs, but it appears that
> they are still shared, and thus the requirement is still there for
> an "integrity" LSM to manage the shared blobs.

Yes, all is correct.

> I'd like to hear everyone's honest opinion on this next question: do
> we have any hope of separating IMA and EVM so they are independent
> (ignore the ordering issues for a moment), or are we always going to
> need to have the "integrity" LSM to manage shared resources, hooks,
> etc.?

I think it should not be technically difficult to do it. But, it would
be very important to understand all the implications of doing those
changes.

Sorry, for now I don't see an immediate need to do that, other than
solving this LSM naming issue. I tried to find the best solution I
could.

Thanks

Roberto

> >  	init_ima_lsm();
> >  	init_evm_lsm();
> >  	return 0;
> 
> --
> paul-moore.com


^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v5 13/23] security: Introduce file_pre_free_security hook
  2023-11-16  9:46     ` Roberto Sassu
@ 2023-11-16 18:41       ` Paul Moore
  0 siblings, 0 replies; 96+ messages in thread
From: Paul Moore @ 2023-11-16 18:41 UTC (permalink / raw)
  To: Roberto Sassu
  Cc: viro, brauner, chuck.lever, jlayton, neilb, kolga, Dai.Ngo, tom,
	jmorris, serge, zohar, dmitry.kasatkin, dhowells, jarkko,
	stephen.smalley.work, eparis, casey, mic, linux-fsdevel,
	linux-kernel, linux-nfs, linux-security-module, linux-integrity,
	keyrings, selinux, Roberto Sassu

On Thu, Nov 16, 2023 at 4:47 AM Roberto Sassu
<roberto.sassu@huaweicloud.com> wrote:
> On Wed, 2023-11-15 at 23:33 -0500, Paul Moore wrote:
> > On Nov  7, 2023 Roberto Sassu <roberto.sassu@huaweicloud.com> wrote:
> > >
> > > In preparation for moving IMA and EVM to the LSM infrastructure, introduce
> > > the file_pre_free_security 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.
> > >
> > > LSMs could also take some action before the last reference of a file is
> > > released.
> > >
> > > The new hook cannot return an error and cannot cause the operation to be
> > > reverted.
> > >
> > > 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/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..64ed74555e64 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_pre_free(file);
> >
> > I worry that security_file_pre_free() is a misleading name as "free"
> > tends to imply memory management tasks, which isn't the main focus of
> > this hook.  What do you think of security_file_release() or
> > security_file_put() instead?
>
> security_file_release() would be fine for me.

Okay, assuming no objections for anyone else let's go with that.
Thanks for indulging my naming nitpick :)

-- 
paul-moore.com

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v5 10/23] security: Introduce inode_post_setattr hook
  2023-11-16  9:43     ` Roberto Sassu
@ 2023-11-16 18:46       ` Paul Moore
  0 siblings, 0 replies; 96+ messages in thread
From: Paul Moore @ 2023-11-16 18:46 UTC (permalink / raw)
  To: Roberto Sassu
  Cc: viro, brauner, chuck.lever, jlayton, neilb, kolga, Dai.Ngo, tom,
	jmorris, serge, zohar, dmitry.kasatkin, dhowells, jarkko,
	stephen.smalley.work, eparis, casey, mic, linux-fsdevel,
	linux-kernel, linux-nfs, linux-security-module, linux-integrity,
	keyrings, selinux, Roberto Sassu, Stefan Berger

On Thu, Nov 16, 2023 at 4:44 AM Roberto Sassu
<roberto.sassu@huaweicloud.com> wrote:
> On Wed, 2023-11-15 at 23:33 -0500, Paul Moore wrote:
> > On Nov  7, 2023 Roberto Sassu <roberto.sassu@huaweicloud.com> wrote:
> > >
> > > In preparation for moving IMA and EVM to the LSM infrastructure, introduce
> > > the inode_post_setattr hook.
> > >
> > > At inode_setattr hook, EVM verifies the file's existing HMAC value. At
> > > inode_post_setattr, EVM re-calculates the file's HMAC based on the modified
> > > file attributes and other file metadata.
> > >
> > > Other LSMs could similarly take some action after successful file attribute
> > > change.
> > >
> > > 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>
> > > Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
> > > Acked-by: Casey Schaufler <casey@schaufler-ca.com>
> > > ---
> > >  fs/attr.c                     |  1 +
> > >  include/linux/lsm_hook_defs.h |  2 ++
> > >  include/linux/security.h      |  7 +++++++
> > >  security/security.c           | 16 ++++++++++++++++
> > >  4 files changed, 26 insertions(+)
> >
> > ...
> >
> > > diff --git a/security/security.c b/security/security.c
> > > index 7935d11d58b5..ce3bc7642e18 100644
> > > --- a/security/security.c
> > > +++ b/security/security.c
> > > @@ -2222,6 +2222,22 @@ int security_inode_setattr(struct mnt_idmap *idmap,
> > >  }
> > >  EXPORT_SYMBOL_GPL(security_inode_setattr);
> > >
> > > +/**
> > > + * security_inode_post_setattr() - Update the inode after a setattr operation
> > > + * @idmap: idmap of the mount
> > > + * @dentry: file
> > > + * @ia_valid: file attributes set
> > > + *
> > > + * Update inode security field after successful setting file attributes.
> > > + */
> > > +void security_inode_post_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
> > > +                            int ia_valid)
> > > +{
> > > +   if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
> > > +           return;
> >
> > I may be missing it, but I don't see the S_PRIVATE flag check in the
> > existing IMA or EVM hooks so I'm curious as to why it is added here?
> > Please don't misunderstand me, I think it makes sense to return early
> > on private dentrys/inodes, but why aren't we doing that now?
>
> My first motivation was that it is in the pre hooks, so it should be in
> the post hook as well.
>
> Thinking more about it, suppose that the post don't have the check,
> private inodes would gain an HMAC without checking the validity of the
> current HMAC first (done in the pre hooks), which would be even worse.
>
> So, my idea about this is that at least we are consistent.
>
> If IMA and EVM should look at private inodes is a different question,
> which would require a discussion.

As I said above, I can understand why having the IS_PRIVATE() macro
check might be a good idea, I am just concerned that the current
IMA/EVM hooks don't check for S_PRIVATE and thus moving to this new
LSM hook would potentially be a change in behavior (like I said, I
could be missing a subtle detail).  I'd just like a quick confirmation
from Mimi that either there is no difference because of X, or she is
aware of the difference and is okay with it.  It's very possible she
is fine with it, she did provide her 'Reviewed-by', but I worry this
is the sort of thing that might have gone unnoticed during review.

-- 
paul-moore.com

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v5 23/23] integrity: Switch from rbtree to LSM-managed blob  for integrity_iint_cache
  2023-11-07 13:40 ` [PATCH v5 23/23] integrity: Switch from rbtree to LSM-managed blob for integrity_iint_cache Roberto Sassu
@ 2023-11-17 20:57   ` Paul Moore
  2023-11-20  8:16     ` Roberto Sassu
  2023-12-13 10:45     ` Roberto Sassu
  0 siblings, 2 replies; 96+ messages in thread
From: Paul Moore @ 2023-11-17 20:57 UTC (permalink / raw)
  To: Roberto Sassu, viro, brauner, chuck.lever, jlayton, neilb, kolga,
	Dai.Ngo, tom, jmorris, serge, zohar, dmitry.kasatkin, dhowells,
	jarkko, stephen.smalley.work, eparis, casey, mic
  Cc: linux-fsdevel, linux-kernel, linux-nfs, linux-security-module,
	linux-integrity, keyrings, selinux, Roberto Sassu

On Nov  7, 2023 Roberto Sassu <roberto.sassu@huaweicloud.com> wrote:
> 
> Before the security field of kernel objects could be shared among LSMs with
> the LSM stacking feature, IMA and EVM had to rely on an alternative storage
> of inode metadata. The association between inode metadata and inode is
> maintained through an rbtree.
> 
> Because of this alternative storage mechanism, there was no need to use
> disjoint inode metadata, so IMA and EVM today still share them.
> 
> With the reservation mechanism offered by the LSM infrastructure, the
> rbtree is no longer necessary, as each LSM could reserve a space in the
> security blob for each inode. However, since IMA and EVM share the
> inode metadata, they cannot directly reserve the space for them.
> 
> Instead, request from the 'integrity' LSM a space in the security blob for
> the pointer of inode metadata (integrity_iint_cache structure). The other
> reason for keeping the 'integrity' LSM is to preserve the original ordering
> of IMA and EVM functions as when they were hardcoded.
> 
> Prefer reserving space for a pointer to allocating the integrity_iint_cache
> structure directly, as IMA would require it only for a subset of inodes.
> Always allocating it would cause a waste of memory.
> 
> Introduce two primitives for getting and setting the pointer of
> integrity_iint_cache in the security blob, respectively
> integrity_inode_get_iint() and integrity_inode_set_iint(). This would make
> the code more understandable, as they directly replace rbtree operations.
> 
> Locking is not needed, as access to inode metadata is not shared, it is per
> inode.
> 
> Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
> Reviewed-by: Casey Schaufler <casey@schaufler-ca.com>
> Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
> ---
>  security/integrity/iint.c      | 71 +++++-----------------------------
>  security/integrity/integrity.h | 20 +++++++++-
>  2 files changed, 29 insertions(+), 62 deletions(-)
> 
> diff --git a/security/integrity/iint.c b/security/integrity/iint.c
> index 882fde2a2607..a5edd3c70784 100644
> --- a/security/integrity/iint.c
> +++ b/security/integrity/iint.c
> @@ -231,6 +175,10 @@ static int __init integrity_lsm_init(void)
>  	return 0;
>  }
>  
> +struct lsm_blob_sizes integrity_blob_sizes __ro_after_init = {
> +	.lbs_inode = sizeof(struct integrity_iint_cache *),
> +};

I'll admit that I'm likely missing an important detail, but is there
a reason why you couldn't stash the integrity_iint_cache struct
directly in the inode's security blob instead of the pointer?  For
example:

  struct lsm_blob_sizes ... = {
    .lbs_inode = sizeof(struct integrity_iint_cache),
  };

  struct integrity_iint_cache *integrity_inode_get(inode)
  {
    if (unlikely(!inode->isecurity))
      return NULL;
    return inode->i_security + integrity_blob_sizes.lbs_inode;
  }

--
paul-moore.com

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v5 22/23] integrity: Move integrity functions to the LSM infrastructure
  2023-11-16 10:07     ` Roberto Sassu
@ 2023-11-17 21:22       ` Paul Moore
  2023-11-20 13:23         ` Roberto Sassu
  0 siblings, 1 reply; 96+ messages in thread
From: Paul Moore @ 2023-11-17 21:22 UTC (permalink / raw)
  To: Roberto Sassu
  Cc: viro, brauner, chuck.lever, jlayton, neilb, kolga, Dai.Ngo, tom,
	jmorris, serge, zohar, dmitry.kasatkin, dhowells, jarkko,
	stephen.smalley.work, eparis, casey, mic, linux-fsdevel,
	linux-kernel, linux-nfs, linux-security-module, linux-integrity,
	keyrings, selinux, Roberto Sassu

On Thu, Nov 16, 2023 at 5:08 AM Roberto Sassu
<roberto.sassu@huaweicloud.com> wrote:
> On Wed, 2023-11-15 at 23:33 -0500, Paul Moore wrote:
> > On Nov  7, 2023 Roberto Sassu <roberto.sassu@huaweicloud.com> wrote:

...

> > > +/*
> > > + * Perform the initialization of the 'integrity', 'ima' and 'evm' LSMs to
> > > + * ensure that the management of integrity metadata is working at the time
> > > + * IMA and EVM hooks are registered to the LSM infrastructure, and to keep
> > > + * the original ordering of IMA and EVM functions as when they were hardcoded.
> > > + */
> > >  static int __init integrity_lsm_init(void)
> > >  {
> > > +   const struct lsm_id *lsmid;
> > > +
> > >     iint_cache =
> > >         kmem_cache_create("iint_cache", sizeof(struct integrity_iint_cache),
> > >                           0, SLAB_PANIC, iint_init_once);
> > > +   /*
> > > +    * Obtain either the IMA or EVM LSM ID to register integrity-specific
> > > +    * hooks under that LSM, since there is no LSM ID assigned to the
> > > +    * 'integrity' LSM.
> > > +    */
> > > +   lsmid = ima_get_lsm_id();
> > > +   if (!lsmid)
> > > +           lsmid = evm_get_lsm_id();
> > > +   /* No point in continuing, since both IMA and EVM are disabled. */
> > > +   if (!lsmid)
> > > +           return 0;
> > > +
> > > +   security_add_hooks(integrity_hooks, ARRAY_SIZE(integrity_hooks), lsmid);
> >
> > Ooof.  I understand, or at least I think I understand, why the above
> > hack is needed, but I really don't like the idea of @integrity_hooks
> > jumping between IMA and EVM depending on how the kernel is configured.
> >
> > Just to make sure I'm understanding things correctly, the "integrity"
> > LSM exists to ensure the proper hook ordering between IMA/EVM, shared
> > metadata management for IMA/EVM, and a little bit of a hack to solve
> > some kernel module loading issues with signatures.  Is that correct?
> >
> > I see that patch 23/23 makes some nice improvements to the metadata
> > management, moving them into LSM security blobs, but it appears that
> > they are still shared, and thus the requirement is still there for
> > an "integrity" LSM to manage the shared blobs.
>
> Yes, all is correct.

Thanks for the clarification, more on this below.

> > I'd like to hear everyone's honest opinion on this next question: do
> > we have any hope of separating IMA and EVM so they are independent
> > (ignore the ordering issues for a moment), or are we always going to
> > need to have the "integrity" LSM to manage shared resources, hooks,
> > etc.?
>
> I think it should not be technically difficult to do it. But, it would
> be very important to understand all the implications of doing those
> changes.
>
> Sorry, for now I don't see an immediate need to do that, other than
> solving this LSM naming issue. I tried to find the best solution I
> could.

I first want to say that I think you've done a great job thus far, and
I'm very grateful for the work you've done.  We can always use more
help in the kernel security space and I'm very happy to see your
contributions - thank you :)

I'm concerned about the integrity LSM because it isn't really a LSM,
it is simply an implementation artifact from a time when only one LSM
was enabled.  Now that we have basic support for stacking LSMs, as we
promote integrity/IMA/EVM I think this is the perfect time to move
away from the "integrity" portion and integrate the necessary
functionality into the IMA and EVM LSMs.  This is even more important
now that we are looking at making the LSMs more visible to userspace
via syscalls; how would you explain to a developer or user the need
for an "integrity" LSM along with the IMA and EVM LSMs?

Let's look at the three things the the integrity code provides in this patchset:

* IMA/EVM hook ordering

For better or worse, we have requirements on LSM ordering today that
are enforced only by convention, the BPF LSM being the perfect
example.  As long as we document this in Kconfig I think we are okay.

* Shared metadata

Looking at the integrity_iint_cache struct at the end of your patchset
I see the following:

  struct integrity_iint_cache {
    struct mutex mutex;
    struct inode *inode;
    u64 version;
    unsigned long flags;
    unsigned long measured_pcrs;
    unsigned long atomic_flags;
    enum integrity_status ima_file_status:4;
    enum integrity_status ima_mmap_status:4;
    enum integrity_status ima_bprm_status:4;
    enum integrity_status ima_read_status:4;
    enum integrity_status ima_creds_status:4;
    enum integrity_status evm_status:4;
    struct ima_digest_data *ima_hash;
  };

Now that we are stashing the metadata in the inode, we should be able
to remove the @inode field back pointer.  It seems like we could
duplicate @mutex and @version without problem.

I only see the @measured_pcrs, @atomic_flags used in the IMA code.

I only see the @ima_XXX_status fields using in the IMA code, and the
@evm_status used in the EVM code.

I only see the @ima_hash field used by the IMA code.

I do see both IMA and EVM using the @flags field, but only one case
(IMA_NEW_FILE) where one LSM (EVM) looks for another flags (IMA).  I'm
not sure how difficult that would be to untangle, but I imagine we
could do something here; if we had to, we could make EVM be dependent
on IMA in Kconfig and add a function call to check on the inode
status.  Although I hope we could find a better solution.

* Kernel module loading hook (integrity_kernel_module_request(...))

My guess is that this is really an IMA hook, but I can't say for
certain.  If it is needed for EVM we could always duplicate it across
the IMA and EVM LSMs, it is trivially small and one extra strcmp() at
kernel module load time doesn't seem awful to me.

-- 
paul-moore.com

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v5 23/23] integrity: Switch from rbtree to LSM-managed blob  for integrity_iint_cache
  2023-11-17 20:57   ` Paul Moore
@ 2023-11-20  8:16     ` Roberto Sassu
  2023-11-20 21:06       ` Paul Moore
  2023-12-13 10:45     ` Roberto Sassu
  1 sibling, 1 reply; 96+ messages in thread
From: Roberto Sassu @ 2023-11-20  8:16 UTC (permalink / raw)
  To: Paul Moore, viro, brauner, chuck.lever, jlayton, neilb, kolga,
	Dai.Ngo, tom, jmorris, serge, zohar, dmitry.kasatkin, dhowells,
	jarkko, stephen.smalley.work, eparis, casey, mic
  Cc: linux-fsdevel, linux-kernel, linux-nfs, linux-security-module,
	linux-integrity, keyrings, selinux, Roberto Sassu

On Fri, 2023-11-17 at 15:57 -0500, Paul Moore wrote:
> On Nov  7, 2023 Roberto Sassu <roberto.sassu@huaweicloud.com> wrote:
> > 
> > Before the security field of kernel objects could be shared among LSMs with
> > the LSM stacking feature, IMA and EVM had to rely on an alternative storage
> > of inode metadata. The association between inode metadata and inode is
> > maintained through an rbtree.
> > 
> > Because of this alternative storage mechanism, there was no need to use
> > disjoint inode metadata, so IMA and EVM today still share them.
> > 
> > With the reservation mechanism offered by the LSM infrastructure, the
> > rbtree is no longer necessary, as each LSM could reserve a space in the
> > security blob for each inode. However, since IMA and EVM share the
> > inode metadata, they cannot directly reserve the space for them.
> > 
> > Instead, request from the 'integrity' LSM a space in the security blob for
> > the pointer of inode metadata (integrity_iint_cache structure). The other
> > reason for keeping the 'integrity' LSM is to preserve the original ordering
> > of IMA and EVM functions as when they were hardcoded.
> > 
> > Prefer reserving space for a pointer to allocating the integrity_iint_cache
> > structure directly, as IMA would require it only for a subset of inodes.
> > Always allocating it would cause a waste of memory.
> > 
> > Introduce two primitives for getting and setting the pointer of
> > integrity_iint_cache in the security blob, respectively
> > integrity_inode_get_iint() and integrity_inode_set_iint(). This would make
> > the code more understandable, as they directly replace rbtree operations.
> > 
> > Locking is not needed, as access to inode metadata is not shared, it is per
> > inode.
> > 
> > Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
> > Reviewed-by: Casey Schaufler <casey@schaufler-ca.com>
> > Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
> > ---
> >  security/integrity/iint.c      | 71 +++++-----------------------------
> >  security/integrity/integrity.h | 20 +++++++++-
> >  2 files changed, 29 insertions(+), 62 deletions(-)
> > 
> > diff --git a/security/integrity/iint.c b/security/integrity/iint.c
> > index 882fde2a2607..a5edd3c70784 100644
> > --- a/security/integrity/iint.c
> > +++ b/security/integrity/iint.c
> > @@ -231,6 +175,10 @@ static int __init integrity_lsm_init(void)
> >  	return 0;
> >  }
> >  
> > +struct lsm_blob_sizes integrity_blob_sizes __ro_after_init = {
> > +	.lbs_inode = sizeof(struct integrity_iint_cache *),
> > +};
> 
> I'll admit that I'm likely missing an important detail, but is there
> a reason why you couldn't stash the integrity_iint_cache struct
> directly in the inode's security blob instead of the pointer?  For
> example:
> 
>   struct lsm_blob_sizes ... = {
>     .lbs_inode = sizeof(struct integrity_iint_cache),
>   };
> 
>   struct integrity_iint_cache *integrity_inode_get(inode)
>   {
>     if (unlikely(!inode->isecurity))
>       return NULL;
>     return inode->i_security + integrity_blob_sizes.lbs_inode;
>   }

It would increase memory occupation. Sometimes the IMA policy
encompasses a small subset of the inodes. Allocating the full
integrity_iint_cache would be a waste of memory, I guess?

On the other hand... (did not think fully about that) if we embed the
full structure in the security blob, we already have a mutex available
to use, and we don't need to take the inode lock (?).

I'm fully convinced that we can improve the implementation
significantly. I just was really hoping to go step by step and not
accumulating improvements as dependency for moving IMA and EVM to the
LSM infrastructure.

Thanks

Roberto


^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v5 22/23] integrity: Move integrity functions to the LSM infrastructure
  2023-11-17 21:22       ` Paul Moore
@ 2023-11-20 13:23         ` Roberto Sassu
  0 siblings, 0 replies; 96+ messages in thread
From: Roberto Sassu @ 2023-11-20 13:23 UTC (permalink / raw)
  To: Paul Moore
  Cc: viro, brauner, chuck.lever, jlayton, neilb, kolga, Dai.Ngo, tom,
	jmorris, serge, zohar, dmitry.kasatkin, dhowells, jarkko,
	stephen.smalley.work, eparis, casey, mic, linux-fsdevel,
	linux-kernel, linux-nfs, linux-security-module, linux-integrity,
	keyrings, selinux, Roberto Sassu

On Fri, 2023-11-17 at 16:22 -0500, Paul Moore wrote:
> On Thu, Nov 16, 2023 at 5:08 AM Roberto Sassu
> <roberto.sassu@huaweicloud.com> wrote:
> > On Wed, 2023-11-15 at 23:33 -0500, Paul Moore wrote:
> > > On Nov  7, 2023 Roberto Sassu <roberto.sassu@huaweicloud.com> wrote:
> 
> ...
> 
> > > > +/*
> > > > + * Perform the initialization of the 'integrity', 'ima' and 'evm' LSMs to
> > > > + * ensure that the management of integrity metadata is working at the time
> > > > + * IMA and EVM hooks are registered to the LSM infrastructure, and to keep
> > > > + * the original ordering of IMA and EVM functions as when they were hardcoded.
> > > > + */
> > > >  static int __init integrity_lsm_init(void)
> > > >  {
> > > > +   const struct lsm_id *lsmid;
> > > > +
> > > >     iint_cache =
> > > >         kmem_cache_create("iint_cache", sizeof(struct integrity_iint_cache),
> > > >                           0, SLAB_PANIC, iint_init_once);
> > > > +   /*
> > > > +    * Obtain either the IMA or EVM LSM ID to register integrity-specific
> > > > +    * hooks under that LSM, since there is no LSM ID assigned to the
> > > > +    * 'integrity' LSM.
> > > > +    */
> > > > +   lsmid = ima_get_lsm_id();
> > > > +   if (!lsmid)
> > > > +           lsmid = evm_get_lsm_id();
> > > > +   /* No point in continuing, since both IMA and EVM are disabled. */
> > > > +   if (!lsmid)
> > > > +           return 0;
> > > > +
> > > > +   security_add_hooks(integrity_hooks, ARRAY_SIZE(integrity_hooks), lsmid);
> > > 
> > > Ooof.  I understand, or at least I think I understand, why the above
> > > hack is needed, but I really don't like the idea of @integrity_hooks
> > > jumping between IMA and EVM depending on how the kernel is configured.
> > > 
> > > Just to make sure I'm understanding things correctly, the "integrity"
> > > LSM exists to ensure the proper hook ordering between IMA/EVM, shared
> > > metadata management for IMA/EVM, and a little bit of a hack to solve
> > > some kernel module loading issues with signatures.  Is that correct?
> > > 
> > > I see that patch 23/23 makes some nice improvements to the metadata
> > > management, moving them into LSM security blobs, but it appears that
> > > they are still shared, and thus the requirement is still there for
> > > an "integrity" LSM to manage the shared blobs.
> > 
> > Yes, all is correct.
> 
> Thanks for the clarification, more on this below.
> 
> > > I'd like to hear everyone's honest opinion on this next question: do
> > > we have any hope of separating IMA and EVM so they are independent
> > > (ignore the ordering issues for a moment), or are we always going to
> > > need to have the "integrity" LSM to manage shared resources, hooks,
> > > etc.?
> > 
> > I think it should not be technically difficult to do it. But, it would
> > be very important to understand all the implications of doing those
> > changes.
> > 
> > Sorry, for now I don't see an immediate need to do that, other than
> > solving this LSM naming issue. I tried to find the best solution I
> > could.
> 
> I first want to say that I think you've done a great job thus far, and
> I'm very grateful for the work you've done.  We can always use more
> help in the kernel security space and I'm very happy to see your
> contributions - thank you :)

Thank you!

> I'm concerned about the integrity LSM because it isn't really a LSM,
> it is simply an implementation artifact from a time when only one LSM
> was enabled.  Now that we have basic support for stacking LSMs, as we
> promote integrity/IMA/EVM I think this is the perfect time to move
> away from the "integrity" portion and integrate the necessary
> functionality into the IMA and EVM LSMs.  This is even more important
> now that we are looking at making the LSMs more visible to userspace
> via syscalls; how would you explain to a developer or user the need
> for an "integrity" LSM along with the IMA and EVM LSMs?
> 
> Let's look at the three things the the integrity code provides in this patchset:
> 
> * IMA/EVM hook ordering
> 
> For better or worse, we have requirements on LSM ordering today that
> are enforced only by convention, the BPF LSM being the perfect
> example.  As long as we document this in Kconfig I think we are okay.
> 
> * Shared metadata
> 
> Looking at the integrity_iint_cache struct at the end of your patchset
> I see the following:
> 
>   struct integrity_iint_cache {
>     struct mutex mutex;
>     struct inode *inode;
>     u64 version;
>     unsigned long flags;
>     unsigned long measured_pcrs;
>     unsigned long atomic_flags;
>     enum integrity_status ima_file_status:4;
>     enum integrity_status ima_mmap_status:4;
>     enum integrity_status ima_bprm_status:4;
>     enum integrity_status ima_read_status:4;
>     enum integrity_status ima_creds_status:4;
>     enum integrity_status evm_status:4;
>     struct ima_digest_data *ima_hash;
>   };
> 
> Now that we are stashing the metadata in the inode, we should be able
> to remove the @inode field back pointer.  It seems like we could
> duplicate @mutex and @version without problem.
> 
> I only see the @measured_pcrs, @atomic_flags used in the IMA code.
> 
> I only see the @ima_XXX_status fields using in the IMA code, and the
> @evm_status used in the EVM code.
> 
> I only see the @ima_hash field used by the IMA code.
> 
> I do see both IMA and EVM using the @flags field, but only one case
> (IMA_NEW_FILE) where one LSM (EVM) looks for another flags (IMA).  I'm
> not sure how difficult that would be to untangle, but I imagine we
> could do something here; if we had to, we could make EVM be dependent
> on IMA in Kconfig and add a function call to check on the inode
> status.  Although I hope we could find a better solution.
> 
> * Kernel module loading hook (integrity_kernel_module_request(...))
> 
> My guess is that this is really an IMA hook, but I can't say for
> certain.  If it is needed for EVM we could always duplicate it across
> the IMA and EVM LSMs, it is trivially small and one extra strcmp() at
> kernel module load time doesn't seem awful to me.

Ok... so, for now I'm trying to separate them just to see if it is
possible. Will send just the integrity-related patches shortly.

Thanks

Roberto


^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v5 11/23] security: Introduce inode_post_removexattr hook
  2023-11-07 17:33   ` Casey Schaufler
  2023-11-07 17:45     ` Roberto Sassu
@ 2023-11-20 17:31     ` Roberto Sassu
  2023-11-20 18:03       ` Casey Schaufler
  1 sibling, 1 reply; 96+ messages in thread
From: Roberto Sassu @ 2023-11-20 17:31 UTC (permalink / raw)
  To: Casey Schaufler, viro, brauner, chuck.lever, jlayton, neilb,
	kolga, Dai.Ngo, tom, paul, jmorris, serge, zohar,
	dmitry.kasatkin, dhowells, jarkko, stephen.smalley.work, eparis,
	mic
  Cc: linux-fsdevel, linux-kernel, linux-nfs, linux-security-module,
	linux-integrity, keyrings, selinux, Roberto Sassu, Stefan Berger

On Tue, 2023-11-07 at 09:33 -0800, Casey Schaufler wrote:
> On 11/7/2023 5:40 AM, 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_removexattr hook.
> > 
> > At inode_removexattr hook, EVM verifies the file's existing HMAC value. At
> > inode_post_removexattr, EVM re-calculates the file's HMAC with the passed
> > xattr removed and other file metadata.
> > 
> > Other LSMs could similarly take some action after successful xattr removal.
> > 
> > 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>
> > Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
> > ---
> >  fs/xattr.c                    |  9 +++++----
> >  include/linux/lsm_hook_defs.h |  2 ++
> >  include/linux/security.h      |  5 +++++
> >  security/security.c           | 14 ++++++++++++++
> >  4 files changed, 26 insertions(+), 4 deletions(-)
> > 
> > diff --git a/fs/xattr.c b/fs/xattr.c
> > index 09d927603433..84a4aa566c02 100644
> > --- a/fs/xattr.c
> > +++ b/fs/xattr.c
> > @@ -552,11 +552,12 @@ __vfs_removexattr_locked(struct mnt_idmap *idmap,
> >  		goto out;
> >  
> >  	error = __vfs_removexattr(idmap, dentry, name);
> > +	if (error)
> > +		goto out;
> 
> Shouldn't this be simply "return error" rather than a goto to nothing
> but "return error"?

I got a review from Andrew Morton. His argument seems convincing, that
having less return places makes the code easier to handle.

Thanks

Roberto

> > -	if (!error) {
> > -		fsnotify_xattr(dentry);
> > -		evm_inode_post_removexattr(dentry, name);
> > -	}
> > +	fsnotify_xattr(dentry);
> > +	security_inode_post_removexattr(dentry, name);
> > +	evm_inode_post_removexattr(dentry, name);
> >  
> >  out:
> >  	return error;
> > diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
> > index 67410e085205..88452e45025c 100644
> > --- a/include/linux/lsm_hook_defs.h
> > +++ b/include/linux/lsm_hook_defs.h
> > @@ -149,6 +149,8 @@ LSM_HOOK(int, 0, inode_getxattr, struct dentry *dentry, const char *name)
> >  LSM_HOOK(int, 0, inode_listxattr, struct dentry *dentry)
> >  LSM_HOOK(int, 0, inode_removexattr, struct mnt_idmap *idmap,
> >  	 struct dentry *dentry, const char *name)
> > +LSM_HOOK(void, LSM_RET_VOID, inode_post_removexattr, struct dentry *dentry,
> > +	 const char *name)
> >  LSM_HOOK(int, 0, inode_set_acl, struct mnt_idmap *idmap,
> >  	 struct dentry *dentry, const char *acl_name, struct posix_acl *kacl)
> >  LSM_HOOK(int, 0, inode_get_acl, struct mnt_idmap *idmap,
> > diff --git a/include/linux/security.h b/include/linux/security.h
> > index 664df46b22a9..922ea7709bae 100644
> > --- a/include/linux/security.h
> > +++ b/include/linux/security.h
> > @@ -380,6 +380,7 @@ int security_inode_getxattr(struct dentry *dentry, const char *name);
> >  int security_inode_listxattr(struct dentry *dentry);
> >  int security_inode_removexattr(struct mnt_idmap *idmap,
> >  			       struct dentry *dentry, const char *name);
> > +void security_inode_post_removexattr(struct dentry *dentry, const char *name);
> >  int security_inode_need_killpriv(struct dentry *dentry);
> >  int security_inode_killpriv(struct mnt_idmap *idmap, struct dentry *dentry);
> >  int security_inode_getsecurity(struct mnt_idmap *idmap,
> > @@ -940,6 +941,10 @@ static inline int security_inode_removexattr(struct mnt_idmap *idmap,
> >  	return cap_inode_removexattr(idmap, dentry, name);
> >  }
> >  
> > +static inline void security_inode_post_removexattr(struct dentry *dentry,
> > +						   const char *name)
> > +{ }
> > +
> >  static inline int security_inode_need_killpriv(struct dentry *dentry)
> >  {
> >  	return cap_inode_need_killpriv(dentry);
> > diff --git a/security/security.c b/security/security.c
> > index ce3bc7642e18..8aa6e9f316dd 100644
> > --- a/security/security.c
> > +++ b/security/security.c
> > @@ -2452,6 +2452,20 @@ int security_inode_removexattr(struct mnt_idmap *idmap,
> >  	return evm_inode_removexattr(idmap, dentry, name);
> >  }
> >  
> > +/**
> > + * security_inode_post_removexattr() - Update the inode after a removexattr op
> > + * @dentry: file
> > + * @name: xattr name
> > + *
> > + * Update the inode after a successful removexattr operation.
> > + */
> > +void security_inode_post_removexattr(struct dentry *dentry, const char *name)
> > +{
> > +	if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
> > +		return;
> > +	call_void_hook(inode_post_removexattr, dentry, name);
> > +}
> > +
> >  /**
> >   * security_inode_need_killpriv() - Check if security_inode_killpriv() required
> >   * @dentry: associated dentry


^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v5 11/23] security: Introduce inode_post_removexattr hook
  2023-11-20 17:31     ` Roberto Sassu
@ 2023-11-20 18:03       ` Casey Schaufler
  2023-11-20 20:55         ` Paul Moore
  0 siblings, 1 reply; 96+ messages in thread
From: Casey Schaufler @ 2023-11-20 18:03 UTC (permalink / raw)
  To: Roberto Sassu, viro, brauner, chuck.lever, jlayton, neilb, kolga,
	Dai.Ngo, tom, paul, jmorris, serge, zohar, dmitry.kasatkin,
	dhowells, jarkko, stephen.smalley.work, eparis, mic
  Cc: linux-fsdevel, linux-kernel, linux-nfs, linux-security-module,
	linux-integrity, keyrings, selinux, Roberto Sassu, Stefan Berger,
	Casey Schaufler

On 11/20/2023 9:31 AM, Roberto Sassu wrote:
> On Tue, 2023-11-07 at 09:33 -0800, Casey Schaufler wrote:
>> On 11/7/2023 5:40 AM, 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_removexattr hook.
>>>
>>> At inode_removexattr hook, EVM verifies the file's existing HMAC value. At
>>> inode_post_removexattr, EVM re-calculates the file's HMAC with the passed
>>> xattr removed and other file metadata.
>>>
>>> Other LSMs could similarly take some action after successful xattr removal.
>>>
>>> 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>
>>> Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
>>> ---
>>>  fs/xattr.c                    |  9 +++++----
>>>  include/linux/lsm_hook_defs.h |  2 ++
>>>  include/linux/security.h      |  5 +++++
>>>  security/security.c           | 14 ++++++++++++++
>>>  4 files changed, 26 insertions(+), 4 deletions(-)
>>>
>>> diff --git a/fs/xattr.c b/fs/xattr.c
>>> index 09d927603433..84a4aa566c02 100644
>>> --- a/fs/xattr.c
>>> +++ b/fs/xattr.c
>>> @@ -552,11 +552,12 @@ __vfs_removexattr_locked(struct mnt_idmap *idmap,
>>>  		goto out;
>>>  
>>>  	error = __vfs_removexattr(idmap, dentry, name);
>>> +	if (error)
>>> +		goto out;
>> Shouldn't this be simply "return error" rather than a goto to nothing
>> but "return error"?
> I got a review from Andrew Morton. His argument seems convincing, that
> having less return places makes the code easier to handle.

That was in a case where you did more than just "return". Nonetheless,
I think it's a matter of style that's not worth debating. Do as you will.

>
> Thanks
>
> Roberto
>
>>> -	if (!error) {
>>> -		fsnotify_xattr(dentry);
>>> -		evm_inode_post_removexattr(dentry, name);
>>> -	}
>>> +	fsnotify_xattr(dentry);
>>> +	security_inode_post_removexattr(dentry, name);
>>> +	evm_inode_post_removexattr(dentry, name);
>>>  
>>>  out:
>>>  	return error;
>>> diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
>>> index 67410e085205..88452e45025c 100644
>>> --- a/include/linux/lsm_hook_defs.h
>>> +++ b/include/linux/lsm_hook_defs.h
>>> @@ -149,6 +149,8 @@ LSM_HOOK(int, 0, inode_getxattr, struct dentry *dentry, const char *name)
>>>  LSM_HOOK(int, 0, inode_listxattr, struct dentry *dentry)
>>>  LSM_HOOK(int, 0, inode_removexattr, struct mnt_idmap *idmap,
>>>  	 struct dentry *dentry, const char *name)
>>> +LSM_HOOK(void, LSM_RET_VOID, inode_post_removexattr, struct dentry *dentry,
>>> +	 const char *name)
>>>  LSM_HOOK(int, 0, inode_set_acl, struct mnt_idmap *idmap,
>>>  	 struct dentry *dentry, const char *acl_name, struct posix_acl *kacl)
>>>  LSM_HOOK(int, 0, inode_get_acl, struct mnt_idmap *idmap,
>>> diff --git a/include/linux/security.h b/include/linux/security.h
>>> index 664df46b22a9..922ea7709bae 100644
>>> --- a/include/linux/security.h
>>> +++ b/include/linux/security.h
>>> @@ -380,6 +380,7 @@ int security_inode_getxattr(struct dentry *dentry, const char *name);
>>>  int security_inode_listxattr(struct dentry *dentry);
>>>  int security_inode_removexattr(struct mnt_idmap *idmap,
>>>  			       struct dentry *dentry, const char *name);
>>> +void security_inode_post_removexattr(struct dentry *dentry, const char *name);
>>>  int security_inode_need_killpriv(struct dentry *dentry);
>>>  int security_inode_killpriv(struct mnt_idmap *idmap, struct dentry *dentry);
>>>  int security_inode_getsecurity(struct mnt_idmap *idmap,
>>> @@ -940,6 +941,10 @@ static inline int security_inode_removexattr(struct mnt_idmap *idmap,
>>>  	return cap_inode_removexattr(idmap, dentry, name);
>>>  }
>>>  
>>> +static inline void security_inode_post_removexattr(struct dentry *dentry,
>>> +						   const char *name)
>>> +{ }
>>> +
>>>  static inline int security_inode_need_killpriv(struct dentry *dentry)
>>>  {
>>>  	return cap_inode_need_killpriv(dentry);
>>> diff --git a/security/security.c b/security/security.c
>>> index ce3bc7642e18..8aa6e9f316dd 100644
>>> --- a/security/security.c
>>> +++ b/security/security.c
>>> @@ -2452,6 +2452,20 @@ int security_inode_removexattr(struct mnt_idmap *idmap,
>>>  	return evm_inode_removexattr(idmap, dentry, name);
>>>  }
>>>  
>>> +/**
>>> + * security_inode_post_removexattr() - Update the inode after a removexattr op
>>> + * @dentry: file
>>> + * @name: xattr name
>>> + *
>>> + * Update the inode after a successful removexattr operation.
>>> + */
>>> +void security_inode_post_removexattr(struct dentry *dentry, const char *name)
>>> +{
>>> +	if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
>>> +		return;
>>> +	call_void_hook(inode_post_removexattr, dentry, name);
>>> +}
>>> +
>>>  /**
>>>   * security_inode_need_killpriv() - Check if security_inode_killpriv() required
>>>   * @dentry: associated dentry

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v5 11/23] security: Introduce inode_post_removexattr hook
  2023-11-20 18:03       ` Casey Schaufler
@ 2023-11-20 20:55         ` Paul Moore
  0 siblings, 0 replies; 96+ messages in thread
From: Paul Moore @ 2023-11-20 20:55 UTC (permalink / raw)
  To: Casey Schaufler
  Cc: Roberto Sassu, viro, brauner, chuck.lever, jlayton, neilb, kolga,
	Dai.Ngo, tom, jmorris, serge, zohar, dmitry.kasatkin, dhowells,
	jarkko, stephen.smalley.work, eparis, mic, linux-fsdevel,
	linux-kernel, linux-nfs, linux-security-module, linux-integrity,
	keyrings, selinux, Roberto Sassu, Stefan Berger

On Mon, Nov 20, 2023 at 1:04 PM Casey Schaufler <casey@schaufler-ca.com> wrote:
> On 11/20/2023 9:31 AM, Roberto Sassu wrote:
> > On Tue, 2023-11-07 at 09:33 -0800, Casey Schaufler wrote:
> >> On 11/7/2023 5:40 AM, 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_removexattr hook.
> >>>
> >>> At inode_removexattr hook, EVM verifies the file's existing HMAC value. At
> >>> inode_post_removexattr, EVM re-calculates the file's HMAC with the passed
> >>> xattr removed and other file metadata.
> >>>
> >>> Other LSMs could similarly take some action after successful xattr removal.
> >>>
> >>> 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>
> >>> Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
> >>> ---
> >>>  fs/xattr.c                    |  9 +++++----
> >>>  include/linux/lsm_hook_defs.h |  2 ++
> >>>  include/linux/security.h      |  5 +++++
> >>>  security/security.c           | 14 ++++++++++++++
> >>>  4 files changed, 26 insertions(+), 4 deletions(-)
> >>>
> >>> diff --git a/fs/xattr.c b/fs/xattr.c
> >>> index 09d927603433..84a4aa566c02 100644
> >>> --- a/fs/xattr.c
> >>> +++ b/fs/xattr.c
> >>> @@ -552,11 +552,12 @@ __vfs_removexattr_locked(struct mnt_idmap *idmap,
> >>>             goto out;
> >>>
> >>>     error = __vfs_removexattr(idmap, dentry, name);
> >>> +   if (error)
> >>> +           goto out;
> >> Shouldn't this be simply "return error" rather than a goto to nothing
> >> but "return error"?
> > I got a review from Andrew Morton. His argument seems convincing, that
> > having less return places makes the code easier to handle.
>
> That was in a case where you did more than just "return". Nonetheless,
> I think it's a matter of style that's not worth debating. Do as you will.

I'm not too bothered by this in the VFS code, that's up to the VFS
maintainers, but for future reference, in the LSM layer I really
dislike jumping to a label simply to return.

-- 
paul-moore.com

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v5 23/23] integrity: Switch from rbtree to LSM-managed blob for integrity_iint_cache
  2023-11-20  8:16     ` Roberto Sassu
@ 2023-11-20 21:06       ` Paul Moore
  2023-11-29 12:27         ` Roberto Sassu
  0 siblings, 1 reply; 96+ messages in thread
From: Paul Moore @ 2023-11-20 21:06 UTC (permalink / raw)
  To: Roberto Sassu
  Cc: viro, brauner, chuck.lever, jlayton, neilb, kolga, Dai.Ngo, tom,
	jmorris, serge, zohar, dmitry.kasatkin, dhowells, jarkko,
	stephen.smalley.work, eparis, casey, mic, linux-fsdevel,
	linux-kernel, linux-nfs, linux-security-module, linux-integrity,
	keyrings, selinux, Roberto Sassu

On Mon, Nov 20, 2023 at 3:16 AM Roberto Sassu
<roberto.sassu@huaweicloud.com> wrote:
> On Fri, 2023-11-17 at 15:57 -0500, Paul Moore wrote:
> > On Nov  7, 2023 Roberto Sassu <roberto.sassu@huaweicloud.com> wrote:
> > >
> > > Before the security field of kernel objects could be shared among LSMs with
> > > the LSM stacking feature, IMA and EVM had to rely on an alternative storage
> > > of inode metadata. The association between inode metadata and inode is
> > > maintained through an rbtree.
> > >
> > > Because of this alternative storage mechanism, there was no need to use
> > > disjoint inode metadata, so IMA and EVM today still share them.
> > >
> > > With the reservation mechanism offered by the LSM infrastructure, the
> > > rbtree is no longer necessary, as each LSM could reserve a space in the
> > > security blob for each inode. However, since IMA and EVM share the
> > > inode metadata, they cannot directly reserve the space for them.
> > >
> > > Instead, request from the 'integrity' LSM a space in the security blob for
> > > the pointer of inode metadata (integrity_iint_cache structure). The other
> > > reason for keeping the 'integrity' LSM is to preserve the original ordering
> > > of IMA and EVM functions as when they were hardcoded.
> > >
> > > Prefer reserving space for a pointer to allocating the integrity_iint_cache
> > > structure directly, as IMA would require it only for a subset of inodes.
> > > Always allocating it would cause a waste of memory.
> > >
> > > Introduce two primitives for getting and setting the pointer of
> > > integrity_iint_cache in the security blob, respectively
> > > integrity_inode_get_iint() and integrity_inode_set_iint(). This would make
> > > the code more understandable, as they directly replace rbtree operations.
> > >
> > > Locking is not needed, as access to inode metadata is not shared, it is per
> > > inode.
> > >
> > > Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
> > > Reviewed-by: Casey Schaufler <casey@schaufler-ca.com>
> > > Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
> > > ---
> > >  security/integrity/iint.c      | 71 +++++-----------------------------
> > >  security/integrity/integrity.h | 20 +++++++++-
> > >  2 files changed, 29 insertions(+), 62 deletions(-)
> > >
> > > diff --git a/security/integrity/iint.c b/security/integrity/iint.c
> > > index 882fde2a2607..a5edd3c70784 100644
> > > --- a/security/integrity/iint.c
> > > +++ b/security/integrity/iint.c
> > > @@ -231,6 +175,10 @@ static int __init integrity_lsm_init(void)
> > >     return 0;
> > >  }
> > >
> > > +struct lsm_blob_sizes integrity_blob_sizes __ro_after_init = {
> > > +   .lbs_inode = sizeof(struct integrity_iint_cache *),
> > > +};
> >
> > I'll admit that I'm likely missing an important detail, but is there
> > a reason why you couldn't stash the integrity_iint_cache struct
> > directly in the inode's security blob instead of the pointer?  For
> > example:
> >
> >   struct lsm_blob_sizes ... = {
> >     .lbs_inode = sizeof(struct integrity_iint_cache),
> >   };
> >
> >   struct integrity_iint_cache *integrity_inode_get(inode)
> >   {
> >     if (unlikely(!inode->isecurity))
> >       return NULL;
> >     return inode->i_security + integrity_blob_sizes.lbs_inode;
> >   }
>
> It would increase memory occupation. Sometimes the IMA policy
> encompasses a small subset of the inodes. Allocating the full
> integrity_iint_cache would be a waste of memory, I guess?

Perhaps, but if it allows us to remove another layer of dynamic memory
I would argue that it may be worth the cost.  It's also worth
considering the size of integrity_iint_cache, while it isn't small, it
isn't exactly huge either.

> On the other hand... (did not think fully about that) if we embed the
> full structure in the security blob, we already have a mutex available
> to use, and we don't need to take the inode lock (?).

That would be excellent, getting rid of a layer of locking would be significant.

> I'm fully convinced that we can improve the implementation
> significantly. I just was really hoping to go step by step and not
> accumulating improvements as dependency for moving IMA and EVM to the
> LSM infrastructure.

I understand, and I agree that an iterative approach is a good idea, I
just want to make sure we keep things tidy from a user perspective,
i.e. not exposing the "integrity" LSM when it isn't required.

--
paul-moore.com

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v5 23/23] integrity: Switch from rbtree to LSM-managed blob for integrity_iint_cache
  2023-11-20 21:06       ` Paul Moore
@ 2023-11-29 12:27         ` Roberto Sassu
  2023-11-29 13:58           ` Roberto Sassu
  2023-11-29 17:22           ` Paul Moore
  0 siblings, 2 replies; 96+ messages in thread
From: Roberto Sassu @ 2023-11-29 12:27 UTC (permalink / raw)
  To: Paul Moore
  Cc: viro, brauner, chuck.lever, jlayton, neilb, kolga, Dai.Ngo, tom,
	jmorris, serge, zohar, dmitry.kasatkin, dhowells, jarkko,
	stephen.smalley.work, eparis, casey, mic, linux-fsdevel,
	linux-kernel, linux-nfs, linux-security-module, linux-integrity,
	keyrings, selinux, Roberto Sassu

On Mon, 2023-11-20 at 16:06 -0500, Paul Moore wrote:
> On Mon, Nov 20, 2023 at 3:16 AM Roberto Sassu
> <roberto.sassu@huaweicloud.com> wrote:
> > On Fri, 2023-11-17 at 15:57 -0500, Paul Moore wrote:
> > > On Nov  7, 2023 Roberto Sassu <roberto.sassu@huaweicloud.com> wrote:
> > > > 
> > > > Before the security field of kernel objects could be shared among LSMs with
> > > > the LSM stacking feature, IMA and EVM had to rely on an alternative storage
> > > > of inode metadata. The association between inode metadata and inode is
> > > > maintained through an rbtree.
> > > > 
> > > > Because of this alternative storage mechanism, there was no need to use
> > > > disjoint inode metadata, so IMA and EVM today still share them.
> > > > 
> > > > With the reservation mechanism offered by the LSM infrastructure, the
> > > > rbtree is no longer necessary, as each LSM could reserve a space in the
> > > > security blob for each inode. However, since IMA and EVM share the
> > > > inode metadata, they cannot directly reserve the space for them.
> > > > 
> > > > Instead, request from the 'integrity' LSM a space in the security blob for
> > > > the pointer of inode metadata (integrity_iint_cache structure). The other
> > > > reason for keeping the 'integrity' LSM is to preserve the original ordering
> > > > of IMA and EVM functions as when they were hardcoded.
> > > > 
> > > > Prefer reserving space for a pointer to allocating the integrity_iint_cache
> > > > structure directly, as IMA would require it only for a subset of inodes.
> > > > Always allocating it would cause a waste of memory.
> > > > 
> > > > Introduce two primitives for getting and setting the pointer of
> > > > integrity_iint_cache in the security blob, respectively
> > > > integrity_inode_get_iint() and integrity_inode_set_iint(). This would make
> > > > the code more understandable, as they directly replace rbtree operations.
> > > > 
> > > > Locking is not needed, as access to inode metadata is not shared, it is per
> > > > inode.
> > > > 
> > > > Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
> > > > Reviewed-by: Casey Schaufler <casey@schaufler-ca.com>
> > > > Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
> > > > ---
> > > >  security/integrity/iint.c      | 71 +++++-----------------------------
> > > >  security/integrity/integrity.h | 20 +++++++++-
> > > >  2 files changed, 29 insertions(+), 62 deletions(-)
> > > > 
> > > > diff --git a/security/integrity/iint.c b/security/integrity/iint.c
> > > > index 882fde2a2607..a5edd3c70784 100644
> > > > --- a/security/integrity/iint.c
> > > > +++ b/security/integrity/iint.c
> > > > @@ -231,6 +175,10 @@ static int __init integrity_lsm_init(void)
> > > >     return 0;
> > > >  }
> > > > 
> > > > +struct lsm_blob_sizes integrity_blob_sizes __ro_after_init = {
> > > > +   .lbs_inode = sizeof(struct integrity_iint_cache *),
> > > > +};
> > > 
> > > I'll admit that I'm likely missing an important detail, but is there
> > > a reason why you couldn't stash the integrity_iint_cache struct
> > > directly in the inode's security blob instead of the pointer?  For
> > > example:
> > > 
> > >   struct lsm_blob_sizes ... = {
> > >     .lbs_inode = sizeof(struct integrity_iint_cache),
> > >   };
> > > 
> > >   struct integrity_iint_cache *integrity_inode_get(inode)
> > >   {
> > >     if (unlikely(!inode->isecurity))
> > >       return NULL;
> > >     return inode->i_security + integrity_blob_sizes.lbs_inode;
> > >   }
> > 
> > It would increase memory occupation. Sometimes the IMA policy
> > encompasses a small subset of the inodes. Allocating the full
> > integrity_iint_cache would be a waste of memory, I guess?
> 
> Perhaps, but if it allows us to remove another layer of dynamic memory
> I would argue that it may be worth the cost.  It's also worth
> considering the size of integrity_iint_cache, while it isn't small, it
> isn't exactly huge either.
> 
> > On the other hand... (did not think fully about that) if we embed the
> > full structure in the security blob, we already have a mutex available
> > to use, and we don't need to take the inode lock (?).
> 
> That would be excellent, getting rid of a layer of locking would be significant.
> 
> > I'm fully convinced that we can improve the implementation
> > significantly. I just was really hoping to go step by step and not
> > accumulating improvements as dependency for moving IMA and EVM to the
> > LSM infrastructure.
> 
> I understand, and I agree that an iterative approach is a good idea, I
> just want to make sure we keep things tidy from a user perspective,
> i.e. not exposing the "integrity" LSM when it isn't required.

Ok, I went back to it again.

I think trying to separate integrity metadata is premature now, too
many things at the same time.

I started to think, does EVM really need integrity metadata or it can
work without?

The fact is that CONFIG_IMA=n and CONFIG_EVM=y is allowed, so we have
the same problem now. What if we make IMA the one that manages
integrity metadata, so that we can remove the 'integrity' LSM?

So, no embedding the full structure in the security blob now, move
integrity_inode_free() and integrity_kernel_module_request() to IMA,
call integrity_iintcache_init() from IMA.

EVM verification of new files would fail without IMA, but it would be
the same now.

Also, evm_verifyxattr() would only work with IMA, as it assumes that
the latter creates integrity metadata and passes them as argument.

Regarding the LSM order, I would take Casey's suggestion of introducing
LSM_ORDER_REALLY_LAST, for EVM.

Thanks

Roberto


^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v5 23/23] integrity: Switch from rbtree to LSM-managed blob for integrity_iint_cache
  2023-11-29 12:27         ` Roberto Sassu
@ 2023-11-29 13:58           ` Roberto Sassu
  2023-11-29 17:22           ` Paul Moore
  1 sibling, 0 replies; 96+ messages in thread
From: Roberto Sassu @ 2023-11-29 13:58 UTC (permalink / raw)
  To: Paul Moore
  Cc: viro, brauner, chuck.lever, jlayton, neilb, kolga, Dai.Ngo, tom,
	jmorris, serge, zohar, dmitry.kasatkin, dhowells, jarkko,
	stephen.smalley.work, eparis, casey, mic, linux-fsdevel,
	linux-kernel, linux-nfs, linux-security-module, linux-integrity,
	keyrings, selinux, Roberto Sassu

[-- Attachment #1: Type: text/plain, Size: 6205 bytes --]

On Wed, 2023-11-29 at 13:27 +0100, Roberto Sassu wrote:
> On Mon, 2023-11-20 at 16:06 -0500, Paul Moore wrote:
> > On Mon, Nov 20, 2023 at 3:16 AM Roberto Sassu
> > <roberto.sassu@huaweicloud.com> wrote:
> > > On Fri, 2023-11-17 at 15:57 -0500, Paul Moore wrote:
> > > > On Nov  7, 2023 Roberto Sassu <roberto.sassu@huaweicloud.com> wrote:
> > > > > 
> > > > > Before the security field of kernel objects could be shared among LSMs with
> > > > > the LSM stacking feature, IMA and EVM had to rely on an alternative storage
> > > > > of inode metadata. The association between inode metadata and inode is
> > > > > maintained through an rbtree.
> > > > > 
> > > > > Because of this alternative storage mechanism, there was no need to use
> > > > > disjoint inode metadata, so IMA and EVM today still share them.
> > > > > 
> > > > > With the reservation mechanism offered by the LSM infrastructure, the
> > > > > rbtree is no longer necessary, as each LSM could reserve a space in the
> > > > > security blob for each inode. However, since IMA and EVM share the
> > > > > inode metadata, they cannot directly reserve the space for them.
> > > > > 
> > > > > Instead, request from the 'integrity' LSM a space in the security blob for
> > > > > the pointer of inode metadata (integrity_iint_cache structure). The other
> > > > > reason for keeping the 'integrity' LSM is to preserve the original ordering
> > > > > of IMA and EVM functions as when they were hardcoded.
> > > > > 
> > > > > Prefer reserving space for a pointer to allocating the integrity_iint_cache
> > > > > structure directly, as IMA would require it only for a subset of inodes.
> > > > > Always allocating it would cause a waste of memory.
> > > > > 
> > > > > Introduce two primitives for getting and setting the pointer of
> > > > > integrity_iint_cache in the security blob, respectively
> > > > > integrity_inode_get_iint() and integrity_inode_set_iint(). This would make
> > > > > the code more understandable, as they directly replace rbtree operations.
> > > > > 
> > > > > Locking is not needed, as access to inode metadata is not shared, it is per
> > > > > inode.
> > > > > 
> > > > > Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
> > > > > Reviewed-by: Casey Schaufler <casey@schaufler-ca.com>
> > > > > Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
> > > > > ---
> > > > >  security/integrity/iint.c      | 71 +++++-----------------------------
> > > > >  security/integrity/integrity.h | 20 +++++++++-
> > > > >  2 files changed, 29 insertions(+), 62 deletions(-)
> > > > > 
> > > > > diff --git a/security/integrity/iint.c b/security/integrity/iint.c
> > > > > index 882fde2a2607..a5edd3c70784 100644
> > > > > --- a/security/integrity/iint.c
> > > > > +++ b/security/integrity/iint.c
> > > > > @@ -231,6 +175,10 @@ static int __init integrity_lsm_init(void)
> > > > >     return 0;
> > > > >  }
> > > > > 
> > > > > +struct lsm_blob_sizes integrity_blob_sizes __ro_after_init = {
> > > > > +   .lbs_inode = sizeof(struct integrity_iint_cache *),
> > > > > +};
> > > > 
> > > > I'll admit that I'm likely missing an important detail, but is there
> > > > a reason why you couldn't stash the integrity_iint_cache struct
> > > > directly in the inode's security blob instead of the pointer?  For
> > > > example:
> > > > 
> > > >   struct lsm_blob_sizes ... = {
> > > >     .lbs_inode = sizeof(struct integrity_iint_cache),
> > > >   };
> > > > 
> > > >   struct integrity_iint_cache *integrity_inode_get(inode)
> > > >   {
> > > >     if (unlikely(!inode->isecurity))
> > > >       return NULL;
> > > >     return inode->i_security + integrity_blob_sizes.lbs_inode;
> > > >   }
> > > 
> > > It would increase memory occupation. Sometimes the IMA policy
> > > encompasses a small subset of the inodes. Allocating the full
> > > integrity_iint_cache would be a waste of memory, I guess?
> > 
> > Perhaps, but if it allows us to remove another layer of dynamic memory
> > I would argue that it may be worth the cost.  It's also worth
> > considering the size of integrity_iint_cache, while it isn't small, it
> > isn't exactly huge either.
> > 
> > > On the other hand... (did not think fully about that) if we embed the
> > > full structure in the security blob, we already have a mutex available
> > > to use, and we don't need to take the inode lock (?).
> > 
> > That would be excellent, getting rid of a layer of locking would be significant.
> > 
> > > I'm fully convinced that we can improve the implementation
> > > significantly. I just was really hoping to go step by step and not
> > > accumulating improvements as dependency for moving IMA and EVM to the
> > > LSM infrastructure.
> > 
> > I understand, and I agree that an iterative approach is a good idea, I
> > just want to make sure we keep things tidy from a user perspective,
> > i.e. not exposing the "integrity" LSM when it isn't required.
> 
> Ok, I went back to it again.
> 
> I think trying to separate integrity metadata is premature now, too
> many things at the same time.
> 
> I started to think, does EVM really need integrity metadata or it can
> work without?
> 
> The fact is that CONFIG_IMA=n and CONFIG_EVM=y is allowed, so we have
> the same problem now. What if we make IMA the one that manages
> integrity metadata, so that we can remove the 'integrity' LSM?
> 
> So, no embedding the full structure in the security blob now, move
> integrity_inode_free() and integrity_kernel_module_request() to IMA,
> call integrity_iintcache_init() from IMA.
> 
> EVM verification of new files would fail without IMA, but it would be
> the same now.
> 
> Also, evm_verifyxattr() would only work with IMA, as it assumes that
> the latter creates integrity metadata and passes them as argument.
> 
> Regarding the LSM order, I would take Casey's suggestion of introducing
> LSM_ORDER_REALLY_LAST, for EVM.

I attach the diff v5..v7.

Tests passes with both IMA and EVM enabled. I did minor tweaks to the
tests to take into account the possibility that IMA is disabled, and
tests pass also in this case.

Roberto


[-- Attachment #2: ima_evm_lsms_v5_v7.diff --]
[-- Type: text/x-patch, Size: 12086 bytes --]

diff --git a/fs/file_table.c b/fs/file_table.c
index e64b0057fa72..0401ac98281c 100644
--- a/fs/file_table.c
+++ b/fs/file_table.c
@@ -384,7 +384,7 @@ static void __fput(struct file *file)
 	eventpoll_release(file);
 	locks_remove_file(file);
 
-	security_file_pre_free(file);
+	security_file_release(file);
 	if (unlikely(file->f_flags & FASYNC)) {
 		if (file->f_op->fasync)
 			file->f_op->fasync(-1, file, 0);
diff --git a/fs/xattr.c b/fs/xattr.c
index 2660bc7effdc..f8b643f91a98 100644
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -552,7 +552,7 @@ __vfs_removexattr_locked(struct mnt_idmap *idmap,
 
 	error = __vfs_removexattr(idmap, dentry, name);
 	if (error)
-		goto out;
+		return error;
 
 	fsnotify_xattr(dentry);
 	security_inode_post_removexattr(dentry, name);
diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
index 9601df10ea28..2679905f4260 100644
--- a/include/linux/lsm_hook_defs.h
+++ b/include/linux/lsm_hook_defs.h
@@ -181,7 +181,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_pre_free_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/lsm_hooks.h b/include/linux/lsm_hooks.h
index a2ade0ffe9e7..8b0c96dd7c90 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -125,7 +125,8 @@ extern void security_add_hooks(struct security_hook_list *hooks, int count,
 enum lsm_order {
 	LSM_ORDER_FIRST = -1,	/* This is only for capabilities. */
 	LSM_ORDER_MUTABLE = 0,
-	LSM_ORDER_LAST = 1,	/* This is only for integrity. */
+	LSM_ORDER_LAST = 1, /* For always enabled LSMs after mutable ones. */
+	LSM_ORDER_REALLY_LAST = 2, /* After the last ones. */
 };
 
 struct lsm_info {
diff --git a/include/linux/security.h b/include/linux/security.h
index 1cd84970ab4c..766eaccc4679 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -402,7 +402,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_pre_free(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_mmap_file(struct file *file, unsigned long prot,
@@ -1028,7 +1028,7 @@ static inline int security_file_alloc(struct file *file)
 	return 0;
 }
 
-static inline void security_file_pre_free(struct file *file)
+static inline void security_file_release(struct file *file)
 { }
 
 static inline void security_file_free(struct file *file)
diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c
index 21560874e5fc..fa54166e1a3d 100644
--- a/security/integrity/evm/evm_main.c
+++ b/security/integrity/evm/evm_main.c
@@ -1037,37 +1037,20 @@ static const struct lsm_id evm_lsmid = {
 	.id = LSM_ID_EVM,
 };
 
-/* Return the EVM LSM ID, if EVM is enabled or NULL if not. */
-const struct lsm_id *evm_get_lsm_id(void)
-{
-	return &evm_lsmid;
-}
-
-/*
- * Since with the LSM_ORDER_LAST there is no guarantee about the ordering
- * within the .lsm_info.init section, ensure that IMA hooks are before EVM
- * ones, by letting the 'integrity' LSM call init_evm_lsm() to initialize the
- * 'ima' and 'evm' LSMs in this sequence.
- */
-void __init init_evm_lsm(void)
+static int __init init_evm_lsm(void)
 {
 	security_add_hooks(evm_hooks, ARRAY_SIZE(evm_hooks), &evm_lsmid);
+	return 0;
 }
 
 static struct lsm_blob_sizes evm_blob_sizes __ro_after_init = {
 	.lbs_xattr_count = 1,
 };
 
-/* Introduce a dummy function as 'evm' init method (it cannot be NULL). */
-static int __init dummy_init_evm_lsm(void)
-{
-	return 0;
-}
-
 DEFINE_LSM(evm) = {
 	.name = "evm",
-	.init = dummy_init_evm_lsm,
-	.order = LSM_ORDER_LAST,
+	.init = init_evm_lsm,
+	.order = LSM_ORDER_REALLY_LAST,
 	.blobs = &evm_blob_sizes,
 };
 
diff --git a/security/integrity/iint.c b/security/integrity/iint.c
index a5edd3c70784..8fc9455dda11 100644
--- a/security/integrity/iint.c
+++ b/security/integrity/iint.c
@@ -94,6 +94,13 @@ struct integrity_iint_cache *integrity_inode_get(struct inode *inode)
 {
 	struct integrity_iint_cache *iint;
 
+	/*
+	 * After removing the 'integrity' LSM, the 'ima' LSM calls
+	 * integrity_iintcache_init() to initialize iint_cache.
+	 */
+	if (!IS_ENABLED(CONFIG_IMA))
+		return NULL;
+
 	iint = integrity_iint_find(inode);
 	if (iint)
 		return iint;
@@ -117,7 +124,7 @@ struct integrity_iint_cache *integrity_inode_get(struct inode *inode)
  *
  * Free the integrity information(iint) associated with an inode.
  */
-static void integrity_inode_free(struct inode *inode)
+void integrity_inode_free(struct inode *inode)
 {
 	struct integrity_iint_cache *iint;
 
@@ -137,41 +144,15 @@ static void iint_init_once(void *foo)
 	memset(iint, 0, sizeof(*iint));
 }
 
-static struct security_hook_list integrity_hooks[] __ro_after_init = {
-	LSM_HOOK_INIT(inode_free_security, integrity_inode_free),
-#ifdef CONFIG_INTEGRITY_ASYMMETRIC_KEYS
-	LSM_HOOK_INIT(kernel_module_request, integrity_kernel_module_request),
-#endif
-};
-
 /*
- * Perform the initialization of the 'integrity', 'ima' and 'evm' LSMs to
- * ensure that the management of integrity metadata is working at the time
- * IMA and EVM hooks are registered to the LSM infrastructure, and to keep
- * the original ordering of IMA and EVM functions as when they were hardcoded.
+ * Initialize the integrity metadata cache from IMA, since it is the only LSM
+ * that really needs it. EVM can work without it.
  */
-static int __init integrity_lsm_init(void)
+int __init integrity_iintcache_init(void)
 {
-	const struct lsm_id *lsmid;
-
 	iint_cache =
 	    kmem_cache_create("iint_cache", sizeof(struct integrity_iint_cache),
 			      0, SLAB_PANIC, iint_init_once);
-	/*
-	 * Obtain either the IMA or EVM LSM ID to register integrity-specific
-	 * hooks under that LSM, since there is no LSM ID assigned to the
-	 * 'integrity' LSM.
-	 */
-	lsmid = ima_get_lsm_id();
-	if (!lsmid)
-		lsmid = evm_get_lsm_id();
-	/* No point in continuing, since both IMA and EVM are disabled. */
-	if (!lsmid)
-		return 0;
-
-	security_add_hooks(integrity_hooks, ARRAY_SIZE(integrity_hooks), lsmid);
-	init_ima_lsm();
-	init_evm_lsm();
 	return 0;
 }
 
@@ -179,17 +160,6 @@ struct lsm_blob_sizes integrity_blob_sizes __ro_after_init = {
 	.lbs_inode = sizeof(struct integrity_iint_cache *),
 };
 
-/*
- * Keep it until IMA and EVM can use disjoint integrity metadata, and their
- * initialization order can be swapped without change in their behavior.
- */
-DEFINE_LSM(integrity) = {
-	.name = "integrity",
-	.init = integrity_lsm_init,
-	.order = LSM_ORDER_LAST,
-	.blobs = &integrity_blob_sizes,
-};
-
 /*
  * integrity_kernel_read - read data from the file
  *
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index 9aabbc37916c..52b4a3bba45a 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -1126,7 +1126,7 @@ static struct security_hook_list ima_hooks[] __ro_after_init = {
 	LSM_HOOK_INIT(bprm_check_security, ima_bprm_check),
 	LSM_HOOK_INIT(file_post_open, ima_file_check),
 	LSM_HOOK_INIT(inode_post_create_tmpfile, ima_post_create_tmpfile),
-	LSM_HOOK_INIT(file_pre_free_security, ima_file_free),
+	LSM_HOOK_INIT(file_release, ima_file_free),
 	LSM_HOOK_INIT(mmap_file, ima_file_mmap),
 	LSM_HOOK_INIT(file_mprotect, ima_file_mprotect),
 	LSM_HOOK_INIT(kernel_load_data, ima_load_data),
@@ -1138,6 +1138,10 @@ static struct security_hook_list ima_hooks[] __ro_after_init = {
 #endif
 #ifdef CONFIG_IMA_MEASURE_ASYMMETRIC_KEYS
 	LSM_HOOK_INIT(key_post_create_or_update, ima_post_key_create_or_update),
+#endif
+	LSM_HOOK_INIT(inode_free_security, integrity_inode_free),
+#ifdef CONFIG_INTEGRITY_ASYMMETRIC_KEYS
+	LSM_HOOK_INIT(kernel_module_request, integrity_kernel_module_request),
 #endif
 };
 
@@ -1146,34 +1150,19 @@ static const struct lsm_id ima_lsmid = {
 	.id = LSM_ID_IMA,
 };
 
-/* Return the IMA LSM ID, if IMA is enabled or NULL if not. */
-const struct lsm_id *ima_get_lsm_id(void)
-{
-	return &ima_lsmid;
-}
-
-/*
- * Since with the LSM_ORDER_LAST there is no guarantee about the ordering
- * within the .lsm_info.init section, ensure that IMA hooks are before EVM
- * ones, by letting the 'integrity' LSM call init_ima_lsm() to initialize the
- * 'ima' and 'evm' LSMs in this sequence.
- */
-void __init init_ima_lsm(void)
+static int __init init_ima_lsm(void)
 {
+	integrity_iintcache_init();
 	security_add_hooks(ima_hooks, ARRAY_SIZE(ima_hooks), &ima_lsmid);
 	init_ima_appraise_lsm(&ima_lsmid);
-}
-
-/* Introduce a dummy function as 'ima' init method (it cannot be NULL). */
-static int __init dummy_init_ima_lsm(void)
-{
 	return 0;
 }
 
 DEFINE_LSM(ima) = {
 	.name = "ima",
-	.init = dummy_init_ima_lsm,
+	.init = init_ima_lsm,
 	.order = LSM_ORDER_LAST,
+	.blobs = &integrity_blob_sizes,
 };
 
 late_initcall(init_ima);	/* Start IMA after the TPM is available */
diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h
index ef2689b5264d..2fb35c67d64d 100644
--- a/security/integrity/integrity.h
+++ b/security/integrity/integrity.h
@@ -180,6 +180,8 @@ struct integrity_iint_cache {
  */
 struct integrity_iint_cache *integrity_iint_find(struct inode *inode);
 struct integrity_iint_cache *integrity_inode_get(struct inode *inode);
+void integrity_inode_free(struct inode *inode);
+int __init integrity_iintcache_init(void);
 
 int integrity_kernel_read(struct file *file, loff_t offset,
 			  void *addr, unsigned long count);
@@ -213,36 +215,6 @@ static inline void integrity_inode_set_iint(const struct inode *inode,
 
 struct modsig;
 
-#ifdef CONFIG_IMA
-const struct lsm_id *ima_get_lsm_id(void);
-void __init init_ima_lsm(void);
-#else
-static inline const struct lsm_id *ima_get_lsm_id(void)
-{
-	return NULL;
-}
-
-static inline void __init init_ima_lsm(void)
-{
-}
-
-#endif
-
-#ifdef CONFIG_EVM
-const struct lsm_id *evm_get_lsm_id(void);
-void __init init_evm_lsm(void);
-#else
-static inline const struct lsm_id *evm_get_lsm_id(void)
-{
-	return NULL;
-}
-
-static inline void __init init_evm_lsm(void)
-{
-}
-
-#endif
-
 #ifdef CONFIG_INTEGRITY_SIGNATURE
 
 int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
diff --git a/security/security.c b/security/security.c
index 0d9eaa4cd260..4e3dbeef09fa 100644
--- a/security/security.c
+++ b/security/security.c
@@ -331,12 +331,18 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
 		}
 	}
 
-	/* LSM_ORDER_LAST is always last. */
+	/* LSM_ORDER_LAST after mutable ones. */
 	for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
 		if (lsm->order == LSM_ORDER_LAST)
 			append_ordered_lsm(lsm, "   last");
 	}
 
+	/* LSM_ORDER_REALLY_LAST after LSM_ORDER_LAST. */
+	for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
+		if (lsm->order == LSM_ORDER_REALLY_LAST)
+			append_ordered_lsm(lsm, "   really last");
+	}
+
 	/* Disable all LSMs not in the ordered list. */
 	for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
 		if (exists_ordered_lsm(lsm))
@@ -2746,14 +2752,14 @@ int security_file_alloc(struct file *file)
 }
 
 /**
- * security_file_pre_free() - Perform actions before releasing the file ref
+ * 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_pre_free(struct file *file)
+void security_file_release(struct file *file)
 {
-	call_void_hook(file_pre_free_security, file);
+	call_void_hook(file_release, file);
 }
 
 /**

^ permalink raw reply related	[flat|nested] 96+ messages in thread

* Re: [PATCH v5 23/23] integrity: Switch from rbtree to LSM-managed blob for integrity_iint_cache
  2023-11-29 12:27         ` Roberto Sassu
  2023-11-29 13:58           ` Roberto Sassu
@ 2023-11-29 17:22           ` Paul Moore
  2023-11-29 18:46             ` Roberto Sassu
  1 sibling, 1 reply; 96+ messages in thread
From: Paul Moore @ 2023-11-29 17:22 UTC (permalink / raw)
  To: Roberto Sassu
  Cc: viro, brauner, chuck.lever, jlayton, neilb, kolga, Dai.Ngo, tom,
	jmorris, serge, zohar, dmitry.kasatkin, dhowells, jarkko,
	stephen.smalley.work, eparis, casey, mic, linux-fsdevel,
	linux-kernel, linux-nfs, linux-security-module, linux-integrity,
	keyrings, selinux, Roberto Sassu

On Wed, Nov 29, 2023 at 7:28 AM Roberto Sassu
<roberto.sassu@huaweicloud.com> wrote:
>
> On Mon, 2023-11-20 at 16:06 -0500, Paul Moore wrote:
> > On Mon, Nov 20, 2023 at 3:16 AM Roberto Sassu
> > <roberto.sassu@huaweicloud.com> wrote:
> > > On Fri, 2023-11-17 at 15:57 -0500, Paul Moore wrote:
> > > > On Nov  7, 2023 Roberto Sassu <roberto.sassu@huaweicloud.com> wrote:
> > > > >
> > > > > Before the security field of kernel objects could be shared among LSMs with
> > > > > the LSM stacking feature, IMA and EVM had to rely on an alternative storage
> > > > > of inode metadata. The association between inode metadata and inode is
> > > > > maintained through an rbtree.
> > > > >
> > > > > Because of this alternative storage mechanism, there was no need to use
> > > > > disjoint inode metadata, so IMA and EVM today still share them.
> > > > >
> > > > > With the reservation mechanism offered by the LSM infrastructure, the
> > > > > rbtree is no longer necessary, as each LSM could reserve a space in the
> > > > > security blob for each inode. However, since IMA and EVM share the
> > > > > inode metadata, they cannot directly reserve the space for them.
> > > > >
> > > > > Instead, request from the 'integrity' LSM a space in the security blob for
> > > > > the pointer of inode metadata (integrity_iint_cache structure). The other
> > > > > reason for keeping the 'integrity' LSM is to preserve the original ordering
> > > > > of IMA and EVM functions as when they were hardcoded.
> > > > >
> > > > > Prefer reserving space for a pointer to allocating the integrity_iint_cache
> > > > > structure directly, as IMA would require it only for a subset of inodes.
> > > > > Always allocating it would cause a waste of memory.
> > > > >
> > > > > Introduce two primitives for getting and setting the pointer of
> > > > > integrity_iint_cache in the security blob, respectively
> > > > > integrity_inode_get_iint() and integrity_inode_set_iint(). This would make
> > > > > the code more understandable, as they directly replace rbtree operations.
> > > > >
> > > > > Locking is not needed, as access to inode metadata is not shared, it is per
> > > > > inode.
> > > > >
> > > > > Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
> > > > > Reviewed-by: Casey Schaufler <casey@schaufler-ca.com>
> > > > > Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
> > > > > ---
> > > > >  security/integrity/iint.c      | 71 +++++-----------------------------
> > > > >  security/integrity/integrity.h | 20 +++++++++-
> > > > >  2 files changed, 29 insertions(+), 62 deletions(-)
> > > > >
> > > > > diff --git a/security/integrity/iint.c b/security/integrity/iint.c
> > > > > index 882fde2a2607..a5edd3c70784 100644
> > > > > --- a/security/integrity/iint.c
> > > > > +++ b/security/integrity/iint.c
> > > > > @@ -231,6 +175,10 @@ static int __init integrity_lsm_init(void)
> > > > >     return 0;
> > > > >  }
> > > > >
> > > > > +struct lsm_blob_sizes integrity_blob_sizes __ro_after_init = {
> > > > > +   .lbs_inode = sizeof(struct integrity_iint_cache *),
> > > > > +};
> > > >
> > > > I'll admit that I'm likely missing an important detail, but is there
> > > > a reason why you couldn't stash the integrity_iint_cache struct
> > > > directly in the inode's security blob instead of the pointer?  For
> > > > example:
> > > >
> > > >   struct lsm_blob_sizes ... = {
> > > >     .lbs_inode = sizeof(struct integrity_iint_cache),
> > > >   };
> > > >
> > > >   struct integrity_iint_cache *integrity_inode_get(inode)
> > > >   {
> > > >     if (unlikely(!inode->isecurity))
> > > >       return NULL;
> > > >     return inode->i_security + integrity_blob_sizes.lbs_inode;
> > > >   }
> > >
> > > It would increase memory occupation. Sometimes the IMA policy
> > > encompasses a small subset of the inodes. Allocating the full
> > > integrity_iint_cache would be a waste of memory, I guess?
> >
> > Perhaps, but if it allows us to remove another layer of dynamic memory
> > I would argue that it may be worth the cost.  It's also worth
> > considering the size of integrity_iint_cache, while it isn't small, it
> > isn't exactly huge either.
> >
> > > On the other hand... (did not think fully about that) if we embed the
> > > full structure in the security blob, we already have a mutex available
> > > to use, and we don't need to take the inode lock (?).
> >
> > That would be excellent, getting rid of a layer of locking would be significant.
> >
> > > I'm fully convinced that we can improve the implementation
> > > significantly. I just was really hoping to go step by step and not
> > > accumulating improvements as dependency for moving IMA and EVM to the
> > > LSM infrastructure.
> >
> > I understand, and I agree that an iterative approach is a good idea, I
> > just want to make sure we keep things tidy from a user perspective,
> > i.e. not exposing the "integrity" LSM when it isn't required.
>
> Ok, I went back to it again.
>
> I think trying to separate integrity metadata is premature now, too
> many things at the same time.

I'm not bothered by the size of the patchset, it is more important
that we do The Right Thing.  I would like to hear in more detail why
you don't think this will work, I'm not interested in hearing about
difficult it may be, I'm interested in hearing about what challenges
we need to solve to do this properly.

> I started to think, does EVM really need integrity metadata or it can
> work without?
>
> The fact is that CONFIG_IMA=n and CONFIG_EVM=y is allowed, so we have
> the same problem now. What if we make IMA the one that manages
> integrity metadata, so that we can remove the 'integrity' LSM?

I guess we should probably revisit the basic idea of if it even makes
sense to enable EVM without IMA?  Should we update the Kconfig to
require IMA when EVM is enabled?

> Regarding the LSM order, I would take Casey's suggestion of introducing
> LSM_ORDER_REALLY_LAST, for EVM.

Please understand that I really dislike that we have imposed ordering
constraints at the LSM layer, but I do understand the necessity (the
BPF LSM ordering upsets me the most).  I really don't want to see us
make things worse by adding yet another ordering bucket, I would
rather that we document it well and leave it alone ... basically treat
it like the BPF LSM (grrrrrr).

-- 
paul-moore.com

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v5 23/23] integrity: Switch from rbtree to LSM-managed blob for integrity_iint_cache
  2023-11-29 17:22           ` Paul Moore
@ 2023-11-29 18:46             ` Roberto Sassu
  2023-11-30  0:41               ` Casey Schaufler
                                 ` (3 more replies)
  0 siblings, 4 replies; 96+ messages in thread
From: Roberto Sassu @ 2023-11-29 18:46 UTC (permalink / raw)
  To: Paul Moore
  Cc: viro, brauner, chuck.lever, jlayton, neilb, kolga, Dai.Ngo, tom,
	jmorris, serge, zohar, dmitry.kasatkin, dhowells, jarkko,
	stephen.smalley.work, eparis, casey, mic, linux-fsdevel,
	linux-kernel, linux-nfs, linux-security-module, linux-integrity,
	keyrings, selinux, Roberto Sassu

On 11/29/2023 6:22 PM, Paul Moore wrote:
> On Wed, Nov 29, 2023 at 7:28 AM Roberto Sassu
> <roberto.sassu@huaweicloud.com> wrote:
>>
>> On Mon, 2023-11-20 at 16:06 -0500, Paul Moore wrote:
>>> On Mon, Nov 20, 2023 at 3:16 AM Roberto Sassu
>>> <roberto.sassu@huaweicloud.com> wrote:
>>>> On Fri, 2023-11-17 at 15:57 -0500, Paul Moore wrote:
>>>>> On Nov  7, 2023 Roberto Sassu <roberto.sassu@huaweicloud.com> wrote:
>>>>>>
>>>>>> Before the security field of kernel objects could be shared among LSMs with
>>>>>> the LSM stacking feature, IMA and EVM had to rely on an alternative storage
>>>>>> of inode metadata. The association between inode metadata and inode is
>>>>>> maintained through an rbtree.
>>>>>>
>>>>>> Because of this alternative storage mechanism, there was no need to use
>>>>>> disjoint inode metadata, so IMA and EVM today still share them.
>>>>>>
>>>>>> With the reservation mechanism offered by the LSM infrastructure, the
>>>>>> rbtree is no longer necessary, as each LSM could reserve a space in the
>>>>>> security blob for each inode. However, since IMA and EVM share the
>>>>>> inode metadata, they cannot directly reserve the space for them.
>>>>>>
>>>>>> Instead, request from the 'integrity' LSM a space in the security blob for
>>>>>> the pointer of inode metadata (integrity_iint_cache structure). The other
>>>>>> reason for keeping the 'integrity' LSM is to preserve the original ordering
>>>>>> of IMA and EVM functions as when they were hardcoded.
>>>>>>
>>>>>> Prefer reserving space for a pointer to allocating the integrity_iint_cache
>>>>>> structure directly, as IMA would require it only for a subset of inodes.
>>>>>> Always allocating it would cause a waste of memory.
>>>>>>
>>>>>> Introduce two primitives for getting and setting the pointer of
>>>>>> integrity_iint_cache in the security blob, respectively
>>>>>> integrity_inode_get_iint() and integrity_inode_set_iint(). This would make
>>>>>> the code more understandable, as they directly replace rbtree operations.
>>>>>>
>>>>>> Locking is not needed, as access to inode metadata is not shared, it is per
>>>>>> inode.
>>>>>>
>>>>>> Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
>>>>>> Reviewed-by: Casey Schaufler <casey@schaufler-ca.com>
>>>>>> Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
>>>>>> ---
>>>>>>   security/integrity/iint.c      | 71 +++++-----------------------------
>>>>>>   security/integrity/integrity.h | 20 +++++++++-
>>>>>>   2 files changed, 29 insertions(+), 62 deletions(-)
>>>>>>
>>>>>> diff --git a/security/integrity/iint.c b/security/integrity/iint.c
>>>>>> index 882fde2a2607..a5edd3c70784 100644
>>>>>> --- a/security/integrity/iint.c
>>>>>> +++ b/security/integrity/iint.c
>>>>>> @@ -231,6 +175,10 @@ static int __init integrity_lsm_init(void)
>>>>>>      return 0;
>>>>>>   }
>>>>>>
>>>>>> +struct lsm_blob_sizes integrity_blob_sizes __ro_after_init = {
>>>>>> +   .lbs_inode = sizeof(struct integrity_iint_cache *),
>>>>>> +};
>>>>>
>>>>> I'll admit that I'm likely missing an important detail, but is there
>>>>> a reason why you couldn't stash the integrity_iint_cache struct
>>>>> directly in the inode's security blob instead of the pointer?  For
>>>>> example:
>>>>>
>>>>>    struct lsm_blob_sizes ... = {
>>>>>      .lbs_inode = sizeof(struct integrity_iint_cache),
>>>>>    };
>>>>>
>>>>>    struct integrity_iint_cache *integrity_inode_get(inode)
>>>>>    {
>>>>>      if (unlikely(!inode->isecurity))
>>>>>        return NULL;
>>>>>      return inode->i_security + integrity_blob_sizes.lbs_inode;
>>>>>    }
>>>>
>>>> It would increase memory occupation. Sometimes the IMA policy
>>>> encompasses a small subset of the inodes. Allocating the full
>>>> integrity_iint_cache would be a waste of memory, I guess?
>>>
>>> Perhaps, but if it allows us to remove another layer of dynamic memory
>>> I would argue that it may be worth the cost.  It's also worth
>>> considering the size of integrity_iint_cache, while it isn't small, it
>>> isn't exactly huge either.
>>>
>>>> On the other hand... (did not think fully about that) if we embed the
>>>> full structure in the security blob, we already have a mutex available
>>>> to use, and we don't need to take the inode lock (?).
>>>
>>> That would be excellent, getting rid of a layer of locking would be significant.
>>>
>>>> I'm fully convinced that we can improve the implementation
>>>> significantly. I just was really hoping to go step by step and not
>>>> accumulating improvements as dependency for moving IMA and EVM to the
>>>> LSM infrastructure.
>>>
>>> I understand, and I agree that an iterative approach is a good idea, I
>>> just want to make sure we keep things tidy from a user perspective,
>>> i.e. not exposing the "integrity" LSM when it isn't required.
>>
>> Ok, I went back to it again.
>>
>> I think trying to separate integrity metadata is premature now, too
>> many things at the same time.
> 
> I'm not bothered by the size of the patchset, it is more important
> that we do The Right Thing.  I would like to hear in more detail why
> you don't think this will work, I'm not interested in hearing about
> difficult it may be, I'm interested in hearing about what challenges
> we need to solve to do this properly.

The right thing in my opinion is to achieve the goal with the minimal 
set of changes, in the most intuitive way.

Until now, there was no solution that could achieve the primary goal of 
this patch set (moving IMA and EVM to the LSM infrastructure) and, at 
the same time, achieve the additional goal you set of removing the 
'integrity' LSM.

If you see the diff, the changes compared to v5 that was already 
accepted by Mimi are very straightforward. If the assumption I made that 
in the end the 'ima' LSM could take over the role of the 'integrity' 
LSM, that for me is the preferable option.

Given that the patch set is not doing any design change, but merely 
moving calls and storing pointers elsewhere, that leaves us with the 
option of thinking better what to do next, including like you suggested 
to make IMA and EVM use disjoint metadata.

>> I started to think, does EVM really need integrity metadata or it can
>> work without?
>>
>> The fact is that CONFIG_IMA=n and CONFIG_EVM=y is allowed, so we have
>> the same problem now. What if we make IMA the one that manages
>> integrity metadata, so that we can remove the 'integrity' LSM?
> 
> I guess we should probably revisit the basic idea of if it even makes
> sense to enable EVM without IMA?  Should we update the Kconfig to
> require IMA when EVM is enabled?

That would be up to Mimi. Also this does not seem the main focus of the 
patch set.

>> Regarding the LSM order, I would take Casey's suggestion of introducing
>> LSM_ORDER_REALLY_LAST, for EVM.
> 
> Please understand that I really dislike that we have imposed ordering
> constraints at the LSM layer, but I do understand the necessity (the
> BPF LSM ordering upsets me the most).  I really don't want to see us
> make things worse by adding yet another ordering bucket, I would
> rather that we document it well and leave it alone ... basically treat
> it like the BPF LSM (grrrrrr).

Uhm, that would not be possible right away (the BPF LSM is mutable), 
remember that we defined LSM_ORDER_LAST so that an LSM can be always 
enable and placed as last (requested by Mimi)?

Thanks

Roberto


^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v5 23/23] integrity: Switch from rbtree to LSM-managed blob for integrity_iint_cache
  2023-11-29 18:46             ` Roberto Sassu
@ 2023-11-30  0:41               ` Casey Schaufler
  2023-11-30  8:30                 ` Petr Tesarik
  2023-11-30 11:12               ` Mimi Zohar
                                 ` (2 subsequent siblings)
  3 siblings, 1 reply; 96+ messages in thread
From: Casey Schaufler @ 2023-11-30  0:41 UTC (permalink / raw)
  To: Roberto Sassu, Paul Moore
  Cc: viro, brauner, chuck.lever, jlayton, neilb, kolga, Dai.Ngo, tom,
	jmorris, serge, zohar, dmitry.kasatkin, dhowells, jarkko,
	stephen.smalley.work, eparis, mic, linux-fsdevel, linux-kernel,
	linux-nfs, linux-security-module, linux-integrity, keyrings,
	selinux, Roberto Sassu, Casey Schaufler

On 11/29/2023 10:46 AM, Roberto Sassu wrote:
> On 11/29/2023 6:22 PM, Paul Moore wrote:
>> On Wed, Nov 29, 2023 at 7:28 AM Roberto Sassu
>> <roberto.sassu@huaweicloud.com> wrote:
>>>
>>> On Mon, 2023-11-20 at 16:06 -0500, Paul Moore wrote:
>>>> On Mon, Nov 20, 2023 at 3:16 AM Roberto Sassu
>>>> <roberto.sassu@huaweicloud.com> wrote:
>>>>> On Fri, 2023-11-17 at 15:57 -0500, Paul Moore wrote:
>>>>>> On Nov  7, 2023 Roberto Sassu <roberto.sassu@huaweicloud.com> wrote:
>>>>>>>
>>>>>>> Before the security field of kernel objects could be shared
>>>>>>> among LSMs with
>>>>>>> the LSM stacking feature, IMA and EVM had to rely on an
>>>>>>> alternative storage
>>>>>>> of inode metadata. The association between inode metadata and
>>>>>>> inode is
>>>>>>> maintained through an rbtree.
>>>>>>>
>>>>>>> Because of this alternative storage mechanism, there was no need
>>>>>>> to use
>>>>>>> disjoint inode metadata, so IMA and EVM today still share them.
>>>>>>>
>>>>>>> With the reservation mechanism offered by the LSM
>>>>>>> infrastructure, the
>>>>>>> rbtree is no longer necessary, as each LSM could reserve a space
>>>>>>> in the
>>>>>>> security blob for each inode. However, since IMA and EVM share the
>>>>>>> inode metadata, they cannot directly reserve the space for them.
>>>>>>>
>>>>>>> Instead, request from the 'integrity' LSM a space in the
>>>>>>> security blob for
>>>>>>> the pointer of inode metadata (integrity_iint_cache structure).
>>>>>>> The other
>>>>>>> reason for keeping the 'integrity' LSM is to preserve the
>>>>>>> original ordering
>>>>>>> of IMA and EVM functions as when they were hardcoded.
>>>>>>>
>>>>>>> Prefer reserving space for a pointer to allocating the
>>>>>>> integrity_iint_cache
>>>>>>> structure directly, as IMA would require it only for a subset of
>>>>>>> inodes.
>>>>>>> Always allocating it would cause a waste of memory.
>>>>>>>
>>>>>>> Introduce two primitives for getting and setting the pointer of
>>>>>>> integrity_iint_cache in the security blob, respectively
>>>>>>> integrity_inode_get_iint() and integrity_inode_set_iint(). This
>>>>>>> would make
>>>>>>> the code more understandable, as they directly replace rbtree
>>>>>>> operations.
>>>>>>>
>>>>>>> Locking is not needed, as access to inode metadata is not
>>>>>>> shared, it is per
>>>>>>> inode.
>>>>>>>
>>>>>>> Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
>>>>>>> Reviewed-by: Casey Schaufler <casey@schaufler-ca.com>
>>>>>>> Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
>>>>>>> ---
>>>>>>>   security/integrity/iint.c      | 71
>>>>>>> +++++-----------------------------
>>>>>>>   security/integrity/integrity.h | 20 +++++++++-
>>>>>>>   2 files changed, 29 insertions(+), 62 deletions(-)
>>>>>>>
>>>>>>> diff --git a/security/integrity/iint.c b/security/integrity/iint.c
>>>>>>> index 882fde2a2607..a5edd3c70784 100644
>>>>>>> --- a/security/integrity/iint.c
>>>>>>> +++ b/security/integrity/iint.c
>>>>>>> @@ -231,6 +175,10 @@ static int __init integrity_lsm_init(void)
>>>>>>>      return 0;
>>>>>>>   }
>>>>>>>
>>>>>>> +struct lsm_blob_sizes integrity_blob_sizes __ro_after_init = {
>>>>>>> +   .lbs_inode = sizeof(struct integrity_iint_cache *),
>>>>>>> +};
>>>>>>
>>>>>> I'll admit that I'm likely missing an important detail, but is there
>>>>>> a reason why you couldn't stash the integrity_iint_cache struct
>>>>>> directly in the inode's security blob instead of the pointer?  For
>>>>>> example:
>>>>>>
>>>>>>    struct lsm_blob_sizes ... = {
>>>>>>      .lbs_inode = sizeof(struct integrity_iint_cache),
>>>>>>    };
>>>>>>
>>>>>>    struct integrity_iint_cache *integrity_inode_get(inode)
>>>>>>    {
>>>>>>      if (unlikely(!inode->isecurity))
>>>>>>        return NULL;
>>>>>>      return inode->i_security + integrity_blob_sizes.lbs_inode;
>>>>>>    }
>>>>>
>>>>> It would increase memory occupation. Sometimes the IMA policy
>>>>> encompasses a small subset of the inodes. Allocating the full
>>>>> integrity_iint_cache would be a waste of memory, I guess?
>>>>
>>>> Perhaps, but if it allows us to remove another layer of dynamic memory
>>>> I would argue that it may be worth the cost.  It's also worth
>>>> considering the size of integrity_iint_cache, while it isn't small, it
>>>> isn't exactly huge either.
>>>>
>>>>> On the other hand... (did not think fully about that) if we embed the
>>>>> full structure in the security blob, we already have a mutex
>>>>> available
>>>>> to use, and we don't need to take the inode lock (?).
>>>>
>>>> That would be excellent, getting rid of a layer of locking would be
>>>> significant.
>>>>
>>>>> I'm fully convinced that we can improve the implementation
>>>>> significantly. I just was really hoping to go step by step and not
>>>>> accumulating improvements as dependency for moving IMA and EVM to the
>>>>> LSM infrastructure.
>>>>
>>>> I understand, and I agree that an iterative approach is a good idea, I
>>>> just want to make sure we keep things tidy from a user perspective,
>>>> i.e. not exposing the "integrity" LSM when it isn't required.
>>>
>>> Ok, I went back to it again.
>>>
>>> I think trying to separate integrity metadata is premature now, too
>>> many things at the same time.
>>
>> I'm not bothered by the size of the patchset, it is more important
>> that we do The Right Thing.  I would like to hear in more detail why
>> you don't think this will work, I'm not interested in hearing about
>> difficult it may be, I'm interested in hearing about what challenges
>> we need to solve to do this properly.
>
> The right thing in my opinion is to achieve the goal with the minimal
> set of changes, in the most intuitive way.
>
> Until now, there was no solution that could achieve the primary goal
> of this patch set (moving IMA and EVM to the LSM infrastructure) and,
> at the same time, achieve the additional goal you set of removing the
> 'integrity' LSM.
>
> If you see the diff, the changes compared to v5 that was already
> accepted by Mimi are very straightforward. If the assumption I made
> that in the end the 'ima' LSM could take over the role of the
> 'integrity' LSM, that for me is the preferable option.
>
> Given that the patch set is not doing any design change, but merely
> moving calls and storing pointers elsewhere, that leaves us with the
> option of thinking better what to do next, including like you
> suggested to make IMA and EVM use disjoint metadata.
>
>>> I started to think, does EVM really need integrity metadata or it can
>>> work without?
>>>
>>> The fact is that CONFIG_IMA=n and CONFIG_EVM=y is allowed, so we have
>>> the same problem now. What if we make IMA the one that manages
>>> integrity metadata, so that we can remove the 'integrity' LSM?
>>
>> I guess we should probably revisit the basic idea of if it even makes
>> sense to enable EVM without IMA?  Should we update the Kconfig to
>> require IMA when EVM is enabled?
>
> That would be up to Mimi. Also this does not seem the main focus of
> the patch set.
>
>>> Regarding the LSM order, I would take Casey's suggestion of introducing
>>> LSM_ORDER_REALLY_LAST, for EVM.
>>
>> Please understand that I really dislike that we have imposed ordering
>> constraints at the LSM layer, but I do understand the necessity (the
>> BPF LSM ordering upsets me the most).  I really don't want to see us
>> make things worse by adding yet another ordering bucket, I would
>> rather that we document it well and leave it alone ... basically treat
>> it like the BPF LSM (grrrrrr).
>
> Uhm, that would not be possible right away (the BPF LSM is mutable),
> remember that we defined LSM_ORDER_LAST so that an LSM can be always
> enable and placed as last (requested by Mimi)?

It would be nice if the solution directly addresses the problem.
EVM needs to be after the LSMs that use xattrs, not after all LSMs.
I suggested LSM_ORDER_REALLY_LAST in part to identify the notion as
unattractive.

You could add an element to lsm_info:

	u64 *follows;

which can be initialized to a list of LSM_ID values that this LSM
cannot precede. LSM_ID_CAPABILITY would be included by all other
LSMs, either implicitly or explicitly. EVM would include all the
LSMs that use xattrs in the list.

	static u64 evm_follow_list[] = {
		LSM_ID_CAPABILITY,
		LSM_ID_SELINUX,
		LSM_ID_SMACK,
		...
	};

		...
		.follows = evm_follow_list;
		...

>
> Thanks
>
> Roberto
>

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v5 23/23] integrity: Switch from rbtree to LSM-managed blob for integrity_iint_cache
  2023-11-30  0:41               ` Casey Schaufler
@ 2023-11-30  8:30                 ` Petr Tesarik
  2023-11-30 16:15                   ` Casey Schaufler
  0 siblings, 1 reply; 96+ messages in thread
From: Petr Tesarik @ 2023-11-30  8:30 UTC (permalink / raw)
  To: Casey Schaufler, Roberto Sassu, Paul Moore
  Cc: viro, brauner, chuck.lever, jlayton, neilb, kolga, Dai.Ngo, tom,
	jmorris, serge, zohar, dmitry.kasatkin, dhowells, jarkko,
	stephen.smalley.work, eparis, mic, linux-fsdevel, linux-kernel,
	linux-nfs, linux-security-module, linux-integrity, keyrings,
	selinux, Roberto Sassu

Hi all,

On 11/30/2023 1:41 AM, Casey Schaufler wrote:
> On 11/29/2023 10:46 AM, Roberto Sassu wrote:
>> On 11/29/2023 6:22 PM, Paul Moore wrote:
>>> On Wed, Nov 29, 2023 at 7:28 AM Roberto Sassu
>>> <roberto.sassu@huaweicloud.com> wrote:
>>>>
>>>> On Mon, 2023-11-20 at 16:06 -0500, Paul Moore wrote:
>>>>> On Mon, Nov 20, 2023 at 3:16 AM Roberto Sassu
>>>>> <roberto.sassu@huaweicloud.com> wrote:
>>>>>> On Fri, 2023-11-17 at 15:57 -0500, Paul Moore wrote:
>>>>>>> On Nov  7, 2023 Roberto Sassu <roberto.sassu@huaweicloud.com> wrote:
>>>>>>>>
>>>>>>>> Before the security field of kernel objects could be shared
>>>>>>>> among LSMs with
>>>>>>>> the LSM stacking feature, IMA and EVM had to rely on an
>>>>>>>> alternative storage
>>>>>>>> of inode metadata. The association between inode metadata and
>>>>>>>> inode is
>>>>>>>> maintained through an rbtree.
>>>>>>>>
>>>>>>>> Because of this alternative storage mechanism, there was no need
>>>>>>>> to use
>>>>>>>> disjoint inode metadata, so IMA and EVM today still share them.
>>>>>>>>
>>>>>>>> With the reservation mechanism offered by the LSM
>>>>>>>> infrastructure, the
>>>>>>>> rbtree is no longer necessary, as each LSM could reserve a space
>>>>>>>> in the
>>>>>>>> security blob for each inode. However, since IMA and EVM share the
>>>>>>>> inode metadata, they cannot directly reserve the space for them.
>>>>>>>>
>>>>>>>> Instead, request from the 'integrity' LSM a space in the
>>>>>>>> security blob for
>>>>>>>> the pointer of inode metadata (integrity_iint_cache structure).
>>>>>>>> The other
>>>>>>>> reason for keeping the 'integrity' LSM is to preserve the
>>>>>>>> original ordering
>>>>>>>> of IMA and EVM functions as when they were hardcoded.
>>>>>>>>
>>>>>>>> Prefer reserving space for a pointer to allocating the
>>>>>>>> integrity_iint_cache
>>>>>>>> structure directly, as IMA would require it only for a subset of
>>>>>>>> inodes.
>>>>>>>> Always allocating it would cause a waste of memory.
>>>>>>>>
>>>>>>>> Introduce two primitives for getting and setting the pointer of
>>>>>>>> integrity_iint_cache in the security blob, respectively
>>>>>>>> integrity_inode_get_iint() and integrity_inode_set_iint(). This
>>>>>>>> would make
>>>>>>>> the code more understandable, as they directly replace rbtree
>>>>>>>> operations.
>>>>>>>>
>>>>>>>> Locking is not needed, as access to inode metadata is not
>>>>>>>> shared, it is per
>>>>>>>> inode.
>>>>>>>>
>>>>>>>> Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
>>>>>>>> Reviewed-by: Casey Schaufler <casey@schaufler-ca.com>
>>>>>>>> Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
>>>>>>>> ---
>>>>>>>>   security/integrity/iint.c      | 71
>>>>>>>> +++++-----------------------------
>>>>>>>>   security/integrity/integrity.h | 20 +++++++++-
>>>>>>>>   2 files changed, 29 insertions(+), 62 deletions(-)
>>>>>>>>
>>>>>>>> diff --git a/security/integrity/iint.c b/security/integrity/iint.c
>>>>>>>> index 882fde2a2607..a5edd3c70784 100644
>>>>>>>> --- a/security/integrity/iint.c
>>>>>>>> +++ b/security/integrity/iint.c
>>>>>>>> @@ -231,6 +175,10 @@ static int __init integrity_lsm_init(void)
>>>>>>>>      return 0;
>>>>>>>>   }
>>>>>>>>
>>>>>>>> +struct lsm_blob_sizes integrity_blob_sizes __ro_after_init = {
>>>>>>>> +   .lbs_inode = sizeof(struct integrity_iint_cache *),
>>>>>>>> +};
>>>>>>>
>>>>>>> I'll admit that I'm likely missing an important detail, but is there
>>>>>>> a reason why you couldn't stash the integrity_iint_cache struct
>>>>>>> directly in the inode's security blob instead of the pointer?  For
>>>>>>> example:
>>>>>>>
>>>>>>>    struct lsm_blob_sizes ... = {
>>>>>>>      .lbs_inode = sizeof(struct integrity_iint_cache),
>>>>>>>    };
>>>>>>>
>>>>>>>    struct integrity_iint_cache *integrity_inode_get(inode)
>>>>>>>    {
>>>>>>>      if (unlikely(!inode->isecurity))
>>>>>>>        return NULL;
>>>>>>>      return inode->i_security + integrity_blob_sizes.lbs_inode;
>>>>>>>    }
>>>>>>
>>>>>> It would increase memory occupation. Sometimes the IMA policy
>>>>>> encompasses a small subset of the inodes. Allocating the full
>>>>>> integrity_iint_cache would be a waste of memory, I guess?
>>>>>
>>>>> Perhaps, but if it allows us to remove another layer of dynamic memory
>>>>> I would argue that it may be worth the cost.  It's also worth
>>>>> considering the size of integrity_iint_cache, while it isn't small, it
>>>>> isn't exactly huge either.
>>>>>
>>>>>> On the other hand... (did not think fully about that) if we embed the
>>>>>> full structure in the security blob, we already have a mutex
>>>>>> available
>>>>>> to use, and we don't need to take the inode lock (?).
>>>>>
>>>>> That would be excellent, getting rid of a layer of locking would be
>>>>> significant.
>>>>>
>>>>>> I'm fully convinced that we can improve the implementation
>>>>>> significantly. I just was really hoping to go step by step and not
>>>>>> accumulating improvements as dependency for moving IMA and EVM to the
>>>>>> LSM infrastructure.
>>>>>
>>>>> I understand, and I agree that an iterative approach is a good idea, I
>>>>> just want to make sure we keep things tidy from a user perspective,
>>>>> i.e. not exposing the "integrity" LSM when it isn't required.
>>>>
>>>> Ok, I went back to it again.
>>>>
>>>> I think trying to separate integrity metadata is premature now, too
>>>> many things at the same time.
>>>
>>> I'm not bothered by the size of the patchset, it is more important
>>> that we do The Right Thing.  I would like to hear in more detail why
>>> you don't think this will work, I'm not interested in hearing about
>>> difficult it may be, I'm interested in hearing about what challenges
>>> we need to solve to do this properly.
>>
>> The right thing in my opinion is to achieve the goal with the minimal
>> set of changes, in the most intuitive way.
>>
>> Until now, there was no solution that could achieve the primary goal
>> of this patch set (moving IMA and EVM to the LSM infrastructure) and,
>> at the same time, achieve the additional goal you set of removing the
>> 'integrity' LSM.
>>
>> If you see the diff, the changes compared to v5 that was already
>> accepted by Mimi are very straightforward. If the assumption I made
>> that in the end the 'ima' LSM could take over the role of the
>> 'integrity' LSM, that for me is the preferable option.
>>
>> Given that the patch set is not doing any design change, but merely
>> moving calls and storing pointers elsewhere, that leaves us with the
>> option of thinking better what to do next, including like you
>> suggested to make IMA and EVM use disjoint metadata.
>>
>>>> I started to think, does EVM really need integrity metadata or it can
>>>> work without?
>>>>
>>>> The fact is that CONFIG_IMA=n and CONFIG_EVM=y is allowed, so we have
>>>> the same problem now. What if we make IMA the one that manages
>>>> integrity metadata, so that we can remove the 'integrity' LSM?
>>>
>>> I guess we should probably revisit the basic idea of if it even makes
>>> sense to enable EVM without IMA?  Should we update the Kconfig to
>>> require IMA when EVM is enabled?
>>
>> That would be up to Mimi. Also this does not seem the main focus of
>> the patch set.
>>
>>>> Regarding the LSM order, I would take Casey's suggestion of introducing
>>>> LSM_ORDER_REALLY_LAST, for EVM.
>>>
>>> Please understand that I really dislike that we have imposed ordering
>>> constraints at the LSM layer, but I do understand the necessity (the
>>> BPF LSM ordering upsets me the most).  I really don't want to see us
>>> make things worse by adding yet another ordering bucket, I would
>>> rather that we document it well and leave it alone ... basically treat
>>> it like the BPF LSM (grrrrrr).
>>
>> Uhm, that would not be possible right away (the BPF LSM is mutable),
>> remember that we defined LSM_ORDER_LAST so that an LSM can be always
>> enable and placed as last (requested by Mimi)?
> 
> It would be nice if the solution directly addresses the problem.
> EVM needs to be after the LSMs that use xattrs, not after all LSMs.
> I suggested LSM_ORDER_REALLY_LAST in part to identify the notion as
> unattractive.

Excuse me to chime in, but do we really need the ordering in code? FWIW
the linker guarantees that objects appear in the order they are seen
during the link (unless --sort-section overrides that default, but this
option is not used in the kernel). Since *.a archive files are used in
kbuild, I have also verified that their use does not break the
assumption; they are always created from scratch.

In short, to enforce an ordering, you can simply list the corresponding
object files in that order in the Makefile. Of course, add a big fat
warning comment, so people understand the order is not arbitrary.

Just my two eurocents,
Petr T


^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v5 23/23] integrity: Switch from rbtree to LSM-managed blob for integrity_iint_cache
  2023-11-29 18:46             ` Roberto Sassu
  2023-11-30  0:41               ` Casey Schaufler
@ 2023-11-30 11:12               ` Mimi Zohar
  2023-11-30 16:59                 ` Paul Moore
  2023-11-30 16:34               ` Paul Moore
  2023-12-01  1:05               ` Dr. Greg
  3 siblings, 1 reply; 96+ messages in thread
From: Mimi Zohar @ 2023-11-30 11:12 UTC (permalink / raw)
  To: Roberto Sassu, Paul Moore
  Cc: viro, brauner, chuck.lever, jlayton, neilb, kolga, Dai.Ngo, tom,
	jmorris, serge, dmitry.kasatkin, dhowells, jarkko,
	stephen.smalley.work, eparis, casey, mic, linux-fsdevel,
	linux-kernel, linux-nfs, linux-security-module, linux-integrity,
	keyrings, selinux, Roberto Sassu

On Wed, 2023-11-29 at 19:46 +0100, Roberto Sassu wrote:
> On 11/29/2023 6:22 PM, Paul Moore wrote:
> > On Wed, Nov 29, 2023 at 7:28 AM Roberto Sassu
> > <roberto.sassu@huaweicloud.com> wrote:
> >>
> >> On Mon, 2023-11-20 at 16:06 -0500, Paul Moore wrote:
> >>> On Mon, Nov 20, 2023 at 3:16 AM Roberto Sassu
> >>> <roberto.sassu@huaweicloud.com> wrote:
> >>>> On Fri, 2023-11-17 at 15:57 -0500, Paul Moore wrote:
> >>>>> On Nov  7, 2023 Roberto Sassu <roberto.sassu@huaweicloud.com> wrote:
> >>>>>>
> >>>>>> Before the security field of kernel objects could be shared among LSMs with
> >>>>>> the LSM stacking feature, IMA and EVM had to rely on an alternative storage
> >>>>>> of inode metadata. The association between inode metadata and inode is
> >>>>>> maintained through an rbtree.
> >>>>>>
> >>>>>> Because of this alternative storage mechanism, there was no need to use
> >>>>>> disjoint inode metadata, so IMA and EVM today still share them.
> >>>>>>
> >>>>>> With the reservation mechanism offered by the LSM infrastructure, the
> >>>>>> rbtree is no longer necessary, as each LSM could reserve a space in the
> >>>>>> security blob for each inode. However, since IMA and EVM share the
> >>>>>> inode metadata, they cannot directly reserve the space for them.
> >>>>>>
> >>>>>> Instead, request from the 'integrity' LSM a space in the security blob for
> >>>>>> the pointer of inode metadata (integrity_iint_cache structure). The other
> >>>>>> reason for keeping the 'integrity' LSM is to preserve the original ordering
> >>>>>> of IMA and EVM functions as when they were hardcoded.
> >>>>>>
> >>>>>> Prefer reserving space for a pointer to allocating the integrity_iint_cache
> >>>>>> structure directly, as IMA would require it only for a subset of inodes.
> >>>>>> Always allocating it would cause a waste of memory.
> >>>>>>
> >>>>>> Introduce two primitives for getting and setting the pointer of
> >>>>>> integrity_iint_cache in the security blob, respectively
> >>>>>> integrity_inode_get_iint() and integrity_inode_set_iint(). This would make
> >>>>>> the code more understandable, as they directly replace rbtree operations.
> >>>>>>
> >>>>>> Locking is not needed, as access to inode metadata is not shared, it is per
> >>>>>> inode.
> >>>>>>
> >>>>>> Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
> >>>>>> Reviewed-by: Casey Schaufler <casey@schaufler-ca.com>
> >>>>>> Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
> >>>>>> ---
> >>>>>>   security/integrity/iint.c      | 71 +++++-----------------------------
> >>>>>>   security/integrity/integrity.h | 20 +++++++++-
> >>>>>>   2 files changed, 29 insertions(+), 62 deletions(-)
> >>>>>>
> >>>>>> diff --git a/security/integrity/iint.c b/security/integrity/iint.c
> >>>>>> index 882fde2a2607..a5edd3c70784 100644
> >>>>>> --- a/security/integrity/iint.c
> >>>>>> +++ b/security/integrity/iint.c
> >>>>>> @@ -231,6 +175,10 @@ static int __init integrity_lsm_init(void)
> >>>>>>      return 0;
> >>>>>>   }
> >>>>>>
> >>>>>> +struct lsm_blob_sizes integrity_blob_sizes __ro_after_init = {
> >>>>>> +   .lbs_inode = sizeof(struct integrity_iint_cache *),
> >>>>>> +};
> >>>>>
> >>>>> I'll admit that I'm likely missing an important detail, but is there
> >>>>> a reason why you couldn't stash the integrity_iint_cache struct
> >>>>> directly in the inode's security blob instead of the pointer?  For
> >>>>> example:
> >>>>>
> >>>>>    struct lsm_blob_sizes ... = {
> >>>>>      .lbs_inode = sizeof(struct integrity_iint_cache),
> >>>>>    };
> >>>>>
> >>>>>    struct integrity_iint_cache *integrity_inode_get(inode)
> >>>>>    {
> >>>>>      if (unlikely(!inode->isecurity))
> >>>>>        return NULL;
> >>>>>      return inode->i_security + integrity_blob_sizes.lbs_inode;
> >>>>>    }
> >>>>
> >>>> It would increase memory occupation. Sometimes the IMA policy
> >>>> encompasses a small subset of the inodes. Allocating the full
> >>>> integrity_iint_cache would be a waste of memory, I guess?
> >>>
> >>> Perhaps, but if it allows us to remove another layer of dynamic memory
> >>> I would argue that it may be worth the cost.  It's also worth
> >>> considering the size of integrity_iint_cache, while it isn't small, it
> >>> isn't exactly huge either.
> >>>
> >>>> On the other hand... (did not think fully about that) if we embed the
> >>>> full structure in the security blob, we already have a mutex available
> >>>> to use, and we don't need to take the inode lock (?).
> >>>
> >>> That would be excellent, getting rid of a layer of locking would be significant.
> >>>
> >>>> I'm fully convinced that we can improve the implementation
> >>>> significantly. I just was really hoping to go step by step and not
> >>>> accumulating improvements as dependency for moving IMA and EVM to the
> >>>> LSM infrastructure.
> >>>
> >>> I understand, and I agree that an iterative approach is a good idea, I
> >>> just want to make sure we keep things tidy from a user perspective,
> >>> i.e. not exposing the "integrity" LSM when it isn't required.
> >>
> >> Ok, I went back to it again.
> >>
> >> I think trying to separate integrity metadata is premature now, too
> >> many things at the same time.
> > 
> > I'm not bothered by the size of the patchset, it is more important
> > that we do The Right Thing.  I would like to hear in more detail why
> > you don't think this will work, I'm not interested in hearing about
> > difficult it may be, I'm interested in hearing about what challenges
> > we need to solve to do this properly.
> 
> The right thing in my opinion is to achieve the goal with the minimal 
> set of changes, in the most intuitive way.
> 
> Until now, there was no solution that could achieve the primary goal of 
> this patch set (moving IMA and EVM to the LSM infrastructure) and, at 
> the same time, achieve the additional goal you set of removing the 
> 'integrity' LSM.
> 
> If you see the diff, the changes compared to v5 that was already 
> accepted by Mimi are very straightforward. If the assumption I made that 
> in the end the 'ima' LSM could take over the role of the 'integrity' 
> LSM, that for me is the preferable option.
> 
> Given that the patch set is not doing any design change, but merely 
> moving calls and storing pointers elsewhere, that leaves us with the 
> option of thinking better what to do next, including like you suggested 
> to make IMA and EVM use disjoint metadata.
> 
> >> I started to think, does EVM really need integrity metadata or it can
> >> work without?
> >>
> >> The fact is that CONFIG_IMA=n and CONFIG_EVM=y is allowed, so we have
> >> the same problem now. What if we make IMA the one that manages
> >> integrity metadata, so that we can remove the 'integrity' LSM?
> > 
> > I guess we should probably revisit the basic idea of if it even makes
> > sense to enable EVM without IMA?  Should we update the Kconfig to
> > require IMA when EVM is enabled?
> 
> That would be up to Mimi. Also this does not seem the main focus of the 
> patch set.

First you suggested lumping IMA and EVM together, dropping EVM
entirely.  Now you're suggesting making EVM dependent on IMA.  Please
stop.  EVM and IMA should remain independent of each other.   The first
user of EVM is IMA.

> >> Regarding the LSM order, I would take Casey's suggestion of introducing
> >> LSM_ORDER_REALLY_LAST, for EVM.
> > 
> > Please understand that I really dislike that we have imposed ordering
> > constraints at the LSM layer, but I do understand the necessity (the
> > BPF LSM ordering upsets me the most).  I really don't want to see us
> > make things worse by adding yet another ordering bucket, I would
> > rather that we document it well and leave it alone ... basically treat
> > it like the BPF LSM (grrrrrr).
> 
> Uhm, that would not be possible right away (the BPF LSM is mutable), 
> remember that we defined LSM_ORDER_LAST so that an LSM can be always 
> enable and placed as last (requested by Mimi)?

Making EVM a full fledged LSM was contingent on two things - EVM always
being enabled if configured and being the last LSM.  Using capability
as a precedent for ordering requirement, Mickaël suggested defining
LSM_ORDER_LAST, which you agreed to.   It sounds like you're
backtracking on an agreement.

Mimi


^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v5 23/23] integrity: Switch from rbtree to LSM-managed blob for integrity_iint_cache
  2023-11-30  8:30                 ` Petr Tesarik
@ 2023-11-30 16:15                   ` Casey Schaufler
  2023-11-30 21:34                     ` Roberto Sassu
  0 siblings, 1 reply; 96+ messages in thread
From: Casey Schaufler @ 2023-11-30 16:15 UTC (permalink / raw)
  To: Petr Tesarik, Roberto Sassu, Paul Moore
  Cc: viro, brauner, chuck.lever, jlayton, neilb, kolga, Dai.Ngo, tom,
	jmorris, serge, zohar, dmitry.kasatkin, dhowells, jarkko,
	stephen.smalley.work, eparis, mic, linux-fsdevel, linux-kernel,
	linux-nfs, linux-security-module, linux-integrity, keyrings,
	selinux, Roberto Sassu, Casey Schaufler

On 11/30/2023 12:30 AM, Petr Tesarik wrote:
> Hi all,
>
> On 11/30/2023 1:41 AM, Casey Schaufler wrote:
>> ...
>> It would be nice if the solution directly addresses the problem.
>> EVM needs to be after the LSMs that use xattrs, not after all LSMs.
>> I suggested LSM_ORDER_REALLY_LAST in part to identify the notion as
>> unattractive.
> Excuse me to chime in, but do we really need the ordering in code?

tl;dr - Yes.

>  FWIW
> the linker guarantees that objects appear in the order they are seen
> during the link (unless --sort-section overrides that default, but this
> option is not used in the kernel). Since *.a archive files are used in
> kbuild, I have also verified that their use does not break the
> assumption; they are always created from scratch.
>
> In short, to enforce an ordering, you can simply list the corresponding
> object files in that order in the Makefile. Of course, add a big fat
> warning comment, so people understand the order is not arbitrary.

Not everyone builds custom kernels.

>
> Just my two eurocents,
> Petr T
>
>

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v5 23/23] integrity: Switch from rbtree to LSM-managed blob for integrity_iint_cache
  2023-11-29 18:46             ` Roberto Sassu
  2023-11-30  0:41               ` Casey Schaufler
  2023-11-30 11:12               ` Mimi Zohar
@ 2023-11-30 16:34               ` Paul Moore
  2023-11-30 21:56                 ` Roberto Sassu
  2023-12-04 13:26                 ` Roberto Sassu
  2023-12-01  1:05               ` Dr. Greg
  3 siblings, 2 replies; 96+ messages in thread
From: Paul Moore @ 2023-11-30 16:34 UTC (permalink / raw)
  To: Roberto Sassu
  Cc: viro, brauner, chuck.lever, jlayton, neilb, kolga, Dai.Ngo, tom,
	jmorris, serge, zohar, dmitry.kasatkin, dhowells, jarkko,
	stephen.smalley.work, eparis, casey, mic, linux-fsdevel,
	linux-kernel, linux-nfs, linux-security-module, linux-integrity,
	keyrings, selinux, Roberto Sassu

On Wed, Nov 29, 2023 at 1:47 PM Roberto Sassu
<roberto.sassu@huaweicloud.com> wrote:
> On 11/29/2023 6:22 PM, Paul Moore wrote:
> > On Wed, Nov 29, 2023 at 7:28 AM Roberto Sassu
> > <roberto.sassu@huaweicloud.com> wrote:
> >>
> >> On Mon, 2023-11-20 at 16:06 -0500, Paul Moore wrote:
> >>> On Mon, Nov 20, 2023 at 3:16 AM Roberto Sassu
> >>> <roberto.sassu@huaweicloud.com> wrote:
> >>>> On Fri, 2023-11-17 at 15:57 -0500, Paul Moore wrote:
> >>>>> On Nov  7, 2023 Roberto Sassu <roberto.sassu@huaweicloud.com> wrote:
> >>>>>>
> >>>>>> Before the security field of kernel objects could be shared among LSMs with
> >>>>>> the LSM stacking feature, IMA and EVM had to rely on an alternative storage
> >>>>>> of inode metadata. The association between inode metadata and inode is
> >>>>>> maintained through an rbtree.
> >>>>>>
> >>>>>> Because of this alternative storage mechanism, there was no need to use
> >>>>>> disjoint inode metadata, so IMA and EVM today still share them.
> >>>>>>
> >>>>>> With the reservation mechanism offered by the LSM infrastructure, the
> >>>>>> rbtree is no longer necessary, as each LSM could reserve a space in the
> >>>>>> security blob for each inode. However, since IMA and EVM share the
> >>>>>> inode metadata, they cannot directly reserve the space for them.
> >>>>>>
> >>>>>> Instead, request from the 'integrity' LSM a space in the security blob for
> >>>>>> the pointer of inode metadata (integrity_iint_cache structure). The other
> >>>>>> reason for keeping the 'integrity' LSM is to preserve the original ordering
> >>>>>> of IMA and EVM functions as when they were hardcoded.
> >>>>>>
> >>>>>> Prefer reserving space for a pointer to allocating the integrity_iint_cache
> >>>>>> structure directly, as IMA would require it only for a subset of inodes.
> >>>>>> Always allocating it would cause a waste of memory.
> >>>>>>
> >>>>>> Introduce two primitives for getting and setting the pointer of
> >>>>>> integrity_iint_cache in the security blob, respectively
> >>>>>> integrity_inode_get_iint() and integrity_inode_set_iint(). This would make
> >>>>>> the code more understandable, as they directly replace rbtree operations.
> >>>>>>
> >>>>>> Locking is not needed, as access to inode metadata is not shared, it is per
> >>>>>> inode.
> >>>>>>
> >>>>>> Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
> >>>>>> Reviewed-by: Casey Schaufler <casey@schaufler-ca.com>
> >>>>>> Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
> >>>>>> ---
> >>>>>>   security/integrity/iint.c      | 71 +++++-----------------------------
> >>>>>>   security/integrity/integrity.h | 20 +++++++++-
> >>>>>>   2 files changed, 29 insertions(+), 62 deletions(-)
> >>>>>>
> >>>>>> diff --git a/security/integrity/iint.c b/security/integrity/iint.c
> >>>>>> index 882fde2a2607..a5edd3c70784 100644
> >>>>>> --- a/security/integrity/iint.c
> >>>>>> +++ b/security/integrity/iint.c
> >>>>>> @@ -231,6 +175,10 @@ static int __init integrity_lsm_init(void)
> >>>>>>      return 0;
> >>>>>>   }
> >>>>>>
> >>>>>> +struct lsm_blob_sizes integrity_blob_sizes __ro_after_init = {
> >>>>>> +   .lbs_inode = sizeof(struct integrity_iint_cache *),
> >>>>>> +};
> >>>>>
> >>>>> I'll admit that I'm likely missing an important detail, but is there
> >>>>> a reason why you couldn't stash the integrity_iint_cache struct
> >>>>> directly in the inode's security blob instead of the pointer?  For
> >>>>> example:
> >>>>>
> >>>>>    struct lsm_blob_sizes ... = {
> >>>>>      .lbs_inode = sizeof(struct integrity_iint_cache),
> >>>>>    };
> >>>>>
> >>>>>    struct integrity_iint_cache *integrity_inode_get(inode)
> >>>>>    {
> >>>>>      if (unlikely(!inode->isecurity))
> >>>>>        return NULL;
> >>>>>      return inode->i_security + integrity_blob_sizes.lbs_inode;
> >>>>>    }
> >>>>
> >>>> It would increase memory occupation. Sometimes the IMA policy
> >>>> encompasses a small subset of the inodes. Allocating the full
> >>>> integrity_iint_cache would be a waste of memory, I guess?
> >>>
> >>> Perhaps, but if it allows us to remove another layer of dynamic memory
> >>> I would argue that it may be worth the cost.  It's also worth
> >>> considering the size of integrity_iint_cache, while it isn't small, it
> >>> isn't exactly huge either.
> >>>
> >>>> On the other hand... (did not think fully about that) if we embed the
> >>>> full structure in the security blob, we already have a mutex available
> >>>> to use, and we don't need to take the inode lock (?).
> >>>
> >>> That would be excellent, getting rid of a layer of locking would be significant.
> >>>
> >>>> I'm fully convinced that we can improve the implementation
> >>>> significantly. I just was really hoping to go step by step and not
> >>>> accumulating improvements as dependency for moving IMA and EVM to the
> >>>> LSM infrastructure.
> >>>
> >>> I understand, and I agree that an iterative approach is a good idea, I
> >>> just want to make sure we keep things tidy from a user perspective,
> >>> i.e. not exposing the "integrity" LSM when it isn't required.
> >>
> >> Ok, I went back to it again.
> >>
> >> I think trying to separate integrity metadata is premature now, too
> >> many things at the same time.
> >
> > I'm not bothered by the size of the patchset, it is more important
> > that we do The Right Thing.  I would like to hear in more detail why
> > you don't think this will work, I'm not interested in hearing about
> > difficult it may be, I'm interested in hearing about what challenges
> > we need to solve to do this properly.
>
> The right thing in my opinion is to achieve the goal with the minimal
> set of changes, in the most intuitive way.

Once again, I want to stress that I don't care about the size of the
change, the number of patches in a patchset, etc.  While it's always
nice to be able to minimize the number of changes in a patch/patchset,
that is secondary to making sure we are doing the right thing over the
long term.  This is especially important when we are talking about
things that are user visible.

> Until now, there was no solution that could achieve the primary goal of
> this patch set (moving IMA and EVM to the LSM infrastructure) and, at
> the same time, achieve the additional goal you set of removing the
> 'integrity' LSM.

We need to stop thinking about the "integrity" code as a LSM, it isn't
a LSM.  It's a vestigial implementation detail that was necessary back
when there could only be one LSM active at a time and there was a
desire to have IMA/EVM active in conjunction with one of the LSMs,
i.e. Smack, SELinux, etc.

IMA and EVM are (or will be) LSMs, "integrity" is not.  I recognize
that eliminating the need for the "integrity" code is a relatively new
addition to this effort, but that is only because I didn't properly
understand the relationship between IMA, EVM, and the "integrity" code
until recently.  The elimination of the shared "integrity" code is
consistent with promoting IMA and EVM as full LSMs, if there is core
functionality that cannot be split up into the IMA and/or EVM LSMs
then we need to look at how to support that without exposing that
implementation detail/hack to userspace.  Maybe that means direct
calls between IMA and EVM, maybe that means preserving some of the
common integrity code hidden from userspace, maybe that means adding
functionality to the LSM layer, maybe that means something else?
Let's think on this to come up with something that we can all accept
as a long term solution instead of just doing the quick and easy
option.

> If you see the diff, the changes compared to v5 that was already
> accepted by Mimi are very straightforward. If the assumption I made that
> in the end the 'ima' LSM could take over the role of the 'integrity'
> LSM, that for me is the preferable option.

I looked at it quickly, but my workflow isn't well suited for patches
as attachments; inline patches (the kernel standard) is preferable.

> Given that the patch set is not doing any design change, but merely
> moving calls and storing pointers elsewhere, that leaves us with the
> option of thinking better what to do next, including like you suggested
> to make IMA and EVM use disjoint metadata.
>
> >> I started to think, does EVM really need integrity metadata or it can
> >> work without?
> >>
> >> The fact is that CONFIG_IMA=n and CONFIG_EVM=y is allowed, so we have
> >> the same problem now. What if we make IMA the one that manages
> >> integrity metadata, so that we can remove the 'integrity' LSM?
> >
> > I guess we should probably revisit the basic idea of if it even makes
> > sense to enable EVM without IMA?  Should we update the Kconfig to
> > require IMA when EVM is enabled?
>
> That would be up to Mimi. Also this does not seem the main focus of the
> patch set.

Yes, it is not part of the original main focus, but it is definitely
relevant to the discussion we are having now.  Once again, the most
important thing to me is that we do The Right Thing for the long term
maintenance of the code base; if that means scope creep, I've got no
problem with that.

> >> Regarding the LSM order, I would take Casey's suggestion of introducing
> >> LSM_ORDER_REALLY_LAST, for EVM.
> >
> > Please understand that I really dislike that we have imposed ordering
> > constraints at the LSM layer, but I do understand the necessity (the
> > BPF LSM ordering upsets me the most).  I really don't want to see us
> > make things worse by adding yet another ordering bucket, I would
> > rather that we document it well and leave it alone ... basically treat
> > it like the BPF LSM (grrrrrr).
>
> Uhm, that would not be possible right away (the BPF LSM is mutable),
> remember that we defined LSM_ORDER_LAST so that an LSM can be always
> enable and placed as last (requested by Mimi)?

To be clear, I can both dislike the bpf-always-last and LSM_ORDER_LAST
concepts while accepting them as necessary evils.  I'm willing to
tolerate LSM_ORDER_LAST, but I'm not currently willing to tolerate
LSM_ORDER_REALLY_LAST; that is one step too far right now.  I brought
up the BPF LSM simply as an example of ordering that is not enforced
by code, but rather by documentation and convention.

-- 
paul-moore.com

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v5 23/23] integrity: Switch from rbtree to LSM-managed blob for integrity_iint_cache
  2023-11-30 11:12               ` Mimi Zohar
@ 2023-11-30 16:59                 ` Paul Moore
  2023-11-30 17:00                   ` Paul Moore
  0 siblings, 1 reply; 96+ messages in thread
From: Paul Moore @ 2023-11-30 16:59 UTC (permalink / raw)
  To: Mimi Zohar
  Cc: Roberto Sassu, viro, brauner, chuck.lever, jlayton, neilb, kolga,
	Dai.Ngo, tom, jmorris, serge, dmitry.kasatkin, dhowells, jarkko,
	stephen.smalley.work, eparis, casey, mic, linux-fsdevel,
	linux-kernel, linux-nfs, linux-security-module, linux-integrity,
	keyrings, selinux, Roberto Sassu

On Thu, Nov 30, 2023 at 6:13 AM Mimi Zohar <zohar@linux.ibm.com> wrote:
> On Wed, 2023-11-29 at 19:46 +0100, Roberto Sassu wrote:
> > On 11/29/2023 6:22 PM, Paul Moore wrote:
> > > On Wed, Nov 29, 2023 at 7:28 AM Roberto Sassu wrote:
> > >> On Mon, 2023-11-20 at 16:06 -0500, Paul Moore wrote:
> > >>> On Mon, Nov 20, 2023 at 3:16 AM Roberto Sassu wrote:
> > >>>> On Fri, 2023-11-17 at 15:57 -0500, Paul Moore wrote:
> > >>>>> On Nov  7, 2023 Roberto Sassu <roberto.sassu@huaweicloud.com> wrote:

...

> First you suggested lumping IMA and EVM together, dropping EVM
> entirely.  Now you're suggesting making EVM dependent on IMA.  Please
> stop.

Welcome to design discussions and brainstorming where changing
opinions and unexpected suggestions are part of the process.  When we
are faced with difficult problems I want everyone to think creatively
and not be afraid to adjust their thinking based on their changing
understanding and the ongoing discussion.

Asking people to stop thinking outside the status quo is not a good
way to solve challenging problems.

> EVM and IMA should remain independent of each other.

A few posts back that was the goal, then Roberto mentioned EVM
breakage when IMA was disabled so I simply asked if it was worth
"revisit the basic idea of if it even makes sense to enable EVM
without IMA?".  A bad answer to that question is what you provided
above (and to be fair, we are all guilty of that at times), a good
answer is to explain why IMA and EVM need to remain independent with
bonus points awarded for realistic use cases that support the
assertion of independence.

> > >> Regarding the LSM order, I would take Casey's suggestion of introducing
> > >> LSM_ORDER_REALLY_LAST, for EVM.
> > >
> > > Please understand that I really dislike that we have imposed ordering
> > > constraints at the LSM layer, but I do understand the necessity (the
> > > BPF LSM ordering upsets me the most).  I really don't want to see us
> > > make things worse by adding yet another ordering bucket, I would
> > > rather that we document it well and leave it alone ... basically treat
> > > it like the BPF LSM (grrrrrr).
> >
> > Uhm, that would not be possible right away (the BPF LSM is mutable),
> > remember that we defined LSM_ORDER_LAST so that an LSM can be always
> > enable and placed as last (requested by Mimi)?
>
> Making EVM a full fledged LSM was contingent on two things - EVM always
> being enabled if configured and being the last LSM.  Using capability
> as a precedent for ordering requirement, Mickaël suggested defining
> LSM_ORDER_LAST, which you agreed to.   It sounds like you're
> backtracking on an agreement.

I not only agreed to LSM_ORDER_LAST, I merged the code and it is
currently in Linus' tree.  See my last reply to Roberto; I see no
reason to change that.  I never would have merged that code or sent it
to Linus if I didn't feel it was necessary.

I'm guessing that you misread my reply above (perhaps you missed the
"another" in "... I really don't want to see us make things worse by
adding yet another ordering bucket ..."), but regardless of that, I
want to deal with your "backtracking" comment.  Similar to my comments
above about brainstorming, I don't want people to feel that they can't
change their mind about something.  Call it backtracking if you want
(although that has a negative connotation for many), but I want people
to feel free to adjust their opinions as they learn more about
something or as the conversation evolves.  I believe this is the
primary (only?) way for us to reach consensus on challenging problems.

If you are uncomfortable with new, different, and changing ideas this
may not be the right place for you.  I might suggest a career in
politics as an alternative.

-- 
paul-moore.com

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v5 23/23] integrity: Switch from rbtree to LSM-managed blob for integrity_iint_cache
  2023-11-30 16:59                 ` Paul Moore
@ 2023-11-30 17:00                   ` Paul Moore
  0 siblings, 0 replies; 96+ messages in thread
From: Paul Moore @ 2023-11-30 17:00 UTC (permalink / raw)
  To: Mimi Zohar, Roberto Sassu
  Cc: viro, brauner, chuck.lever, jlayton, neilb, kolga, Dai.Ngo, tom,
	jmorris, serge, dmitry.kasatkin, dhowells, jarkko,
	stephen.smalley.work, eparis, casey, mic, linux-fsdevel,
	linux-kernel, linux-nfs, linux-security-module, linux-integrity,
	keyrings, selinux, Roberto Sassu

A quick note that I'm going to have some networking disruptions at
home and email responses may be delayed for the next few days.

-- 
paul-moore.com

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v5 23/23] integrity: Switch from rbtree to LSM-managed blob for integrity_iint_cache
  2023-11-30 16:15                   ` Casey Schaufler
@ 2023-11-30 21:34                     ` Roberto Sassu
  2023-11-30 23:31                       ` Casey Schaufler
  0 siblings, 1 reply; 96+ messages in thread
From: Roberto Sassu @ 2023-11-30 21:34 UTC (permalink / raw)
  To: Casey Schaufler, Petr Tesarik, Paul Moore
  Cc: viro, brauner, chuck.lever, jlayton, neilb, kolga, Dai.Ngo, tom,
	jmorris, serge, zohar, dmitry.kasatkin, dhowells, jarkko,
	stephen.smalley.work, eparis, mic, linux-fsdevel, linux-kernel,
	linux-nfs, linux-security-module, linux-integrity, keyrings,
	selinux, Roberto Sassu

On 11/30/2023 5:15 PM, Casey Schaufler wrote:
> On 11/30/2023 12:30 AM, Petr Tesarik wrote:
>> Hi all,
>>
>> On 11/30/2023 1:41 AM, Casey Schaufler wrote:
>>> ...
>>> It would be nice if the solution directly addresses the problem.
>>> EVM needs to be after the LSMs that use xattrs, not after all LSMs.
>>> I suggested LSM_ORDER_REALLY_LAST in part to identify the notion as
>>> unattractive.
>> Excuse me to chime in, but do we really need the ordering in code?
> 
> tl;dr - Yes.
> 
>>   FWIW
>> the linker guarantees that objects appear in the order they are seen
>> during the link (unless --sort-section overrides that default, but this
>> option is not used in the kernel). Since *.a archive files are used in
>> kbuild, I have also verified that their use does not break the
>> assumption; they are always created from scratch.
>>
>> In short, to enforce an ordering, you can simply list the corresponding
>> object files in that order in the Makefile. Of course, add a big fat
>> warning comment, so people understand the order is not arbitrary.
> 
> Not everyone builds custom kernels.

Sorry, I didn't understand your comment. Everyone builds the kernel, 
also Linux distros. What Petr was suggesting was that it does not matter 
how you build the kernel, the linker will place the LSMs in the order 
they appear in the Makefile. And for this particular case, we have:

obj-$(CONFIG_IMA)                       += ima/
obj-$(CONFIG_EVM)                       += evm/

In the past, I also verified that swapping these two resulted in the 
swapped order of LSMs. Petr confirmed that it would always happen.

Thanks

Roberto


^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v5 23/23] integrity: Switch from rbtree to LSM-managed blob for integrity_iint_cache
  2023-11-30 16:34               ` Paul Moore
@ 2023-11-30 21:56                 ` Roberto Sassu
  2023-12-04 13:26                 ` Roberto Sassu
  1 sibling, 0 replies; 96+ messages in thread
From: Roberto Sassu @ 2023-11-30 21:56 UTC (permalink / raw)
  To: Paul Moore
  Cc: viro, brauner, chuck.lever, jlayton, neilb, kolga, Dai.Ngo, tom,
	jmorris, serge, zohar, dmitry.kasatkin, dhowells, jarkko,
	stephen.smalley.work, eparis, casey, mic, linux-fsdevel,
	linux-kernel, linux-nfs, linux-security-module, linux-integrity,
	keyrings, selinux, Roberto Sassu

On 11/30/2023 5:34 PM, Paul Moore wrote:
> On Wed, Nov 29, 2023 at 1:47 PM Roberto Sassu
> <roberto.sassu@huaweicloud.com> wrote:
>> On 11/29/2023 6:22 PM, Paul Moore wrote:
>>> On Wed, Nov 29, 2023 at 7:28 AM Roberto Sassu
>>> <roberto.sassu@huaweicloud.com> wrote:
>>>>
>>>> On Mon, 2023-11-20 at 16:06 -0500, Paul Moore wrote:
>>>>> On Mon, Nov 20, 2023 at 3:16 AM Roberto Sassu
>>>>> <roberto.sassu@huaweicloud.com> wrote:
>>>>>> On Fri, 2023-11-17 at 15:57 -0500, Paul Moore wrote:
>>>>>>> On Nov  7, 2023 Roberto Sassu <roberto.sassu@huaweicloud.com> wrote:
>>>>>>>>
>>>>>>>> Before the security field of kernel objects could be shared among LSMs with
>>>>>>>> the LSM stacking feature, IMA and EVM had to rely on an alternative storage
>>>>>>>> of inode metadata. The association between inode metadata and inode is
>>>>>>>> maintained through an rbtree.
>>>>>>>>
>>>>>>>> Because of this alternative storage mechanism, there was no need to use
>>>>>>>> disjoint inode metadata, so IMA and EVM today still share them.
>>>>>>>>
>>>>>>>> With the reservation mechanism offered by the LSM infrastructure, the
>>>>>>>> rbtree is no longer necessary, as each LSM could reserve a space in the
>>>>>>>> security blob for each inode. However, since IMA and EVM share the
>>>>>>>> inode metadata, they cannot directly reserve the space for them.
>>>>>>>>
>>>>>>>> Instead, request from the 'integrity' LSM a space in the security blob for
>>>>>>>> the pointer of inode metadata (integrity_iint_cache structure). The other
>>>>>>>> reason for keeping the 'integrity' LSM is to preserve the original ordering
>>>>>>>> of IMA and EVM functions as when they were hardcoded.
>>>>>>>>
>>>>>>>> Prefer reserving space for a pointer to allocating the integrity_iint_cache
>>>>>>>> structure directly, as IMA would require it only for a subset of inodes.
>>>>>>>> Always allocating it would cause a waste of memory.
>>>>>>>>
>>>>>>>> Introduce two primitives for getting and setting the pointer of
>>>>>>>> integrity_iint_cache in the security blob, respectively
>>>>>>>> integrity_inode_get_iint() and integrity_inode_set_iint(). This would make
>>>>>>>> the code more understandable, as they directly replace rbtree operations.
>>>>>>>>
>>>>>>>> Locking is not needed, as access to inode metadata is not shared, it is per
>>>>>>>> inode.
>>>>>>>>
>>>>>>>> Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
>>>>>>>> Reviewed-by: Casey Schaufler <casey@schaufler-ca.com>
>>>>>>>> Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
>>>>>>>> ---
>>>>>>>>    security/integrity/iint.c      | 71 +++++-----------------------------
>>>>>>>>    security/integrity/integrity.h | 20 +++++++++-
>>>>>>>>    2 files changed, 29 insertions(+), 62 deletions(-)
>>>>>>>>
>>>>>>>> diff --git a/security/integrity/iint.c b/security/integrity/iint.c
>>>>>>>> index 882fde2a2607..a5edd3c70784 100644
>>>>>>>> --- a/security/integrity/iint.c
>>>>>>>> +++ b/security/integrity/iint.c
>>>>>>>> @@ -231,6 +175,10 @@ static int __init integrity_lsm_init(void)
>>>>>>>>       return 0;
>>>>>>>>    }
>>>>>>>>
>>>>>>>> +struct lsm_blob_sizes integrity_blob_sizes __ro_after_init = {
>>>>>>>> +   .lbs_inode = sizeof(struct integrity_iint_cache *),
>>>>>>>> +};
>>>>>>>
>>>>>>> I'll admit that I'm likely missing an important detail, but is there
>>>>>>> a reason why you couldn't stash the integrity_iint_cache struct
>>>>>>> directly in the inode's security blob instead of the pointer?  For
>>>>>>> example:
>>>>>>>
>>>>>>>     struct lsm_blob_sizes ... = {
>>>>>>>       .lbs_inode = sizeof(struct integrity_iint_cache),
>>>>>>>     };
>>>>>>>
>>>>>>>     struct integrity_iint_cache *integrity_inode_get(inode)
>>>>>>>     {
>>>>>>>       if (unlikely(!inode->isecurity))
>>>>>>>         return NULL;
>>>>>>>       return inode->i_security + integrity_blob_sizes.lbs_inode;
>>>>>>>     }
>>>>>>
>>>>>> It would increase memory occupation. Sometimes the IMA policy
>>>>>> encompasses a small subset of the inodes. Allocating the full
>>>>>> integrity_iint_cache would be a waste of memory, I guess?
>>>>>
>>>>> Perhaps, but if it allows us to remove another layer of dynamic memory
>>>>> I would argue that it may be worth the cost.  It's also worth
>>>>> considering the size of integrity_iint_cache, while it isn't small, it
>>>>> isn't exactly huge either.
>>>>>
>>>>>> On the other hand... (did not think fully about that) if we embed the
>>>>>> full structure in the security blob, we already have a mutex available
>>>>>> to use, and we don't need to take the inode lock (?).
>>>>>
>>>>> That would be excellent, getting rid of a layer of locking would be significant.
>>>>>
>>>>>> I'm fully convinced that we can improve the implementation
>>>>>> significantly. I just was really hoping to go step by step and not
>>>>>> accumulating improvements as dependency for moving IMA and EVM to the
>>>>>> LSM infrastructure.
>>>>>
>>>>> I understand, and I agree that an iterative approach is a good idea, I
>>>>> just want to make sure we keep things tidy from a user perspective,
>>>>> i.e. not exposing the "integrity" LSM when it isn't required.
>>>>
>>>> Ok, I went back to it again.
>>>>
>>>> I think trying to separate integrity metadata is premature now, too
>>>> many things at the same time.
>>>
>>> I'm not bothered by the size of the patchset, it is more important
>>> that we do The Right Thing.  I would like to hear in more detail why
>>> you don't think this will work, I'm not interested in hearing about
>>> difficult it may be, I'm interested in hearing about what challenges
>>> we need to solve to do this properly.
>>
>> The right thing in my opinion is to achieve the goal with the minimal
>> set of changes, in the most intuitive way.
> 
> Once again, I want to stress that I don't care about the size of the
> change, the number of patches in a patchset, etc.  While it's always
> nice to be able to minimize the number of changes in a patch/patchset,
> that is secondary to making sure we are doing the right thing over the
> long term.  This is especially important when we are talking about
> things that are user visible.

If we successfully remove the 'integrity' LSM we achieve the goal.

What you say is beyond the scope of this patch set, which is just moving 
IMA and EVM to the LSM infrastructure.

Of course we can discuss about nice ideas, how to improve IMA and EVM, 
but again this is beyond scope.

>> Until now, there was no solution that could achieve the primary goal of
>> this patch set (moving IMA and EVM to the LSM infrastructure) and, at
>> the same time, achieve the additional goal you set of removing the
>> 'integrity' LSM.
> 
> We need to stop thinking about the "integrity" code as a LSM, it isn't
> a LSM.  It's a vestigial implementation detail that was necessary back
> when there could only be one LSM active at a time and there was a
> desire to have IMA/EVM active in conjunction with one of the LSMs,
> i.e. Smack, SELinux, etc.
> 
> IMA and EVM are (or will be) LSMs, "integrity" is not.  I recognize
> that eliminating the need for the "integrity" code is a relatively new
> addition to this effort, but that is only because I didn't properly
> understand the relationship between IMA, EVM, and the "integrity" code
> until recently.  The elimination of the shared "integrity" code is
> consistent with promoting IMA and EVM as full LSMs, if there is core
> functionality that cannot be split up into the IMA and/or EVM LSMs
> then we need to look at how to support that without exposing that
> implementation detail/hack to userspace.  Maybe that means direct
> calls between IMA and EVM, maybe that means preserving some of the
> common integrity code hidden from userspace, maybe that means adding
> functionality to the LSM layer, maybe that means something else?
> Let's think on this to come up with something that we can all accept
> as a long term solution instead of just doing the quick and easy
> option.

Sorry, once we find the proper way to interface the 'ima' and 'evm' LSM 
with the LSM infrastructure, that is all we need to do.

Not changing any internal gives the best guarantee that the behavior 
remains unchanged. And the best thing is that we are not doing a hack, 
we are just preserving what is there.

Sorry, again, we are not exposing to user space any interface that is 
going to change in the future once we refactor the integrity metadata 
management. So, given that, I still haven't seen any compelling reason 
to do the change you suggested.

>> If you see the diff, the changes compared to v5 that was already
>> accepted by Mimi are very straightforward. If the assumption I made that
>> in the end the 'ima' LSM could take over the role of the 'integrity'
>> LSM, that for me is the preferable option.
> 
> I looked at it quickly, but my workflow isn't well suited for patches
> as attachments; inline patches (the kernel standard) is preferable.

Ok, no problem. I send the patches.

>> Given that the patch set is not doing any design change, but merely
>> moving calls and storing pointers elsewhere, that leaves us with the
>> option of thinking better what to do next, including like you suggested
>> to make IMA and EVM use disjoint metadata.
>>
>>>> I started to think, does EVM really need integrity metadata or it can
>>>> work without?
>>>>
>>>> The fact is that CONFIG_IMA=n and CONFIG_EVM=y is allowed, so we have
>>>> the same problem now. What if we make IMA the one that manages
>>>> integrity metadata, so that we can remove the 'integrity' LSM?
>>>
>>> I guess we should probably revisit the basic idea of if it even makes
>>> sense to enable EVM without IMA?  Should we update the Kconfig to
>>> require IMA when EVM is enabled?
>>
>> That would be up to Mimi. Also this does not seem the main focus of the
>> patch set.
> 
> Yes, it is not part of the original main focus, but it is definitely
> relevant to the discussion we are having now.  Once again, the most
> important thing to me is that we do The Right Thing for the long term
> maintenance of the code base; if that means scope creep, I've got no
> problem with that.
> 
>>>> Regarding the LSM order, I would take Casey's suggestion of introducing
>>>> LSM_ORDER_REALLY_LAST, for EVM.
>>>
>>> Please understand that I really dislike that we have imposed ordering
>>> constraints at the LSM layer, but I do understand the necessity (the
>>> BPF LSM ordering upsets me the most).  I really don't want to see us
>>> make things worse by adding yet another ordering bucket, I would
>>> rather that we document it well and leave it alone ... basically treat
>>> it like the BPF LSM (grrrrrr).
>>
>> Uhm, that would not be possible right away (the BPF LSM is mutable),
>> remember that we defined LSM_ORDER_LAST so that an LSM can be always
>> enable and placed as last (requested by Mimi)?
> 
> To be clear, I can both dislike the bpf-always-last and LSM_ORDER_LAST
> concepts while accepting them as necessary evils.  I'm willing to
> tolerate LSM_ORDER_LAST, but I'm not currently willing to tolerate
> LSM_ORDER_REALLY_LAST; that is one step too far right now.  I brought
> up the BPF LSM simply as an example of ordering that is not enforced
> by code, but rather by documentation and convention.

Given what Petr found, we don't need an additional order.

Thanks

Roberto


^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v5 23/23] integrity: Switch from rbtree to LSM-managed blob for integrity_iint_cache
  2023-11-30 21:34                     ` Roberto Sassu
@ 2023-11-30 23:31                       ` Casey Schaufler
  2023-11-30 23:43                         ` Roberto Sassu
  0 siblings, 1 reply; 96+ messages in thread
From: Casey Schaufler @ 2023-11-30 23:31 UTC (permalink / raw)
  To: Roberto Sassu, Petr Tesarik, Paul Moore
  Cc: viro, brauner, chuck.lever, jlayton, neilb, kolga, Dai.Ngo, tom,
	jmorris, serge, zohar, dmitry.kasatkin, dhowells, jarkko,
	stephen.smalley.work, eparis, mic, linux-fsdevel, linux-kernel,
	linux-nfs, linux-security-module, linux-integrity, keyrings,
	selinux, Roberto Sassu, Casey Schaufler

On 11/30/2023 1:34 PM, Roberto Sassu wrote:
> On 11/30/2023 5:15 PM, Casey Schaufler wrote:
>> On 11/30/2023 12:30 AM, Petr Tesarik wrote:
>>> Hi all,
>>>
>>> On 11/30/2023 1:41 AM, Casey Schaufler wrote:
>>>> ...
>>>> It would be nice if the solution directly addresses the problem.
>>>> EVM needs to be after the LSMs that use xattrs, not after all LSMs.
>>>> I suggested LSM_ORDER_REALLY_LAST in part to identify the notion as
>>>> unattractive.
>>> Excuse me to chime in, but do we really need the ordering in code?
>>
>> tl;dr - Yes.
>>
>>>   FWIW
>>> the linker guarantees that objects appear in the order they are seen
>>> during the link (unless --sort-section overrides that default, but this
>>> option is not used in the kernel). Since *.a archive files are used in
>>> kbuild, I have also verified that their use does not break the
>>> assumption; they are always created from scratch.
>>>
>>> In short, to enforce an ordering, you can simply list the corresponding
>>> object files in that order in the Makefile. Of course, add a big fat
>>> warning comment, so people understand the order is not arbitrary.
>>
>> Not everyone builds custom kernels.
>
> Sorry, I didn't understand your comment.

Most people run a disto supplied kernel. If the LSM ordering were determined
only at compile time you could never run a kernel that omitted an LSM.

> Everyone builds the kernel, also Linux distros. What Petr was
> suggesting was that it does not matter how you build the kernel, the
> linker will place the LSMs in the order they appear in the Makefile.
> And for this particular case, we have:
>
> obj-$(CONFIG_IMA)                       += ima/
> obj-$(CONFIG_EVM)                       += evm/
>
> In the past, I also verified that swapping these two resulted in the
> swapped order of LSMs. Petr confirmed that it would always happen.

LSM execution order is not based on compilation order. It is specified
by CONFIG_LSM, and may be modified by the LSM_ORDER value. I don't
understand why the linker is even being brought into the discussion.

>
> Thanks
>
> Roberto

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v5 23/23] integrity: Switch from rbtree to LSM-managed blob for integrity_iint_cache
  2023-11-30 23:31                       ` Casey Schaufler
@ 2023-11-30 23:43                         ` Roberto Sassu
  2023-12-01  0:12                           ` Casey Schaufler
  0 siblings, 1 reply; 96+ messages in thread
From: Roberto Sassu @ 2023-11-30 23:43 UTC (permalink / raw)
  To: Casey Schaufler, Petr Tesarik, Paul Moore
  Cc: viro, brauner, chuck.lever, jlayton, neilb, kolga, Dai.Ngo, tom,
	jmorris, serge, zohar, dmitry.kasatkin, dhowells, jarkko,
	stephen.smalley.work, eparis, mic, linux-fsdevel, linux-kernel,
	linux-nfs, linux-security-module, linux-integrity, keyrings,
	selinux, Roberto Sassu

On 12/1/2023 12:31 AM, Casey Schaufler wrote:
> On 11/30/2023 1:34 PM, Roberto Sassu wrote:
>> On 11/30/2023 5:15 PM, Casey Schaufler wrote:
>>> On 11/30/2023 12:30 AM, Petr Tesarik wrote:
>>>> Hi all,
>>>>
>>>> On 11/30/2023 1:41 AM, Casey Schaufler wrote:
>>>>> ...
>>>>> It would be nice if the solution directly addresses the problem.
>>>>> EVM needs to be after the LSMs that use xattrs, not after all LSMs.
>>>>> I suggested LSM_ORDER_REALLY_LAST in part to identify the notion as
>>>>> unattractive.
>>>> Excuse me to chime in, but do we really need the ordering in code?
>>>
>>> tl;dr - Yes.
>>>
>>>>    FWIW
>>>> the linker guarantees that objects appear in the order they are seen
>>>> during the link (unless --sort-section overrides that default, but this
>>>> option is not used in the kernel). Since *.a archive files are used in
>>>> kbuild, I have also verified that their use does not break the
>>>> assumption; they are always created from scratch.
>>>>
>>>> In short, to enforce an ordering, you can simply list the corresponding
>>>> object files in that order in the Makefile. Of course, add a big fat
>>>> warning comment, so people understand the order is not arbitrary.
>>>
>>> Not everyone builds custom kernels.
>>
>> Sorry, I didn't understand your comment.
> 
> Most people run a disto supplied kernel. If the LSM ordering were determined
> only at compile time you could never run a kernel that omitted an LSM.

Ah, ok. We are talking about the LSMs with order LSM_ORDER_LAST which 
are always enabled and the last.

This is the code in security.c to handle them:

         /* LSM_ORDER_LAST is always last. */
         for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
                 if (lsm->order == LSM_ORDER_LAST)
                         append_ordered_lsm(lsm, "   last");
         }

Those LSMs are not affected by lsm= in the kernel command line, or the 
order in the kernel configuration (those are the mutable LSMs).

In this case, clearly, what matters is how LSMs are stored in the 
.lsm_info.init section. See the DEFINE_LSM() macro:

#define DEFINE_LSM(lsm)                                                \
         static struct lsm_info __lsm_##lsm                             \
                 __used __section(".lsm_info.init")                     \
                 __aligned(sizeof(unsigned long))

With Petr, we started to wonder if somehow the order in which LSMs are 
placed in this section is deterministic. I empirically tried to swap the 
order in which IMA and EVM are compiled in the Makefile, and that led to 
'evm' being placed in the LSM list before 'ima'.

The question is if this behavior is deterministic, or there is a case 
where 'evm' is before 'ima', despite they are in the inverse order in 
the Makefile.

Petr looked at the kernel linking process, which is relevant for the 
order of LSMs in the .lsm_info.init section, and he found that the order 
in the section always corresponds to the order in the Makefile.

Thanks

Roberto
>> Everyone builds the kernel, also Linux distros. What Petr was
>> suggesting was that it does not matter how you build the kernel, the
>> linker will place the LSMs in the order they appear in the Makefile.
>> And for this particular case, we have:
>>
>> obj-$(CONFIG_IMA)                       += ima/
>> obj-$(CONFIG_EVM)                       += evm/
>>
>> In the past, I also verified that swapping these two resulted in the
>> swapped order of LSMs. Petr confirmed that it would always happen.
> 
> LSM execution order is not based on compilation order. It is specified
> by CONFIG_LSM, and may be modified by the LSM_ORDER value. I don't
> understand why the linker is even being brought into the discussion.
> 
>>
>> Thanks
>>
>> Roberto


^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v5 23/23] integrity: Switch from rbtree to LSM-managed blob for integrity_iint_cache
  2023-11-30 23:43                         ` Roberto Sassu
@ 2023-12-01  0:12                           ` Casey Schaufler
  0 siblings, 0 replies; 96+ messages in thread
From: Casey Schaufler @ 2023-12-01  0:12 UTC (permalink / raw)
  To: Roberto Sassu, Petr Tesarik, Paul Moore
  Cc: viro, brauner, chuck.lever, jlayton, neilb, kolga, Dai.Ngo, tom,
	jmorris, serge, zohar, dmitry.kasatkin, dhowells, jarkko,
	stephen.smalley.work, eparis, mic, linux-fsdevel, linux-kernel,
	linux-nfs, linux-security-module, linux-integrity, keyrings,
	selinux, Roberto Sassu, Casey Schaufler

On 11/30/2023 3:43 PM, Roberto Sassu wrote:
> On 12/1/2023 12:31 AM, Casey Schaufler wrote:
>> On 11/30/2023 1:34 PM, Roberto Sassu wrote:
>>> On 11/30/2023 5:15 PM, Casey Schaufler wrote:
>>>> On 11/30/2023 12:30 AM, Petr Tesarik wrote:
>>>>> Hi all,
>>>>>
>>>>> On 11/30/2023 1:41 AM, Casey Schaufler wrote:
>>>>>> ...
>>>>>> It would be nice if the solution directly addresses the problem.
>>>>>> EVM needs to be after the LSMs that use xattrs, not after all LSMs.
>>>>>> I suggested LSM_ORDER_REALLY_LAST in part to identify the notion as
>>>>>> unattractive.
>>>>> Excuse me to chime in, but do we really need the ordering in code?
>>>>
>>>> tl;dr - Yes.
>>>>
>>>>>    FWIW
>>>>> the linker guarantees that objects appear in the order they are seen
>>>>> during the link (unless --sort-section overrides that default, but
>>>>> this
>>>>> option is not used in the kernel). Since *.a archive files are
>>>>> used in
>>>>> kbuild, I have also verified that their use does not break the
>>>>> assumption; they are always created from scratch.
>>>>>
>>>>> In short, to enforce an ordering, you can simply list the
>>>>> corresponding
>>>>> object files in that order in the Makefile. Of course, add a big fat
>>>>> warning comment, so people understand the order is not arbitrary.
>>>>
>>>> Not everyone builds custom kernels.
>>>
>>> Sorry, I didn't understand your comment.
>>
>> Most people run a disto supplied kernel. If the LSM ordering were
>> determined
>> only at compile time you could never run a kernel that omitted an LSM.
>
> Ah, ok. We are talking about the LSMs with order LSM_ORDER_LAST which
> are always enabled and the last.
>
> This is the code in security.c to handle them:
>
>         /* LSM_ORDER_LAST is always last. */
>         for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
>                 if (lsm->order == LSM_ORDER_LAST)
>                         append_ordered_lsm(lsm, "   last");
>         }
>
> Those LSMs are not affected by lsm= in the kernel command line, or the
> order in the kernel configuration (those are the mutable LSMs).
>
> In this case, clearly, what matters is how LSMs are stored in the
> .lsm_info.init section. See the DEFINE_LSM() macro:
>
> #define DEFINE_LSM(lsm)                                                \
>         static struct lsm_info __lsm_##lsm                             \
>                 __used __section(".lsm_info.init")                     \
>                 __aligned(sizeof(unsigned long))
>
> With Petr, we started to wonder if somehow the order in which LSMs are
> placed in this section is deterministic. I empirically tried to swap
> the order in which IMA and EVM are compiled in the Makefile, and that
> led to 'evm' being placed in the LSM list before 'ima'.
>
> The question is if this behavior is deterministic, or there is a case
> where 'evm' is before 'ima', despite they are in the inverse order in
> the Makefile.
>
> Petr looked at the kernel linking process, which is relevant for the
> order of LSMs in the .lsm_info.init section, and he found that the
> order in the section always corresponds to the order in the Makefile.

OK, that's staring to make sense. My recollection is that there wasn't
an expectation for multiple LSM_ORDER_FIRST or LSM_ORDER_LAST entries
in the beginning. They were supposed to be special cases, not general
features.

>
> Thanks
>
> Roberto
>>> Everyone builds the kernel, also Linux distros. What Petr was
>>> suggesting was that it does not matter how you build the kernel, the
>>> linker will place the LSMs in the order they appear in the Makefile.
>>> And for this particular case, we have:
>>>
>>> obj-$(CONFIG_IMA)                       += ima/
>>> obj-$(CONFIG_EVM)                       += evm/
>>>
>>> In the past, I also verified that swapping these two resulted in the
>>> swapped order of LSMs. Petr confirmed that it would always happen.
>>
>> LSM execution order is not based on compilation order. It is specified
>> by CONFIG_LSM, and may be modified by the LSM_ORDER value. I don't
>> understand why the linker is even being brought into the discussion.
>>
>>>
>>> Thanks
>>>
>>> Roberto
>

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v5 23/23] integrity: Switch from rbtree to LSM-managed blob for integrity_iint_cache
  2023-11-29 18:46             ` Roberto Sassu
                                 ` (2 preceding siblings ...)
  2023-11-30 16:34               ` Paul Moore
@ 2023-12-01  1:05               ` Dr. Greg
  2023-12-01 18:54                 ` Casey Schaufler
  3 siblings, 1 reply; 96+ messages in thread
From: Dr. Greg @ 2023-12-01  1:05 UTC (permalink / raw)
  To: Roberto Sassu
  Cc: Paul Moore, viro, brauner, chuck.lever, jlayton, neilb, kolga,
	Dai.Ngo, tom, jmorris, serge, zohar, dmitry.kasatkin, dhowells,
	jarkko, stephen.smalley.work, eparis, casey, mic, linux-fsdevel,
	linux-kernel, linux-nfs, linux-security-module, linux-integrity,
	keyrings, selinux, Roberto Sassu

On Wed, Nov 29, 2023 at 07:46:43PM +0100, Roberto Sassu wrote:

Good evening, I hope the week has gone well for everyone.

> On 11/29/2023 6:22 PM, Paul Moore wrote:
> >On Wed, Nov 29, 2023 at 7:28???AM Roberto Sassu
> ><roberto.sassu@huaweicloud.com> wrote:
> >>
> >>On Mon, 2023-11-20 at 16:06 -0500, Paul Moore wrote:
> >>>On Mon, Nov 20, 2023 at 3:16???AM Roberto Sassu
> >>><roberto.sassu@huaweicloud.com> wrote:
> >>>>On Fri, 2023-11-17 at 15:57 -0500, Paul Moore wrote:
> >>>>>On Nov  7, 2023 Roberto Sassu <roberto.sassu@huaweicloud.com> wrote:
> >>>>>>
> >>>>>>Before the security field of kernel objects could be shared among 
> >>>>>>LSMs with
> >>>>>>the LSM stacking feature, IMA and EVM had to rely on an alternative 
> >>>>>>storage
> >>>>>>of inode metadata. The association between inode metadata and inode is
> >>>>>>maintained through an rbtree.
> >>>>>>
> >>>>>>Because of this alternative storage mechanism, there was no need to 
> >>>>>>use
> >>>>>>disjoint inode metadata, so IMA and EVM today still share them.
> >>>>>>
> >>>>>>With the reservation mechanism offered by the LSM infrastructure, the
> >>>>>>rbtree is no longer necessary, as each LSM could reserve a space in 
> >>>>>>the
> >>>>>>security blob for each inode. However, since IMA and EVM share the
> >>>>>>inode metadata, they cannot directly reserve the space for them.
> >>>>>>
> >>>>>>Instead, request from the 'integrity' LSM a space in the security 
> >>>>>>blob for
> >>>>>>the pointer of inode metadata (integrity_iint_cache structure). The 
> >>>>>>other
> >>>>>>reason for keeping the 'integrity' LSM is to preserve the original 
> >>>>>>ordering
> >>>>>>of IMA and EVM functions as when they were hardcoded.
> >>>>>>
> >>>>>>Prefer reserving space for a pointer to allocating the 
> >>>>>>integrity_iint_cache
> >>>>>>structure directly, as IMA would require it only for a subset of 
> >>>>>>inodes.
> >>>>>>Always allocating it would cause a waste of memory.
> >>>>>>
> >>>>>>Introduce two primitives for getting and setting the pointer of
> >>>>>>integrity_iint_cache in the security blob, respectively
> >>>>>>integrity_inode_get_iint() and integrity_inode_set_iint(). This would 
> >>>>>>make
> >>>>>>the code more understandable, as they directly replace rbtree 
> >>>>>>operations.
> >>>>>>
> >>>>>>Locking is not needed, as access to inode metadata is not shared, it 
> >>>>>>is per
> >>>>>>inode.
> >>>>>>
> >>>>>>Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
> >>>>>>Reviewed-by: Casey Schaufler <casey@schaufler-ca.com>
> >>>>>>Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
> >>>>>>---
> >>>>>>  security/integrity/iint.c      | 71 
> >>>>>>  +++++-----------------------------
> >>>>>>  security/integrity/integrity.h | 20 +++++++++-
> >>>>>>  2 files changed, 29 insertions(+), 62 deletions(-)
> >>>>>>
> >>>>>>diff --git a/security/integrity/iint.c b/security/integrity/iint.c
> >>>>>>index 882fde2a2607..a5edd3c70784 100644
> >>>>>>--- a/security/integrity/iint.c
> >>>>>>+++ b/security/integrity/iint.c
> >>>>>>@@ -231,6 +175,10 @@ static int __init integrity_lsm_init(void)
> >>>>>>     return 0;
> >>>>>>  }
> >>>>>>
> >>>>>>+struct lsm_blob_sizes integrity_blob_sizes __ro_after_init = {
> >>>>>>+   .lbs_inode = sizeof(struct integrity_iint_cache *),
> >>>>>>+};
> >>>>>
> >>>>>I'll admit that I'm likely missing an important detail, but is there
> >>>>>a reason why you couldn't stash the integrity_iint_cache struct
> >>>>>directly in the inode's security blob instead of the pointer?  For
> >>>>>example:
> >>>>>
> >>>>>   struct lsm_blob_sizes ... = {
> >>>>>     .lbs_inode = sizeof(struct integrity_iint_cache),
> >>>>>   };
> >>>>>
> >>>>>   struct integrity_iint_cache *integrity_inode_get(inode)
> >>>>>   {
> >>>>>     if (unlikely(!inode->isecurity))
> >>>>>       return NULL;
> >>>>>     return inode->i_security + integrity_blob_sizes.lbs_inode;
> >>>>>   }
> >>>>
> >>>>It would increase memory occupation. Sometimes the IMA policy
> >>>>encompasses a small subset of the inodes. Allocating the full
> >>>>integrity_iint_cache would be a waste of memory, I guess?
> >>>
> >>>Perhaps, but if it allows us to remove another layer of dynamic memory
> >>>I would argue that it may be worth the cost.  It's also worth
> >>>considering the size of integrity_iint_cache, while it isn't small, it
> >>>isn't exactly huge either.
> >>>
> >>>>On the other hand... (did not think fully about that) if we embed the
> >>>>full structure in the security blob, we already have a mutex available
> >>>>to use, and we don't need to take the inode lock (?).
> >>>
> >>>That would be excellent, getting rid of a layer of locking would be 
> >>>significant.
> >>>
> >>>>I'm fully convinced that we can improve the implementation
> >>>>significantly. I just was really hoping to go step by step and not
> >>>>accumulating improvements as dependency for moving IMA and EVM to the
> >>>>LSM infrastructure.
> >>>
> >>>I understand, and I agree that an iterative approach is a good idea, I
> >>>just want to make sure we keep things tidy from a user perspective,
> >>>i.e. not exposing the "integrity" LSM when it isn't required.
> >>
> >>Ok, I went back to it again.
> >>
> >>I think trying to separate integrity metadata is premature now, too
> >>many things at the same time.
> >
> >I'm not bothered by the size of the patchset, it is more important
> >that we do The Right Thing.  I would like to hear in more detail why
> >you don't think this will work, I'm not interested in hearing about
> >difficult it may be, I'm interested in hearing about what challenges
> >we need to solve to do this properly.
> 
> The right thing in my opinion is to achieve the goal with the minimal 
> set of changes, in the most intuitive way.
> 
> Until now, there was no solution that could achieve the primary goal of 
> this patch set (moving IMA and EVM to the LSM infrastructure) and, at 
> the same time, achieve the additional goal you set of removing the 
> 'integrity' LSM.
> 
> If you see the diff, the changes compared to v5 that was already 
> accepted by Mimi are very straightforward. If the assumption I made that 
> in the end the 'ima' LSM could take over the role of the 'integrity' 
> LSM, that for me is the preferable option.
> 
> Given that the patch set is not doing any design change, but merely 
> moving calls and storing pointers elsewhere, that leaves us with the 
> option of thinking better what to do next, including like you suggested 
> to make IMA and EVM use disjoint metadata.

A suggestion has been made in this thread that there needs to be broad
thinking on this issue, and by extension, other tough problems.  On
that note, we would be interested in any thoughts regarding the notion
of a long term solution for this issue being the migration of EVM to a
BPF based implementation?

There appears to be consensus that the BPF LSM will always go last, a
BPF implementation would seem to address the EVM ordering issue.

In a larger context, there have been suggestions in other LSM threads
that BPF is the future for doing LSM's.  Coincident with that has come
some disagreement about whether or not BPF embodies sufficient
functionality for this role.

The EVM codebase is reasonably modest with a very limited footprint of
hooks that it handles.  A BPF implementation on this scale would seem
to go a long ways in placing BPF sufficiency concerns to rest.

Thoughts/issues?

> Thanks
> 
> Roberto

Have a good weekend.

As always,
Dr. Greg

The Quixote Project - Flailing at the Travails of Cybersecurity

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v5 23/23] integrity: Switch from rbtree to LSM-managed blob for integrity_iint_cache
  2023-12-01  1:05               ` Dr. Greg
@ 2023-12-01 18:54                 ` Casey Schaufler
  2023-12-01 23:53                   ` Dr. Greg
  0 siblings, 1 reply; 96+ messages in thread
From: Casey Schaufler @ 2023-12-01 18:54 UTC (permalink / raw)
  To: Dr. Greg, Roberto Sassu
  Cc: Paul Moore, viro, brauner, chuck.lever, jlayton, neilb, kolga,
	Dai.Ngo, tom, jmorris, serge, zohar, dmitry.kasatkin, dhowells,
	jarkko, stephen.smalley.work, eparis, mic, linux-fsdevel,
	linux-kernel, linux-nfs, linux-security-module, linux-integrity,
	keyrings, selinux, Roberto Sassu, Casey Schaufler

On 11/30/2023 5:05 PM, Dr. Greg wrote:
> A suggestion has been made in this thread that there needs to be broad
> thinking on this issue, and by extension, other tough problems.  On
> that note, we would be interested in any thoughts regarding the notion
> of a long term solution for this issue being the migration of EVM to a
> BPF based implementation?
>
> There appears to be consensus that the BPF LSM will always go last, a
> BPF implementation would seem to address the EVM ordering issue.
>
> In a larger context, there have been suggestions in other LSM threads
> that BPF is the future for doing LSM's.  Coincident with that has come
> some disagreement about whether or not BPF embodies sufficient
> functionality for this role.
>
> The EVM codebase is reasonably modest with a very limited footprint of
> hooks that it handles.  A BPF implementation on this scale would seem
> to go a long ways in placing BPF sufficiency concerns to rest.
>
> Thoughts/issues?

Converting EVM to BPF looks like a 5 to 10 year process. Creating a
EVM design description to work from, building all the support functions
required, then getting sufficient reviews and testing isn't going to be
a walk in the park. That leaves out the issue of distribution of the
EVM-BPF programs. Consider how the rush to convert kernel internals to
Rust is progressing. EVM isn't huge, but it isn't trivial, either. Tetsuo
had a good hard look at converting TOMOYO to BPF, and concluded that it
wasn't practical. TOMOYO is considerably less complicated than EVM.


^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v5 23/23] integrity: Switch from rbtree to LSM-managed blob for integrity_iint_cache
  2023-12-01 18:54                 ` Casey Schaufler
@ 2023-12-01 23:53                   ` Dr. Greg
  2023-12-02  0:17                     ` Casey Schaufler
  0 siblings, 1 reply; 96+ messages in thread
From: Dr. Greg @ 2023-12-01 23:53 UTC (permalink / raw)
  To: Casey Schaufler
  Cc: Roberto Sassu, Paul Moore, viro, brauner, chuck.lever, jlayton,
	neilb, kolga, Dai.Ngo, tom, jmorris, serge, zohar,
	dmitry.kasatkin, dhowells, jarkko, stephen.smalley.work, eparis,
	mic, linux-fsdevel, linux-kernel, linux-nfs,
	linux-security-module, linux-integrity, keyrings, selinux,
	Roberto Sassu

On Fri, Dec 01, 2023 at 10:54:54AM -0800, Casey Schaufler wrote:

Good evening Casey, thanks for taking the time to respond.

> On 11/30/2023 5:05 PM, Dr. Greg wrote:
> > A suggestion has been made in this thread that there needs to be broad
> > thinking on this issue, and by extension, other tough problems.  On
> > that note, we would be interested in any thoughts regarding the notion
> > of a long term solution for this issue being the migration of EVM to a
> > BPF based implementation?
> >
> > There appears to be consensus that the BPF LSM will always go last, a
> > BPF implementation would seem to address the EVM ordering issue.
> >
> > In a larger context, there have been suggestions in other LSM threads
> > that BPF is the future for doing LSM's.  Coincident with that has come
> > some disagreement about whether or not BPF embodies sufficient
> > functionality for this role.
> >
> > The EVM codebase is reasonably modest with a very limited footprint of
> > hooks that it handles.  A BPF implementation on this scale would seem
> > to go a long ways in placing BPF sufficiency concerns to rest.
> >
> > Thoughts/issues?

> Converting EVM to BPF looks like a 5 to 10 year process. Creating a
> EVM design description to work from, building all the support functions
> required, then getting sufficient reviews and testing isn't going to be
> a walk in the park. That leaves out the issue of distribution of the
> EVM-BPF programs. Consider how the rush to convert kernel internals to
> Rust is progressing. EVM isn't huge, but it isn't trivial, either. Tetsuo
> had a good hard look at converting TOMOYO to BPF, and concluded that it
> wasn't practical. TOMOYO is considerably less complicated than EVM.

Interesting, thanks for the reflections.

On a functional line basis, EVM is 14% of the TOMOYO codebase, not
counting the IMA code.

Given your observations, one would than presume around a decade of
development effort to deliver a full featured LSM, ie. SELINUX, SMACK,
APPARMOR, TOMOYO in BPF form.

Very useful information, we can now return the thread to what appears
is going to be the vexing implementation of:

lsm_set_order(LSM_ORDER_FU_I_REALLY_AM_GOING_TO_BE_THE_LAST_ONE_TO_RUN);

:-)

Have a good weekend.

As always,
Dr. Greg

The Quixote Project - Flailing at the Travails of Cybersecurity

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v5 23/23] integrity: Switch from rbtree to LSM-managed blob for integrity_iint_cache
  2023-12-01 23:53                   ` Dr. Greg
@ 2023-12-02  0:17                     ` Casey Schaufler
  0 siblings, 0 replies; 96+ messages in thread
From: Casey Schaufler @ 2023-12-02  0:17 UTC (permalink / raw)
  To: Dr. Greg
  Cc: Roberto Sassu, Paul Moore, viro, brauner, chuck.lever, jlayton,
	neilb, kolga, Dai.Ngo, tom, jmorris, serge, zohar,
	dmitry.kasatkin, dhowells, jarkko, stephen.smalley.work, eparis,
	mic, linux-fsdevel, linux-kernel, linux-nfs,
	linux-security-module, linux-integrity, keyrings, selinux,
	Roberto Sassu, Casey Schaufler

On 12/1/2023 3:53 PM, Dr. Greg wrote:
> On Fri, Dec 01, 2023 at 10:54:54AM -0800, Casey Schaufler wrote:
>
> Good evening Casey, thanks for taking the time to respond.
>
>> On 11/30/2023 5:05 PM, Dr. Greg wrote:
>>> A suggestion has been made in this thread that there needs to be broad
>>> thinking on this issue, and by extension, other tough problems.  On
>>> that note, we would be interested in any thoughts regarding the notion
>>> of a long term solution for this issue being the migration of EVM to a
>>> BPF based implementation?
>>>
>>> There appears to be consensus that the BPF LSM will always go last, a
>>> BPF implementation would seem to address the EVM ordering issue.
>>>
>>> In a larger context, there have been suggestions in other LSM threads
>>> that BPF is the future for doing LSM's.  Coincident with that has come
>>> some disagreement about whether or not BPF embodies sufficient
>>> functionality for this role.
>>>
>>> The EVM codebase is reasonably modest with a very limited footprint of
>>> hooks that it handles.  A BPF implementation on this scale would seem
>>> to go a long ways in placing BPF sufficiency concerns to rest.
>>>
>>> Thoughts/issues?
>> Converting EVM to BPF looks like a 5 to 10 year process. Creating a
>> EVM design description to work from, building all the support functions
>> required, then getting sufficient reviews and testing isn't going to be
>> a walk in the park. That leaves out the issue of distribution of the
>> EVM-BPF programs. Consider how the rush to convert kernel internals to
>> Rust is progressing. EVM isn't huge, but it isn't trivial, either. Tetsuo
>> had a good hard look at converting TOMOYO to BPF, and concluded that it
>> wasn't practical. TOMOYO is considerably less complicated than EVM.
> Interesting, thanks for the reflections.
>
> On a functional line basis, EVM is 14% of the TOMOYO codebase, not
> counting the IMA code.

For EVM to be completely converted to BPF you'll need significant, but
as yet undiscovered, changes in IMA and, most likely, the LSM infrastructure.

> Given your observations, one would than presume around a decade of
> development effort to deliver a full featured LSM, ie. SELINUX, SMACK,
> APPARMOR, TOMOYO in BPF form.

That's not quite true. A new, from scratch LSM implementing something
like SELinux, Smack or AppArmor would take considerably less time. Converting
an existing LSM and being "bug compatible" is going to be painful.

> Very useful information, we can now return the thread to what appears
> is going to be the vexing implementation of:
>
> lsm_set_order(LSM_ORDER_FU_I_REALLY_AM_GOING_TO_BE_THE_LAST_ONE_TO_RUN);

Just so.

>
> :-)
>
> Have a good weekend.
>
> As always,
> Dr. Greg
>
> The Quixote Project - Flailing at the Travails of Cybersecurity
>

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v5 23/23] integrity: Switch from rbtree to LSM-managed blob for integrity_iint_cache
  2023-11-30 16:34               ` Paul Moore
  2023-11-30 21:56                 ` Roberto Sassu
@ 2023-12-04 13:26                 ` Roberto Sassu
  2023-12-04 15:01                   ` Mimi Zohar
  2023-12-06 13:10                   ` Roberto Sassu
  1 sibling, 2 replies; 96+ messages in thread
From: Roberto Sassu @ 2023-12-04 13:26 UTC (permalink / raw)
  To: Paul Moore
  Cc: viro, brauner, chuck.lever, jlayton, neilb, kolga, Dai.Ngo, tom,
	jmorris, serge, zohar, dmitry.kasatkin, dhowells, jarkko,
	stephen.smalley.work, eparis, casey, mic, linux-fsdevel,
	linux-kernel, linux-nfs, linux-security-module, linux-integrity,
	keyrings, selinux, Roberto Sassu

On Thu, 2023-11-30 at 11:34 -0500, Paul Moore wrote:
> On Wed, Nov 29, 2023 at 1:47 PM Roberto Sassu
> <roberto.sassu@huaweicloud.com> wrote:
> > On 11/29/2023 6:22 PM, Paul Moore wrote:
> > > On Wed, Nov 29, 2023 at 7:28 AM Roberto Sassu
> > > <roberto.sassu@huaweicloud.com> wrote:
> > > > 
> > > > On Mon, 2023-11-20 at 16:06 -0500, Paul Moore wrote:
> > > > > On Mon, Nov 20, 2023 at 3:16 AM Roberto Sassu
> > > > > <roberto.sassu@huaweicloud.com> wrote:
> > > > > > On Fri, 2023-11-17 at 15:57 -0500, Paul Moore wrote:
> > > > > > > On Nov  7, 2023 Roberto Sassu <roberto.sassu@huaweicloud.com> wrote:
> > > > > > > > 
> > > > > > > > Before the security field of kernel objects could be shared among LSMs with
> > > > > > > > the LSM stacking feature, IMA and EVM had to rely on an alternative storage
> > > > > > > > of inode metadata. The association between inode metadata and inode is
> > > > > > > > maintained through an rbtree.
> > > > > > > > 
> > > > > > > > Because of this alternative storage mechanism, there was no need to use
> > > > > > > > disjoint inode metadata, so IMA and EVM today still share them.
> > > > > > > > 
> > > > > > > > With the reservation mechanism offered by the LSM infrastructure, the
> > > > > > > > rbtree is no longer necessary, as each LSM could reserve a space in the
> > > > > > > > security blob for each inode. However, since IMA and EVM share the
> > > > > > > > inode metadata, they cannot directly reserve the space for them.
> > > > > > > > 
> > > > > > > > Instead, request from the 'integrity' LSM a space in the security blob for
> > > > > > > > the pointer of inode metadata (integrity_iint_cache structure). The other
> > > > > > > > reason for keeping the 'integrity' LSM is to preserve the original ordering
> > > > > > > > of IMA and EVM functions as when they were hardcoded.
> > > > > > > > 
> > > > > > > > Prefer reserving space for a pointer to allocating the integrity_iint_cache
> > > > > > > > structure directly, as IMA would require it only for a subset of inodes.
> > > > > > > > Always allocating it would cause a waste of memory.
> > > > > > > > 
> > > > > > > > Introduce two primitives for getting and setting the pointer of
> > > > > > > > integrity_iint_cache in the security blob, respectively
> > > > > > > > integrity_inode_get_iint() and integrity_inode_set_iint(). This would make
> > > > > > > > the code more understandable, as they directly replace rbtree operations.
> > > > > > > > 
> > > > > > > > Locking is not needed, as access to inode metadata is not shared, it is per
> > > > > > > > inode.
> > > > > > > > 
> > > > > > > > Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
> > > > > > > > Reviewed-by: Casey Schaufler <casey@schaufler-ca.com>
> > > > > > > > Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
> > > > > > > > ---
> > > > > > > >   security/integrity/iint.c      | 71 +++++-----------------------------
> > > > > > > >   security/integrity/integrity.h | 20 +++++++++-
> > > > > > > >   2 files changed, 29 insertions(+), 62 deletions(-)
> > > > > > > > 
> > > > > > > > diff --git a/security/integrity/iint.c b/security/integrity/iint.c
> > > > > > > > index 882fde2a2607..a5edd3c70784 100644
> > > > > > > > --- a/security/integrity/iint.c
> > > > > > > > +++ b/security/integrity/iint.c
> > > > > > > > @@ -231,6 +175,10 @@ static int __init integrity_lsm_init(void)
> > > > > > > >      return 0;
> > > > > > > >   }
> > > > > > > > 
> > > > > > > > +struct lsm_blob_sizes integrity_blob_sizes __ro_after_init = {
> > > > > > > > +   .lbs_inode = sizeof(struct integrity_iint_cache *),
> > > > > > > > +};
> > > > > > > 
> > > > > > > I'll admit that I'm likely missing an important detail, but is there
> > > > > > > a reason why you couldn't stash the integrity_iint_cache struct
> > > > > > > directly in the inode's security blob instead of the pointer?  For
> > > > > > > example:
> > > > > > > 
> > > > > > >    struct lsm_blob_sizes ... = {
> > > > > > >      .lbs_inode = sizeof(struct integrity_iint_cache),
> > > > > > >    };
> > > > > > > 
> > > > > > >    struct integrity_iint_cache *integrity_inode_get(inode)
> > > > > > >    {
> > > > > > >      if (unlikely(!inode->isecurity))
> > > > > > >        return NULL;
> > > > > > >      return inode->i_security + integrity_blob_sizes.lbs_inode;
> > > > > > >    }
> > > > > > 
> > > > > > It would increase memory occupation. Sometimes the IMA policy
> > > > > > encompasses a small subset of the inodes. Allocating the full
> > > > > > integrity_iint_cache would be a waste of memory, I guess?
> > > > > 
> > > > > Perhaps, but if it allows us to remove another layer of dynamic memory
> > > > > I would argue that it may be worth the cost.  It's also worth
> > > > > considering the size of integrity_iint_cache, while it isn't small, it
> > > > > isn't exactly huge either.
> > > > > 
> > > > > > On the other hand... (did not think fully about that) if we embed the
> > > > > > full structure in the security blob, we already have a mutex available
> > > > > > to use, and we don't need to take the inode lock (?).
> > > > > 
> > > > > That would be excellent, getting rid of a layer of locking would be significant.
> > > > > 
> > > > > > I'm fully convinced that we can improve the implementation
> > > > > > significantly. I just was really hoping to go step by step and not
> > > > > > accumulating improvements as dependency for moving IMA and EVM to the
> > > > > > LSM infrastructure.
> > > > > 
> > > > > I understand, and I agree that an iterative approach is a good idea, I
> > > > > just want to make sure we keep things tidy from a user perspective,
> > > > > i.e. not exposing the "integrity" LSM when it isn't required.
> > > > 
> > > > Ok, I went back to it again.
> > > > 
> > > > I think trying to separate integrity metadata is premature now, too
> > > > many things at the same time.
> > > 
> > > I'm not bothered by the size of the patchset, it is more important
> > > that we do The Right Thing.  I would like to hear in more detail why
> > > you don't think this will work, I'm not interested in hearing about
> > > difficult it may be, I'm interested in hearing about what challenges
> > > we need to solve to do this properly.
> > 
> > The right thing in my opinion is to achieve the goal with the minimal
> > set of changes, in the most intuitive way.
> 
> Once again, I want to stress that I don't care about the size of the
> change, the number of patches in a patchset, etc.  While it's always
> nice to be able to minimize the number of changes in a patch/patchset,
> that is secondary to making sure we are doing the right thing over the
> long term.  This is especially important when we are talking about
> things that are user visible.
> 
> > Until now, there was no solution that could achieve the primary goal of
> > this patch set (moving IMA and EVM to the LSM infrastructure) and, at
> > the same time, achieve the additional goal you set of removing the
> > 'integrity' LSM.
> 
> We need to stop thinking about the "integrity" code as a LSM, it isn't
> a LSM.  It's a vestigial implementation detail that was necessary back
> when there could only be one LSM active at a time and there was a
> desire to have IMA/EVM active in conjunction with one of the LSMs,
> i.e. Smack, SELinux, etc.
> 
> IMA and EVM are (or will be) LSMs, "integrity" is not.  I recognize
> that eliminating the need for the "integrity" code is a relatively new
> addition to this effort, but that is only because I didn't properly
> understand the relationship between IMA, EVM, and the "integrity" code
> until recently.  The elimination of the shared "integrity" code is
> consistent with promoting IMA and EVM as full LSMs, if there is core
> functionality that cannot be split up into the IMA and/or EVM LSMs
> then we need to look at how to support that without exposing that
> implementation detail/hack to userspace.  Maybe that means direct
> calls between IMA and EVM, maybe that means preserving some of the
> common integrity code hidden from userspace, maybe that means adding
> functionality to the LSM layer, maybe that means something else?
> Let's think on this to come up with something that we can all accept
> as a long term solution instead of just doing the quick and easy
> option.

If the result of this patch set should be that IMA and EVM become
proper LSMs without the shared integrity layer, instead of collapsing
all changes in this patch set, I think we should first verify if IMA
and EVM can be really independent. Once we guarantee that, we can
proceed making the proper LSMs.

These are the changes I have in mind:

1) Fix evm_verifyxattr(), and make it work without integrity_iint_cache
2) Remove the integrity_iint_cache parameter from evm_verifyxattr(),
   since the other callers are not going to use it
3) Create an internal function with the original parameters to be used
   by IMA
4) Introduce evm_post_path_mknod(), which similarly to
   ima_post_path_mknod(), sets IMA_NEW_FILE for new files
5) Add hardcoded call to evm_post_path_mknod() after
   ima_post_path_mknod() in security.c

If we think that this is good enough, we proceed with the move of IMA
and EVM functions to the LSM infrastructure (patches v7 19-21).

The next patches are going to be similar to patches v6 22-23, but
unlike those, their goal would be simply to split metadata, not to make
IMA and EVM independent, which at this point has been addressed
separately in the prerequisite patches.

The final patch is to remove the 'integrity' LSM and the integrity
metadata management code, which now is not used anymore.

Would that work?

Thanks

Roberto

> > If you see the diff, the changes compared to v5 that was already
> > accepted by Mimi are very straightforward. If the assumption I made that
> > in the end the 'ima' LSM could take over the role of the 'integrity'
> > LSM, that for me is the preferable option.
> 
> I looked at it quickly, but my workflow isn't well suited for patches
> as attachments; inline patches (the kernel standard) is preferable.
> 
> > Given that the patch set is not doing any design change, but merely
> > moving calls and storing pointers elsewhere, that leaves us with the
> > option of thinking better what to do next, including like you suggested
> > to make IMA and EVM use disjoint metadata.
> > 
> > > > I started to think, does EVM really need integrity metadata or it can
> > > > work without?
> > > > 
> > > > The fact is that CONFIG_IMA=n and CONFIG_EVM=y is allowed, so we have
> > > > the same problem now. What if we make IMA the one that manages
> > > > integrity metadata, so that we can remove the 'integrity' LSM?
> > > 
> > > I guess we should probably revisit the basic idea of if it even makes
> > > sense to enable EVM without IMA?  Should we update the Kconfig to
> > > require IMA when EVM is enabled?
> > 
> > That would be up to Mimi. Also this does not seem the main focus of the
> > patch set.
> 
> Yes, it is not part of the original main focus, but it is definitely
> relevant to the discussion we are having now.  Once again, the most
> important thing to me is that we do The Right Thing for the long term
> maintenance of the code base; if that means scope creep, I've got no
> problem with that.
> 
> > > > Regarding the LSM order, I would take Casey's suggestion of introducing
> > > > LSM_ORDER_REALLY_LAST, for EVM.
> > > 
> > > Please understand that I really dislike that we have imposed ordering
> > > constraints at the LSM layer, but I do understand the necessity (the
> > > BPF LSM ordering upsets me the most).  I really don't want to see us
> > > make things worse by adding yet another ordering bucket, I would
> > > rather that we document it well and leave it alone ... basically treat
> > > it like the BPF LSM (grrrrrr).
> > 
> > Uhm, that would not be possible right away (the BPF LSM is mutable),
> > remember that we defined LSM_ORDER_LAST so that an LSM can be always
> > enable and placed as last (requested by Mimi)?
> 
> To be clear, I can both dislike the bpf-always-last and LSM_ORDER_LAST
> concepts while accepting them as necessary evils.  I'm willing to
> tolerate LSM_ORDER_LAST, but I'm not currently willing to tolerate
> LSM_ORDER_REALLY_LAST; that is one step too far right now.  I brought
> up the BPF LSM simply as an example of ordering that is not enforced
> by code, but rather by documentation and convention.
> 


^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v5 23/23] integrity: Switch from rbtree to LSM-managed blob for integrity_iint_cache
  2023-12-04 13:26                 ` Roberto Sassu
@ 2023-12-04 15:01                   ` Mimi Zohar
  2023-12-06 13:10                   ` Roberto Sassu
  1 sibling, 0 replies; 96+ messages in thread
From: Mimi Zohar @ 2023-12-04 15:01 UTC (permalink / raw)
  To: Roberto Sassu, Paul Moore
  Cc: viro, brauner, chuck.lever, jlayton, neilb, kolga, Dai.Ngo, tom,
	jmorris, serge, dmitry.kasatkin, dhowells, jarkko,
	stephen.smalley.work, eparis, casey, mic, linux-fsdevel,
	linux-kernel, linux-nfs, linux-security-module, linux-integrity,
	keyrings, selinux, Roberto Sassu

On Mon, 2023-12-04 at 14:26 +0100, Roberto Sassu wrote:
> On Thu, 2023-11-30 at 11:34 -0500, Paul Moore wrote:
> > On Wed, Nov 29, 2023 at 1:47 PM Roberto Sassu
> > <roberto.sassu@huaweicloud.com> wrote:
> > > On 11/29/2023 6:22 PM, Paul Moore wrote:
> > > > On Wed, Nov 29, 2023 at 7:28 AM Roberto Sassu
> > > > <roberto.sassu@huaweicloud.com> wrote:
> > > > > 
> > > > > On Mon, 2023-11-20 at 16:06 -0500, Paul Moore wrote:
> > > > > > On Mon, Nov 20, 2023 at 3:16 AM Roberto Sassu
> > > > > > <roberto.sassu@huaweicloud.com> wrote:
> > > > > > > On Fri, 2023-11-17 at 15:57 -0500, Paul Moore wrote:
> > > > > > > > On Nov  7, 2023 Roberto Sassu <roberto.sassu@huaweicloud.com> wrote:
> > > > > > > > > 
> > > > > > > > > Before the security field of kernel objects could be shared among LSMs with
> > > > > > > > > the LSM stacking feature, IMA and EVM had to rely on an alternative storage
> > > > > > > > > of inode metadata. The association between inode metadata and inode is
> > > > > > > > > maintained through an rbtree.
> > > > > > > > > 
> > > > > > > > > Because of this alternative storage mechanism, there was no need to use
> > > > > > > > > disjoint inode metadata, so IMA and EVM today still share them.
> > > > > > > > > 
> > > > > > > > > With the reservation mechanism offered by the LSM infrastructure, the
> > > > > > > > > rbtree is no longer necessary, as each LSM could reserve a space in the
> > > > > > > > > security blob for each inode. However, since IMA and EVM share the
> > > > > > > > > inode metadata, they cannot directly reserve the space for them.
> > > > > > > > > 
> > > > > > > > > Instead, request from the 'integrity' LSM a space in the security blob for
> > > > > > > > > the pointer of inode metadata (integrity_iint_cache structure). The other
> > > > > > > > > reason for keeping the 'integrity' LSM is to preserve the original ordering
> > > > > > > > > of IMA and EVM functions as when they were hardcoded.
> > > > > > > > > 
> > > > > > > > > Prefer reserving space for a pointer to allocating the integrity_iint_cache
> > > > > > > > > structure directly, as IMA would require it only for a subset of inodes.
> > > > > > > > > Always allocating it would cause a waste of memory.
> > > > > > > > > 
> > > > > > > > > Introduce two primitives for getting and setting the pointer of
> > > > > > > > > integrity_iint_cache in the security blob, respectively
> > > > > > > > > integrity_inode_get_iint() and integrity_inode_set_iint(). This would make
> > > > > > > > > the code more understandable, as they directly replace rbtree operations.
> > > > > > > > > 
> > > > > > > > > Locking is not needed, as access to inode metadata is not shared, it is per
> > > > > > > > > inode.
> > > > > > > > > 
> > > > > > > > > Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
> > > > > > > > > Reviewed-by: Casey Schaufler <casey@schaufler-ca.com>
> > > > > > > > > Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
> > > > > > > > > ---
> > > > > > > > >   security/integrity/iint.c      | 71 +++++-----------------------------
> > > > > > > > >   security/integrity/integrity.h | 20 +++++++++-
> > > > > > > > >   2 files changed, 29 insertions(+), 62 deletions(-)
> > > > > > > > > 
> > > > > > > > > diff --git a/security/integrity/iint.c b/security/integrity/iint.c
> > > > > > > > > index 882fde2a2607..a5edd3c70784 100644
> > > > > > > > > --- a/security/integrity/iint.c
> > > > > > > > > +++ b/security/integrity/iint.c
> > > > > > > > > @@ -231,6 +175,10 @@ static int __init integrity_lsm_init(void)
> > > > > > > > >      return 0;
> > > > > > > > >   }
> > > > > > > > > 
> > > > > > > > > +struct lsm_blob_sizes integrity_blob_sizes __ro_after_init = {
> > > > > > > > > +   .lbs_inode = sizeof(struct integrity_iint_cache *),
> > > > > > > > > +};
> > > > > > > > 
> > > > > > > > I'll admit that I'm likely missing an important detail, but is there
> > > > > > > > a reason why you couldn't stash the integrity_iint_cache struct
> > > > > > > > directly in the inode's security blob instead of the pointer?  For
> > > > > > > > example:
> > > > > > > > 
> > > > > > > >    struct lsm_blob_sizes ... = {
> > > > > > > >      .lbs_inode = sizeof(struct integrity_iint_cache),
> > > > > > > >    };
> > > > > > > > 
> > > > > > > >    struct integrity_iint_cache *integrity_inode_get(inode)
> > > > > > > >    {
> > > > > > > >      if (unlikely(!inode->isecurity))
> > > > > > > >        return NULL;
> > > > > > > >      return inode->i_security + integrity_blob_sizes.lbs_inode;
> > > > > > > >    }
> > > > > > > 
> > > > > > > It would increase memory occupation. Sometimes the IMA policy
> > > > > > > encompasses a small subset of the inodes. Allocating the full
> > > > > > > integrity_iint_cache would be a waste of memory, I guess?
> > > > > > 
> > > > > > Perhaps, but if it allows us to remove another layer of dynamic memory
> > > > > > I would argue that it may be worth the cost.  It's also worth
> > > > > > considering the size of integrity_iint_cache, while it isn't small, it
> > > > > > isn't exactly huge either.
> > > > > > 
> > > > > > > On the other hand... (did not think fully about that) if we embed the
> > > > > > > full structure in the security blob, we already have a mutex available
> > > > > > > to use, and we don't need to take the inode lock (?).
> > > > > > 
> > > > > > That would be excellent, getting rid of a layer of locking would be significant.
> > > > > > 
> > > > > > > I'm fully convinced that we can improve the implementation
> > > > > > > significantly. I just was really hoping to go step by step and not
> > > > > > > accumulating improvements as dependency for moving IMA and EVM to the
> > > > > > > LSM infrastructure.
> > > > > > 
> > > > > > I understand, and I agree that an iterative approach is a good idea, I
> > > > > > just want to make sure we keep things tidy from a user perspective,
> > > > > > i.e. not exposing the "integrity" LSM when it isn't required.
> > > > > 
> > > > > Ok, I went back to it again.
> > > > > 
> > > > > I think trying to separate integrity metadata is premature now, too
> > > > > many things at the same time.
> > > > 
> > > > I'm not bothered by the size of the patchset, it is more important
> > > > that we do The Right Thing.  I would like to hear in more detail why
> > > > you don't think this will work, I'm not interested in hearing about
> > > > difficult it may be, I'm interested in hearing about what challenges
> > > > we need to solve to do this properly.
> > > 
> > > The right thing in my opinion is to achieve the goal with the minimal
> > > set of changes, in the most intuitive way.
> > 
> > Once again, I want to stress that I don't care about the size of the
> > change, the number of patches in a patchset, etc.  While it's always
> > nice to be able to minimize the number of changes in a patch/patchset,
> > that is secondary to making sure we are doing the right thing over the
> > long term.  This is especially important when we are talking about
> > things that are user visible.
> > 
> > > Until now, there was no solution that could achieve the primary goal of
> > > this patch set (moving IMA and EVM to the LSM infrastructure) and, at
> > > the same time, achieve the additional goal you set of removing the
> > > 'integrity' LSM.
> > 
> > We need to stop thinking about the "integrity" code as a LSM, it isn't
> > a LSM.  It's a vestigial implementation detail that was necessary back
> > when there could only be one LSM active at a time and there was a
> > desire to have IMA/EVM active in conjunction with one of the LSMs,
> > i.e. Smack, SELinux, etc.
> > 
> > IMA and EVM are (or will be) LSMs, "integrity" is not.  I recognize
> > that eliminating the need for the "integrity" code is a relatively new
> > addition to this effort, but that is only because I didn't properly
> > understand the relationship between IMA, EVM, and the "integrity" code
> > until recently.  The elimination of the shared "integrity" code is
> > consistent with promoting IMA and EVM as full LSMs, if there is core
> > functionality that cannot be split up into the IMA and/or EVM LSMs
> > then we need to look at how to support that without exposing that
> > implementation detail/hack to userspace.  Maybe that means direct
> > calls between IMA and EVM, maybe that means preserving some of the
> > common integrity code hidden from userspace, maybe that means adding
> > functionality to the LSM layer, maybe that means something else?
> > Let's think on this to come up with something that we can all accept
> > as a long term solution instead of just doing the quick and easy
> > option.
> 
> If the result of this patch set should be that IMA and EVM become
> proper LSMs without the shared integrity layer, instead of collapsing
> all changes in this patch set, I think we should first verify if IMA
> and EVM can be really independent. Once we guarantee that, we can
> proceed making the proper LSMs.
> 
> These are the changes I have in mind:
> 
> 1) Fix evm_verifyxattr(), and make it work without integrity_iint_cache
> 2) Remove the integrity_iint_cache parameter from evm_verifyxattr(),
>    since the other callers are not going to use it
> 3) Create an internal function with the original parameters to be used
>    by IMA
> 4) Introduce evm_post_path_mknod(), which similarly to
>    ima_post_path_mknod(), sets IMA_NEW_FILE for new files
> 5) Add hardcoded call to evm_post_path_mknod() after
>    ima_post_path_mknod() in security.c
> 
> If we think that this is good enough, we proceed with the move of IMA
> and EVM functions to the LSM infrastructure (patches v7 19-21).
> 
> The next patches are going to be similar to patches v6 22-23, but
> unlike those, their goal would be simply to split metadata, not to make
> IMA and EVM independent, which at this point has been addressed
> separately in the prerequisite patches.
> 
> The final patch is to remove the 'integrity' LSM and the integrity
> metadata management code, which now is not used anymore.
> 
> Would that work?

Sounds good to me.

Mimi


^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v5 23/23] integrity: Switch from rbtree to LSM-managed blob for integrity_iint_cache
  2023-12-04 13:26                 ` Roberto Sassu
  2023-12-04 15:01                   ` Mimi Zohar
@ 2023-12-06 13:10                   ` Roberto Sassu
  2023-12-06 16:11                     ` Mimi Zohar
  1 sibling, 1 reply; 96+ messages in thread
From: Roberto Sassu @ 2023-12-06 13:10 UTC (permalink / raw)
  To: Paul Moore
  Cc: viro, brauner, chuck.lever, jlayton, neilb, kolga, Dai.Ngo, tom,
	jmorris, serge, zohar, dmitry.kasatkin, dhowells, jarkko,
	stephen.smalley.work, eparis, casey, mic, linux-fsdevel,
	linux-kernel, linux-nfs, linux-security-module, linux-integrity,
	keyrings, selinux, Roberto Sassu

On Mon, 2023-12-04 at 14:26 +0100, Roberto Sassu wrote:
> On Thu, 2023-11-30 at 11:34 -0500, Paul Moore wrote:
> > On Wed, Nov 29, 2023 at 1:47 PM Roberto Sassu
> > <roberto.sassu@huaweicloud.com> wrote:
> > > On 11/29/2023 6:22 PM, Paul Moore wrote:
> > > > On Wed, Nov 29, 2023 at 7:28 AM Roberto Sassu
> > > > <roberto.sassu@huaweicloud.com> wrote:
> > > > > 
> > > > > On Mon, 2023-11-20 at 16:06 -0500, Paul Moore wrote:
> > > > > > On Mon, Nov 20, 2023 at 3:16 AM Roberto Sassu
> > > > > > <roberto.sassu@huaweicloud.com> wrote:
> > > > > > > On Fri, 2023-11-17 at 15:57 -0500, Paul Moore wrote:
> > > > > > > > On Nov  7, 2023 Roberto Sassu <roberto.sassu@huaweicloud.com> wrote:
> > > > > > > > > 
> > > > > > > > > Before the security field of kernel objects could be shared among LSMs with
> > > > > > > > > the LSM stacking feature, IMA and EVM had to rely on an alternative storage
> > > > > > > > > of inode metadata. The association between inode metadata and inode is
> > > > > > > > > maintained through an rbtree.
> > > > > > > > > 
> > > > > > > > > Because of this alternative storage mechanism, there was no need to use
> > > > > > > > > disjoint inode metadata, so IMA and EVM today still share them.
> > > > > > > > > 
> > > > > > > > > With the reservation mechanism offered by the LSM infrastructure, the
> > > > > > > > > rbtree is no longer necessary, as each LSM could reserve a space in the
> > > > > > > > > security blob for each inode. However, since IMA and EVM share the
> > > > > > > > > inode metadata, they cannot directly reserve the space for them.
> > > > > > > > > 
> > > > > > > > > Instead, request from the 'integrity' LSM a space in the security blob for
> > > > > > > > > the pointer of inode metadata (integrity_iint_cache structure). The other
> > > > > > > > > reason for keeping the 'integrity' LSM is to preserve the original ordering
> > > > > > > > > of IMA and EVM functions as when they were hardcoded.
> > > > > > > > > 
> > > > > > > > > Prefer reserving space for a pointer to allocating the integrity_iint_cache
> > > > > > > > > structure directly, as IMA would require it only for a subset of inodes.
> > > > > > > > > Always allocating it would cause a waste of memory.
> > > > > > > > > 
> > > > > > > > > Introduce two primitives for getting and setting the pointer of
> > > > > > > > > integrity_iint_cache in the security blob, respectively
> > > > > > > > > integrity_inode_get_iint() and integrity_inode_set_iint(). This would make
> > > > > > > > > the code more understandable, as they directly replace rbtree operations.
> > > > > > > > > 
> > > > > > > > > Locking is not needed, as access to inode metadata is not shared, it is per
> > > > > > > > > inode.
> > > > > > > > > 
> > > > > > > > > Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
> > > > > > > > > Reviewed-by: Casey Schaufler <casey@schaufler-ca.com>
> > > > > > > > > Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
> > > > > > > > > ---
> > > > > > > > >   security/integrity/iint.c      | 71 +++++-----------------------------
> > > > > > > > >   security/integrity/integrity.h | 20 +++++++++-
> > > > > > > > >   2 files changed, 29 insertions(+), 62 deletions(-)
> > > > > > > > > 
> > > > > > > > > diff --git a/security/integrity/iint.c b/security/integrity/iint.c
> > > > > > > > > index 882fde2a2607..a5edd3c70784 100644
> > > > > > > > > --- a/security/integrity/iint.c
> > > > > > > > > +++ b/security/integrity/iint.c
> > > > > > > > > @@ -231,6 +175,10 @@ static int __init integrity_lsm_init(void)
> > > > > > > > >      return 0;
> > > > > > > > >   }
> > > > > > > > > 
> > > > > > > > > +struct lsm_blob_sizes integrity_blob_sizes __ro_after_init = {
> > > > > > > > > +   .lbs_inode = sizeof(struct integrity_iint_cache *),
> > > > > > > > > +};
> > > > > > > > 
> > > > > > > > I'll admit that I'm likely missing an important detail, but is there
> > > > > > > > a reason why you couldn't stash the integrity_iint_cache struct
> > > > > > > > directly in the inode's security blob instead of the pointer?  For
> > > > > > > > example:
> > > > > > > > 
> > > > > > > >    struct lsm_blob_sizes ... = {
> > > > > > > >      .lbs_inode = sizeof(struct integrity_iint_cache),
> > > > > > > >    };
> > > > > > > > 
> > > > > > > >    struct integrity_iint_cache *integrity_inode_get(inode)
> > > > > > > >    {
> > > > > > > >      if (unlikely(!inode->isecurity))
> > > > > > > >        return NULL;
> > > > > > > >      return inode->i_security + integrity_blob_sizes.lbs_inode;
> > > > > > > >    }
> > > > > > > 
> > > > > > > It would increase memory occupation. Sometimes the IMA policy
> > > > > > > encompasses a small subset of the inodes. Allocating the full
> > > > > > > integrity_iint_cache would be a waste of memory, I guess?
> > > > > > 
> > > > > > Perhaps, but if it allows us to remove another layer of dynamic memory
> > > > > > I would argue that it may be worth the cost.  It's also worth
> > > > > > considering the size of integrity_iint_cache, while it isn't small, it
> > > > > > isn't exactly huge either.
> > > > > > 
> > > > > > > On the other hand... (did not think fully about that) if we embed the
> > > > > > > full structure in the security blob, we already have a mutex available
> > > > > > > to use, and we don't need to take the inode lock (?).
> > > > > > 
> > > > > > That would be excellent, getting rid of a layer of locking would be significant.
> > > > > > 
> > > > > > > I'm fully convinced that we can improve the implementation
> > > > > > > significantly. I just was really hoping to go step by step and not
> > > > > > > accumulating improvements as dependency for moving IMA and EVM to the
> > > > > > > LSM infrastructure.
> > > > > > 
> > > > > > I understand, and I agree that an iterative approach is a good idea, I
> > > > > > just want to make sure we keep things tidy from a user perspective,
> > > > > > i.e. not exposing the "integrity" LSM when it isn't required.
> > > > > 
> > > > > Ok, I went back to it again.
> > > > > 
> > > > > I think trying to separate integrity metadata is premature now, too
> > > > > many things at the same time.
> > > > 
> > > > I'm not bothered by the size of the patchset, it is more important
> > > > that we do The Right Thing.  I would like to hear in more detail why
> > > > you don't think this will work, I'm not interested in hearing about
> > > > difficult it may be, I'm interested in hearing about what challenges
> > > > we need to solve to do this properly.
> > > 
> > > The right thing in my opinion is to achieve the goal with the minimal
> > > set of changes, in the most intuitive way.
> > 
> > Once again, I want to stress that I don't care about the size of the
> > change, the number of patches in a patchset, etc.  While it's always
> > nice to be able to minimize the number of changes in a patch/patchset,
> > that is secondary to making sure we are doing the right thing over the
> > long term.  This is especially important when we are talking about
> > things that are user visible.
> > 
> > > Until now, there was no solution that could achieve the primary goal of
> > > this patch set (moving IMA and EVM to the LSM infrastructure) and, at
> > > the same time, achieve the additional goal you set of removing the
> > > 'integrity' LSM.
> > 
> > We need to stop thinking about the "integrity" code as a LSM, it isn't
> > a LSM.  It's a vestigial implementation detail that was necessary back
> > when there could only be one LSM active at a time and there was a
> > desire to have IMA/EVM active in conjunction with one of the LSMs,
> > i.e. Smack, SELinux, etc.
> > 
> > IMA and EVM are (or will be) LSMs, "integrity" is not.  I recognize
> > that eliminating the need for the "integrity" code is a relatively new
> > addition to this effort, but that is only because I didn't properly
> > understand the relationship between IMA, EVM, and the "integrity" code
> > until recently.  The elimination of the shared "integrity" code is
> > consistent with promoting IMA and EVM as full LSMs, if there is core
> > functionality that cannot be split up into the IMA and/or EVM LSMs
> > then we need to look at how to support that without exposing that
> > implementation detail/hack to userspace.  Maybe that means direct
> > calls between IMA and EVM, maybe that means preserving some of the
> > common integrity code hidden from userspace, maybe that means adding
> > functionality to the LSM layer, maybe that means something else?
> > Let's think on this to come up with something that we can all accept
> > as a long term solution instead of just doing the quick and easy
> > option.
> 
> If the result of this patch set should be that IMA and EVM become
> proper LSMs without the shared integrity layer, instead of collapsing
> all changes in this patch set, I think we should first verify if IMA
> and EVM can be really independent. Once we guarantee that, we can
> proceed making the proper LSMs.
> 
> These are the changes I have in mind:
> 
> 1) Fix evm_verifyxattr(), and make it work without integrity_iint_cache
> 2) Remove the integrity_iint_cache parameter from evm_verifyxattr(),
>    since the other callers are not going to use it

Ehm, I checked better.

integrity_inode_get() is public too (although it is not exported). So,
a caller (not IMA) could do:

iint = integrity_inode_get(inode);
status = evm_verifyxattr(..., iint);

However, it should not call integrity_inode_free(), which is also in
include/linux/integrity.h, since this is going to be called by
security_inode_free() (currently).

> 3) Create an internal function with the original parameters to be used
>    by IMA
> 4) Introduce evm_post_path_mknod(), which similarly to
>    ima_post_path_mknod(), sets IMA_NEW_FILE for new files

I just realized that also this is changing the current behavior.

IMA would clear IMA_NEW_FILE in ima_check_last_writer(), while EVM
wouldn't (unless we implement the file_release hook in EVM too).

> 5) Add hardcoded call to evm_post_path_mknod() after
>    ima_post_path_mknod() in security.c
> 
> If we think that this is good enough, we proceed with the move of IMA
> and EVM functions to the LSM infrastructure (patches v7 19-21).
> 
> The next patches are going to be similar to patches v6 22-23, but
> unlike those, their goal would be simply to split metadata, not to make
> IMA and EVM independent, which at this point has been addressed
> separately in the prerequisite patches.
> 
> The final patch is to remove the 'integrity' LSM and the integrity
> metadata management code, which now is not used anymore.
> 
> Would that work?

We are not making much progress, I'm going to follow any recommendation
that would move this forward.

Thanks

Roberto

> Thanks
> 
> Roberto
> 
> > > If you see the diff, the changes compared to v5 that was already
> > > accepted by Mimi are very straightforward. If the assumption I made that
> > > in the end the 'ima' LSM could take over the role of the 'integrity'
> > > LSM, that for me is the preferable option.
> > 
> > I looked at it quickly, but my workflow isn't well suited for patches
> > as attachments; inline patches (the kernel standard) is preferable.
> > 
> > > Given that the patch set is not doing any design change, but merely
> > > moving calls and storing pointers elsewhere, that leaves us with the
> > > option of thinking better what to do next, including like you suggested
> > > to make IMA and EVM use disjoint metadata.
> > > 
> > > > > I started to think, does EVM really need integrity metadata or it can
> > > > > work without?
> > > > > 
> > > > > The fact is that CONFIG_IMA=n and CONFIG_EVM=y is allowed, so we have
> > > > > the same problem now. What if we make IMA the one that manages
> > > > > integrity metadata, so that we can remove the 'integrity' LSM?
> > > > 
> > > > I guess we should probably revisit the basic idea of if it even makes
> > > > sense to enable EVM without IMA?  Should we update the Kconfig to
> > > > require IMA when EVM is enabled?
> > > 
> > > That would be up to Mimi. Also this does not seem the main focus of the
> > > patch set.
> > 
> > Yes, it is not part of the original main focus, but it is definitely
> > relevant to the discussion we are having now.  Once again, the most
> > important thing to me is that we do The Right Thing for the long term
> > maintenance of the code base; if that means scope creep, I've got no
> > problem with that.
> > 
> > > > > Regarding the LSM order, I would take Casey's suggestion of introducing
> > > > > LSM_ORDER_REALLY_LAST, for EVM.
> > > > 
> > > > Please understand that I really dislike that we have imposed ordering
> > > > constraints at the LSM layer, but I do understand the necessity (the
> > > > BPF LSM ordering upsets me the most).  I really don't want to see us
> > > > make things worse by adding yet another ordering bucket, I would
> > > > rather that we document it well and leave it alone ... basically treat
> > > > it like the BPF LSM (grrrrrr).
> > > 
> > > Uhm, that would not be possible right away (the BPF LSM is mutable),
> > > remember that we defined LSM_ORDER_LAST so that an LSM can be always
> > > enable and placed as last (requested by Mimi)?
> > 
> > To be clear, I can both dislike the bpf-always-last and LSM_ORDER_LAST
> > concepts while accepting them as necessary evils.  I'm willing to
> > tolerate LSM_ORDER_LAST, but I'm not currently willing to tolerate
> > LSM_ORDER_REALLY_LAST; that is one step too far right now.  I brought
> > up the BPF LSM simply as an example of ordering that is not enforced
> > by code, but rather by documentation and convention.
> > 


^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v5 23/23] integrity: Switch from rbtree to LSM-managed blob for integrity_iint_cache
  2023-12-06 13:10                   ` Roberto Sassu
@ 2023-12-06 16:11                     ` Mimi Zohar
  2023-12-06 16:50                       ` Roberto Sassu
  0 siblings, 1 reply; 96+ messages in thread
From: Mimi Zohar @ 2023-12-06 16:11 UTC (permalink / raw)
  To: Roberto Sassu, Paul Moore
  Cc: viro, brauner, chuck.lever, jlayton, neilb, kolga, Dai.Ngo, tom,
	jmorris, serge, dmitry.kasatkin, dhowells, jarkko,
	stephen.smalley.work, eparis, casey, mic, linux-fsdevel,
	linux-kernel, linux-nfs, linux-security-module, linux-integrity,
	keyrings, selinux, Roberto Sassu

On Wed, 2023-12-06 at 14:10 +0100, Roberto Sassu wrote:
> On Mon, 2023-12-04 at 14:26 +0100, Roberto Sassu wrote:

...
> > If the result of this patch set should be that IMA and EVM become
> > proper LSMs without the shared integrity layer, instead of collapsing
> > all changes in this patch set, I think we should first verify if IMA
> > and EVM can be really independent. Once we guarantee that, we can
> > proceed making the proper LSMs.
> > 
> > These are the changes I have in mind:
> > 
> > 1) Fix evm_verifyxattr(), and make it work without integrity_iint_cache
> > 2) Remove the integrity_iint_cache parameter from evm_verifyxattr(),
> >    since the other callers are not going to use it
> 
> Ehm, I checked better.
> 
> integrity_inode_get() is public too (although it is not exported). So,
> a caller (not IMA) could do:
> 
> iint = integrity_inode_get(inode);
> status = evm_verifyxattr(..., iint);
> 
> However, it should not call integrity_inode_free(), which is also in
> include/linux/integrity.h, since this is going to be called by
> security_inode_free() (currently).

Calling integrity_inode_free() directly would release the iint early.  
As a result, IMA would then need to re-allocate it on next access. 
Other than impacting IMA's performance, is this a problem?

> > 3) Create an internal function with the original parameters to be used
> >    by IMA
> > 4) Introduce evm_post_path_mknod(), which similarly to
> >    ima_post_path_mknod(), sets IMA_NEW_FILE for new files
> 
> I just realized that also this is changing the current behavior.
> 
> IMA would clear IMA_NEW_FILE in ima_check_last_writer(), while EVM
> wouldn't (unless we implement the file_release hook in EVM too).

True

Mimi

> > 5) Add hardcoded call to evm_post_path_mknod() after
> >    ima_post_path_mknod() in security.c
> > 
> > If we think that this is good enough, we proceed with the move of IMA
> > and EVM functions to the LSM infrastructure (patches v7 19-21).
> > 
> > The next patches are going to be similar to patches v6 22-23, but
> > unlike those, their goal would be simply to split metadata, not to make
> > IMA and EVM independent, which at this point has been addressed
> > separately in the prerequisite patches.
> > 
> > The final patch is to remove the 'integrity' LSM and the integrity
> > metadata management code, which now is not used anymore.
> > 
> > Would that work?
> 
> We are not making much progress, I'm going to follow any recommendation
> that would move this forward.


^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v5 23/23] integrity: Switch from rbtree to LSM-managed blob for integrity_iint_cache
  2023-12-06 16:11                     ` Mimi Zohar
@ 2023-12-06 16:50                       ` Roberto Sassu
  0 siblings, 0 replies; 96+ messages in thread
From: Roberto Sassu @ 2023-12-06 16:50 UTC (permalink / raw)
  To: Mimi Zohar, Paul Moore
  Cc: viro, brauner, chuck.lever, jlayton, neilb, kolga, Dai.Ngo, tom,
	jmorris, serge, dmitry.kasatkin, dhowells, jarkko,
	stephen.smalley.work, eparis, casey, mic, linux-fsdevel,
	linux-kernel, linux-nfs, linux-security-module, linux-integrity,
	keyrings, selinux, Roberto Sassu

On Wed, 2023-12-06 at 11:11 -0500, Mimi Zohar wrote:
> On Wed, 2023-12-06 at 14:10 +0100, Roberto Sassu wrote:
> > On Mon, 2023-12-04 at 14:26 +0100, Roberto Sassu wrote:
> 
> ...
> > > If the result of this patch set should be that IMA and EVM become
> > > proper LSMs without the shared integrity layer, instead of collapsing
> > > all changes in this patch set, I think we should first verify if IMA
> > > and EVM can be really independent. Once we guarantee that, we can
> > > proceed making the proper LSMs.
> > > 
> > > These are the changes I have in mind:
> > > 
> > > 1) Fix evm_verifyxattr(), and make it work without integrity_iint_cache
> > > 2) Remove the integrity_iint_cache parameter from evm_verifyxattr(),
> > >    since the other callers are not going to use it
> > 
> > Ehm, I checked better.
> > 
> > integrity_inode_get() is public too (although it is not exported). So,
> > a caller (not IMA) could do:
> > 
> > iint = integrity_inode_get(inode);
> > status = evm_verifyxattr(..., iint);
> > 
> > However, it should not call integrity_inode_free(), which is also in
> > include/linux/integrity.h, since this is going to be called by
> > security_inode_free() (currently).

Oh, I needed to add a check for the iint here:


void integrity_inode_free(struct inode *inode)
{
	struct integrity_iint_cache *iint;

	if (!IS_IMA(inode))
		return;

	iint = integrity_iint_find(inode);
	if (!iint)                          <=== this
		return;

	integrity_inode_set_iint(inode, NULL);

	iint_free(iint);
}

> Calling integrity_inode_free() directly would release the iint early.  
> As a result, IMA would then need to re-allocate it on next access. 
> Other than impacting IMA's performance, is this a problem?

Uhm, I think the iint could be freed while IMA is using it, for example
in process_measurement().

Roberto

> > > 3) Create an internal function with the original parameters to be used
> > >    by IMA
> > > 4) Introduce evm_post_path_mknod(), which similarly to
> > >    ima_post_path_mknod(), sets IMA_NEW_FILE for new files
> > 
> > I just realized that also this is changing the current behavior.
> > 
> > IMA would clear IMA_NEW_FILE in ima_check_last_writer(), while EVM
> > wouldn't (unless we implement the file_release hook in EVM too).
> 
> True
> 
> Mimi
> 
> > > 5) Add hardcoded call to evm_post_path_mknod() after
> > >    ima_post_path_mknod() in security.c
> > > 
> > > If we think that this is good enough, we proceed with the move of IMA
> > > and EVM functions to the LSM infrastructure (patches v7 19-21).
> > > 
> > > The next patches are going to be similar to patches v6 22-23, but
> > > unlike those, their goal would be simply to split metadata, not to make
> > > IMA and EVM independent, which at this point has been addressed
> > > separately in the prerequisite patches.
> > > 
> > > The final patch is to remove the 'integrity' LSM and the integrity
> > > metadata management code, which now is not used anymore.
> > > 
> > > Would that work?
> > 
> > We are not making much progress, I'm going to follow any recommendation
> > that would move this forward.
> 


^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v5 23/23] integrity: Switch from rbtree to LSM-managed blob for integrity_iint_cache
  2023-11-17 20:57   ` Paul Moore
  2023-11-20  8:16     ` Roberto Sassu
@ 2023-12-13 10:45     ` Roberto Sassu
  2023-12-13 18:08       ` Casey Schaufler
  1 sibling, 1 reply; 96+ messages in thread
From: Roberto Sassu @ 2023-12-13 10:45 UTC (permalink / raw)
  To: Paul Moore, viro, brauner, chuck.lever, jlayton, neilb, kolga,
	Dai.Ngo, tom, jmorris, serge, zohar, dmitry.kasatkin, dhowells,
	jarkko, stephen.smalley.work, eparis, casey, mic
  Cc: linux-fsdevel, linux-kernel, linux-nfs, linux-security-module,
	linux-integrity, keyrings, selinux, Roberto Sassu

On 17.11.23 21:57, Paul Moore wrote:
> On Nov  7, 2023 Roberto Sassu <roberto.sassu@huaweicloud.com> wrote:
>>
>> Before the security field of kernel objects could be shared among LSMs with
>> the LSM stacking feature, IMA and EVM had to rely on an alternative storage
>> of inode metadata. The association between inode metadata and inode is
>> maintained through an rbtree.
>>
>> Because of this alternative storage mechanism, there was no need to use
>> disjoint inode metadata, so IMA and EVM today still share them.
>>
>> With the reservation mechanism offered by the LSM infrastructure, the
>> rbtree is no longer necessary, as each LSM could reserve a space in the
>> security blob for each inode. However, since IMA and EVM share the
>> inode metadata, they cannot directly reserve the space for them.
>>
>> Instead, request from the 'integrity' LSM a space in the security blob for
>> the pointer of inode metadata (integrity_iint_cache structure). The other
>> reason for keeping the 'integrity' LSM is to preserve the original ordering
>> of IMA and EVM functions as when they were hardcoded.
>>
>> Prefer reserving space for a pointer to allocating the integrity_iint_cache
>> structure directly, as IMA would require it only for a subset of inodes.
>> Always allocating it would cause a waste of memory.
>>
>> Introduce two primitives for getting and setting the pointer of
>> integrity_iint_cache in the security blob, respectively
>> integrity_inode_get_iint() and integrity_inode_set_iint(). This would make
>> the code more understandable, as they directly replace rbtree operations.
>>
>> Locking is not needed, as access to inode metadata is not shared, it is per
>> inode.
>>
>> Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
>> Reviewed-by: Casey Schaufler <casey@schaufler-ca.com>
>> Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
>> ---
>>   security/integrity/iint.c      | 71 +++++-----------------------------
>>   security/integrity/integrity.h | 20 +++++++++-
>>   2 files changed, 29 insertions(+), 62 deletions(-)
>>
>> diff --git a/security/integrity/iint.c b/security/integrity/iint.c
>> index 882fde2a2607..a5edd3c70784 100644
>> --- a/security/integrity/iint.c
>> +++ b/security/integrity/iint.c
>> @@ -231,6 +175,10 @@ static int __init integrity_lsm_init(void)
>>   	return 0;
>>   }
>>   
>> +struct lsm_blob_sizes integrity_blob_sizes __ro_after_init = {
>> +	.lbs_inode = sizeof(struct integrity_iint_cache *),
>> +};
> 
> I'll admit that I'm likely missing an important detail, but is there
> a reason why you couldn't stash the integrity_iint_cache struct
> directly in the inode's security blob instead of the pointer?  For
> example:
> 
>    struct lsm_blob_sizes ... = {
>      .lbs_inode = sizeof(struct integrity_iint_cache),
>    };
> 
>    struct integrity_iint_cache *integrity_inode_get(inode)
>    {
>      if (unlikely(!inode->isecurity))
>        return NULL;

Ok, this caught my attention...

I see that selinux_inode() has it, but smack_inode() doesn't.

Some Smack code assumes that the inode security blob is always non-NULL:

static void init_inode_smack(struct inode *inode, struct smack_known *skp)
{
	struct inode_smack *isp = smack_inode(inode);

	isp->smk_inode = skp;
	isp->smk_flags = 0;
}


Is that intended? Should I add the check?

Thanks

Roberto

>      return inode->i_security + integrity_blob_sizes.lbs_inode;
>    }
> 
> --
> paul-moore.com


^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v5 23/23] integrity: Switch from rbtree to LSM-managed blob for integrity_iint_cache
  2023-12-13 10:45     ` Roberto Sassu
@ 2023-12-13 18:08       ` Casey Schaufler
  0 siblings, 0 replies; 96+ messages in thread
From: Casey Schaufler @ 2023-12-13 18:08 UTC (permalink / raw)
  To: Roberto Sassu, Paul Moore, viro, brauner, chuck.lever, jlayton,
	neilb, kolga, Dai.Ngo, tom, jmorris, serge, zohar,
	dmitry.kasatkin, dhowells, jarkko, stephen.smalley.work, eparis,
	mic
  Cc: linux-fsdevel, linux-kernel, linux-nfs, linux-security-module,
	linux-integrity, keyrings, selinux, Roberto Sassu,
	Casey Schaufler

On 12/13/2023 2:45 AM, Roberto Sassu wrote:
> On 17.11.23 21:57, Paul Moore wrote:
>> On Nov  7, 2023 Roberto Sassu <roberto.sassu@huaweicloud.com> wrote:
>>>
>>> ...
>>>
>>> diff --git a/security/integrity/iint.c b/security/integrity/iint.c
>>> index 882fde2a2607..a5edd3c70784 100644
>>> --- a/security/integrity/iint.c
>>> +++ b/security/integrity/iint.c
>>> @@ -231,6 +175,10 @@ static int __init integrity_lsm_init(void)
>>>       return 0;
>>>   }
>>>   +struct lsm_blob_sizes integrity_blob_sizes __ro_after_init = {
>>> +    .lbs_inode = sizeof(struct integrity_iint_cache *),
>>> +};
>>
>> I'll admit that I'm likely missing an important detail, but is there
>> a reason why you couldn't stash the integrity_iint_cache struct
>> directly in the inode's security blob instead of the pointer?  For
>> example:
>>
>>    struct lsm_blob_sizes ... = {
>>      .lbs_inode = sizeof(struct integrity_iint_cache),
>>    };
>>
>>    struct integrity_iint_cache *integrity_inode_get(inode)
>>    {
>>      if (unlikely(!inode->isecurity))
>>        return NULL;
>
> Ok, this caught my attention...
>
> I see that selinux_inode() has it, but smack_inode() doesn't.
>
> Some Smack code assumes that the inode security blob is always non-NULL:
>
> static void init_inode_smack(struct inode *inode, struct smack_known
> *skp)
> {
>     struct inode_smack *isp = smack_inode(inode);
>
>     isp->smk_inode = skp;
>     isp->smk_flags = 0;
> }
>
>
> Is that intended? Should I add the check?

Unless there's a case where inodes are created without calling
security_inode_alloc() there should never be an inode without a
security blob by the time you get to the Smack hook. That said,
people seem inclined to take all sorts of shortcuts and create
various "inodes" that aren't really inodes. I also see that SELinux
doesn't check the blob for cred or file structures. And that I
wrote the code in both cases.

Based on lack of bug reports for Smack on inodes and SELinux on
creds or files, It appears that the check is unnecessary. On the
other hand, it sure looks like good error detection hygiene. I
would be inclined to include the check in new code, but not get
in a panic about existing code.

>
> Thanks
>
> Roberto
>
>>      return inode->i_security + integrity_blob_sizes.lbs_inode;
>>    }
>>
>> -- 
>> paul-moore.com
>
>

^ permalink raw reply	[flat|nested] 96+ messages in thread

end of thread, other threads:[~2023-12-13 18:08 UTC | newest]

Thread overview: 96+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-11-07 13:39 [PATCH v5 00/23] security: Move IMA and EVM to the LSM infrastructure Roberto Sassu
2023-11-07 13:39 ` [PATCH v5 01/23] ima: Align ima_inode_post_setattr() definition with " Roberto Sassu
2023-11-07 17:21   ` Casey Schaufler
2023-11-07 13:39 ` [PATCH v5 02/23] ima: Align ima_file_mprotect() " Roberto Sassu
2023-11-07 17:22   ` Casey Schaufler
2023-11-07 13:39 ` [PATCH v5 03/23] ima: Align ima_inode_setxattr() " Roberto Sassu
2023-11-07 17:23   ` Casey Schaufler
2023-11-07 13:39 ` [PATCH v5 04/23] ima: Align ima_inode_removexattr() " Roberto Sassu
2023-11-07 17:24   ` Casey Schaufler
2023-11-07 13:39 ` [PATCH v5 05/23] ima: Align ima_post_read_file() " Roberto Sassu
2023-11-07 17:25   ` Casey Schaufler
2023-11-07 13:39 ` [PATCH v5 06/23] evm: Align evm_inode_post_setattr() " Roberto Sassu
2023-11-07 17:26   ` Casey Schaufler
2023-11-07 13:39 ` [PATCH v5 07/23] evm: Align evm_inode_setxattr() " Roberto Sassu
2023-11-07 17:27   ` Casey Schaufler
2023-11-07 13:39 ` [PATCH v5 08/23] evm: Align evm_inode_post_setxattr() " Roberto Sassu
2023-11-07 17:28   ` Casey Schaufler
2023-11-07 13:39 ` [PATCH v5 09/23] security: Align inode_setattr hook definition with EVM Roberto Sassu
2023-11-07 13:39 ` [PATCH v5 10/23] security: Introduce inode_post_setattr hook Roberto Sassu
2023-11-07 17:30   ` Casey Schaufler
2023-11-16  4:33   ` Paul Moore
2023-11-16  9:43     ` Roberto Sassu
2023-11-16 18:46       ` Paul Moore
2023-11-07 13:40 ` [PATCH v5 11/23] security: Introduce inode_post_removexattr hook Roberto Sassu
2023-11-07 17:33   ` Casey Schaufler
2023-11-07 17:45     ` Roberto Sassu
2023-11-20 17:31     ` Roberto Sassu
2023-11-20 18:03       ` Casey Schaufler
2023-11-20 20:55         ` Paul Moore
2023-11-16  4:33   ` Paul Moore
2023-11-07 13:40 ` [PATCH v5 12/23] security: Introduce file_post_open hook Roberto Sassu
2023-11-07 17:35   ` Casey Schaufler
2023-11-07 13:40 ` [PATCH v5 13/23] security: Introduce file_pre_free_security hook Roberto Sassu
2023-11-07 17:39   ` Casey Schaufler
2023-11-16  4:33   ` Paul Moore
2023-11-16  9:46     ` Roberto Sassu
2023-11-16 18:41       ` Paul Moore
2023-11-07 13:40 ` [PATCH v5 14/23] security: Introduce path_post_mknod hook Roberto Sassu
2023-11-07 17:41   ` Casey Schaufler
2023-11-07 13:40 ` [PATCH v5 15/23] security: Introduce inode_post_create_tmpfile hook Roberto Sassu
2023-11-07 17:42   ` Casey Schaufler
2023-11-16  4:33   ` Paul Moore
2023-11-07 13:40 ` [PATCH v5 16/23] security: Introduce inode_post_set_acl hook Roberto Sassu
2023-11-07 17:44   ` Casey Schaufler
2023-11-16  4:33   ` Paul Moore
2023-11-07 13:40 ` [PATCH v5 17/23] security: Introduce inode_post_remove_acl hook Roberto Sassu
2023-11-07 17:45   ` Casey Schaufler
2023-11-16  4:33   ` Paul Moore
2023-11-07 13:40 ` [PATCH v5 18/23] security: Introduce key_post_create_or_update hook Roberto Sassu
2023-11-07 17:47   ` Casey Schaufler
2023-11-07 13:40 ` [PATCH v5 19/23] ima: Move to LSM infrastructure Roberto Sassu
2023-11-07 17:52   ` Casey Schaufler
2023-11-07 13:40 ` [PATCH v5 20/23] ima: Move IMA-Appraisal " Roberto Sassu
2023-11-07 18:43   ` Casey Schaufler
2023-11-07 13:40 ` [PATCH v5 21/23] evm: Move " Roberto Sassu
2023-11-07 18:45   ` Casey Schaufler
2023-11-07 13:40 ` [PATCH v5 22/23] integrity: Move integrity functions to the " Roberto Sassu
2023-11-07 18:46   ` Casey Schaufler
2023-11-16  4:33   ` Paul Moore
2023-11-16 10:07     ` Roberto Sassu
2023-11-17 21:22       ` Paul Moore
2023-11-20 13:23         ` Roberto Sassu
2023-11-07 13:40 ` [PATCH v5 23/23] integrity: Switch from rbtree to LSM-managed blob for integrity_iint_cache Roberto Sassu
2023-11-17 20:57   ` Paul Moore
2023-11-20  8:16     ` Roberto Sassu
2023-11-20 21:06       ` Paul Moore
2023-11-29 12:27         ` Roberto Sassu
2023-11-29 13:58           ` Roberto Sassu
2023-11-29 17:22           ` Paul Moore
2023-11-29 18:46             ` Roberto Sassu
2023-11-30  0:41               ` Casey Schaufler
2023-11-30  8:30                 ` Petr Tesarik
2023-11-30 16:15                   ` Casey Schaufler
2023-11-30 21:34                     ` Roberto Sassu
2023-11-30 23:31                       ` Casey Schaufler
2023-11-30 23:43                         ` Roberto Sassu
2023-12-01  0:12                           ` Casey Schaufler
2023-11-30 11:12               ` Mimi Zohar
2023-11-30 16:59                 ` Paul Moore
2023-11-30 17:00                   ` Paul Moore
2023-11-30 16:34               ` Paul Moore
2023-11-30 21:56                 ` Roberto Sassu
2023-12-04 13:26                 ` Roberto Sassu
2023-12-04 15:01                   ` Mimi Zohar
2023-12-06 13:10                   ` Roberto Sassu
2023-12-06 16:11                     ` Mimi Zohar
2023-12-06 16:50                       ` Roberto Sassu
2023-12-01  1:05               ` Dr. Greg
2023-12-01 18:54                 ` Casey Schaufler
2023-12-01 23:53                   ` Dr. Greg
2023-12-02  0:17                     ` Casey Schaufler
2023-12-13 10:45     ` Roberto Sassu
2023-12-13 18:08       ` Casey Schaufler
2023-11-07 14:05 ` [PATCH v5 00/23] security: Move IMA and EVM to the LSM infrastructure Roberto Sassu
2023-11-07 19:37   ` Mimi Zohar
2023-11-08  3:14   ` Paul Moore

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.