Merge tag 'lsm-pr-20240312' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/lsm

Pull lsm updates from Paul Moore:

 - Promote IMA/EVM to a proper LSM

   This is the bulk of the diffstat, and the source of all the changes
   in the VFS code. Prior to the start of the LSM stacking work it was
   important that IMA/EVM were separate from the rest of the LSMs,
   complete with their own hooks, infrastructure, etc. as it was the
   only way to enable IMA/EVM at the same time as a LSM.

   However, now that the bulk of the LSM infrastructure supports
   multiple simultaneous LSMs, we can simplify things greatly by
   bringing IMA/EVM into the LSM infrastructure as proper LSMs. This is
   something I've wanted to see happen for quite some time and Roberto
   was kind enough to put in the work to make it happen.

 - Use the LSM hook default values to simplify the call_int_hook() macro

   Previously the call_int_hook() macro required callers to supply a
   default return value, despite a default value being specified when
   the LSM hook was defined.

   This simplifies the macro by using the defined default return value
   which makes life easier for callers and should also reduce the number
   of return value bugs in the future (we've had a few pop up recently,
   hence this work).

 - Use the KMEM_CACHE() macro instead of kmem_cache_create()

   The guidance appears to be to use the KMEM_CACHE() macro when
   possible and there is no reason why we can't use the macro, so let's
   use it.

 - Fix a number of comment typos in the LSM hook comment blocks

   Not much to say here, we fixed some questionable grammar decisions in
   the LSM hook comment blocks.

* tag 'lsm-pr-20240312' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/lsm: (28 commits)
  cred: Use KMEM_CACHE() instead of kmem_cache_create()
  lsm: use default hook return value in call_int_hook()
  lsm: fix typos in security/security.c comment headers
  integrity: Remove LSM
  ima: Make it independent from 'integrity' LSM
  evm: Make it independent from 'integrity' LSM
  evm: Move to LSM infrastructure
  ima: Move IMA-Appraisal to LSM infrastructure
  ima: Move to LSM infrastructure
  integrity: Move integrity_kernel_module_request() to IMA
  security: Introduce key_post_create_or_update hook
  security: Introduce inode_post_remove_acl hook
  security: Introduce inode_post_set_acl hook
  security: Introduce inode_post_create_tmpfile hook
  security: Introduce path_post_mknod hook
  security: Introduce file_release hook
  security: Introduce file_post_open hook
  security: Introduce inode_post_removexattr hook
  security: Introduce inode_post_setattr hook
  security: Align inode_setattr hook definition with EVM
  ...
This commit is contained in:
Linus Torvalds
2024-03-12 20:03:34 -07:00
36 changed files with 1126 additions and 1141 deletions

View File

@@ -16,8 +16,6 @@
#include <linux/fcntl.h>
#include <linux/filelock.h>
#include <linux/security.h>
#include <linux/evm.h>
#include <linux/ima.h>
#include "internal.h"
@@ -502,8 +500,7 @@ int notify_change(struct mnt_idmap *idmap, struct dentry *dentry,
if (!error) {
fsnotify_change(dentry, ia_valid);
ima_inode_post_setattr(idmap, dentry);
evm_inode_post_setattr(dentry, ia_valid);
security_inode_post_setattr(idmap, dentry, ia_valid);
}
return error;

View File

@@ -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>
@@ -414,7 +413,7 @@ static void __fput(struct file *file)
eventpoll_release(file);
locks_remove_file(file);
ima_file_free(file);
security_file_release(file);
if (unlikely(file->f_flags & FASYNC)) {
if (file->f_op->fasync)
file->f_op->fasync(-1, file, 0);

View File

@@ -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>
@@ -3642,7 +3641,7 @@ static int do_open(struct nameidata *nd,
if (!error && !(file->f_mode & FMODE_OPENED))
error = vfs_open(&nd->path, file);
if (!error)
error = ima_file_check(file, op->acc_mode);
error = security_file_post_open(file, op->acc_mode);
if (!error && do_truncate)
error = handle_truncate(idmap, file);
if (unlikely(error > 0)) {
@@ -3705,7 +3704,7 @@ static int vfs_tmpfile(struct mnt_idmap *idmap,
inode->i_state |= I_LINKABLE;
spin_unlock(&inode->i_lock);
}
ima_post_create_tmpfile(idmap, inode);
security_inode_post_create_tmpfile(idmap, inode);
return 0;
}
@@ -4051,8 +4050,6 @@ retry:
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,
@@ -4063,6 +4060,11 @@ retry:
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)) {

View File

@@ -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>
@@ -895,7 +894,7 @@ __nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type,
goto out;
}
host_err = ima_file_check(file, may_flags);
host_err = security_file_post_open(file, may_flags);
if (host_err) {
fput(file);
goto out;

View File

@@ -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>

View File

@@ -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>
@@ -1137,7 +1136,7 @@ retry_deleg:
error = -EIO;
if (!error) {
fsnotify_xattr(dentry);
evm_inode_post_set_acl(dentry, acl_name, kacl);
security_inode_post_set_acl(dentry, acl_name, kacl);
}
out_inode_unlock:
@@ -1245,7 +1244,7 @@ retry_deleg:
error = -EIO;
if (!error) {
fsnotify_xattr(dentry);
evm_inode_post_remove_acl(idmap, dentry, acl_name);
security_inode_post_remove_acl(idmap, dentry, acl_name);
}
out_inode_unlock:

View File

@@ -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>
@@ -552,11 +551,11 @@ __vfs_removexattr_locked(struct mnt_idmap *idmap,
goto out;
error = __vfs_removexattr(idmap, dentry, name);
if (error)
return error;
if (!error) {
fsnotify_xattr(dentry);
evm_inode_post_removexattr(dentry, name);
}
fsnotify_xattr(dentry);
security_inode_post_removexattr(dentry, name);
out:
return error;

View File

@@ -12,52 +12,12 @@
#include <linux/integrity.h>
#include <linux/xattr.h>
struct integrity_iint_cache;
#ifdef CONFIG_EVM
extern int evm_set_key(void *key, size_t keylen);
extern enum integrity_status evm_verifyxattr(struct dentry *dentry,
const char *xattr_name,
void *xattr_value,
size_t xattr_value_len,
struct integrity_iint_cache *iint);
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 int evm_inode_setxattr(struct mnt_idmap *idmap,
struct dentry *dentry, const char *name,
const void *value, size_t size);
extern void evm_inode_post_setxattr(struct dentry *dentry,
const char *xattr_name,
const void *xattr_value,
size_t xattr_value_len);
extern int evm_inode_copy_up_xattr(const char *name);
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);
}
size_t xattr_value_len);
int evm_inode_init_security(struct inode *inode, struct inode *dir,
const struct qstr *qstr, struct xattr *xattrs,
int *xattr_count);
@@ -85,85 +45,12 @@ static inline int evm_set_key(void *key, size_t keylen)
static inline enum integrity_status evm_verifyxattr(struct dentry *dentry,
const char *xattr_name,
void *xattr_value,
size_t xattr_value_len,
struct integrity_iint_cache *iint)
size_t xattr_value_len)
{
return INTEGRITY_UNKNOWN;
}
#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 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)
{
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)
{
return;
}
static inline int evm_inode_copy_up_xattr(const char *name)
{
return 0;
}
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,

View File

@@ -16,23 +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 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, void *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);
@@ -57,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 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, void *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;
@@ -169,76 +90,13 @@ 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,
struct dentry *dentry);
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,
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 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)
{
return;
}
static inline int ima_inode_setxattr(struct dentry *dentry,
const char *xattr_name,
const void *xattr_value,
size_t xattr_value_len)
{
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 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)

View File

@@ -19,40 +19,13 @@ enum integrity_status {
INTEGRITY_UNKNOWN,
};
/* List of EVM protected security xattrs */
#ifdef CONFIG_INTEGRITY
extern struct integrity_iint_cache *integrity_inode_get(struct inode *inode);
extern void integrity_inode_free(struct inode *inode);
extern void __init integrity_load_keys(void);
#else
static inline struct integrity_iint_cache *
integrity_inode_get(struct inode *inode)
{
return NULL;
}
static inline void integrity_inode_free(struct inode *inode)
{
return;
}
static inline void integrity_load_keys(void)
{
}
#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 */

View File

@@ -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)
@@ -119,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)
@@ -135,7 +139,10 @@ 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(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,
@@ -146,12 +153,18 @@ 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(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,
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)
@@ -168,6 +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_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)
@@ -186,6 +200,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)
@@ -390,6 +405,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

View File

@@ -345,6 +345,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);
@@ -362,6 +364,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,
@@ -369,16 +373,22 @@ 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,
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);
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,
@@ -393,6 +403,7 @@ int security_kernfs_init_security(struct kernfs_node *kn_dir,
struct kernfs_node *kn);
int security_file_permission(struct file *file, int mask);
int security_file_alloc(struct file *file);
void security_file_release(struct file *file);
void security_file_free(struct file *file);
int security_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
int security_file_ioctl_compat(struct file *file, unsigned int cmd,
@@ -409,6 +420,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);
@@ -807,6 +819,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)
@@ -880,6 +896,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;
@@ -900,6 +921,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)
@@ -914,6 +940,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)
{ }
@@ -936,6 +967,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);
@@ -996,6 +1031,9 @@ static inline int security_file_alloc(struct file *file)
return 0;
}
static inline void security_file_release(struct file *file)
{ }
static inline void security_file_free(struct file *file)
{ }
@@ -1063,6 +1101,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;
@@ -1872,6 +1915,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);
@@ -1906,6 +1950,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;
@@ -1957,6 +2005,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
@@ -1984,6 +2035,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 */

View File

@@ -62,6 +62,8 @@ struct lsm_ctx {
#define LSM_ID_LOCKDOWN 108
#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

View File

@@ -606,8 +606,8 @@ int set_cred_ucounts(struct cred *new)
void __init cred_init(void)
{
/* allocate a slab in which we can store credentials */
cred_jar = kmem_cache_create("cred_jar", sizeof(struct cred), 0,
SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_ACCOUNT, NULL);
cred_jar = KMEM_CACHE(cred,
SLAB_HWCACHE_ALIGN | SLAB_PANIC | SLAB_ACCOUNT);
}
/**

View File

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

View File

@@ -132,26 +132,3 @@ out:
pr_debug("%s() = %d\n", __func__, ret);
return ret;
}
/**
* integrity_kernel_module_request - prevent crypto-pkcs1pad(rsa,*) requests
* @kmod_name: kernel module name
*
* We have situation, when public_key_verify_signature() in case of RSA
* algorithm use alg_name to store internal information in order to
* construct an algorithm on the fly, but crypto_larval_lookup() will try
* to use alg_name in order to load kernel module with same name.
* Since we don't have any real "crypto-pkcs1pad(rsa,*)" kernel modules,
* we are safe to fail such module request from crypto_larval_lookup().
*
* In this way we prevent modprobe execution during digsig verification
* and avoid possible deadlock if modprobe and/or it's dependencies
* also signed with digsig.
*/
int integrity_kernel_module_request(char *kmod_name)
{
if (strncmp(kmod_name, "crypto-pkcs1pad(rsa,", 20) == 0)
return -EINVAL;
return 0;
}

View File

@@ -6,6 +6,7 @@ config EVM
select CRYPTO_HMAC
select CRYPTO_SHA1
select CRYPTO_HASH_INFO
select SECURITY_PATH
default n
help
EVM protects a file's security extended attributes against

View File

@@ -32,6 +32,25 @@ struct xattr_list {
bool enabled;
};
#define EVM_NEW_FILE 0x00000001
#define EVM_IMMUTABLE_DIGSIG 0x00000002
/* EVM integrity metadata associated with an inode */
struct evm_iint_cache {
unsigned long flags;
enum integrity_status evm_status:4;
};
extern struct lsm_blob_sizes evm_blob_sizes;
static inline struct evm_iint_cache *evm_iint_inode(const struct inode *inode)
{
if (unlikely(!inode->i_security))
return NULL;
return inode->i_security + evm_blob_sizes.lbs_inode;
}
extern int evm_initialized;
#define EVM_ATTR_FSUUID 0x0001

View File

@@ -322,10 +322,10 @@ int evm_calc_hash(struct dentry *dentry, const char *req_xattr_name,
static int evm_is_immutable(struct dentry *dentry, struct inode *inode)
{
const struct evm_ima_xattr_data *xattr_data = NULL;
struct integrity_iint_cache *iint;
struct evm_iint_cache *iint;
int rc = 0;
iint = integrity_iint_find(inode);
iint = evm_iint_inode(inode);
if (iint && (iint->flags & EVM_IMMUTABLE_DIGSIG))
return 1;

View File

@@ -178,14 +178,14 @@ static int is_unsupported_fs(struct dentry *dentry)
static enum integrity_status evm_verify_hmac(struct dentry *dentry,
const char *xattr_name,
char *xattr_value,
size_t xattr_value_len,
struct integrity_iint_cache *iint)
size_t xattr_value_len)
{
struct evm_ima_xattr_data *xattr_data = NULL;
struct signature_v2_hdr *hdr;
enum integrity_status evm_status = INTEGRITY_PASS;
struct evm_digest digest;
struct inode *inode;
struct inode *inode = d_backing_inode(dentry);
struct evm_iint_cache *iint = evm_iint_inode(inode);
int rc, xattr_len, evm_immutable = 0;
if (iint && (iint->evm_status == INTEGRITY_PASS ||
@@ -254,8 +254,6 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry,
(const char *)xattr_data, xattr_len,
digest.digest, digest.hdr.length);
if (!rc) {
inode = d_backing_inode(dentry);
if (xattr_data->type == EVM_XATTR_PORTABLE_DIGSIG) {
if (iint)
iint->flags |= EVM_IMMUTABLE_DIGSIG;
@@ -403,7 +401,6 @@ int evm_read_protected_xattrs(struct dentry *dentry, u8 *buffer,
* @xattr_name: requested xattr
* @xattr_value: requested xattr value
* @xattr_value_len: requested xattr value length
* @iint: inode integrity metadata
*
* Calculate the HMAC for the given dentry and verify it against the stored
* security.evm xattr. For performance, use the xattr value and length
@@ -416,8 +413,7 @@ int evm_read_protected_xattrs(struct dentry *dentry, u8 *buffer,
*/
enum integrity_status evm_verifyxattr(struct dentry *dentry,
const char *xattr_name,
void *xattr_value, size_t xattr_value_len,
struct integrity_iint_cache *iint)
void *xattr_value, size_t xattr_value_len)
{
if (!evm_key_loaded() || !evm_protected_xattr(xattr_name))
return INTEGRITY_UNKNOWN;
@@ -425,13 +421,8 @@ enum integrity_status evm_verifyxattr(struct dentry *dentry,
if (is_unsupported_fs(dentry))
return INTEGRITY_UNKNOWN;
if (!iint) {
iint = integrity_iint_find(d_backing_inode(dentry));
if (!iint)
return INTEGRITY_UNKNOWN;
}
return evm_verify_hmac(dentry, xattr_name, xattr_value,
xattr_value_len, iint);
xattr_value_len);
}
EXPORT_SYMBOL_GPL(evm_verifyxattr);
@@ -448,7 +439,7 @@ static enum integrity_status evm_verify_current_integrity(struct dentry *dentry)
if (!evm_key_loaded() || !S_ISREG(inode->i_mode) || evm_fixmode)
return INTEGRITY_PASS;
return evm_verify_hmac(dentry, NULL, NULL, 0, NULL);
return evm_verify_hmac(dentry, NULL, NULL, 0);
}
/*
@@ -526,14 +517,14 @@ static int evm_protect_xattr(struct mnt_idmap *idmap,
evm_status = evm_verify_current_integrity(dentry);
if (evm_status == INTEGRITY_NOXATTRS) {
struct integrity_iint_cache *iint;
struct evm_iint_cache *iint;
/* Exception if the HMAC is not going to be calculated. */
if (evm_hmac_disabled())
return 0;
iint = integrity_iint_find(d_backing_inode(dentry));
if (iint && (iint->flags & IMA_NEW_FILE))
iint = evm_iint_inode(d_backing_inode(dentry));
if (iint && (iint->flags & EVM_NEW_FILE))
return 0;
/* exception for pseudo filesystems */
@@ -581,6 +572,7 @@ out:
* @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
@@ -588,9 +580,9 @@ out:
* 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)
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;
@@ -620,8 +612,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
@@ -671,9 +663,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;
@@ -712,11 +706,29 @@ 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;
struct evm_iint_cache *iint;
iint = integrity_iint_find(inode);
iint = evm_iint_inode(inode);
if (iint)
iint->evm_status = INTEGRITY_UNKNOWN;
}
@@ -752,6 +764,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.
*
@@ -759,8 +772,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)
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;
@@ -779,6 +795,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
@@ -789,7 +820,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;
@@ -805,6 +837,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)
{
@@ -828,8 +876,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;
@@ -870,6 +918,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
*
@@ -879,7 +928,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)
static void evm_inode_post_setattr(struct mnt_idmap *idmap,
struct dentry *dentry, int ia_valid)
{
if (!evm_revalidate_status(NULL))
return;
@@ -896,7 +946,7 @@ void evm_inode_post_setattr(struct dentry *dentry, int ia_valid)
evm_update_evmxattr(dentry, NULL, NULL, 0);
}
int evm_inode_copy_up_xattr(const char *name)
static int evm_inode_copy_up_xattr(const char *name)
{
if (strcmp(name, XATTR_NAME_EVM) == 0)
return 1; /* Discard */
@@ -960,6 +1010,42 @@ out:
}
EXPORT_SYMBOL_GPL(evm_inode_init_security);
static int evm_inode_alloc_security(struct inode *inode)
{
struct evm_iint_cache *iint = evm_iint_inode(inode);
/* Called by security_inode_alloc(), it cannot be NULL. */
iint->flags = 0UL;
iint->evm_status = INTEGRITY_UNKNOWN;
return 0;
}
static void evm_file_release(struct file *file)
{
struct inode *inode = file_inode(file);
struct evm_iint_cache *iint = evm_iint_inode(inode);
fmode_t mode = file->f_mode;
if (!S_ISREG(inode->i_mode) || !(mode & FMODE_WRITE))
return;
if (iint && atomic_read(&inode->i_writecount) == 1)
iint->flags &= ~EVM_NEW_FILE;
}
static void evm_post_path_mknod(struct mnt_idmap *idmap, struct dentry *dentry)
{
struct inode *inode = d_backing_inode(dentry);
struct evm_iint_cache *iint = evm_iint_inode(inode);
if (!S_ISREG(inode->i_mode))
return;
if (iint)
iint->flags |= EVM_NEW_FILE;
}
#ifdef CONFIG_EVM_LOAD_X509
void __init evm_load_x509(void)
{
@@ -999,4 +1085,45 @@ error:
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_copy_up_xattr, evm_inode_copy_up_xattr),
LSM_HOOK_INIT(inode_setxattr, evm_inode_setxattr),
LSM_HOOK_INIT(inode_post_setxattr, evm_inode_post_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_removexattr, evm_inode_removexattr),
LSM_HOOK_INIT(inode_post_removexattr, evm_inode_post_removexattr),
LSM_HOOK_INIT(inode_init_security, evm_inode_init_security),
LSM_HOOK_INIT(inode_alloc_security, evm_inode_alloc_security),
LSM_HOOK_INIT(file_release, evm_file_release),
LSM_HOOK_INIT(path_post_mknod, evm_post_path_mknod),
};
static const struct lsm_id evm_lsmid = {
.name = "evm",
.id = LSM_ID_EVM,
};
static int __init init_evm_lsm(void)
{
security_add_hooks(evm_hooks, ARRAY_SIZE(evm_hooks), &evm_lsmid);
return 0;
}
struct lsm_blob_sizes evm_blob_sizes __ro_after_init = {
.lbs_inode = sizeof(struct evm_iint_cache),
.lbs_xattr_count = 1,
};
DEFINE_LSM(evm) = {
.name = "evm",
.init = init_evm_lsm,
.order = LSM_ORDER_LAST,
.blobs = &evm_blob_sizes,
};
late_initcall(init_evm);

Some files were not shown because too many files have changed in this diff Show More